diff --git a/NEWS b/NEWS index f9d6979fe..015ca1663 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,8 @@ Noteworthy changes in version 2.0.12 (not released) * Better synchronization of several smartcard sessions. + * Support for the Telesec Netkey 3 cards. + Noteworthy changes in version 2.0.11 (2009-03-03) ------------------------------------------------- diff --git a/agent/ChangeLog b/agent/ChangeLog index e91731d5f..c55199135 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,5 +1,9 @@ 2009-03-26 Werner Koch + * agent.h (MAX_DIGEST_LEN): Change to 64. + * command.c (cmd_sethash): Allow digest length of 48 and 64. + (cmd_sethash): Allow more hash algos. + * trustlist.c (reformat_name): New. (agent_marktrusted): Use a reformatted name. Reload the table before the update and always reload it at the end. diff --git a/agent/agent.h b/agent/agent.h index 48b199be0..ba31d9396 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -42,7 +42,7 @@ #define MD_USER_TLS_MD5SHA1 (GCRY_MODULE_ID_USER+1) /* Maximum length of a digest. */ -#define MAX_DIGEST_LEN 36 +#define MAX_DIGEST_LEN 64 /* A large struct name "opt" to keep global flags */ struct diff --git a/agent/command.c b/agent/command.c index b31e40553..56d390bd8 100644 --- a/agent/command.c +++ b/agent/command.c @@ -637,8 +637,14 @@ cmd_sethash (assuan_context_t ctx, char *line) { if (has_option (line, "--hash=sha1")) algo = GCRY_MD_SHA1; + else if (has_option (line, "--hash=sha224")) + algo = GCRY_MD_SHA224; else if (has_option (line, "--hash=sha256")) algo = GCRY_MD_SHA256; + else if (has_option (line, "--hash=sha384")) + algo = GCRY_MD_SHA384; + else if (has_option (line, "--hash=sha512")) + algo = GCRY_MD_SHA512; else if (has_option (line, "--hash=rmd160")) algo = GCRY_MD_RMD160; else if (has_option (line, "--hash=md5")) @@ -671,7 +677,8 @@ cmd_sethash (assuan_context_t ctx, char *line) n /= 2; if (algo == MD_USER_TLS_MD5SHA1 && n == 36) ; - else if (n != 16 && n != 20 && n != 24 && n != 32) + else if (n != 16 && n != 20 && n != 24 + && n != 28 && n != 32 && n != 48 && n != 64) return set_error (GPG_ERR_ASS_PARAMETER, "unsupported length of hash"); if (n > MAX_DIGEST_LEN) diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index 659d546f2..08b1c4568 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -568,6 +568,12 @@ encryption. For convenience the strings @code{3DES}, @code{AES} and @code{AES256} may be used instead of their OIDs. The default is @code{3DES} (1.2.840.113549.3.7). +@item --digest-algo @code{name} +Use @code{name} as the message digest algorithm. Usually this +algorithm is deduced from the respective signing certificate. This +option forces the use of the given algorithm and may lead to severe +interoperability problems. + @end table diff --git a/scd/ChangeLog b/scd/ChangeLog index c12603a59..f6de2599d 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,16 @@ +2009-03-26 Werner Koch + + * command.c (cmd_pksign): Allow more hash algorithms. + + * scdaemon.h (MAX_DIGEST_LEN): Change to 64. + + * apdu.c (open_ccid_reader): Clear the is_to flag. + + * app-nks.c (filelist): Add field KID. + (do_getattr): Change standard authentication key. + (do_sign): Setup a security environment for TCOS 3 cards and support + all SHA-2 algorithms. + 2009-03-24 Werner Koch * command.c (struct server_local_s): Add flag diff --git a/scd/apdu.c b/scd/apdu.c index dfddd3f72..b12b7e951 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -1951,6 +1951,9 @@ open_ccid_reader (const char *portstr) reader_table[slot].send_apdu_reader = send_apdu_ccid; reader_table[slot].check_keypad = check_ccid_keypad; reader_table[slot].dump_status_reader = dump_ccid_reader_status; + /* Our CCID reader code does not support T=0 at all, thus reset the + flag. */ + reader_table[slot].is_t0 = 0; dump_reader_status (slot); return slot; @@ -2839,10 +2842,10 @@ send_le (int slot, int class, int ins, int p0, int p1, if (lc != -1 && (lc > 255 || lc < 0)) { - /* Data does not fit into an APDU. What we do now dependes on + /* Data does not fit into an APDU. What we do now depends on the EXTENDED_MODE parameter. */ if (!extended_mode) - return SW_WRONG_LENGTH; /* No way. to send such an APDU. */ + return SW_WRONG_LENGTH; /* No way to send such an APDU. */ else if (extended_mode > 0) return SW_HOST_NOT_SUPPORTED; /* FIXME. */ else if (extended_mode < 0) diff --git a/scd/app-nks.c b/scd/app-nks.c index 3113d343c..d2ba9789d 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -19,10 +19,11 @@ /* Notes: - - This is still work in progress. We are now targeting TCOS 3 cards - but try to keep compatibility to TCOS 2. Both are not fully - working as of now. TCOS 3 PIN management seems to work. Use GPA - from SVN trunk to test it. + - We are now targeting TCOS 3 cards and it may happen that there is + a regression towards TCOS 2 cards. Please report. + + - The TKS3 AUT key is not used by our authentication command but + accessible via the decrypt command. - If required, we automagically switch between the NKS application and the SigG application. This avoids to use the DINSIG @@ -63,25 +64,26 @@ static struct int fid; /* File ID. */ int nks_ver; /* 0 for NKS version 2, 3 for version 3. */ int certtype; /* Type of certificate or 0 if it is not a certificate. */ - int iskeypair; /* If true has the FID of the correspoding certificate. */ + int iskeypair; /* If true has the FID of the corresponding certificate. */ int issignkey; /* True if file is a key usable for signing. */ int isenckey; /* True if file is a key usable for decryption. */ + unsigned char kid; /* Corresponding key references. */ } filelist[] = { - { 0, 0x4531, 0, 0, 0xC000, 1, 0 }, /* EF_PK.NKS.SIG */ - { 1, 0x4531, 3, 0, 0x0000, 1, 1 }, /* EF_PK.CH.SIG */ - { 0, 0xC000, 0, 101 }, /* EF_C.NKS.SIG */ - { 1, 0xC000, 0, 101 }, /* EF_C.CH.SIG */ + { 0, 0x4531, 0, 0, 0xC000, 1, 0, 0x80 }, /* EF_PK.NKS.SIG */ + { 1, 0x4531, 3, 0, 0x0000, 1, 1, 0x84 }, /* EF_PK.CH.SIG */ + { 0, 0xC000, 0, 101 }, /* EF_C.NKS.SIG */ + { 1, 0xC000, 0, 101 }, /* EF_C.CH.SIG */ { 0, 0x4331, 0, 100 }, { 0, 0x4332, 0, 100 }, - { 0, 0xB000, 0, 110 }, /* EF_PK.RCA.NKS */ - { 0, 0x45B1, 0, 0, 0xC200, 0, 1 }, /* EF_PK.NKS.ENC */ - { 0, 0xC200, 0, 101 }, /* EF_C.NKS.ENC */ + { 0, 0xB000, 0, 110 }, /* EF_PK.RCA.NKS */ + { 0, 0x45B1, 0, 0, 0xC200, 0, 1, 0x81 }, /* EF_PK.NKS.ENC */ + { 0, 0xC200, 0, 101 }, /* EF_C.NKS.ENC */ { 0, 0x43B1, 0, 100 }, { 0, 0x43B2, 0, 100 }, - { 0, 0x4571, 3, 0, 0xc500, 0, 0 }, /* EF_PK.NKS.AUT */ - { 0, 0xC500, 3, 101 }, /* EF_C.NKS.AUT */ - { 0, 0x45B2, 3, 0, 0xC201, 0, 1 }, /* EF_PK.NKS.ENC1024 */ - { 0, 0xC201, 3, 101 }, /* EF_C.NKS.ENC1024 */ + { 0, 0x4571, 3, 0, 0xc500, 0, 0, 0x82 }, /* EF_PK.NKS.AUT */ + { 0, 0xC500, 3, 101 }, /* EF_C.NKS.AUT */ + { 0, 0x45B2, 3, 0, 0xC201, 0, 1, 0x83 }, /* EF_PK.NKS.ENC1024 */ + { 0, 0xC201, 3, 101 }, /* EF_C.NKS.ENC1024 */ /* { 1, 0xB000, 3, ... */ { 0, 0 } }; @@ -303,10 +305,12 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) { case 1: /* $AUTHKEYID */ { - /* NetKey 3.0 cards define this key for authentication. - FIXME: We don't have the readkey command, so this - information is pretty useless. */ - char const tmp[] = "NKS-NKS3.4571"; + /* NetKey 3.0 cards define an authentication key but according + to the specs this key is only usable for encryption and not + signing. it might work anyway but it has not yet been + tested - fixme. Thus for now we use the NKS signature key + for authentication. */ + char const tmp[] = "NKS-NKS3.4531"; send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0); } break; @@ -685,13 +689,18 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, int rc, i; int is_sigg = 0; int fid; - unsigned char data[35]; /* Must be large enough for a SHA-1 digest - + the largest OID _prefix above. */ + unsigned char kid; + unsigned char data[83]; /* Must be large enough for a SHA-1 digest + + the largest OID prefix. */ + size_t datalen; if (!keyidstr || !*keyidstr) return gpg_error (GPG_ERR_INV_VALUE); - if (indatalen != 20 && indatalen != 16 && indatalen != 35) - return gpg_error (GPG_ERR_INV_VALUE); + switch (indatalen) + { + case 16: case 20: case 35: case 47: case 51: case 67: case 83: break; + default: return gpg_error (GPG_ERR_INV_VALUE); + } /* Check that the provided ID is valid. This is not really needed but we do it to enforce correct usage by the caller. */ @@ -721,22 +730,35 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, return gpg_error (GPG_ERR_NOT_FOUND); if (!filelist[i].issignkey) return gpg_error (GPG_ERR_INV_ID); + kid = filelist[i].kid; - /* Prepare the DER object from INDATA. */ - if (indatalen == 35) + /* Prepare the DER object from INDATA. */ + if (app->app_local->nks_version > 2 && (indatalen == 35 + || indatalen == 47 + || indatalen == 51 + || indatalen == 67 + || indatalen == 83)) + { + /* The caller send data matching the length of the ASN.1 encoded + hash for SHA-{1,224,256,384,512}. Assume that is okay. */ + assert (indatalen <= sizeof data); + memcpy (data, indata, indatalen); + datalen = indatalen; + } + else if (indatalen == 35) { /* Alright, the caller was so kind to send us an already - prepared DER object. Check that it is waht we want and that - it matches the hash algorithm. */ + prepared DER object. This is for TCOS 2. */ if (hashalgo == GCRY_MD_SHA1 && !memcmp (indata, sha1_prefix, 15)) ; - else if (hashalgo == GCRY_MD_RMD160 && !memcmp (indata, rmd160_prefix,15)) + else if (hashalgo == GCRY_MD_RMD160 && !memcmp (indata,rmd160_prefix,15)) ; else return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); memcpy (data, indata, indatalen); + datalen = 35; } - else + else if (indatalen == 20) { if (hashalgo == GCRY_MD_SHA1) memcpy (data, sha1_prefix, 15); @@ -745,11 +767,32 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, else return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); memcpy (data+15, indata, indatalen); + datalen = 35; } + else + return gpg_error (GPG_ERR_INV_VALUE); - rc = verify_pin (app, 0, NULL, pincb, pincb_arg); + + /* Send an MSE for PSO:Computer_Signature. */ + if (app->app_local->nks_version > 2) + { + unsigned char mse[6]; + + mse[0] = 0x80; /* Algorithm reference. */ + mse[1] = 1; + mse[2] = 2; /* RSA, card does pkcs#1 v1.5 padding, no ASN.1 check. */ + mse[3] = 0x84; /* Private key reference. */ + mse[4] = 1; + mse[5] = kid; + rc = iso7816_manage_security_env (app->slot, 0x41, 0xB6, + mse, sizeof mse); + } + /* Verify using PW1.CH. */ if (!rc) - rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen); + rc = verify_pin (app, 0, NULL, pincb, pincb_arg); + /* Compute the signature. */ + if (!rc) + rc = iso7816_compute_ds (app->slot, data, datalen, outdata, outdatalen); return rc; } diff --git a/scd/command.c b/scd/command.c index aa0e6350a..07aed176a 100644 --- a/scd/command.c +++ b/scd/command.c @@ -905,7 +905,7 @@ pin_cb (void *opaque, const char *info, char **retstr) } -/* PKSIGN [--hash=[rmd160|sha1|md5]] +/* PKSIGN [--hash=[rmd160|sha{1,224,256,384,512}|md5]] The --hash option is optional; the default is SHA1. @@ -924,6 +924,14 @@ cmd_pksign (assuan_context_t ctx, char *line) hash_algo = GCRY_MD_RMD160; else if (has_option (line, "--hash=sha1")) hash_algo = GCRY_MD_SHA1; + else if (has_option (line, "--hash=sha224")) + hash_algo = GCRY_MD_SHA224; + else if (has_option (line, "--hash=sha256")) + hash_algo = GCRY_MD_SHA256; + else if (has_option (line, "--hash=sha384")) + hash_algo = GCRY_MD_SHA384; + else if (has_option (line, "--hash=sha512")) + hash_algo = GCRY_MD_SHA512; else if (has_option (line, "--hash=md5")) hash_algo = GCRY_MD_MD5; else if (!strstr (line, "--")) diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 7c636920b..c42939643 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -39,7 +39,7 @@ #define MD_USER_TLS_MD5SHA1 (GCRY_MODULE_ID_USER+1) /* Maximum length of a digest. */ -#define MAX_DIGEST_LEN 36 +#define MAX_DIGEST_LEN 64 diff --git a/sm/ChangeLog b/sm/ChangeLog index 0905159ce..9f926cfc7 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,5 +1,12 @@ 2009-03-26 Werner Koch + * gpgsm.c (main): s/def_digest_string/forced_digest_algo/ and + activate the --digest-algo option. + * gpgsm.h (struct opt): s/def_digest_algo/forced_digest_algo/. + * sign.c (gpgsm_sign): Implement --digest-algo. + + * sign.c (MAX_DIGEST_LEN): Change to 64. + * call-agent.c (gpgsm_agent_marktrusted): Format the issuer name. 2009-03-25 Werner Koch diff --git a/sm/gpgsm.c b/sm/gpgsm.c index f49b742c2..8a2a1c0b9 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -843,8 +843,8 @@ main ( int argc, char **argv) int use_random_seed = 1; int no_common_certs_import = 0; int with_fpr = 0; - char *def_digest_string = NULL; - char *extra_digest_algo = NULL; + const char *forced_digest_algo = NULL; + const char *extra_digest_algo = NULL; enum cmd_and_opt_values cmd = 0; struct server_control_s ctrl; certlist_t recplist = NULL; @@ -1301,7 +1301,7 @@ main ( int argc, char **argv) break; case oDigestAlgo: - /* Dummy for now. */ + forced_digest_algo = pargs.r.ret_str; break; case oExtraDigestAlgo: @@ -1460,12 +1460,10 @@ main ( int argc, char **argv) || !gcry_cipher_mode_from_oid (opt.def_cipher_algoid)) log_error (_("selected cipher algorithm is invalid\n")); - if (def_digest_string) + if (forced_digest_algo) { - opt.def_digest_algo = gcry_md_map_name (def_digest_string); - xfree (def_digest_string); - def_digest_string = NULL; - if (our_md_test_algo(opt.def_digest_algo) ) + opt.forced_digest_algo = gcry_md_map_name (forced_digest_algo); + if (our_md_test_algo(opt.forced_digest_algo) ) log_error (_("selected digest algorithm is invalid\n")); } if (extra_digest_algo) diff --git a/sm/gpgsm.h b/sm/gpgsm.h index e9327d217..781561a71 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -33,7 +33,7 @@ #include "../common/estream.h" #include "../common/audit.h" -#define MAX_DIGEST_LEN 24 +#define MAX_DIGEST_LEN 64 struct keyserver_spec { @@ -92,9 +92,10 @@ struct const char *def_cipher_algoid; /* cipher algorithm to use if nothing else is specified */ - int def_digest_algo; /* Ditto for hash algorithm */ int def_compress_algo; /* Ditto for compress algorithm */ + int forced_digest_algo; /* User forced hash algorithm. */ + char *def_recipient; /* userID of the default recipient */ int def_recipient_self; /* The default recipient is the default key */ diff --git a/sm/sign.c b/sm/sign.c index fadd66469..446cd3792 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -399,11 +399,22 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, /* Figure out the hash algorithm to use. We do not want to use the one for the certificate but if possible an OID for the plain algorithm. */ + if (opt.forced_digest_algo && opt.verbose) + log_info ("user requested hash algorithm %d\n", opt.forced_digest_algo); for (i=0, cl=signerlist; cl; cl = cl->next, i++) { const char *oid = ksba_cert_get_digest_algo (cl->cert); - cl->hash_algo = oid ? gcry_md_map_name (oid) : 0; + if (opt.forced_digest_algo) + { + oid = NULL; + cl->hash_algo = opt.forced_digest_algo; + } + else + { + oid = ksba_cert_get_digest_algo (cl->cert); + cl->hash_algo = oid ? gcry_md_map_name (oid) : 0; + } switch (cl->hash_algo) { case GCRY_MD_SHA1: oid = "1.3.14.3.2.26"; break; @@ -427,6 +438,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, } cl->hash_algo_oid = oid; } + if (opt.verbose) { for (i=0, cl=signerlist; cl; cl = cl->next, i++)