diff --git a/g10/ChangeLog b/g10/ChangeLog index 50bbefc4b..89d63276b 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,21 @@ +2006-04-20 David Shaw + + * options.h, gpg.c (main): Add --enable-dsa2 and --disable-dsa2. + Defaults to disable. + + * pkclist.c (algo_available): If --enable-dsa2 is set, we're + allowed to truncate hashes to fit DSA keys. + + * sign.c (match_dsa_hash): New. Return the best match hash for a + given q size. + (do_sign, hash_for, sign_file): When signing with a DSA key, if it + has q==160, assume it is an old DSA key and don't allow truncation + unless --enable-dsa2 is also set. q!=160 always allows truncation + since they must be DSA2 keys. + (make_keysig_packet): If the user doesn't specify a + --cert-digest-algo, use match_dsa_hash to pick the best hash for + key signatures. + 2006-04-19 David Shaw * gpg.c (print_mds), armor.c (armor_filter, parse_hash_header): diff --git a/g10/gpg.c b/g10/gpg.c index 276a35b43..ac4df6b41 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -362,6 +362,8 @@ enum cmd_and_opt_values oAutoKeyLocate, oNoAutoKeyLocate, oAllowMultisigVerification, + oEnableDSA2, + oDisableDSA2, oNoop }; @@ -699,6 +701,8 @@ static ARGPARSE_OPTS opts[] = { { oDebugCCIDDriver, "debug-ccid-driver", 0, "@"}, #endif { oAllowMultisigVerification, "allow-multisig-verification", 0, "@"}, + { oEnableDSA2, "enable-dsa2", 0, "@"}, + { oDisableDSA2, "disable-dsa2", 0, "@"}, /* These two are aliases to help users of the PGP command line product use gpg with minimal pain. Many commands are common @@ -2659,6 +2663,9 @@ main (int argc, char **argv ) opt.allow_multisig_verification = 1; break; + case oEnableDSA2: opt.flags.dsa2=1; break; + case oDisableDSA2: opt.flags.dsa2=0; break; + case oNoop: break; default : pargs.err = configfp? 1:2; break; diff --git a/g10/options.h b/g10/options.h index 06ea29130..6c69d80aa 100644 --- a/g10/options.h +++ b/g10/options.h @@ -222,6 +222,7 @@ struct unsigned int require_cross_cert:1; unsigned int use_embedded_filename:1; unsigned int utf8_filename:1; + unsigned int dsa2:1; } flags; /* Linked list of ways to find a key if the key isn't on the local diff --git a/g10/pkclist.c b/g10/pkclist.c index 5cce7f209..7f3285bf9 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -1,6 +1,6 @@ /* pkclist.c - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, - * 2004, 2005 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, + * 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -1210,8 +1210,20 @@ algo_available( preftype_t preftype, int algo, void *hint ) } else if( preftype == PREFTYPE_HASH ) { - if(hint && ((*(int *)hint) != md_digest_length(algo))) - return 0; + if(hint) + { + if(opt.flags.dsa2) + { + /* If --enable-dsa2 is set, then we'll accept a hash + that is larger than we need. If --enable-dsa2 is not + set, then we won't accept any hash that isn't exactly + the right size. */ + if((*(int *)hint) > md_digest_length(algo)) + return 0; + } + else if(((*(int *)hint) != md_digest_length(algo))) + return 0; + } if((PGP6 || PGP7) && (algo != DIGEST_ALGO_MD5 && algo != DIGEST_ALGO_SHA1 diff --git a/g10/sign.c b/g10/sign.c index 9552602a9..5ef791004 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -319,10 +319,15 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig, } else { - /* TODO: remove this check in the future once all the - variable-q DSA stuff makes it into the standard. */ - if(!opt.expert - && sk->pubkey_algo==PUBKEY_ALGO_DSA + /* If it's a DSA key, and q is 160 bits, it might be an + old-style DSA key. If the hash doesn't match the q, fail + unless --enable-dsa2 is set. If the q isn't 160 bits, then + allow any hash since it must be a DSA2 key (if the hash is + too small, we'll fail in encode_md_value). */ + + if(sk->pubkey_algo==PUBKEY_ALGO_DSA + && (mpi_get_nbits(sk->skey[1])/8)==20 + && !opt.flags.dsa2 && md_digest_length(digest_algo)!=20) { log_error(_("DSA requires the use of a 160 bit hash algorithm\n")); @@ -384,6 +389,29 @@ complete_sig( PKT_signature *sig, PKT_secret_key *sk, MD_HANDLE md ) return rc; } +static int +match_dsa_hash(unsigned int qbytes) +{ + if(qbytes<=20) + return DIGEST_ALGO_SHA1; +#ifdef USE_SHA256 + if(qbytes<=28) + return DIGEST_ALGO_SHA224; + if(qbytes<=32) + return DIGEST_ALGO_SHA256; +#endif +#ifdef USE_SHA512 + if(qbytes<=48) + return DIGEST_ALGO_SHA384; + if(qbytes<=64) + return DIGEST_ALGO_SHA512; +#endif + return DEFAULT_DIGEST_ALGO; + /* DEFAULT_DIGEST_ALGO will certainly fail, but it's the best wrong + answer we have if the larger SHAs aren't there. */ +} + + /* First try --digest-algo. If that isn't set, see if the recipient has a preferred algorithm (which is also filtered through @@ -405,21 +433,50 @@ hash_for(PKT_secret_key *sk) return opt.def_digest_algo; else if( recipient_digest_algo ) return recipient_digest_algo; - else if(sk->pubkey_algo==PUBKEY_ALGO_DSA - || (sk->is_protected && sk->protect.s2k.mode==1002)) + else if(sk->pubkey_algo==PUBKEY_ALGO_DSA) { - /* The sk lives on a smartcard, or it's a DSA key. DSA requires - a 160-bit hash, and current smartcards only handle SHA-1 and - RIPEMD/160 (i.e. 160-bit hashes). This is correct now, but - may need revision as the cards add algorithms and/or DSA is - expanded to use larger hashes. */ + unsigned int qbytes=mpi_get_nbits(sk->skey[1])/8; + + /* It's a DSA key, so find a hash that is the same size as q or + larger. If q is 160, assume it is an old DSA key and use a + 160-bit hash unless --enable-dsa2 is set, in which case act + like a new DSA key that just happens to have a 160-bit q + (i.e. allow truncation). If q is not 160, by definition it + must be a new DSA key. */ + + if(opt.personal_digest_prefs) + { + prefitem_t *prefs; + + if(qbytes!=20 || opt.flags.dsa2) + { + for(prefs=opt.personal_digest_prefs;prefs->type;prefs++) + if(md_digest_length(prefs->value)>=qbytes) + return prefs->value; + } + else + { + for(prefs=opt.personal_digest_prefs;prefs->type;prefs++) + if(md_digest_length(prefs->value)==qbytes) + return prefs->value; + } + } + + return match_dsa_hash(qbytes); + } + else if(sk->is_protected && sk->protect.s2k.mode==1002) + { + /* The sk lives on a smartcard, and current smartcards only + handle SHA-1 and RIPEMD/160. This is correct now, but may + need revision as the cards add algorithms. */ if(opt.personal_digest_prefs) { prefitem_t *prefs; for(prefs=opt.personal_digest_prefs;prefs->type;prefs++) - if(md_digest_length(prefs->value)==20) + if(prefs->value==DIGEST_ALGO_SHA1 + || prefs->value==DIGEST_ALGO_RMD160) return prefs->value; } @@ -822,22 +879,35 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, int hashlen=0,algo; /* Of course, if the recipient asks for something - unreasonable (like a non-160-bit hash for DSA, for - example), then don't do it. Check all sk's - if any - are DSA, then the hash must be 160-bit. In the future - this can be more complex with different hashes for each - sk, but so long as there is only one signing algorithm - with hash restrictions, this is ok. -dms */ - - /* Current smartcards only do 160-bit hashes as well. - Note that this may well have to change as the cards add - algorithms. */ + unreasonable (like a non-160-bit hash for DSA without + --enable-dsa2, for example), then don't do it. Check + all sk's - if any are DSA, then the hash has + restrictions. In the future this can be more complex + with different hashes for each sk, but so long as there + is only one signing algorithm with hash restrictions, + this is ok. -dms */ for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) - if(sk_rover->sk->pubkey_algo==PUBKEY_ALGO_DSA - || (sk_rover->sk->is_protected - && sk_rover->sk->protect.s2k.mode==1002)) - hashlen=20; + { + if(sk_rover->sk->pubkey_algo==PUBKEY_ALGO_DSA) + { + if(opt.flags.dsa2) + hashlen=mpi_get_nbits(sk_rover->sk->skey[1])/8; + else + hashlen=20; + break; + } + else if(sk_rover->sk->is_protected + && sk_rover->sk->protect.s2k.mode==1002) + { + /* Current smartcards only do 160-bit hashes. + Note that this may well have to change as the + cards add algorithms. */ + + hashlen=20; + break; + } + } if((algo= select_algo_from_prefs(pk_list,PREFTYPE_HASH,-1, @@ -1350,16 +1420,19 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk, { /* Basically, this means use SHA1 always unless it's a v3 RSA key making a v3 cert (use MD5), or the user specified - something (use whatever they said). They still must use a - 160-bit hash with DSA, or the signature will fail. Note - that this still allows the caller of make_keysig_packet to - override the user setting if it must. */ + something (use whatever they said), or it's DSA (use the + best match). They still can't pick an inappropriate hash + for DSA or the signature will fail. Note that this still + allows the caller of make_keysig_packet to override the + user setting if it must. */ if(opt.cert_digest_algo) digest_algo=opt.cert_digest_algo; else if(sk->pubkey_algo==PUBKEY_ALGO_RSA && pk->version<4 && sigversion<4) digest_algo = DIGEST_ALGO_MD5; + else if(sk->pubkey_algo==PUBKEY_ALGO_DSA) + digest_algo = match_dsa_hash(mpi_get_nbits(sk->skey[1])/8); else digest_algo = DIGEST_ALGO_SHA1; }