Index: b/doc/gpg.texi =================================================================== --- b/doc/gpg.texi +++ b/doc/gpg.texi @@ -2789,9 +2789,20 @@ @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 @opindex no-default-keyring Index: b/doc/gpgv.texi =================================================================== --- b/doc/gpgv.texi +++ b/doc/gpgv.texi @@ -118,6 +118,14 @@ @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 Index: b/g10/gpg.c =================================================================== --- b/g10/gpg.c +++ b/g10/gpg.c @@ -389,6 +389,7 @@ oPrintDANERecords, oTOFUDefaultPolicy, oTOFUDBFormat, + oWeakDigest, oNoop }; @@ -749,6 +750,7 @@ ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-preferences", "@"), ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"), + ARGPARSE_s_s (oWeakDigest, "weak-digest","@"), /* Aliases. I constantly mistype these, and assume other people do as well. */ @@ -2208,6 +2210,7 @@ set_homedir (default_homedir ()); opt.passphrase_repeat = 1; opt.emit_version = 1; /* Limit to the major number. */ + opt.additional_weak_digests = NULL; /* Check whether we have a config file on the command line. */ orig_argc = argc; @@ -3124,6 +3127,9 @@ break; case oAgentProgram: opt.agent_program = pargs.r.ret_str; break; case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break; + case oWeakDigest: + additional_weak_digest(pargs.r.ret_str); + break; case oDisplay: set_opt_session_env ("DISPLAY", pargs.r.ret_str); Index: b/g10/gpgv.c =================================================================== --- b/g10/gpgv.c +++ b/g10/gpgv.c @@ -61,6 +61,7 @@ oStatusFD, oLoggerFD, oHomedir, + oWeakDigest, aTest }; @@ -78,6 +79,7 @@ N_("|FD|write status info to this FD")), ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"), ARGPARSE_s_s (oHomedir, "homedir", "@"), + ARGPARSE_s_s (oWeakDigest, "weak-digest", "@"), ARGPARSE_end () }; @@ -192,6 +194,9 @@ log_set_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1)); 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 = ARGPARSE_PRINT_ERROR; break; } Index: b/g10/main.h =================================================================== --- b/g10/main.h +++ b/g10/main.h @@ -69,6 +69,12 @@ struct groupitem *next; }; +struct weakhash +{ + enum gcry_md_algos algo; + struct weakhash *next; +}; + /*-- gpg.c --*/ extern int g10_errors_seen; @@ -82,6 +88,7 @@ void print_cipher_algo_note (cipher_algo_t algo); void print_digest_algo_note (digest_algo_t algo); void print_md5_rejected_note (void); +void additional_weak_digest (const char* digestname); /*-- armor.c --*/ char *make_radix64_string( const byte *data, size_t len ); Index: b/g10/misc.c =================================================================== --- b/g10/misc.c +++ b/g10/misc.c @@ -307,6 +307,10 @@ void print_digest_algo_note (digest_algo_t algo) { + int deprecated = 0; + const enum gcry_md_algos galgo = map_md_openpgp_to_gcry (algo); + const struct weakhash *weak; + if(algo >= 100 && algo <= 110) { static int warn=0; @@ -315,14 +319,21 @@ warn=1; es_fflush (es_stdout); log_info (_("WARNING: using experimental digest algorithm %s\n"), - gcry_md_algo_name (algo)); + gcry_md_algo_name (galgo)); } } - else if(algo==DIGEST_ALGO_MD5) + else if(algo == DIGEST_ALGO_MD5) + deprecated = 1; + else + for (weak = opt.additional_weak_digests; weak != NULL; weak = weak->next) + if (weak->algo == galgo) + deprecated = 1; + + if (deprecated) { es_fflush (es_stdout); log_info (_("WARNING: digest algorithm %s is deprecated\n"), - gcry_md_algo_name (algo)); + gcry_md_algo_name (galgo)); } } @@ -1676,3 +1687,37 @@ qbits /= 2; return qbits; } + + +/* ignore signatures and certifications made over certain digest + algorithms by default, MD5 is considered weak. This allows users + to deprecate support for other algorithms as well. +*/ +void +additional_weak_digest (const char* digestname) +{ + struct weakhash *weak = NULL; + const enum gcry_md_algos algo = string_to_digest_algo(digestname); + + if (algo == GCRY_MD_MD5) + return; /* MD5 is always considered weak, no need to add it */ + + if (algo == GCRY_MD_NONE) + { + log_error(_("Unknown weak digest '%s'\n"), digestname); + return; + } + + /* check to ensure it's not already present */ + for (weak = opt.additional_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->next = opt.additional_weak_digests; + opt.additional_weak_digests = weak; +} Index: b/g10/options.h =================================================================== --- b/g10/options.h +++ b/g10/options.h @@ -170,6 +170,7 @@ prefitem_t *personal_cipher_prefs; prefitem_t *personal_digest_prefs; prefitem_t *personal_compress_prefs; + struct weakhash *additional_weak_digests; int no_perm_warn; int no_mdc_warn; char *temp_dir; Index: b/g10/sig-check.c =================================================================== --- b/g10/sig-check.c +++ b/g10/sig-check.c @@ -274,15 +274,18 @@ { gcry_mpi_t result = NULL; int rc = 0; + const struct weakhash *weak; if( (rc=do_check_messages(pk,sig,r_expired,r_revoked)) ) return rc; - if (sig->digest_algo == GCRY_MD_MD5 - && !opt.flags.allow_weak_digest_algos) + if (!opt.flags.allow_weak_digest_algos) { - print_md5_rejected_note (); - return GPG_ERR_DIGEST_ALGO; + if (sig->digest_algo == GCRY_MD_MD5) + return GPG_ERR_DIGEST_ALGO; + for (weak = opt.additional_weak_digests; weak != NULL; weak = weak->next) + if (sig->digest_algo == weak->algo) + return GPG_ERR_DIGEST_ALGO; } /* Make sure the digest algo is enabled (in case of a detached