From 46ebdd20784c242ca96b949813d90167349177d9 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Tue, 12 Nov 2013 19:10:49 -0800 Subject: [PATCH] Use fingerprints as key index in DB4 backend Up until now the DB4 backend has used the 64 bit key ID as the index into the key database. The fingerprint has always been a better idea and it's easy to create a v3 key that causes a collision, so switch to using the fingerprint in the DB4 backend. These changes to not require an upgrade to an existing DB4 setup; keys will get transitioned to the new storage method as they are updated in the keyserver. --- keyarray.c | 39 ++-- keyarray.h | 18 +- keydb_db4.c | 599 ++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 524 insertions(+), 132 deletions(-) diff --git a/keyarray.c b/keyarray.c index cb846de..8bade8c 100644 --- a/keyarray.c +++ b/keyarray.c @@ -24,8 +24,21 @@ #include #include "keyarray.h" +#include "keystructs.h" -bool array_find(struct keyarray *array, uint64_t key) +int fingerprint_cmp(struct openpgp_fingerprint *a, + struct openpgp_fingerprint *b) +{ + if (a->length < b->length) { + return -1; + } else if (a->length > b->length) { + return 1; + } else { + return memcmp(a->fp, b->fp, a->length); + } +} + +bool array_find(struct keyarray *array, struct openpgp_fingerprint *fp) { bool found; int top = 0; @@ -38,19 +51,19 @@ bool array_find(struct keyarray *array, uint64_t key) top = array->count - 1; while ((top - bottom) > 1) { curpos = (top + bottom) / 2; - if (key > array->keys[curpos]) { + if (fingerprint_cmp(fp, &array->keys[curpos]) > 0) { bottom = curpos; } else { top = curpos; } } - found = (array->keys[top] == key); + found = (fingerprint_cmp(fp, &array->keys[top]) == 0); } return found; } -bool array_add(struct keyarray *array, uint64_t key) +bool array_add(struct keyarray *array, struct openpgp_fingerprint *fp) { bool found; int top = 0; @@ -63,15 +76,15 @@ bool array_add(struct keyarray *array, uint64_t key) top = array->count - 1; while ((top - bottom) > 1) { curpos = (top + bottom) / 2; - if (key > array->keys[curpos]) { + if (fingerprint_cmp(fp, &array->keys[curpos]) > 0) { bottom = curpos; } else { top = curpos; } } - found = (array->keys[top] == key); + found = (fingerprint_cmp(fp, &array->keys[top]) == 0); - if (key > array->keys[top]) { + if (fingerprint_cmp(fp, &array->keys[top]) > 0) { curpos = top + 1; } else { curpos = top; @@ -80,23 +93,25 @@ bool array_add(struct keyarray *array, uint64_t key) if (!found) { if (array->size == 0) { - array->keys = malloc(16 * sizeof(uint64_t)); + array->keys = malloc(16 * + sizeof(struct openpgp_fingerprint)); array->size = 16; array->count = 1; - array->keys[0] = key; + array->keys[0] = *fp; } else { if (array->count >= array->size) { array->size *= 2; array->keys = realloc(array->keys, - array->size * sizeof(uint64_t)); + array->size * + sizeof(struct openpgp_fingerprint)); } if (curpos < array->count) { memmove(&array->keys[curpos+1], &array->keys[curpos], - sizeof(uint64_t) * + sizeof(struct openpgp_fingerprint) * (array->count - curpos)); } - array->keys[curpos] = key; + array->keys[curpos] = *fp; array->count++; } } diff --git a/keyarray.h b/keyarray.h index 5be7b78..a3e288a 100644 --- a/keyarray.h +++ b/keyarray.h @@ -24,16 +24,18 @@ #include #include +#include "keystructs.h" + /** - * @brief A sorted array of keyids + * @brief A sorted array of fingerprints * - * Holds a sorted list of keyids, with room for growth - has details of both - * the total size of the array as well as the current number of elements. + * Holds a sorted list of fingerprints, with room for growth - has details of + * both the total size of the array as well as the current number of elements. */ struct keyarray { - /** The array of key ids */ - uint64_t *keys; - /** Number of key ids in the array */ + /** The array of key fingerprints */ + struct openpgp_fingerprint *keys; + /** Number of fingerprints in the array */ size_t count; /** Total size of the array */ size_t size; @@ -44,7 +46,7 @@ struct keyarray { * @param array Pointer to the key array * @param key The keyid to look for */ -bool array_find(struct keyarray *array, uint64_t key); +bool array_find(struct keyarray *array, struct openpgp_fingerprint *fp); /** * @brief Free a key array @@ -61,6 +63,6 @@ void array_free(struct keyarray *array); * Returns true if the key was added, false if it was found to be already * present. */ -bool array_add(struct keyarray *array, uint64_t key); +bool array_add(struct keyarray *array, struct openpgp_fingerprint *fp); #endif /* __KEYARRAY_H__ */ diff --git a/keydb_db4.c b/keydb_db4.c index 2ffb256..288e467 100644 --- a/keydb_db4.c +++ b/keydb_db4.c @@ -50,12 +50,13 @@ struct onak_db4_dbctx { DB **dbconns; /* Connections to the key data databases */ DB *worddb; /* Connection to the word lookup database */ DB *id32db; /* Connection to the 32 bit ID lookup database */ + DB *id64db; /* Connection to the 64 bit ID lookup database */ DB *skshashdb; /* Connection to the SKS hash database */ DB *subkeydb; /* Connection to the subkey ID lookup database */ DB_TXN *txn; /* Our current transaction ID */ }; -DB *keydb(struct onak_db4_dbctx *privctx, uint64_t keyid) +DB *keydb_id(struct onak_db4_dbctx *privctx, uint64_t keyid) { uint64_t keytrun; @@ -64,6 +65,18 @@ DB *keydb(struct onak_db4_dbctx *privctx, uint64_t keyid) return(privctx->dbconns[keytrun % privctx->numdbs]); } +DB *keydb_fp(struct onak_db4_dbctx *privctx, struct openpgp_fingerprint *fp) +{ + uint64_t keytrun; + + keytrun = (fp->fp[4] << 24) | + (fp->fp[5] << 16) | + (fp->fp[6] << 8) | + (fp->fp[7]); + + return(privctx->dbconns[keytrun % privctx->numdbs]); +} + /** * db4_errfunc - Direct DB errors to logfile * @@ -220,6 +233,18 @@ static int db4_upgradedb(struct onak_db4_dbctx *privctx) db_strerror(ret)); } + ret = db_create(&curdb, NULL, 0); + if (ret == 0) { + snprintf(buf, sizeof(buf) - 1, "%s/id64db", config.db_dir); + logthing(LOGTHING_DEBUG, "Upgrading %s", buf); + curdb->upgrade(curdb, buf, 0); + curdb->close(curdb, 0); + } else { + logthing(LOGTHING_ERROR, "Error upgrading DB %s : %s", + buf, + db_strerror(ret)); + } + ret = db_create(&curdb, NULL, 0); if (ret == 0) { snprintf(buf, sizeof(buf) - 1, "%s/skshashdb", config.db_dir); @@ -265,6 +290,7 @@ static uint64_t db4_getfullkeyid(struct onak_dbctx *dbctx, uint64_t keyid) DBC *cursor = NULL; uint32_t shortkeyid = 0; int ret = 0; + int i; if (keyid < 0x100000000LL) { ret = privctx->id32db->cursor(privctx->id32db, @@ -290,7 +316,15 @@ static uint64_t db4_getfullkeyid(struct onak_dbctx *dbctx, uint64_t keyid) DB_SET); if (ret == 0) { - keyid = *(uint64_t *) data.data; + if (data.size == 8) { + keyid = * (uint64_t *) data.data; + } else { + keyid = 0; + for (i = 12; i < 20; i++) { + keyid <<= 8; + keyid |= ((uint8_t *) data.data)[i]; + } + } if (data.data != NULL) { free(data.data); @@ -305,6 +339,100 @@ static uint64_t db4_getfullkeyid(struct onak_dbctx *dbctx, uint64_t keyid) return keyid; } +/** + * fetch_key_fp - Given a fingerprint fetch the key from storage. + */ +static int db4_fetch_key_fp(struct onak_dbctx *dbctx, + struct openpgp_fingerprint *fingerprint, + struct openpgp_publickey **publickey, + bool intrans) +{ + struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv; + struct openpgp_packet_list *packets = NULL; + DBT key, data; + int ret = 0; + int numkeys = 0; + struct buffer_ctx fetchbuf; + struct openpgp_fingerprint subfp; + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + data.size = 0; + data.data = NULL; + + key.size = fingerprint->length; + key.data = fingerprint->fp; + + if (!intrans) { + db4_starttrans(dbctx); + } + + ret = keydb_fp(privctx, fingerprint)->get(keydb_fp(privctx, + fingerprint), + privctx->txn, + &key, + &data, + 0); /* flags*/ + + if (ret == DB_NOTFOUND) { + /* 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)); + data.data = subfp.fp; + data.ulen = MAX_FINGERPRINT_LEN; + data.flags = DB_DBT_USERMEM; + key.data = fingerprint->fp; + key.size = fingerprint->length; + + ret = privctx->subkeydb->get(privctx->subkeydb, + privctx->txn, + &key, + &data, + 0); /* flags*/ + + if (ret == 0) { + /* We got a subkey match; retrieve the actual key */ + memset(&key, 0, sizeof(key)); + key.size = subfp.length = data.size; + key.data = subfp.fp; + + memset(&data, 0, sizeof(data)); + data.size = 0; + data.data = NULL; + + ret = keydb_fp(privctx, &subfp)->get( + keydb_fp(privctx, &subfp), + privctx->txn, + &key, + &data, + 0); /* flags*/ + } + } + + if (ret == 0) { + fetchbuf.buffer = data.data; + fetchbuf.offset = 0; + fetchbuf.size = data.size; + read_openpgp_stream(buffer_fetchchar, &fetchbuf, + &packets, 0); + parse_keys(packets, publickey); + free_packet_list(packets); + packets = NULL; + numkeys++; + } else if (ret != DB_NOTFOUND) { + logthing(LOGTHING_ERROR, + "Problem retrieving key: %s", + db_strerror(ret)); + } + + if (!intrans) { + db4_endtrans(dbctx); + } + + return (numkeys); +} + /** * fetch_key_id - Given a keyid fetch the key from storage. * @keyid: The keyid to fetch. @@ -327,6 +455,7 @@ static int db4_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, int ret = 0; int numkeys = 0; struct buffer_ctx fetchbuf; + struct openpgp_fingerprint fingerprint; if (keyid < 0x100000000LL) { keyid = db4_getfullkeyid(dbctx, keyid); @@ -345,39 +474,43 @@ static int db4_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, db4_starttrans(dbctx); } - ret = keydb(privctx, keyid)->get(keydb(privctx, keyid), + /* + * First we try a legacy stored key where we used the 64 bit key ID + * as the DB key. + */ + ret = keydb_id(privctx, keyid)->get(keydb_id(privctx, keyid), privctx->txn, &key, &data, 0); /* flags*/ if (ret == DB_NOTFOUND) { - /* If we didn't find the key ID see if it's a subkey ID */ + /* If we didn't find the key ID try the 64 bit map DB */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); - data.size = 0; - data.data = NULL; + data.ulen = MAX_FINGERPRINT_LEN; + data.data = fingerprint.fp; + data.flags = DB_DBT_USERMEM; key.size = sizeof(keyid); key.data = &keyid; - ret = privctx->subkeydb->get(privctx->subkeydb, + ret = privctx->id64db->get(privctx->id64db, privctx->txn, &key, &data, 0); /* flags*/ if (ret == 0) { - /* We got a subkey match; retrieve the actual key */ - keyid = *(uint64_t *) data.data; + /* We got a match; retrieve the actual key */ + fingerprint.length = data.size; memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); - data.size = 0; - data.data = NULL; - key.size = sizeof(keyid); - key.data = &keyid; + key.size = fingerprint.length; + key.data = fingerprint.fp; - ret = keydb(privctx, keyid)->get(keydb(privctx, keyid), + ret = keydb_fp(privctx, &fingerprint)->get( + keydb_fp(privctx, &fingerprint), privctx->txn, &key, &data, @@ -408,6 +541,7 @@ static int db4_fetch_key_id(struct onak_dbctx *dbctx, uint64_t keyid, return (numkeys); } + int worddb_cmp(const void *d1, const void *d2) { return memcmp(d1, d2, 12); @@ -437,6 +571,7 @@ static int db4_fetch_key_text(struct onak_dbctx *dbctx, const char *search, struct keyarray keylist = { NULL, 0, 0 }; struct keyarray newkeylist = { NULL, 0, 0 }; int firstpass = 1; + struct openpgp_fingerprint fingerprint; numkeys = 0; searchtext = strdup(search); @@ -467,11 +602,17 @@ static int db4_fetch_key_text(struct onak_dbctx *dbctx, const char *search, while (ret == 0 && strncmp(key.data, curword->object, key.size) == 0 && ((char *) curword->object)[key.size] == 0) { - keyid = 0; - for (i = 4; i < 12; i++) { - keyid <<= 8; - keyid += ((unsigned char *) - data.data)[i]; + if (data.size == 12) { + /* Old style creation + key id */ + fingerprint.length = 8; + for (i = 4; i < 12; i++) { + fingerprint.fp[i - 4] = + ((unsigned char *) + data.data)[i]; + } + } else { + fingerprint.length = data.size; + memcpy(fingerprint.fp, data.data, data.size); } /* @@ -479,8 +620,8 @@ static int db4_fetch_key_text(struct onak_dbctx *dbctx, const char *search, * our first pass (ie we have no existing key list), * or the key contained a previous word. */ - if (firstpass || array_find(&keylist, keyid)) { - array_add(&newkeylist, keyid); + if (firstpass || array_find(&keylist, &fingerprint)) { + array_add(&newkeylist, &fingerprint); } free(data.data); @@ -492,7 +633,9 @@ static int db4_fetch_key_text(struct onak_dbctx *dbctx, const char *search, DB_NEXT); } array_free(&keylist); - keylist = newkeylist; + keylist.keys = newkeylist.keys; + keylist.count = newkeylist.count; + keylist.size = newkeylist.size; newkeylist.keys = NULL; newkeylist.count = newkeylist.size = 0; if (data.data != NULL) { @@ -513,9 +656,20 @@ static int db4_fetch_key_text(struct onak_dbctx *dbctx, const char *search, db4_starttrans(dbctx); for (i = 0; i < keylist.count; i++) { - numkeys += db4_fetch_key_id(dbctx, keylist.keys[i], - publickey, - true); + if (keylist.keys[i].length == 8) { + keyid = 0; + for (int j = 0; j < 8; j++) { + keyid <<= 8; + keyid |= keylist.keys[i].fp[j]; + } + numkeys += db4_fetch_key_id(dbctx, keyid, + publickey, + true); + } else { + numkeys += db4_fetch_key_fp(dbctx, &keylist.keys[i], + publickey, + true); + } } array_free(&keylist); free(searchtext); @@ -534,7 +688,9 @@ static int db4_fetch_key_skshash(struct onak_dbctx *dbctx, DBT key, data; DBC *cursor = NULL; uint64_t keyid = 0; - int ret = 0; + int ret; + int count = 0; + struct openpgp_fingerprint fingerprint; ret = privctx->skshashdb->cursor(privctx->skshashdb, privctx->txn, @@ -557,7 +713,17 @@ static int db4_fetch_key_skshash(struct onak_dbctx *dbctx, DB_SET); if (ret == 0) { - keyid = *(uint64_t *) data.data; + if (data.size == 8) { + /* Legacy key ID record */ + keyid = *(uint64_t *) data.data; + count = db4_fetch_key_id(dbctx, keyid, publickey, + false); + } else { + fingerprint.length = data.size; + memcpy(fingerprint.fp, data.data, data.size); + count = db4_fetch_key_fp(dbctx, &fingerprint, + publickey, false); + } if (data.data != NULL) { free(data.data); @@ -568,7 +734,7 @@ static int db4_fetch_key_skshash(struct onak_dbctx *dbctx, cursor->c_close(cursor); cursor = NULL; - return db4_fetch_key_id(dbctx, keyid, publickey, false); + return count; } /** @@ -586,7 +752,9 @@ static int db4_delete_key(struct onak_dbctx *dbctx, struct openpgp_publickey *publickey = NULL; DBT key, data; DBC *cursor = NULL; - uint32_t shortkeyid = 0; + DBC *cursor64 = NULL; + uint32_t shortkeyid = 0; + uint64_t subkeyid = 0; struct openpgp_fingerprint *subkeyids = NULL; int ret = 0; int i; @@ -597,13 +765,18 @@ static int db4_delete_key(struct onak_dbctx *dbctx, struct ll *curword = NULL; bool deadlock = false; struct skshash hash; - uint64_t subkeyid; + struct openpgp_fingerprint fingerprint; if (!intrans) { db4_starttrans(dbctx); } - db4_fetch_key_id(dbctx, keyid, &publickey, true); + if (db4_fetch_key_id(dbctx, keyid, &publickey, true) == 0) { + db4_endtrans(dbctx); + return 1; + } + + get_fingerprint(publickey->publickey, &fingerprint); /* * Walk through the uids removing the words from the worddb. @@ -631,8 +804,8 @@ static int db4_delete_key(struct onak_dbctx *dbctx, data.size = sizeof(worddb_data); /* - * Our data is the key creation time followed by the - * key id. + * Old format word db data was the key creation time + * followed by the 64 bit key id. */ worddb_data[ 0] = publickey->publickey->data[1]; worddb_data[ 1] = publickey->publickey->data[2]; @@ -656,33 +829,13 @@ static int db4_delete_key(struct onak_dbctx *dbctx, ret = cursor->c_del(cursor, 0); } - if (ret != 0) { - logthing(LOGTHING_ERROR, - "Problem deleting word: %s " - "(0x%016" PRIX64 ")", - db_strerror(ret), - keyid); - if (ret == DB_LOCK_DEADLOCK) { - deadlock = true; - } - } - } - cursor->c_close(cursor); - cursor = NULL; - - ret = privctx->skshashdb->cursor(privctx->skshashdb, - privctx->txn, - &cursor, - 0); /* flags */ - if (ret == 0) { - get_skshash(publickey, &hash); - + /* New style just uses the fingerprint as the data */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); - key.data = hash.hash; - key.size = sizeof(hash.hash); - data.data = &keyid; - data.size = sizeof(keyid); + key.data = curword->object; + key.size = strlen(key.data); + data.data = fingerprint.fp; + data.size = fingerprint.length; ret = cursor->c_get(cursor, &key, @@ -693,9 +846,9 @@ static int db4_delete_key(struct onak_dbctx *dbctx, ret = cursor->c_del(cursor, 0); } - if (ret != 0) { + if (ret != 0 && ret != DB_NOTFOUND) { logthing(LOGTHING_ERROR, - "Problem deleting skshash: %s " + "Problem deleting word: %s " "(0x%016" PRIX64 ")", db_strerror(ret), keyid); @@ -703,10 +856,9 @@ static int db4_delete_key(struct onak_dbctx *dbctx, deadlock = true; } } - - cursor->c_close(cursor); - cursor = NULL; } + cursor->c_close(cursor); + cursor = NULL; /* * Free our UID and word lists. @@ -718,8 +870,6 @@ static int db4_delete_key(struct onak_dbctx *dbctx, } free(uids); uids = NULL; - free_publickey(publickey); - publickey = NULL; } if (!deadlock) { @@ -727,9 +877,14 @@ static int db4_delete_key(struct onak_dbctx *dbctx, privctx->txn, &cursor, 0); /* flags */ + privctx->id64db->cursor(privctx->id64db, + privctx->txn, + &cursor64, + 0); /* flags */ shortkeyid = keyid & 0xFFFFFFFF; + /* Old style mapping to 64 bit key id */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); key.data = &shortkeyid; @@ -746,7 +901,24 @@ static int db4_delete_key(struct onak_dbctx *dbctx, ret = cursor->c_del(cursor, 0); } - if (ret != 0) { + /* New style mapping to fingerprint */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = &shortkeyid; + key.size = sizeof(shortkeyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; + + ret = cursor->c_get(cursor, + &key, + &data, + DB_GET_BOTH); + + if (ret == 0) { + ret = cursor->c_del(cursor, 0); + } + + if (ret != 0 && ret != DB_NOTFOUND) { logthing(LOGTHING_ERROR, "Problem deleting short keyid: %s " "(0x%016" PRIX64 ")", @@ -757,16 +929,44 @@ static int db4_delete_key(struct onak_dbctx *dbctx, } } + /* 64 bit key mapping to fingerprint */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = &keyid; + key.size = sizeof(keyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; + + ret = cursor64->c_get(cursor64, + &key, + &data, + DB_GET_BOTH); + + if (ret == 0) { + ret = cursor64->c_del(cursor64, 0); + } + + if (ret != 0 && ret != DB_NOTFOUND) { + logthing(LOGTHING_ERROR, + "Problem deleting keyid: %s " + "(0x%016" PRIX64 ")", + db_strerror(ret), + keyid); + if (ret == DB_LOCK_DEADLOCK) { + deadlock = true; + } + } + subkeyids = keysubkeys(publickey); i = 0; while (subkeyids != NULL && subkeyids[i].length != 0) { subkeyid = fingerprint2keyid(&subkeyids[i]); memset(&key, 0, sizeof(key)); - key.data = &subkeyid; - key.size = sizeof(subkeyid); + key.data = subkeyids[i].fp; + key.size = subkeyids[i].length; privctx->subkeydb->del(privctx->subkeydb, privctx->txn, &key, 0); - if (ret != 0) { + if (ret != 0 && ret != DB_NOTFOUND) { logthing(LOGTHING_ERROR, "Problem deleting subkey id: %s " "(0x%016" PRIX64 ")", @@ -779,6 +979,7 @@ static int db4_delete_key(struct onak_dbctx *dbctx, shortkeyid = subkeyid & 0xFFFFFFFF; + /* Remove 32 bit keyid -> 64 bit keyid mapping */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); key.data = &shortkeyid; @@ -795,7 +996,24 @@ static int db4_delete_key(struct onak_dbctx *dbctx, ret = cursor->c_del(cursor, 0); } - if (ret != 0) { + /* Remove 32 bit keyid -> fingerprint mapping */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = &shortkeyid; + key.size = sizeof(shortkeyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; + + ret = cursor->c_get(cursor, + &key, + &data, + DB_GET_BOTH); + + if (ret == 0) { + ret = cursor->c_del(cursor, 0); + } + + if (ret != 0 && ret != DB_NOTFOUND) { logthing(LOGTHING_ERROR, "Problem deleting short keyid: %s " "(0x%016" PRIX64 ")", @@ -805,21 +1023,111 @@ static int db4_delete_key(struct onak_dbctx *dbctx, deadlock = true; } } + + /* Remove 64 bit keyid -> fingerprint mapping */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = &subkeyid; + key.size = sizeof(subkeyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; + + ret = cursor->c_get(cursor, + &key, + &data, + DB_GET_BOTH); + + if (ret == 0) { + ret = cursor->c_del(cursor, 0); + } + + if (ret != 0 && ret != DB_NOTFOUND) { + logthing(LOGTHING_ERROR, + "Problem deleting keyid: %s " + "(0x%016" PRIX64 ")", + db_strerror(ret), + keyid); + if (ret == DB_LOCK_DEADLOCK) { + deadlock = true; + } + } i++; } if (subkeyids != NULL) { free(subkeyids); subkeyids = NULL; } + cursor64->c_close(cursor64); + cursor64 = NULL; cursor->c_close(cursor); cursor = NULL; } + if (!deadlock) { + ret = privctx->skshashdb->cursor(privctx->skshashdb, + privctx->txn, + &cursor, + 0); /* flags */ + if (ret == 0) { + get_skshash(publickey, &hash); + + /* First delete old style keyid mapping */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = hash.hash; + key.size = sizeof(hash.hash); + data.data = &keyid; + data.size = sizeof(keyid); + + ret = cursor->c_get(cursor, + &key, + &data, + DB_GET_BOTH); + + if (ret == 0) { + ret = cursor->c_del(cursor, 0); + } + + /* Then delete new style fingerprint mapping */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = hash.hash; + key.size = sizeof(hash.hash); + data.data = fingerprint.fp; + data.size = fingerprint.length; + + ret = cursor->c_get(cursor, + &key, + &data, + DB_GET_BOTH); + + if (ret == 0) { + ret = cursor->c_del(cursor, 0); + } + + if (ret != 0 && ret != DB_NOTFOUND) { + logthing(LOGTHING_ERROR, + "Problem deleting skshash: %s " + "(0x%016" PRIX64 ")", + db_strerror(ret), + keyid); + if (ret == DB_LOCK_DEADLOCK) { + deadlock = true; + } + } + + cursor->c_close(cursor); + cursor = NULL; + } + } + free_publickey(publickey); + publickey = NULL; + if (!deadlock) { key.data = &keyid; key.size = sizeof(keyid); - keydb(privctx, keyid)->del(keydb(privctx, keyid), + keydb_id(privctx, keyid)->del(keydb_id(privctx, keyid), privctx->txn, &key, 0); /* flags */ @@ -862,18 +1170,22 @@ static int db4_store_key(struct onak_dbctx *dbctx, struct openpgp_fingerprint *subkeyids = NULL; char **uids = NULL; char *primary = NULL; - unsigned char worddb_data[12]; struct ll *wordlist = NULL; struct ll *curword = NULL; bool deadlock = false; struct skshash hash; - uint64_t subkeyid; + struct openpgp_fingerprint fingerprint; if (get_keyid(publickey, &keyid) != ONAK_E_OK) { logthing(LOGTHING_ERROR, "Couldn't find key ID for key."); return 0; } + if (get_fingerprint(publickey->publickey, &fingerprint) != ONAK_E_OK) { + logthing(LOGTHING_ERROR, "Couldn't find fingerprint for key."); + return 0; + } + if (!intrans) { db4_starttrans(dbctx); } @@ -911,12 +1223,13 @@ static int db4_store_key(struct onak_dbctx *dbctx, */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); - key.data = &keyid; - key.size = sizeof(keyid); + key.data = fingerprint.fp; + key.size = fingerprint.length; data.size = storebuf.offset; data.data = storebuf.buffer; - ret = keydb(privctx, keyid)->put(keydb(privctx, keyid), + ret = keydb_fp(privctx, &fingerprint)->put( + keydb_fp(privctx, &fingerprint), privctx->txn, &key, &data, @@ -956,25 +1269,9 @@ static int db4_store_key(struct onak_dbctx *dbctx, memset(&data, 0, sizeof(data)); key.data = curword->object; key.size = strlen(key.data); - data.data = worddb_data; - data.size = sizeof(worddb_data); + data.data = fingerprint.fp; + data.size = fingerprint.length; - /* - * Our data is the key creation time followed by the - * key id. - */ - worddb_data[ 0] = publickey->publickey->data[1]; - worddb_data[ 1] = publickey->publickey->data[2]; - worddb_data[ 2] = publickey->publickey->data[3]; - worddb_data[ 3] = publickey->publickey->data[4]; - worddb_data[ 4] = (keyid >> 56) & 0xFF; - worddb_data[ 5] = (keyid >> 48) & 0xFF; - worddb_data[ 6] = (keyid >> 40) & 0xFF; - worddb_data[ 7] = (keyid >> 32) & 0xFF; - worddb_data[ 8] = (keyid >> 24) & 0xFF; - worddb_data[ 9] = (keyid >> 16) & 0xFF; - worddb_data[10] = (keyid >> 8) & 0xFF; - worddb_data[11] = keyid & 0xFF; ret = privctx->worddb->put(privctx->worddb, privctx->txn, &key, @@ -1003,8 +1300,8 @@ static int db4_store_key(struct onak_dbctx *dbctx, } /* - * Write the truncated 32 bit keyid so we can lookup the full id for - * queries. + * Write the truncated 32 bit keyid so we can lookup the fingerprint + * for queries. */ if (!deadlock) { shortkeyid = keyid & 0xFFFFFFFF; @@ -1013,8 +1310,8 @@ static int db4_store_key(struct onak_dbctx *dbctx, memset(&data, 0, sizeof(data)); key.data = &shortkeyid; key.size = sizeof(shortkeyid); - data.data = &keyid; - data.size = sizeof(keyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; ret = privctx->id32db->put(privctx->id32db, privctx->txn, @@ -1031,18 +1328,44 @@ static int db4_store_key(struct onak_dbctx *dbctx, } } + /* + * Write the 64 bit keyid so we can lookup the fingerprint for + * queries. + */ + if (!deadlock) { + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = &keyid; + key.size = sizeof(keyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; + + ret = privctx->id64db->put(privctx->id64db, + privctx->txn, + &key, + &data, + 0); + if (ret != 0) { + logthing(LOGTHING_ERROR, + "Problem storing keyid: %s", + db_strerror(ret)); + if (ret == DB_LOCK_DEADLOCK) { + deadlock = true; + } + } + } + if (!deadlock) { subkeyids = keysubkeys(publickey); i = 0; while (subkeyids != NULL && subkeyids[i].length != 0) { - subkeyid = fingerprint2keyid(&subkeyids[i]); - /* Store the subkey ID -> main key ID mapping */ + /* Store the subkey ID -> main key fp mapping */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); - key.data = &subkeyid; - key.size = sizeof(subkeyid); - data.data = &keyid; - data.size = sizeof(keyid); + key.data = subkeyids[i].fp; + key.size = subkeyids[i].length; + data.data = fingerprint.fp; + data.size = fingerprint.length; ret = privctx->subkeydb->put(privctx->subkeydb, privctx->txn, @@ -1058,15 +1381,39 @@ static int db4_store_key(struct onak_dbctx *dbctx, } } - /* Store the short subkey ID -> main key ID mapping */ - shortkeyid = subkeyid & 0xFFFFFFFF; + /* Store the 64 bit subkey ID -> main key fp mapping */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + keyid = fingerprint2keyid(&subkeyids[i]); + key.data = &keyid; + key.size = sizeof(keyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; + + ret = privctx->id64db->put(privctx->id64db, + privctx->txn, + &key, + &data, + 0); + if (ret != 0) { + logthing(LOGTHING_ERROR, + "Problem storing keyid: %s", + db_strerror(ret)); + if (ret == DB_LOCK_DEADLOCK) { + deadlock = true; + } + } + + /* Store the short subkey ID -> main key fp mapping */ + shortkeyid = keyid & 0xFFFFFFFF; memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); key.data = &shortkeyid; key.size = sizeof(shortkeyid); - data.data = &keyid; - data.size = sizeof(keyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; ret = privctx->id32db->put(privctx->id32db, privctx->txn, @@ -1095,8 +1442,8 @@ static int db4_store_key(struct onak_dbctx *dbctx, memset(&data, 0, sizeof(data)); key.data = hash.hash; key.size = sizeof(hash.hash); - data.data = &keyid; - data.size = sizeof(keyid); + data.data = fingerprint.fp; + data.size = fingerprint.length; ret = privctx->skshashdb->put(privctx->skshashdb, privctx->txn, @@ -1198,7 +1545,6 @@ static int db4_iterate_keys(struct onak_dbctx *dbctx, #define NEED_GETKEYSIGS 1 #define NEED_KEYID2UID 1 #define NEED_UPDATEKEYS 1 -#define NEED_GET_FP 1 #include "keydb.c" /** @@ -1222,6 +1568,10 @@ static void db4_cleanupdb(struct onak_dbctx *dbctx) privctx->skshashdb->close(privctx->skshashdb, 0); privctx->skshashdb = NULL; } + if (privctx->id64db != NULL) { + privctx->id64db->close(privctx->id64db, 0); + privctx->id64db = NULL; + } if (privctx->id32db != NULL) { privctx->id32db->close(privctx->id32db, 0); privctx->id32db = NULL; @@ -1490,6 +1840,31 @@ struct onak_dbctx *keydb_db4_init(bool readonly) } } + if (ret == 0) { + ret = db_create(&privctx->id64db, privctx->dbenv, 0); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, "db_create: %s", + db_strerror(ret)); + } + } + + if (ret == 0) { + ret = privctx->id64db->set_flags(privctx->id64db, DB_DUP); + } + + if (ret == 0) { + ret = privctx->id64db->open(privctx->id64db, privctx->txn, + "id64db", "id64db", DB_HASH, + flags, + 0664); + if (ret != 0) { + logthing(LOGTHING_CRITICAL, + "Error opening id64 database: %s (%s)", + "id64db", + db_strerror(ret)); + } + } + if (ret == 0) { ret = db_create(&privctx->skshashdb, privctx->dbenv, 0); if (ret != 0) { @@ -1549,7 +1924,7 @@ struct onak_dbctx *keydb_db4_init(bool readonly) dbctx->starttrans = db4_starttrans; dbctx->endtrans = db4_endtrans; dbctx->fetch_key_id = db4_fetch_key_id; - dbctx->fetch_key_fp = generic_fetch_key_fp; + dbctx->fetch_key_fp = db4_fetch_key_fp; dbctx->fetch_key_text = db4_fetch_key_text; dbctx->fetch_key_skshash = db4_fetch_key_skshash; dbctx->store_key = db4_store_key; -- 2.39.2