]> the.earth.li Git - onak.git/commitdiff
Add support for a key fingerprint blacklist
authorJonathan McDowell <noodles@earth.li>
Sun, 18 Aug 2019 20:55:45 +0000 (21:55 +0100)
committerJonathan McDowell <noodles@earth.li>
Sun, 18 Aug 2019 20:55:45 +0000 (21:55 +0100)
There are various keys in the wild, such as Evil32 (https://evil32.com/)
which a keyserver is unlikely to want to carry in the general case.
Introduce the capability to have a blacklist of fingerprints which will
not be accepted into the keyserver.

15 files changed:
cgi/add.c
keyarray.c
keyarray.h
keydb.c
keydb.h
keydb_dynamic.c
keydb_keyring.c
keydb_stacked.c
keystructs.h
onak-conf.c
onak-conf.h
onak.c
onak.ini.in
runtests
t/test-in.ini

index c3a54a7295601947fc46b8277dbaa4731e324901..02eb3eb00703a1bca1bff3e4b20b10e8cb37f304 100644 (file)
--- a/cgi/add.c
+++ b/cgi/add.c
@@ -92,7 +92,8 @@ int main(int argc, char *argv[])
                        logthing(LOGTHING_INFO, "%d keys cleaned.",
                                        count);
 
-                       count = dbctx->update_keys(dbctx, &keys, true);
+                       count = dbctx->update_keys(dbctx, &keys,
+                                       &config.blacklist, true);
                        logthing(LOGTHING_NOTICE, "Got %d new keys.",
                                count);
 
index f869802b83b80fcf549e8c2d685cee47be6a2acc..85485556929ac0421665a41fc2ceaf6c01f43a5f 100644 (file)
@@ -16,6 +16,8 @@
  * this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+#include <ctype.h>
+#include <errno.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -128,3 +130,70 @@ void array_free(struct keyarray *array)
 
        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;
+}
+
+bool array_load(struct keyarray *array, const char *file)
+{
+       struct openpgp_fingerprint fp;
+       char curline[1024];
+       FILE *fpfile;
+       int i;
+
+       fpfile = fopen(file, "r");
+
+       if (fpfile != NULL) {
+               if (!fgets(curline, sizeof(curline) - 1, fpfile)) {
+                       fclose(fpfile);
+                       return false;
+               }
+
+               while (!feof(fpfile)) {
+                       /* Strip any trailing white space */
+                       for (i = strlen(curline) - 1;
+                                       i >= 0 && isspace(curline[i]); i--) {
+                               curline[i] = 0;
+                       }
+                       i++;
+                       //if ((i % 2) != 0) {
+                       //      break;
+                       //}
+                       i >>= 1;
+                       if (curline[0] == '#') {
+                               // Comment line, ignore
+                       } else if (i == FINGERPRINT_V3_LEN ||
+                                       i == FINGERPRINT_V4_LEN ||
+                                       i == FINGERPRINT_V5_LEN) {
+                               fp.length = i;
+                               for (i = 0; i < fp.length; i++) {
+                                       fp.fp[i] = hex2bin(curline[i * 2]);
+                                       fp.fp[i] <<= 4;
+                                       fp.fp[i] |=
+                                               hex2bin(curline[i * 2 + 1]);
+                               }
+                               array_add(array, &fp);
+                       } else {
+                               printf("Bad line.\n");
+                       }
+
+                       if (!fgets(curline, sizeof(curline) - 1, fpfile)) {
+                               break;
+                       }
+               }
+
+               fclose(fpfile);
+       }
+
+       return (array->count != 0);
+}
index e50a030c4ec2dd576d0040ad62e85b54484d9701..1ac13ba571c68d0190a5aa92bdf44d5e3ea9bbf8 100644 (file)
@@ -64,6 +64,18 @@ void array_free(struct keyarray *array);
  */
 bool array_add(struct keyarray *array, struct openpgp_fingerprint *fp);
 
+/**
+ * @brief Load a file into a keyarray
+ * @param array Pointer to the key array
+ * @param file The full path to the file to load
+ *
+ * Loads fingerprints from the supplied file into the provided keyarray. Does
+ * not re-initialise the array so can be called repeatedly to add multiple
+ * files. The file does not need to be sorted; array_add() is called for each
+ * key to ensure the array is suitable for binary searching with array_find()
+ */
+bool array_load(struct keyarray *array, const char *file);
+
 /**
  * @brief Compare two OpenPGP fingerprints
  * @param a Fingerprint 1
diff --git a/keydb.c b/keydb.c
index 30a77caf61f912ddf5142aff5669b8d1be2844cc..f362b1adddf3e59fc338ea686e9b70c89992b331 100644 (file)
--- a/keydb.c
+++ b/keydb.c
@@ -168,7 +168,9 @@ struct ll *generic_cached_getkeysigs(struct onak_dbctx *dbctx, uint64_t keyid)
  *     the DB). Returns the number of entirely new keys added.
  */
 int generic_update_keys(struct onak_dbctx *dbctx,
-               struct openpgp_publickey **keys, bool sendsync)
+               struct openpgp_publickey **keys,
+               struct keyarray *blacklist,
+               bool sendsync)
 {
        struct openpgp_publickey **curkey, *tmp = NULL;
        struct openpgp_publickey *oldkey = NULL;
@@ -179,6 +181,14 @@ int generic_update_keys(struct onak_dbctx *dbctx,
        curkey = keys;
        while (*curkey != NULL) {
                get_fingerprint((*curkey)->publickey, &fp);
+               if (blacklist && array_find(blacklist, &fp)) {
+                       logthing(LOGTHING_INFO, "Ignoring blacklisted key.");
+                       tmp = *curkey;
+                       *curkey = (*curkey)->next;
+                       tmp->next = NULL;
+                       free_publickey(tmp);
+                       continue;
+               }
 
                intrans = dbctx->starttrans(dbctx);
 
diff --git a/keydb.h b/keydb.h
index 5dcb4364860e10967eb31709fb808e0a94c494d7..a1078c76afd423963965613515c6a3aca3365386 100644 (file)
--- a/keydb.h
+++ b/keydb.h
@@ -23,6 +23,7 @@
 #include <stdbool.h>
 #include <inttypes.h>
 
+#include "keyarray.h"
 #include "keystructs.h"
 #include "ll.h"
 
@@ -139,6 +140,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.
  * @param sendsync If we should send a keysync mail.
  *
  * Takes a list of keys and adds them to the database, merging them with
@@ -151,7 +153,9 @@ struct onak_dbctx {
  * with the update.
  */
        int (*update_keys)(struct onak_dbctx *,
-                       struct openpgp_publickey **keys, bool sendsync);
+                       struct openpgp_publickey **keys,
+                       struct keyarray *blacklist,
+                       bool sendsync);
 
 /**
  * @brief Takes a keyid and returns the primary UID for it.
index 52a4af9bec00e062cb5c157a07bf728dc6df78b9..cf9d87fa030af270ae48bacfa154e139c6a7577a 100644 (file)
@@ -120,13 +120,15 @@ static int dynamic_delete_key(struct onak_dbctx *dbctx,
 }
 
 static int dynamic_update_keys(struct onak_dbctx *dbctx,
-               struct openpgp_publickey **keys, bool sendsync)
+               struct openpgp_publickey **keys,
+               struct keyarray *blacklist,
+               bool sendsync)
 {
        struct onak_dynamic_dbctx *privctx =
                        (struct onak_dynamic_dbctx *) dbctx->priv;
 
        return privctx->loadeddbctx->update_keys(privctx->loadeddbctx,
-                       keys, sendsync);
+                       keys, blacklist, sendsync);
 }
 
 static struct ll *dynamic_getkeysigs(struct onak_dbctx *dbctx,
index 0b865b57efb6554c7489b87b08fac03061869b16..e3f8584a05df3c492e768679fd59921d773f8081 100644 (file)
@@ -222,7 +222,9 @@ static int keyring_iterate_keys(struct onak_dbctx *dbctx,
 }
 
 static int keyring_update_keys(struct onak_dbctx *dbctx,
-                struct openpgp_publickey **keys, bool sendsync)
+               struct openpgp_publickey **keys,
+               struct keyarray *blacklist,
+               bool sendsync)
 {
        return 0;
 }
index ee1c5cfa63df4475dbcb22cd9767bb6afe50e70b..b702c84b97a41d152f909e13deeac57e48cd518a 100644 (file)
@@ -85,14 +85,16 @@ static int stacked_delete_key(struct onak_dbctx *dbctx,
 }
 
 static int stacked_update_keys(struct onak_dbctx *dbctx,
-               struct openpgp_publickey **keys, bool sendsync)
+               struct openpgp_publickey **keys,
+               struct keyarray *blacklist,
+               bool sendsync)
 {
        struct onak_stacked_dbctx *privctx =
                        (struct onak_stacked_dbctx *) dbctx->priv;
        struct onak_dbctx *backend =
                        (struct onak_dbctx *) privctx->backends->object;
 
-       return backend->update_keys(backend, keys, sendsync);
+       return backend->update_keys(backend, keys, blacklist, sendsync);
 }
 
 static int stacked_iterate_keys(struct onak_dbctx *dbctx,
index af909f7c12aec4b51f136eabe8ac5a9256e6f258..18a9ba4ce12ca29017bafab63e256ed5d3ecc8a4 100644 (file)
 #include "ll.h"
 
 /*
+ * Fingerprint lengths
+ *
  * v3 MD5 fingerprint is 16 bytes
  * v4 SHA-1 fingerprint is 20
  * v5 SHA2-256 fingerprint is 32
  */
-#define MAX_FINGERPRINT_LEN 32
+#define FINGERPRINT_V3_LEN     16
+#define FINGERPRINT_V4_LEN     20
+#define FINGERPRINT_V5_LEN     32
+#define MAX_FINGERPRINT_LEN    32
 
 /**
  * @brief Stores the fingerprint of an OpenPGP key
index 7b8a2e3d6b1eb32ddb0bd908c96fbda7244ab756..f0768a0f11657f008ccf8623e7f3a9a82493233d 100644 (file)
@@ -284,6 +284,8 @@ static bool parseconfigline(char *line)
                        config.syncsites = lladd(config.syncsites,
                                strdup(value));
                /* [verification] section */
+               } else if (MATCH("verification", "blacklist")) {
+                       array_load(&config.blacklist, value);
                } else if (MATCH("verification", "drop_v3")) {
                        if (parsebool(value, config.clean_policies &
                                        ONAK_CLEAN_DROP_V3_KEYS)) {
@@ -602,4 +604,7 @@ void cleanupconfig(void) {
                free(config.mail_dir);
                config.mail_dir = NULL;
        }
+       if (config.blacklist.count != 0) {
+               array_free(&config.blacklist);
+       }
 }
index 3e02b7a0226769bacc240e47db3972a7e42d7aca..5d39f6ab2a44bcdd06af245d178b4742474adb3f 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+#include "keyarray.h"
 #include "ll.h"
 
 /**
@@ -89,6 +90,9 @@ struct onak_config {
        /** Pointer to the initialisation function for our loaded DB backend */
        struct onak_dbctx *(*dbinit)(struct onak_db_config *, bool);
 
+       /** Blacklist of fingerprints to reject */
+       struct keyarray blacklist;
+
        /** What policies should we use for cleaning keys? */
        uint64_t clean_policies;
 
diff --git a/onak.c b/onak.c
index 4c319cd194c68ed6137f3f6715485347a642f25f..70f54348ccf39b5fa733b37425f523ef0ba04b72 100644 (file)
--- a/onak.c
+++ b/onak.c
@@ -241,7 +241,8 @@ int main(int argc, char *argv[])
                        dbctx = config.dbinit(config.backend, false);
                        logthing(LOGTHING_NOTICE, "Got %d new keys.",
                                        dbctx->update_keys(dbctx, &keys,
-                                       false));
+                                               &config.blacklist,
+                                               false));
                        if (keys != NULL && update) {
                                flatten_publickey(keys,
                                        &packets,
index 8989f0704a28832ed4685c8671b562bf1fd32c98..a9745cd4a38c125ab5c42a27e4acad0f575552c5 100644 (file)
@@ -16,6 +16,9 @@ max_reply_keys=128
 
 ; Settings related to key verification options available.
 [verification]
+; Blacklist certain fingerprints (e.g. EVIL32). One fingerprint per line,
+; comment lines start with #
+;blacklist=blacklist.txt
 ; Verify signature hashes - verify that the hash a signature claims to be
 ; over matches the hash of the data. Does not actually verify the signature.
 check_sighash=true
index 60c02229520714bf4082ec7cff80823888004838..6b5b830dd6c9db123a5d2f664e5c3763cf008706 100755 (executable)
--- a/runtests
+++ b/runtests
@@ -37,6 +37,7 @@ for t in libkeydb_*.so; do
                sed -e "s;BUILDDIR;${BUILDDIR};" -e "s;WORKDIR;${WORKDIR};" \
                        -e "s;DB;${backend};" \
                        ${TESTSDIR}/test-in.ini > ${WORKDIR}/test.ini
+               touch ${WORKDIR}/blacklist
                for t in ${TESTSDIR}/$backend-*.t ${TESTSDIR}/all-*.t; do
                        total=`expr $total + 1`
                        mkdir ${WORKDIR}/db/
index b7414018c1219e2d7951f6da8bcd346286f325da..e40c0e2439c74c10e0747f26a7cd2b2306842c8e 100644 (file)
@@ -13,3 +13,6 @@ location=WORKDIR/db/
 [mail]
 bin_dir=BUILDDIR
 this_site=pgp-public-keys@localhost
+
+[verification]
+blacklist=WORKDIR/blacklist