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