diff --git a/g10/ChangeLog b/g10/ChangeLog index 6259bdc20..b8f789e8b 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,59 @@ +2006-04-28 David Shaw (wk) + + * keyserver.c (direct_uri_map): New. + (keyserver_spawn): Used here to add "_uri" to certain gpgkeys_xxx + helpers when the meaning is different if a path is provided (i.e. + ldap). + (keyserver_import_cert): Show warning if there is a CERT + fingerprint, but no --keyserver set. + + * keyserver.c: Fix build problem with platforms that stick libcurl + in a place not in the regular include search path. + + * 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. + + * gpg.c (print_mds): Add SHA-224. + * armor.c (armor_filter, parse_hash_header): Add SHA-224. + + * sign.c (write_plaintext_packet): + Factor common literal packet setup code from here, to... + * encode.c (encode_simple): .. there. + + * main.h, plaintext.c (setup_plaintext_name): Here. New. Make sure + the literal packet filename field is UTF-8 encoded. + + * options.h, gpg.c (main): Make sure --set-filename is UTF-8 + encoded and note when filenames are already UTF-8. + + * keyedit.c (menu_backsign): Give some more verbose errors when we + have no need to backsign. + + * getkey.c (parse_auto_key_locate): Fix dupe-removal code. + + * keyedit.c (menu_backsign): Allow backsigning even if the secret + subkey doesn't have a binding signature. + + * armor.c (radix64_read): Don't report EOF when reading only a pad + (=) character. The EOF actually starts after the pad. + + * gpg.c (main): Make --export, --send-keys, --recv-keys, + --refresh-keys, and --fetch-keys follow their arguments from left + to right. Suggested by Peter Palfrader. + 2006-04-18 Werner Koch * tdbio.c (open_db, migrate_from_v2): Removed feature to migration diff --git a/g10/armor.c b/g10/armor.c index a154c5cfe..e02591372 100644 --- a/g10/armor.c +++ b/g10/armor.c @@ -1,6 +1,6 @@ /* armor.c - Armor flter - * 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. * @@ -242,12 +242,14 @@ parse_hash_header( const char *line ) found |= 2; else if( !strncmp( s, "MD5", s2-s ) ) found |= 4; - else if( !strncmp( s, "SHA256", s2-s ) ) + else if( !strncmp( s, "SHA224", s2-s ) ) found |= 8; - else if( !strncmp( s, "SHA384", s2-s ) ) + else if( !strncmp( s, "SHA256", s2-s ) ) found |= 16; - else if( !strncmp( s, "SHA512", s2-s ) ) + else if( !strncmp( s, "SHA384", s2-s ) ) found |= 32; + else if( !strncmp( s, "SHA512", s2-s ) ) + found |= 64; else return 0; for(; *s2 && (*s2==' ' || *s2 == '\t'); s2++ ) @@ -676,7 +678,7 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, int checkcrc=0; int rc = 0; size_t n = 0; - int idx, i; + int idx, i, onlypad=0; u32 crc; crc = afx->crc; @@ -720,6 +722,8 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, goto again; } } + else if(n==0) + onlypad=1; if( idx == 1 ) buf[n++] = val; @@ -848,7 +852,7 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, } } - if( !n ) + if( !n && !onlypad ) rc = -1; *retn = n; @@ -951,10 +955,12 @@ armor_filter( void *opaque, int control, if( hashes & 4 ) buf[n++] = DIGEST_ALGO_MD5; if( hashes & 8 ) - buf[n++] = DIGEST_ALGO_SHA256; + buf[n++] = DIGEST_ALGO_SHA224; if( hashes & 16 ) - buf[n++] = DIGEST_ALGO_SHA384; + buf[n++] = DIGEST_ALGO_SHA256; if( hashes & 32 ) + buf[n++] = DIGEST_ALGO_SHA384; + if( hashes & 64 ) buf[n++] = DIGEST_ALGO_SHA512; buf[1] = n - 2; diff --git a/g10/encode.c b/g10/encode.c index bb3e7bbc2..292e2bc5a 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -1,6 +1,6 @@ /* encode.c - encode data - * 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. * @@ -278,22 +278,8 @@ encode_simple( const char *filename, int mode, int use_seskey ) xfree(enc); } - if (!opt.no_literal) { - /* setup the inner packet */ - if( filename || opt.set_filename ) { - char *s = make_basename( opt.set_filename ? opt.set_filename - : filename, - iobuf_get_real_fname( inp ) ); - pt = xmalloc( sizeof *pt + strlen(s) - 1 ); - pt->namelen = strlen(s); - memcpy(pt->name, s, pt->namelen ); - xfree(s); - } - else { /* no filename */ - pt = xmalloc( sizeof *pt - 1 ); - pt->namelen = 0; - } - } + if (!opt.no_literal) + pt=setup_plaintext_name(filename,inp); /* Note that PGP 5 has problems decrypting symmetrically encrypted data if the file length is in the inner packet. It works when diff --git a/g10/getkey.c b/g10/getkey.c index acd992c21..bff2a0ddc 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -2948,7 +2948,7 @@ parse_auto_key_locate(char *options) while((tok=optsep(&options))) { - struct akl *akl,*last; + struct akl *akl,*check,*last=NULL; int dupe=0; if(tok[0]=='\0') @@ -2977,13 +2977,13 @@ parse_auto_key_locate(char *options) } /* We must maintain the order the user gave us */ - for(last=opt.auto_key_locate;last && last->next;last=last->next) + for(check=opt.auto_key_locate;check;last=check,check=check->next) { /* Check for duplicates */ - if(last && last->type==akl->type + if(check->type==akl->type && (akl->type!=AKL_SPEC || (akl->type==AKL_SPEC - && strcmp(last->spec->uri,akl->spec->uri)==0))) + && strcmp(check->spec->uri,akl->spec->uri)==0))) { dupe=1; free_akl(akl); diff --git a/g10/gpg.c b/g10/gpg.c index 49687fff1..25b55b705 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -354,6 +354,8 @@ enum cmd_and_opt_values oAutoKeyLocate, oNoAutoKeyLocate, oAllowMultisigVerification, + oEnableDSA2, + oDisableDSA2, oNoop }; @@ -684,6 +686,8 @@ static ARGPARSE_OPTS opts[] = { { oLimitCardInsertTries, "limit-card-insert-tries", 1, "@"}, { 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 @@ -2169,7 +2173,12 @@ main (int argc, char **argv ) case oCompressSigs: opt.compress_sigs = 1; break; case oRFC2440Text: opt.rfc2440_text=1; break; case oNoRFC2440Text: opt.rfc2440_text=0; break; - case oSetFilename: opt.set_filename = pargs.r.ret_str; break; + case oSetFilename: + if(utf8_strings) + opt.set_filename = pargs.r.ret_str; + else + opt.set_filename = native_to_utf8(pargs.r.ret_str); + break; case oForYourEyesOnly: eyes_only = 1; break; case oNoForYourEyesOnly: eyes_only = 0; break; case oSetPolicyURL: @@ -2195,8 +2204,12 @@ main (int argc, char **argv ) opt.verify_options&=~VERIFY_SHOW_POLICY_URLS; break; case oSigKeyserverURL: add_keyserver_url(pargs.r.ret_str,0); break; - case oUseEmbeddedFilename: opt.use_embedded_filename = 1; break; - case oNoUseEmbeddedFilename: opt.use_embedded_filename = 0; break; + case oUseEmbeddedFilename: + opt.flags.use_embedded_filename=1; + break; + case oNoUseEmbeddedFilename: + opt.flags.use_embedded_filename=0; + break; case oComment: if(pargs.r.ret_str[0]) append_to_strlist(&opt.comments,pargs.r.ret_str); @@ -2639,6 +2652,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; @@ -3086,6 +3102,9 @@ main (int argc, char **argv ) fname = argc? *argv : NULL; + if(fname && utf8_strings) + opt.flags.utf8_filename=1; + switch( cmd ) { case aPrimegen: case aPrintMD: @@ -3390,12 +3409,17 @@ main (int argc, char **argv ) import_keys( argc? argv:NULL, argc, NULL, opt.import_options ); break; + /* TODO: There are a number of command that use this same + "make strlist, call function, report error, free strlist" + pattern. Join them together here and avoid all that + duplicated code. */ + case aExport: case aSendKeys: case aRecvKeys: sl = NULL; for( ; argc; argc--, argv++ ) - add_to_strlist2( &sl, *argv, utf8_strings ); + append_to_strlist2( &sl, *argv, utf8_strings ); if( cmd == aSendKeys ) rc=keyserver_export( sl ); else if( cmd == aRecvKeys ) @@ -3427,7 +3451,7 @@ main (int argc, char **argv ) case aRefreshKeys: sl = NULL; for( ; argc; argc--, argv++ ) - add_to_strlist2( &sl, *argv, utf8_strings ); + append_to_strlist2( &sl, *argv, utf8_strings ); rc=keyserver_refresh(sl); if(rc) log_error(_("keyserver refresh failed: %s\n"),g10_errstr(rc)); @@ -3437,7 +3461,7 @@ main (int argc, char **argv ) case aFetchKeys: sl = NULL; for( ; argc; argc--, argv++ ) - add_to_strlist2( &sl, *argv, utf8_strings ); + append_to_strlist2( &sl, *argv, utf8_strings ); rc=keyserver_fetch(sl); if(rc) log_error("key fetch failed: %s\n",g10_errstr(rc)); @@ -3913,6 +3937,7 @@ print_mds( const char *fname, int algo ) gcry_md_enable (md, GCRY_MD_SHA1); gcry_md_enable (md, GCRY_MD_RMD160); #ifdef USE_SHA256 + gcry_md_enable (md, DIGEST_ALGO_SHA224); gcry_md_enable (md, GCRY_MD_SHA256); #endif #ifdef USE_SHA512 @@ -3935,6 +3960,8 @@ print_mds( const char *fname, int algo ) print_hashline( md, GCRY_MD_SHA1, fname ); print_hashline( md, GCRY_MD_RMD160, fname ); #ifdef USE_SHA256 + if (!gcry_md_test_algo (DIGEST_ALGO_SHA224) + print_hashline (md, DIGEST_ALGO_SHA224, fname); print_hashline( md, GCRY_MD_SHA256, fname ); #endif #ifdef USE_SHA512 @@ -3951,6 +3978,8 @@ print_mds( const char *fname, int algo ) print_hex( md, GCRY_MD_SHA1, fname ); print_hex( md, GCRY_MD_RMD160, fname ); #ifdef USE_SHA256 + if (!gcry_md_test_algo (DIGEST_ALGO_SHA224) + print_hex (md, DIGEST_ALGO_SHA224, fname); print_hex( md, GCRY_MD_SHA256, fname ); #endif #ifdef USE_SHA512 diff --git a/g10/keyedit.c b/g10/keyedit.c index bfe3f8546..80d714adc 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -3661,10 +3661,21 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock) } /* Find a signing subkey with no backsig */ - if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY - && (node->pkt->pkt.public_key->pubkey_usage&PUBKEY_USAGE_SIG) - && !node->pkt->pkt.public_key->backsig) - sub_pk=node->pkt->pkt.public_key; + if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY) + { + if(node->pkt->pkt.public_key->pubkey_usage&PUBKEY_USAGE_SIG) + { + if(node->pkt->pkt.public_key->backsig) + tty_printf(_("signing subkey %s is already cross-certified\n"), + keystr_from_pk(node->pkt->pkt.public_key)); + else + sub_pk=node->pkt->pkt.public_key; + } + else + tty_printf(_("subkey %s does not sign and so does" + " not need to be cross-certified\n"), + keystr_from_pk(node->pkt->pkt.public_key)); + } if(!sub_pk) continue; @@ -3693,7 +3704,11 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock) } if(!sub_sk) - continue; + { + tty_printf(_("no secret subkey for public subkey %s - ignoring\n"), + keystr_from_pk(sub_pk)); + continue; + } /* Now finally find the matching selfsig on the secret subkey. We can't use chosen_selfsig here (it's not set for secret @@ -3712,11 +3727,8 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock) break; } - if(!sig_sk) - continue; - /* Now we can get to work. We have a main key and secret part, - a signing subkey with signature and secret part with + a signing subkey with signature and secret part possibly with signature. */ passphrase=get_last_passphrase(); @@ -3745,13 +3757,16 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock) xfree(sig_pk->pkt); sig_pk->pkt=newpkt; - /* Put the new sig into place on the seckey */ - newpkt=xmalloc_clear(sizeof(*newpkt)); - newpkt->pkttype=PKT_SIGNATURE; - newpkt->pkt.signature=copy_signature(NULL,newsig); - free_packet(sig_sk->pkt); - xfree(sig_sk->pkt); - sig_sk->pkt=newpkt; + if(sig_sk) + { + /* Put the new sig into place on the seckey */ + newpkt=xmalloc_clear(sizeof(*newpkt)); + newpkt->pkttype=PKT_SIGNATURE; + newpkt->pkt.signature=copy_signature(NULL,newsig); + free_packet(sig_sk->pkt); + xfree(sig_sk->pkt); + sig_sk->pkt=newpkt; + } modified=1; } diff --git a/g10/keygen.c b/g10/keygen.c index 32c09a97d..c7a97a0fc 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -341,7 +341,7 @@ keygen_set_std_prefs (const char *string,int personal) /* SHA-1 */ strcat(dummy_string,"H2 "); - if(!check_digest_algo(DIGEST_ALGO_SHA256)) + if (!openpgp_md_test_algo(DIGEST_ALGO_SHA256)) strcat(dummy_string,"H8 "); /* RIPEMD160 */ @@ -370,12 +370,12 @@ keygen_set_std_prefs (const char *string,int personal) while((tok=strsep(&prefstring," ,"))) { - if((val=openpgp_cipher_map_name (tok))) + if((val=gcry_cipher_map_name (tok))) { if(set_one_pref(val,1,tok,sym,&nsym)) rc=-1; } - else if((val=openpgp_md_map_name (tok))) + else if((val=gcry_md_map_name (tok))) { if(set_one_pref(val,2,tok,hash,&nhash)) rc=-1; @@ -2138,7 +2138,7 @@ get_parameter_algo( struct para_data_s *para, enum para_name key ) if( digitp( r->u.value ) ) i = atoi( r->u.value ); else - i = openpgp_pk_map_name (r->u.value); + i = gcry_pk_map_name (r->u.value); if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S) i = 0; /* we don't want to allow generation of these algorithms */ return i; @@ -2289,7 +2289,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname, if(r) { algo=get_parameter_algo(para,pKEYTYPE); - if (openpgp_pk_test_algo (algo, PUBKEY_USAGE_SIG)) + if (openpgp_pk_test_algo2 (algo, PUBKEY_USAGE_SIG)) { log_error("%s:%d: invalid algorithm\n", fname, r->lnr ); return -1; diff --git a/g10/keyserver.c b/g10/keyserver.c index 3e72b2820..3127a4795 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -26,9 +26,7 @@ #include #include #include -#ifdef HAVE_LIBCURL -#include -#endif +#include #include "gpg.h" #include "iobuf.h" @@ -45,18 +43,6 @@ #include "keyserver-internal.h" #include "util.h" -#define GPGKEYS_PREFIX "gpgkeys_" - -#if defined(HAVE_LIBCURL) || defined(FAKE_CURL) -#define GPGKEYS_CURL "gpgkeys_curl" -#endif - -#ifdef GPGKEYS_CURL -#define GPGKEYS_PREFIX_LEN (strlen(GPGKEYS_PREFIX)+strlen(GPGKEYS_CURL)) -#else -#define GPGKEYS_PREFIX_LEN (strlen(GPGKEYS_PREFIX)) -#endif - struct keyrec { KEYDB_SEARCH_DESC desc; @@ -419,7 +405,7 @@ parse_keyserver_uri(const char *string,int require_scheme, else keyserver->path=xstrdup("/"); - if(keyserver->path[1]!='\0') + if(keyserver->path[1]) keyserver->flags.direct_uri=1; } else if(uri[0]!='/') @@ -941,19 +927,20 @@ keyserver_typemap(const char *type) return type; } -#ifdef GPGKEYS_CURL /* The PGP LDAP and the curl fetch-a-LDAP-object methodologies are sufficiently different that we can't use curl to do LDAP. */ static int -curl_cant_handle(const char *scheme,unsigned int direct_uri) +direct_uri_map(const char *scheme,unsigned int is_direct) { - if(!direct_uri && (strcmp(scheme,"ldap")==0 || strcmp(scheme,"ldaps")==0)) + if(is_direct && strcmp(scheme,"ldap")==0) return 1; return 0; } -#endif +#define GPGKEYS_PREFIX "gpgkeys_" +#define GPGKEYS_CURL GPGKEYS_PREFIX "curl" EXEEXT +#define GPGKEYS_PREFIX_LEN (strlen(GPGKEYS_CURL)) #define KEYSERVER_ARGS_KEEP " -o \"%O\" \"%I\"" #define KEYSERVER_ARGS_NOKEEP " -o \"%o\" \"%i\"" @@ -1021,19 +1008,29 @@ keyserver_spawn(enum ks_action action,STRLIST list,KEYDB_SEARCH_DESC *desc, end=command+strlen(command); + /* Build a path for the keyserver helper. If it is direct_uri + (i.e. an object fetch and not a keyserver), then add "_uri" to + the end to distinguish the keyserver helper from an object + fetcher that can speak that protocol (this is a problem for + LDAP). */ + strcat(command,GPGKEYS_PREFIX); strcat(command,scheme); - if(keyserver->flags.direct_uri) - strcat(command,"uri"); + /* This "_uri" thing is in case we need to call a direct handler + instead of the keyserver handler. This lets us use gpgkeys_curl + or gpgkeys_ldap_uri (we don't provide it, but a user might) + instead of gpgkeys_ldap to fetch things like + ldap://keyserver.pgp.com/o=PGP%20keys?pgpkey?sub?pgpkeyid=99242560 */ + + if(direct_uri_map(scheme,keyserver->flags.direct_uri)) + strcat(command,"_uri"); strcat(command,EXEEXT); -#ifdef GPGKEYS_CURL - if(!curl_cant_handle(scheme,keyserver->flags.direct_uri) - && path_access(command,X_OK)!=0) + /* Can we execute it? If not, try curl as our catchall. */ + if(path_access(command,X_OK)!=0) strcpy(end,GPGKEYS_CURL); -#endif if(opt.keyserver_options.options&KEYSERVER_USE_TEMP_FILES) { @@ -1950,15 +1947,6 @@ keyserver_fetch(STRLIST urilist) { int rc; - /* - Set the direct_uri flag so we know later to call a direct - handler instead of the keyserver style. This lets us use - gpgkeys_curl or gpgkeys_ldapuri instead of gpgkeys_ldap to - fetch things like - ldap://keyserver.pgp.com/o=PGP%20keys?pgpkey?sub?pgpkeyid=99242560 - */ - spec->flags.direct_uri=1; - rc=keyserver_work(KS_GET,NULL,&desc,1,NULL,NULL,spec); if(rc) log_info (_("WARNING: unable to fetch URI %s: %s\n"), @@ -2038,6 +2026,12 @@ keyserver_import_cert(const char *name,unsigned char **fpr,size_t *fpr_len) rc=keyserver_import_fprint(*fpr,*fpr_len,opt.keyserver); } + else + log_info(_("no keyserver known (use option --keyserver)\n")); + + /* Give a better string here? "CERT fingerprint for \"%s\" + found, but no keyserver" " known (use option + --keyserver)\n" ? */ xfree(url); } diff --git a/g10/main.h b/g10/main.h index fd306a467..cd6926b69 100644 --- a/g10/main.h +++ b/g10/main.h @@ -282,6 +282,7 @@ void decrypt_messages(int nfiles, char *files[]); /*-- plaintext.c --*/ int hash_datafiles( gcry_md_hd_t md, gcry_md_hd_t md2, STRLIST files, const char *sigfilename, int textmode ); +PKT_plaintext *setup_plaintext_name(const char *filename,IOBUF iobuf); /*-- signal.c --*/ void init_signals(void); diff --git a/g10/mainproc.c b/g10/mainproc.c index 27989d3b2..1f91c8ca6 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -659,9 +659,9 @@ proc_plaintext( CTX c, PACKET *pkt ) often. There is no good way to specify what algorithms to use in that case, so these three are the historical answer. */ - md_enable( c->mfx.md, DIGEST_ALGO_RMD160 ); - md_enable( c->mfx.md, DIGEST_ALGO_SHA1 ); - md_enable( c->mfx.md, DIGEST_ALGO_MD5 ); + gcry_md_enable( c->mfx.md, DIGEST_ALGO_RMD160 ); + gcry_md_enable( c->mfx.md, DIGEST_ALGO_SHA1 ); + gcry_md_enable( c->mfx.md, DIGEST_ALGO_MD5 ); } if( opt.pgp2_workarounds && only_md5 && !opt.skip_verify ) { /* This is a kludge to work around a bug in pgp2. It does only diff --git a/g10/options.h b/g10/options.h index f61cd4c9e..de5fa7920 100644 --- a/g10/options.h +++ b/g10/options.h @@ -170,7 +170,6 @@ struct STRLIST sig_keyserver_url; STRLIST cert_subpackets; STRLIST sig_subpackets; - int use_embedded_filename; int allow_non_selfsigned_uid; int allow_freeform_uid; int no_literal; @@ -222,6 +221,10 @@ struct made by signing subkeys. If not set, a missing backsig is not an error (but an invalid backsig still is). */ 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 9e2a63642..4a12083d3 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -1,6 +1,6 @@ /* pkclist.c - create a list of public keys - * 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) != gcry_md_get_algo_dlen (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) > gcry_md_get_algo_dlen (algo)) + return 0; + } + else if (((*(int *)hint) != gcry_md_get_algo_dlen (algo))) + return 0; + } if((PGP6 || PGP7) && (algo != DIGEST_ALGO_MD5 && algo != DIGEST_ALGO_SHA1 diff --git a/g10/plaintext.c b/g10/plaintext.c index 2ae851e30..c0a6c3e11 100644 --- a/g10/plaintext.c +++ b/g10/plaintext.c @@ -1,6 +1,6 @@ /* plaintext.c - process plaintext packets - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, - * 2005, 2006 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. * @@ -91,7 +91,7 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, log_info(_("data not saved; use option \"--output\" to save it\n")); nooutput = 1; } - else if( !opt.use_embedded_filename ) { + else if( !opt.flags.use_embedded_filename ) { fname = make_outfile_name( iobuf_get_real_fname(pt->buf) ); if( !fname ) fname = ask_outfile_name( pt->name, pt->namelen ); @@ -100,9 +100,8 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, goto leave; } } - else { - fname = make_printable_string( pt->name, pt->namelen, 0 ); - } + else + fname=utf8_to_native(pt->name,pt->namelen,0); if( nooutput ) ; @@ -318,9 +317,10 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, goto leave; } else if( fwrite( buffer, 1, len, fp ) != len ) { + rc = (errno? gpg_error_from_errno (errno) + : gpg_error (GPG_ERR_INTERNAL)); log_error("Error writing to `%s': %s\n", fname, strerror(errno) ); - rc = G10ERR_WRITE_FILE; xfree( buffer ); goto leave; } @@ -554,3 +554,44 @@ hash_datafiles( gcry_md_hd_t md, gcry_md_hd_t md2, STRLIST files, return 0; } + + +/* Set up a plaintext packet with the appropriate filename. If there + is a --set-filename, use it (it's already UTF8). If there is a + regular filename, UTF8-ize it if necessary. If there is no + filenames at all, set the field empty. */ + +PKT_plaintext * +setup_plaintext_name(const char *filename,IOBUF iobuf) +{ + PKT_plaintext *pt; + + if(filename || opt.set_filename) + { + char *s; + + if(opt.set_filename) + s=make_basename(opt.set_filename,iobuf_get_real_fname(iobuf)); + else if(filename && !opt.flags.utf8_filename) + { + char *tmp=native_to_utf8(filename); + s=make_basename(tmp,iobuf_get_real_fname(iobuf)); + xfree(tmp); + } + else + s=make_basename(filename,iobuf_get_real_fname(iobuf)); + + pt = xmalloc (sizeof *pt + strlen(s) - 1); + pt->namelen = strlen (s); + memcpy (pt->name, s, pt->namelen); + xfree (s); + } + else + { + /* no filename */ + pt = xmalloc (sizeof *pt - 1); + pt->namelen = 0; + } + + return pt; +} diff --git a/g10/sign.c b/g10/sign.c index 9bb35c898..fa3796758 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -320,11 +320,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 - && gcry_md_get_algo_dlen (digest_algo)!=20) + /* 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 + && (gcry_mpi_get_nbits (sk->skey[1])/8)==20 + && !opt.flags.dsa2 + && gcry_md_get_algo_dlen (digest_algo)!=20) { log_error(_("DSA requires the use of a 160 bit hash algorithm\n")); return G10ERR_GENERAL; @@ -384,6 +388,32 @@ complete_sig( PKT_signature *sig, PKT_secret_key *sk, gcry_md_hd_t 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 @@ -397,7 +427,6 @@ complete_sig( PKT_signature *sig, PKT_secret_key *sk, gcry_md_hd_t md ) the signing key prefs either before or after using the personal list? */ - static int hash_for(PKT_secret_key *sk) { @@ -405,32 +434,61 @@ 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 = gcry_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 (gcry_md_get_algo_dlen (prefs->value) >= qbytes) + return prefs->value; + } + else + { + for (prefs=opt.personal_digest_prefs; prefs->type; prefs++) + if (gcry_md-get_algo_dlen (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 (gcry_md_get_algo_dlen (prefs->value) == 20) + for (prefs=opt.personal_digest_prefs;prefs->type;prefs++) + if (prefs->value==DIGEST_ALGO_SHA1 + || prefs->value==DIGEST_ALGO_RMD160) return prefs->value; } return DIGEST_ALGO_SHA1; } - else if(PGP2 && sk->pubkey_algo == PUBKEY_ALGO_RSA && sk->version < 4 ) + else if (PGP2 && sk->pubkey_algo == PUBKEY_ALGO_RSA && sk->version < 4 ) { - /* Old-style PGP only understands MD5. */ + /* Old-style PGP only understands MD5 */ return DIGEST_ALGO_MD5; } - else if( opt.personal_digest_prefs ) + else if ( opt.personal_digest_prefs ) { /* It's not DSA, so we can use whatever the first hash algorithm is in the pref list */ @@ -440,6 +498,7 @@ hash_for(PKT_secret_key *sk) return DEFAULT_DIGEST_ALGO; } + static int only_old_style( SK_LIST sk_list ) { @@ -537,21 +596,8 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode) u32 filesize; int rc = 0; - if (!opt.no_literal) { - if (fname || opt.set_filename) { - char *s = make_basename (opt.set_filename? opt.set_filename - : fname, - iobuf_get_real_fname(inp)); - pt = xmalloc (sizeof *pt + strlen(s) - 1); - pt->namelen = strlen (s); - memcpy (pt->name, s, pt->namelen); - xfree (s); - } - else { /* no filename */ - pt = xmalloc (sizeof *pt - 1); - pt->namelen = 0; - } - } + if (!opt.no_literal) + pt=setup_plaintext_name(fname,inp); /* try to calculate the length of the data */ if ( !iobuf_is_pipe_filename (fname) && *fname ) @@ -1367,16 +1413,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 (gcry_mpi_get_nbits (sk->skey[1])/8); else digest_algo = DIGEST_ALGO_SHA1; } diff --git a/g10/status.c b/g10/status.c index ffee8559f..2098d6738 100644 --- a/g10/status.c +++ b/g10/status.c @@ -209,9 +209,10 @@ set_status_fd ( int fd ) fd, strerror(errno)); } last_fd = fd; - register_primegen_progress ( progress_cb, "primegen" ); - register_pk_dsa_progress ( progress_cb, "pk_dsa" ); - register_pk_elg_progress ( progress_cb, "pk_elg" ); +#warning Use libgrypt calls for progress indicators +/* register_primegen_progress ( progress_cb, "primegen" ); */ +/* register_pk_dsa_progress ( progress_cb, "pk_dsa" ); */ +/* register_pk_elg_progress ( progress_cb, "pk_elg" ); */ } int