]> the.earth.li Git - onak.git/commitdiff
Add support for old Elgamal v3 key IDs
authorJonathan McDowell <noodles@earth.li>
Sun, 3 Nov 2013 01:22:33 +0000 (18:22 -0700)
committerJonathan McDowell <noodles@earth.li>
Sun, 3 Nov 2013 01:22:33 +0000 (18:22 -0700)
Old versions of GnuPG put Elgamal (type 16) keys inside v3 packets.
The method of getting the keyid for these keys was via a RIPE MD160
hash approach similar to the SHA-1 approach used in v4. While nothing
supports this these days there are keys in the public keyserver
network that contain this sort of data and if we don't parse the keyid
correctly we can't show things like self-sigs.

keyid.c

diff --git a/keyid.c b/keyid.c
index d114852bd3081b2f44da24fd785ccce3bada8dfe..6920ee478ef4bca7362bca7313047a199b01f02e 100644 (file)
--- a/keyid.c
+++ b/keyid.c
@@ -31,6 +31,7 @@
 
 #ifdef HAVE_NETTLE
 #include <nettle/md5.h>
+#include <nettle/ripemd160.h>
 #include <nettle/sha.h>
 #else
 #include "md5.h"
@@ -130,6 +131,10 @@ onak_status_t get_packetid(struct openpgp_packet *packet, uint64_t *keyid)
        int             i = 0;
        size_t          length = 0;
        unsigned char   buff[20];
+#ifdef NETTLE_WITH_RIPEMD160
+       struct ripemd160_ctx ripemd160_context;
+       uint8_t         data;
+#endif
 
        if (packet == NULL)
                return ONAK_E_INVALID_PARAM;
@@ -137,6 +142,46 @@ onak_status_t get_packetid(struct openpgp_packet *packet, uint64_t *keyid)
        switch (packet->data[0]) {
        case 2:
        case 3:
+               /*
+                * Old versions of GnuPG would put Elgamal keys inside
+                * a V3 key structure, then generate the keyid using
+                * RIPED160.
+                */
+#ifdef NETTLE_WITH_RIPEMD160
+               if (packet->data[7] == 16) {
+                       ripemd160_init(&ripemd160_context);
+                       data = 0x99;
+                       ripemd160_update(&ripemd160_context, 1, &data);
+                       data = packet->length >> 8;
+                       ripemd160_update(&ripemd160_context, 1, &data);
+                       data = packet->length & 0xFF;
+                       ripemd160_update(&ripemd160_context, 1, &data);
+                       ripemd160_update(&ripemd160_context,
+                               packet->length,
+                               packet->data);
+
+                       ripemd160_digest(&ripemd160_context,
+                               RIPEMD160_DIGEST_SIZE,
+                               buff);
+
+                       for (*keyid = 0, i = 12; i < 20; i++) {
+                               *keyid <<= 8;
+                               *keyid += buff[i];
+                       }
+
+                       return ONAK_E_OK;
+               }
+#endif
+               /*
+                * Check for an RSA key; if not return an error.
+                * 1 == RSA
+                * 2 == RSA Encrypt-Only
+                * 3 == RSA Sign-Only
+                */
+               if (packet->data[7] < 1 || packet->data[7] > 3) {
+                       return ONAK_E_INVALID_PKT;
+               }
+
                /*
                 * For a type 2 or 3 key the keyid is the last 64 bits of the
                 * public modulus n, which is stored as an MPI from offset 8
@@ -150,15 +195,6 @@ onak_status_t get_packetid(struct openpgp_packet *packet, uint64_t *keyid)
                        *keyid <<= 8;
                        *keyid += packet->data[offset++];
                }
-               /*
-                * Check for an RSA key; if not return an error.
-                * 1 == RSA
-                * 2 == RSA Encrypt-Only
-                * 3 == RSA Sign-Only
-                */
-               if (packet->data[7] < 1 || packet->data[7] > 3) {
-                       return ONAK_E_INVALID_PKT;
-               }
                break;
        case 4:
                get_fingerprint(packet, buff, &length);