2 * keyindex.c - Routines to list an OpenPGP key.
4 * Copyright 2002-2008 Jonathan McDowell <noodles@earth.li>
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.
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
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/>.
26 #include "decodekey.h"
30 #include "keystructs.h"
36 * Convert a Public Key algorithm to its single character representation.
38 char pkalgo2char(uint8_t algo)
43 case OPENPGP_PKALGO_DSA:
46 case OPENPGP_PKALGO_ECDSA:
47 case OPENPGP_PKALGO_EDDSA:
50 case OPENPGP_PKALGO_EC:
53 case OPENPGP_PKALGO_ELGAMAL_SIGN:
56 case OPENPGP_PKALGO_ELGAMAL_ENC:
59 case OPENPGP_PKALGO_RSA:
62 case OPENPGP_PKALGO_RSA_ENC:
65 case OPENPGP_PKALGO_RSA_SIGN:
77 * txt2html - Takes a string and converts it to HTML.
78 * @string: The string to HTMLize.
80 * Takes a string and escapes any HTML entities.
82 const char *txt2html(const char *string)
84 static char buf[1024];
88 if (strlen(string) > 1000) {
94 ptr = strchr(string, '<');
98 strncpy(buf, string, 1023);
99 strncat(buf, "<", 1023 - strlen(buf));
103 ptr = strchr(string, '>');
107 strncat(buf, string, 1023 - strlen(buf));
108 strncat(buf, ">", 1023 - strlen(buf));
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.
119 strncat(buf, string, 1023 - strlen(buf));
125 * Given a public key/subkey packet return the key length.
127 unsigned int keylength(struct openpgp_packet *keydata)
133 switch (keydata->data[0]) {
136 length = (keydata->data[8] << 8) +
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) {
152 } else if (oid == ONAK_OID_ED25519) {
154 } else if (oid == ONAK_OID_NISTP256) {
156 } else if (oid == ONAK_OID_NISTP384) {
158 } else if (oid == ONAK_OID_NISTP521) {
160 } else if (oid == ONAK_OID_BRAINPOOLP256R1) {
162 } else if (oid == ONAK_OID_BRAINPOOLP384R1) {
164 } else if (oid == ONAK_OID_BRAINPOOLP512R1) {
166 } else if (oid == ONAK_OID_SECP256K1) {
169 logthing(LOGTHING_ERROR,
170 "Unknown elliptic curve size");
175 length = (keydata->data[keyofs] << 8) +
176 keydata->data[keyofs + 1];
180 logthing(LOGTHING_ERROR, "Unknown key version: %d",
188 int list_sigs(struct onak_dbctx *dbctx,
189 struct openpgp_packet_list *sigs, bool html)
195 while (sigs != NULL) {
196 sigid = sig_keyid(sigs->packet);
198 uid = dbctx->keyid2uid(dbctx, sigid);
200 if (sigs->packet->data[0] == 4 &&
201 sigs->packet->data[1] == 0x30) {
202 /* It's a Type 4 sig revocation */
207 if (html && uid != NULL) {
208 printf("%s <a href=\"lookup?op=get&"
209 "search=0x%016" PRIX64 "\">0x%016" PRIX64
211 "<a href=\"lookup?op=vindex&search=0x%016"
212 PRIX64 "\">%s</a>\n",
218 } else if (html && uid == NULL) {
219 printf("%s 0x%016" PRIX64 " "
220 "[User id not found]\n",
224 printf("%s 0x%016" PRIX64
228 (uid != NULL) ? uid :
229 "[User id not found]");
241 int list_uids(struct onak_dbctx *dbctx,
242 uint64_t keyid, struct openpgp_signedpacket_list *uids,
243 bool verbose, bool html)
248 while (uids != NULL) {
249 if (uids->packet->tag == OPENPGP_PACKET_UID) {
250 snprintf(buf, 1023, "%.*s",
251 (int) uids->packet->length,
254 (html) ? txt2html(buf) : buf);
255 } else if (uids->packet->tag == OPENPGP_PACKET_UAT) {
258 printf("<img src=\"lookup?op=photo&search="
259 "0x%016" PRIX64 "&idx=%d\" alt=\""
265 printf("[photo id]\n");
269 list_sigs(dbctx, uids->sigs, html);
277 int list_subkeys(struct onak_dbctx *dbctx,
278 struct openpgp_signedpacket_list *subkeys, bool verbose,
282 time_t created_time = 0;
287 while (subkeys != NULL) {
288 if (subkeys->packet->tag == OPENPGP_PACKET_PUBLICSUBKEY) {
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);
296 switch (subkeys->packet->data[0]) {
299 type = subkeys->packet->data[7];
303 type = subkeys->packet->data[5];
306 logthing(LOGTHING_ERROR,
307 "Unknown key version: %d",
308 subkeys->packet->data[0]);
310 length = keylength(subkeys->packet);
312 if (get_packetid(subkeys->packet,
313 &keyid) != ONAK_E_OK) {
314 logthing(LOGTHING_ERROR, "Couldn't get keyid.");
316 printf("sub %5d%c/0x%016" PRIX64 " %04d/%02d/%02d\n",
320 created.tm_year + 1900,
326 list_sigs(dbctx, subkeys->sigs, html);
328 subkeys = subkeys->next;
334 void display_fingerprint(struct openpgp_publickey *key)
337 struct openpgp_fingerprint fingerprint;
339 get_fingerprint(key->publickey, &fingerprint);
340 printf(" Key fingerprint =");
341 for (i = 0; i < fingerprint.length; i++) {
342 if ((fingerprint.length == 16) ||
346 if (fingerprint.length == 20 &&
347 (i * 2) == fingerprint.length) {
348 /* Extra space in the middle of a SHA1 fingerprint */
351 printf("%02X", fingerprint.fp[i]);
358 void display_skshash(struct openpgp_publickey *key, bool html)
363 get_skshash(key, &hash);
364 printf(" Key hash = ");
366 printf("<a href=\"lookup?op=hget&search=");
367 for (i = 0; i < sizeof(hash.hash); i++) {
368 printf("%02X", hash.hash[i]);
372 for (i = 0; i < sizeof(hash.hash); i++) {
373 printf("%02X", hash.hash[i]);
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?
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.
393 int key_index(struct onak_dbctx *dbctx,
394 struct openpgp_publickey *keys, bool verbose, bool fingerprint,
395 bool skshash, bool html)
397 struct openpgp_signedpacket_list *curuid = NULL;
399 time_t created_time = 0;
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);
417 switch (keys->publickey->data[0]) {
420 type = keys->publickey->data[7];
424 type = keys->publickey->data[5];
427 logthing(LOGTHING_ERROR, "Unknown key version: %d",
428 keys->publickey->data[0]);
430 length = keylength(keys->publickey);
432 if (get_keyid(keys, &keyid) != ONAK_E_OK) {
433 logthing(LOGTHING_ERROR, "Couldn't get keyid.");
437 printf("pub %5d%c/<a href=\"lookup?op=get&"
438 "search=0x%016" PRIX64 "\">0x%016" PRIX64
439 "</a> %04d/%02d/%02d ",
444 created.tm_year + 1900,
448 printf("pub %5d%c/0x%016" PRIX64 " %04d/%02d/%02d ",
452 created.tm_year + 1900,
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);
464 printf("<a href=\"lookup?op=vindex&"
465 "search=0x%016" PRIX64 "\">",
469 (html) ? txt2html(buf) : buf,
470 (html) ? "</a>" : "",
471 (keys->revoked) ? " *** REVOKED ***" : "");
473 display_skshash(keys, html);
476 display_fingerprint(keys);
479 list_sigs(dbctx, curuid->sigs, html);
481 curuid = curuid->next;
484 (keys->revoked) ? "*** REVOKED ***": "");
486 display_fingerprint(keys);
490 list_uids(dbctx, keyid, curuid, verbose, html);
492 list_subkeys(dbctx, keys->subkeys, verbose, html);
506 * mrkey_index - List a set of OpenPGP keys in the MRHKP format.
507 * @keys: The keys to display.
509 * This function takes a list of OpenPGP public keys and displays a
510 * machine readable list of them.
512 int mrkey_index(struct openpgp_publickey *keys)
514 struct openpgp_signedpacket_list *curuid = NULL;
515 time_t created_time = 0;
521 struct openpgp_fingerprint fingerprint;
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];
531 switch (keys->publickey->data[0]) {
534 if (get_keyid(keys, &keyid) != ONAK_E_OK) {
535 logthing(LOGTHING_ERROR, "Couldn't get keyid");
537 printf("%016" PRIX64, keyid);
538 type = keys->publickey->data[7];
542 (void) get_fingerprint(keys->publickey, &fingerprint);
544 for (i = 0; i < fingerprint.length; i++) {
545 printf("%02X", fingerprint.fp[i]);
548 type = keys->publickey->data[5];
551 logthing(LOGTHING_ERROR, "Unknown key version: %d",
552 keys->publickey->data[0]);
554 length = keylength(keys->publickey);
556 printf(":%d:%d:%ld::%s\n",
560 (keys->revoked) ? "r" : "");
562 for (curuid = keys->uids; curuid != NULL;
563 curuid = curuid->next) {
565 if (curuid->packet->tag == OPENPGP_PACKET_UID) {
567 for (i = 0; i < (int) curuid->packet->length;
569 c = curuid->packet->data[i];
573 } else if (c == ':' || c > 127) {