diff --git a/common/userids.c b/common/userids.c index eb714a9af..5e2704362 100644 --- a/common/userids.c +++ b/common/userids.c @@ -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; diff --git a/common/util.h b/common/util.h index 6c878083a..fc869800a 100644 --- a/common/util.h +++ b/common/util.h @@ -55,6 +55,10 @@ * 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" diff --git a/doc/DETAILS b/doc/DETAILS index 6ce340e8c..bd00006e9 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -1152,11 +1152,10 @@ 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 (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 (^). + and 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 prefixed with a caret (^). * Format of the --attribute-fd output diff --git a/g10/call-keyboxd.c b/g10/call-keyboxd.c index 9625587ac..99dfac58f 100644 --- a/g10/call-keyboxd.c +++ b/g10/call-keyboxd.c @@ -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; diff --git a/g10/keydb-private.h b/g10/keydb-private.h index 47a09ca93..fdc905edf 100644 --- a/g10/keydb-private.h +++ b/g10/keydb-private.h @@ -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 */ diff --git a/g10/keydb.c b/g10/keydb.c index 57d51e7b7..bf411371e 100644 --- a/g10/keydb.c +++ b/g10/keydb.c @@ -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"); diff --git a/kbx/backend-cache.c b/kbx/backend-cache.c index 10a6f6bd9..45e5c7158 100644 --- a/kbx/backend-cache.c +++ b/kbx/backend-cache.c @@ -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) +/* 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, diff --git a/kbx/backend-kbx.c b/kbx/backend-kbx.c index d8dafe0e5..ff4f56773 100644 --- a/kbx/backend-kbx.c +++ b/kbx/backend-kbx.c @@ -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); diff --git a/kbx/backend-support.c b/kbx/backend-support.c index f1a97996f..f1e80b0c3 100644 --- a/kbx/backend-support.c +++ b/kbx/backend-support.c @@ -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); } } diff --git a/kbx/backend.h b/kbx/backend.h index e97855246..c372d9071 100644 --- a/kbx/backend.h +++ b/kbx/backend.h @@ -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); diff --git a/kbx/frontend.c b/kbx/frontend.c index 5bf18809e..de9373c8f 100644 --- a/kbx/frontend.c +++ b/kbx/frontend.c @@ -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, -/* 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: diff --git a/kbx/frontend.h b/kbx/frontend.h index 7c86514d0..45a8dbdbd 100644 --- a/kbx/frontend.h +++ b/kbx/frontend.h @@ -23,6 +23,14 @@ #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*/ diff --git a/kbx/kbxserver.c b/kbx/kbxserver.c index 0da937f39..511362004 100644 --- a/kbx/kbxserver.c +++ b/kbx/kbxserver.c @@ -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: diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c index 0fced7e1c..b953e8c57 100644 --- a/kbx/keybox-blob.c +++ b/kbx/keybox-blob.c @@ -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 @@ -145,9 +144,6 @@ - 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); diff --git a/kbx/keybox-dump.c b/kbx/keybox-dump.c index 55a47a403..0c289d50a 100644 --- a/kbx/keybox-dump.c +++ b/kbx/keybox-dump.c @@ -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; } diff --git a/kbx/keybox-search-desc.h b/kbx/keybox-search-desc.h index 7fa97e97b..1167b1a6d 100644 --- a/kbx/keybox-search-desc.h +++ b/kbx/keybox-search-desc.h @@ -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). */ diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c index 95ad07251..91d2a1735 100644 --- a/kbx/keybox-search.c +++ b/kbx/keybox-search.c @@ -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, /* - 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) diff --git a/kbx/keybox.h b/kbx/keybox.h index b57823a98..6e5a51c63 100644 --- a/kbx/keybox.h +++ b/kbx/keybox.h @@ -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