From e624c41dbafd33af82c1153188d14de72fcc7cd8 Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Thu, 7 Nov 2019 10:36:17 +0100
Subject: [PATCH] gpg: Add option --allow-weak-key-signatures.

* g10/gpg.c (oAllowWeakKeySignatures): New.
(opts): Add --allow-weak-key-signatures.
(main): Set it.
* g10/options.h (struct opt): Add flags.allow_weak_key_signatures.
* g10/misc.c (print_sha1_keysig_rejected_note): New.
* g10/sig-check.c (check_signature_over_key_or_uid): Print note and
act on new option.

Signed-off-by: Werner Koch <wk@gnupg.org>
---
 doc/gpg.texi    | 19 ++++++++++++++-----
 g10/gpg.c       |  8 ++++++++
 g10/main.h      |  1 +
 g10/misc.c      | 18 ++++++++++++++++++
 g10/options.h   |  1 +
 g10/sig-check.c |  4 +++-
 6 files changed, 45 insertions(+), 6 deletions(-)

diff --git a/doc/gpg.texi b/doc/gpg.texi
index 8a88b11..093c309 100644
--- a/doc/gpg.texi
+++ b/doc/gpg.texi
@@ -113,9 +113,12 @@ only one command is allowed.  Generally speaking, irrelevant options
 are silently ignored, and may not be checked for correctness.
 
 @command{@gpgname} may be run with no commands. In this case it will
-perform a reasonable action depending on the type of file it is given
-as input (an encrypted message is decrypted, a signature is verified,
-a file containing keys is listed, etc.).
+print a warning perform a reasonable action depending on the type of
+file it is given as input (an encrypted message is decrypted, a
+signature is verified, a file containing keys is listed, etc.).
+
+If you run into any problems, please add the option @option{--verbose}
+to the invocation to see more diagnostics.
 
 
 @menu
@@ -2355,10 +2358,10 @@ opposite meaning. The options are:
 
   @item self-sigs-only
   Accept only self-signatures while importing a key.  All other
-  key-signatures are skipped at an early import stage.  This option
+  key signatures are skipped at an early import stage.  This option
   can be used with @code{keyserver-options} to mitigate attempts to
   flood a key with bogus signatures from a keyserver.  The drawback is
-  that all other valid key-signatures, as required by the Web of Trust
+  that all other valid key signatures, as required by the Web of Trust
   are also not imported.
 
   @item repair-keys
@@ -3262,6 +3265,12 @@ 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 --allow-weak-key-signatures
+@opindex allow-weak-key-signatures
+To avoid a minor risk of collision attacks on third-party key
+signatures made using SHA-1, those key signatures are considered
+invalid.  This options allows to override this restriction.
+
 @item --no-default-keyring
 @opindex no-default-keyring
 Do not add the default keyrings to the list of keyrings. Note that
diff --git a/g10/gpg.c b/g10/gpg.c
index 2c784d4..03540a1 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -407,6 +407,7 @@ enum cmd_and_opt_values
     oAllowMultipleMessages,
     oNoAllowMultipleMessages,
     oAllowWeakDigestAlgos,
+    oAllowWeakKeySignatures,
     oFakedSystemTime,
     oNoAutostart,
     oPrintPKARecords,
@@ -867,6 +868,9 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oNoAllowMultipleMessages, "no-allow-multiple-messages", "@"),
   ARGPARSE_s_n (oAllowWeakDigestAlgos, "allow-weak-digest-algos", "@"),
 
+  /* Options to override new security defaults.  */
+  ARGPARSE_s_n (oAllowWeakKeySignatures, "allow-weak-key-signatures", "@"),
+
   ARGPARSE_s_s (oDefaultNewKeyAlgo, "default-new-key-algo", "@"),
 
   /* These two are aliases to help users of the PGP command line
@@ -3550,6 +3554,10 @@ main (int argc, char **argv)
             opt.flags.allow_weak_digest_algos = 1;
             break;
 
+          case oAllowWeakKeySignatures:
+            opt.flags.allow_weak_key_signatures = 1;
+            break;
+
           case oFakedSystemTime:
             {
               size_t len = strlen (pargs.r.ret_str);
diff --git a/g10/main.h b/g10/main.h
index 9136e4c..90e164f 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -91,6 +91,7 @@ void print_pubkey_algo_note (pubkey_algo_t algo);
 void print_cipher_algo_note (cipher_algo_t algo);
 void print_digest_algo_note (digest_algo_t algo);
 void print_digest_rejected_note (enum gcry_md_algos algo);
+void print_sha1_keysig_rejected_note (void);
 void print_reported_error (gpg_error_t err, gpg_err_code_t skip_if_ec);
 void print_further_info (const char *format, ...) GPGRT_ATTR_PRINTF(1,2);
 void additional_weak_digest (const char* digestname);
diff --git a/g10/misc.c b/g10/misc.c
index 6d525a8..291d36f 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -357,6 +357,24 @@ print_digest_rejected_note (enum gcry_md_algos algo)
 }
 
 
+void
+print_sha1_keysig_rejected_note (void)
+{
+  static int shown;
+
+  if (shown)
+    return;
+
+  shown = 1;
+  es_fflush (es_stdout);
+  log_info (_("Note: third-party key signatures using"
+              " the %s algorithm are rejected\n"),
+            gcry_md_algo_name (GCRY_MD_SHA1));
+  print_further_info ("use option \"%s\" to override",
+                      "--allow-weak-key-signatures");
+}
+
+
 /* Print a message
  *  "(reported error: %s)\n
  * in verbose mode to further explain an error.  If the error code has
diff --git a/g10/options.h b/g10/options.h
index 0f007c1..ffeecaa 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -237,6 +237,7 @@ struct
     unsigned int dsa2:1;
     unsigned int allow_multiple_messages:1;
     unsigned int allow_weak_digest_algos:1;
+    unsigned int allow_weak_key_signatures:1;
     unsigned int large_rsa:1;
     unsigned int disable_signer_uid:1;
     /* Flag to enable experimental features from RFC4880bis.  */
diff --git a/g10/sig-check.c b/g10/sig-check.c
index a4e0df1..f48f0cd 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -965,12 +965,14 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
   else if (IS_UID_SIG (sig) || IS_UID_REV (sig))
     {
       log_assert (packet->pkttype == PKT_USER_ID);
-      if (sig->digest_algo == DIGEST_ALGO_SHA1 && !*is_selfsig)
+      if (sig->digest_algo == DIGEST_ALGO_SHA1 && !*is_selfsig
+          && !opt.flags.allow_weak_key_signatures)
         {
           /* If the signature was created using SHA-1 we consider this
            * signature invalid because it makes it possible to mount a
            * chosen-prefix collision.  We don't do this for
            * self-signatures, though.  */
+          print_sha1_keysig_rejected_note ();
           rc = gpg_error (GPG_ERR_DIGEST_ALGO);
         }
       else
-- 
1.8.3.1

