]> the.earth.li Git - onak.git/blob - keyindex.c
4883f636cfabdc4f55363a515d906a3a2c783866
[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                 if (dbctx) {
226                         uid = dbctx->keyid2uid(dbctx, sigid);
227                 }
228                 if (sigs->packet->data[0] == 4 &&
229                                 sigs->packet->data[1] == 0x30) {
230                         /* It's a Type 4 sig revocation */
231                         sig = "rev";
232                 } else {
233                         sig = "sig";
234                 }
235                 if (html && uid != NULL) {
236                         printf("%s         <a href=\"lookup?op=get&"
237                                 "search=0x%016" PRIX64 "\">%08" PRIX64
238                                 "</a>             "
239                                 "<a href=\"lookup?op=vindex&search=0x%016"
240                                 PRIX64 "\">%s</a>\n",
241                                 sig,
242                                 sigid,
243                                 sigid & 0xFFFFFFFF,
244                                 sigid,
245                                 txt2html(uid));
246                 } else if (html && uid == NULL) {
247                         printf("%s         %08" PRIX64 "             "
248                                 "[User id not found]\n",
249                                 sig,
250                                 sigid & 0xFFFFFFFF);
251                 } else {
252                         printf("%s         %08" PRIX64
253                                 "             %s\n",
254                                 sig,
255                                 sigid & 0xFFFFFFFF,
256                                 (uid != NULL) ? uid :
257                                 "[User id not found]");
258                 }
259                 if (uid != NULL) {
260                         free(uid);
261                         uid = NULL;
262                 }
263                 sigs = sigs->next;
264         }
265
266         return 0;
267 }
268
269 int list_uids(struct onak_dbctx *dbctx,
270                 uint64_t keyid, struct openpgp_signedpacket_list *uids,
271                 bool verbose, bool html)
272 {
273         char buf[1024];
274         int  imgindx = 0;
275
276         while (uids != NULL) {
277                 if (uids->packet->tag == OPENPGP_PACKET_UID) {
278                         snprintf(buf, 1023, "%.*s",
279                                 (int) uids->packet->length,
280                                 uids->packet->data);
281                         printf("                                %s\n",
282                                 (html) ? txt2html(buf) : buf);
283                 } else if (uids->packet->tag == OPENPGP_PACKET_UAT) {
284                         printf("                                ");
285                         if (html) {
286                                 printf("<img src=\"lookup?op=photo&search="
287                                         "0x%016" PRIX64 "&idx=%d\" alt=\""
288                                         "[photo id]\">\n",
289                                         keyid,
290                                         imgindx);
291                                 imgindx++;
292                         } else {
293                                 printf("[photo id]\n");
294                         }
295                 }
296                 if (verbose) {
297                         list_sigs(dbctx, uids->sigs, html);
298                 }
299                 uids = uids->next;
300         }
301
302         return 0;
303 }
304
305 int list_subkeys(struct onak_dbctx *dbctx,
306                 struct openpgp_signedpacket_list *subkeys, bool verbose,
307                 bool html)
308 {
309         struct tm       *created = NULL;
310         time_t          created_time = 0;
311         int             type = 0;
312         int             length = 0;
313         uint64_t        keyid = 0;
314
315         while (subkeys != NULL) {
316                 if (subkeys->packet->tag == OPENPGP_PACKET_PUBLICSUBKEY) {
317
318                         created_time = (subkeys->packet->data[1] << 24) +
319                                         (subkeys->packet->data[2] << 16) +
320                                         (subkeys->packet->data[3] << 8) +
321                                         subkeys->packet->data[4];
322                         created = gmtime(&created_time);
323
324                         switch (subkeys->packet->data[0]) {
325                         case 2:
326                         case 3:
327                                 type = subkeys->packet->data[7];
328                                 break;
329                         case 4:
330                         case 5:
331                                 type = subkeys->packet->data[5];
332                                 break;
333                         default:
334                                 logthing(LOGTHING_ERROR,
335                                         "Unknown key version: %d",
336                                         subkeys->packet->data[0]);
337                         }
338                         length = keylength(subkeys->packet);
339
340                         if (get_packetid(subkeys->packet,
341                                         &keyid) != ONAK_E_OK) {
342                                 logthing(LOGTHING_ERROR, "Couldn't get keyid.");
343                         }
344                         printf("sub  %5d%c/%08X %04d/%02d/%02d\n",
345                                 length,
346                                 pkalgo2char(type),
347                                 (uint32_t) (keyid & 0xFFFFFFFF),
348                                 created->tm_year + 1900,
349                                 created->tm_mon + 1,
350                                 created->tm_mday);
351
352                 }
353                 if (verbose) {
354                         list_sigs(dbctx, subkeys->sigs, html);
355                 }
356                 subkeys = subkeys->next;
357         }
358
359         return 0;
360 }
361
362 void display_fingerprint(struct openpgp_publickey *key)
363 {
364         int             i = 0;
365         struct openpgp_fingerprint fingerprint;
366
367         get_fingerprint(key->publickey, &fingerprint);
368         printf("      Key fingerprint =");
369         for (i = 0; i < fingerprint.length; i++) {
370                 if ((fingerprint.length == 16) ||
371                         (i % 2 == 0)) {
372                         printf(" ");
373                 }
374                 if (fingerprint.length == 20 &&
375                                 (i * 2) == fingerprint.length) {
376                         /* Extra space in the middle of a SHA1 fingerprint */
377                         printf(" ");
378                 }
379                 printf("%02X", fingerprint.fp[i]);
380         }
381         printf("\n");
382
383         return;
384 }
385
386 void display_skshash(struct openpgp_publickey *key, bool html)
387 {
388         int             i = 0;
389         struct skshash  hash;
390
391         get_skshash(key, &hash);
392         printf("      Key hash = ");
393         if (html) {
394                 printf("<a href=\"lookup?op=hget&search=");
395                 for (i = 0; i < sizeof(hash.hash); i++) {
396                         printf("%02X", hash.hash[i]);
397                 }
398                 printf("\">");
399         }
400         for (i = 0; i < sizeof(hash.hash); i++) {
401                 printf("%02X", hash.hash[i]);
402         }
403         if (html) {
404                 printf("</a>");
405         }
406         printf("\n");
407
408         return;
409 }
410
411 /**
412  *      key_index - List a set of OpenPGP keys.
413  *      @keys: The keys to display.
414  *      @verbose: Should we list sigs as well?
415  *      @fingerprint: List the fingerprint?
416  *      @html: Should the output be tailored for HTML?
417  *
418  *      This function takes a list of OpenPGP public keys and displays an index
419  *      of them. Useful for debugging or the keyserver Index function.
420  */
421 int key_index(struct onak_dbctx *dbctx,
422                 struct openpgp_publickey *keys, bool verbose, bool fingerprint,
423                         bool skshash, bool html)
424 {
425         struct openpgp_signedpacket_list        *curuid = NULL;
426         struct tm                               *created = NULL;
427         time_t                                   created_time = 0;
428         int                                      type = 0;
429         int                                      length = 0;
430         char                                     buf[1024];
431         uint64_t                                 keyid;
432
433         if (html) {
434                 puts("<pre>");
435         }
436         puts("Type   bits/keyID    Date       User ID");
437         while (keys != NULL) {
438                 created_time = (keys->publickey->data[1] << 24) +
439                                         (keys->publickey->data[2] << 16) +
440                                         (keys->publickey->data[3] << 8) +
441                                         keys->publickey->data[4];
442                 created = gmtime(&created_time);
443
444                 switch (keys->publickey->data[0]) {
445                 case 2:
446                 case 3:
447                         type = keys->publickey->data[7];
448                         break;
449                 case 4:
450                 case 5:
451                         type = keys->publickey->data[5];
452                         break;
453                 default:
454                         logthing(LOGTHING_ERROR, "Unknown key version: %d",
455                                 keys->publickey->data[0]);
456                 }
457                 length = keylength(keys->publickey);
458
459                 if (get_keyid(keys, &keyid) != ONAK_E_OK) {
460                         logthing(LOGTHING_ERROR, "Couldn't get keyid.");
461                 }
462
463                 if (html) {
464                         printf("pub  %5d%c/<a href=\"lookup?op=get&"
465                                 "search=0x%016" PRIX64 "\">%08" PRIX64
466                                 "</a> %04d/%02d/%02d ",
467                                 length,
468                                 pkalgo2char(type),
469                                 keyid,
470                                 keyid & 0xFFFFFFFF,
471                                 created->tm_year + 1900,
472                                 created->tm_mon + 1,
473                                 created->tm_mday);
474                 } else {
475                         printf("pub  %5d%c/%08" PRIX64 " %04d/%02d/%02d ",
476                                 length,
477                                 pkalgo2char(type),
478                                 keyid & 0xFFFFFFFF,
479                                 created->tm_year + 1900,
480                                 created->tm_mon + 1,
481                                 created->tm_mday);
482                 }
483
484                 curuid = keys->uids;
485                 if (curuid != NULL &&
486                                 curuid->packet->tag == OPENPGP_PACKET_UID) {
487                         snprintf(buf, 1023, "%.*s",
488                                 (int) curuid->packet->length,
489                                 curuid->packet->data);
490                         if (html) {
491                                 printf("<a href=\"lookup?op=vindex&"
492                                         "search=0x%016" PRIX64 "\">",
493                                         keyid);
494                         }
495                         printf("%s%s%s\n", 
496                                 (html) ? txt2html(buf) : buf,
497                                 (html) ? "</a>" : "",
498                                 (keys->revoked) ? " *** REVOKED ***" : "");
499                         if (skshash) {
500                                 display_skshash(keys, html);
501                         }
502                         if (fingerprint) {
503                                 display_fingerprint(keys);
504                         }
505                         if (verbose) {
506                                 list_sigs(dbctx, curuid->sigs, html);
507                         }
508                         curuid = curuid->next;
509                 } else {
510                         printf("%s\n", 
511                                 (keys->revoked) ? "*** REVOKED ***": "");
512                         if (fingerprint) {
513                                 display_fingerprint(keys);
514                         }
515                 }
516
517                 list_uids(dbctx, keyid, curuid, verbose, html);
518                 if (verbose) {
519                         list_subkeys(dbctx, keys->subkeys, verbose, html);
520                 }
521
522                 keys = keys->next;
523         }
524
525         if (html) {
526                 puts("</pre>");
527         }
528
529         return 0;
530 }
531
532 /**
533  *      mrkey_index - List a set of OpenPGP keys in the MRHKP format.
534  *      @keys: The keys to display.
535  *
536  *      This function takes a list of OpenPGP public keys and displays a
537  *      machine readable list of them.
538  */
539 int mrkey_index(struct openpgp_publickey *keys)
540 {
541         struct openpgp_signedpacket_list        *curuid = NULL;
542         time_t                                   created_time = 0;
543         int                                      type = 0;
544         int                                      length = 0;
545         int                                      i = 0;
546         int                                      c;
547         uint64_t                                 keyid;
548         struct openpgp_fingerprint fingerprint;
549
550         while (keys != NULL) {
551                 created_time = (keys->publickey->data[1] << 24) +
552                                         (keys->publickey->data[2] << 16) +
553                                         (keys->publickey->data[3] << 8) +
554                                         keys->publickey->data[4];
555
556                 printf("pub:");
557
558                 switch (keys->publickey->data[0]) {
559                 case 2:
560                 case 3:
561                         if (get_keyid(keys, &keyid) != ONAK_E_OK) {
562                                 logthing(LOGTHING_ERROR, "Couldn't get keyid");
563                         }
564                         printf("%016" PRIX64, keyid);
565                         type = keys->publickey->data[7];
566                         break;
567                 case 4:
568                 case 5:
569                         (void) get_fingerprint(keys->publickey, &fingerprint);
570
571                         for (i = 0; i < fingerprint.length; i++) {
572                                 printf("%02X", fingerprint.fp[i]);
573                         }
574
575                         type = keys->publickey->data[5];
576                         break;
577                 default:
578                         logthing(LOGTHING_ERROR, "Unknown key version: %d",
579                                 keys->publickey->data[0]);
580                 }
581                 length = keylength(keys->publickey);
582
583                 printf(":%d:%d:%ld::%s\n",
584                         type,
585                         length,
586                         created_time,
587                         (keys->revoked) ? "r" : "");
588         
589                 for (curuid = keys->uids; curuid != NULL;
590                          curuid = curuid->next) {
591                 
592                         if (curuid->packet->tag == OPENPGP_PACKET_UID) {
593                                 printf("uid:");
594                                 for (i = 0; i < (int) curuid->packet->length;
595                                                 i++) {
596                                         c = curuid->packet->data[i];
597                                         if (c == '%') {
598                                                 putchar('%');
599                                                 putchar(c);
600                                         } else if (c == ':' || c > 127) {
601                                                 printf("%%%X", c);
602                                         } else {
603                                                 putchar(c);
604                                         }
605                                 }
606                                 printf("\n");
607                         }
608                 }
609                 keys = keys->next;
610         }
611         return 0;
612 }