diff options
Diffstat (limited to 'sm')
-rw-r--r-- | sm/ChangeLog | 7 | ||||
-rw-r--r-- | sm/call-agent.c | 88 | ||||
-rw-r--r-- | sm/certreqgen.c | 74 | ||||
-rw-r--r-- | sm/gpgsm.h | 5 |
4 files changed, 153 insertions, 21 deletions
diff --git a/sm/ChangeLog b/sm/ChangeLog index 74c5c4302..8bf306e54 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,10 @@ +2006-10-11 Werner Koch <[email protected]> + + * 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 <[email protected]> * Makefile.am (AM_CFLAGS): Use PTH version of libassuan. diff --git a/sm/call-agent.c b/sm/call-agent.c index 35ad1b83b..47f53041d 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -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); diff --git a/sm/certreqgen.c b/sm/certreqgen.c index e1006753e..f0221d3fd 100644 --- a/sm/certreqgen.c +++ b/sm/certreqgen.c @@ -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)); diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 541783dd7..d92bf5923 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -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); |