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