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