Add a test for key fetching by SKS hash
[onak.git] / keyid.c
1 /*
2  * keyid.c - Routines to calculate key IDs.
3  *
4  * Jonathan McDowell <noodles@earth.li>
5  *
6  * Copyright 2002 Project Purple
7  */
8
9 #include <string.h>
10 #include <sys/types.h>
11 #include <arpa/inet.h>
12
13 #include "keyid.h"
14 #include "keystructs.h"
15 #include "log.h"
16 #include "parsekey.h"
17 #include "md5.h"
18 #include "mem.h"
19 #include "merge.h"
20 #include "sha1.h"
21
22
23 /**
24  *      get_keyid - Given a public key returns the keyid.
25  *      @publickey: The key to calculate the id for.
26  */
27 uint64_t get_keyid(struct openpgp_publickey *publickey)
28 {
29         return (get_packetid(publickey->publickey));
30 }
31
32 /**
33  *      get_fingerprint - Given a public key returns the fingerprint.
34  *      @publickey: The key to calculate the id for.
35  *      @fingerprint: The fingerprint (must be at least 20 bytes of space). 
36  *      @len: The length of the returned fingerprint.
37  *
38  *      This function returns the fingerprint for a given public key. As Type 3
39  *      fingerprints are 16 bytes and Type 4 are 20 the len field indicates
40  *      which we've returned.
41  */
42 unsigned char *get_fingerprint(struct openpgp_packet *packet,
43         unsigned char *fingerprint,
44         size_t *len)
45 {
46         SHA1_CTX sha_ctx;
47         struct md5_ctx md5_context;
48         unsigned char c;
49         size_t         modlen, explen;
50
51         log_assert(fingerprint != NULL);
52         log_assert(len != NULL);
53
54         *len = 0;
55
56         switch (packet->data[0]) {
57         case 2:
58         case 3:
59                 md5_init_ctx(&md5_context);
60
61                 /*
62                  * MD5 the modulus and exponent.
63                  */
64                 modlen = ((packet->data[8] << 8) +
65                          packet->data[9] + 7) >> 3;
66                 md5_process_bytes(&packet->data[10], modlen, &md5_context);
67
68                 explen = ((packet->data[10+modlen] << 8) +
69                          packet->data[11+modlen] + 7) >> 3;
70                 md5_process_bytes(&packet->data[12 + modlen], explen,
71                                 &md5_context);
72
73                 md5_finish_ctx(&md5_context, fingerprint);
74                 *len = 16;
75
76                 break;
77
78         case 4:
79                 SHA1Init(&sha_ctx);
80                 /*
81                  * TODO: Can this be 0x99? Are all public key packets old
82                  * format with 2 bytes of length data?
83                  */
84                 c = 0x99;
85                 SHA1Update(&sha_ctx, &c, sizeof(c));
86                 c = packet->length >> 8;
87                 SHA1Update(&sha_ctx, &c, sizeof(c));
88                 c = packet->length & 0xFF;
89                 SHA1Update(&sha_ctx, &c, sizeof(c));
90                 SHA1Update(&sha_ctx, packet->data,
91                         packet->length);
92                 SHA1Final(fingerprint, &sha_ctx);
93                 *len = 20;
94
95                 break;
96         default:
97                 logthing(LOGTHING_ERROR, "Unknown key type: %d",
98                                 packet->data[0]);
99         }
100
101         return fingerprint;
102 }
103
104
105 /**
106  *      get_packetid - Given a PGP packet returns the keyid.
107  *      @packet: The packet to calculate the id for.
108  */
109 uint64_t get_packetid(struct openpgp_packet *packet)
110 {
111         uint64_t        keyid = 0;
112         int             offset = 0;
113         int             i = 0;
114         size_t          length = 0;
115         unsigned char   buff[20];
116
117         log_assert(packet != NULL);
118
119         switch (packet->data[0]) {
120         case 2:
121         case 3:
122                 /*
123                  * For a type 2 or 3 key the keyid is the last 64 bits of the
124                  * public modulus n, which is stored as an MPI from offset 8
125                  * onwards.
126                  */
127                 offset = (packet->data[8] << 8) +
128                         packet->data[9];
129                 offset = ((offset + 7) / 8) + 2;
130
131                 for (keyid = 0, i = 0; i < 8; i++) {
132                         keyid <<= 8;
133                         keyid += packet->data[offset++];
134                 }
135                 /*
136                  * Check for an RSA key; if not then log but accept anyway.
137                  * 1 == RSA
138                  * 2 == RSA Encrypt-Only
139                  * 3 == RSA Sign-Only
140                  */
141                 if (packet->data[7] < 1 || packet->data[7] > 3) {
142                         logthing(LOGTHING_NOTICE,
143                                 "Type 2 or 3 key, but not RSA: %llx (type %d)",
144                                 keyid,
145                                 packet->data[7]);
146                 }
147                 break;
148         case 4:
149                 get_fingerprint(packet, buff, &length);
150                 
151                 for (keyid = 0, i = 12; i < 20; i++) {
152                         keyid <<= 8;
153                         keyid += buff[i];
154                 }
155
156                 break;
157         default:
158                 logthing(LOGTHING_ERROR, "Unknown key type: %d",
159                                 packet->data[0]);
160         }
161
162         return keyid;
163 }
164
165 static struct openpgp_packet_list *sortpackets(struct openpgp_packet_list
166                                                         *packets)
167 {
168         struct openpgp_packet_list *sorted, **cur, *next;
169
170         sorted = NULL;
171         while (packets != NULL) {
172                 cur = &sorted;
173                 while (*cur != NULL && compare_packets((*cur)->packet,
174                                 packets->packet) < 0) {
175                         cur = &((*cur)->next);
176                 }
177                 next = *cur;
178                 *cur = packets;
179                 packets = packets->next;
180                 (*cur)->next = next;
181         }
182
183         return sorted;
184 }
185
186 void get_skshash(struct openpgp_publickey *key, struct skshash *hash)
187 {
188         struct openpgp_packet_list *packets = NULL, *list_end = NULL;
189         struct openpgp_packet_list *curpacket;
190         struct md5_ctx md5_context;
191         struct openpgp_publickey *next;
192         uint32_t tmp;
193
194         /*
195          * We only want a single key, so clear any link to the next
196          * one for the period during the flatten.
197          */
198         next = key->next;
199         key->next = NULL;
200         flatten_publickey(key, &packets, &list_end);
201         key->next = next;
202         packets = sortpackets(packets);
203
204         md5_init_ctx(&md5_context);
205
206         for (curpacket = packets; curpacket != NULL;
207                         curpacket = curpacket->next) {
208                 tmp = htonl(curpacket->packet->tag);
209                 md5_process_bytes(&tmp, sizeof(tmp), &md5_context);
210                 tmp = htonl(curpacket->packet->length);
211                 md5_process_bytes(&tmp, sizeof(tmp), &md5_context);
212                 md5_process_bytes(curpacket->packet->data,
213                                 curpacket->packet->length,
214                                 &md5_context);
215         }
216
217         md5_finish_ctx(&md5_context, &hash->hash);
218         free_packet_list(packets);
219 }
220
221 uint8_t hexdigit(char c)
222 {
223         if (c >= '0' && c <= '9')
224                 return c - '0';
225         else if (c >= 'a' && c <= 'f')
226                 return c - 'a' + 10;
227         else if (c >= 'A' && c <= 'F')
228                 return c - 'A' + 10;
229         else
230                 return 0;
231 }
232
233 int parse_skshash(char *search, struct skshash *hash)
234 {
235         int i, len;
236
237         len = strlen(search);
238         if (len > 32) {
239                 return 0;
240         }
241
242         for (i = 0; i < len; i += 2) {
243                 hash->hash[i >> 1] = (hexdigit(search[i]) << 4) +
244                                 hexdigit(search[i + 1]);
245         }
246
247         return 1;
248 }