]> the.earth.li Git - onak.git/commitdiff
Provide key_fetch routine that will not search subkey fingerprints
authorJonathan McDowell <noodles@earth.li>
Fri, 17 Jan 2020 19:48:10 +0000 (19:48 +0000)
committerJonathan McDowell <noodles@earth.li>
Fri, 17 Jan 2020 19:48:10 +0000 (19:48 +0000)
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.

15 files changed:
keydb.h
keydb/keyd.c
keydb/keyd.h
keydb/keydb.c
keydb/keydb_db4.c
keydb/keydb_dynamic.c
keydb/keydb_file.c
keydb/keydb_fs.c
keydb/keydb_hkp.c
keydb/keydb_keyd.c
keydb/keydb_keyring.c
keydb/keydb_pg.c
keydb/keydb_stacked.c
onak.c
t/all-095-get-subkey-fingerprint.t [new file with mode: 0755]

diff --git a/keydb.h b/keydb.h
index 7297a7664b39fe53ceccefb23c791951acfb586a..9a9371b4ac9614759c3501c9d756d019488cfa51 100644 (file)
--- 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.
index 0df7192bfb6795b35d0d2b85ae8eafb6b699d6d1..ff02116d239a28d62762cfa4b30f3b9f50455611 100644 (file)
@@ -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;
index 1ea601c82777af9de57ecc039578f0e8b4e1b5b3..f92e7c69314c096cf0855c910cae05888f21d1bc 100644 (file)
@@ -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 */
 };
 
index f6b9682f2d4b4ade0db0494fbf4c4b312a80171e..692a7b7c902a42590b92d5ec29cbdc01e409e714 100644 (file)
@@ -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
index 1f306e267f60e9851c0dd65b0874517ba7afcb39..d9c45a9815799397d49231a7c659efb2b9f9989b 100644 (file)
@@ -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;
index 385c09cbb5ef3600e2b9e9a59a79b61d423f4c03..459779f7aa7391bdb057ec9a81352f9524468a05 100644 (file)
@@ -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;
index ded6a9e2e0c8e9db23f245b93e02a20f67e3a369..d3963646aa9ea6dc68fc83d02e09e80c352ab9d2 100644 (file)
@@ -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;
index f8d55dc8233dd80a2b92e6878abee3719dc67cd0..f7c865ee6b897cfb7995a35b5828dca1e7a63d12 100644 (file)
@@ -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;
index 79d5c4b302e30d433a63664092fedba9895b2bc4..ab33f4960127aa713f4be474c765ef6cfc62be49 100644 (file)
@@ -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;
index e8f9961b79a6d2f9364ec53e6dd42abe70953ec5..baf04e1ce64db86b258e103267c86aa5a68bc00d 100644 (file)
@@ -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;
index 9550434c612d5b027f3cf4a369b001d696d8e9fe..8e4790f5f20c0b0682bd6ada02593648b0cebec0 100644 (file)
@@ -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;
index 7d59640b0fd2a82189f0411fe2f0d5018c7fdf97..52d27fc538220b1c3c4661d5e952430b2e690067 100644 (file)
@@ -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;
index 6cfb1f76eed1b073a84b2926337ad7820b41a2b2..28ca6fa2d8c66e1d5e5fa06533c59c67ae02517a 100644 (file)
@@ -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 717402ee41137e0e90aa6862d87c8a4396d3f552..a27ff983e78908d6de2e57013173d7b97d7118cf 100644 (file)
--- 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 (executable)
index 0000000..58f0f70
--- /dev/null
@@ -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