]> the.earth.li Git - onak.git/commitdiff
Add de-duplication of subkeys on a key
authorJonathan McDowell <noodles@earth.li>
Fri, 14 Aug 2015 17:19:15 +0000 (18:19 +0100)
committerJonathan McDowell <noodles@earth.li>
Fri, 14 Aug 2015 17:19:15 +0000 (18:19 +0100)
GnuPG will incorrectly add a pre-existing subkey that it doesn't
understand (e.g. ECC) to a key. This results in keys with a large
number of identical subkeys. Avoid this by detecting such keys and
de-duplicating the identical subkeys.

(gnupg bug report at https://bugs.gnupg.org/gnupg/issue1962)

cleankey.c

index 7d0bfe4b8cb16315926399f395f58b2142061aad..5608ef04926213893794f83756c20b7ad7b9c4e0 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 
 #include "cleankey.h"
+#include "keyid.h"
 #include "keystructs.h"
 #include "log.h"
 #include "mem.h"
@@ -73,6 +74,53 @@ int dedupuids(struct openpgp_publickey *key)
        return merged;
 }
 
+/**
+ *     dedupsubkeys - Merge duplicate subkeys on a key.
+ *     @key: The key to de-dup subkeys on.
+ *
+ *     This function attempts to merge duplicate subkeys on a key. It returns
+ *     0 if the key is unchanged, otherwise the number of dups merged.
+ */
+int dedupsubkeys(struct openpgp_publickey *key)
+{
+       struct openpgp_signedpacket_list *cursubkey = NULL;
+       struct openpgp_signedpacket_list *dup = NULL;
+       struct openpgp_signedpacket_list *tmp = NULL;
+       int                               merged = 0;
+       uint64_t                          subkeyid;
+
+       log_assert(key != NULL);
+       cursubkey = key->subkeys;
+       while (cursubkey != NULL) {
+               dup = find_signed_packet(cursubkey->next, cursubkey->packet);
+               while (dup != NULL) {
+                       get_packetid(cursubkey->packet, &subkeyid);
+                       logthing(LOGTHING_INFO,
+                               "Found duplicate subkey: 0x%016" PRIX64,
+                               subkeyid);
+                       merged++;
+                       merge_packet_sigs(cursubkey, dup);
+                       /*
+                        * Remove the duplicate uid.
+                        */
+                       tmp = cursubkey;
+                       while (tmp != NULL && tmp->next != dup) {
+                               tmp = tmp->next;
+                       }
+                       log_assert(tmp != NULL);
+                       tmp->next = dup->next;
+                       dup->next = NULL;
+                       free_signedpacket_list(dup);
+
+                       dup = find_signed_packet(cursubkey->next,
+                               cursubkey->packet);
+               }
+               cursubkey = cursubkey->next;
+       }
+
+       return merged;
+}
+
 /**
  *     check_sighashes - Check that sig hashes are correct.
  *     @key - the check to check the sig hashes of.
@@ -146,6 +194,7 @@ int cleankeys(struct openpgp_publickey *keys)
 
        while (keys != NULL) {
                count = dedupuids(keys);
+               count += dedupsubkeys(keys);
                if (config.check_sighash) {
                        count += clean_key_sighashes(keys);
                }