From 4be79b5abeae82b9840e6aa93874f743e13c6df7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 27 Sep 2019 10:05:07 +0200 Subject: [PATCH] kbx,gpg: Allow lookup using a UBID. * 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 --- common/userids.c | 14 ++++++++++++++ doc/DETAILS | 9 +++++---- g10/call-keyboxd.c | 8 ++++++++ g10/keydb.c | 10 +++++++++- kbx/backend-cache.c | 27 +++++++++++++++++++++++++-- kbx/backend-kbx.c | 2 ++ kbx/backend.h | 1 + 7 files changed, 64 insertions(+), 7 deletions(-) diff --git a/common/userids.c b/common/userids.c index 55bd85546..eb714a9af 100644 --- a/common/userids.c +++ b/common/userids.c @@ -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') { diff --git a/doc/DETAILS b/doc/DETAILS index ed5cadec6..0610108f4 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -1144,10 +1144,11 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB: *** PUBKEY_INFO The type of the public key in the following D-lines or communicated via a pipe. is the value of =enum pubkey_types= - and 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 of up to 64 characters. - + and 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 of up to 64 characters. + Note that the keyboxd SEARCH command can be used to lookup the + public key using the prefixed with a caret (^). * Format of the --attribute-fd output diff --git a/g10/call-keyboxd.c b/g10/call-keyboxd.c index 97f84c03d..88ad07817 100644 --- a/g10/call-keyboxd.c +++ b/g10/call-keyboxd.c @@ -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; diff --git a/g10/keydb.c b/g10/keydb.c index 6ca239475..39ec5442e 100644 --- a/g10/keydb.c +++ b/g10/keydb.c @@ -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: diff --git a/kbx/backend-cache.c b/kbx/backend-cache.c index d5b46b50a..10a6f6bd9 100644 --- a/kbx/backend-cache.c +++ b/kbx/backend-cache.c @@ -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); diff --git a/kbx/backend-kbx.c b/kbx/backend-kbx.c index e58b74a3b..851f2dadf 100644 --- a/kbx/backend-kbx.c +++ b/kbx/backend-kbx.c @@ -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); diff --git a/kbx/backend.h b/kbx/backend.h index 8b389d35c..675ec213d 100644 --- a/kbx/backend.h +++ b/kbx/backend.h @@ -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;