]> the.earth.li Git - onak.git/blob - keyindex.c
Cleanup various includes
[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 "keydb.h"
30 #include "keyid.h"
31 #include "keyindex.h"
32 #include "keystructs.h"
33 #include "log.h"
34 #include "onak.h"
35 #include "openpgp.h"
36
37 /*
38  * Convert a Public Key algorithm to its single character representation.
39  */
40 char pkalgo2char(uint8_t algo)
41 {
42         char typech;
43
44         switch (algo) {
45         case OPENPGP_PKALGO_DSA:
46                 typech = 'D';
47                 break;
48         case OPENPGP_PKALGO_ECDSA:
49         case OPENPGP_PKALGO_EDDSA:
50                 typech = 'E';
51                 break;
52         case OPENPGP_PKALGO_EC:
53                 typech = 'e';
54                 break;
55         case OPENPGP_PKALGO_ELGAMAL_SIGN:
56                 typech = 'G';
57                 break;
58         case OPENPGP_PKALGO_ELGAMAL_ENC:
59                 typech = 'g';
60                 break;
61         case OPENPGP_PKALGO_RSA:
62                 typech = 'R';
63                 break;
64         case OPENPGP_PKALGO_RSA_ENC:
65                 typech = 'r';
66                 break;
67         case OPENPGP_PKALGO_RSA_SIGN:
68                 typech = 's';
69                 break;
70         default:
71                 typech = '?';
72                 break;
73         }
74
75         return typech;
76 }
77
78 /*
79  * Given a public key/subkey packet return the key length.
80  */
81 unsigned int keylength(struct openpgp_packet *keydata)
82 {
83         unsigned int length;
84
85         switch (keydata->data[0]) {
86         case 2:
87         case 3:
88                 length = (keydata->data[8] << 8) +
89                                 keydata->data[9];
90                 break;
91         case 4:
92                 switch (keydata->data[5]) {
93                 case OPENPGP_PKALGO_EC:
94                 case OPENPGP_PKALGO_ECDSA:
95                 case OPENPGP_PKALGO_EDDSA:
96                         /* Elliptic curve key size is based on OID */
97                         /* Curve25519 / 1.3.6.1.4.1.3029.1.5.1 */
98                         if ((keydata->data[6] == 10) &&
99                                         (keydata->data[7] == 0x2B) &&
100                                         (keydata->data[8] == 0x06) &&
101                                         (keydata->data[9] == 0x01) &&
102                                         (keydata->data[10] == 0x04) &&
103                                         (keydata->data[11] == 0x01) &&
104                                         (keydata->data[12] == 0x97) &&
105                                         (keydata->data[13] == 0x55) &&
106                                         (keydata->data[14] == 0x01) &&
107                                         (keydata->data[15] == 0x05) &&
108                                         (keydata->data[16] == 0x01)) {
109                                 length = 255;
110                         /* Ed25519 / 1.3.6.1.4.1.11591.15.1 */
111                         } else if ((keydata->data[6] == 9) &&
112                                         (keydata->data[7] == 0x2B) &&
113                                         (keydata->data[8] == 0x06) &&
114                                         (keydata->data[9] == 0x01) &&
115                                         (keydata->data[10] == 0x04) &&
116                                         (keydata->data[11] == 0x01) &&
117                                         (keydata->data[12] == 0xDA) &&
118                                         (keydata->data[13] == 0x47) &&
119                                         (keydata->data[14] == 0x0F) &&
120                                         (keydata->data[15] == 0x01)) {
121                                 length = 255;
122                         /* nistp256 / 1.2.840.10045.3.1.7 */
123                         } else if ((keydata->data[6] == 8) &&
124                                         (keydata->data[7] == 0x2A) &&
125                                         (keydata->data[8] == 0x86) &&
126                                         (keydata->data[9] == 0x48) &&
127                                         (keydata->data[10] == 0xCE) &&
128                                         (keydata->data[11] == 0x3D) &&
129                                         (keydata->data[12] == 0x03) &&
130                                         (keydata->data[13] == 0x01) &&
131                                         (keydata->data[14] == 0x07)) {
132                                 length = 256;
133                         /* nistp384 / 1.3.132.0.34 */
134                         } else if ((keydata->data[6] == 5) &&
135                                         (keydata->data[7] == 0x2B) &&
136                                         (keydata->data[8] == 0x81) &&
137                                         (keydata->data[9] == 0x04) &&
138                                         (keydata->data[10] == 0x00) &&
139                                         (keydata->data[11] == 0x22)) {
140                                 length = 384;
141                         /* nistp521 / 1.3.132.0.35 */
142                         } else if ((keydata->data[6] == 5) &&
143                                         (keydata->data[7] == 0x2B) &&
144                                         (keydata->data[8] == 0x81) &&
145                                         (keydata->data[9] == 0x04) &&
146                                         (keydata->data[10] == 0x00) &&
147                                         (keydata->data[11] == 0x23)) {
148                                 length = 521;
149                         /* brainpoolP256r1 / 1.3.36.3.3.2.8.1.1.7 */
150                         } else if ((keydata->data[6] == 9) &&
151                                         (keydata->data[7] == 0x2B) &&
152                                         (keydata->data[8] == 0x24) &&
153                                         (keydata->data[9] == 0x03) &&
154                                         (keydata->data[10] == 0x03) &&
155                                         (keydata->data[11] == 0x02) &&
156                                         (keydata->data[12] == 0x08) &&
157                                         (keydata->data[13] == 0x01) &&
158                                         (keydata->data[14] == 0x01) &&
159                                         (keydata->data[15] == 0x07)) {
160                                 length = 256;
161                         /* brainpoolP384r1 / 1.3.36.3.3.2.8.1.1.11 */
162                         } else if ((keydata->data[6] == 9) &&
163                                         (keydata->data[7] == 0x2B) &&
164                                         (keydata->data[8] == 0x24) &&
165                                         (keydata->data[9] == 0x03) &&
166                                         (keydata->data[10] == 0x03) &&
167                                         (keydata->data[11] == 0x02) &&
168                                         (keydata->data[12] == 0x08) &&
169                                         (keydata->data[13] == 0x01) &&
170                                         (keydata->data[14] == 0x01) &&
171                                         (keydata->data[15] == 0x0B)) {
172                                 length = 384;
173                         /* brainpoolP512r1 / 1.3.36.3.3.2.8.1.1.13 */
174                         } else if ((keydata->data[6] == 9) &&
175                                         (keydata->data[7] == 0x2B) &&
176                                         (keydata->data[8] == 0x24) &&
177                                         (keydata->data[9] == 0x03) &&
178                                         (keydata->data[10] == 0x03) &&
179                                         (keydata->data[11] == 0x02) &&
180                                         (keydata->data[12] == 0x08) &&
181                                         (keydata->data[13] == 0x01) &&
182                                         (keydata->data[14] == 0x01) &&
183                                         (keydata->data[15] == 0x0D)) {
184                                 length = 512;
185                         /* secp256k1 / 1.3.132.0.10 */
186                         } else if ((keydata->data[6] == 5) &&
187                                         (keydata->data[7] == 0x2B) &&
188                                         (keydata->data[8] == 0x81) &&
189                                         (keydata->data[9] == 0x04) &&
190                                         (keydata->data[10] == 0x00) &&
191                                         (keydata->data[11] == 0x0A)) {
192                                 length = 256;
193                         } else {
194                                 logthing(LOGTHING_ERROR,
195                                         "Unknown elliptic curve size");
196                                 length = 0;
197                         }
198                         break;
199                 default:
200                         length = (keydata->data[6] << 8) +
201                                 keydata->data[7];
202                 }
203                 break;
204         default:
205                 logthing(LOGTHING_ERROR, "Unknown key version: %d",
206                         keydata->data[0]);
207                 length = 0;
208         }
209
210         return length;
211 }
212
213 int list_sigs(struct onak_dbctx *dbctx,
214                 struct openpgp_packet_list *sigs, bool html)
215 {
216         char *uid = NULL;
217         uint64_t sigid = 0;
218         char *sig = NULL;
219
220         while (sigs != NULL) {
221                 sigid = sig_keyid(sigs->packet);
222                 uid = dbctx->keyid2uid(dbctx, sigid);
223                 if (sigs->packet->data[0] == 4 &&
224                                 sigs->packet->data[1] == 0x30) {
225                         /* It's a Type 4 sig revocation */
226                         sig = "rev";
227                 } else {
228                         sig = "sig";
229                 }
230                 if (html && uid != NULL) {
231                         printf("%s         <a href=\"lookup?op=get&"
232                                 "search=0x%016" PRIX64 "\">%08" PRIX64
233                                 "</a>             "
234                                 "<a href=\"lookup?op=vindex&search=0x%016"
235                                 PRIX64 "\">%s</a>\n",
236                                 sig,
237                                 sigid,
238                                 sigid & 0xFFFFFFFF,
239                                 sigid,
240                                 txt2html(uid));
241                 } else if (html && uid == NULL) {
242                         printf("%s         %08" PRIX64 "             "
243                                 "[User id not found]\n",
244                                 sig,
245                                 sigid & 0xFFFFFFFF);
246                 } else {
247                         printf("%s         %08" PRIX64
248                                 "             %s\n",
249                                 sig,
250                                 sigid & 0xFFFFFFFF,
251                                 (uid != NULL) ? uid :
252                                 "[User id not found]");
253                 }
254                 if (uid != NULL) {
255                         free(uid);
256                         uid = NULL;
257                 }
258                 sigs = sigs->next;
259         }
260
261         return 0;
262 }
263
264 int list_uids(struct onak_dbctx *dbctx,
265                 uint64_t keyid, struct openpgp_signedpacket_list *uids,
266                 bool verbose, bool html)
267 {
268         char buf[1024];
269         int  imgindx = 0;
270
271         while (uids != NULL) {
272                 if (uids->packet->tag == OPENPGP_PACKET_UID) {
273                         snprintf(buf, 1023, "%.*s",
274                                 (int) uids->packet->length,
275                                 uids->packet->data);
276                         printf("                                %s\n",
277                                 (html) ? txt2html(buf) : buf);
278                 } else if (uids->packet->tag == OPENPGP_PACKET_UAT) {
279                         printf("                                ");
280                         if (html) {
281                                 printf("<img src=\"lookup?op=photo&search="
282                                         "0x%016" PRIX64 "&idx=%d\" alt=\""
283                                         "[photo id]\">\n",
284                                         keyid,
285                                         imgindx);
286                                 imgindx++;
287                         } else {
288                                 printf("[photo id]\n");
289                         }
290                 }
291                 if (verbose) {
292                         list_sigs(dbctx, uids->sigs, html);
293                 }
294                 uids = uids->next;
295         }
296
297         return 0;
298 }
299
300 int list_subkeys(struct onak_dbctx *dbctx,
301                 struct openpgp_signedpacket_list *subkeys, bool verbose,
302                 bool html)
303 {
304         struct tm       *created = NULL;
305         time_t          created_time = 0;
306         int             type = 0;
307         int             length = 0;
308         uint64_t        keyid = 0;
309
310         while (subkeys != NULL) {
311                 if (subkeys->packet->tag == OPENPGP_PACKET_PUBLICSUBKEY) {
312
313                         created_time = (subkeys->packet->data[1] << 24) +
314                                         (subkeys->packet->data[2] << 16) +
315                                         (subkeys->packet->data[3] << 8) +
316                                         subkeys->packet->data[4];
317                         created = gmtime(&created_time);
318
319                         switch (subkeys->packet->data[0]) {
320                         case 2:
321                         case 3:
322                                 type = subkeys->packet->data[7];
323                                 break;
324                         case 4:
325                                 type = subkeys->packet->data[5];
326                                 break;
327                         default:
328                                 logthing(LOGTHING_ERROR,
329                                         "Unknown key type: %d",
330                                         subkeys->packet->data[0]);
331                         }
332                         length = keylength(subkeys->packet);
333
334                         if (get_packetid(subkeys->packet,
335                                         &keyid) != ONAK_E_OK) {
336                                 logthing(LOGTHING_ERROR, "Couldn't get keyid.");
337                         }
338                         printf("sub  %5d%c/%08X %04d/%02d/%02d\n",
339                                 length,
340                                 pkalgo2char(type),
341                                 (uint32_t) (keyid & 0xFFFFFFFF),
342                                 created->tm_year + 1900,
343                                 created->tm_mon + 1,
344                                 created->tm_mday);
345
346                 }
347                 if (verbose) {
348                         list_sigs(dbctx, subkeys->sigs, html);
349                 }
350                 subkeys = subkeys->next;
351         }
352
353         return 0;
354 }
355
356 void display_fingerprint(struct openpgp_publickey *key)
357 {
358         int             i = 0;
359         struct openpgp_fingerprint fingerprint;
360
361         get_fingerprint(key->publickey, &fingerprint);
362         printf("      Key fingerprint =");
363         for (i = 0; i < fingerprint.length; i++) {
364                 if ((fingerprint.length == 16) ||
365                         (i % 2 == 0)) {
366                         printf(" ");
367                 }
368                 if (fingerprint.length == 20 &&
369                                 (i * 2) == fingerprint.length) {
370                         /* Extra space in the middle of a SHA1 fingerprint */
371                         printf(" ");
372                 }
373                 printf("%02X", fingerprint.fp[i]);
374         }
375         printf("\n");
376
377         return;
378 }
379
380 void display_skshash(struct openpgp_publickey *key, bool html)
381 {
382         int             i = 0;
383         struct skshash  hash;
384
385         get_skshash(key, &hash);
386         printf("      Key hash = ");
387         if (html) {
388                 printf("<a href=\"lookup?op=hget&search=");
389                 for (i = 0; i < sizeof(hash.hash); i++) {
390                         printf("%02X", hash.hash[i]);
391                 }
392                 printf("\">");
393         }
394         for (i = 0; i < sizeof(hash.hash); i++) {
395                 printf("%02X", hash.hash[i]);
396         }
397         if (html) {
398                 printf("</a>");
399         }
400         printf("\n");
401
402         return;
403 }
404
405 /**
406  *      key_index - List a set of OpenPGP keys.
407  *      @keys: The keys to display.
408  *      @verbose: Should we list sigs as well?
409  *      @fingerprint: List the fingerprint?
410  *      @html: Should the output be tailored for HTML?
411  *
412  *      This function takes a list of OpenPGP public keys and displays an index
413  *      of them. Useful for debugging or the keyserver Index function.
414  */
415 int key_index(struct onak_dbctx *dbctx,
416                 struct openpgp_publickey *keys, bool verbose, bool fingerprint,
417                         bool skshash, bool html)
418 {
419         struct openpgp_signedpacket_list        *curuid = NULL;
420         struct tm                               *created = NULL;
421         time_t                                   created_time = 0;
422         int                                      type = 0;
423         int                                      length = 0;
424         char                                     buf[1024];
425         uint64_t                                 keyid;
426
427         if (html) {
428                 puts("<pre>");
429         }
430         puts("Type   bits/keyID    Date       User ID");
431         while (keys != NULL) {
432                 created_time = (keys->publickey->data[1] << 24) +
433                                         (keys->publickey->data[2] << 16) +
434                                         (keys->publickey->data[3] << 8) +
435                                         keys->publickey->data[4];
436                 created = gmtime(&created_time);
437
438                 switch (keys->publickey->data[0]) {
439                 case 2:
440                 case 3:
441                         type = keys->publickey->data[7];
442                         break;
443                 case 4:
444                         type = keys->publickey->data[5];
445                         break;
446                 default:
447                         logthing(LOGTHING_ERROR, "Unknown key type: %d",
448                                 keys->publickey->data[0]);
449                 }
450                 length = keylength(keys->publickey);
451
452                 if (get_keyid(keys, &keyid) != ONAK_E_OK) {
453                         logthing(LOGTHING_ERROR, "Couldn't get keyid.");
454                 }
455
456                 if (html) {
457                         printf("pub  %5d%c/<a href=\"lookup?op=get&"
458                                 "search=0x%016" PRIX64 "\">%08" PRIX64
459                                 "</a> %04d/%02d/%02d ",
460                                 length,
461                                 pkalgo2char(type),
462                                 keyid,
463                                 keyid & 0xFFFFFFFF,
464                                 created->tm_year + 1900,
465                                 created->tm_mon + 1,
466                                 created->tm_mday);
467                 } else {
468                         printf("pub  %5d%c/%08" PRIX64 " %04d/%02d/%02d ",
469                                 length,
470                                 pkalgo2char(type),
471                                 keyid & 0xFFFFFFFF,
472                                 created->tm_year + 1900,
473                                 created->tm_mon + 1,
474                                 created->tm_mday);
475                 }
476
477                 curuid = keys->uids;
478                 if (curuid != NULL &&
479                                 curuid->packet->tag == OPENPGP_PACKET_UID) {
480                         snprintf(buf, 1023, "%.*s",
481                                 (int) curuid->packet->length,
482                                 curuid->packet->data);
483                         if (html) {
484                                 printf("<a href=\"lookup?op=vindex&"
485                                         "search=0x%016" PRIX64 "\">",
486                                         keyid);
487                         }
488                         printf("%s%s%s\n", 
489                                 (html) ? txt2html(buf) : buf,
490                                 (html) ? "</a>" : "",
491                                 (keys->revoked) ? " *** REVOKED ***" : "");
492                         if (skshash) {
493                                 display_skshash(keys, html);
494                         }
495                         if (fingerprint) {
496                                 display_fingerprint(keys);
497                         }
498                         if (verbose) {
499                                 list_sigs(dbctx, curuid->sigs, html);
500                         }
501                         curuid = curuid->next;
502                 } else {
503                         printf("%s\n", 
504                                 (keys->revoked) ? "*** REVOKED ***": "");
505                         if (fingerprint) {
506                                 display_fingerprint(keys);
507                         }
508                 }
509
510                 list_uids(dbctx, keyid, curuid, verbose, html);
511                 if (verbose) {
512                         list_subkeys(dbctx, keys->subkeys, verbose, html);
513                 }
514
515                 keys = keys->next;
516         }
517
518         if (html) {
519                 puts("</pre>");
520         }
521
522         return 0;
523 }
524
525 /**
526  *      mrkey_index - List a set of OpenPGP keys in the MRHKP format.
527  *      @keys: The keys to display.
528  *
529  *      This function takes a list of OpenPGP public keys and displays a
530  *      machine readable list of them.
531  */
532 int mrkey_index(struct openpgp_publickey *keys)
533 {
534         struct openpgp_signedpacket_list        *curuid = NULL;
535         time_t                                   created_time = 0;
536         int                                      type = 0;
537         int                                      length = 0;
538         int                                      i = 0;
539         int                                      c;
540         uint64_t                                 keyid;
541         struct openpgp_fingerprint fingerprint;
542
543         while (keys != NULL) {
544                 created_time = (keys->publickey->data[1] << 24) +
545                                         (keys->publickey->data[2] << 16) +
546                                         (keys->publickey->data[3] << 8) +
547                                         keys->publickey->data[4];
548
549                 printf("pub:");
550
551                 switch (keys->publickey->data[0]) {
552                 case 2:
553                 case 3:
554                         if (get_keyid(keys, &keyid) != ONAK_E_OK) {
555                                 logthing(LOGTHING_ERROR, "Couldn't get keyid");
556                         }
557                         printf("%016" PRIX64, keyid);
558                         type = keys->publickey->data[7];
559                         break;
560                 case 4:
561                         (void) get_fingerprint(keys->publickey, &fingerprint);
562
563                         for (i = 0; i < fingerprint.length; i++) {
564                                 printf("%02X", fingerprint.fp[i]);
565                         }
566
567                         type = keys->publickey->data[5];
568                         break;
569                 default:
570                         logthing(LOGTHING_ERROR, "Unknown key type: %d",
571                                 keys->publickey->data[0]);
572                 }
573                 length = keylength(keys->publickey);
574
575                 printf(":%d:%d:%ld::%s\n",
576                         type,
577                         length,
578                         created_time,
579                         (keys->revoked) ? "r" : "");
580         
581                 for (curuid = keys->uids; curuid != NULL;
582                          curuid = curuid->next) {
583                 
584                         if (curuid->packet->tag == OPENPGP_PACKET_UID) {
585                                 printf("uid:");
586                                 for (i = 0; i < (int) curuid->packet->length;
587                                                 i++) {
588                                         c = curuid->packet->data[i];
589                                         if (c == '%') {
590                                                 putchar('%');
591                                                 putchar(c);
592                                         } else if (c == ':' || c > 127) {
593                                                 printf("%%%X", c);
594                                         } else {
595                                                 putchar(c);
596                                         }
597                                 }
598                                 printf("\n");
599                         }
600                 }
601                 keys = keys->next;
602         }
603         return 0;
604 }