Add -1 to Debian package version
[onak.git] / decodekey.c
1 /*
2  * decodekey.c - Routines to further decode an OpenPGP key.
3  *
4  * Copyright 2002-2008 Jonathan McDowell <noodles@earth.li>
5  */
6
7 #include <stdbool.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <time.h>
12
13 #include "decodekey.h"
14 #include "hash.h"
15 #include "keyid.h"
16 #include "keystructs.h"
17 #include "ll.h"
18 #include "log.h"
19
20 /*
21  *      parse_subpackets - Parse the subpackets of a Type 4 signature.
22  *      @data: The subpacket data.
23  *      @keyid: A pointer to where we should return the keyid.
24  *      @creationtime: A pointer to where we should return the creation time.
25  *
26  *      This function parses the subkey data of a Type 4 signature and fills
27  *      in the supplied variables. It also returns the length of the data
28  *      processed. If the value of any piece of data is not desired a NULL
29  *      can be passed instead of a pointer to a storage area for that value.
30  */
31 int parse_subpackets(unsigned char *data, uint64_t *keyid, time_t *creation)
32 {
33         int offset = 0;
34         int length = 0;
35         int packetlen = 0;
36
37         log_assert(data != NULL);
38
39         length = (data[0] << 8) + data[1] + 2;
40
41         offset = 2;
42         while (offset < length) {
43                 packetlen = data[offset++];
44                 if (packetlen > 191 && packetlen < 255) {
45                         packetlen = ((packetlen - 192) << 8) +
46                                         data[offset++] + 192;
47                 } else if (packetlen == 255) {
48                         packetlen = data[offset++];
49                         packetlen <<= 8;
50                         packetlen = data[offset++];
51                         packetlen <<= 8;
52                         packetlen = data[offset++];
53                         packetlen <<= 8;
54                         packetlen = data[offset++];
55                 }
56                 switch (data[offset] & 0x7F) {
57                 case 2:
58                         /*
59                          * Signature creation time.
60                          */
61                         if (creation != NULL) {
62                                 *creation = data[offset + packetlen - 4];
63                                 *creation <<= 8;
64                                 *creation = data[offset + packetlen - 3];
65                                 *creation <<= 8;
66                                 *creation = data[offset + packetlen - 2];
67                                 *creation <<= 8;
68                                 *creation = data[offset + packetlen - 1];
69                         }
70                         break;
71                 case 3:
72                         /*
73                          * Signature expiration time. Might want to output this?
74                          */
75                         break;
76                 case 6:
77                         /*
78                          * Regular expression for UIDs this sig is over.
79                          */
80                         break;
81                 case 16:
82                         if (keyid != NULL) {
83                                 *keyid = data[offset+packetlen - 8];
84                                 *keyid <<= 8;
85                                 *keyid += data[offset+packetlen - 7];
86                                 *keyid <<= 8;
87                                 *keyid += data[offset+packetlen - 6];
88                                 *keyid <<= 8;
89                                 *keyid += data[offset+packetlen - 5];
90                                 *keyid <<= 8;
91                                 *keyid += data[offset+packetlen - 4];
92                                 *keyid <<= 8;
93                                 *keyid += data[offset+packetlen - 3];
94                                 *keyid <<= 8;
95                                 *keyid += data[offset+packetlen - 2];
96                                 *keyid <<= 8;
97                                 *keyid += data[offset+packetlen - 1];
98                         }
99                         break;
100                 case 20:
101                         /*
102                          * Annotation data.
103                          */
104                         break;
105
106                 case 23:
107                         /*
108                          * Key server preferences. Including no-modify.
109                          */
110                         break;
111                 case 25:
112                         /*
113                          * Primary UID.
114                          */
115                         break;
116                 case 26:
117                         /*
118                          * Policy URI.
119                          */
120                         break;
121                 default:
122                         /*
123                          * We don't care about unrecognized packets unless bit
124                          * 7 is set in which case we log a major error.
125                          */
126                         if (data[offset] & 0x80) {
127                                 logthing(LOGTHING_CRITICAL,
128                                 "Critical subpacket type not parsed: 0x%X",
129                                         data[offset]);
130                         }
131                                 
132                 }
133                 offset += packetlen;
134         }
135
136         return length;
137 }
138
139 /**
140  *      keysigs - Return the sigs on a given OpenPGP signature list.
141  *      @curll: The current linked list. Can be NULL to create a new list.
142  *      @sigs: The signature list we want the sigs on.
143  *
144  *      Returns a linked list of stats_key elements containing the sigs on the
145  *      supplied OpenPGP packet list.
146  */
147 struct ll *keysigs(struct ll *curll,
148                 struct openpgp_packet_list *sigs)
149 {
150         uint64_t keyid = 0;
151         
152         while (sigs != NULL) {
153                 keyid = sig_keyid(sigs->packet);
154                 sigs = sigs->next;
155                 curll = lladd(curll, createandaddtohash(keyid));
156         }
157
158         return curll;
159 }
160
161 /**
162  *      sig_info - Get info on a given OpenPGP signature packet
163  *      @packet: The signature packet
164  *      @keyid: A pointer for where to return the signature keyid
165  *      @creation: A pointer for where to return the signature creation time
166  *
167  *      Gets any info about a signature packet; parses the subpackets for a v4
168  *      key or pulls the data directly from v2/3. NULL can be passed for any
169  *      values which aren't cared about.
170  */
171 void sig_info(struct openpgp_packet *packet, uint64_t *keyid, time_t *creation)
172 {
173         int length = 0;
174         
175         if (packet != NULL) {
176                 switch (packet->data[0]) {
177                 case 2:
178                 case 3:
179                         if (keyid != NULL) {
180                                 *keyid = packet->data[7];
181                                 *keyid <<= 8;
182                                 *keyid += packet->data[8];
183                                 *keyid <<= 8;
184                                 *keyid += packet->data[9];
185                                 *keyid <<= 8;
186                                 *keyid += packet->data[10];
187                                 *keyid <<= 8;
188                                 *keyid += packet->data[11];
189                                 *keyid <<= 8;
190                                 *keyid += packet->data[12];
191                                 *keyid <<= 8;
192                                 *keyid += packet->data[13];
193                                 *keyid <<= 8;
194                                 *keyid += packet->data[14];
195                         }
196                         if (creation != NULL) {
197                                 *creation = packet->data[3];
198                                 *creation <<= 8;
199                                 *creation = packet->data[4];
200                                 *creation <<= 8;
201                                 *creation = packet->data[5];
202                                 *creation <<= 8;
203                                 *creation = packet->data[6];
204                         }
205                         break;
206                 case 4:
207                         length = parse_subpackets(&packet->data[4],
208                                         keyid, creation);
209                         parse_subpackets(&packet->data[length + 4],
210                                         keyid, creation);
211                         /*
212                          * Don't bother to look at the unsigned packets.
213                          */
214                         break;
215                 default:
216                         break;
217                 }
218         }
219
220         return;
221 }
222
223 /**
224  *      sig_keyid - Return the keyid for a given OpenPGP signature packet.
225  *      @packet: The signature packet.
226  *
227  *      Returns the keyid for the supplied signature packet.
228  */
229 uint64_t sig_keyid(struct openpgp_packet *packet)
230 {
231         uint64_t keyid = 0;
232
233         sig_info(packet, &keyid, NULL);
234
235         return keyid;
236 }
237
238
239 /*
240  * TODO: Abstract out; all our linked lists should be generic and then we can
241  * llsize them.
242  */
243 int spsize(struct openpgp_signedpacket_list *list)
244 {
245         int size = 0;
246         struct openpgp_signedpacket_list *cur;
247
248         for (cur = list; cur != NULL; cur = cur->next, size++) ;
249
250         return size;
251 }
252
253 /**
254  *      keyuids - Takes a key and returns an array of its UIDs
255  *      @key: The key to get the uids of.
256  *      @primary: A pointer to store the primary UID in.
257  *
258  *      keyuids takes a public key structure and builds an array of the UIDs 
259  *      on the key. It also attempts to work out the primary UID and returns a
260  *      separate pointer to that particular element of the array.
261  */
262 char **keyuids(struct openpgp_publickey *key, char **primary)
263 {
264         struct openpgp_signedpacket_list *curuid = NULL;
265         char buf[1024];
266         char **uids = NULL;
267         int count = 0;
268         
269         if (primary != NULL) {
270                 *primary = NULL;
271         }
272
273         if (key != NULL && key->uids != NULL) {
274                 uids = malloc((spsize(key->uids) + 1) * sizeof (char *));
275         
276                 curuid = key->uids;
277                 while (curuid != NULL) {
278                         buf[0] = 0;
279                         if (curuid->packet->tag == 13) {
280                                 snprintf(buf, 1023, "%.*s",
281                                                 (int) curuid->packet->length,
282                                                 curuid->packet->data);
283                                 uids[count++] = strdup(buf);
284                         }
285                         curuid = curuid -> next;
286                 }
287                 uids[count] = NULL;
288
289                 /*
290                  * TODO: Parse subpackets for real primary ID (v4 keys)
291                  */
292                 if (primary != NULL) {
293                         *primary = uids[0];
294                 }
295         }
296
297         return uids;
298 }
299
300 /**
301  *      keysubkeys - Takes a key and returns an array of its subkey keyids.
302  *      @key: The key to get the subkeys of.
303  *
304  *      keysubkeys takes a public key structure and returns an array of the
305  *      subkey keyids for that key.
306  */
307 uint64_t *keysubkeys(struct openpgp_publickey *key)
308 {
309         struct openpgp_signedpacket_list *cursubkey = NULL;
310         uint64_t                         *subkeys = NULL;
311         int                               count = 0;
312         
313         if (key != NULL && key->subkeys != NULL) {
314                 subkeys = malloc((spsize(key->subkeys) + 1) *
315                                 sizeof (uint64_t));
316                 cursubkey = key->subkeys;
317                 while (cursubkey != NULL) {
318                         subkeys[count++] = get_packetid(cursubkey->packet);
319                         cursubkey = cursubkey -> next;
320                 }
321                 subkeys[count] = 0;
322         }
323
324         return subkeys;
325 }