kbx,gpg: Allow lookup using a UBID.
authorWerner Koch <wk@gnupg.org>
Fri, 27 Sep 2019 08:05:07 +0000 (10:05 +0200)
committerWerner Koch <wk@gnupg.org>
Fri, 27 Sep 2019 08:05:07 +0000 (10:05 +0200)
* common/userids.c (classify_user_id): Detect UBIDs.
* kbx/backend-cache.c (blob_table_put): Store the public key type.
(be_cache_search): Add search mode for UBIDs.
* kbx/backend.h (struct db_request_part_s): Add cache.seqno_ubid.
* g10/keydb.c (keydb_search_desc_dump): Fix printing of keygrip.  Add
ubid printing.
* g10/call-keyboxd.c (keydb_search): Support search by UBID.

Signed-off-by: Werner Koch <wk@gnupg.org>
common/userids.c
doc/DETAILS
g10/call-keyboxd.c
g10/keydb.c
kbx/backend-cache.c
kbx/backend-kbx.c
kbx/backend.h

index 55bd855..eb714a9 100644 (file)
@@ -65,6 +65,9 @@
  *   (note that you can't search for these characters). Compare
  *   is not case sensitive.
  * - If the userid starts with a '&' a 40 hex digits keygrip is expected.
+ * - If the userid starts with a '^' followed by 40 hex digits it describes
+ *   a Unique-Blob-ID (UBID) which is the hash of keyblob or certificate as
+ *   stored in the database.  This is used in the IPC of the keyboxd.
  */
 
 gpg_error_t
@@ -251,6 +254,17 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
       }
       break;
 
+    case '^': /* UBID */
+      {
+        if (hex2bin (s+1, desc->u.ubid, 20) < 0)
+          {
+            rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid. */
+            goto out;
+          }
+        mode = KEYDB_SEARCH_MODE_UBID;
+      }
+      break;
+
     default:
       if (s[0] == '0' && s[1] == 'x')
         {
index ed5cade..0610108 100644 (file)
@@ -1144,10 +1144,11 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
 *** PUBKEY_INFO <n> <ubid>
     The type of the public key in the following D-lines or
     communicated via a pipe.  <n> is the value of =enum pubkey_types=
-    and <ubid> the Unique Blob ID which is a SHA-1 digest the entire
-    blob here formatted in hex..  The consumer of this status line
-    should be prepared to see a <ubid> of up to 64 characters.
-
+    and <ubid> the Unique Blob ID (UBID) which is a SHA-1 digest the
+    entire blob here formatted in hex.  The consumer of this status
+    line should be prepared to see a <ubid> of up to 64 characters.
+    Note that the keyboxd SEARCH command can be used to lookup the
+    public key using the <ubid> prefixed with a caret (^).
 
 * Format of the --attribute-fd output
 
index 97f84c0..88ad078 100644 (file)
@@ -1017,6 +1017,14 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
       }
       break;
 
+    case KEYDB_SEARCH_MODE_UBID:
+      {
+        unsigned char hexubid[20 * 2 + 1];
+        bin2hex (desc[0].u.grip, 20, hexubid);
+        snprintf (line, sizeof line, "SEARCH ^%s", hexubid);
+      }
+      break;
+
     case KEYDB_SEARCH_MODE_FIRST:
       snprintf (line, sizeof line, "SEARCH");
       break;
index 6ca2394..39ec544 100644 (file)
@@ -456,6 +456,10 @@ keydb_search_desc_dump (struct keydb_search_desc *desc)
   char b[MAX_FORMATTED_FINGERPRINT_LEN + 1];
   char fpr[2 * MAX_FINGERPRINT_LEN + 1];
 
+#if MAX_FINGERPRINT_LEN < 20
+#error MAX_FINGERPRINT_LEN shorter than GRIP and UBID length/
+#endif
+
   switch (desc->mode)
     {
     case KEYDB_SEARCH_MODE_EXACT:
@@ -495,7 +499,11 @@ keydb_search_desc_dump (struct keydb_search_desc *desc)
     case KEYDB_SEARCH_MODE_SUBJECT:
       return xasprintf ("SUBJECT: '%s'", desc->u.name);
     case KEYDB_SEARCH_MODE_KEYGRIP:
-      return xasprintf ("KEYGRIP: %s", desc->u.grip);
+      bin2hex (desc[0].u.grip, 20, fpr);
+      return xasprintf ("KEYGRIP: %s", fpr);
+    case KEYDB_SEARCH_MODE_UBID:
+      bin2hex (desc[0].u.ubid, 20, fpr);
+      return xasprintf ("UBID: %s", fpr);
     case KEYDB_SEARCH_MODE_FIRST:
       return xasprintf ("FIRST");
     case KEYDB_SEARCH_MODE_NEXT:
index d5b46b5..10a6f6b 100644 (file)
@@ -207,7 +207,7 @@ compare_blobs (const void *arg_a, const void *arg_b)
 /* Put the blob (BLOBDATA, BLOBDATALEN) into the cache using UBID as
  * the index.  If it is already in the cache nothing happens.  */
 static void
-blob_table_put (const unsigned char *ubid,
+blob_table_put (const unsigned char *ubid, enum pubkey_types pktype,
                 const void *blobdata, unsigned int blobdatalen)
 {
   unsigned int hash;
@@ -335,6 +335,7 @@ blob_table_put (const unsigned char *ubid,
   b = blob_attic;
   blob_attic = b->next;
   b->next = NULL;
+  b->pktype = pktype;
   b->data = blobdatacopy;
   b->datalen = blobdatalen;
   memcpy (b->ubid, ubid, 20);
@@ -932,6 +933,7 @@ be_cache_search (ctrl_t ctrl, backend_handle_t backend_hd, db_request_t request,
       reqpart->cache_seqno.fpr = 0;
       reqpart->cache_seqno.kid = 0;
       reqpart->cache_seqno.grip = 0;
+      reqpart->cache_seqno.ubid = 0;
       err = 0;
       goto leave;
     }
@@ -992,6 +994,27 @@ be_cache_search (ctrl_t ctrl, backend_handle_t backend_hd, db_request_t request,
         /*   ki = query_by_grip (desc[n].u.fpr, desc[n].fprlen); */
         /*   break; */
 
+        case KEYDB_SEARCH_MODE_UBID:
+          /* This is the quite special UBID mode: If this is
+           * encountered in the search list we will return just this
+           * one and obviously look only into the blob cache.  */
+          if (reqpart->cache_seqno.ubid)
+            err = gpg_error (GPG_ERR_NOT_FOUND);
+          else
+            {
+              b = blob_table_get (desc[n].u.ubid);
+              if (b)
+                {
+                  err = be_return_pubkey (ctrl, b->data, b->datalen,
+                                          b->pktype, desc[n].u.ubid);
+                  blob_unref (b);
+                  reqpart->cache_seqno.ubid++;
+                }
+              else
+                err = gpg_error (GPG_ERR_EOF);
+            }
+          goto leave;
+
         default:
           ki = NULL;
           break;
@@ -1123,7 +1146,7 @@ be_cache_pubkey (ctrl_t ctrl, const unsigned char *ubid,
           return;
         }
 
-      blob_table_put (ubid, blob, bloblen);
+      blob_table_put (ubid, pubkey_type, blob, bloblen);
 
       kinfo = &info.primary;
       key_table_put (kinfo->fpr, kinfo->fprlen, ubid, 0);
index e58b74a..851f2da 100644 (file)
@@ -302,6 +302,8 @@ be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
   unsigned long skipped_long_blobs;
   KEYDB_SEARCH_DESC desc;
 
+  (void)ctrl;
+
   log_assert (backend_hd && backend_hd->db_type == DB_TYPE_KBX);
   log_assert (request);
 
index 8b389d3..675ec21 100644 (file)
@@ -61,6 +61,7 @@ struct db_request_part_s
     unsigned int fpr;
     unsigned int kid;
     unsigned int grip;
+    unsigned int ubid;
   } cache_seqno;
 };
 typedef struct db_request_part_s *db_request_part_t;