diff --git a/common/userids.c b/common/userids.c index 01f2cd84b..41cf2876c 100644 --- a/common/userids.c +++ b/common/userids.c @@ -226,14 +226,15 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack) goto out; } } - if (i != 32 && i != 40) + if (i != 32 && i != 40 && i != 64) { rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid length of fpr. */ goto out; } for (i=0,si=s; si < se; i++, si +=2) desc->u.fpr[i] = hextobyte(si); - for (; i < 20; i++) + desc->fprlen = i; + for (; i < 32; i++) desc->u.fpr[i]= 0; mode = KEYDB_SEARCH_MODE_FPR; } @@ -326,6 +327,8 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack) } desc->u.fpr[i] = c; } + for (; i < 32; i++) + desc->u.fpr[i]= 0; mode = KEYDB_SEARCH_MODE_FPR16; } else if ((hexlength == 40 @@ -333,7 +336,7 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack) || (s[hexlength] == '!' && s[hexlength + 1] == 0))) || (!hexprefix && hexlength == 41 && *s == '0')) { - /* SHA1/RMD160 fingerprint. */ + /* SHA1 fingerprint. */ int i; if (hexlength == 41) s++; @@ -347,8 +350,31 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack) } desc->u.fpr[i] = c; } + for (; i < 32; i++) + desc->u.fpr[i]= 0; mode = KEYDB_SEARCH_MODE_FPR20; } + else if ((hexlength == 64 + && (s[hexlength] == 0 + || (s[hexlength] == '!' && s[hexlength + 1] == 0))) + || (!hexprefix && hexlength == 65 && *s == '0')) + { + /* SHA256 fingerprint. */ + int i; + if (hexlength == 65) + s++; + for (i=0; i < 32; i++, s+=2) + { + int c = hextobyte(s); + if (c == -1) + { + rc = gpg_error (GPG_ERR_INV_USER_ID); + goto out; + } + desc->u.fpr[i] = c; + } + mode = KEYDB_SEARCH_MODE_FPR32; + } else if (!hexprefix) { /* The fingerprint in an X.509 listing is often delimited by @@ -368,14 +394,17 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack) } if (i == 20) mode = KEYDB_SEARCH_MODE_FPR20; + for (; i < 32; i++) + desc->u.fpr[i]= 0; } if (!mode) { /* Still not found. Now check for a space separated - OpenPGP v4 fingerprint like: - 8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367 - or - 8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367 + * OpenPGP v4 fingerprint like: + * 8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367 + * or + * 8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367 + * FIXME: Support OpenPGP v5 fingerprint */ hexlength = strspn (s, " 0123456789abcdefABCDEF"); if (s[hexlength] && s[hexlength] != ' ') @@ -410,6 +439,8 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack) } if (i == 20) mode = KEYDB_SEARCH_MODE_FPR20; + for (; i < 32; i++) + desc->u.fpr[i]= 0; } } if (!mode) /* Default to substring search. */ diff --git a/g10/delkey.c b/g10/delkey.c index bf8c4e93b..b4d643f59 100644 --- a/g10/delkey.c +++ b/g10/delkey.c @@ -71,7 +71,8 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force, err = classify_user_id (username, &desc, 1); exactmatch = (desc.mode == KEYDB_SEARCH_MODE_FPR || desc.mode == KEYDB_SEARCH_MODE_FPR16 - || desc.mode == KEYDB_SEARCH_MODE_FPR20); + || desc.mode == KEYDB_SEARCH_MODE_FPR20 + || desc.mode == KEYDB_SEARCH_MODE_FPR32); if (!err) err = keydb_search (hd, &desc, 1, NULL); if (err) diff --git a/g10/export.c b/g10/export.c index d53be99fe..2d34c8244 100644 --- a/g10/export.c +++ b/g10/export.c @@ -453,8 +453,9 @@ exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node) case KEYDB_SEARCH_MODE_FPR16: case KEYDB_SEARCH_MODE_FPR20: + case KEYDB_SEARCH_MODE_FPR32: case KEYDB_SEARCH_MODE_FPR: - fingerprint_from_pk (node->pkt->pkt.public_key, fpr,&fprlen); + fingerprint_from_pk (node->pkt->pkt.public_key, fpr, &fprlen); break; default: @@ -474,13 +475,22 @@ exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node) break; case KEYDB_SEARCH_MODE_FPR16: - if (!memcmp (desc->u.fpr, fpr, 16)) + if (fprlen == 16 && !memcmp (desc->u.fpr, fpr, 16)) result = 1; break; case KEYDB_SEARCH_MODE_FPR20: + if (fprlen == 20 && !memcmp (desc->u.fpr, fpr, 20)) + result = 1; + break; + + case KEYDB_SEARCH_MODE_FPR32: + if (fprlen == 32 && !memcmp (desc->u.fpr, fpr, 32)) + result = 1; + break; + case KEYDB_SEARCH_MODE_FPR: - if (!memcmp (desc->u.fpr, fpr, 20)) + if (fprlen == desc->fprlen && !memcmp (desc->u.fpr, fpr, desc->fprlen)) result = 1; break; diff --git a/g10/getkey.c b/g10/getkey.c index 039a5edb5..1467bc89f 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -899,6 +899,7 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist, && ctx->items[n].mode != KEYDB_SEARCH_MODE_LONG_KID && ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR16 && ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR20 + && ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR32 && ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR) { ctx->items[n].skipfnc = skip_unusable; @@ -1654,7 +1655,7 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock, if (r_keyblock) *r_keyblock = NULL; - if (fprint_len == 20 || fprint_len == 16) + if (fprint_len == 32 || fprint_len == 20 || fprint_len == 16) { struct getkey_ctx_s ctx; KBNODE kb = NULL; @@ -1670,9 +1671,9 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock, return gpg_error_from_syserror (); ctx.nitems = 1; - ctx.items[0].mode = fprint_len == 16 ? KEYDB_SEARCH_MODE_FPR16 - : KEYDB_SEARCH_MODE_FPR20; + ctx.items[0].mode = KEYDB_SEARCH_MODE_FPR; memcpy (ctx.items[0].u.fpr, fprint, fprint_len); + ctx.items[0].fprlen = fprint_len; if (pk) ctx.req_usage = pk->req_usage; rc = lookup (ctrl, &ctx, 0, &kb, &found_key); @@ -1745,8 +1746,6 @@ get_keyblock_byfprint_fast (kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd, for (i = 0; i < MAX_FINGERPRINT_LEN && i < fprint_len; i++) fprbuf[i] = fprint[i]; - while (i < MAX_FINGERPRINT_LEN) - fprbuf[i++] = 0; hd = keydb_new (); if (!hd) @@ -1770,7 +1769,7 @@ get_keyblock_byfprint_fast (kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd, if (r_hd) *r_hd = hd; - err = keydb_search_fpr (hd, fprbuf); + err = keydb_search_fpr (hd, fprbuf, fprint_len); if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) { if (!r_hd) diff --git a/g10/gpg.c b/g10/gpg.c index ddf8c86eb..b15c8eaa3 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -5077,6 +5077,7 @@ main (int argc, char **argv) || desc.mode == KEYDB_SEARCH_MODE_LONG_KID || desc.mode == KEYDB_SEARCH_MODE_FPR16 || desc.mode == KEYDB_SEARCH_MODE_FPR20 + || desc.mode == KEYDB_SEARCH_MODE_FPR32 || desc.mode == KEYDB_SEARCH_MODE_FPR || desc.mode == KEYDB_SEARCH_MODE_KEYGRIP)) { diff --git a/g10/import.c b/g10/import.c index 64cc4b093..25ccc2fc6 100644 --- a/g10/import.c +++ b/g10/import.c @@ -2957,9 +2957,7 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options, size_t an; fingerprint_from_pk (pk, afp, &an); - while (an < MAX_FINGERPRINT_LEN) - afp[an++] = 0; - rc = keydb_search_fpr (hd, afp); + rc = keydb_search_fpr (hd, afp, an); } if (rc) { diff --git a/g10/keydb.c b/g10/keydb.c index 03fadfd54..6ecb4eb8b 100644 --- a/g10/keydb.c +++ b/g10/keydb.c @@ -81,6 +81,7 @@ enum keyblock_cache_states { struct keyblock_cache { enum keyblock_cache_states state; byte fpr[MAX_FINGERPRINT_LEN]; + byte fprlen; iobuf_t iobuf; /* Image of the keyblock. */ int pk_no; int uid_no; @@ -566,8 +567,12 @@ keydb_search_desc_dump (struct keydb_search_desc *desc) bin2hex (desc->u.fpr, 20, fpr); return xasprintf ("FPR20: '%s'", format_hexfingerprint (fpr, b, sizeof (b))); - case KEYDB_SEARCH_MODE_FPR: + case KEYDB_SEARCH_MODE_FPR32: bin2hex (desc->u.fpr, 20, fpr); + return xasprintf ("FPR32: '%s'", + format_hexfingerprint (fpr, b, sizeof (b))); + case KEYDB_SEARCH_MODE_FPR: + bin2hex (desc->u.fpr, desc->fprlen, fpr); return xasprintf ("FPR: '%s'", format_hexfingerprint (fpr, b, sizeof (b))); case KEYDB_SEARCH_MODE_ISSUER: @@ -1531,6 +1536,8 @@ keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb) fingerprint_from_pk (pk, desc.u.fpr, &len); if (len == 20) desc.mode = KEYDB_SEARCH_MODE_FPR20; + else if (len == 32) + desc.mode = KEYDB_SEARCH_MODE_FPR32; else log_bug ("%s: Unsupported key length: %zu\n", __func__, len); @@ -1862,6 +1869,7 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, int was_reset = hd->is_reset; /* If an entry is already in the cache, then don't add it again. */ int already_in_cache = 0; + int fprlen; if (descindex) *descindex = 0; /* Make sure it is always set on return. */ @@ -1902,12 +1910,21 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, /* NB: If one of the exact search modes below is used in a loop to walk over all keys (with the same fingerprint) the caching must have been disabled for the handle. */ + if (desc[0].mode == KEYDB_SEARCH_MODE_FPR20) + fprlen = 20; + else if (desc[0].mode == KEYDB_SEARCH_MODE_FPR32) + fprlen = 32; + else if (desc[0].mode == KEYDB_SEARCH_MODE_FPR) + fprlen = desc[0].fprlen; + else + fprlen = 0; + if (!hd->no_caching && ndesc == 1 - && (desc[0].mode == KEYDB_SEARCH_MODE_FPR20 - || desc[0].mode == KEYDB_SEARCH_MODE_FPR) - && hd->keyblock_cache.state == KEYBLOCK_CACHE_FILLED - && !memcmp (hd->keyblock_cache.fpr, desc[0].u.fpr, 20) + && fprlen + && hd->keyblock_cache.state == KEYBLOCK_CACHE_FILLED + && hd->keyblock_cache.fprlen == fprlen + && !memcmp (hd->keyblock_cache.fpr, desc[0].u.fpr, fprlen) /* Make sure the current file position occurs before the cached result to avoid an infinite loop. */ && (hd->current < hd->keyblock_cache.resource @@ -1922,8 +1939,7 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, hd->current = hd->keyblock_cache.resource; /* HD->KEYBLOCK_CACHE.OFFSET is the last byte in the record. Seek just beyond that. */ - keybox_seek (hd->active[hd->current].u.kb, - hd->keyblock_cache.offset + 1); + keybox_seek (hd->active[hd->current].u.kb, hd->keyblock_cache.offset + 1); keydb_stats.found_cached++; return 0; } @@ -1986,8 +2002,8 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, keyblock_cache_clear (hd); if (!hd->no_caching && !rc - && ndesc == 1 && (desc[0].mode == KEYDB_SEARCH_MODE_FPR20 - || desc[0].mode == KEYDB_SEARCH_MODE_FPR) + && ndesc == 1 + && fprlen && hd->active[hd->current].type == KEYDB_RESOURCE_TYPE_KEYBOX) { hd->keyblock_cache.state = KEYBLOCK_CACHE_PREPARED; @@ -1997,11 +2013,14 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, within the record. */ hd->keyblock_cache.offset = keybox_offset (hd->active[hd->current].u.kb) - 1; - memcpy (hd->keyblock_cache.fpr, desc[0].u.fpr, 20); + memcpy (hd->keyblock_cache.fpr, desc[0].u.fpr, fprlen); + hd->keyblock_cache.fprlen = fprlen; } if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND - && ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID && was_reset + && ndesc == 1 + && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID + && was_reset && !already_in_cache) kid_not_found_insert (desc[0].u.kid); @@ -2078,12 +2097,13 @@ keydb_search_kid (KEYDB_HANDLE hd, u32 *kid) * off. If you want to search the whole database, then you need to * first call keydb_search_reset(). */ gpg_error_t -keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr) +keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr, size_t fprlen) { KEYDB_SEARCH_DESC desc; memset (&desc, 0, sizeof desc); desc.mode = KEYDB_SEARCH_MODE_FPR; - memcpy (desc.u.fpr, fpr, MAX_FINGERPRINT_LEN); + memcpy (desc.u.fpr, fpr, fprlen); + desc.fprlen = fprlen; return keydb_search (hd, &desc, 1, NULL); } diff --git a/g10/keydb.h b/g10/keydb.h index acb424455..c52856d7f 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -244,9 +244,9 @@ gpg_error_t keydb_search_next (KEYDB_HANDLE hd); key id. */ gpg_error_t keydb_search_kid (KEYDB_HANDLE hd, u32 *kid); -/* This is a convenience function for searching for keys with a long - (20 byte) fingerprint. */ -gpg_error_t keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr); +/* This is a convenience function for searching for keys by + * fingerprint. */ +gpg_error_t keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr, size_t fprlen); /*-- pkclist.c --*/ diff --git a/g10/keyedit.c b/g10/keyedit.c index 63a54fa21..ed1fd8a23 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -2566,7 +2566,8 @@ find_by_primary_fpr (ctrl_t ctrl, const char *fpr, if (classify_user_id (fpr, &desc, 1) || !(desc.mode == KEYDB_SEARCH_MODE_FPR || desc.mode == KEYDB_SEARCH_MODE_FPR16 - || desc.mode == KEYDB_SEARCH_MODE_FPR20)) + || desc.mode == KEYDB_SEARCH_MODE_FPR20 + || desc.mode == KEYDB_SEARCH_MODE_FPR32)) { log_error (_("\"%s\" is not a fingerprint\n"), fpr); err = gpg_error (GPG_ERR_INV_NAME); @@ -2591,10 +2592,16 @@ find_by_primary_fpr (ctrl_t ctrl, const char *fpr, && !desc.u.fpr[18] && !desc.u.fpr[19]) ; - else if (fprlen == 20 && (desc.mode == KEYDB_SEARCH_MODE_FPR20 - || desc.mode == KEYDB_SEARCH_MODE_FPR) + else if (fprlen == 20 && desc.mode == KEYDB_SEARCH_MODE_FPR20 && !memcmp (fprbin, desc.u.fpr, 20)) ; + else if (fprlen == 32 && desc.mode == KEYDB_SEARCH_MODE_FPR32 + && !memcmp (fprbin, desc.u.fpr, 32)) + ; + else if (desc.mode == KEYDB_SEARCH_MODE_FPR + && fprlen == desc.fprlen + && !memcmp (fprbin, desc.u.fpr, fprlen)) + ; else { log_error (_("\"%s\" is not the primary fingerprint\n"), fpr); @@ -2918,7 +2925,8 @@ keyedit_quick_set_expire (ctrl_t ctrl, const char *fpr, const char *expirestr, /* Parse the fingerprint. */ if (classify_user_id (subkeyfprs[idx], &desc, 1) || !(desc.mode == KEYDB_SEARCH_MODE_FPR - || desc.mode == KEYDB_SEARCH_MODE_FPR20)) + || desc.mode == KEYDB_SEARCH_MODE_FPR20 + || desc.mode == KEYDB_SEARCH_MODE_FPR32)) { log_error (_("\"%s\" is not a proper fingerprint\n"), subkeyfprs[idx] ); diff --git a/g10/keyid.c b/g10/keyid.c index e099c7d97..9558a2617 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -481,6 +481,32 @@ keystr_from_desc(KEYDB_SEARCH_DESC *desc) return keystr(keyid); } + case KEYDB_SEARCH_MODE_FPR32: + { + u32 keyid[2]; + + keyid[0] = buf32_to_u32 (desc->u.fpr); + keyid[1] = buf32_to_u32 (desc->u.fpr+4); + return keystr(keyid); + } + + case KEYDB_SEARCH_MODE_FPR: + { + u32 keyid[2]; + + if (desc->fprlen == 32) + { + keyid[0] = buf32_to_u32 (desc->u.fpr); + keyid[1] = buf32_to_u32 (desc->u.fpr+4); + } + else + { + keyid[0] = buf32_to_u32 (desc->u.fpr+12); + keyid[1] = buf32_to_u32 (desc->u.fpr+16); + } + return keystr(keyid); + } + case KEYDB_SEARCH_MODE_FPR16: return "?v3 fpr?"; diff --git a/g10/keyring.c b/g10/keyring.c index 25ef50747..bc1d06c09 100644 --- a/g10/keyring.c +++ b/g10/keyring.c @@ -997,6 +997,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, break; case KEYDB_SEARCH_MODE_FPR16: case KEYDB_SEARCH_MODE_FPR20: + case KEYDB_SEARCH_MODE_FPR32: case KEYDB_SEARCH_MODE_FPR: need_fpr = 1; break; @@ -1134,11 +1135,12 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, pk = pkt.pkt.public_key; ++pk_no; - if (need_fpr) { - fingerprint_from_pk (pk, afp, &an); - while (an < 20) /* fill up to 20 bytes */ - afp[an++] = 0; - } + if (need_fpr) + { + fingerprint_from_pk (pk, afp, &an); + while (an < 32) /* fill up to 32 bytes */ + afp[an++] = 0; + } if (need_keyid) keyid_from_pk (pk, aki); @@ -1185,10 +1187,18 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, goto found; break; case KEYDB_SEARCH_MODE_FPR20: - case KEYDB_SEARCH_MODE_FPR: if (pk && !memcmp (desc[n].u.fpr, afp, 20)) goto found; break; + case KEYDB_SEARCH_MODE_FPR32: + if (pk && !memcmp (desc[n].u.fpr, afp, 32)) + goto found; + break; + case KEYDB_SEARCH_MODE_FPR: + if (pk && desc[n].fprlen >= 16 && desc[n].fprlen <= 32 + && !memcmp (desc[n].u.fpr, afp, desc[n].fprlen)) + goto found; + break; case KEYDB_SEARCH_MODE_FIRST: if (pk) goto found; diff --git a/g10/keyserver.c b/g10/keyserver.c index 1ba94ed49..c414e2cb1 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -527,6 +527,25 @@ print_keyrec (ctrl_t ctrl, int number,struct keyrec *keyrec) } break; + /* If we get a modern fingerprint, we have the most + flexibility. */ + case KEYDB_SEARCH_MODE_FPR32: + { + u32 kid[2]; + keyid_from_fingerprint (ctrl, keyrec->desc.u.fpr, 32, kid); + es_printf("key %s",keystr(kid)); + } + break; + + case KEYDB_SEARCH_MODE_FPR: + { + u32 kid[2]; + keyid_from_fingerprint (ctrl, keyrec->desc.u.fpr, keyrec->desc.fprlen, + kid); + es_printf("key %s",keystr(kid)); + } + break; + default: BUG(); break; @@ -614,7 +633,9 @@ parse_keyrec(char *keystring) if (err || (work->desc.mode != KEYDB_SEARCH_MODE_SHORT_KID && work->desc.mode != KEYDB_SEARCH_MODE_LONG_KID && work->desc.mode != KEYDB_SEARCH_MODE_FPR16 - && work->desc.mode != KEYDB_SEARCH_MODE_FPR20)) + && work->desc.mode != KEYDB_SEARCH_MODE_FPR20 + && work->desc.mode != KEYDB_SEARCH_MODE_FPR32 + && work->desc.mode != KEYDB_SEARCH_MODE_FPR)) { work->desc.mode=KEYDB_SEARCH_MODE_NONE; return ret; @@ -996,7 +1017,9 @@ keyserver_export (ctrl_t ctrl, strlist_t users) if (err || (desc.mode != KEYDB_SEARCH_MODE_SHORT_KID && desc.mode != KEYDB_SEARCH_MODE_LONG_KID && desc.mode != KEYDB_SEARCH_MODE_FPR16 - && desc.mode != KEYDB_SEARCH_MODE_FPR20)) + && desc.mode != KEYDB_SEARCH_MODE_FPR20 + && desc.mode != KEYDB_SEARCH_MODE_FPR32 + && desc.mode != KEYDB_SEARCH_MODE_FPR)) { log_error(_("\"%s\" not a key ID: skipping\n"),users->d); continue; @@ -1070,6 +1093,16 @@ keyserver_retrieval_screener (kbnode_t keyblock, void *opaque) if (fpr_len == 20 && !memcmp (fpr, desc[n].u.fpr, 20)) return 0; } + else if (desc[n].mode == KEYDB_SEARCH_MODE_FPR32) + { + if (fpr_len == 32 && !memcmp (fpr, desc[n].u.fpr, 32)) + return 0; + } + else if (desc[n].mode == KEYDB_SEARCH_MODE_FPR) + { + if (fpr_len == desc[n].fprlen && !memcmp (fpr, desc[n].u.fpr, 32)) + return 0; + } else if (desc[n].mode == KEYDB_SEARCH_MODE_FPR16) { if (fpr_len == 16 && !memcmp (fpr, desc[n].u.fpr, 16)) @@ -1111,7 +1144,9 @@ keyserver_import (ctrl_t ctrl, strlist_t users) if (err || (desc[count].mode != KEYDB_SEARCH_MODE_SHORT_KID && desc[count].mode != KEYDB_SEARCH_MODE_LONG_KID && desc[count].mode != KEYDB_SEARCH_MODE_FPR16 - && desc[count].mode != KEYDB_SEARCH_MODE_FPR20)) + && desc[count].mode != KEYDB_SEARCH_MODE_FPR20 + && desc[count].mode != KEYDB_SEARCH_MODE_FPR32 + && desc[count].mode != KEYDB_SEARCH_MODE_FPR)) { log_error (_("\"%s\" not a key ID: skipping\n"), users->d); continue; @@ -1171,10 +1206,13 @@ keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len, desc.mode=KEYDB_SEARCH_MODE_FPR16; else if(fprint_len==20) desc.mode=KEYDB_SEARCH_MODE_FPR20; + else if(fprint_len==32) + desc.mode=KEYDB_SEARCH_MODE_FPR32; else return -1; memcpy(desc.u.fpr,fprint,fprint_len); + desc.fprlen = fprint_len; /* TODO: Warn here if the fingerprint we got doesn't match the one we asked for? */ @@ -1291,20 +1329,23 @@ keyidlist (ctrl_t ctrl, strlist_t users, KEYDB_SEARCH_DESC **klist, This is because it's easy to calculate any sort of keyid from a v4 fingerprint, but not a v3 fingerprint. */ - if(node->pkt->pkt.public_key->version<4) + if (node->pkt->pkt.public_key->version < 4) { (*klist)[*count].mode=KEYDB_SEARCH_MODE_LONG_KID; keyid_from_pk(node->pkt->pkt.public_key, (*klist)[*count].u.kid); } else - { + { size_t dummy; - (*klist)[*count].mode=KEYDB_SEARCH_MODE_FPR20; - fingerprint_from_pk(node->pkt->pkt.public_key, - (*klist)[*count].u.fpr,&dummy); - } + if (node->pkt->pkt.public_key->version == 4) + (*klist)[*count].mode = KEYDB_SEARCH_MODE_FPR20; + else + (*klist)[*count].mode = KEYDB_SEARCH_MODE_FPR32; + fingerprint_from_pk (node->pkt->pkt.public_key, + (*klist)[*count].u.fpr,&dummy); + } /* This is a little hackish, using the skipfncvalue as a void* pointer to the keyserver spec, but we don't need @@ -1621,9 +1662,10 @@ keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, int quiet = 0; if (desc[idx].mode == KEYDB_SEARCH_MODE_FPR20 + || desc[idx].mode == KEYDB_SEARCH_MODE_FPR32 || desc[idx].mode == KEYDB_SEARCH_MODE_FPR16) { - n = 1+2+2*20; + n = 1+2+2*32; if (idx && linelen + n > MAX_KS_GET_LINELEN) break; /* Declare end of this chunk. */ linelen += n; @@ -1635,10 +1677,12 @@ keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, { strcpy (pattern[npat], "0x"); bin2hex (desc[idx].u.fpr, + desc[idx].mode == KEYDB_SEARCH_MODE_FPR32? 32 : desc[idx].mode == KEYDB_SEARCH_MODE_FPR20? 20 : 16, pattern[npat]+2); npat++; - if (desc[idx].mode == KEYDB_SEARCH_MODE_FPR20) + if (desc[idx].mode == KEYDB_SEARCH_MODE_FPR20 + || desc[idx].mode == KEYDB_SEARCH_MODE_FPR32) npat_fpr++; } } @@ -1717,7 +1761,7 @@ keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, } } - /* Remember now many of search items were considered. Note that + /* Remember how many of the search items were considered. Note that this is different from NPAT. */ *r_ndesc_used = idx; diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c index 817253590..0bcd4a323 100644 --- a/kbx/keybox-blob.c +++ b/kbx/keybox-blob.c @@ -62,7 +62,8 @@ 2 = OpenPGP 3 = X509 - byte Version number of this blob type - 1 = The only defined value + 1 = Blob with 20 byte fingerprints + 2 = Blob with 32 byte fingerprints and no keyids. - u16 Blob flags bit 0 = contains secret key material (not used) bit 1 = ephemeral blob (e.g. used while querying external resources) @@ -70,19 +71,36 @@ certificate - u32 The length of the keyblock or certificate - u16 [NKEYS] Number of keys (at least 1!) [X509: always 1] - - u16 Size of the key information structure (at least 28). + - u16 Size of the key information structure (at least 28 or 56). - NKEYS times: + Version 1 blob: - b20 The fingerprint of the key. Fingerprints are always 20 bytes, MD5 left padded with zeroes. - u32 Offset to the n-th key's keyID (a keyID is always 8 byte) or 0 if not known which is the case only for X.509. + Note that this separate keyid is not anymore used by + gnupg since the support for v3 keys has been removed. + We create this field anyway for backward compatibility with + old EOL-ed versions. Eventually we will completely move + to the version 2 blob format. - u16 Key flags bit 0 = qualified signature (not yet implemented} - u16 RFU - bN Optional filler up to the specified length of this structure. + Version 2 blob: + - b32 The fingerprint of the key. This fingerprint is + either 20 or 32 bytes. A 20 byte fingerprint is + right filled with zeroes. + - u16 Key flags + bit 0 = qualified signature (not yet implemented} + bit 7 = 32 byte fingerprint in use. + - u16 RFU + - b20 keygrip + - bN Optional filler up to the specified length of this + structure. - u16 Size of the serial number (may be zero) - - bN The serial number. N as giiven above. + - bN The serial number. N as given above. - u16 Number of user IDs - u16 [NUIDS] Size of user ID information structure - NUIDS times: @@ -172,15 +190,12 @@ struct membuf { }; -/* #if MAX_FINGERPRINT_LEN < 20 */ -/* #error fingerprints are 20 bytes */ -/* #endif */ - struct keyboxblob_key { - char fpr[20]; + char fpr[32]; u32 off_kid; ulong off_kid_addr; u16 flags; + u16 fprlen; /* Either 20 or 32 */ }; struct keyboxblob_uid { u32 off; @@ -380,10 +395,9 @@ pgp_create_key_part_single (KEYBOXBLOB blob, int n, int off; fprlen = kinfo->fprlen; - if (fprlen > 20) - fprlen = 20; memcpy (blob->keys[n].fpr, kinfo->fpr, fprlen); - if (fprlen != 20) /* v3 fpr - shift right and fill with zeroes. */ + blob->keys[n].fprlen = fprlen; + if (fprlen < 20) /* v3 fpr - shift right and fill with zeroes. */ { memmove (blob->keys[n].fpr + 20 - fprlen, blob->keys[n].fpr, fprlen); memset (blob->keys[n].fpr, 0, 20 - fprlen); @@ -533,30 +547,51 @@ release_kid_list (struct keyid_list *kl) } - +/* Create a new blob header. If WANT_FPR32 is set a version 2 blob is + * created. */ static int -create_blob_header (KEYBOXBLOB blob, int blobtype, int as_ephemeral) +create_blob_header (KEYBOXBLOB blob, int blobtype, int as_ephemeral, + int want_fpr32) { struct membuf *a = blob->buf; int i; put32 ( a, 0 ); /* blob length, needs fixup */ put8 ( a, blobtype); - put8 ( a, 1 ); /* blob type version */ + put8 ( a, want_fpr32? 2:1 ); /* blob type version */ put16 ( a, as_ephemeral? 2:0 ); /* blob flags */ put32 ( a, 0 ); /* offset to the raw data, needs fixup */ put32 ( a, 0 ); /* length of the raw data, needs fixup */ put16 ( a, blob->nkeys ); - put16 ( a, 20 + 4 + 2 + 2 ); /* size of key info */ + if (want_fpr32) + put16 ( a, 32 + 2 + 2 + 20); /* size of key info */ + else + put16 ( a, 20 + 4 + 2 + 2 ); /* size of key info */ for ( i=0; i < blob->nkeys; i++ ) { - put_membuf (a, blob->keys[i].fpr, 20); - blob->keys[i].off_kid_addr = a->len; - put32 ( a, 0 ); /* offset to keyid, fixed up later */ - put16 ( a, blob->keys[i].flags ); - put16 ( a, 0 ); /* reserved */ + if (want_fpr32) + { + put_membuf (a, blob->keys[i].fpr, blob->keys[i].fprlen); + blob->keys[i].off_kid_addr = a->len; + if (blob->keys[i].fprlen == 32) + put16 ( a, (blob->keys[i].flags | 0x80)); + else + put16 ( a, blob->keys[i].flags); + put16 ( a, 0 ); /* reserved */ + /* FIXME: Put the real grip here instead of the filler. */ + put_membuf (a, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20); + } + else + { + log_assert (blob->keys[i].fprlen <= 20); + put_membuf (a, blob->keys[i].fpr, 20); + blob->keys[i].off_kid_addr = a->len; + put32 ( a, 0 ); /* offset to keyid, fixed up later */ + put16 ( a, blob->keys[i].flags ); + put16 ( a, 0 ); /* reserved */ + } } put16 (a, blob->seriallen); /*fixme: check that it fits into 16 bits*/ @@ -593,11 +628,14 @@ create_blob_header (KEYBOXBLOB blob, int blobtype, int as_ephemeral) /* space where we write keyIDs and other stuff so that the pointers can actually point to somewhere */ - if (blobtype == KEYBOX_BLOBTYPE_PGP) + if (blobtype == KEYBOX_BLOBTYPE_PGP && !want_fpr32) { - /* We need to store the keyids for all pgp v3 keys because those key - IDs are not part of the fingerprint. While we are doing that, we - fixup all the keyID offsets */ + /* For version 1 blobs, we need to store the keyids for all v3 + * keys because those key IDs are not part of the fingerprint. + * While we are doing that, we fixup all the keyID offsets. For + * version 2 blobs (which can't carry v3 keys) we compute the + * keyids in the fly because they are just stripped down + * fingerprints. */ for (i=0; i < blob->nkeys; i++ ) { if (blob->keys[i].off_kid) @@ -711,9 +749,27 @@ _keybox_create_openpgp_blob (KEYBOXBLOB *r_blob, { gpg_error_t err; KEYBOXBLOB blob; + int need_fpr32 = 0; *r_blob = NULL; + + /* Check whether we need a blob with 32 bit fingerprints. We could + * use this always but for backward compatiblity we do this only for + * v5 keys. */ + if (info->primary.version == 5) + need_fpr32 = 1; + else + { + struct _keybox_openpgp_key_info *kinfo; + for (kinfo = &info->subkeys; kinfo; kinfo = kinfo->next) + if (kinfo->version == 5) + { + need_fpr32 = 1; + break; + } + } + blob = xtrycalloc (1, sizeof *blob); if (!blob) return gpg_error_from_syserror (); @@ -756,7 +812,8 @@ _keybox_create_openpgp_blob (KEYBOXBLOB *r_blob, init_membuf (&blob->bufbuf, 1024); blob->buf = &blob->bufbuf; - err = create_blob_header (blob, KEYBOX_BLOBTYPE_PGP, as_ephemeral); + err = create_blob_header (blob, KEYBOX_BLOBTYPE_PGP, + as_ephemeral, need_fpr32); if (err) goto leave; err = pgp_create_blob_keyblock (blob, image, imagelen); @@ -943,7 +1000,7 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, ksba_cert_t cert, init_membuf (&blob->bufbuf, 1024); blob->buf = &blob->bufbuf; /* write out what we already have */ - rc = create_blob_header (blob, KEYBOX_BLOBTYPE_X509, as_ephemeral); + rc = create_blob_header (blob, KEYBOX_BLOBTYPE_X509, as_ephemeral, 0); if (rc) goto leave; rc = x509_create_blob_cert (blob, cert); diff --git a/kbx/keybox-defs.h b/kbx/keybox-defs.h index d2b79baf2..354d5fd11 100644 --- a/kbx/keybox-defs.h +++ b/kbx/keybox-defs.h @@ -99,10 +99,11 @@ struct _keybox_openpgp_key_info { struct _keybox_openpgp_key_info *next; int algo; + int version; unsigned char grip[20]; unsigned char keyid[8]; - int fprlen; /* Either 16 or 20 */ - unsigned char fpr[20]; + int fprlen; /* Either 16, 20 or 32 */ + unsigned char fpr[32]; }; struct _keybox_openpgp_uid_info diff --git a/kbx/keybox-dump.c b/kbx/keybox-dump.c index aa1d93be7..48c3f63c5 100644 --- a/kbx/keybox-dump.c +++ b/kbx/keybox-dump.c @@ -170,6 +170,7 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp) ulong nserial; ulong unhashed; const byte *p; + int is_fpr32; /* blob ersion 2 */ buffer = _keybox_get_blob_image (blob, &length); @@ -207,7 +208,9 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp) fprintf (fp, "[can't dump this blob type]\n"); return 0; } + /* Here we have either BLOGTYPE_X509 or BLOBTYPE_OPENPGP */ fprintf (fp, "Version: %d\n", buffer[5]); + is_fpr32 = buffer[5] == 2; if (length < 40) { @@ -267,15 +270,24 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp) ulong kidoff, kflags; fprintf (fp, "Key-Fpr[%lu]: ", n ); - for (i=0; i < 20; i++ ) - fprintf (fp, "%02X", p[i]); - kidoff = get32 (p + 20); - fprintf (fp, "\nKey-Kid-Off[%lu]: %lu\n", n, kidoff ); - fprintf (fp, "Key-Kid[%lu]: ", n ); - /* fixme: check bounds */ - for (i=0; i < 8; i++ ) - fprintf (fp, "%02X", buffer[kidoff+i] ); - kflags = get16 (p + 24 ); + if (is_fpr32) + { + kflags = get16 (p + 32 ); + for (i=0; i < ((kflags & 0x80)?32:20); i++ ) + fprintf (fp, "%02X", p[i]); + } + else + { + for (i=0; i < 20; i++ ) + fprintf (fp, "%02X", p[i]); + kidoff = get32 (p + 20); + fprintf (fp, "\nKey-Kid-Off[%lu]: %lu\n", n, kidoff ); + fprintf (fp, "Key-Kid[%lu]: ", n ); + /* fixme: check bounds */ + for (i=0; i < 8; i++ ) + fprintf (fp, "%02X", buffer[kidoff+i] ); + kflags = get16 (p + 24 ); + } fprintf( fp, "\nKey-Flags[%lu]: %04lX\n", n, kflags); } diff --git a/kbx/keybox-openpgp.c b/kbx/keybox-openpgp.c index 6d6ed77dc..7a35475ca 100644 --- a/kbx/keybox-openpgp.c +++ b/kbx/keybox-openpgp.c @@ -265,14 +265,17 @@ parse_key (const unsigned char *data, size_t datalen, unsigned char hashbuffer[768]; gcry_md_hd_t md; int is_ecc = 0; + int is_v5; + /* unsigned int pkbytes; for v5: # of octets of the public key params. */ struct keyparm_s keyparm[OPENPGP_MAX_NPKEY]; unsigned char *helpmpibuf[OPENPGP_MAX_NPKEY] = { NULL }; if (datalen < 5) return gpg_error (GPG_ERR_INV_PACKET); version = *data++; datalen--; - if (version < 2 || version > 4 ) + if (version < 2 || version > 5 ) return gpg_error (GPG_ERR_INV_PACKET); /* Invalid version. */ + is_v5 = version == 5; /*timestamp = ((data[0]<<24)|(data[1]<<16)|(data[2]<<8)|(data[3]));*/ data +=4; datalen -=4; @@ -288,6 +291,15 @@ parse_key (const unsigned char *data, size_t datalen, return gpg_error (GPG_ERR_INV_PACKET); algorithm = *data++; datalen--; + if (is_v5) + { + if (datalen < 4) + return gpg_error (GPG_ERR_INV_PACKET); + /* pkbytes = buf32_to_uint (data); */ + data += 4; + datalen -= 4; + } + switch (algorithm) { case PUBKEY_ALGO_RSA: @@ -315,6 +327,7 @@ parse_key (const unsigned char *data, size_t datalen, return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM); } + ki->version = version; ki->algo = algorithm; for (i=0; i < npkey; i++ ) @@ -411,29 +424,63 @@ parse_key (const unsigned char *data, size_t datalen, have a scatter-gather enabled hash function. What we do here is to use a static buffer if this one is large enough and only use the regular hash functions if this buffer is not - large enough. */ - if ( 3 + n < sizeof hashbuffer ) + large enough. + FIXME: Factor this out to a shared fingerprint function. + */ + if (version == 5) { - hashbuffer[0] = 0x99; /* CTB */ - hashbuffer[1] = (n >> 8); /* 2 byte length header. */ - hashbuffer[2] = n; - memcpy (hashbuffer + 3, data_start, n); - gcry_md_hash_buffer (GCRY_MD_SHA1, ki->fpr, hashbuffer, 3 + n); + if ( 5 + n < sizeof hashbuffer ) + { + hashbuffer[0] = 0x9a; /* CTB */ + hashbuffer[1] = (n >> 24);/* 4 byte length header. */ + hashbuffer[2] = (n >> 16); + hashbuffer[3] = (n >> 8); + hashbuffer[4] = (n ); + memcpy (hashbuffer + 5, data_start, n); + gcry_md_hash_buffer (GCRY_MD_SHA256, ki->fpr, hashbuffer, 5 + n); + } + else + { + err = gcry_md_open (&md, GCRY_MD_SHA256, 0); + if (err) + return err; /* Oops */ + gcry_md_putc (md, 0x9a ); /* CTB */ + gcry_md_putc (md, (n >> 24)); /* 4 byte length header. */ + gcry_md_putc (md, (n >> 16)); + gcry_md_putc (md, (n >> 8)); + gcry_md_putc (md, (n )); + gcry_md_write (md, data_start, n); + memcpy (ki->fpr, gcry_md_read (md, 0), 32); + gcry_md_close (md); + } + ki->fprlen = 32; + memcpy (ki->keyid, ki->fpr, 8); } else { - err = gcry_md_open (&md, GCRY_MD_SHA1, 0); - if (err) - return err; /* Oops */ - gcry_md_putc (md, 0x99 ); /* CTB */ - gcry_md_putc (md, (n >> 8) ); /* 2 byte length header. */ - gcry_md_putc (md, n ); - gcry_md_write (md, data_start, n); - memcpy (ki->fpr, gcry_md_read (md, 0), 20); - gcry_md_close (md); + if ( 3 + n < sizeof hashbuffer ) + { + hashbuffer[0] = 0x99; /* CTB */ + hashbuffer[1] = (n >> 8); /* 2 byte length header. */ + hashbuffer[2] = (n ); + memcpy (hashbuffer + 3, data_start, n); + gcry_md_hash_buffer (GCRY_MD_SHA1, ki->fpr, hashbuffer, 3 + n); + } + else + { + err = gcry_md_open (&md, GCRY_MD_SHA1, 0); + if (err) + return err; /* Oops */ + gcry_md_putc (md, 0x99 ); /* CTB */ + gcry_md_putc (md, (n >> 8)); /* 2 byte length header. */ + gcry_md_putc (md, (n )); + gcry_md_write (md, data_start, n); + memcpy (ki->fpr, gcry_md_read (md, 0), 20); + gcry_md_close (md); + } + ki->fprlen = 20; + memcpy (ki->keyid, ki->fpr+12, 8); } - ki->fprlen = 20; - memcpy (ki->keyid, ki->fpr+12, 8); } leave: diff --git a/kbx/keybox-search-desc.h b/kbx/keybox-search-desc.h index c75bfa4c7..cde1cf56f 100644 --- a/kbx/keybox-search-desc.h +++ b/kbx/keybox-search-desc.h @@ -38,7 +38,8 @@ typedef enum { KEYDB_SEARCH_MODE_LONG_KID, KEYDB_SEARCH_MODE_FPR16, KEYDB_SEARCH_MODE_FPR20, - KEYDB_SEARCH_MODE_FPR, + KEYDB_SEARCH_MODE_FPR32, + KEYDB_SEARCH_MODE_FPR, /* (Length of fpr in .fprlen) */ KEYDB_SEARCH_MODE_ISSUER, KEYDB_SEARCH_MODE_ISSUER_SN, KEYDB_SEARCH_MODE_SN, @@ -49,7 +50,7 @@ typedef enum { } KeydbSearchMode; -/* Forwward declaration. See g10/packet.h. */ +/* Forward declaration. See g10/packet.h. */ struct gpg_pkt_user_id_s; typedef struct gpg_pkt_user_id_s *gpg_pkt_user_id_t; @@ -73,6 +74,7 @@ struct keydb_search_desc u32 kid[2]; /* Note that this is in native endianness. */ unsigned char grip[20]; } 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 946ef52ad..db98648f4 100644 --- a/kbx/keybox-search.c +++ b/kbx/keybox-search.c @@ -66,18 +66,31 @@ blob_get_first_keyid (KEYBOXBLOB blob, u32 *kid) { const unsigned char *buffer; size_t length, nkeys, keyinfolen; + int fpr32; buffer = _keybox_get_blob_image (blob, &length); if (length < 48) return 0; /* blob too short */ + fpr32 = buffer[5] == 2; + if (fpr32 && length < 56) + return 0; /* blob to short */ nkeys = get16 (buffer + 16); keyinfolen = get16 (buffer + 18); - if (!nkeys || keyinfolen < 28) + if (!nkeys || keyinfolen < (fpr32?56:28)) return 0; /* invalid blob */ - kid[0] = get32 (buffer + 32); - kid[1] = get32 (buffer + 36); + if (fpr32 && (get16 (buffer + 20 + 32) & 0x80)) + { + /* 32 byte fingerprint. */ + kid[0] = get32 (buffer + 20); + kid[1] = get32 (buffer + 20 + 4); + } + else /* 20 byte fingerprint. */ + { + kid[0] = get32 (buffer + 20 + 12); + kid[1] = get32 (buffer + 20 + 16); + } return 1; } @@ -229,22 +242,23 @@ blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen) For X.509 this is always 1, for OpenPGP this is 1 for the primary key and 2 and more for the subkeys. */ static int -blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr) +blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr, unsigned int fprlen) { const unsigned char *buffer; size_t length; size_t pos, off; size_t nkeys, keyinfolen; - int idx; + int idx, fpr32, storedfprlen; 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 (keyinfolen < 28) + if (keyinfolen < (fpr32?56:28)) return 0; /* invalid blob */ pos = 20; if (pos + (uint64_t)keyinfolen*nkeys > (uint64_t)length) @@ -253,12 +267,19 @@ blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr) for (idx=0; idx < nkeys; idx++) { off = pos + idx*keyinfolen; - if (!memcmp (buffer + off, fpr, 20)) + if (fpr32) + storedfprlen = (get16 (buffer + off + 32) & 0x80)? 32:20; + else + storedfprlen = 20; + if (storedfprlen == fprlen + && !memcmp (buffer + off, fpr, storedfprlen)) return idx+1; /* found */ } return 0; /* not found */ } + +/* Helper for has_short_kid and has_long_kid. */ static int blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr, int fproff, int fprlen) @@ -267,25 +288,33 @@ blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr, size_t length; size_t pos, off; size_t nkeys, keyinfolen; - int idx; + int idx, fpr32, storedfprlen; 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 (keyinfolen < 28) + if (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 (fpr32) + fproff = 0; /* keyid are the high-order bits. */ for (idx=0; idx < nkeys; idx++) { off = pos + idx*keyinfolen; - if (!memcmp (buffer + off + fproff, fpr, fprlen)) + if (fpr32) + storedfprlen = (get16 (buffer + off + 32) & 0x80)? 32:20; + else + storedfprlen = 20; + if (storedfprlen == fproff + fprlen + && !memcmp (buffer + off + fproff, fpr, fprlen)) return idx+1; /* found */ } return 0; /* not found */ @@ -650,9 +679,9 @@ has_long_kid (KEYBOXBLOB blob, u32 mkid, u32 lkid) } static inline int -has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr) +has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr, unsigned int fprlen) { - return blob_cmp_fpr (blob, fpr); + return blob_cmp_fpr (blob, fpr, fprlen); } static inline int @@ -1047,12 +1076,25 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc, if (pk_no) goto found; break; + case KEYDB_SEARCH_MODE_FPR: - case KEYDB_SEARCH_MODE_FPR20: - pk_no = has_fingerprint (blob, desc[n].u.fpr); + pk_no = has_fingerprint (blob, desc[n].u.fpr, desc[n].fprlen); if (pk_no) goto found; break; + + case KEYDB_SEARCH_MODE_FPR20: + pk_no = has_fingerprint (blob, desc[n].u.fpr, 20); + if (pk_no) + goto found; + break; + + case KEYDB_SEARCH_MODE_FPR32: + pk_no = has_fingerprint (blob, desc[n].u.fpr, 32); + if (pk_no) + goto found; + break; + case KEYDB_SEARCH_MODE_KEYGRIP: if (has_keygrip (blob, desc[n].u.grip)) goto found; diff --git a/sm/keydb.c b/sm/keydb.c index a6ea9f77f..f66a5766d 100644 --- a/sm/keydb.c +++ b/sm/keydb.c @@ -1052,6 +1052,7 @@ keydb_search_fpr (ctrl_t ctrl, KEYDB_HANDLE hd, const byte *fpr) memset (&desc, 0, sizeof desc); desc.mode = KEYDB_SEARCH_MODE_FPR; memcpy (desc.u.fpr, fpr, 20); + desc.fprlen = 20; return keydb_search (ctrl, hd, &desc, 1); }