From 9112fed78b33faae32d21ab581721758ae2e95f2 Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Sat, 11 Oct 2014 19:41:51 +0200
Subject: [PATCH 13/31] gpg: Avoid using cached MD5 signature status.

* g10/sig-check.c (check_key_signature2): Avoid using a cached MD5
signature status.
* g10/keyring.c (keyring_get_keyblock): Ditto.
(write_keyblock): Ditto.

* g10/sig-check.c (do_check): Move reject warning to ...
* g10/misc.c (print_md5_rejected_note): new.
--

Modified by dkg (2015-01-04) to avoid needless whitespace transformations.

---
 g10/keyring.c   | 14 ++++++++++++--
 g10/main.h      |  7 ++++---
 g10/misc.c      | 16 ++++++++++++++++
 g10/sig-check.c | 17 +++++------------
 4 files changed, 37 insertions(+), 17 deletions(-)

diff --git a/g10/keyring.c b/g10/keyring.c
index 7482724..837df5e 100644
--- a/g10/keyring.c
+++ b/g10/keyring.c
@@ -434,12 +434,19 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
                  && (pkt->pkt.ring_trust->sigcache & 1) ) {
                 /* This is a ring trust packet with a checked signature 
                  * status cache following directly a signature paket.
-                 * Set the cache status into that signature packet.  */
+                 * Set the cache status into that signature packet.
+                 *
+                 * We do not use cached signatures made with MD5 to
+                 * avoid using a cached status created with an older
+                 * version of gpg.  */
                 PKT_signature *sig = lastnode->pkt->pkt.signature;
-                
-                sig->flags.checked = 1;
-                sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
+
+                if (sig->digest_algo != DIGEST_ALGO_MD5)
+                  {
+                    sig->flags.checked = 1;
+                    sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
+                  }
             }
             /* Reset LASTNODE, so that we set the cache status only from
              * the ring trust packet immediately following a signature. */
             lastnode = NULL;
@@ -490,9 +497,12 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
              && lastnode->pkt->pkttype == PKT_SIGNATURE
              && (pkt->pkt.ring_trust->sigcache & 1) ) {
             PKT_signature *sig = lastnode->pkt->pkt.signature;
-            sig->flags.checked = 1;
-            sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
+            if (sig->digest_algo != DIGEST_ALGO_MD5)
+              {
+                sig->flags.checked = 1;
+                sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
+              }
         }
 	*ret_kb = keyblock;
     }
     free_packet (pkt);
@@ -1354,7 +1364,7 @@ write_keyblock (IOBUF fp, KBNODE keyblock)
           PKT_signature *sig = node->pkt->pkt.signature;
           unsigned int cacheval = 0;
           
-          if (sig->flags.checked) 
+          if (sig->flags.checked && sig->digest_algo != DIGEST_ALGO_MD5)
             {
               cacheval |= 1;
               if (sig->flags.valid)
diff --git a/g10/main.h b/g10/main.h
index 9904820..2ac3854 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -63,9 +63,6 @@ extern int g10_errors_seen;
 #else
   void g10_exit(int rc);
 #endif
-void print_pubkey_algo_note( int algo );
-void print_cipher_algo_note( int algo );
-void print_digest_algo_note( int algo );
 
 /*-- armor.c --*/
 char *make_radix64_string( const byte *data, size_t len );
@@ -82,6 +79,10 @@ u16 checksum( byte *p, unsigned n );
 u16 checksum_mpi( gcry_mpi_t a );
 u32 buffer_to_u32( const byte *buffer );
 const byte *get_session_marker( size_t *rlen );
+void print_pubkey_algo_note( int algo );
+void print_cipher_algo_note( int algo );
+void print_digest_algo_note( int algo );
+void print_md5_rejected_note (void);
 int map_cipher_openpgp_to_gcry (int algo);
 #define openpgp_cipher_open(_a,_b,_c,_d) gcry_cipher_open((_a),map_cipher_openpgp_to_gcry((_b)),(_c),(_d))
 #define openpgp_cipher_get_algo_keylen(_a) gcry_cipher_get_algo_keylen(map_cipher_openpgp_to_gcry((_a)))
diff --git a/g10/misc.c b/g10/misc.c
index 43ea0d2..1ca9580 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -340,6 +340,22 @@ print_digest_algo_note( int algo )
 }
 
 
+void
+print_md5_rejected_note (void)
+{
+  static int shown;
+
+  if (!shown)
+    {
+      fflush (stdout);
+      log_info
+        (_("Note: signatures using the %s algorithm are rejected\n"),
+         "MD5");
+      shown = 1;
+    }
+}
+
+
 /* Map OpenPGP algo numbers to those used by Libgcrypt.  We need to do
    this for algorithms we implemented in Libgcrypt after they become
    part of OpenPGP.  */
diff --git a/g10/sig-check.c b/g10/sig-check.c
index ed4fa89..2999693 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -272,16 +272,7 @@ do_check( PKT_public_key *pk, PKT_signature *sig, gcry_md_hd_t digest,
     if (sig->digest_algo == GCRY_MD_MD5
         && !opt.flags.allow_weak_digest_algos)
       {
-        static int shown;
-
-        if (!shown)
-          {
-            log_info
-              (_("Note: signatures using the %s algorithm are rejected\n"),
-               "MD5");
-            shown = 1;
-          }
-
+        print_md5_rejected_note ();
         return GPG_ERR_DIGEST_ALGO;
       }
 
@@ -549,9 +540,11 @@ check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
     /* Check whether we have cached the result of a previous signature
        check.  Note that we may no longer have the pubkey or hash
        needed to verify a sig, but can still use the cached value.  A
-       cache refresh detects and clears these cases. */
+       cache refresh detects and clears these cases.
+       For safety reasons we ignore cache entries from MD5 signatures.  */
     if ( !opt.no_sig_cache ) {
-        if (sig->flags.checked) { /*cached status available*/
+        if (sig->flags.checked && sig->digest_algo != DIGEST_ALGO_MD5) {
+            /*cached status available*/
 	    if( is_selfsig ) {
 		u32 keyid[2];
 
