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