Add checking for signature hashes
[onak.git] / keyindex.c
1 /*
2  * keyindex.c - Routines to list an OpenPGP key.
3  *
4  * Copyright 2002-2008 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 <inttypes.h>
21 #include <stdbool.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26
27 #include "decodekey.h"
28 #include "getcgi.h"
29 #include "hash.h"
30 #include "keydb.h"
31 #include "keyid.h"
32 #include "keyindex.h"
33 #include "keystructs.h"
34 #include "log.h"
35 #include "onak-conf.h"
36 #include "openpgp.h"
37
38 int list_sigs(struct openpgp_packet_list *sigs, bool html)
39 {
40         char *uid = NULL;
41         uint64_t sigid = 0;
42         char *sig = NULL;
43
44         while (sigs != NULL) {
45                 sigid = sig_keyid(sigs->packet);
46                 uid = config.dbbackend->keyid2uid(sigid);
47                 if (sigs->packet->data[0] == 4 &&
48                                 sigs->packet->data[1] == 0x30) {
49                         /* It's a Type 4 sig revocation */
50                         sig = "rev";
51                 } else {
52                         sig = "sig";
53                 }
54                 if (html && uid != NULL) {
55                         printf("%s         <a href=\"lookup?op=get&"
56                                 "search=0x%016" PRIX64 "\">%08" PRIX64
57                                 "</a>             "
58                                 "<a href=\"lookup?op=vindex&search=0x%016"
59                                 PRIX64 "\">%s</a>\n",
60                                 sig,
61                                 sigid,
62                                 sigid & 0xFFFFFFFF,
63                                 sigid,
64                                 txt2html(uid));
65                 } else if (html && uid == NULL) {
66                         printf("%s         %08" PRIX64 "             "
67                                 "[User id not found]\n",
68                                 sig,
69                                 sigid & 0xFFFFFFFF);
70                 } else {
71                         printf("%s         %08" PRIX64
72                                 "             %s\n",
73                                 sig,
74                                 sigid & 0xFFFFFFFF,
75                                 (uid != NULL) ? uid :
76                                 "[User id not found]");
77                 }
78                 if (uid != NULL) {
79                         free(uid);
80                         uid = NULL;
81                 }
82                 sigs = sigs->next;
83         }
84
85         return 0;
86 }
87
88 int list_uids(uint64_t keyid, struct openpgp_signedpacket_list *uids,
89                 bool verbose, bool html)
90 {
91         char buf[1024];
92         int  imgindx = 0;
93
94         while (uids != NULL) {
95                 if (uids->packet->tag == OPENPGP_PACKET_UID) {
96                         snprintf(buf, 1023, "%.*s",
97                                 (int) uids->packet->length,
98                                 uids->packet->data);
99                         printf("                                %s\n",
100                                 (html) ? txt2html(buf) : buf);
101                 } else if (uids->packet->tag == OPENPGP_PACKET_UAT) {
102                         printf("                                ");
103                         if (html) {
104                                 printf("<img src=\"lookup?op=photo&search="
105                                         "0x%016" PRIX64 "&idx=%d\" alt=\""
106                                         "[photo id]\">\n",
107                                         keyid,
108                                         imgindx);
109                                 imgindx++;
110                         } else {
111                                 printf("[photo id]\n");
112                         }
113                 }
114                 if (verbose) {
115                         list_sigs(uids->sigs, html);
116                 }
117                 uids = uids->next;
118         }
119
120         return 0;
121 }
122
123 int list_subkeys(struct openpgp_signedpacket_list *subkeys, bool verbose,
124                 bool html)
125 {
126         struct tm       *created = NULL;
127         time_t          created_time = 0;
128         int             type = 0;
129         int             length = 0;
130
131         while (subkeys != NULL) {
132                 if (subkeys->packet->tag == OPENPGP_PACKET_PUBLICSUBKEY) {
133
134                         created_time = (subkeys->packet->data[1] << 24) +
135                                         (subkeys->packet->data[2] << 16) +
136                                         (subkeys->packet->data[3] << 8) +
137                                         subkeys->packet->data[4];
138                         created = gmtime(&created_time);
139
140                         switch (subkeys->packet->data[0]) {
141                         case 2:
142                         case 3:
143                                 type = subkeys->packet->data[7];
144                                 length = (subkeys->packet->data[8] << 8) +
145                                         subkeys->packet->data[9];
146                                 break;
147                         case 4:
148                                 type = subkeys->packet->data[5];
149                                 length = (subkeys->packet->data[6] << 8) +
150                                         subkeys->packet->data[7];
151                                 break;
152                         default:
153                                 logthing(LOGTHING_ERROR,
154                                         "Unknown key type: %d",
155                                         subkeys->packet->data[0]);
156                         }
157                 
158                         printf("sub  %5d%c/%08X %04d/%02d/%02d\n",
159                                 length,
160                                 (type == OPENPGP_PKALGO_RSA) ? 'R' :
161                                 ((type == OPENPGP_PKALGO_ELGAMAL) ? 'g' :
162                                 ((type == OPENPGP_PKALGO_DSA) ? 'D' : '?')),
163                                 (uint32_t) (get_packetid(subkeys->packet) &
164                                             0xFFFFFFFF),
165                                 created->tm_year + 1900,
166                                 created->tm_mon + 1,
167                                 created->tm_mday);
168
169                 }
170                 if (verbose) {
171                         list_sigs(subkeys->sigs, html);
172                 }
173                 subkeys = subkeys->next;
174         }
175
176         return 0;
177 }
178
179 void display_fingerprint(struct openpgp_publickey *key)
180 {
181         int             i = 0;
182         size_t          length = 0;
183         unsigned char   fp[20];
184
185         get_fingerprint(key->publickey, fp, &length);
186         printf("      Key fingerprint =");
187         for (i = 0; i < length; i++) {
188                 if ((length == 16) ||
189                         (i % 2 == 0)) {
190                         printf(" ");
191                 }
192                 if (length == 20 && (i * 2) == length) {
193                         /* Extra space in the middle of a SHA1 fingerprint */
194                         printf(" ");
195                 }
196                 printf("%02X", fp[i]);
197         }
198         printf("\n");
199
200         return;
201 }
202
203 void display_skshash(struct openpgp_publickey *key, bool html)
204 {
205         int             i = 0;
206         struct skshash  hash;
207
208         get_skshash(key, &hash);
209         printf("      Key hash = ");
210         if (html) {
211                 printf("<a href=\"lookup?op=hget&search=");
212                 for (i = 0; i < sizeof(hash.hash); i++) {
213                         printf("%02X", hash.hash[i]);
214                 }
215                 printf("\">");
216         }
217         for (i = 0; i < sizeof(hash.hash); i++) {
218                 printf("%02X", hash.hash[i]);
219         }
220         if (html) {
221                 printf("</a>");
222         }
223         printf("\n");
224
225         return;
226 }
227
228 /**
229  *      key_index - List a set of OpenPGP keys.
230  *      @keys: The keys to display.
231  *      @verbose: Should we list sigs as well?
232  *      @fingerprint: List the fingerprint?
233  *      @html: Should the output be tailored for HTML?
234  *
235  *      This function takes a list of OpenPGP public keys and displays an index
236  *      of them. Useful for debugging or the keyserver Index function.
237  */
238 int key_index(struct openpgp_publickey *keys, bool verbose, bool fingerprint,
239                         bool skshash, bool html)
240 {
241         struct openpgp_signedpacket_list        *curuid = NULL;
242         struct tm                               *created = NULL;
243         time_t                                   created_time = 0;
244         int                                      type = 0;
245         char                                     typech;
246         int                                      length = 0;
247         char                                     buf[1024];
248         uint64_t                                 keyid;
249
250         if (html) {
251                 puts("<pre>");
252         }
253         puts("Type   bits/keyID    Date       User ID");
254         while (keys != NULL) {
255                 created_time = (keys->publickey->data[1] << 24) +
256                                         (keys->publickey->data[2] << 16) +
257                                         (keys->publickey->data[3] << 8) +
258                                         keys->publickey->data[4];
259                 created = gmtime(&created_time);
260
261                 switch (keys->publickey->data[0]) {
262                 case 2:
263                 case 3:
264                         type = keys->publickey->data[7];
265                         length = (keys->publickey->data[8] << 8) +
266                                         keys->publickey->data[9];
267                         break;
268                 case 4:
269                         type = keys->publickey->data[5];
270                         length = (keys->publickey->data[6] << 8) +
271                                         keys->publickey->data[7];
272                         break;
273                 default:
274                         logthing(LOGTHING_ERROR, "Unknown key type: %d",
275                                 keys->publickey->data[0]);
276                 }
277                 
278                 keyid = get_keyid(keys);
279
280                 switch (type) {
281                 case OPENPGP_PKALGO_RSA:
282                         typech = 'R';
283                         break;
284                 case OPENPGP_PKALGO_ELGAMAL:
285                         typech = 'g';
286                         break;
287                 case OPENPGP_PKALGO_DSA:
288                         typech = 'D';
289                         break;
290                 case OPENPGP_PKALGO_ELGAMAL_SIGN:
291                         typech = 'G';
292                         break;
293                 default:
294                         typech = '?';
295                         break;
296                 }
297
298                 if (html) {
299                         printf("pub  %5d%c/<a href=\"lookup?op=get&"
300                                 "search=0x%016" PRIX64 "\">%08" PRIX64
301                                 "</a> %04d/%02d/%02d ",
302                                 length,
303                                 typech,
304                                 keyid,
305                                 keyid & 0xFFFFFFFF,
306                                 created->tm_year + 1900,
307                                 created->tm_mon + 1,
308                                 created->tm_mday);
309                 } else {
310                         printf("pub  %5d%c/%08" PRIX64 " %04d/%02d/%02d ",
311                                 length,
312                                 typech,
313                                 keyid & 0xFFFFFFFF,
314                                 created->tm_year + 1900,
315                                 created->tm_mon + 1,
316                                 created->tm_mday);
317                 }
318
319                 curuid = keys->uids;
320                 if (curuid != NULL &&
321                                 curuid->packet->tag == OPENPGP_PACKET_UID) {
322                         snprintf(buf, 1023, "%.*s",
323                                 (int) curuid->packet->length,
324                                 curuid->packet->data);
325                         if (html) {
326                                 printf("<a href=\"lookup?op=vindex&"
327                                         "search=0x%016" PRIX64 "\">",
328                                         keyid);
329                         }
330                         printf("%s%s%s\n", 
331                                 (html) ? txt2html(buf) : buf,
332                                 (html) ? "</a>" : "",
333                                 (keys->revoked) ? " *** REVOKED ***" : "");
334                         if (skshash) {
335                                 display_skshash(keys, html);
336                         }
337                         if (fingerprint) {
338                                 display_fingerprint(keys);
339                         }
340                         if (verbose) {
341                                 list_sigs(curuid->sigs, html);
342                         }
343                         curuid = curuid->next;
344                 } else {
345                         printf("%s\n", 
346                                 (keys->revoked) ? "*** REVOKED ***": "");
347                         if (fingerprint) {
348                                 display_fingerprint(keys);
349                         }
350                 }
351
352                 list_uids(keyid, curuid, verbose, html);
353                 if (verbose) {
354                         list_subkeys(keys->subkeys, verbose, html);
355                 }
356
357                 keys = keys->next;
358         }
359
360         if (html) {
361                 puts("</pre>");
362         }
363
364         return 0;
365 }
366
367 /**
368  *      mrkey_index - List a set of OpenPGP keys in the MRHKP format.
369  *      @keys: The keys to display.
370  *
371  *      This function takes a list of OpenPGP public keys and displays a
372  *      machine readable list of them.
373  */
374 int mrkey_index(struct openpgp_publickey *keys)
375 {
376         struct openpgp_signedpacket_list        *curuid = NULL;
377         time_t                                   created_time = 0;
378         int                                      type = 0;
379         int                                      length = 0;
380         int                                      i = 0;
381         size_t                                   fplength = 0;
382         unsigned char                            fp[20];
383         int                                      c;
384
385         while (keys != NULL) {
386                 created_time = (keys->publickey->data[1] << 24) +
387                                         (keys->publickey->data[2] << 16) +
388                                         (keys->publickey->data[3] << 8) +
389                                         keys->publickey->data[4];
390
391                 printf("pub:");
392
393                 switch (keys->publickey->data[0]) {
394                 case 2:
395                 case 3:
396                         printf("%016" PRIX64, get_keyid(keys));
397                         type = keys->publickey->data[7];
398                         length = (keys->publickey->data[8] << 8) +
399                                         keys->publickey->data[9];
400                         break;
401                 case 4:
402                         (void) get_fingerprint(keys->publickey, fp, &fplength);
403
404                         for (i = 0; i < fplength; i++) {
405                                 printf("%02X", fp[i]);
406                         }
407
408                         type = keys->publickey->data[5];
409                         length = (keys->publickey->data[6] << 8) +
410                                         keys->publickey->data[7];
411                         break;
412                 default:
413                         logthing(LOGTHING_ERROR, "Unknown key type: %d",
414                                 keys->publickey->data[0]);
415                 }
416
417                 printf(":%d:%d:%ld::%s\n",
418                         type,
419                         length,
420                         created_time,
421                         (keys->revoked) ? "r" : "");
422         
423                 for (curuid = keys->uids; curuid != NULL;
424                          curuid = curuid->next) {
425                 
426                         if (curuid->packet->tag == OPENPGP_PACKET_UID) {
427                                 printf("uid:");
428                                 for (i = 0; i < (int) curuid->packet->length;
429                                                 i++) {
430                                         c = curuid->packet->data[i];
431                                         if (c == '%') {
432                                                 putchar('%');
433                                                 putchar(c);
434                                         } else if (c == ':' || c > 127) {
435                                                 printf("%%%X", c);
436                                         } else {
437                                                 putchar(c);
438                                         }
439                                 }
440                                 printf("\n");
441                         }
442                 }
443                 keys = keys->next;
444         }
445         return 0;
446 }