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