gpg: Cache a once computed fingerprint in PKT_public_key.
authorWerner Koch <wk@gnupg.org>
Fri, 12 Apr 2019 09:11:09 +0000 (11:11 +0200)
committerWerner Koch <wk@gnupg.org>
Fri, 12 Apr 2019 09:11:09 +0000 (11:11 +0200)
* g10/packet.h (PKT_public_key): Add fields fpr and fprlen.
* g10/keyid.c (do_fingerprint_md): Remove.
(compute_fingerprint): New.
(keyid_from_pk): Simplify.
(fingerprint_from_pk): Simplify.
(hexfingerprint): Avoid using extra array.
--

This is similar to what we are doing with the keyid for a long time.

Signed-off-by: Werner Koch <wk@gnupg.org>
g10/keyid.c
g10/packet.h

index 45454f0..7605cb3 100644 (file)
@@ -253,20 +253,6 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
 }
 
 
-static gcry_md_hd_t
-do_fingerprint_md( PKT_public_key *pk )
-{
-  gcry_md_hd_t md;
-
-  if (gcry_md_open (&md, pk->version == 5 ? GCRY_MD_SHA256 : GCRY_MD_SHA1, 0))
-    BUG ();
-  hash_public_key (md,pk);
-  gcry_md_final (md);
-
-  return md;
-}
-
-
 /* fixme: Check whether we can replace this function or if not
    describe why we need it.  */
 u32
@@ -520,6 +506,37 @@ keystr_from_desc(KEYDB_SEARCH_DESC *desc)
 }
 
 
+/* Compute the fingerprint and keyid and store it in PK.  */
+static void
+compute_fingerprint (PKT_public_key *pk)
+{
+  const byte *dp;
+  gcry_md_hd_t md;
+  size_t len;
+
+  if (gcry_md_open (&md, pk->version == 5 ? GCRY_MD_SHA256 : GCRY_MD_SHA1, 0))
+    BUG ();
+  hash_public_key (md, pk);
+  gcry_md_final (md);
+  dp = gcry_md_read (md, 0);
+  len = gcry_md_get_algo_dlen (gcry_md_get_algo (md));
+  log_assert (len <= MAX_FINGERPRINT_LEN);
+  memcpy (pk->fpr, dp, len);
+  pk->fprlen = len;
+  if (pk->version == 5)
+    {
+      pk->keyid[0] = buf32_to_u32 (dp);
+      pk->keyid[1] = buf32_to_u32 (dp+4);
+    }
+  else
+    {
+      pk->keyid[0] = buf32_to_u32 (dp+12);
+      pk->keyid[1] = buf32_to_u32 (dp+16);
+    }
+  gcry_md_close( md);
+}
+
+
 /*
  * Get the keyid from the public key PK and store it at KEYID unless
  * this is NULL.  Returns the 32 bit short keyid.
@@ -532,37 +549,11 @@ keyid_from_pk (PKT_public_key *pk, u32 *keyid)
   if (!keyid)
     keyid = dummy_keyid;
 
-  if( pk->keyid[0] || pk->keyid[1] )
-    {
-      keyid[0] = pk->keyid[0];
-      keyid[1] = pk->keyid[1];
-    }
-  else
-    {
-      const byte *dp;
-      gcry_md_hd_t md;
-
-      md = do_fingerprint_md(pk);
-      if(md)
-       {
-         dp = gcry_md_read ( md, 0 );
-          if (pk->version == 5)
-            {
-              keyid[0] = buf32_to_u32 (dp);
-              keyid[1] = buf32_to_u32 (dp+4);
-            }
-          else
-            {
-              keyid[0] = buf32_to_u32 (dp+12);
-              keyid[1] = buf32_to_u32 (dp+16);
-            }
-         gcry_md_close (md);
-         pk->keyid[0] = keyid[0];
-         pk->keyid[1] = keyid[1];
-       }
-      else
-       pk->keyid[0] = pk->keyid[1] = keyid[0]= keyid[1] = 0xFFFFFFFF;
-    }
+  if (!pk->fprlen)
+    compute_fingerprint (pk);
+
+  keyid[0] = pk->keyid[0];
+  keyid[1] = pk->keyid[1];
 
   return keyid[1]; /*FIXME:shortkeyid ist different for v5*/
 }
@@ -805,6 +796,7 @@ colon_expirestr_from_sig (PKT_signature *sig)
 }
 
 
+
 /*
  * Return a byte array with the fingerprint for the given PK/SK
  * The length of the array is returned in ret_len. Caller must free
@@ -813,31 +805,15 @@ colon_expirestr_from_sig (PKT_signature *sig)
 byte *
 fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
 {
-  const byte *dp;
-  size_t len;
-  gcry_md_hd_t md;
+  if (!pk->fprlen)
+    compute_fingerprint (pk);
 
-  md = do_fingerprint_md (pk);
-  dp = gcry_md_read (md, 0);
-  len = gcry_md_get_algo_dlen (gcry_md_get_algo (md));
-  log_assert (len <= MAX_FINGERPRINT_LEN);
   if (!array)
-    array = xmalloc ( len );
-  memcpy (array, dp, len );
-  if (pk->version == 5)
-    {
-      pk->keyid[0] = buf32_to_u32 (dp);
-      pk->keyid[1] = buf32_to_u32 (dp+4);
-    }
-  else
-    {
-      pk->keyid[0] = buf32_to_u32 (dp+12);
-      pk->keyid[1] = buf32_to_u32 (dp+16);
-    }
-  gcry_md_close( md);
+    array = xmalloc (pk->fprlen);
+  memcpy (array, pk->fpr, pk->fprlen);
 
   if (ret_len)
-    *ret_len = len;
+    *ret_len = pk->fprlen;
   return array;
 }
 
@@ -852,19 +828,19 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
 char *
 hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen)
 {
-  unsigned char fpr[MAX_FINGERPRINT_LEN];
-  size_t len;
+  if (!pk->fprlen)
+    compute_fingerprint (pk);
 
-  fingerprint_from_pk (pk, fpr, &len);
   if (!buffer)
     {
-      buffer = xtrymalloc (2 * len + 1);
+      buffer = xtrymalloc (2 * pk->fprlen + 1);
       if (!buffer)
         return NULL;
     }
-  else if (buflen < 2*len+1)
+  else if (buflen < 2 * pk->fprlen + 1)
     log_fatal ("%s: buffer too short (%zu)\n", __func__, buflen);
-  bin2hex (fpr, len, buffer);
+
+  bin2hex (pk->fpr, pk->fprlen, buffer);
   return buffer;
 }
 
index 41dd1a9..d05a8f0 100644 (file)
@@ -394,6 +394,7 @@ typedef struct
   byte    pubkey_algo;
   byte    pubkey_usage;   /* for now only used to pass it to getkey() */
   byte    req_usage;      /* hack to pass a request to getkey() */
+  byte    fprlen;         /* 0 or length of FPR.  */
   u32     has_expired;    /* set to the expiration date if expired */
   /* keyid of the primary key.  Never access this value directly.
      Instead, use pk_main_keyid().  */
@@ -401,6 +402,8 @@ typedef struct
   /* keyid of this key.  Never access this value directly!  Instead,
      use pk_keyid().  */
   u32     keyid[2];
+  /* Fingerprint of the key.  Only valid if FPRLEN is not 0.  */
+  byte    fpr[MAX_FINGERPRINT_LEN];
   prefitem_t *prefs;      /* list of preferences (may be NULL) */
   struct
   {