]> the.earth.li Git - onak.git/commitdiff
Fix handling of other signature requirement
authorJonathan McDowell <noodles@earth.li>
Thu, 3 Feb 2022 19:07:58 +0000 (19:07 +0000)
committerJonathan McDowell <noodles@earth.li>
Thu, 3 Feb 2022 19:07:58 +0000 (19:07 +0000)
Two fixes related to the check that a key has another signature on it.

Firstly, if any of the UIDs has a signature from another key then allow
all of them. Otherwise it's not possible to add a new UID to an existing
key. Our primary concern is that the key is linked into the WoT, rather
than policing individual UIDs.

Secondly, if a key is already present in the backend database then don't
perform the other signature check. If we've added to the backend and all
of the cross signatures are removed then it would be no longer possible
to update the key, which isn't what we want. If we've trusted it at some
point and added it then we should allow verifiable updates, even if
there are no valid cross signatures left.

cleankey.c

index 3a74098c4683e114ef37421099fc46f67a0ca3a2..10fb661bca71b9dd3918e5ffdc83d69bb50aa6dc 100644 (file)
@@ -151,9 +151,6 @@ int clean_sighashes(struct onak_dbctx *dbctx,
        bool remove;
 
        get_keyid(key, &keyid);
-       if (othersig != NULL) {
-               *othersig = false;
-       }
        if (selfsig != NULL) {
                *selfsig = false;
        }
@@ -249,17 +246,19 @@ int clean_list_sighashes(struct onak_dbctx *dbctx,
                        struct openpgp_signedpacket_list **siglist,
                        bool fullverify, bool needother)
 {
-       struct openpgp_signedpacket_list *tmp = NULL;
+       struct openpgp_signedpacket_list **orig, *tmp = NULL;
        bool selfsig, othersig;
        int removed = 0;
 
+       othersig = false;
+       orig = siglist;
        while (siglist != NULL && *siglist != NULL) {
-               selfsig = othersig = false;
+               selfsig = false;
 
                removed += clean_sighashes(dbctx, key, (*siglist)->packet,
                        &(*siglist)->sigs, fullverify, &selfsig, &othersig);
 
-               if (fullverify && (!selfsig || (needother && !othersig))) {
+               if (fullverify && !selfsig) {
                        /* Remove the UID/subkey if there's no selfsig */
                        tmp = *siglist;
                        *siglist = (*siglist)->next;
@@ -270,6 +269,20 @@ int clean_list_sighashes(struct onak_dbctx *dbctx,
                }
        }
 
+       /*
+        * We need at least one UID to have a signature from another key,
+        * otherwise we remove all of them if needother is set.
+        */
+       if (needother && fullverify && !othersig) {
+               siglist = orig;
+               while (siglist != NULL && *siglist != NULL) {
+                       tmp = *siglist;
+                       *siglist = (*siglist)->next;
+                       tmp->next = NULL;
+                       free_signedpacket_list(tmp);
+               }
+       }
+
        return removed;
 }
 
@@ -350,7 +363,9 @@ int cleankeys(struct onak_dbctx *dbctx, struct openpgp_publickey **keys,
                uint64_t policies)
 {
        struct openpgp_publickey **curkey, *tmp;
+       struct openpgp_fingerprint fp;
        int changed = 0, count = 0;
+       bool needother;
 
        if (keys == NULL)
                return 0;
@@ -375,9 +390,24 @@ int cleankeys(struct onak_dbctx *dbctx, struct openpgp_publickey **keys,
                count += dedupsubkeys(*curkey);
                if (policies & (ONAK_CLEAN_CHECK_SIGHASH |
                                        ONAK_CLEAN_VERIFY_SIGNATURES)) {
+
+                       needother = policies & ONAK_CLEAN_NEED_OTHER_SIG;
+                       if (needother) {
+                               /*
+                                * Check if we already have the key; if we do
+                                * then we can skip the check to make sure we
+                                * have signatures from other keys.
+                                */
+                               get_fingerprint((*curkey)->publickey, &fp);
+                               tmp = NULL;
+                               needother = dbctx->fetch_key(dbctx, &fp,
+                                               &tmp, false) == 0;
+                               free_publickey(tmp);
+                       }
+
                        count += clean_key_signatures(dbctx, *curkey,
                                policies & ONAK_CLEAN_VERIFY_SIGNATURES,
-                               policies & ONAK_CLEAN_NEED_OTHER_SIG);
+                               needother);
                }
                if (count > 0) {
                        changed++;