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