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