Allow pkcs#10 creation directkly from a smart card

This commit is contained in:
Werner Koch 2006-10-11 17:52:15 +00:00
parent e0edd19f95
commit 43825e9dae
11 changed files with 211 additions and 39 deletions

4
NEWS
View File

@ -1,3 +1,7 @@
Noteworthy changes in version 1.9.93
-------------------------------------------------
Noteworthy changes in version 1.9.92 (2006-10-11)
-------------------------------------------------

View File

@ -236,7 +236,7 @@ parse_hexstring (assuan_context_t ctx, const char *string, size_t *len)
}
/* Parse the keygrip in STRING into the provided buffer BUF. BUF must
provide space for 20 bytes. BUF is not changed if the fucntions
provide space for 20 bytes. BUF is not changed if the function
returns an error. */
static int
parse_keygrip (assuan_context_t ctx, const char *string, unsigned char *buf)

View File

@ -26,8 +26,8 @@ min_automake_version="1.9.3"
# Remember to change the version number immediately *after* a release.
# Set my_issvn to "yes" for non-released code. Remember to run an
# "svn up" and "autogen.sh" right before creating a distribution.
m4_define([my_version], [1.9.92])
m4_define([my_issvn], [no])
m4_define([my_version], [1.9.93])
m4_define([my_issvn], [yes])
m4_define([svn_revision], m4_esyscmd([echo -n $((svn info 2>/dev/null \

View File

@ -1,3 +1,7 @@
2006-10-11 Werner Koch <wk@g10code.com>
* app-openpgp.c (do_sign): Redirect to do_auth for OpenPGP.3.
2006-10-06 Werner Koch <wk@g10code.com>
* Makefile.am (AM_CFLAGS): Use PTH version of libassuan.

View File

@ -142,6 +142,11 @@ struct app_local_s {
static unsigned long convert_sig_counter_value (const unsigned char *value,
size_t valuelen);
static unsigned long get_sig_counter (app_t app);
static gpg_error_t do_auth (app_t app, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen);
@ -2088,7 +2093,11 @@ check_against_given_fingerprint (app_t app, const char *fpr, int keyno)
Note that this function may return the error code
GPG_ERR_WRONG_CARD to indicate that the card currently present does
not match the one required for the requested action (e.g. the
serial number does not match). */
serial number does not match).
As a special feature a KEYIDSTR of "OPENPGP.3" redirects the
operation to the auth command.
*/
static gpg_error_t
do_sign (app_t app, const char *keyidstr, int hashalgo,
gpg_error_t (*pincb)(void*, const char *, char **),
@ -2109,6 +2118,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
int n;
const char *fpr = NULL;
unsigned long sigcount;
int use_auth = 0;
if (!keyidstr || !*keyidstr)
return gpg_error (GPG_ERR_INV_VALUE);
@ -2136,6 +2146,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
/* Check whether an OpenPGP card of any version has been requested. */
if (!strcmp (keyidstr, "OPENPGP.1"))
;
else if (!strcmp (keyidstr, "OPENPGP.3"))
use_auth = 1;
else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
return gpg_error (GPG_ERR_INV_ID);
else
@ -2178,6 +2190,14 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
memcpy (data+15, indata, indatalen);
if (use_auth)
{
/* This is a hack to redirect to the internal authenticate command. */
return do_auth (app, "OPENPGP.3", pincb, pincb_arg,
data, 35,
outdata, outdatalen);
}
sigcount = get_sig_counter (app);
log_info (_("signatures created so far: %lu\n"), sigcount);

View File

@ -1,3 +1,10 @@
2006-10-11 Werner Koch <wk@g10code.com>
* certreqgen.c (proc_parameters, create_request): Allow for
creation directly from a card.
* call-agent.c (gpgsm_agent_readkey): New arg FROMCARD.
(gpgsm_scd_pksign): New.
2006-10-06 Werner Koch <wk@g10code.com>
* Makefile.am (AM_CFLAGS): Use PTH version of libassuan.

View File

@ -271,6 +271,84 @@ gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
}
/* Call the scdaemon to do a sign operation using the key identified by
the hex string KEYID. */
int
gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
unsigned char *digest, size_t digestlen, int digestalgo,
unsigned char **r_buf, size_t *r_buflen )
{
int rc, i;
char *p, line[ASSUAN_LINELENGTH];
membuf_t data;
size_t len;
const char *hashopt;
unsigned char *sigbuf;
size_t sigbuflen;
*r_buf = NULL;
switch(digestalgo)
{
case GCRY_MD_SHA1: hashopt = "--hash=sha1"; break;
case GCRY_MD_RMD160:hashopt = "--hash=rmd160"; break;
case GCRY_MD_MD5: hashopt = "--hash=md5"; break;
case GCRY_MD_SHA256:hashopt = "--hash=sha256"; break;
default:
return gpg_error (GPG_ERR_DIGEST_ALGO);
}
rc = start_agent (ctrl);
if (rc)
return rc;
if (digestlen*2 + 50 > DIM(line))
return gpg_error (GPG_ERR_GENERAL);
p = stpcpy (line, "SCD SETDATA " );
for (i=0; i < digestlen ; i++, p += 2 )
sprintf (p, "%02X", digest[i]);
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return rc;
init_membuf (&data, 1024);
snprintf (line, DIM(line)-1, "SCD PKSIGN %s %s", hashopt, keyid);
line[DIM(line)-1] = 0;
rc = assuan_transact (agent_ctx, line,
membuf_data_cb, &data, NULL, NULL, NULL, NULL);
if (rc)
{
xfree (get_membuf (&data, &len));
return rc;
}
sigbuf = get_membuf (&data, &sigbuflen);
/* Create an S-expression from it which is formatted like this:
"(7:sig-val(3:rsa(1:sSIGBUFLEN:SIGBUF)))" Fixme: If a card ever
creates non-RSA keys we need to change things. */
*r_buflen = 21 + 11 + sigbuflen + 4;
p = xtrymalloc (*r_buflen);
*r_buf = (unsigned char*)p;
if (!p)
{
xfree (sigbuf);
return 0;
}
p = stpcpy (p, "(7:sig-val(3:rsa(1:s" );
sprintf (p, "%u:", (unsigned int)sigbuflen);
p += strlen (p);
memcpy (p, sigbuf, sigbuflen);
p += sigbuflen;
strcpy (p, ")))");
xfree (sigbuf);
assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL));
return 0;
}
/* Handle a CIPHERTEXT inquiry. Note, we only send the data,
@ -449,9 +527,12 @@ gpgsm_agent_genkey (ctrl_t ctrl,
}
/* Call the agent to read the public key part for a given keygrip. */
/* Call the agent to read the public key part for a given keygrip. If
FROMCARD is true, the key is directly read from the current
smartcard. In this case HEXKEYGRIP should be the keyID
(e.g. OPENPGP.3). */
int
gpgsm_agent_readkey (ctrl_t ctrl, const char *hexkeygrip,
gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
ksba_sexp_t *r_pubkey)
{
int rc;
@ -469,7 +550,8 @@ gpgsm_agent_readkey (ctrl_t ctrl, const char *hexkeygrip,
if (rc)
return rc;
snprintf (line, DIM(line)-1, "READKEY %s", hexkeygrip);
snprintf (line, DIM(line)-1, "%sREADKEY %s",
fromcard? "SCD ":"", hexkeygrip);
line[DIM(line)-1] = 0;
init_membuf (&data, 1024);

View File

@ -148,6 +148,7 @@ static int proc_parameters (ctrl_t ctrl,
struct reqgen_ctrl_s *outctrl);
static int create_request (ctrl_t ctrl,
struct para_data_s *para,
const char *carddirect,
ksba_const_sexp_t public,
struct reqgen_ctrl_s *outctrl);
@ -452,15 +453,24 @@ proc_parameters (ctrl_t ctrl,
ksba_sexp_t public;
int seq;
size_t erroff, errlen;
char *cardkeyid = NULL;
/* Check that we have all required parameters; */
assert (get_parameter (para, pKEYTYPE, 0));
/* We can only use RSA for now. There is a with pkcs-10 on how to
use ElGamal because it is expected that a PK algorithm can always
be used for signing. */
/* We can only use RSA for now. There is a problem with pkcs-10 on
how to use ElGamal because it is expected that a PK algorithm can
always be used for signing. Another problem is that on-card
generated encryption keys may not be used for signing. */
i = get_parameter_algo (para, pKEYTYPE);
if (i < 1 || i != GCRY_PK_RSA )
if (!i && (s = get_parameter_value (para, pKEYTYPE, 0)) && *s)
{
/* Hack to allow creation of certificates directly from a smart
card. For example: "Key-Type: card:OPENPGP.3". */
if (!strncmp (s, "card:", 5) && s[5])
cardkeyid = xtrystrdup (s+5);
}
if ( (i < 1 || i != GCRY_PK_RSA) && !cardkeyid )
{
r = get_parameter (para, pKEYTYPE, 0);
log_error (_("line %d: invalid algorithm\n"), r->lnr);
@ -472,18 +482,22 @@ proc_parameters (ctrl_t ctrl,
nbits = 1024;
else
nbits = get_parameter_uint (para, pKEYLENGTH);
if (nbits < 1024 || nbits > 4096)
if ((nbits < 1024 || nbits > 4096) && !cardkeyid)
{
/* The BSI specs dated 2002-11-25 don't allow lengths below 1024. */
r = get_parameter (para, pKEYLENGTH, 0);
log_error (_("line %d: invalid key length %u (valid are %d to %d)\n"),
r->lnr, nbits, 1024, 4096);
xfree (cardkeyid);
return gpg_error (GPG_ERR_INV_PARAMETER);
}
/* Check the usage. */
if (parse_parameter_usage (para, pKEYUSAGE))
return gpg_error (GPG_ERR_INV_PARAMETER);
{
xfree (cardkeyid);
return gpg_error (GPG_ERR_INV_PARAMETER);
}
/* Check that there is a subject name and that this DN fits our
requirements. */
@ -491,6 +505,7 @@ proc_parameters (ctrl_t ctrl,
{
r = get_parameter (para, pNAMEDN, 0);
log_error (_("line %d: no subject name given\n"), r->lnr);
xfree (cardkeyid);
return gpg_error (GPG_ERR_INV_PARAMETER);
}
err = ksba_dn_teststr (s, 0, &erroff, &errlen);
@ -504,6 +519,7 @@ proc_parameters (ctrl_t ctrl,
log_error (_("line %d: invalid subject name `%s' at pos %d\n"),
r->lnr, s, erroff);
xfree (cardkeyid);
return gpg_error (GPG_ERR_INV_PARAMETER);
}
@ -518,19 +534,32 @@ proc_parameters (ctrl_t ctrl,
{
r = get_parameter (para, pNAMEEMAIL, seq);
log_error (_("line %d: not a valid email address\n"), r->lnr);
xfree (cardkeyid);
return gpg_error (GPG_ERR_INV_PARAMETER);
}
}
s = get_parameter_value (para, pKEYGRIP, 0);
if (s) /* Use existing key. */
if (cardkeyid) /* Take the key from the current smart card. */
{
rc = gpgsm_agent_readkey (ctrl, s, &public);
rc = gpgsm_agent_readkey (ctrl, 1, cardkeyid, &public);
if (rc)
{
r = get_parameter (para, pKEYTYPE, 0);
log_error (_("line %d: error reading key `%s' from card: %s\n"),
r->lnr, cardkeyid, gpg_strerror (rc));
xfree (cardkeyid);
return rc;
}
}
else if ((s=get_parameter_value (para, pKEYGRIP, 0))) /* Use existing key.*/
{
rc = gpgsm_agent_readkey (ctrl, 0, s, &public);
if (rc)
{
r = get_parameter (para, pKEYTYPE, 0);
log_error (_("line %d: error getting key by keygrip `%s': %s\n"),
r->lnr, s, gpg_strerror (rc));
xfree (cardkeyid);
return rc;
}
}
@ -546,12 +575,14 @@ proc_parameters (ctrl_t ctrl,
r = get_parameter (para, pKEYTYPE, 0);
log_error (_("line %d: key generation failed: %s\n"),
r->lnr, gpg_strerror (rc));
xfree (cardkeyid);
return rc;
}
}
rc = create_request (ctrl, para, public, outctrl);
rc = create_request (ctrl, para, cardkeyid, public, outctrl);
xfree (public);
xfree (cardkeyid);
return rc;
}
@ -560,8 +591,10 @@ proc_parameters (ctrl_t ctrl,
/* Parameters are checked, the key pair has been created. Now
generate the request and write it out */
static int
create_request (ctrl_t ctrl,
struct para_data_s *para, ksba_const_sexp_t public,
create_request (ctrl_t ctrl,
struct para_data_s *para,
const char *carddirect,
ksba_const_sexp_t public,
struct reqgen_ctrl_s *outctrl)
{
ksba_certreq_t cr;
@ -758,11 +791,18 @@ create_request (ctrl_t ctrl,
for (n=0; n < 20; n++)
sprintf (hexgrip+n*2, "%02X", grip[n]);
rc = gpgsm_agent_pksign (ctrl, hexgrip, NULL,
gcry_md_read(md, GCRY_MD_SHA1),
gcry_md_get_algo_dlen (GCRY_MD_SHA1),
GCRY_MD_SHA1,
&sigval, &siglen);
if (carddirect)
rc = gpgsm_scd_pksign (ctrl, carddirect, NULL,
gcry_md_read(md, GCRY_MD_SHA1),
gcry_md_get_algo_dlen (GCRY_MD_SHA1),
GCRY_MD_SHA1,
&sigval, &siglen);
else
rc = gpgsm_agent_pksign (ctrl, hexgrip, NULL,
gcry_md_read(md, GCRY_MD_SHA1),
gcry_md_get_algo_dlen (GCRY_MD_SHA1),
GCRY_MD_SHA1,
&sigval, &siglen);
if (rc)
{
log_error ("signing failed: %s\n", gpg_strerror (rc));

View File

@ -322,12 +322,15 @@ int gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
size_t digestlen,
int digestalgo,
unsigned char **r_buf, size_t *r_buflen);
int gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
unsigned char *digest, size_t digestlen, int digestalgo,
unsigned char **r_buf, size_t *r_buflen);
int gpgsm_agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
ksba_const_sexp_t ciphertext,
char **r_buf, size_t *r_buflen);
int gpgsm_agent_genkey (ctrl_t ctrl,
ksba_const_sexp_t keyparms, ksba_sexp_t *r_pubkey);
int gpgsm_agent_readkey (ctrl_t ctrl, const char *hexkeygrip,
int gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
ksba_sexp_t *r_pubkey);
int gpgsm_agent_istrusted (ctrl_t ctrl, ksba_cert_t cert,
struct rootca_flags_s *rootca_flags);

View File

@ -1,3 +1,7 @@
2006-10-11 Werner Koch <wk@g10code.com>
* gpgsm-gencert.sh: Allow generation of card keys.
2006-10-08 Werner Koch <wk@g10code.com>
* Makefile.am (gpgkey2ssh_LDADD): Add LIBINTL. Suggested by

View File

@ -84,19 +84,27 @@ query_user_menu()
echo "You selected: $ANSWER" >&2
}
query_user_menu "Key type" "RSA" "existing key"
if [ "$ANSWER" = "existing key" ]; then
# User requested to use an existing key; need to set some dummy defaults
KEY_TYPE=RSA
KEY_LENGTH=1024
query_user "Keygrip "
KEY_GRIP=$ANSWER
else
KEY_TYPE=$ANSWER
query_user_menu "Key length" "1024" "2048"
KEY_LENGTH=$ANSWER
KEY_GRIP=
fi
query_user_menu "Key type" "RSA" "existing key" "OPENPGP.1" "OPENPGP.3"
case "$ANSWER" in
RSA)
KEY_TYPE=$ANSWER
query_user_menu "Key length" "1024" "2048"
KEY_LENGTH=$ANSWER
KEY_GRIP=
;;
existing*)
# User requested to use an existing key; need to set some dummy defaults
KEY_TYPE=RSA
KEY_LENGTH=1024
query_user "Keygrip "
KEY_GRIP=$ANSWER
;;
*)
KEY_TYPE="card:$ANSWER"
KEY_LENGTH=
KEY_GRIP=
;;
esac
query_user_menu "Key usage" "sign, encrypt" "sign" "encrypt"
@ -162,7 +170,7 @@ query_user_menu "Really create such a CSR?" "yes" "no"
echo -e "$ASSUAN_COMMANDS" | \
gpgsm --no-log-file --debug-level none --debug-none \
gpgsm --no-log-file --debug-level none --debug-none \
--server 4< "$file_parameter" 5>"$outfile" >/dev/null
cat "$outfile"