From 9ce8c6ced68d45b462abb4c6531b6476f4d1e681 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Wed, 21 Aug 2019 18:56:57 +0100 Subject: [PATCH] Add option to only accept updates for existing keys It's plausible in a curated keyring scenario where a keyserver should accept updates to existing keys (new signatures, updated expiries, new subkeys) but no entirely new keys. Add a configuration file option which enforces this behaviour. --- cgi/add.c | 4 +++- cleankey.h | 1 + keydb.c | 17 ++++++++++++----- keydb.h | 2 ++ keydb_dynamic.c | 3 ++- keydb_keyring.c | 1 + keydb_stacked.c | 4 +++- onak-conf.c | 9 +++++++++ onak.c | 2 ++ onak.ini.in | 4 ++++ t/all-036-update-only.t | 17 +++++++++++++++++ 11 files changed, 56 insertions(+), 8 deletions(-) create mode 100755 t/all-036-update-only.t diff --git a/cgi/add.c b/cgi/add.c index 02eb3eb..e17d3d9 100644 --- a/cgi/add.c +++ b/cgi/add.c @@ -93,7 +93,9 @@ int main(int argc, char *argv[]) count); count = dbctx->update_keys(dbctx, &keys, - &config.blacklist, true); + &config.blacklist, + config.clean_policies & ONAK_CLEAN_UPDATE_ONLY, + true); logthing(LOGTHING_NOTICE, "Got %d new keys.", count); diff --git a/cleankey.h b/cleankey.h index 834b622..22a7e45 100644 --- a/cleankey.h +++ b/cleankey.h @@ -24,6 +24,7 @@ #define ONAK_CLEAN_CHECK_SIGHASH (1 << 0) #define ONAK_CLEAN_LARGE_PACKETS (1 << 1) #define ONAK_CLEAN_DROP_V3_KEYS (1 << 2) +#define ONAK_CLEAN_UPDATE_ONLY (1 << 3) #define ONAK_CLEAN_ALL (uint64_t) -1 /** diff --git a/keydb.c b/keydb.c index f362b1a..f6b9682 100644 --- a/keydb.c +++ b/keydb.c @@ -159,6 +159,8 @@ struct ll *generic_cached_getkeysigs(struct onak_dbctx *dbctx, uint64_t keyid) /** * update_keys - Takes a list of public keys and updates them in the DB. * @keys: The keys to update in the DB. + * @blacklist: A keyarray of key fingerprints not to accept. + * @updateonly: Only update existing keys, don't add new ones. * @sendsync: Should we send a sync mail to our peers. * * Takes a list of keys and adds them to the database, merging them with @@ -170,12 +172,13 @@ struct ll *generic_cached_getkeysigs(struct onak_dbctx *dbctx, uint64_t keyid) int generic_update_keys(struct onak_dbctx *dbctx, struct openpgp_publickey **keys, struct keyarray *blacklist, + bool updateonly, bool sendsync) { struct openpgp_publickey **curkey, *tmp = NULL; struct openpgp_publickey *oldkey = NULL; struct openpgp_fingerprint fp; - int newkeys = 0; + int newkeys = 0, ret; bool intrans; curkey = keys; @@ -192,10 +195,13 @@ int generic_update_keys(struct onak_dbctx *dbctx, intrans = dbctx->starttrans(dbctx); - logthing(LOGTHING_INFO, - "Fetching key, result: %d", - dbctx->fetch_key_fp(dbctx, &fp, &oldkey, - intrans)); + ret = dbctx->fetch_key_fp(dbctx, &fp, &oldkey, intrans); + if (ret == 0 && updateonly) { + logthing(LOGTHING_INFO, + "Skipping new key as update only set."); + curkey = &(*curkey)->next; + goto next; + } /* * If we already have the key stored in the DB then merge it @@ -228,6 +234,7 @@ int generic_update_keys(struct onak_dbctx *dbctx, newkeys++; curkey = &(*curkey)->next; } +next: dbctx->endtrans(dbctx); } diff --git a/keydb.h b/keydb.h index a1078c7..7297a76 100644 --- a/keydb.h +++ b/keydb.h @@ -141,6 +141,7 @@ struct onak_dbctx { * @brief Takes a list of public keys and updates them in the DB. * @param keys The keys to update in the DB. * @param blacklist A keyarray of fingerprints that shouldn't be added. + * @updateonly: Only update existing keys, don't add new ones. * @param sendsync If we should send a keysync mail. * * Takes a list of keys and adds them to the database, merging them with @@ -155,6 +156,7 @@ struct onak_dbctx { int (*update_keys)(struct onak_dbctx *, struct openpgp_publickey **keys, struct keyarray *blacklist, + bool updateonly, bool sendsync); /** diff --git a/keydb_dynamic.c b/keydb_dynamic.c index cf9d87f..385c09c 100644 --- a/keydb_dynamic.c +++ b/keydb_dynamic.c @@ -122,13 +122,14 @@ static int dynamic_delete_key(struct onak_dbctx *dbctx, static int dynamic_update_keys(struct onak_dbctx *dbctx, struct openpgp_publickey **keys, struct keyarray *blacklist, + bool updateonly, bool sendsync) { struct onak_dynamic_dbctx *privctx = (struct onak_dynamic_dbctx *) dbctx->priv; return privctx->loadeddbctx->update_keys(privctx->loadeddbctx, - keys, blacklist, sendsync); + keys, blacklist, updateonly, sendsync); } static struct ll *dynamic_getkeysigs(struct onak_dbctx *dbctx, diff --git a/keydb_keyring.c b/keydb_keyring.c index 0f24366..9550434 100644 --- a/keydb_keyring.c +++ b/keydb_keyring.c @@ -224,6 +224,7 @@ static int keyring_iterate_keys(struct onak_dbctx *dbctx, static int keyring_update_keys(struct onak_dbctx *dbctx, struct openpgp_publickey **keys, struct keyarray *blacklist, + bool updateonly, bool sendsync) { return 0; diff --git a/keydb_stacked.c b/keydb_stacked.c index b702c84..7e997d9 100644 --- a/keydb_stacked.c +++ b/keydb_stacked.c @@ -87,6 +87,7 @@ static int stacked_delete_key(struct onak_dbctx *dbctx, static int stacked_update_keys(struct onak_dbctx *dbctx, struct openpgp_publickey **keys, struct keyarray *blacklist, + bool updateonly, bool sendsync) { struct onak_stacked_dbctx *privctx = @@ -94,7 +95,8 @@ static int stacked_update_keys(struct onak_dbctx *dbctx, struct onak_dbctx *backend = (struct onak_dbctx *) privctx->backends->object; - return backend->update_keys(backend, keys, blacklist, sendsync); + return backend->update_keys(backend, keys, blacklist, updateonly, + sendsync); } static int stacked_iterate_keys(struct onak_dbctx *dbctx, diff --git a/onak-conf.c b/onak-conf.c index f0768a0..a67c950 100644 --- a/onak-conf.c +++ b/onak-conf.c @@ -313,6 +313,15 @@ static bool parseconfigline(char *line) config.clean_policies &= ~ONAK_CLEAN_LARGE_PACKETS; } + } else if (MATCH("verification", "update_only")) { + if (parsebool(value, config.clean_policies & + ONAK_CLEAN_UPDATE_ONLY)) { + config.clean_policies |= + ONAK_CLEAN_UPDATE_ONLY; + } else { + config.clean_policies &= + ~ONAK_CLEAN_UPDATE_ONLY; + } } else { return false; } diff --git a/onak.c b/onak.c index 70f5434..030d468 100644 --- a/onak.c +++ b/onak.c @@ -242,6 +242,8 @@ int main(int argc, char *argv[]) logthing(LOGTHING_NOTICE, "Got %d new keys.", dbctx->update_keys(dbctx, &keys, &config.blacklist, + (config.clean_policies & + ONAK_CLEAN_UPDATE_ONLY), false)); if (keys != NULL && update) { flatten_publickey(keys, diff --git a/onak.ini.in b/onak.ini.in index a9745cd..dc68e1f 100644 --- a/onak.ini.in +++ b/onak.ini.in @@ -25,6 +25,10 @@ check_sighash=true ; Drop v3 (and older) keys. These are long considered insecure, so unless there ; is a good reason you should accept this default. drop_v3=true +; Only allow keys that already exist to be update; silently drop the addition +; of any key we don't already know about. Useful for allowing updates to +; curated keys without the addition of new keys. +;update_only=false ; Settings related to the email interface to onak. [mail] diff --git a/t/all-036-update-only.t b/t/all-036-update-only.t new file mode 100755 index 0000000..e0b3027 --- /dev/null +++ b/t/all-036-update-only.t @@ -0,0 +1,17 @@ +#!/bin/sh +# Check we can't submit a new key when update_only is set + +set -e + +cd ${WORKDIR} +cp $1 update-only.ini +echo update_only=true >> update-only.ini +${BUILDDIR}/onak -b -c update-only.ini add < ${TESTSDIR}/../keys/noodles.key || true +rm update-only.ini +if ! ${BUILDDIR}/onak -c $1 get 0x94FA372B2DA8B985 2>&1 | \ + grep -q 'Key not found'; then + echo "* Did not correctly error on update-only key" + exit 1 +fi + +exit 0 -- 2.39.5