* 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.
This commit is contained in:
David Shaw 2006-04-20 21:32:42 +00:00
parent b625a6d1a9
commit 0f1c0a9f28
5 changed files with 145 additions and 34 deletions

View File

@ -1,3 +1,21 @@
2006-04-20 David Shaw <dshaw@jabberwocky.com>
* 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 <dshaw@jabberwocky.com>
* gpg.c (print_mds), armor.c (armor_filter, parse_hash_header):

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;
}