From a2979c20e1ab2d52e3a961ac7dad45fee9d6345a Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Fri, 17 Jan 2020 19:48:10 +0000 Subject: [PATCH] Provide key_fetch routine that will not search subkey fingerprints We have *_key_fetch_fp to search for keys by fingerprint, but that includes subkeys. While unlikely a subkey could be bound to multiple certification primary keys, resulting in multiple keys being returned for a fingerprint query. Provide a plain *_fetch_key that only searches primary keys and is thus guaranteed to return at most one key. --- keydb.h | 71 ++++++++++++++++++------------ keydb/keyd.c | 36 ++++++++++++++- keydb/keyd.h | 1 + keydb/keydb.c | 44 ++++++++++++++++++ keydb/keydb_db4.c | 26 +++++++++-- keydb/keydb_dynamic.c | 26 ++++++++--- keydb/keydb_file.c | 4 +- keydb/keydb_fs.c | 4 +- keydb/keydb_hkp.c | 40 +++++++++-------- keydb/keydb_keyd.c | 62 +++++++++++++++++++++++--- keydb/keydb_keyring.c | 21 ++++++--- keydb/keydb_pg.c | 4 +- keydb/keydb_stacked.c | 31 +++++++++++-- onak.c | 15 +++++-- t/all-095-get-subkey-fingerprint.t | 25 +++++++++++ 15 files changed, 330 insertions(+), 80 deletions(-) create mode 100755 t/all-095-get-subkey-fingerprint.t diff --git a/keydb.h b/keydb.h index 7297a76..9a9371b 100644 --- a/keydb.h +++ b/keydb.h @@ -55,6 +55,22 @@ struct onak_dbctx { */ void (*endtrans)(struct onak_dbctx *); +/** + * @brief Given a fingerprint fetch the key from storage. + * @param fp The fingerprint to fetch. + * @param fpsize Number of bytes in the fingerprint (16 for v3, 20 for v4) + * @param publickey A pointer to a structure to return the key in. + * @param intrans If we're already in a transaction. + * + * This function returns a public key from whatever storage mechanism we + * are using. This only searches for the fingerprint of the primary key + * and will thus only ever return at most a single key. + */ + int (*fetch_key)(struct onak_dbctx *, + struct openpgp_fingerprint *fingerprint, + struct openpgp_publickey **publickey, + bool intrans); + /** * @brief Given a keyid fetch the key from storage. * @param keyid The keyid to fetch. @@ -62,9 +78,8 @@ struct onak_dbctx { * @param intrans If we're already in a transaction. * * This function returns a public key from whatever storage mechanism we - * are using. - * - * TODO: What about keyid collisions? Should we use fingerprint instead? + * are using. It may return multiple keys in the case where there are + * colliding keyids. */ int (*fetch_key_id)(struct onak_dbctx *, uint64_t keyid, @@ -79,13 +94,38 @@ struct onak_dbctx { * @param intrans If we're already in a transaction. * * This function returns a public key from whatever storage mechanism we - * are using. + * are using. Although the fingerprint should be unique this function may + * also search subkeys, which could be bound to multiple primary keys. As + * a result multiple keys may be returned. */ int (*fetch_key_fp)(struct onak_dbctx *, struct openpgp_fingerprint *fingerprint, struct openpgp_publickey **publickey, bool intrans); +/** + * @brief Tries to find the keys that contain the supplied text. + * @param search The text to search for. + * @param publickey A pointer to a structure to return the key in. + * + * This function searches for the supplied text and returns the keys that + * contain it. It is likely it will return multiple keys. + */ + int (*fetch_key_text)(struct onak_dbctx *, const char *search, + struct openpgp_publickey **publickey); + +/** + * @brief Tries to find the keys from an SKS hash + * @param hash The hash to search for. + * @param publickey A pointer to a structure to return the key in. + * + * This function looks for the key that is referenced by the supplied + * SKS hash and returns it. + */ + int (*fetch_key_skshash)(struct onak_dbctx *, + const struct skshash *hash, + struct openpgp_publickey **publickey); + /** * @brief Takes a key and stores it. * @param publickey A pointer to the public key to store. @@ -114,29 +154,6 @@ struct onak_dbctx { int (*delete_key)(struct onak_dbctx *, struct openpgp_fingerprint *fp, bool intrans); -/** - * @brief Trys to find the keys that contain the supplied text. - * @param search The text to search for. - * @param publickey A pointer to a structure to return the key in. - * - * This function searches for the supplied text and returns the keys that - * contain it. - */ - int (*fetch_key_text)(struct onak_dbctx *, const char *search, - struct openpgp_publickey **publickey); - -/** - * @brief Tries to find the keys from an SKS hash - * @param hash The hash to search for. - * @param publickey A pointer to a structure to return the key in. - * - * This function looks for the key that is referenced by the supplied - * SKS hash and returns it. - */ - int (*fetch_key_skshash)(struct onak_dbctx *, - const struct skshash *hash, - struct openpgp_publickey **publickey); - /** * @brief Takes a list of public keys and updates them in the DB. * @param keys The keys to update in the DB. diff --git a/keydb/keyd.c b/keydb/keyd.c index 0df7192..ff02116 100644 --- a/keydb/keyd.c +++ b/keydb/keyd.c @@ -300,6 +300,41 @@ static int sock_do(struct onak_dbctx *dbctx, int fd) } } break; + case KEYD_CMD_GET: + if (!keyd_write_reply(fd, KEYD_REPLY_OK)) { + ret = 1; + } + if (ret == 0) { + if ((read(fd, &bytes, 1) != 1) || + (bytes > MAX_FINGERPRINT_LEN)) { + ret = 1; + } else { + fingerprint.length = bytes; + bytes = read(fd, fingerprint.fp, + fingerprint.length); + if (bytes != fingerprint.length) { + ret = 1; + } + } + } + if (ret == 0) { + logthing(LOGTHING_INFO, + "Fetching by fingerprint" + ", result: %d", + dbctx->fetch_key(dbctx, + &fingerprint, + &key, false)); + if (key != NULL) { + keyd_write_key(fd, key); + free_publickey(key); + key = NULL; + } else { + if (!keyd_write_size(fd, 0)) { + ret = 1; + } + } + } + break; case KEYD_CMD_GET_ID: if (!keyd_write_reply(fd, KEYD_REPLY_OK)) { ret = 1; @@ -364,7 +399,6 @@ static int sock_do(struct onak_dbctx *dbctx, int fd) } } break; - case KEYD_CMD_GET_TEXT: if (!keyd_write_reply(fd, KEYD_REPLY_OK)) { ret = 1; diff --git a/keydb/keyd.h b/keydb/keyd.h index 1ea601c..f92e7c6 100644 --- a/keydb/keyd.h +++ b/keydb/keyd.h @@ -45,6 +45,7 @@ enum keyd_ops { KEYD_CMD_GET_SKSHASH, KEYD_CMD_GET_FP, KEYD_CMD_UPDATE, + KEYD_CMD_GET, KEYD_CMD_LAST /* Placeholder */ }; diff --git a/keydb/keydb.c b/keydb/keydb.c index f6b9682..692a7b7 100644 --- a/keydb/keydb.c +++ b/keydb/keydb.c @@ -265,6 +265,9 @@ static int generic_fetch_key_fp(struct onak_dbctx *dbctx, * keys need the top 64 bits. This doesn't work for v3 keys, * but there's no way to map from v3 fingerprint to v3 key ID so * if the backend can't do it we're going to fail anyway. + * + * We are also assuming they store a single key based on the ID, so + * we are implementing fetch_key rather than fetch_key_fp */ keyid = 0; if (fingerprint->length == 20) { @@ -283,3 +286,44 @@ static int generic_fetch_key_fp(struct onak_dbctx *dbctx, return dbctx->fetch_key_id(dbctx, keyid, publickey, intrans); } #endif + +#ifdef NEED_GET +/* + * This fetches a key by fingerprint from the back end, then filters + * out what we got back to ensure it's the primary key that matches the + * fingerprint, and that only one is returned. + */ +static int generic_fetch_key(struct onak_dbctx *dbctx, + struct openpgp_fingerprint *fingerprint, + struct openpgp_publickey **publickey, + bool intrans) +{ + struct openpgp_publickey *curkey, **newkey; + struct openpgp_publickey *keys; + struct openpgp_fingerprint fp; + int count; + + /* Find the last key in the provided set of keys */ + for (newkey = publickey; *newkey != NULL; newkey = &(*newkey)->next) + ; + + keys = NULL; + dbctx->fetch_key_fp(dbctx, fingerprint, &keys, intrans); + + count = 0; + for (curkey = keys; curkey != NULL; curkey = curkey->next) { + if (get_fingerprint(curkey->publickey, &fp) == ONAK_E_OK) { + if (fingerprint_cmp(fingerprint, &fp) == 0) { + *newkey = curkey; + curkey = curkey->next; + (*newkey)->next = NULL; + count = 1; + break; + } + } + } + free_publickey(keys); + + return count; +} +#endif diff --git a/keydb/keydb_db4.c b/keydb/keydb_db4.c index 1f306e2..d9c45a9 100644 --- a/keydb/keydb_db4.c +++ b/keydb/keydb_db4.c @@ -295,10 +295,11 @@ static int db4_upgradedb(struct onak_dbctx *dbctx) /** * fetch_key_fp - Given a fingerprint fetch the key from storage. */ -static int db4_fetch_key_fp(struct onak_dbctx *dbctx, +static int db4_fetch_key_int(struct onak_dbctx *dbctx, struct openpgp_fingerprint *fingerprint, struct openpgp_publickey **publickey, - bool intrans) + bool intrans, + bool dosubkey) { struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; struct openpgp_packet_list *packets = NULL; @@ -328,7 +329,7 @@ static int db4_fetch_key_fp(struct onak_dbctx *dbctx, &data, 0); /* flags*/ - if (ret == DB_NOTFOUND) { + if (ret == DB_NOTFOUND && dosubkey) { /* If we didn't find the key ID see if it's a subkey ID */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); @@ -386,6 +387,22 @@ static int db4_fetch_key_fp(struct onak_dbctx *dbctx, return (numkeys); } +static int db4_fetch_key(struct onak_dbctx *dbctx, + struct openpgp_fingerprint *fingerprint, + struct openpgp_publickey **publickey, + bool intrans) +{ + return db4_fetch_key_int(dbctx, fingerprint, publickey, intrans, false); +} + +static int db4_fetch_key_fp(struct onak_dbctx *dbctx, + struct openpgp_fingerprint *fingerprint, + struct openpgp_publickey **publickey, + bool intrans) +{ + return db4_fetch_key_int(dbctx, fingerprint, publickey, intrans, true); +} + /** * fetch_key_id - Given a keyid fetch the key from storage. * @keyid: The keyid to fetch. @@ -1744,8 +1761,9 @@ struct onak_dbctx *keydb_db4_init(struct onak_db_config *dbcfg, bool readonly) dbctx->cleanupdb = db4_cleanupdb; dbctx->starttrans = db4_starttrans; dbctx->endtrans = db4_endtrans; - dbctx->fetch_key_id = db4_fetch_key_id; + dbctx->fetch_key = db4_fetch_key; dbctx->fetch_key_fp = db4_fetch_key_fp; + dbctx->fetch_key_id = db4_fetch_key_id; dbctx->fetch_key_text = db4_fetch_key_text; dbctx->fetch_key_skshash = db4_fetch_key_skshash; dbctx->store_key = db4_store_key; diff --git a/keydb/keydb_dynamic.c b/keydb/keydb_dynamic.c index 385c09c..459779f 100644 --- a/keydb/keydb_dynamic.c +++ b/keydb/keydb_dynamic.c @@ -54,14 +54,15 @@ static void dynamic_endtrans(struct onak_dbctx *dbctx) privctx->loadeddbctx->endtrans(privctx->loadeddbctx); } -static int dynamic_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, +static int dynamic_fetch_key(struct onak_dbctx *dbctx, + struct openpgp_fingerprint *fingerprint, struct openpgp_publickey **publickey, bool intrans) { struct onak_dynamic_dbctx *privctx = (struct onak_dynamic_dbctx *) dbctx->priv; - return privctx->loadeddbctx->fetch_key_id(privctx->loadeddbctx, keyid, - publickey, intrans); + return privctx->loadeddbctx->fetch_key(privctx->loadeddbctx, + fingerprint, publickey, intrans); } static int dynamic_fetch_key_fp(struct onak_dbctx *dbctx, @@ -71,8 +72,22 @@ static int dynamic_fetch_key_fp(struct onak_dbctx *dbctx, struct onak_dynamic_dbctx *privctx = (struct onak_dynamic_dbctx *) dbctx->priv; - return privctx->loadeddbctx->fetch_key_fp(privctx->loadeddbctx, + if (privctx->loadeddbctx->fetch_key_fp) + return privctx->loadeddbctx->fetch_key_fp(privctx->loadeddbctx, fingerprint, publickey, intrans); + else + return privctx->loadeddbctx->fetch_key(privctx->loadeddbctx, + fingerprint, publickey, intrans); +} + +static int dynamic_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, + struct openpgp_publickey **publickey, bool intrans) +{ + struct onak_dynamic_dbctx *privctx = + (struct onak_dynamic_dbctx *) dbctx->priv; + + return privctx->loadeddbctx->fetch_key_id(privctx->loadeddbctx, keyid, + publickey, intrans); } static int dynamic_fetch_key_text(struct onak_dbctx *dbctx, @@ -304,8 +319,9 @@ struct onak_dbctx *keydb_dynamic_init(struct onak_db_config *dbcfg, dbctx->cleanupdb = dynamic_cleanupdb; dbctx->starttrans = dynamic_starttrans; dbctx->endtrans = dynamic_endtrans; - dbctx->fetch_key_id = dynamic_fetch_key_id; + dbctx->fetch_key = dynamic_fetch_key; dbctx->fetch_key_fp = dynamic_fetch_key_fp; + dbctx->fetch_key_id = dynamic_fetch_key_id; dbctx->fetch_key_text = dynamic_fetch_key_text; dbctx->fetch_key_skshash = dynamic_fetch_key_skshash; dbctx->store_key = dynamic_store_key; diff --git a/keydb/keydb_file.c b/keydb/keydb_file.c index ded6a9e..d396364 100644 --- a/keydb/keydb_file.c +++ b/keydb/keydb_file.c @@ -285,8 +285,10 @@ struct onak_dbctx *keydb_file_init(struct onak_db_config *dbcfg, bool readonly) dbctx->cleanupdb = file_cleanupdb; dbctx->starttrans = file_starttrans; dbctx->endtrans = file_endtrans; - dbctx->fetch_key_id = file_fetch_key_id; + /* Our fetch fp doesn't look at subkeys */ + dbctx->fetch_key = generic_fetch_key_fp; dbctx->fetch_key_fp = generic_fetch_key_fp; + dbctx->fetch_key_id = file_fetch_key_id; dbctx->fetch_key_text = file_fetch_key_text; dbctx->store_key = file_store_key; dbctx->update_keys = generic_update_keys; diff --git a/keydb/keydb_fs.c b/keydb/keydb_fs.c index f8d55dc..f7c865e 100644 --- a/keydb/keydb_fs.c +++ b/keydb/keydb_fs.c @@ -633,6 +633,7 @@ static int fs_iterate_keys(struct onak_dbctx *dbctx, #define NEED_KEYID2UID 1 #define NEED_GETKEYSIGS 1 #define NEED_UPDATEKEYS 1 +#define NEED_GET 1 #define NEED_GET_FP 1 #include "keydb.c" @@ -709,8 +710,9 @@ struct onak_dbctx *keydb_fs_init(struct onak_db_config *dbcfg, bool readonly) dbctx->cleanupdb = fs_cleanupdb; dbctx->starttrans = fs_starttrans; dbctx->endtrans = fs_endtrans; - dbctx->fetch_key_id = fs_fetch_key_id; + dbctx->fetch_key = generic_fetch_key; dbctx->fetch_key_fp = generic_fetch_key_fp; + dbctx->fetch_key_id = fs_fetch_key_id; dbctx->fetch_key_text = fs_fetch_key_text; dbctx->fetch_key_skshash = fs_fetch_key_skshash; dbctx->store_key = fs_store_key; diff --git a/keydb/keydb_hkp.c b/keydb/keydb_hkp.c index 79d5c4b..ab33f49 100644 --- a/keydb/keydb_hkp.c +++ b/keydb/keydb_hkp.c @@ -143,24 +143,6 @@ static int hkp_fetch_key_url(struct onak_dbctx *dbctx, return count; } -/** - * hkp_fetch_key_id - Given a keyid fetch the key from HKP server. - */ -static int hkp_fetch_key_id(struct onak_dbctx *dbctx, - uint64_t keyid, - struct openpgp_publickey **publickey, - bool intrans) -{ - struct onak_hkp_dbctx *privctx = (struct onak_hkp_dbctx *) dbctx->priv; - char keyurl[1024]; - - snprintf(keyurl, sizeof(keyurl), - "%s/lookup?op=get&search=0x%08" PRIX64, - privctx->hkpbase, keyid); - - return (hkp_fetch_key_url(dbctx, keyurl, publickey, intrans)); -} - /** * hkp_fetch_key_fp - Given a fingerprint fetch the key from HKP server. */ @@ -191,6 +173,24 @@ static int hkp_fetch_key_fp(struct onak_dbctx *dbctx, return (hkp_fetch_key_url(dbctx, keyurl, publickey, intrans)); } +/** + * hkp_fetch_key_id - Given a keyid fetch the key from HKP server. + */ +static int hkp_fetch_key_id(struct onak_dbctx *dbctx, + uint64_t keyid, + struct openpgp_publickey **publickey, + bool intrans) +{ + struct onak_hkp_dbctx *privctx = (struct onak_hkp_dbctx *) dbctx->priv; + char keyurl[1024]; + + snprintf(keyurl, sizeof(keyurl), + "%s/lookup?op=get&search=0x%08" PRIX64, + privctx->hkpbase, keyid); + + return (hkp_fetch_key_url(dbctx, keyurl, publickey, intrans)); +} + /** * fetch_key_text - Tries to find the keys that contain the supplied text. * @search: The text to search for. @@ -322,6 +322,7 @@ static void hkp_endtrans(struct onak_dbctx *dbctx) #define NEED_KEYID2UID 1 #define NEED_GETKEYSIGS 1 #define NEED_UPDATEKEYS 1 +#define NEED_GET 1 #include "keydb.c" /** @@ -363,8 +364,9 @@ struct onak_dbctx *keydb_hkp_init(struct onak_db_config *dbcfg, bool readonly) dbctx->cleanupdb = hkp_cleanupdb; dbctx->starttrans = hkp_starttrans; dbctx->endtrans = hkp_endtrans; - dbctx->fetch_key_id = hkp_fetch_key_id; + dbctx->fetch_key = generic_fetch_key; dbctx->fetch_key_fp = hkp_fetch_key_fp; + dbctx->fetch_key_id = hkp_fetch_key_id; dbctx->fetch_key_text = hkp_fetch_key_text; dbctx->store_key = hkp_store_key; dbctx->update_keys = generic_update_keys; diff --git a/keydb/keydb_keyd.c b/keydb/keydb_keyd.c index e8f9961..baf04e1 100644 --- a/keydb/keydb_keyd.c +++ b/keydb/keydb_keyd.c @@ -91,11 +91,9 @@ static bool keyd_send_cmd(int fd, enum keyd_ops _cmd) * * This function returns a public key from whatever storage mechanism we * are using. - * - * TODO: What about keyid collisions? Should we use fingerprint instead? */ -static int keyd_fetch_key_id(struct onak_dbctx *dbctx, - uint64_t keyid, +static int keyd_fetch_key(struct onak_dbctx *dbctx, + struct openpgp_fingerprint *fingerprint, struct openpgp_publickey **publickey, bool intrans) { @@ -104,9 +102,16 @@ static int keyd_fetch_key_id(struct onak_dbctx *dbctx, struct openpgp_packet_list *packets = NULL; ssize_t bytes = 0; ssize_t count = 0; + uint8_t size; - if (keyd_send_cmd(keyd_fd, KEYD_CMD_GET_ID)) { - write(keyd_fd, &keyid, sizeof(keyid)); + if (fingerprint->length > MAX_FINGERPRINT_LEN) { + return 0; + } + + if (keyd_send_cmd(keyd_fd, KEYD_CMD_GET)) { + size = fingerprint->length; + write(keyd_fd, &size, sizeof(size)); + write(keyd_fd, fingerprint->fp, size); keybuf.offset = 0; read(keyd_fd, &keybuf.size, sizeof(keybuf.size)); if (keybuf.size > 0) { @@ -185,6 +190,48 @@ static int keyd_fetch_key_fp(struct onak_dbctx *dbctx, return (count > 0) ? 1 : 0; } +static int keyd_fetch_key_id(struct onak_dbctx *dbctx, + uint64_t keyid, + struct openpgp_publickey **publickey, + bool intrans) +{ + int keyd_fd = (intptr_t) dbctx->priv; + struct buffer_ctx keybuf; + struct openpgp_packet_list *packets = NULL; + ssize_t bytes = 0; + ssize_t count = 0; + + if (keyd_send_cmd(keyd_fd, KEYD_CMD_GET_ID)) { + write(keyd_fd, &keyid, sizeof(keyid)); + keybuf.offset = 0; + read(keyd_fd, &keybuf.size, sizeof(keybuf.size)); + if (keybuf.size > 0) { + keybuf.buffer = malloc(keybuf.size); + bytes = count = 0; + logthing(LOGTHING_TRACE, + "Getting %d bytes of key data.", + keybuf.size); + while (bytes >= 0 && count < keybuf.size) { + bytes = read(keyd_fd, &keybuf.buffer[count], + keybuf.size - count); + logthing(LOGTHING_TRACE, + "Read %d bytes.", bytes); + count += bytes; + } + read_openpgp_stream(buffer_fetchchar, &keybuf, + &packets, 0); + parse_keys(packets, publickey); + free_packet_list(packets); + packets = NULL; + free(keybuf.buffer); + keybuf.buffer = NULL; + keybuf.size = 0; + } + } + + return (count > 0) ? 1 : 0; +} + /** * delete_key - Given a keyid delete the key from storage. * @fp: The fingerprint of the key to delete. @@ -559,8 +606,9 @@ struct onak_dbctx *keydb_keyd_init(struct onak_db_config *dbcfg, bool readonly) dbctx->cleanupdb = keyd_cleanupdb; dbctx->starttrans = keyd_starttrans; dbctx->endtrans = keyd_endtrans; - dbctx->fetch_key_id = keyd_fetch_key_id; + dbctx->fetch_key = keyd_fetch_key; dbctx->fetch_key_fp = keyd_fetch_key_fp; + dbctx->fetch_key_id = keyd_fetch_key_id; dbctx->fetch_key_text = keyd_fetch_key_text; dbctx->fetch_key_skshash = keyd_fetch_key_skshash; dbctx->store_key = keyd_store_key; diff --git a/keydb/keydb_keyring.c b/keydb/keydb_keyring.c index 9550434..8e4790f 100644 --- a/keydb/keydb_keyring.c +++ b/keydb/keydb_keyring.c @@ -75,7 +75,7 @@ static void keyring_endtrans(struct onak_dbctx *dbctx) /** * keyring_fetch_key - fetch a key given its index */ -static int keyring_fetch_key(struct onak_keyring_dbctx *privctx, +static int keyring_fetch_key_idx(struct onak_keyring_dbctx *privctx, unsigned int index, struct openpgp_publickey **publickey) { @@ -97,7 +97,11 @@ static int keyring_fetch_key(struct onak_keyring_dbctx *privctx, return 1; } -static int keyring_fetch_key_fp(struct onak_dbctx *dbctx, +/* + * We only index the primary fingerprint of the key, so will only return one + * key at most from this function. + */ +static int keyring_fetch_key(struct onak_dbctx *dbctx, struct openpgp_fingerprint *fingerprint, struct openpgp_publickey **publickey, bool intrans) @@ -112,7 +116,7 @@ static int keyring_fetch_key_fp(struct onak_dbctx *dbctx, } if (i < privctx->count) { - return keyring_fetch_key(privctx, i, publickey); + return keyring_fetch_key_idx(privctx, i, publickey); } return 0; @@ -136,7 +140,7 @@ static int keyring_fetch_key_id(struct onak_dbctx *dbctx, count = 0; for (i = 0; i < privctx->count; i++) { if (fingerprint2keyid(&privctx->keys[i].fp) == keyid) { - if (keyring_fetch_key(privctx, i, publickey)) + if (keyring_fetch_key_idx(privctx, i, publickey)) count++; } } @@ -211,7 +215,7 @@ static int keyring_iterate_keys(struct onak_dbctx *dbctx, count = 0; for (i = 0; i < privctx->count; i++) { - if (keyring_fetch_key(privctx, i, &key)) { + if (keyring_fetch_key_idx(privctx, i, &key)) { iterfunc(ctx, key); free_publickey(key); key = NULL; @@ -327,7 +331,8 @@ static int keyring_parse_keys(struct onak_keyring_dbctx *privctx) * We need to fetch the key to calculate the * fingerprint. */ - keyring_fetch_key(privctx, privctx->count - 1, + keyring_fetch_key_idx(privctx, + privctx->count - 1, &key); get_fingerprint(key->publickey, &privctx->keys[privctx->count - 1].fp); @@ -440,8 +445,10 @@ struct onak_dbctx *keydb_keyring_init(struct onak_db_config *dbcfg, dbctx->cleanupdb = keyring_cleanupdb; dbctx->starttrans = keyring_starttrans; dbctx->endtrans = keyring_endtrans; + dbctx->fetch_key = keyring_fetch_key; + /* We don't index by subkey fingerprint, so fallback to fetch_key */ + dbctx->fetch_key_fp = keyring_fetch_key; dbctx->fetch_key_id = keyring_fetch_key_id; - dbctx->fetch_key_fp = keyring_fetch_key_fp; dbctx->fetch_key_text = keyring_fetch_key_text; dbctx->store_key = keyring_store_key; dbctx->update_keys = keyring_update_keys; diff --git a/keydb/keydb_pg.c b/keydb/keydb_pg.c index 7d59640..52d27fc 100644 --- a/keydb/keydb_pg.c +++ b/keydb/keydb_pg.c @@ -644,6 +644,7 @@ static int pg_iterate_keys(struct onak_dbctx *dbctx, * Include the basic keydb routines. */ #define NEED_UPDATEKEYS 1 +#define NEED_GET 1 #define NEED_GET_FP 1 #include "keydb.c" @@ -702,8 +703,9 @@ struct onak_dbctx *keydb_pg_init(struct onak_db_config *dbcfg, bool readonly) dbctx->cleanupdb = pg_cleanupdb; dbctx->starttrans = pg_starttrans; dbctx->endtrans = pg_endtrans; - dbctx->fetch_key_id = pg_fetch_key_id; + dbctx->fetch_key = generic_fetch_key; dbctx->fetch_key_fp = generic_fetch_key_fp; + dbctx->fetch_key_id = pg_fetch_key_id; dbctx->fetch_key_text = pg_fetch_key_text; dbctx->store_key = pg_store_key; dbctx->update_keys = generic_update_keys; diff --git a/keydb/keydb_stacked.c b/keydb/keydb_stacked.c index 6cfb1f7..28ca6fa 100644 --- a/keydb/keydb_stacked.c +++ b/keydb/keydb_stacked.c @@ -134,7 +134,8 @@ static void store_on_fallback(struct onak_stacked_dbctx *privctx, * reach the end or get a successful result. */ -static int stacked_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, +static int stacked_fetch_key(struct onak_dbctx *dbctx, + struct openpgp_fingerprint *fingerprint, struct openpgp_publickey **publickey, bool intrans) { struct onak_stacked_dbctx *privctx = @@ -146,7 +147,7 @@ static int stacked_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, for (cur = privctx->backends; cur != NULL && res == 0; cur = cur->next) { backend = (struct onak_dbctx *) cur->object; - res = backend->fetch_key_id(backend, keyid, publickey, + res = backend->fetch_key(backend, fingerprint, publickey, intrans); } @@ -181,6 +182,29 @@ static int stacked_fetch_key_fp(struct onak_dbctx *dbctx, return res; } +static int stacked_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, + struct openpgp_publickey **publickey, bool intrans) +{ + struct onak_stacked_dbctx *privctx = + (struct onak_stacked_dbctx *) dbctx->priv; + struct onak_dbctx *backend; + struct ll *cur; + int res = 0; + + for (cur = privctx->backends; cur != NULL && res == 0; + cur = cur->next) { + backend = (struct onak_dbctx *) cur->object; + res = backend->fetch_key_id(backend, keyid, publickey, + intrans); + } + + if (privctx->store_on_fallback && cur != privctx->backends) { + store_on_fallback(privctx, *publickey, intrans); + } + + return res; +} + static int stacked_fetch_key_text(struct onak_dbctx *dbctx, const char *search, struct openpgp_publickey **publickey) @@ -369,8 +393,9 @@ struct onak_dbctx *keydb_stacked_init(struct onak_db_config *dbcfg, dbctx->cleanupdb = stacked_cleanupdb; dbctx->starttrans = stacked_starttrans; dbctx->endtrans = stacked_endtrans; - dbctx->fetch_key_id = stacked_fetch_key_id; + dbctx->fetch_key = stacked_fetch_key; dbctx->fetch_key_fp = stacked_fetch_key_fp; + dbctx->fetch_key_id = stacked_fetch_key_id; dbctx->fetch_key_text = stacked_fetch_key_text; dbctx->fetch_key_skshash = stacked_fetch_key_skshash; dbctx->store_key = stacked_store_key; diff --git a/onak.c b/onak.c index 717402e..a27ff98 100644 --- a/onak.c +++ b/onak.c @@ -56,7 +56,10 @@ void find_keys(struct onak_dbctx *dbctx, if (ishex) { count = dbctx->fetch_key_id(dbctx, keyid, &publickey, false); - } else if (isfp) { + } else if (isfp && exact) { + count = dbctx->fetch_key(dbctx, fingerprint, + &publickey, false); + } else if (isfp && !exact) { count = dbctx->fetch_key_fp(dbctx, fingerprint, &publickey, false); } else { @@ -165,6 +168,7 @@ int main(int argc, char *argv[]) char *end = NULL; uint64_t keyid = 0; int i; + bool exact = false; bool ishex = false; bool isfp = false; bool update = false; @@ -177,7 +181,7 @@ int main(int argc, char *argv[]) struct onak_dbctx *dbctx; struct openpgp_fingerprint fingerprint; - while ((optchar = getopt(argc, argv, "bc:fsuv")) != -1 ) { + while ((optchar = getopt(argc, argv, "bc:efsuv")) != -1 ) { switch (optchar) { case 'b': binary = true; @@ -185,6 +189,9 @@ int main(int argc, char *argv[]) case 'c': configfile = strdup(optarg); break; + case 'e': + exact = true; + break; case 'f': dispfp = true; break; @@ -366,11 +373,11 @@ int main(int argc, char *argv[]) if (!strcmp("index", argv[optind])) { find_keys(dbctx, search, keyid, &fingerprint, ishex, isfp, dispfp, skshash, - false, false); + exact, false); } else if (!strcmp("vindex", argv[optind])) { find_keys(dbctx, search, keyid, &fingerprint, ishex, isfp, dispfp, skshash, - false, true); + exact, true); } else if (!strcmp("getphoto", argv[optind])) { if (!ishex) { puts("Can't get a key on uid text." diff --git a/t/all-095-get-subkey-fingerprint.t b/t/all-095-get-subkey-fingerprint.t new file mode 100755 index 0000000..58f0f70 --- /dev/null +++ b/t/all-095-get-subkey-fingerprint.t @@ -0,0 +1,25 @@ +#!/bin/sh +# Check we can retrieve a key by keyid + +set -e + +# Backends should really support full fingerprint retrieval, but they don't +# always. +if [ "$2" = "file" ]; then + exit 0 +fi + +cd ${WORKDIR} +${BUILDDIR}/onak -b -c $1 add < ${TESTSDIR}/../keys/noodles.key +if ! ${BUILDDIR}/onak -c $1 index 0x448B17C122A22C19FE289DC1045281F1B9A66E35 2> /dev/null | \ + grep -q -- 'noodles@earth.li'; then + echo "* Did not correctly retrieve key by subkey fingerprint." + exit 1 +fi +if ${BUILDDIR}/onak -e -c $1 index 0x448B17C122A22C19FE289DC1045281F1B9A66E35 2> /dev/null | \ + grep -q -- 'noodles@earth.li'; then + echo "* Incorrectly retrieved key by subkey fingerprint." + exit 1 +fi + +exit 0 -- 2.39.2