]> the.earth.li Git - onak.git/blob - keyid.c
Switch keysubkeys to returning an array of fingerprints instead of IDs
[onak.git] / keyid.c
1 /*
2  * keyid.c - Routines to calculate key IDs.
3  *
4  * Copyright 2002,2011 Jonathan McDowell <noodles@earth.li>
5  *
6  * This program is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 51
17  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #include <string.h>
21 #include <sys/types.h>
22 #include <arpa/inet.h>
23
24 #include "config.h"
25 #include "keyid.h"
26 #include "keystructs.h"
27 #include "onak.h"
28 #include "parsekey.h"
29 #include "mem.h"
30 #include "merge.h"
31
32 #ifdef HAVE_NETTLE
33 #include <nettle/md5.h>
34 #include <nettle/ripemd160.h>
35 #include <nettle/sha.h>
36 #else
37 #include "md5.h"
38 #include "sha1.h"
39 #endif
40
41 uint64_t fingerprint2keyid(struct openpgp_fingerprint *fingerprint)
42 {
43         uint64_t keyid;
44         int i;
45
46         keyid = 0;
47         for (keyid = 0, i = 12; i < 20; i++) {
48                 keyid <<= 8;
49                 keyid += fingerprint->fp[i];
50         }
51
52         return keyid;
53 }
54
55
56 /**
57  *      get_keyid - Given a public key returns the keyid.
58  *      @publickey: The key to calculate the id for.
59  */
60 onak_status_t get_keyid(struct openpgp_publickey *publickey, uint64_t *keyid)
61 {
62         return (get_packetid(publickey->publickey, keyid));
63 }
64
65 /**
66  *      get_fingerprint - Given a public key returns the fingerprint.
67  *      @publickey: The key to calculate the id for.
68  *      @fingerprint: The fingerprint (must be at least 20 bytes of space).
69  *      @len: The length of the returned fingerprint.
70  *
71  *      This function returns the fingerprint for a given public key. As Type 3
72  *      fingerprints are 16 bytes and Type 4 are 20 the len field indicates
73  *      which we've returned.
74  */
75 onak_status_t get_fingerprint(struct openpgp_packet *packet,
76         struct openpgp_fingerprint *fingerprint)
77 {
78         struct sha1_ctx sha_ctx;
79         struct md5_ctx md5_context;
80         unsigned char c;
81         size_t         modlen, explen;
82
83         if (fingerprint == NULL)
84                 return ONAK_E_INVALID_PARAM;
85
86         fingerprint->length = 0;
87
88         switch (packet->data[0]) {
89         case 2:
90         case 3:
91                 md5_init(&md5_context);
92
93                 /*
94                  * MD5 the modulus and exponent.
95                  */
96                 modlen = ((packet->data[8] << 8) +
97                          packet->data[9] + 7) >> 3;
98                 md5_update(&md5_context, modlen, &packet->data[10]);
99
100                 explen = ((packet->data[10+modlen] << 8) +
101                          packet->data[11+modlen] + 7) >> 3;
102                 md5_update(&md5_context, explen, &packet->data[12 + modlen]);
103
104                 fingerprint->length = 16;
105                 md5_digest(&md5_context, fingerprint->length, fingerprint->fp);
106
107                 break;
108
109         case 4:
110                 sha1_init(&sha_ctx);
111                 /*
112                  * TODO: Can this be 0x99? Are all public key packets old
113                  * format with 2 bytes of length data?
114                  */
115                 c = 0x99;
116                 sha1_update(&sha_ctx, sizeof(c), &c);
117                 c = packet->length >> 8;
118                 sha1_update(&sha_ctx, sizeof(c), &c);
119                 c = packet->length & 0xFF;
120                 sha1_update(&sha_ctx, sizeof(c), &c);
121                 sha1_update(&sha_ctx, packet->length,
122                         packet->data);
123                 fingerprint->length = 20;
124                 sha1_digest(&sha_ctx, fingerprint->length, fingerprint->fp);
125
126                 break;
127         default:
128                 return ONAK_E_UNKNOWN_VER;
129         }
130
131         return ONAK_E_OK;
132 }
133
134
135 /**
136  *      get_packetid - Given a PGP packet returns the keyid.
137  *      @packet: The packet to calculate the id for.
138  */
139 onak_status_t get_packetid(struct openpgp_packet *packet, uint64_t *keyid)
140 {
141         int             offset = 0;
142         int             i = 0;
143         struct openpgp_fingerprint fingerprint;
144 #ifdef NETTLE_WITH_RIPEMD160
145         struct ripemd160_ctx ripemd160_context;
146         uint8_t         data;
147 #endif
148
149         if (packet == NULL)
150                 return ONAK_E_INVALID_PARAM;
151
152         switch (packet->data[0]) {
153         case 2:
154         case 3:
155                 /*
156                  * Old versions of GnuPG would put Elgamal keys inside
157                  * a V3 key structure, then generate the keyid using
158                  * RIPED160.
159                  */
160 #ifdef NETTLE_WITH_RIPEMD160
161                 if (packet->data[7] == 16) {
162                         ripemd160_init(&ripemd160_context);
163                         data = 0x99;
164                         ripemd160_update(&ripemd160_context, 1, &data);
165                         data = packet->length >> 8;
166                         ripemd160_update(&ripemd160_context, 1, &data);
167                         data = packet->length & 0xFF;
168                         ripemd160_update(&ripemd160_context, 1, &data);
169                         ripemd160_update(&ripemd160_context,
170                                 packet->length,
171                                 packet->data);
172
173                         ripemd160_digest(&ripemd160_context,
174                                 RIPEMD160_DIGEST_SIZE,
175                                 fingerprint.fp);
176                         fingerprint.length = RIPEMD160_DIGEST_SIZE;
177
178                         *keyid = fingerprint2keyid(&fingerprint);
179
180                         return ONAK_E_OK;
181                 }
182 #endif
183                 /*
184                  * Check for an RSA key; if not return an error.
185                  * 1 == RSA
186                  * 2 == RSA Encrypt-Only
187                  * 3 == RSA Sign-Only
188                  */
189                 if (packet->data[7] < 1 || packet->data[7] > 3) {
190                         return ONAK_E_INVALID_PKT;
191                 }
192
193                 /*
194                  * For a type 2 or 3 key the keyid is the last 64 bits of the
195                  * public modulus n, which is stored as an MPI from offset 8
196                  * onwards.
197                  */
198                 offset = (packet->data[8] << 8) +
199                         packet->data[9];
200                 offset = ((offset + 7) / 8) + 2;
201
202                 for (*keyid = 0, i = 0; i < 8; i++) {
203                         *keyid <<= 8;
204                         *keyid += packet->data[offset++];
205                 }
206                 break;
207         case 4:
208                 get_fingerprint(packet, &fingerprint);
209
210                 *keyid = fingerprint2keyid(&fingerprint);
211
212                 break;
213         default:
214                 return ONAK_E_UNKNOWN_VER;
215         }
216
217         return ONAK_E_OK;
218 }
219
220 static struct openpgp_packet_list *sortpackets(struct openpgp_packet_list
221                                                         *packets)
222 {
223         struct openpgp_packet_list *sorted, **cur, *next;
224
225         sorted = NULL;
226         while (packets != NULL) {
227                 cur = &sorted;
228                 while (*cur != NULL && compare_packets((*cur)->packet,
229                                 packets->packet) < 0) {
230                         cur = &((*cur)->next);
231                 }
232                 next = *cur;
233                 *cur = packets;
234                 packets = packets->next;
235                 (*cur)->next = next;
236         }
237
238         return sorted;
239 }
240
241 onak_status_t get_skshash(struct openpgp_publickey *key, struct skshash *hash)
242 {
243         struct openpgp_packet_list *packets = NULL, *list_end = NULL;
244         struct openpgp_packet_list *curpacket;
245         struct md5_ctx md5_context;
246         struct openpgp_publickey *next;
247         uint32_t tmp;
248
249         /*
250          * We only want a single key, so clear any link to the next
251          * one for the period during the flatten.
252          */
253         next = key->next;
254         key->next = NULL;
255         flatten_publickey(key, &packets, &list_end);
256         key->next = next;
257         packets = sortpackets(packets);
258
259         md5_init(&md5_context);
260
261         for (curpacket = packets; curpacket != NULL;
262                         curpacket = curpacket->next) {
263                 tmp = htonl(curpacket->packet->tag);
264                 md5_update(&md5_context, sizeof(tmp), (void *) &tmp);
265                 tmp = htonl(curpacket->packet->length);
266                 md5_update(&md5_context, sizeof(tmp), (void *) &tmp);
267                 md5_update(&md5_context,
268                                 curpacket->packet->length,
269                                 curpacket->packet->data);
270         }
271
272         md5_digest(&md5_context, 16, (uint8_t *) &hash->hash);
273         free_packet_list(packets);
274
275         return ONAK_E_OK;
276 }
277
278 uint8_t hexdigit(char c)
279 {
280         if (c >= '0' && c <= '9')
281                 return c - '0';
282         else if (c >= 'a' && c <= 'f')
283                 return c - 'a' + 10;
284         else if (c >= 'A' && c <= 'F')
285                 return c - 'A' + 10;
286         else
287                 return 0;
288 }
289
290 int parse_skshash(char *search, struct skshash *hash)
291 {
292         int i, len;
293
294         len = strlen(search);
295         if (len > 32) {
296                 return 0;
297         }
298
299         for (i = 0; i < len; i += 2) {
300                 hash->hash[i >> 1] = (hexdigit(search[i]) << 4) +
301                                 hexdigit(search[i + 1]);
302         }
303
304         return 1;
305 }