cscvs to tla changeset 12
[onak.git] / keyindex.c
1 /*
2  * keyindex.c - Routines to list an OpenPGP key.
3  *
4  * Jonathan McDowell <noodles@earth.li>
5  *
6  * Copyright 2002 Project Purple
7  */
8
9 #include <assert.h>
10 #include <stdbool.h>
11 #include <stdio.h>
12 #include <stdint.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <time.h>
16
17 #include "getcgi.h"
18 #include "hash.h"
19 #include "keydb.h"
20 #include "keyid.h"
21 #include "keyindex.h"
22 #include "keystructs.h"
23 #include "ll.h"
24 #include "stats.h"
25
26 int list_sigs(struct openpgp_packet_list *sigs, bool html)
27 {
28         int length = 0;
29         char *uid = NULL;
30         uint64_t sigid = 0;
31
32         while (sigs != NULL) {
33                 sigid = sig_keyid(sigs->packet);
34                 uid = keyid2uid(sigid);
35                 if (html && uid != NULL) {
36                         printf("sig         <a href=\"lookup?op=get&"
37                                 "search=%08llX\">%08llX</a>             "
38                                 "<a href=\"lookup?op=vindex&search=0x%08llX\">"
39                                 "%s</a>\n",
40                                 sigid & 0xFFFFFFFF,
41                                 sigid & 0xFFFFFFFF,
42                                 sigid & 0xFFFFFFFF,
43                                 txt2html(uid));
44                 } else if (html && uid == NULL) {
45                         printf("sig         %08llX             "
46                                 "[User id not found]\n",
47                                 sigid & 0xFFFFFFFF);
48                 } else {
49                         printf("sig         %08llX"
50                                 "             %s\n",
51                                 sigid & 0xFFFFFFFF,
52                                 (uid != NULL) ? uid :
53                                 "[User id not found]");
54                 }
55                 if (uid != NULL) {
56                         free(uid);
57                         uid = NULL;
58                 }
59                 sigs = sigs->next;
60         }
61
62         return 0;
63 }
64
65 int list_uids(struct openpgp_signedpacket_list *uids, bool verbose, bool html)
66 {
67         char buf[1024];
68
69         while (uids != NULL) {
70                 if (uids->packet->tag == 13) {
71                         snprintf(buf, 1023, "%.*s",
72                                 (int) uids->packet->length,
73                                 uids->packet->data);
74                         printf("uid                             %s\n",
75                                 (html) ? txt2html(buf) : buf);
76                 } else if (uids->packet->tag == 17) {
77                         printf("uid                             "
78                                 "[photo id]\n");
79                 }
80                 if (verbose) {
81                         list_sigs(uids->sigs, html);
82                 }
83                 uids = uids->next;
84         }
85
86         return 0;
87 }
88
89 /**
90  *      key_index - List a set of OpenPGP keys.
91  *      @keys: The keys to display.
92  *      @verbose: Should we list sigs as well?
93  *      @fingerprint: List the fingerprint?
94  *      @html: Should the output be tailored for HTML?
95  *
96  *      This function takes a list of OpenPGP public keys and displays an index
97  *      of them. Useful for debugging or the keyserver Index function.
98  */
99 int key_index(struct openpgp_publickey *keys, bool verbose, bool fingerprint,
100                         bool html)
101 {
102         struct openpgp_signedpacket_list        *curuid = NULL;
103         struct tm                               *created = NULL;
104         time_t                                   created_time = 0;
105         int                                      type = 0;
106         int                                      length = 0;
107         char                                     buf[1024];
108
109         if (html) {
110                 puts("<pre>");
111         }
112         puts("Type   bits/keyID    Date       User ID");
113         while (keys != NULL) {
114                 created_time = (keys->publickey->data[1] << 24) +
115                                         (keys->publickey->data[2] << 16) +
116                                         (keys->publickey->data[3] << 8) +
117                                         keys->publickey->data[4];
118                 created = gmtime(&created_time);
119
120                 switch (keys->publickey->data[0]) {
121                 case 2:
122                 case 3:
123                         type = keys->publickey->data[7];
124                         length = (keys->publickey->data[8] << 8) +
125                                         keys->publickey->data[9];
126                         break;
127                 case 4:
128                         type = keys->publickey->data[5];
129                         length = (keys->publickey->data[6] << 8) +
130                                         keys->publickey->data[7];
131                         break;
132                 default:
133                         fprintf(stderr, "Unknown key type: %d\n",
134                                 keys->publickey->data[0]);
135                 }
136                 
137                 printf("pub  %5d%c/%08X %04d/%02d/%02d ",
138                         length,
139                         (type == 1) ? 'R' : ((type == 17) ? 'D' : '?'),
140                         (uint32_t) (get_keyid(keys) & 0xFFFFFFFF),
141                         created->tm_year + 1900,
142                         created->tm_mon + 1,
143                         created->tm_mday);
144
145                 curuid = keys->uids;
146                 if (curuid != NULL && curuid->packet->tag == 13) {
147                         snprintf(buf, 1023, "%.*s",
148                                 (int) curuid->packet->length,
149                                 curuid->packet->data);
150                         printf("%s\n", (html) ? txt2html(buf) : buf);
151                         if (verbose) {
152                                 list_sigs(curuid->sigs, html);
153                         }
154                         curuid = curuid->next;
155                 } else {
156                         putchar('\n');
157                 }
158
159                 list_uids(curuid, verbose, html);
160
161                 //TODO: List subkeys.
162
163                 keys = keys->next;
164         }
165
166         if (html) {
167                 puts("</pre>");
168         }
169
170         return 0;
171 }
172
173 /*
174  *      parse_subpackets - Parse the subpackets of a Type 4 signature.
175  *      @data: The subpacket data.
176  *      @keyid: A pointer to where we should return the keyid.
177  *
178  *      This function parses the subkey data of a Type 4 signature and fills
179  *      in the supplied variables. It also returns the length of the data
180  *      processed.
181  */
182 int parse_subpackets(unsigned char *data, uint64_t *keyid)
183 {
184         int offset = 0;
185         int length = 0;
186         int packetlen = 0;
187
188         assert(data != NULL);
189
190         length = (data[0] << 8) + data[1] + 2;
191
192         offset = 2;
193         while (offset < length) {
194                 packetlen = data[offset++];
195                 if (packetlen > 191 && packetlen < 255) {
196                         packetlen = ((packetlen - 192) << 8) +
197                                         data[offset++] + 192;
198                 } else if (packetlen == 255) {
199                         packetlen = data[offset++];
200                         packetlen <<= 8;
201                         packetlen = data[offset++];
202                         packetlen <<= 8;
203                         packetlen = data[offset++];
204                         packetlen <<= 8;
205                         packetlen = data[offset++];
206                 }
207                 switch (data[offset]) {
208                 case 2:
209                         /*
210                          * Signature creation time. Might want to output this?
211                          */
212                         break;
213                 case 0x83:
214                         /*
215                          * Signature expiration time. Might want to output this?
216                          */
217                         break;
218                 case 16:
219                         *keyid = data[offset+packetlen - 8];
220                         *keyid <<= 8;
221                         *keyid += data[offset+packetlen - 7];
222                         *keyid <<= 8;
223                         *keyid += data[offset+packetlen - 6];
224                         *keyid <<= 8;
225                         *keyid += data[offset+packetlen - 5];
226                         *keyid <<= 8;
227                         *keyid += data[offset+packetlen - 4];
228                         *keyid <<= 8;
229                         *keyid += data[offset+packetlen - 3];
230                         *keyid <<= 8;
231                         *keyid += data[offset+packetlen - 2];
232                         *keyid <<= 8;
233                         *keyid += data[offset+packetlen - 1];
234                         break;
235                 case 23:
236                         /*
237                          * Key server preferences. Including no-modify.
238                          */
239                         break;
240                 case 25:
241                         /*
242                          * Primary UID.
243                          */
244                         break;
245                 default:
246                         /*
247                          * We don't care about unrecognized packets unless bit
248                          * 7 is set in which case we prefer an error than
249                          * ignoring it.
250                          */
251                         assert(!(data[offset] & 0x80));
252                 }
253                 offset += packetlen;
254         }
255
256         return length;
257 }
258
259 /**
260  *      keysigs - Return the sigs on a given OpenPGP signature list.
261  *      @curll: The current linked list. Can be NULL to create a new list.
262  *      @sigs: The signature list we want the sigs on.
263  *
264  *      Returns a linked list of stats_key elements containing the sigs on the
265  *      supplied OpenPGP packet list.
266  */
267 struct ll *keysigs(struct ll *curll,
268                 struct openpgp_packet_list *sigs)
269 {
270         uint64_t keyid = 0;
271         
272         while (sigs != NULL) {
273                 keyid = sig_keyid(sigs->packet);
274                 sigs = sigs->next;
275                 curll = lladd(curll, createandaddtohash(keyid));
276         }
277
278         return curll;
279 }
280
281 /**
282  *      sig_keyid - Return the keyid for a given OpenPGP signature packet.
283  *      @packet: The signature packet.
284  *
285  *      Returns the keyid for the supplied signature packet.
286  */
287 uint64_t sig_keyid(struct openpgp_packet *packet)
288 {
289         int length = 0;
290         uint64_t keyid = 0;
291         
292         if (packet != NULL) {
293                 keyid = 0;
294                 switch (packet->data[0]) {
295                 case 2:
296                 case 3:
297                         keyid = packet->data[7];
298                         keyid <<= 8;
299                         keyid += packet->data[8];
300                         keyid <<= 8;
301                         keyid += packet->data[9];
302                         keyid <<= 8;
303                         keyid += packet->data[10];
304                         keyid <<= 8;
305                         keyid += packet->data[11];
306                         keyid <<= 8;
307                         keyid += packet->data[12];
308                         keyid <<= 8;
309                         keyid += packet->data[13];
310                         keyid <<= 8;
311                         keyid += packet->data[14];
312                         break;
313                 case 4:
314                         length = parse_subpackets(&packet->data[4],
315                                         &keyid);
316                         parse_subpackets(&packet->data[length + 4],
317                                         &keyid);
318                         /*
319                          * Don't bother to look at the unsigned packets.
320                          */
321                         break;
322                 default:
323                         break;
324                 }
325         }
326
327         return keyid;
328 }
329
330 /*
331  * TODO: Abstract out; all our linked lists should be generic and then we can
332  * llsize them.
333  */
334 int spsize(struct openpgp_signedpacket_list *list)
335 {
336         int size = 0;
337         struct openpgp_signedpacket_list *cur;
338
339         for (cur = list; cur != NULL; cur = cur->next, size++) ;
340
341         return size;
342 }
343
344 /**
345  *      keyuids - Takes a key and returns an array of its UIDs
346  *      @key: The key to get the uids of.
347  *      @primary: A pointer to store the primary UID in.
348  *
349  *      keyuids takes a public key structure and builds an array of the UIDs 
350  *      on the key. It also attempts to work out the primary UID and returns a
351  *      separate pointer to that particular element of the array.
352  */
353 char **keyuids(struct openpgp_publickey *key, char **primary)
354 {
355         struct openpgp_signedpacket_list *curuid = NULL;
356         char buf[1024];
357         char **uids = NULL;
358         int count = 0;
359
360         if (key != NULL && key->uids != NULL) {
361                 uids = malloc((spsize(key->uids) + 1) * sizeof (char *));
362         
363                 curuid = key->uids;
364                 while (curuid != NULL) {
365                         buf[0] = 0;
366                         if (curuid->packet->tag == 13) {
367                                 snprintf(buf, 1023, "%.*s",
368                                                 (int) curuid->packet->length,
369                                                 curuid->packet->data);
370                                 uids[count++] = strdup(buf);
371                         }
372                         curuid = curuid -> next;
373                 }
374                 uids[count] = NULL;
375         }
376         /*
377          * TODO: Parse subpackets for real primary ID (v4 keys)
378          */
379         if (primary != NULL) {
380                 *primary = uids[0];
381         }
382
383         return uids;
384 }