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