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