summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/userids.c45
-rw-r--r--g10/delkey.c3
-rw-r--r--g10/export.c16
-rw-r--r--g10/getkey.c11
-rw-r--r--g10/gpg.c1
-rw-r--r--g10/import.c4
-rw-r--r--g10/keydb.c46
-rw-r--r--g10/keydb.h6
-rw-r--r--g10/keyedit.c16
-rw-r--r--g10/keyid.c26
-rw-r--r--g10/keyring.c22
-rw-r--r--g10/keyserver.c68
-rw-r--r--kbx/keybox-blob.c109
-rw-r--r--kbx/keybox-defs.h5
-rw-r--r--kbx/keybox-dump.c30
-rw-r--r--kbx/keybox-openpgp.c85
-rw-r--r--kbx/keybox-search-desc.h6
-rw-r--r--kbx/keybox-search.c68
-rw-r--r--sm/keydb.c1
19 files changed, 439 insertions, 129 deletions
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:
+ 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);
+ 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);
}