diff options
author | David Shaw <[email protected]> | 2002-06-04 23:18:37 +0000 |
---|---|---|
committer | David Shaw <[email protected]> | 2002-06-04 23:18:37 +0000 |
commit | fd08b135280dfa810e641db7b09062a945c9c2b0 (patch) | |
tree | 93d797b2e617a43a03d519afe90bb1dd170da834 | |
parent | forgot the changelog :) (diff) | |
download | gnupg-fd08b135280dfa810e641db7b09062a945c9c2b0.tar.gz gnupg-fd08b135280dfa810e641db7b09062a945c9c2b0.zip |
* sign.c (hash_for, sign_file): When encrypting and signing at the same
time, consult the various hash prefs to pick a hash algorithm to use.
Pass in a 160-bit hint if any of the signing keys are DSA.
* keydb.h, pkclist.c (select_algo_from_prefs, algo_available): Pass a
"hints" opaque pointer in to let the caller give hints as to what
algorithms would be acceptable. The only current hint is for
PREFTYPE_HASH to require a 160-bit hash for DSA. Change all callers in
encode.c (encode_crypt, encrypt_filter) and sign.c (sign_file). If we
settle on MD5 as the best algorithm based solely on recepient keys and
SHA1 is also a possibility, use SHA1 unless the user intentionally chose
MD5. This is as per 2440:13.
* exec.c (make_tempdir): Fix duplicated filename problem.
-rw-r--r-- | g10/ChangeLog | 18 | ||||
-rw-r--r-- | g10/encode.c | 7 | ||||
-rw-r--r-- | g10/exec.c | 16 | ||||
-rw-r--r-- | g10/keydb.h | 2 | ||||
-rw-r--r-- | g10/pkclist.c | 62 | ||||
-rw-r--r-- | g10/sign.c | 30 |
6 files changed, 115 insertions, 20 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog index b9e82eae4..cdc62aa35 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,21 @@ +2002-06-04 David Shaw <[email protected]> + + * sign.c (hash_for, sign_file): When encrypting and signing at the + same time, consult the various hash prefs to pick a hash algorithm + to use. Pass in a 160-bit hint if any of the signing keys are + DSA. + + * keydb.h, pkclist.c (select_algo_from_prefs, algo_available): + Pass a "hints" opaque pointer in to let the caller give hints as + to what algorithms would be acceptable. The only current hint is + for PREFTYPE_HASH to require a 160-bit hash for DSA. Change all + callers in encode.c (encode_crypt, encrypt_filter) and sign.c + (sign_file). If we settle on MD5 as the best algorithm based + solely on recepient keys and SHA1 is also a possibility, use SHA1 + unless the user intentionally chose MD5. This is as per 2440:13. + + * exec.c (make_tempdir): Fix duplicated filename problem. + 2002-06-03 David Shaw <[email protected]> * packet.h, parse-packet.c (enum_sig_subpkt): Report back from diff --git a/g10/encode.c b/g10/encode.c index 8033201d4..141e4363f 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -336,7 +336,7 @@ encode_crypt( const char *filename, STRLIST remusr ) /* create a session key */ cfx.dek = m_alloc_secure_clear (sizeof *cfx.dek); if( !opt.def_cipher_algo ) { /* try to get it from the prefs */ - cfx.dek->algo = select_algo_from_prefs( pk_list, PREFTYPE_SYM ); + cfx.dek->algo = select_algo_from_prefs( pk_list, PREFTYPE_SYM, NULL ); /* The only way select_algo_from_prefs can fail here is when mixing v3 and v4 keys, as v4 keys have an implicit preference entry for 3DES, and the pk_list cannot be empty. @@ -415,7 +415,8 @@ encode_crypt( const char *filename, STRLIST remusr ) if(compr_algo==-1) { - if((compr_algo=select_algo_from_prefs( pk_list, PREFTYPE_ZIP))==-1) + if((compr_algo= + select_algo_from_prefs(pk_list,PREFTYPE_ZIP,NULL))==-1) compr_algo=DEFAULT_COMPRESS_ALGO; } @@ -485,7 +486,7 @@ encrypt_filter( void *opaque, int control, if( !opt.def_cipher_algo ) { /* try to get it from the prefs */ efx->cfx.dek->algo = - select_algo_from_prefs( efx->pk_list, PREFTYPE_SYM ); + select_algo_from_prefs( efx->pk_list, PREFTYPE_SYM, NULL ); if( efx->cfx.dek->algo == -1 ) { /* because 3DES is implicitly in the prefs, this can only * happen if we do not have any public keys in the list */ diff --git a/g10/exec.c b/g10/exec.c index 8aa87dd0c..d8111bdca 100644 --- a/g10/exec.c +++ b/g10/exec.c @@ -93,10 +93,12 @@ static int win_system(const char *command) /* Makes a temp directory and filenames */ static int make_tempdir(struct exec_info *info) { - char *tmp=opt.temp_dir,*name=info->name; + char *tmp=opt.temp_dir,*namein=info->name,*nameout; - if(!name) - name=info->binary?"tempfile" EXTSEP_S "bin":"tempfile" EXTSEP_S "txt"; + if(!namein) + namein=info->binary?"tempin" EXTSEP_S "bin":"tempin" EXTSEP_S "txt"; + + nameout=info->binary?"tempout" EXTSEP_S "bin":"tempout" EXTSEP_S "txt"; /* Make up the temp dir and files in case we need them */ @@ -151,14 +153,14 @@ static int make_tempdir(struct exec_info *info) info->madedir=1; info->tempfile_in=m_alloc(strlen(info->tempdir)+ - strlen(DIRSEP_S)+strlen(name)+1); - sprintf(info->tempfile_in,"%s" DIRSEP_S "%s",info->tempdir,name); + strlen(DIRSEP_S)+strlen(namein)+1); + sprintf(info->tempfile_in,"%s" DIRSEP_S "%s",info->tempdir,namein); if(!info->writeonly) { info->tempfile_out=m_alloc(strlen(info->tempdir)+ - strlen(DIRSEP_S)+strlen(name)+1); - sprintf(info->tempfile_out,"%s" DIRSEP_S "%s",info->tempdir,name); + strlen(DIRSEP_S)+strlen(nameout)+1); + sprintf(info->tempfile_out,"%s" DIRSEP_S "%s",info->tempdir,nameout); } } diff --git a/g10/keydb.h b/g10/keydb.h index ee2f0c8af..dc7863a99 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -166,7 +166,7 @@ void show_revocation_reason( PKT_public_key *pk, int mode ); int check_signatures_trust( PKT_signature *sig ); void release_pk_list( PK_LIST pk_list ); int build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use ); -int select_algo_from_prefs( PK_LIST pk_list, int preftype ); +int select_algo_from_prefs( PK_LIST pk_list, int preftype, void *hint ); int select_mdc_from_pklist (PK_LIST pk_list); /*-- skclist.c --*/ diff --git a/g10/pkclist.c b/g10/pkclist.c index 190faaec9..f3b247850 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -970,7 +970,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use ) such a broken preference list, so I'm including it. -dms */ static int -algo_available( int preftype, int algo ) +algo_available( int preftype, int algo, void *hint ) { if( preftype == PREFTYPE_SYM ) { if( opt.pgp6 && ( algo != 1 && algo != 2 && algo != 3) ) @@ -983,6 +983,14 @@ algo_available( int preftype, int algo ) return algo && !check_cipher_algo( algo ); } else if( preftype == PREFTYPE_HASH ) { + int bits=0; + + if(hint) + bits=*(int *)hint; + + if(bits && (bits != md_digest_length(algo))) + return 0; + if( (opt.pgp6 || opt.pgp7 ) && ( algo != 1 && algo != 2 && algo != 3) ) return 0; @@ -1004,7 +1012,7 @@ algo_available( int preftype, int algo ) * Return -1 if we could not find an algorithm. */ int -select_algo_from_prefs( PK_LIST pk_list, int preftype ) +select_algo_from_prefs( PK_LIST pk_list, int preftype, void *hint ) { PK_LIST pkr; u32 bits[8]; @@ -1022,9 +1030,9 @@ select_algo_from_prefs( PK_LIST pk_list, int preftype ) memset( mask, 0, 8 * sizeof *mask ); if( preftype == PREFTYPE_SYM ) { - if( pkr->pk->version < 4 && - pkr->pk->selfsigversion < 4 && - opt.pgp2 ) + if( opt.pgp2 && + pkr->pk->version < 4 && + pkr->pk->selfsigversion < 4 ) mask[0] |= (1<<1); /* IDEA is implicitly there for v3 keys with v3 selfsigs (rfc2440:12.1) if --pgp2 mode is on. This doesn't @@ -1033,6 +1041,21 @@ select_algo_from_prefs( PK_LIST pk_list, int preftype ) else mask[0] |= (1<<2); /* 3DES is implicitly there for everyone else */ } + else if( preftype == PREFTYPE_HASH ) { + /* While I am including this code for completeness, note + that currently --pgp2 mode locks the hash at MD5, so this + function will never even be called. Even if the hash + wasn't locked at MD5, we don't support sign+encrypt in + --pgp2 mode, and that's the only time PREFTYPE_HASH is + used anyway. -dms */ + if( opt.pgp2 && + pkr->pk->version < 4 && + pkr->pk->selfsigversion < 4 ) + mask[0] |= (1<<1); /* MD5 is there for v3 keys with v3 + selfsigs when --pgp2 is on. */ + else + mask[0] |= (1<<2); /* SHA1 is there for everyone else */ + } else if( preftype == PREFTYPE_ZIP ) mask[0] |= (1<<0); /* Uncompressed is implicit */ @@ -1086,7 +1109,7 @@ select_algo_from_prefs( PK_LIST pk_list, int preftype ) for(j=0; prefs[j].type; j++ ) { if( prefs[j].type == preftype ) { if( (bits[prefs[j].value/32] & (1<<(prefs[j].value%32))) ) { - if( algo_available( preftype, prefs[j].value ) ) { + if( algo_available( preftype, prefs[j].value, hint ) ) { any = 1; i = prefs[j].value; break; @@ -1098,7 +1121,7 @@ select_algo_from_prefs( PK_LIST pk_list, int preftype ) if( !prefs || !any ) { for(j=0; j < 256; j++ ) if( (bits[j/32] & (1<<(j%32))) ) { - if( algo_available( preftype, j ) ) { + if( algo_available( preftype, j, hint ) ) { i = j; break; } @@ -1115,6 +1138,29 @@ select_algo_from_prefs( PK_LIST pk_list, int preftype ) i = 1; /* yep; we can use compression algo 1 */ } + /* "If you are building an authentication system, the recipient + may specify a preferred signing algorithm. However, the signer + would be foolish to use a weak algorithm simply because the + recipient requests it." RFC2440:13. If we settle on MD5, and + SHA1 is also available, use SHA1 instead. Of course, if the + user intentinally chose MD5 (by putting it in their personal + prefs), then we should do what they say. */ + + if(preftype==PREFTYPE_HASH && + i==DIGEST_ALGO_MD5 && (bits[0] & (1<<DIGEST_ALGO_SHA1))) + { + i=DIGEST_ALGO_SHA1; + + if(opt.personal_prefs) + for(j=0; prefs[j].type; j++ ) + if(opt.personal_prefs[j].type==PREFTYPE_HASH && + opt.personal_prefs[j].value==DIGEST_ALGO_MD5) + { + i=DIGEST_ALGO_MD5; + break; + } + } + return i; } @@ -1138,7 +1184,7 @@ select_mdc_from_pklist (PK_LIST pk_list) else mdc = pkr->pk->mdc_feature; if (!mdc) - return 0; /* at least on recipeint does not support it */ + return 0; /* at least one recipient does not support it */ } return 1; /* can be used */ } diff --git a/g10/sign.c b/g10/sign.c index 6cf1c8804..cfab80066 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -49,6 +49,8 @@ #define LF "\n" #endif +static int recipient_digest_algo=0; + /**************** * Create a notation. It is assumed that the stings in STRLIST * are already checked to contain only printable data and have a valid @@ -332,6 +334,8 @@ hash_for(int pubkey_algo, int packet_version ) { if( opt.def_digest_algo ) return opt.def_digest_algo; + if( recipient_digest_algo ) + return recipient_digest_algo; if( pubkey_algo == PUBKEY_ALGO_DSA ) return DIGEST_ALGO_SHA1; if( pubkey_algo == PUBKEY_ALGO_RSA && packet_version < 4 ) @@ -673,6 +677,28 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, iobuf_push_filter( inp, text_filter, &tfx ); mfx.md = md_open(0, 0); + /* If we're encrypting and signing, it is reasonable to pick the + hash algorithm to use out of the recepient key prefs. */ + if(pk_list && !opt.def_digest_algo) + { + 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 */ + + for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) + if(sk_rover->sk->pubkey_algo==PUBKEY_ALGO_DSA) + hashlen=20; + + if((algo=select_algo_from_prefs(pk_list,PREFTYPE_HASH,&hashlen))>0) + recipient_digest_algo=algo; + } + for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) { PKT_secret_key *sk = sk_rover->sk; md_enable(mfx.md, hash_for(sk->pubkey_algo, sk->version )); @@ -707,7 +733,8 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, Still, if it did fail, we'll also end up with the default. */ - if((compr_algo=select_algo_from_prefs( pk_list, PREFTYPE_ZIP))==-1) + if((compr_algo= + select_algo_from_prefs(pk_list,PREFTYPE_ZIP,NULL))==-1) compr_algo=DEFAULT_COMPRESS_ALGO; } @@ -788,6 +815,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, md_close( mfx.md ); release_sk_list( sk_list ); release_pk_list( pk_list ); + recipient_digest_algo=0; return rc; } |