diff options
Diffstat (limited to '')
-rw-r--r-- | g10/sign.c | 133 |
1 files changed, 103 insertions, 30 deletions
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; } |