From c04c1c60469823c01268187ec49102d1ff540806 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Mon, 4 Nov 2013 16:56:31 -0800 Subject: [PATCH] Extend database backends to support fetching by key fingerprint 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. --- gpgwww.c | 4 +- keyd.c | 59 +++++++++++++++++++++++++-- keyd.h | 9 +++-- keydb.c | 35 ++++++++++++++-- keydb.h | 18 ++++++++- keydb_db4.c | 15 ++++--- keydb_dynamic.c | 40 +++++++++++++----- keydb_file.c | 9 +++-- keydb_fs.c | 11 +++-- keydb_hkp.c | 105 ++++++++++++++++++++++++------------------------ keydb_keyd.c | 64 ++++++++++++++++++++++++++--- keydb_pg.c | 9 +++-- keydctl.c | 7 +++- keystructs.h | 3 ++ lookup.c | 61 ++++++++++++++++++++-------- onak.c | 60 +++++++++++++++++++-------- 16 files changed, 376 insertions(+), 133 deletions(-) diff --git a/gpgwww.c b/gpgwww.c index 84f00e4..07b448e 100644 --- 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 21d3bdb..a89f0e1 100644 --- 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 91959c8..b33cab9 100644 --- a/keyd.h +++ b/keyd.h @@ -34,16 +34,17 @@ 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 c257eb5..ac70640 100644 --- 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 20ab62f..6ad9a59 100644 --- 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); /** diff --git a/keydb_db4.c b/keydb_db4.c index f4fffa5..dae8a2a 100644 --- a/keydb_db4.c +++ b/keydb_db4.c @@ -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, diff --git a/keydb_dynamic.c b/keydb_dynamic.c index 6537386..536909a 100644 --- a/keydb_dynamic.c +++ b/keydb_dynamic.c @@ -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, diff --git a/keydb_file.c b/keydb_file.c index 4321a68..eeae01f 100644 --- a/keydb_file.c +++ b/keydb_file.c @@ -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, diff --git a/keydb_fs.c b/keydb_fs.c index b7117be..b944732 100644 --- a/keydb_fs.c +++ b/keydb_fs.c @@ -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, diff --git a/keydb_hkp.c b/keydb_hkp.c index ac1edac..3fa1593 100644 --- a/keydb_hkp.c +++ b/keydb_hkp.c @@ -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, diff --git a/keydb_keyd.c b/keydb_keyd.c index 4820ee3..7995e38 100644 --- a/keydb_keyd.c +++ b/keydb_keyd.c @@ -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, diff --git a/keydb_pg.c b/keydb_pg.c index 480f1f1..04c760d 100644 --- a/keydb_pg.c +++ b/keydb_pg.c @@ -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, diff --git a/keydctl.c b/keydctl.c index 5a2ac21..4ffecae 100644 --- 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", diff --git a/keystructs.h b/keystructs.h index fcfed12..13f9160 100644 --- a/keystructs.h +++ b/keystructs.h @@ -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. * diff --git a/lookup.c b/lookup.c index 9af11d9..13ffbcc 100644 --- a/lookup.c +++ b/lookup.c @@ -46,15 +46,19 @@ #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 6baea3d..f67c969 100644 --- a/onak.c +++ b/onak.c @@ -44,14 +44,19 @@ #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, -- 2.39.5