kbx: Redefine the UBID which is now the primary fingerprint.
authorWerner Koch <wk@gnupg.org>
Thu, 28 Nov 2019 08:39:35 +0000 (09:39 +0100)
committerWerner Koch <wk@gnupg.org>
Thu, 28 Nov 2019 10:16:13 +0000 (11:16 +0100)
* common/util.h (UBID_LEN): New.  Use it at all places.
* kbx/keybox-blob.c (create_blob_finish): Do not write the UBID item.
* kbx/keybox-dump.c (print_ubib): Remove.
(_keybox_dump_blob): Do not print the now removed ubid flag.
* kbx/keybox-search-desc.h (struct keydb_search_desc): Use constants
for the size of the ubid and grip.
* kbx/keybox-search.c (blob_cmp_ubid): New.
(has_ubid): Make it a simple wrapper around blob_cmp_ubid.
(keybox_get_data): Add arg 'r_ubid'.

* kbx/frontend.h (enum kbxd_store_modes): New.
* kbx/kbxserver.c (cmd_store): Add new option --insert.

* kbx/backend-cache.c (be_cache_initialize): New.
(be_cache_add_resource): Call it here.
* kbx/backend-kbx.c (be_kbx_seek): Remove args 'fpr' and 'fprlen'.
(be_kbx_search): Get the UBID from keybox_get_data.
* kbx/backend-support.c (be_fingerprint_from_blob): Replace by ...
(be_ubid_from_blob): new.  Change all callers.

* kbx/frontend.c (kbxd_add_resource): Temporary disable the cache but
use the new cache init function.
(kbxd_store): Replace arg 'only_update' by 'mode'.  Seek using the
ubid.  Take care of the mode.
--

It turned out that using the hash of the entire blob was not helpful.
Thus we redefine the Unique-Blob-ID (UBID) as the primary fingerprint
of the blob.  In case this is a v5 OpenPGP key a left truncated
version of the SHA-256 hash is used; in all other cases the full SHA-1
hash.  Using a SHA-256 hash does not make sense because v4 keys are
and will for some time be the majority of keys and thus padding them
with zeroes won't make any difference.  Even if fingerprint collisions
can eventually be created we will assume that the keys are bogus and
that it does not make sense to store its twin also in our key storage.
We can also easily extend the update code to detect a collision and
reject the update.

Signed-off-by: Werner Koch <wk@gnupg.org>
18 files changed:
common/userids.c
common/util.h
doc/DETAILS
g10/call-keyboxd.c
g10/keydb-private.h
g10/keydb.c
kbx/backend-cache.c
kbx/backend-kbx.c
kbx/backend-support.c
kbx/backend.h
kbx/frontend.c
kbx/frontend.h
kbx/kbxserver.c
kbx/keybox-blob.c
kbx/keybox-dump.c
kbx/keybox-search-desc.h
kbx/keybox-search.c
kbx/keybox.h

index eb714a9..5e27043 100644 (file)
@@ -256,7 +256,7 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
 
     case '^': /* UBID */
       {
-        if (hex2bin (s+1, desc->u.ubid, 20) < 0)
+        if (hex2bin (s+1, desc->u.ubid, UBID_LEN) < 0)
           {
             rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid. */
             goto out;
index 6c87808..fc86980 100644 (file)
  * parameters as generated by gcry_pk_get_keygrip.  */
 #define KEYGRIP_LEN 20
 
+/* The length of the unique blob identifier as used by the keyboxd.
+ * This is the possible truncated fingerprint of the primary key.  */
+#define UBID_LEN    20
+
 
 /* Get all the stuff from jnlib. */
 #include "../common/logging.h"
index 6ce340e..bd00006 100644 (file)
@@ -1152,11 +1152,10 @@ 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 (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 (^).
+    and <ubid> the Unique Blob ID (UBID) which is the fingerprint of
+    the primary key truncated to 20 octets and formatted in hex.  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 9625587..99dfac5 100644 (file)
@@ -1049,8 +1049,8 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
 
     case KEYDB_SEARCH_MODE_UBID:
       {
-        unsigned char hexubid[20 * 2 + 1];
-        bin2hex (desc[0].u.grip, 20, hexubid);
+        unsigned char hexubid[UBID_LEN * 2 + 1];
+        bin2hex (desc[0].u.grip, UBID_LEN, hexubid);
         snprintf (line, sizeof line, "SEARCH ^%s", hexubid);
       }
       break;
index 47a09ca..fdc905e 100644 (file)
@@ -100,7 +100,7 @@ struct keydb_handle_s
   unsigned int last_ubid_valid:1;
 
   /* The UBID of the last returned keyblock.  */
-  unsigned char last_ubid[20];
+  unsigned char last_ubid[UBID_LEN];
 
   /* END USE_KEYBOXD */
 
index 57d51e7..bf41137 100644 (file)
@@ -456,8 +456,8 @@ 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/
+#if MAX_FINGERPRINT_LEN < UBID_LEN || MAX_FINGERPRINT_LEN < KEYGRIP_LEN
+#error MAX_FINGERPRINT_LEN is shorter than KEYGRIP or UBID length.
 #endif
 
   switch (desc->mode)
@@ -499,10 +499,10 @@ 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:
-      bin2hex (desc[0].u.grip, 20, fpr);
+      bin2hex (desc[0].u.grip, KEYGRIP_LEN, fpr);
       return xasprintf ("KEYGRIP: %s", fpr);
     case KEYDB_SEARCH_MODE_UBID:
-      bin2hex (desc[0].u.ubid, 20, fpr);
+      bin2hex (desc[0].u.ubid, UBID_LEN, fpr);
       return xasprintf ("UBID: %s", fpr);
     case KEYDB_SEARCH_MODE_FIRST:
       return xasprintf ("FIRST");
index 10a6f6b..45e5c71 100644 (file)
@@ -63,7 +63,7 @@ typedef struct blob_s
   unsigned int usecount;
   unsigned int datalen;
   unsigned char *data;        /* The actual data of length DATALEN.  */
-  unsigned char ubid[20];
+  unsigned char ubid[UBID_LEN];
 } *blob_t;
 
 
@@ -90,7 +90,7 @@ typedef struct bloblist_s
   unsigned int subkey:1;        /* The entry is for a subkey.   */
   unsigned int fprlen:8;        /* The length of the fingerprint or 0.  */
   char fpr[32];                 /* The buffer for the fingerprint.  */
-  unsigned char ubid[20];       /* The Unique-Blob-ID of the blob.  */
+  unsigned char ubid[UBID_LEN]; /* The Unique-Blob-ID of the blob.  */
 } *bloblist_t;
 
 static bloblist_t bloblist_attic;  /* List of freed items.  */
@@ -179,7 +179,7 @@ find_blob (unsigned int hash, const unsigned char *ubid,
   unsigned int count = 0;
 
   for (b = blob_table[hash]; b; b = b->next, count++)
-    if (!memcmp (b->ubid, ubid, 20))
+    if (!memcmp (b->ubid, ubid, UBID_LEN))
       break;
   if (r_count)
     *r_count = count;
@@ -338,7 +338,7 @@ blob_table_put (const unsigned char *ubid, enum pubkey_types pktype,
   b->pktype = pktype;
   b->data = blobdatacopy;
   b->datalen = blobdatalen;
-  memcpy (b->ubid, ubid, 20);
+  memcpy (b->ubid, ubid, UBID_LEN);
   b->usecount = 1;
   b->refcount = 1;
   b->next = blob_table[hash];
@@ -532,9 +532,9 @@ new_bloblist_item (const unsigned char *fpr, unsigned int fprlen,
   bl->next = NULL;
 
   if (ubid)
-    memcpy (bl->ubid, ubid, 20);
+    memcpy (bl->ubid, ubid, UBID_LEN);
   else
-    memset (bl->ubid, 0, 20);
+    memset (bl->ubid, 0, UBID_LEN);
   bl->ubid_valid = 1;
   bl->final_kid = 0;
   bl->final_fpr = 0;
@@ -846,6 +846,19 @@ query_by_fpr (const unsigned char *fpr, unsigned int fprlen)
 
 
 \f
+/* Make sure the tables are initialized.  */
+gpg_error_t
+be_cache_initialize (void)
+{
+  gpg_error_t err;
+
+  err = blob_table_init ();
+  if (!err)
+    err = key_table_init ();
+  return err;
+}
+
+
 /* Install a new resource and return a handle for that backend.  */
 gpg_error_t
 be_cache_add_resource (ctrl_t ctrl, backend_handle_t *r_hd)
@@ -863,11 +876,8 @@ be_cache_add_resource (ctrl_t ctrl, backend_handle_t *r_hd)
 
   hd->backend_id = be_new_backend_id ();
 
-  err = blob_table_init ();
-  if (err)
-    goto leave;
-
-  err = key_table_init ();
+  /* Just in case make sure we are initialized.  */
+  err = be_cache_initialize ();
   if (err)
     goto leave;
 
@@ -1030,7 +1040,7 @@ be_cache_search (ctrl_t ctrl, backend_handle_t backend_hd, db_request_t request,
     {
       if (bl && bl->ubid_valid)
         {
-          memcpy (request->last_cached_ubid, bl->ubid, 20);
+          memcpy (request->last_cached_ubid, bl->ubid, UBID_LEN);
           request->last_cached_valid = 1;
           request->last_cached_fprlen = desc[descidx].fprlen;
           memcpy (request->last_cached_fpr,
index d8dafe0..ff4f567 100644 (file)
@@ -271,15 +271,15 @@ be_kbx_search (ctrl_t ctrl, backend_handle_t backend_hd, db_request_t request,
       void *buffer;
       size_t buflen;
       enum pubkey_types pubkey_type;
-      unsigned char blobid[20];
+      unsigned char ubid[UBID_LEN];
 
-      err = keybox_get_data (part->kbx_hd, &buffer, &buflen, &pubkey_type);
+      err = keybox_get_data (part->kbx_hd, &buffer, &buflen,
+                             &pubkey_type, ubid);
       if (err)
         goto leave;
-      gcry_md_hash_buffer (GCRY_MD_SHA1, blobid, buffer, buflen);
-      err = be_return_pubkey (ctrl, buffer, buflen, pubkey_type, blobid);
+      err = be_return_pubkey (ctrl, buffer, buflen, pubkey_type, ubid);
       if (!err)
-        be_cache_pubkey (ctrl, blobid, buffer, buflen, pubkey_type);
+        be_cache_pubkey (ctrl, ubid, buffer, buflen, pubkey_type);
       xfree (buffer);
     }
 
@@ -295,8 +295,7 @@ be_kbx_search (ctrl_t ctrl, backend_handle_t backend_hd, db_request_t request,
  * operation starts right after that UBID. */
 gpg_error_t
 be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
-             db_request_t request, const unsigned char *ubid,
-             const unsigned char *fpr, unsigned int fprlen)
+             db_request_t request, const unsigned char *ubid)
 {
   gpg_error_t err;
   db_request_part_t part;
@@ -310,19 +309,8 @@ be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
   log_assert (request);
 
   memset (&desc, 0, sizeof desc);
-  if (ubid)
-    {
-      desc.mode = KEYDB_SEARCH_MODE_FPR;
-      memcpy (desc.u.ubid, ubid, 20);
-    }
-  else
-    {
-      if (fprlen > sizeof desc.u.fpr)
-        return gpg_error (GPG_ERR_TOO_LARGE);
-      desc.mode = KEYDB_SEARCH_MODE_FPR;
-      memcpy (desc.u.fpr, fpr, fprlen);
-      desc.fprlen = fprlen;
-    }
+  desc.mode = KEYDB_SEARCH_MODE_UBID;
+  memcpy (desc.u.ubid, ubid, UBID_LEN);
 
   /* Find the specific request part or allocate it.  */
   err = be_find_request_part (backend_hd, request, &part);
index f1a9799..f1e80b0 100644 (file)
@@ -155,9 +155,9 @@ be_return_pubkey (ctrl_t ctrl, const void *buffer, size_t buflen,
                   enum pubkey_types pubkey_type, const unsigned char *ubid)
 {
   gpg_error_t err;
-  char hexubid[41];
+  char hexubid[2*UBID_LEN+1];
 
-  bin2hex (ubid, 20, hexubid);
+  bin2hex (ubid, UBID_LEN, hexubid);
   err = status_printf (ctrl, "PUBKEY_INFO", "%d %s", pubkey_type, hexubid);
   if (err)
     goto leave;
@@ -228,14 +228,12 @@ is_x509_blob (const unsigned char *blob, size_t bloblen)
 
 
 /* Return the public key type and the (primary) fingerprint for
- * (BLOB,BLOBLEN).  R_FPR must point to a buffer of at least 32 bytes,
- * it received the fi gerprint on success with the length of that
- * fingerprint stored at R_FPRLEN.  R_PKTYPE receives the public key
- * type.  */
+ * (BLOB,BLOBLEN).  r_UBID must point to a buffer of at least UBID_LEN
+ * bytes, on success it receives the UBID (primary fingerprint
+ * truncated 20 octets). R_PKTYPE receives the public key type.  */
 gpg_error_t
-be_fingerprint_from_blob (const void *blob, size_t bloblen,
-                          enum pubkey_types *r_pktype,
-                          char *r_fpr, unsigned int *r_fprlen)
+be_ubid_from_blob (const void *blob, size_t bloblen,
+                   enum pubkey_types *r_pktype, char *r_ubid)
 {
   gpg_error_t err;
 
@@ -246,9 +244,7 @@ be_fingerprint_from_blob (const void *blob, size_t bloblen,
        * we have the entire certificate here (we checked the start of
        * the blob and assume that the length is also okay).  */
       *r_pktype = PUBKEY_TYPE_X509;
-      gcry_md_hash_buffer (GCRY_MD_SHA1, r_fpr, blob, bloblen);
-      *r_fprlen = 20;
-
+      gcry_md_hash_buffer (GCRY_MD_SHA1, r_ubid, blob, bloblen);
       err = 0;
     }
   else
@@ -264,10 +260,8 @@ be_fingerprint_from_blob (const void *blob, size_t bloblen,
       else
         {
           *r_pktype = PUBKEY_TYPE_OPGP;
-          log_assert (info.primary.fprlen <= 32);
-          memcpy (r_fpr, info.primary.fpr, info.primary.fprlen);
-          *r_fprlen = info.primary.fprlen;
-
+          log_assert (info.primary.fprlen >= 20);
+          memcpy (r_ubid, info.primary.fpr, UBID_LEN);
           _keybox_destroy_openpgp_info (&info);
         }
     }
index e978552..c372d90 100644 (file)
@@ -83,11 +83,11 @@ struct db_request_s
   unsigned int next_dbidx;
 
   /* The last UBID found in the cache and the corresponding keyid and,
-   * if found via fpr, the fingerprint.  For the LAST_CACHE_FPRLEN see
-   * above.  The entry here is only valid if LAST_CACHE_VALID is set;
-   * if LAST_CACHE_FINAL is also set, this indicates that no further
+   * if found via fpr, the fingerprint.  For the LAST_CACHED_FPRLEN see
+   * above.  The entry here is only valid if LAST_CACHED_VALID is set;
+   * if LAST_CACHED_FINAL is also set, this indicates that no further
    * database searches are required.  */
-  unsigned char last_cached_ubid[20];
+  unsigned char last_cached_ubid[UBID_LEN];
   u32 last_cached_kid_h;
   u32 last_cached_kid_l;
   unsigned char last_cached_fpr[32];
@@ -106,12 +106,12 @@ gpg_error_t be_find_request_part (backend_handle_t backend_hd,
 gpg_error_t be_return_pubkey (ctrl_t ctrl, const void *buffer, size_t buflen,
                               enum pubkey_types pubkey_type,
                               const unsigned char *ubid);
-gpg_error_t be_fingerprint_from_blob (const void *blob, size_t bloblen,
-                                      enum pubkey_types *r_pktype,
-                                      char *r_fpr, unsigned int *r_fprlen);
+gpg_error_t be_ubid_from_blob (const void *blob, size_t bloblen,
+                               enum pubkey_types *r_pktype, char *r_ubid);
 
 
 /*-- backend-cache.c --*/
+gpg_error_t be_cache_initialize (void);
 gpg_error_t be_cache_add_resource (ctrl_t ctrl, backend_handle_t *r_hd);
 void be_cache_release_resource (ctrl_t ctrl, backend_handle_t hd);
 gpg_error_t be_cache_search (ctrl_t ctrl, backend_handle_t backend_hd,
@@ -137,8 +137,7 @@ gpg_error_t be_kbx_search (ctrl_t ctrl, backend_handle_t hd,
                            db_request_t request,
                            KEYDB_SEARCH_DESC *desc, unsigned int ndesc);
 gpg_error_t be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
-                         db_request_t request, const unsigned char *ubid,
-                         const unsigned char *fpr, unsigned int fprlen);
+                         db_request_t request, const unsigned char *ubid);
 gpg_error_t be_kbx_insert (ctrl_t ctrl, backend_handle_t backend_hd,
                            db_request_t request, enum pubkey_types pktype,
                            const void *blob, size_t bloblen);
index 5bf1880..de9373c 100644 (file)
@@ -112,7 +112,8 @@ kbxd_add_resource  (ctrl_t ctrl, const char *filename_arg, int readonly)
    * always be the first to be queried.  */
   if (!no_of_databases && !db_type)
     {
-      err = kbxd_add_resource (ctrl, "[cache]", 0);
+      err = be_cache_initialize ();
+      /* err = kbxd_add_resource (ctrl, "[cache]", 0); */
       if (err)
         goto leave;
     }
@@ -339,7 +340,7 @@ kbxd_search (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
         {
           /* We need to set the startpoint for the search.  */
           err = be_kbx_seek (ctrl, db->backend_handle, request,
-                             request->last_cached_ubid, NULL, 0);
+                             request->last_cached_ubid);
           if (err)
             {
               log_debug ("%s: seeking %s to an UBID failed: %s\n",
@@ -386,17 +387,17 @@ kbxd_search (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
 
 
 \f
-/* Store; that is insert or update the key (BLOB,BLOBLEN).  If
- * ONLY_UPDATE is set the key must exist.  */
+/* Store; that is insert or update the key (BLOB,BLOBLEN).  MODE
+ * controls whether only updates or only inserts are allowed.  */
 gpg_error_t
-kbxd_store (ctrl_t ctrl, const void *blob, size_t bloblen, int only_update)
+kbxd_store (ctrl_t ctrl, const void *blob, size_t bloblen,
+            enum kbxd_store_modes mode)
 {
   gpg_error_t err;
   db_request_t request;
   unsigned int dbidx;
   db_desc_t db;
-  char fpr[32];
-  unsigned int fprlen;
+  char ubid[UBID_LEN];
   enum pubkey_types pktype;
   int insert = 0;
 
@@ -418,7 +419,7 @@ kbxd_store (ctrl_t ctrl, const void *blob, size_t bloblen, int only_update)
   request = ctrl->opgp_req;
 
   /* Check whether to insert or update.  */
-  err = be_fingerprint_from_blob (blob, bloblen, &pktype, fpr, &fprlen);
+  err = be_ubid_from_blob (blob, bloblen, &pktype, ubid);
   if (err)
     goto leave;
 
@@ -433,7 +434,7 @@ kbxd_store (ctrl_t ctrl, const void *blob, size_t bloblen, int only_update)
     }
   db = databases + dbidx;
 
-  err = be_kbx_seek (ctrl, db->backend_handle, request, NULL, fpr, fprlen);
+  err = be_kbx_seek (ctrl, db->backend_handle, request, ubid);
   if (!err)
     ; /* Found - need to update.  */
   else if (gpg_err_code (err) == GPG_ERR_EOF)
@@ -447,15 +448,19 @@ kbxd_store (ctrl_t ctrl, const void *blob, size_t bloblen, int only_update)
 
   if (insert)
     {
-      err = be_kbx_insert (ctrl, db->backend_handle, request,
-                           pktype, blob, bloblen);
+      if (mode == KBXD_STORE_UPDATE)
+        err = gpg_error (GPG_ERR_CONFLICT);
+      else
+        err = be_kbx_insert (ctrl, db->backend_handle, request,
+                             pktype, blob, bloblen);
     }
-  else if (only_update)
-    err = gpg_error (GPG_ERR_DUP_KEY);
   else /* Update.  */
     {
-      err = be_kbx_update (ctrl, db->backend_handle, request,
-                           pktype, blob, bloblen);
+      if (mode == KBXD_STORE_INSERT)
+        err = gpg_error (GPG_ERR_CONFLICT);
+      else
+        err = be_kbx_update (ctrl, db->backend_handle, request,
+                             pktype, blob, bloblen);
     }
 
  leave:
index 7c86514..45a8dbd 100644 (file)
 #include "keybox-search-desc.h"
 
 
+enum kbxd_store_modes
+  {
+   KBXD_STORE_AUTO = 0, /* Update or insert.    */
+   KBXD_STORE_INSERT,   /* Allow only inserts.  */
+   KBXD_STORE_UPDATE    /* Allow only updates.  */
+  };
+
+
 gpg_error_t kbxd_add_resource  (ctrl_t ctrl,
                                 const char *filename_arg, int readonly);
 
@@ -32,7 +40,7 @@ gpg_error_t kbxd_search (ctrl_t ctrl,
                          KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
                          int reset);
 gpg_error_t kbxd_store (ctrl_t ctrl, const void *blob, size_t bloblen,
-                        int only_update);
+                        enum kbxd_store_modes mode);
 
 
 #endif /*KBX_FRONTEND_H*/
index 0da937f..5113620 100644 (file)
@@ -466,29 +466,38 @@ cmd_next (assuan_context_t ctx, char *line)
 
 
 static const char hlp_store[] =
-  "STORE [--update]\n"
+  "STORE [--update|--insert]\n"
   "\n"
   "Insert a key into the database.  Whether to insert or update\n"
   "the key is decided by looking at the primary key's fingerprint.\n"
-  "With option --update the key must already exist. The actual key\n"
-  "material is requested by this function using\n"
+  "With option --update the key must already exist.\n"
+  "With option --insert the key must not already exist.\n"
+  "The actual key material is requested by this function using\n"
   "  INQUIRE BLOB";
 static gpg_error_t
 cmd_store (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
-  int opt_update;
+  int opt_update, opt_insert;
+  enum kbxd_store_modes mode;
   gpg_error_t err;
   unsigned char *value = NULL;
   size_t valuelen;
 
   opt_update = has_option (line, "--update");
+  opt_insert = has_option (line, "--insert");
   line = skip_options (line);
   if (*line)
     {
       err = set_error (GPG_ERR_INV_ARG, "no args expected");
       goto leave;
     }
+  if (opt_update && !opt_insert)
+    mode = KBXD_STORE_UPDATE;
+  else if (!opt_update && opt_insert)
+    mode = KBXD_STORE_INSERT;
+  else
+    mode = KBXD_STORE_AUTO;
 
   /* Ask for the key material.  */
   err = assuan_inquire (ctx, "BLOB", &value, &valuelen, 0);
@@ -504,7 +513,7 @@ cmd_store (assuan_context_t ctx, char *line)
       goto leave;
     }
 
-  err = kbxd_store (ctrl, value, valuelen, opt_update);
+  err = kbxd_store (ctrl, value, valuelen, mode);
 
 
  leave:
index 0fced7e..b953e8c 100644 (file)
@@ -67,7 +67,6 @@
    - u16  Blob flags
           bit 0 = contains secret key material (not used)
           bit 1 = ephemeral blob (e.g. used while querying external resources)
-          bit 2 = blob has an UBID field.
    - u32  Offset to the OpenPGP keyblock or the X.509 DER encoded
           certificate
    - u32  The length of the keyblock or certificate
    - bN   Space for the keyblock or certificate.
    - bN   RFU.  This is the remaining space after keyblock and before
           the checksum.  Not part of the SHA-1 checksum.
-   - bN   Only if blob flags bit 2 is set: 20 octet Unique Blob-ID (UBID).
-          This is the SHA-1 checksum of the keyblock or certificate.
-          This is not part of the SHA-1 checksum below.
    - b20  SHA-1 checksum (useful for KS synchronization?)
           Note, that KBX versions before GnuPG 2.1 used an MD5
           checksum.  However it was only created but never checked.
@@ -694,8 +690,8 @@ create_blob_finish (KEYBOXBLOB blob)
   unsigned char *pp;
   size_t n;
 
-  /* Write placeholders for the UBID and the checksum */
-  put_membuf (a, NULL, 40);
+  /* Write placeholders for the checksum.  */
+  put_membuf (a, NULL, 20);
 
   /* get the memory area */
   n = 0; /* (Just to avoid compiler warning.) */
@@ -729,9 +725,6 @@ create_blob_finish (KEYBOXBLOB blob)
     blob->fixups = NULL;
   }
 
-  /* Compute and store the UBID.                     (image_off)  (image_len) */
-  gcry_md_hash_buffer (GCRY_MD_SHA1, p + n - 40, p + get32 (p+8), get32 (p+12));
-
   /* Compute and store the SHA-1 checksum. */
   gcry_md_hash_buffer (GCRY_MD_SHA1, p + n - 20, p, n - 40);
 
index 55a47a4..0c289d5 100644 (file)
@@ -63,41 +63,6 @@ print_string (FILE *fp, const byte *p, size_t n, int delim)
 }
 
 
-static void
-print_ubib (const byte *buffer, size_t length, FILE *fp)
-{
-  const byte *p;
-  int i;
-  size_t image_off, image_len;
-  unsigned char digest[20];
-
-  fprintf (fp, "UBIB: ");
-  if (length < 40)
-    {
-      fputs ("[blob too short for a stored UBIB]\n", fp);
-      return;
-    }
-
-  p = buffer + length - 40;
-  for (i=0; i < 20; p++, i++)
-    fprintf (fp, "%02X", *p);
-
-  image_off = get32 (buffer+8);
-  image_len = get32 (buffer+12);
-  if ((uint64_t)image_off+(uint64_t)image_len > (uint64_t)length)
-    {
-      fputs (" [image claims to be longer than the blob]\n", fp);
-      return;
-    }
-
-  gcry_md_hash_buffer (GCRY_MD_SHA1, digest, buffer+image_off,image_len);
-  if (memcmp (digest, buffer + length - 40, 20))
-    fputs (" [does not match the image]\n", fp);
-  else
-    fputc ('\n', fp);
-}
-
-
 static int
 print_checksum (const byte *buffer, size_t length, size_t unhashed, FILE *fp)
 {
@@ -205,8 +170,7 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
   ulong nserial;
   ulong unhashed;
   const byte *p;
-  int is_fpr32;  /* blob ersion 2 */
-  int have_ubib = 0;
+  int is_fpr32;  /* blob version 2 */
 
   buffer = _keybox_get_blob_image (blob, &length);
 
@@ -273,14 +237,6 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
           fputs ("ephemeral", fp);
           any++;
         }
-      if ((n & 4))
-        {
-          if (any)
-            putc (',', fp);
-          fputs ("ubid", fp);
-          any++;
-          have_ubib = 1;
-        }
       putc (')', fp);
     }
   putc ('\n', fp);
@@ -466,8 +422,6 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
       n = get32 ( buffer + length - unhashed);
       fprintf (fp, "Storage-Flags: %08lx\n", n );
     }
-  if (have_ubib)
-    print_ubib (buffer, length, fp);
   print_checksum (buffer, length, unhashed, fp);
   return 0;
 }
index 7fa97e9..1167b1a 100644 (file)
@@ -61,6 +61,7 @@ enum pubkey_types
 struct gpg_pkt_user_id_s;
 typedef struct gpg_pkt_user_id_s *gpg_pkt_user_id_t;
 
+
 /* A search descriptor.  */
 struct keydb_search_desc
 {
@@ -79,8 +80,8 @@ struct keydb_search_desc
     const char *name;
     unsigned char fpr[32];
     u32 kid[2]; /* Note that this is in native endianness.  */
-    unsigned char grip[20];
-    unsigned char ubid[20];
+    unsigned char grip[KEYGRIP_LEN];
+    unsigned char ubid[UBID_LEN];
   } u;
   byte fprlen;  /* Only used with KEYDB_SEARCH_MODE_FPR.  */
   int exact;    /* Use exactly this key ('!' suffix in gpg).  */
index 95ad072..91d2a17 100644 (file)
@@ -321,6 +321,36 @@ blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
 }
 
 
+/* Returns true if found.  */
+static int
+blob_cmp_ubid (KEYBOXBLOB blob, const unsigned char *ubid)
+{
+  const unsigned char *buffer;
+  size_t length;
+  size_t pos;
+  size_t nkeys, keyinfolen;
+  int fpr32;
+
+  buffer = _keybox_get_blob_image (blob, &length);
+  if (length < 40)
+    return 0; /* blob too short */
+  fpr32 = buffer[5] == 2;
+
+  /*keys*/
+  nkeys = get16 (buffer + 16);
+  keyinfolen = get16 (buffer + 18 );
+  if (!nkeys || keyinfolen < (fpr32?56:28))
+    return 0; /* invalid blob */
+  pos = 20;
+  if (pos + (uint64_t)keyinfolen*nkeys > (uint64_t)length)
+    return 0; /* out of bounds */
+
+  if (!memcmp (buffer + pos, ubid, UBID_LEN))
+    return 1; /* found */
+  return 0;   /* not found */
+}
+
+
 static int
 blob_cmp_name (KEYBOXBLOB blob, int idx,
                const char *name, size_t namelen, int substr, int x509)
@@ -696,36 +726,16 @@ has_keygrip (KEYBOXBLOB blob, const unsigned char *grip)
   return 0;
 }
 
+
+/* The UBID is the primary fingerprint.  For OpenPGP v5 keys only the
+ * leftmost 20 bytes (UBID_LEN) are used.  */
 static inline int
 has_ubid (KEYBOXBLOB blob, const unsigned char *ubid)
 {
-  size_t length;
-  const unsigned char *buffer;
-  size_t image_off, image_len;
-  unsigned char ubid_blob[20];
-
-  buffer = _keybox_get_blob_image (blob, &length);
-  if (length < 40)
-    return 0; /*GPG_ERR_TOO_SHORT*/
-
-  if ((get16 (buffer + 6) & 4))
-    {
-      /* The blob has a stored UBID.  */
-      return !memcmp (ubid, buffer + length - 40, 20);
-    }
-  else
-    {
-      /* Need to compute the UBID.  */
-      image_off = get32 (buffer+8);
-      image_len = get32 (buffer+12);
-      if ((uint64_t)image_off+(uint64_t)image_len > (uint64_t)length)
-        return 0; /*GPG_ERR_TOO_SHORT*/
-
-      gcry_md_hash_buffer (GCRY_MD_SHA1, ubid_blob, buffer+image_off,image_len);
-      return !memcmp (ubid, ubid_blob, 20);
-    }
+  return blob_cmp_ubid (blob, ubid);
 }
 
+
 static inline int
 has_issuer (KEYBOXBLOB blob, const char *name)
 {
@@ -1209,17 +1219,18 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
 
 \f
 /*
  Functions to return a certificate or a keyblock.  To be used after
  a successful search operation.
-*/
* Functions to return a certificate or a keyblock.  To be used after
* a successful search operation.
+ */
 
 /* Return the raw data from the last found blob.  Caller must release
  * the value stored at R_BUFFER.  If called with NULL for R_BUFFER
  * only the needed length for the buffer and the public key type is
- * returned.  */
+ * returned.  R_PUBKEY_TYPE and R_UBID can be used to return these
+ * attributes. */
 gpg_error_t
 keybox_get_data (KEYBOX_HANDLE hd, void **r_buffer, size_t *r_length,
-                 enum pubkey_types *r_pubkey_type)
+                 enum pubkey_types *r_pubkey_type, unsigned char *r_ubid)
 {
   const unsigned char *buffer;
   size_t length;
@@ -1259,6 +1270,20 @@ keybox_get_data (KEYBOX_HANDLE hd, void **r_buffer, size_t *r_length,
   if ((uint64_t)image_off+(uint64_t)image_len > (uint64_t)length)
     return gpg_error (GPG_ERR_TOO_SHORT);
 
+  if (r_ubid)
+    {
+      size_t keyinfolen;
+
+      /* We do a quick but sufficient consistency check.  For the full
+       * check see blob_cmp_ubid.  */
+      if (!get16 (buffer + 16)         /* No keys.  */
+          || (keyinfolen = get16 (buffer + 18)) < 28
+          || (20 + (uint64_t)keyinfolen) > (uint64_t)length)
+        return gpg_error (GPG_ERR_TOO_SHORT);
+
+      memcpy (r_ubid, buffer + 20, UBID_LEN);
+    }
+
   if (r_length)
     *r_length = image_len;
   if (r_buffer)
index b57823a..6e5a51c 100644 (file)
@@ -87,7 +87,8 @@ gpg_error_t _keybox_write_header_blob (FILE *fp, estream_t stream,
 /*-- keybox-search.c --*/
 gpg_error_t keybox_get_data (KEYBOX_HANDLE hd,
                              void **r_buffer, size_t *r_length,
-                             enum pubkey_types *r_pubkey_type);
+                             enum pubkey_types *r_pubkey_type,
+                             unsigned char *r_ubid);
 gpg_error_t keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf,
                                  int *r_pk_no, int *r_uid_no);
 #ifdef KEYBOX_WITH_X509