*/
        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.
  * @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,
  * @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.
        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.
 
                                }
                        }
                        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;
                                }
                        }
                        break;
-
                case KEYD_CMD_GET_TEXT:
                        if (!keyd_write_reply(fd, KEYD_REPLY_OK)) {
                                ret = 1;
 
        KEYD_CMD_GET_SKSHASH,
        KEYD_CMD_GET_FP,
        KEYD_CMD_UPDATE,
+       KEYD_CMD_GET,
        KEYD_CMD_LAST                   /* Placeholder */
 };
 
 
         * 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) {
        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
 
 /**
  *     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;
                        &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));
        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.
        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;
 
        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,
        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,
                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;
 
        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;
 
 #define NEED_KEYID2UID 1
 #define NEED_GETKEYSIGS 1
 #define NEED_UPDATEKEYS 1
+#define NEED_GET 1
 #define NEED_GET_FP 1
 #include "keydb.c"
 
        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;
 
        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.
  */
        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.
 #define NEED_KEYID2UID 1
 #define NEED_GETKEYSIGS 1
 #define NEED_UPDATEKEYS 1
+#define NEED_GET 1
 #include "keydb.c"
 
 /**
        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;
 
  *
  *     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)
 {
        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) {
        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.
        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;
 
 /**
  * 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)
 {
        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)
        }
 
        if (i < privctx->count) {
-               return keyring_fetch_key(privctx, i, publickey);
+               return keyring_fetch_key_idx(privctx, i, publickey);
        }
 
        return 0;
        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++;
                }
        }
 
        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;
                                 * 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);
        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;
 
  * Include the basic keydb routines.
  */
 #define NEED_UPDATEKEYS 1
+#define NEED_GET 1
 #define NEED_GET_FP 1
 #include "keydb.c"
 
        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;
 
  * 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 =
        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);
        }
 
        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)
                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;
 
        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 {
        char                            *end = NULL;
        uint64_t                         keyid = 0;
        int                              i;
+       bool                             exact = false;
        bool                             ishex = false;
        bool                             isfp = false;
        bool                             update = false;
        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;
                case 'c':
                        configfile = strdup(optarg);
                        break;
+               case 'e':
+                       exact = true;
+                       break;
                case 'f': 
                        dispfp = true;
                        break;
                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."
 
--- /dev/null
+#!/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