]> the.earth.li Git - onak.git/commitdiff
Extend database backends to support fetching by key fingerprint
authorJonathan McDowell <noodles@earth.li>
Tue, 5 Nov 2013 00:56:31 +0000 (16:56 -0800)
committerJonathan McDowell <noodles@earth.li>
Tue, 5 Nov 2013 01:11:43 +0000 (17:11 -0800)
Up until now the database backends have supported fetching a specific
key only by 64 bit key id. We should really have been using the
fingerprint where possible. Add a new backend function, fetch_key_fp,
to allow us to fetch using the fingerprint, and a generic implementation
that just truncates the fingerprint to get the 64 bit key id (valid for
v4 only). The HKP, keyd and dynamic backends gain full passthrough
support for retrieval by fingerprint with this commit.

16 files changed:
gpgwww.c
keyd.c
keyd.h
keydb.c
keydb.h
keydb_db4.c
keydb_dynamic.c
keydb_file.c
keydb_fs.c
keydb_hkp.c
keydb_keyd.c
keydb_pg.c
keydctl.c
keystructs.h
lookup.c
onak.c

index 84f00e4d70d9674cfc11f0c9babe1a112c714aca..07b448e37eff10cac7d40b211bafd1b576d91c5e 100644 (file)
--- a/gpgwww.c
+++ b/gpgwww.c
@@ -104,7 +104,7 @@ int getkeyspath(uint64_t have, uint64_t want, int count)
                        curkey = findinhash(keyinfoa->parent);
                        while (curkey != NULL && curkey->keyid != 0) {
                                if (curkey->keyid != fullwant &&
-                                               config.dbbackend->fetch_key(
+                                               config.dbbackend->fetch_key_id(
                                                curkey->keyid,
                                                &publickey, false)) {
                                        flatten_publickey(publickey,
@@ -125,7 +125,7 @@ int getkeyspath(uint64_t have, uint64_t want, int count)
        /*
         * Add the destination key to the list of returned keys.
         */
-       if (config.dbbackend->fetch_key(fullwant, &publickey, false)) {
+       if (config.dbbackend->fetch_key_id(fullwant, &publickey, false)) {
                flatten_publickey(publickey,
                                &packets,
                                &list_end);
diff --git a/keyd.c b/keyd.c
index 21d3bdbe2f35dabd020f3f74fde8ea798414bba9..a89f0e1f37aade33ecf00d4f171f92d191bf1dee 100644 (file)
--- a/keyd.c
+++ b/keyd.c
@@ -151,6 +151,7 @@ int sock_do(int fd)
        ssize_t  count = 0;
        int      ret = 0;
        uint64_t keyid = 0;
+       uint8_t  fp[MAX_FINGERPRINT_LEN];
        char     *search = NULL;
        struct openpgp_publickey *key = NULL;
        struct openpgp_packet_list *packets = NULL;
@@ -183,7 +184,7 @@ int sock_do(int fd)
                        write(fd, &cmd, sizeof(cmd));
                        write(fd, &keyd_version, sizeof(keyd_version));
                        break;
-               case KEYD_CMD_GET:
+               case KEYD_CMD_GET_ID:
                        cmd = KEYD_REPLY_OK;
                        write(fd, &cmd, sizeof(cmd));
                        bytes = read(fd, &keyid, sizeof(keyid));
@@ -197,7 +198,8 @@ int sock_do(int fd)
                                                ", result: %d",
                                                keyid,
                                                config.dbbackend->
-                                               fetch_key(keyid, &key, false));
+                                               fetch_key_id(keyid,
+                                                       &key, false));
                                if (key != NULL) {
                                        storebuf.size = 8192;
                                        storebuf.buffer = malloc(8192);
@@ -229,7 +231,56 @@ int sock_do(int fd)
                                }
                        }
                        break;
-               case KEYD_CMD_GETTEXT:
+               case KEYD_CMD_GET_FP:
+                       cmd = KEYD_REPLY_OK;
+                       write(fd, &cmd, sizeof(cmd));
+                       read(fd, &bytes, 1);
+                       if (bytes > MAX_FINGERPRINT_LEN) {
+                               ret = 1;
+                       } else {
+                               read(fd, fp, bytes);
+                       }
+                       storebuf.offset = 0;
+                       if (ret == 0) {
+                               logthing(LOGTHING_INFO,
+                                               "Fetching by fingerprint"
+                                               ", result: %d",
+                                               config.dbbackend->
+                                               fetch_key_fp(fp, bytes,
+                                                       &key, false));
+                               if (key != NULL) {
+                                       storebuf.size = 8192;
+                                       storebuf.buffer = malloc(8192);
+
+                                       flatten_publickey(key,
+                                                       &packets,
+                                                       &list_end);
+                                       write_openpgp_stream(buffer_putchar,
+                                                       &storebuf,
+                                                       packets);
+                                       logthing(LOGTHING_TRACE,
+                                                       "Sending %d bytes.",
+                                                       storebuf.offset);
+                                       write(fd, &storebuf.offset,
+                                               sizeof(storebuf.offset));
+                                       write(fd, storebuf.buffer,
+                                               storebuf.offset);
+
+                                       free(storebuf.buffer);
+                                       storebuf.buffer = NULL;
+                                       storebuf.size = storebuf.offset = 0;
+                                       free_packet_list(packets);
+                                       packets = list_end = NULL;
+                                       free_publickey(key);
+                                       key = NULL;
+                               } else {
+                                       write(fd, &storebuf.offset,
+                                               sizeof(storebuf.offset));
+                               }
+                       }
+                       break;
+
+               case KEYD_CMD_GET_TEXT:
                        cmd = KEYD_REPLY_OK;
                        write(fd, &cmd, sizeof(cmd));
                        bytes = read(fd, &count, sizeof(count));
@@ -375,7 +426,7 @@ int sock_do(int fd)
                        write(fd, stats,
                                sizeof(*stats));
                        break;
-               case KEYD_CMD_GETSKSHASH:
+               case KEYD_CMD_GET_SKSHASH:
                        cmd = KEYD_REPLY_OK;
                        write(fd, &cmd, sizeof(cmd));
                        bytes = read(fd, hash.hash, sizeof(hash.hash));
diff --git a/keyd.h b/keyd.h
index 91959c87258a616475bd065b081cf3fa599b0e70..b33cab90984685663afe4975f8cbfb6029fc3ae5 100644 (file)
--- a/keyd.h
+++ b/keyd.h
 enum keyd_ops {
        KEYD_CMD_UNKNOWN = 0,
        KEYD_CMD_VERSION = 1,
-       KEYD_CMD_GET,
+       KEYD_CMD_GET_ID,
        KEYD_CMD_STORE,
        KEYD_CMD_DELETE,
-       KEYD_CMD_GETTEXT,
+       KEYD_CMD_GET_TEXT,
        KEYD_CMD_GETFULLKEYID,
        KEYD_CMD_KEYITER,
        KEYD_CMD_CLOSE,
        KEYD_CMD_QUIT,
        KEYD_CMD_STATS,
-       KEYD_CMD_GETSKSHASH,
+       KEYD_CMD_GET_SKSHASH,
+       KEYD_CMD_GET_FP,
        KEYD_CMD_LAST                   /* Placeholder */
 };
 
@@ -58,7 +59,7 @@ enum keyd_reply {
 /**
  * @brief Version of the keyd protocol currently supported
  */
-static const uint32_t keyd_version = 3;
+static const uint32_t keyd_version = 4;
 
 /**
  * @brief Response structure for the @a KEYD_CMD_STATS response
diff --git a/keydb.c b/keydb.c
index c257eb589db31b1c51962049c0e79a3384969dfe..ac70640e26df6bfedcfd7f506a09e30155a75abf 100644 (file)
--- a/keydb.c
+++ b/keydb.c
@@ -50,7 +50,7 @@ char *generic_keyid2uid(uint64_t keyid)
        char buf[1024];
 
        buf[0]=0;
-       if (config.dbbackend->fetch_key(keyid, &publickey, false) &&
+       if (config.dbbackend->fetch_key_id(keyid, &publickey, false) &&
                        publickey != NULL) {
                curuid = publickey->uids;
                while (curuid != NULL && buf[0] == 0) {
@@ -88,7 +88,7 @@ struct ll *generic_getkeysigs(uint64_t keyid, bool *revoked)
        struct openpgp_signedpacket_list *uids = NULL;
        struct openpgp_publickey *publickey = NULL;
 
-       config.dbbackend->fetch_key(keyid, &publickey, false);
+       config.dbbackend->fetch_key_id(keyid, &publickey, false);
        
        if (publickey != NULL) {
                for (uids = publickey->uids; uids != NULL; uids = uids->next) {
@@ -160,7 +160,7 @@ uint64_t generic_getfullkeyid(uint64_t keyid)
        struct openpgp_publickey *publickey = NULL;
 
        if (keyid < 0x100000000LL) {
-               config.dbbackend->fetch_key(keyid, &publickey, false);
+               config.dbbackend->fetch_key_id(keyid, &publickey, false);
                if (publickey != NULL) {
                        get_keyid(publickey, &keyid);
                        free_publickey(publickey);
@@ -201,7 +201,7 @@ int generic_update_keys(struct openpgp_publickey **keys, bool sendsync)
                logthing(LOGTHING_INFO,
                        "Fetching key 0x%" PRIX64 ", result: %d",
                        keyid,
-                       config.dbbackend->fetch_key(keyid, &oldkey,
+                       config.dbbackend->fetch_key_id(keyid, &oldkey,
                                        intrans));
 
                /*
@@ -249,3 +249,30 @@ int generic_update_keys(struct openpgp_publickey **keys, bool sendsync)
        return newkeys;
 }
 #endif /* NEED_UPDATEKEYS */
+
+#ifdef NEED_GET_FP
+static int generic_fetch_key_fp(uint8_t *fp, size_t fpsize,
+               struct openpgp_publickey **publickey, bool intrans)
+{
+       uint64_t keyid;
+       int i;
+
+       if (fpsize > MAX_FINGERPRINT_LEN) {
+               return 0;
+       }
+
+       /*
+        * We assume if the backend is using this function it's not storing
+        * anything bigger than the 64 bit key ID and just truncate the
+        * fingerprint to get that value. 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.
+        */
+       keyid = 0;
+       for (i = (fpsize - 8); i < fpsize; i++) {
+               keyid = (keyid << 8) + fp[i];
+       }
+
+       return config.dbbackend->fetch_key_id(keyid, publickey, intrans);
+}
+#endif
diff --git a/keydb.h b/keydb.h
index 20ab62f3bef32096ce50787c299e46f98c2f190c..6ad9a59fb46403d6da242bb5559681fa5dca1d34 100644 (file)
--- a/keydb.h
+++ b/keydb.h
@@ -75,7 +75,23 @@ struct dbfuncs {
  *
  * TODO: What about keyid collisions? Should we use fingerprint instead?
  */
-       int (*fetch_key)(uint64_t keyid, struct openpgp_publickey **publickey,
+       int (*fetch_key_id)(uint64_t keyid,
+                       struct openpgp_publickey **publickey,
+                       bool intrans);
+
+/**
+ * @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.
+ */
+       int (*fetch_key_fp)(uint8_t *fp,
+                       size_t fpsize,
+                       struct openpgp_publickey **publickey,
                        bool intrans);
 
 /**
index f4fffa58849b90e7c5f4f0cc93e28b05f29d1300..dae8a2a91f8f9ad830908baa82a405b500d7f559 100644 (file)
@@ -641,7 +641,7 @@ static uint64_t db4_getfullkeyid(uint64_t keyid)
 }
 
 /**
- *     fetch_key - Given a keyid fetch the key from storage.
+ *     fetch_key_id - Given a keyid fetch the key from storage.
  *     @keyid: The keyid to fetch.
  *     @publickey: A pointer to a structure to return the key in.
  *     @intrans: If we're already in a transaction.
@@ -652,7 +652,8 @@ static uint64_t db4_getfullkeyid(uint64_t keyid)
  *     in and then parse_keys() to parse the packets into a publickey
  *     structure.
  */
-static int db4_fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
+static int db4_fetch_key_id(uint64_t keyid,
+               struct openpgp_publickey **publickey,
                bool intrans)
 {
        struct openpgp_packet_list *packets = NULL;
@@ -840,7 +841,7 @@ static int db4_fetch_key_text(const char *search,
        
        db4_starttrans();
        for (i = 0; i < keylist.count; i++) {
-               numkeys += db4_fetch_key(keylist.keys[i],
+               numkeys += db4_fetch_key_id(keylist.keys[i],
                        publickey,
                        true);
        }
@@ -889,7 +890,7 @@ static int db4_fetch_key_skshash(const struct skshash *hash,
        ret = cursor->c_close(cursor);
        cursor = NULL;
 
-       return db4_fetch_key(keyid, publickey, false);
+       return db4_fetch_key_id(keyid, publickey, false);
 }
 
 /**
@@ -921,7 +922,7 @@ static int db4_delete_key(uint64_t keyid, bool intrans)
                db4_starttrans();
        }
 
-       db4_fetch_key(keyid, &publickey, true);
+       db4_fetch_key_id(keyid, &publickey, true);
 
        /*
         * Walk through the uids removing the words from the worddb.
@@ -1501,6 +1502,7 @@ static int db4_iterate_keys(void (*iterfunc)(void *ctx,
 #define NEED_GETKEYSIGS 1
 #define NEED_KEYID2UID 1
 #define NEED_UPDATEKEYS 1
+#define NEED_GET_FP 1
 #include "keydb.c"
 
 struct dbfuncs keydb_db4_funcs = {
@@ -1508,7 +1510,8 @@ struct dbfuncs keydb_db4_funcs = {
        .cleanupdb              = db4_cleanupdb,
        .starttrans             = db4_starttrans,
        .endtrans               = db4_endtrans,
-       .fetch_key              = db4_fetch_key,
+       .fetch_key_id           = db4_fetch_key_id,
+       .fetch_key_fp           = generic_fetch_key_fp,
        .fetch_key_text         = db4_fetch_key_text,
        .fetch_key_skshash      = db4_fetch_key_skshash,
        .store_key              = db4_store_key,
index 65373860461243548727048858493850d2a597d7..536909a67c67e1c4219ce913d9ada34665cb1761 100644 (file)
@@ -147,22 +147,42 @@ static void dynamic_endtrans()
        }
 }
 
-static int dynamic_fetch_key(uint64_t keyid,
+static int dynamic_fetch_key_id(uint64_t keyid,
                struct openpgp_publickey **publickey, bool intrans)
 {
        if (loaded_backend == NULL) {
                load_backend();
        }
-       
+
        if (loaded_backend != NULL) {
-               if (loaded_backend->fetch_key != NULL) {
-                       return loaded_backend->fetch_key(keyid,publickey,intrans);
+               if (loaded_backend->fetch_key_id != NULL) {
+                       return loaded_backend->fetch_key_id(keyid,
+                               publickey, intrans);
                }
        }
 
        return -1;
 }
 
+static int dynamic_fetch_key_fp(uint8_t *fp, size_t fpsize,
+               struct openpgp_publickey **publickey, bool intrans)
+{
+       if (loaded_backend == NULL) {
+               load_backend();
+       }
+
+       if (loaded_backend != NULL) {
+               if (loaded_backend->fetch_key_id != NULL) {
+                       return loaded_backend->fetch_key_fp(fp, fpsize,
+                               publickey, intrans);
+               }
+       }
+
+       return -1;
+}
+
+
+
 static int dynamic_store_key(struct openpgp_publickey *publickey, bool intrans,
                bool update)
 {
@@ -264,7 +284,8 @@ static char *dynamic_keyid2uid(uint64_t keyid)
        }
        
        buf[0]=0;
-       if (dynamic_fetch_key(keyid, &publickey, false) && publickey != NULL) {
+       if (dynamic_fetch_key_id(keyid, &publickey, false) &&
+                       publickey != NULL) {
                curuid = publickey->uids;
                while (curuid != NULL && buf[0] == 0) {
                        if (curuid->packet->tag == OPENPGP_PACKET_UID) {
@@ -309,7 +330,7 @@ static struct ll *dynamic_getkeysigs(uint64_t keyid, bool *revoked)
                }
        }
 
-       dynamic_fetch_key(keyid, &publickey, false);
+       dynamic_fetch_key_id(keyid, &publickey, false);
        
        if (publickey != NULL) {
                for (uids = publickey->uids; uids != NULL; uids = uids->next) {
@@ -391,7 +412,7 @@ static uint64_t dynamic_getfullkeyid(uint64_t keyid)
        }
 
        if (keyid < 0x100000000LL) {
-               dynamic_fetch_key(keyid, &publickey, false);
+               dynamic_fetch_key_id(keyid, &publickey, false);
                if (publickey != NULL) {
                        get_keyid(publickey, &keyid);
                        free_publickey(publickey);
@@ -440,7 +461,7 @@ static int dynamic_update_keys(struct openpgp_publickey **keys, bool sendsync)
                logthing(LOGTHING_INFO,
                        "Fetching key 0x%" PRIX64 ", result: %d",
                        keyid,
-                       dynamic_fetch_key(keyid, &oldkey, intrans));
+                       dynamic_fetch_key_id(keyid, &oldkey, intrans));
 
                /*
                 * If we already have the key stored in the DB then merge it
@@ -516,7 +537,8 @@ struct dbfuncs keydb_dynamic_funcs = {
        .cleanupdb              = dynamic_cleanupdb,
        .starttrans             = dynamic_starttrans,
        .endtrans               = dynamic_endtrans,
-       .fetch_key              = dynamic_fetch_key,
+       .fetch_key_id           = dynamic_fetch_key_id,
+       .fetch_key_fp           = dynamic_fetch_key_fp,
        .fetch_key_text         = dynamic_fetch_key_text,
        .fetch_key_skshash      = dynamic_fetch_key_skshash,
        .store_key              = dynamic_store_key,
index 4321a682ee762e4c51855858fb746851a0ed0fa2..eeae01f3013585504ac13b5c520e2374443c3474 100644 (file)
@@ -76,7 +76,7 @@ static void file_endtrans(void)
 }
 
 /**
- *     fetch_key - Given a keyid fetch the key from storage.
+ *     fetch_key_id - Given a keyid fetch the key from storage.
  *     @keyid: The keyid to fetch.
  *     @publickey: A pointer to a structure to return the key in.
  *     @intrans: If we're already in a transaction.
@@ -87,7 +87,8 @@ static void file_endtrans(void)
  *     in and then parse_keys() to parse the packets into a publickey
  *     structure.
  */
-static int file_fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
+static int file_fetch_key_id(uint64_t keyid,
+               struct openpgp_publickey **publickey,
                bool intrans)
 {
        struct openpgp_packet_list *packets = NULL;
@@ -253,6 +254,7 @@ static int file_iterate_keys(void (*iterfunc)(void *ctx,
 #define NEED_GETKEYSIGS 1
 #define NEED_GETFULLKEYID 1
 #define NEED_UPDATEKEYS 1
+#define NEED_GET_FP 1
 #include "keydb.c"
 
 struct dbfuncs keydb_file_funcs = {
@@ -260,7 +262,8 @@ struct dbfuncs keydb_file_funcs = {
        .cleanupdb              = file_cleanupdb,
        .starttrans             = file_starttrans,
        .endtrans               = file_endtrans,
-       .fetch_key              = file_fetch_key,
+       .fetch_key_id           = file_fetch_key_id,
+       .fetch_key_fp           = generic_fetch_key_fp,
        .fetch_key_text         = file_fetch_key_text,
        .store_key              = file_store_key,
        .update_keys            = generic_update_keys,
index b7117bebab4ffeda8f4bf36a2b650eb3c600a256..b9447321153d1f4bd40b4d90a62c9dfb25d45645 100644 (file)
@@ -285,7 +285,8 @@ static uint64_t fs_getfullkeyid(uint64_t keyid)
  *     @publickey: A pointer to a structure to return the key in.
  *     @intrans: If we're already in a transaction.
  */
-static int fs_fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
+static int fs_fetch_key_id(uint64_t keyid,
+             struct openpgp_publickey **publickey,
              bool intrans)
 {
        static char buffer[PATH_MAX];
@@ -430,7 +431,7 @@ static int fs_delete_key(uint64_t keyid, bool intrans)
        if (!intrans)
                fs_starttrans();
 
-       ret = fs_fetch_key(keyid, &pk, true);
+       ret = fs_fetch_key_id(keyid, &pk, true);
 
        if (ret) {
                logthing(LOGTHING_DEBUG, "Wordlist for key %016" PRIX64,
@@ -563,7 +564,7 @@ static int fs_fetch_key_text(const char *search,
        while (wl) {
                logthing(LOGTHING_DEBUG, "Adding key: %s", wl->object);
                addedkeys +=
-                   fs_fetch_key(strtoull(wl->object, NULL, 16), publickey,
+                   fs_fetch_key_id(strtoull(wl->object, NULL, 16), publickey,
                              false);
                if (addedkeys >= config.maxkeys)
                        break;
@@ -626,6 +627,7 @@ static int fs_iterate_keys(void (*iterfunc)(void *ctx,
 #define NEED_KEYID2UID 1
 #define NEED_GETKEYSIGS 1
 #define NEED_UPDATEKEYS 1
+#define NEED_GET_FP 1
 #include "keydb.c"
 
 struct dbfuncs keydb_fs_funcs = {
@@ -633,7 +635,8 @@ struct dbfuncs keydb_fs_funcs = {
        .cleanupdb              = fs_cleanupdb,
        .starttrans             = fs_starttrans,
        .endtrans               = fs_endtrans,
-       .fetch_key              = fs_fetch_key,
+       .fetch_key_id           = fs_fetch_key_id,
+       .fetch_key_fp           = generic_fetch_key_fp,
        .fetch_key_text         = fs_fetch_key_text,
        .fetch_key_skshash      = fs_fetch_key_skshash,
        .store_key              = fs_store_key,
index ac1edace24617127c6cd6375c7241f493044e025..3fa15935196b4222d86075d86573942822435acd 100644 (file)
@@ -147,35 +147,20 @@ static size_t hkp_curl_recv_data(void *buffer, size_t size, size_t nmemb,
        return (nmemb * size);
 }
 
-/**
- *     fetch_key - Given a keyid fetch the key from storage.
- *     @keyid: The keyid to fetch.
- *     @publickey: A pointer to a structure to return the key in.
- *     @intrans: If we're already in a transaction.
- *
- *     We use the hex representation of the keyid as the filename to fetch the
- *     key from. The key is stored in the file as a binary OpenPGP stream of
- *     packets, so we can just use read_openpgp_stream() to read the packets
- *     in and then parse_keys() to parse the packets into a publickey
- *     structure.
- */
-static int hkp_fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
+static int hkp_fetch_key_url(char *url,
+               struct openpgp_publickey **publickey,
                bool intrans)
 {
        struct openpgp_packet_list *packets = NULL;
-       char keyurl[1024];
        CURLcode res;
        struct buffer_ctx buf;
+       int count = 0;
 
        buf.offset = 0;
        buf.size = 8192;
        buf.buffer = malloc(8192);
 
-       snprintf(keyurl, sizeof(keyurl),
-                       "%s/lookup?op=get&search=0x%08" PRIX64,
-                       hkpbase, keyid);
-
-       curl_easy_setopt(curl, CURLOPT_URL, keyurl);
+       curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
                        hkp_curl_recv_data);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf);
@@ -184,7 +169,7 @@ static int hkp_fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
        if (res == 0) {
                buf.offset = 0;
                dearmor_openpgp_stream(buffer_fetchchar, &buf, &packets);
-               parse_keys(packets, publickey);
+               count = parse_keys(packets, publickey);
                free_packet_list(packets);
                packets = NULL;
        } else {
@@ -196,7 +181,51 @@ static int hkp_fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
        buf.offset = buf.size = 0;
        buf.buffer = NULL;
 
-       return (res == 0) ? 1 : 0;
+       return count;
+}
+
+/**
+ *     hkp_fetch_key_id - Given a keyid fetch the key from HKP server.
+ */
+static int hkp_fetch_key_id(uint64_t keyid,
+               struct openpgp_publickey **publickey,
+               bool intrans)
+{
+       char keyurl[1024];
+
+       snprintf(keyurl, sizeof(keyurl),
+                       "%s/lookup?op=get&search=0x%08" PRIX64,
+                       hkpbase, keyid);
+
+       return (hkp_fetch_key_url(keyurl, publickey, intrans));
+}
+
+/**
+ *     hkp_fetch_key_fp - Given a fingerprint fetch the key from HKP server.
+ */
+static int hkp_fetch_key_fp(uint8_t *fp, size_t fpsize,
+               struct openpgp_publickey **publickey,
+               bool intrans)
+{
+       char keyurl[1024];
+       int i, ofs;
+
+       if (fpsize > MAX_FINGERPRINT_LEN) {
+               return 0;
+       }
+
+       ofs = snprintf(keyurl, sizeof(keyurl),
+                       "%s/lookup?op=get&search=0x", hkpbase);
+
+       if ((ofs + fpsize * 2 + 1)> sizeof(keyurl)) {
+               return 0;
+       }
+
+       for (i = 0; i < fpsize; i++) {
+               ofs += sprintf(&keyurl[ofs], "%02X", fp[i]);
+       }
+
+       return (hkp_fetch_key_url(keyurl, publickey, intrans));
 }
 
 /**
@@ -212,42 +241,13 @@ static int hkp_fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
 static int hkp_fetch_key_text(const char *search,
                struct openpgp_publickey **publickey)
 {
-       struct openpgp_packet_list *packets = NULL;
        char keyurl[1024];
-       CURLcode res;
-       struct buffer_ctx buf;
-       int count = 0;
-
-       buf.offset = 0;
-       buf.size = 8192;
-       buf.buffer = malloc(8192);
 
        snprintf(keyurl, sizeof(keyurl),
                        "%s/lookup?op=get&search=%s",
                        hkpbase, search);
 
-       curl_easy_setopt(curl, CURLOPT_URL, keyurl);
-       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
-                       hkp_curl_recv_data);
-       curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf);
-       res = curl_easy_perform(curl);
-
-       if (res == 0) {
-               buf.offset = 0;
-               dearmor_openpgp_stream(buffer_fetchchar, &buf, &packets);
-               count = parse_keys(packets, publickey);
-               free_packet_list(packets);
-               packets = NULL;
-       } else {
-               logthing(LOGTHING_ERROR, "Couldn't find key: %s (%d)",
-                       curl_easy_strerror(res), res);
-       }
-
-       free(buf.buffer);
-       buf.offset = buf.size = 0;
-       buf.buffer = NULL;
-
-       return count;
+       return (hkp_fetch_key_url(keyurl, publickey, false));
 }
 
 /**
@@ -361,7 +361,8 @@ struct dbfuncs keydb_hkp_funcs = {
        .cleanupdb              = hkp_cleanupdb,
        .starttrans             = hkp_starttrans,
        .endtrans               = hkp_endtrans,
-       .fetch_key              = hkp_fetch_key,
+       .fetch_key_id           = hkp_fetch_key_id,
+       .fetch_key_fp           = hkp_fetch_key_fp,
        .fetch_key_text         = hkp_fetch_key_text,
        .store_key              = hkp_store_key,
        .update_keys            = generic_update_keys,
index 4820ee31d9a0a364f0e15f7670dedaf0767a98e8..7995e38a8e757ddb7a1d685432ae54d7b432aa0e 100644 (file)
@@ -187,12 +187,13 @@ static void keyd_endtrans(void)
  *
  *      TODO: What about keyid collisions? Should we use fingerprint instead?
  */
-static int keyd_fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
+static int keyd_fetch_key_id(uint64_t keyid,
+               struct openpgp_publickey **publickey,
                bool intrans)
 {
        struct buffer_ctx           keybuf;
        struct openpgp_packet_list *packets = NULL;
-       uint32_t                    cmd = KEYD_CMD_GET;
+       uint32_t                    cmd = KEYD_CMD_GET_ID;
        ssize_t                     bytes = 0;
        ssize_t                     count = 0;
 
@@ -225,7 +226,57 @@ static int keyd_fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
                        keybuf.size = 0;
                }
        }
-       
+
+       return (count > 0) ? 1 : 0;
+}
+
+static int keyd_fetch_key_fp(uint8_t *fp, size_t fpsize,
+               struct openpgp_publickey **publickey,
+               bool intrans)
+{
+       struct buffer_ctx           keybuf;
+       struct openpgp_packet_list *packets = NULL;
+       uint32_t                    cmd = KEYD_CMD_GET_FP;
+       ssize_t                     bytes = 0;
+       ssize_t                     count = 0;
+       uint8_t                     size;
+
+       if (fpsize > MAX_FINGERPRINT_LEN) {
+               return 0;
+       }
+
+       write(keyd_fd, &cmd, sizeof(cmd));
+       read(keyd_fd, &cmd, sizeof(cmd));
+       if (cmd == KEYD_REPLY_OK) {
+               size = fpsize;
+               write(keyd_fd, &size, sizeof(size));
+               write(keyd_fd, fp, size);
+               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;
 }
 
@@ -325,7 +376,7 @@ static int keyd_fetch_key_text(const char *search,
 {
        struct buffer_ctx           keybuf;
        struct openpgp_packet_list *packets = NULL;
-       uint32_t                    cmd = KEYD_CMD_GETTEXT;
+       uint32_t                    cmd = KEYD_CMD_GET_TEXT;
        ssize_t                     bytes = 0;
        ssize_t                     count = 0;
 
@@ -371,7 +422,7 @@ static int keyd_fetch_key_skshash(const struct skshash *hash,
 {
        struct buffer_ctx           keybuf;
        struct openpgp_packet_list *packets = NULL;
-       uint32_t                    cmd = KEYD_CMD_GETSKSHASH;
+       uint32_t                    cmd = KEYD_CMD_GET_SKSHASH;
        ssize_t                     bytes = 0;
        ssize_t                     count = 0;
 
@@ -509,7 +560,8 @@ struct dbfuncs keydb_keyd_funcs = {
        .cleanupdb              = keyd_cleanupdb,
        .starttrans             = keyd_starttrans,
        .endtrans               = keyd_endtrans,
-       .fetch_key              = keyd_fetch_key,
+       .fetch_key_id           = keyd_fetch_key_id,
+       .fetch_key_fp           = keyd_fetch_key_fp,
        .fetch_key_text         = keyd_fetch_key_text,
        .fetch_key_skshash      = keyd_fetch_key_skshash,
        .store_key              = keyd_store_key,
index 480f1f1d34541831c6e3fd414785867d0a2c3ed1..04c760dfbf9759cca2e60241f1fdaeac1f2f8bb3 100644 (file)
@@ -131,7 +131,7 @@ static void pg_endtrans(void)
 }
 
 /**
- *     fetch_key - Given a keyid fetch the key from storage.
+ *     fetch_key_id - Given a keyid fetch the key from storage.
  *     @keyid: The keyid to fetch.
  *     @publickey: A pointer to a structure to return the key in.
  *     @intrans: If we're already in a transaction.
@@ -142,7 +142,8 @@ static void pg_endtrans(void)
  *     in and then parse_keys() to parse the packets into a publickey
  *     structure.
  */
-static int pg_fetch_key(uint64_t keyid, struct openpgp_publickey **publickey,
+static int pg_fetch_key_id(uint64_t keyid,
+               struct openpgp_publickey **publickey,
                bool intrans)
 {
        struct openpgp_packet_list *packets = NULL;
@@ -655,6 +656,7 @@ static int pg_iterate_keys(void (*iterfunc)(void *ctx,
  */
 #define NEED_GETFULLKEYID 1
 #define NEED_UPDATEKEYS 1
+#define NEED_GET_FP 1
 #include "keydb.c"
 
 struct dbfuncs keydb_pg_funcs = {
@@ -662,7 +664,8 @@ struct dbfuncs keydb_pg_funcs = {
        .cleanupdb              = pg_cleanupdb,
        .starttrans             = pg_starttrans,
        .endtrans               = pg_endtrans,
-       .fetch_key              = pg_fetch_key,
+       .fetch_key_id           = pg_fetch_key_id,
+       .fetch_key_fp           = generic_fetch_key_fp,
        .fetch_key_text         = pg_fetch_key_text,
        .store_key              = pg_store_key,
        .update_keys            = generic_update_keys,
index 5a2ac212b96be129cab52b173b48d8737e26757a..4ffecae2943a3fa2bcb51ba08a4889aa0c8208dc 100644 (file)
--- a/keydctl.c
+++ b/keydctl.c
@@ -164,13 +164,16 @@ static void keyd_status(void)
        printf("Command statistics:\n");
        printf("  Version:          %d\n",
                stats.command_stats[KEYD_CMD_VERSION]);
-       printf("  Get key:          %d\n", stats.command_stats[KEYD_CMD_GET]);
+       printf("  Get key by ID:    %d\n",
+               stats.command_stats[KEYD_CMD_GET_ID]);
+       printf("  Get key by FP:    %d\n",
+               stats.command_stats[KEYD_CMD_GET_FP]);
        printf("  Store key:        %d\n",
                stats.command_stats[KEYD_CMD_STORE]);
        printf("  Delete key:       %d\n",
                stats.command_stats[KEYD_CMD_DELETE]);
        printf("  Search key:       %d\n",
-               stats.command_stats[KEYD_CMD_GETTEXT]);
+               stats.command_stats[KEYD_CMD_GET_TEXT]);
        printf("  Get full keyid:   %d\n",
                stats.command_stats[KEYD_CMD_GETFULLKEYID]);
        printf("  Iterate all keys: %d\n",
index fcfed121dd66b9be29114aa314c1b38a0ae11912..13f9160ed46f9c3afee272eb1a5862b28d7a1b16 100644 (file)
@@ -27,6 +27,9 @@
 
 #include "ll.h"
 
+/* v3 MD5 fingerprint is 16 characters, v4 SHA-1 fingerprint is 20 */
+#define MAX_FINGERPRINT_LEN 20
+
 /**
  * @brief Stores an OpenPGP packet.
  *
index 9af11d93204dac0c75b57dd26a856cdc4cade1bf..13ffbcc9e11848557f454c96de6009673411d058 100644 (file)
--- a/lookup.c
+++ b/lookup.c
 #define OP_PHOTO   4
 #define OP_HGET    5
 
-void find_keys(char *search, uint64_t keyid, bool ishex,
-               bool fingerprint, bool skshash, bool exact, bool verbose,
-               bool mrhkp)
+void find_keys(char *search, uint64_t keyid, uint8_t *fp, size_t fpsize,
+               bool ishex, bool isfp, bool fingerprint, bool skshash,
+               bool exact, bool verbose, bool mrhkp)
 {
        struct openpgp_publickey *publickey = NULL;
        int count = 0;
 
        if (ishex) {
-               count = config.dbbackend->fetch_key(keyid, &publickey, false);
+               count = config.dbbackend->fetch_key_id(keyid, &publickey,
+                               false);
+       } else if (isfp) {
+               count = config.dbbackend->fetch_key_fp(fp, fpsize, &publickey,
+                               false);
        } else {
                count = config.dbbackend->fetch_key_text(search, &publickey);
        }
@@ -86,6 +90,19 @@ void find_keys(char *search, uint64_t keyid, bool ishex,
        }
 }
 
+static uint8_t hex2bin(char c)
+{
+       if (c >= '0' && c <= '9') {
+               return (c - '0');
+       } else if (c >= 'a' && c <= 'f') {
+               return (c - 'a' + 10);
+       } else if (c >= 'A' && c <= 'F') {
+               return (c - 'A' + 10);
+       }
+
+       return 255;
+}
+
 int main(int argc, char *argv[])
 {
        char **params = NULL;
@@ -96,8 +113,10 @@ int main(int argc, char *argv[])
        bool skshash = false;
        bool exact = false;
        bool ishex = false;
+       bool isfp = false;
        bool mrhkp = false;
        uint64_t keyid = 0;
+       uint8_t fp[MAX_FINGERPRINT_LEN];
        char *search = NULL;
        char *end = NULL;
        struct openpgp_publickey *publickey = NULL;
@@ -125,14 +144,12 @@ int main(int argc, char *argv[])
                        params[i+1] = NULL;
                        if (search != NULL && strlen(search) == 42 &&
                                        search[0] == '0' && search[1] == 'x') {
-                               /*
-                                * Fingerprint. Truncate to last 64 bits for
-                                * now.
-                                */
-                               keyid = strtoull(&search[26], &end, 16);
-                               if (end != NULL && *end == 0) {
-                                       ishex = true;
+                               for (i = 0; i < MAX_FINGERPRINT_LEN; i++) {
+                                       fp[i] = (hex2bin(search[2 + i * 2])
+                                                               << 4) +
+                                               hex2bin(search[3 + i * 2]);
                                }
+                               isfp = true;
                        } else if (search != NULL) {
                                keyid = strtoull(search, &end, 16);
                                if (*search != 0 &&
@@ -202,8 +219,11 @@ int main(int argc, char *argv[])
                                result = config.dbbackend->fetch_key_skshash(
                                        &hash, &publickey);
                        } else if (ishex) {
-                               result = config.dbbackend->fetch_key(keyid,
+                               result = config.dbbackend->fetch_key_id(keyid,
                                        &publickey, false);
+                       } else if (isfp) {
+                               result = config.dbbackend->fetch_key_fp(fp,
+                                       MAX_FINGERPRINT_LEN, &publickey, false);
                        } else {
                                result = config.dbbackend->fetch_key_text(
                                        search,
@@ -231,16 +251,25 @@ int main(int argc, char *argv[])
                        }
                        break;
                case OP_INDEX:
-                       find_keys(search, keyid, ishex, fingerprint, skshash,
+                       find_keys(search, keyid, fp, MAX_FINGERPRINT_LEN,
+                                       ishex, isfp, fingerprint, skshash,
                                        exact, false, mrhkp);
                        break;
                case OP_VINDEX:
-                       find_keys(search, keyid, ishex, fingerprint, skshash,
+                       find_keys(search, keyid, fp, MAX_FINGERPRINT_LEN,
+                                       ishex, isfp, fingerprint, skshash,
                                        exact, true, mrhkp);
                        break;
                case OP_PHOTO:
-                       if (config.dbbackend->fetch_key(keyid, &publickey,
-                                       false)) {
+                       if (isfp) {
+                               config.dbbackend->fetch_key_fp(fp,
+                                       MAX_FINGERPRINT_LEN,
+                                       &publickey, false);
+                       } else {
+                               config.dbbackend->fetch_key_id(keyid,
+                                       &publickey, false);
+                       }
+                       if (publickey != NULL) {
                                unsigned char *photo = NULL;
                                size_t         length = 0;
 
diff --git a/onak.c b/onak.c
index 6baea3debb96715cfd16350480eed24dc57cd119..f67c969e513e47382cff59e1e5be867de36ed0bc 100644 (file)
--- a/onak.c
+++ b/onak.c
 #include "photoid.h"
 #include "version.h"
 
-void find_keys(char *search, uint64_t keyid, bool ishex,
-               bool fingerprint, bool skshash, bool exact, bool verbose)
+void find_keys(char *search, uint64_t keyid, uint8_t *fp, bool ishex,
+               bool isfp, bool fingerprint, bool skshash, bool exact,
+               bool verbose)
 {
        struct openpgp_publickey *publickey = NULL;
        int count = 0;
 
        if (ishex) {
-               count = config.dbbackend->fetch_key(keyid, &publickey, false);
+               count = config.dbbackend->fetch_key_id(keyid, &publickey,
+                               false);
+       } else if (isfp) {
+               count = config.dbbackend->fetch_key_fp(fp, MAX_FINGERPRINT_LEN,
+                               &publickey, false);
        } else {
                count = config.dbbackend->fetch_key_text(search, &publickey);
        }
@@ -111,6 +116,19 @@ void dump_func(void *ctx, struct openpgp_publickey *key)
        return;
 }
 
+static uint8_t hex2bin(char c)
+{
+       if (c >= '0' && c <= '9') {
+               return (c - '0');
+       } else if (c >= 'a' && c <= 'f') {
+               return (c - 'a' + 10);
+       } else if (c >= 'A' && c <= 'F') {
+               return (c - 'A' + 10);
+       }
+
+       return 255;
+}
+
 void usage(void) {
        puts("onak " ONAK_VERSION " - an OpenPGP keyserver.\n");
        puts("Usage:\n");
@@ -142,7 +160,10 @@ int main(int argc, char *argv[])
        char                            *search = NULL;
        char                            *end = NULL;
        uint64_t                         keyid = 0;
+       uint8_t                          fp[MAX_FINGERPRINT_LEN];
+       int                              i;
        bool                             ishex = false;
+       bool                             isfp = false;
        bool                             verbose = false;
        bool                             update = false;
        bool                             binary = false;
@@ -298,14 +319,11 @@ int main(int argc, char *argv[])
                search = argv[optind+1];
                if (search != NULL && strlen(search) == 42 &&
                                search[0] == '0' && search[1] == 'x') {
-                       /*
-                        * Fingerprint. Truncate to last 64 bits for
-                        * now.
-                        */
-                       keyid = strtoull(&search[26], &end, 16);
-                       if (end != NULL && *end == 0) {
-                               ishex = true;
+                       for (i = 0; i < MAX_FINGERPRINT_LEN; i++) {
+                               fp[i] = (hex2bin(search[2 + i * 2]) << 4) +
+                                               hex2bin(search[3 + i * 2]);
                        }
+                       isfp = true;
                } else if (search != NULL) {
                        keyid = strtoul(search, &end, 16);
                        if (*search != 0 &&
@@ -316,16 +334,18 @@ int main(int argc, char *argv[])
                }
                config.dbbackend->initdb(false);
                if (!strcmp("index", argv[optind])) {
-                       find_keys(search, keyid, ishex, fingerprint, skshash,
+                       find_keys(search, keyid, fp, ishex, isfp,
+                                       fingerprint, skshash,
                                        false, false);
                } else if (!strcmp("vindex", argv[optind])) {
-                       find_keys(search, keyid, ishex, fingerprint, skshash,
+                       find_keys(search, keyid, fp, ishex, isfp,
+                                       fingerprint, skshash,
                                        false, true);
                } else if (!strcmp("getphoto", argv[optind])) {
                        if (!ishex) {
                                puts("Can't get a key on uid text."
                                        " You must supply a keyid.");
-                       } else if (config.dbbackend->fetch_key(keyid, &keys,
+                       } else if (config.dbbackend->fetch_key_id(keyid, &keys,
                                        false)) {
                                unsigned char *photo = NULL;
                                size_t         length = 0;
@@ -347,11 +367,17 @@ int main(int argc, char *argv[])
                                        config.dbbackend->getfullkeyid(keyid),
                                        false);
                } else if (!strcmp("get", argv[optind])) {
-                       if (!ishex) {
+                       if (!(ishex || isfp)) {
                                puts("Can't get a key on uid text."
-                                       " You must supply a keyid.");
-                       } else if (config.dbbackend->fetch_key(keyid, &keys,
-                                       false)) {
+                                       " You must supply a keyid / "
+                                       "fingerprint.");
+                       } else if ((isfp &&
+                                       config.dbbackend->fetch_key_fp(fp,
+                                               MAX_FINGERPRINT_LEN,
+                                               &keys, false)) ||
+                                       (ishex &&
+                                       config.dbbackend->fetch_key_id(keyid,
+                                               &keys, false))) {
                                logthing(LOGTHING_INFO, "Got key.");
                                flatten_publickey(keys,
                                                &packets,