diff --git a/doc/gpg.texi b/doc/gpg.texi index 93baf16e1..fd6508349 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2610,9 +2610,20 @@ message was tampered with intentionally by an attacker. @item --allow-weak-digest-algos @opindex allow-weak-digest-algos -Signatures made with the broken MD5 algorithm are normally rejected -with an ``invalid digest algorithm'' message. This option allows the -verification of signatures made with such weak algorithms. +Signatures made with known-weak digest algorithms are normally +rejected with an ``invalid digest algorithm'' message. This option +allows the verification of signatures made with such weak algorithms. +MD5 is the only digest algorithm considered weak by default. See also +@option{--weak-digest} to reject other digest algorithms. + +@item --weak-digest @code{name} +@opindex weak-digest +Treat the specified digest algorithm as weak. Signatures made over +weak digests algorithms are normally rejected. This option can be +supplied multiple times if multiple algorithms should be considered +weak. See also @option{--allow-weak-digest-algos} to disable +rejection of weak digests. MD5 is always considered weak, and does +not need to be listed explicitly. @item --no-default-keyring diff --git a/doc/gpgv.texi b/doc/gpgv.texi index 0cb2360f8..7172a8cad 100644 --- a/doc/gpgv.texi +++ b/doc/gpgv.texi @@ -115,6 +115,14 @@ checks into warnings. @include opt-homedir.texi +@item --weak-digest @code{name} +@opindex weak-digest +Treat the specified digest algorithm as weak. Signatures made over +weak digests algorithms are normally rejected. This option can be +supplied multiple times if multiple algorithms should be considered +weak. MD5 is always considered weak, and does not need to be listed +explicitly. + @end table @mansect return value diff --git a/g10/gpg.c b/g10/gpg.c index ce33e12d4..0095d3475 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -377,6 +377,7 @@ enum cmd_and_opt_values oAllowMultipleMessages, oNoAllowMultipleMessages, oAllowWeakDigestAlgos, + oWeakDigest, oNoop }; @@ -689,6 +690,7 @@ static ARGPARSE_OPTS opts[] = { { oPersonalCipherPreferences, "personal-cipher-preferences", 2, "@"}, { oPersonalDigestPreferences, "personal-digest-preferences", 2, "@"}, { oPersonalCompressPreferences, "personal-compress-preferences", 2, "@"}, + { oWeakDigest, "weak-digest", 2, "@"}, /* Aliases. I constantly mistype these, and assume other people do as well. */ { oPersonalCipherPreferences, "personal-cipher-prefs", 2, "@"}, @@ -1923,6 +1925,8 @@ main (int argc, char **argv ) #endif opt.disable_keypad = 1; /* No keypad support; use gpg2 instead. */ #endif /*ENABLE_CARD_SUPPORT*/ + opt.weak_digests = NULL; + additional_weak_digest("MD5"); /* check whether we have a config file on the commandline */ orig_argc = argc; @@ -2793,6 +2797,9 @@ main (int argc, char **argv ) case oDisplay: opt.display = pargs.r.ret_str; break; case oTTYname: opt.ttyname = pargs.r.ret_str; break; case oTTYtype: opt.ttytype = pargs.r.ret_str; break; + case oWeakDigest: + additional_weak_digest(pargs.r.ret_str); + break; case oLCctype: opt.lc_ctype = pargs.r.ret_str; break; case oLCmessages: opt.lc_messages = pargs.r.ret_str; break; case oGroup: add_group(pargs.r.ret_str); break; diff --git a/g10/gpgv.c b/g10/gpgv.c index b67985397..b2721bae9 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -60,6 +60,7 @@ enum cmd_and_opt_values { aNull = 0, oStatusFD, oLoggerFD, oHomedir, + oWeakDigest, aTest }; @@ -75,6 +76,7 @@ static ARGPARSE_OPTS opts[] = { { oStatusFD, "status-fd" ,1, N_("|FD|write status info to this FD") }, { oLoggerFD, "logger-fd",1, "@" }, { oHomedir, "homedir", 2, "@" }, /* defaults to "~/.gnupg" */ + { oWeakDigest, "weak-digest", 2, "@" }, /* defaults to "~/.gnupg" */ {0} }; @@ -143,6 +145,7 @@ main( int argc, char **argv ) opt.keyserver_options.options|=KEYSERVER_AUTO_KEY_RETRIEVE; opt.trust_model = TM_ALWAYS; opt.batch = 1; + opt.weak_digests = NULL; opt.homedir = default_homedir (); @@ -151,6 +154,7 @@ main( int argc, char **argv ) dotlock_disable (); set_native_charset (NULL); /* Try to auto set the character set */ + additional_weak_digest("MD5"); pargs.argc = &argc; pargs.argv = &argv; @@ -164,6 +168,7 @@ main( int argc, char **argv ) case oStatusFD: set_status_fd( pargs.r.ret_int ); break; case oLoggerFD: log_set_logfile( NULL, pargs.r.ret_int ); break; case oHomedir: opt.homedir = pargs.r.ret_str; break; + case oWeakDigest: additional_weak_digest(pargs.r.ret_str); break; case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break; default : pargs.err = 2; break; } diff --git a/g10/main.h b/g10/main.h index 21ec1f077..a0b96f984 100644 --- a/g10/main.h +++ b/g10/main.h @@ -60,6 +60,14 @@ struct groupitem struct groupitem *next; }; +struct weakhash +{ + int algo; + int rejection_shown; + struct weakhash *next; +}; + + /*-- gpg.c --*/ extern int g10_errors_seen; @@ -71,6 +79,7 @@ extern int g10_errors_seen; void print_pubkey_algo_note( int algo ); void print_cipher_algo_note( int algo ); void print_digest_algo_note( int algo ); +void additional_weak_digest (const char* digestname); /*-- armor.c --*/ char *make_radix64_string( const byte *data, size_t len ); diff --git a/g10/misc.c b/g10/misc.c index 2b38a8fcc..c863be43c 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -332,6 +332,8 @@ print_cipher_algo_note( int algo ) void print_digest_algo_note( int algo ) { + const struct weakhash *weak; + if(algo >= 100 && algo <= 110) { static int warn=0; @@ -342,8 +344,11 @@ print_digest_algo_note( int algo ) digest_algo_to_string(algo)); } } - else if(algo==DIGEST_ALGO_MD5) - md5_digest_warn (1); + else + for (weak = opt.weak_digests; weak; weak = weak->next) + if (weak->algo == algo) + log_info (_("WARNING: digest algorithm %s is deprecated\n"), + digest_algo_to_string(algo)); } /* Return a string which is used as a kind of process ID */ @@ -1310,3 +1315,32 @@ path_access(const char *file,int mode) } #endif /*ndef __VMS*/ + +/* Ignore signatures and certifications made over certain digest + * algorithms. This allows users to deprecate support for algorithms + * they are not willing to rely on. + */ +void +additional_weak_digest (const char* digestname) +{ + struct weakhash *weak = NULL; + const int algo = string_to_digest_algo(digestname); + + if (algo == 0) + { + log_error(_("Unknown weak digest '%s'\n"), digestname); + return; + } + + /* Check to ensure it's not already present. */ + for (weak = opt.weak_digests; weak != NULL; weak = weak->next) + if (algo == weak->algo) + return; + + /* Add it to the head of the list. */ + weak = xmalloc(sizeof(*weak)); + weak->algo = algo; + weak->rejection_shown = 0; + weak->next = opt.weak_digests; + opt.weak_digests = weak; +} diff --git a/g10/options.h b/g10/options.h index 26d65e560..5aa3a048d 100644 --- a/g10/options.h +++ b/g10/options.h @@ -164,6 +164,7 @@ struct prefitem_t *personal_cipher_prefs; prefitem_t *personal_digest_prefs; prefitem_t *personal_compress_prefs; + struct weakhash *weak_digests; int no_perm_warn; int no_mdc_warn; char *temp_dir; diff --git a/g10/sig-check.c b/g10/sig-check.c index 94f0cc5ff..6bac63034 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -239,26 +239,25 @@ do_check( PKT_public_key *pk, PKT_signature *sig, MD_HANDLE digest, { MPI result = NULL; int rc=0; + struct weakhash *weak; if( (rc=do_check_messages(pk,sig,r_expired,r_revoked)) ) return rc; - if (sig->digest_algo == DIGEST_ALGO_MD5 - && !opt.flags.allow_weak_digest_algos) - { - static int shown; - - if (!shown) + if (!opt.flags.allow_weak_digest_algos) + for (weak = opt.weak_digests; weak; weak = weak->next) + if (sig->digest_algo == weak->algo) { - log_info - (_("Note: signatures using the %s algorithm are rejected\n"), - "MD5"); - shown = 1; + if (!weak->rejection_shown) + { + log_info + (_("Note: signatures using the %s algorithm are rejected\n"), + digest_algo_to_string(sig->digest_algo)); + weak->rejection_shown = 1; + } + return G10ERR_DIGEST_ALGO; } - return G10ERR_DIGEST_ALGO; - } - /* make sure the digest algo is enabled (in case of a detached signature)*/ md_enable( digest, sig->digest_algo );