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