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"
31 #include "keystructs.h"
37 * Convert a Public Key algorithm to its single character representation.
39 char pkalgo2char(uint8_t algo)
44 case OPENPGP_PKALGO_DSA:
47 case OPENPGP_PKALGO_ECDSA:
48 case OPENPGP_PKALGO_EDDSA:
51 case OPENPGP_PKALGO_EC:
54 case OPENPGP_PKALGO_ELGAMAL_SIGN:
57 case OPENPGP_PKALGO_ELGAMAL_ENC:
60 case OPENPGP_PKALGO_RSA:
63 case OPENPGP_PKALGO_RSA_ENC:
66 case OPENPGP_PKALGO_RSA_SIGN:
78 * Given a public key/subkey packet return the key length.
80 unsigned int keylength(struct openpgp_packet *keydata)
86 switch (keydata->data[0]) {
89 length = (keydata->data[8] << 8) +
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) {
105 } else if (oid == ONAK_OID_ED25519) {
107 } else if (oid == ONAK_OID_NISTP256) {
109 } else if (oid == ONAK_OID_NISTP384) {
111 } else if (oid == ONAK_OID_NISTP521) {
113 } else if (oid == ONAK_OID_BRAINPOOLP256R1) {
115 } else if (oid == ONAK_OID_BRAINPOOLP384R1) {
117 } else if (oid == ONAK_OID_BRAINPOOLP512R1) {
119 } else if (oid == ONAK_OID_SECP256K1) {
122 logthing(LOGTHING_ERROR,
123 "Unknown elliptic curve size");
128 length = (keydata->data[keyofs] << 8) +
129 keydata->data[keyofs + 1];
133 logthing(LOGTHING_ERROR, "Unknown key version: %d",
141 int list_sigs(struct onak_dbctx *dbctx,
142 struct openpgp_packet_list *sigs, bool html)
148 while (sigs != NULL) {
149 sigid = sig_keyid(sigs->packet);
151 uid = dbctx->keyid2uid(dbctx, sigid);
153 if (sigs->packet->data[0] == 4 &&
154 sigs->packet->data[1] == 0x30) {
155 /* It's a Type 4 sig revocation */
160 if (html && uid != NULL) {
161 printf("%s <a href=\"lookup?op=get&"
162 "search=0x%016" PRIX64 "\">0x%016" PRIX64
164 "<a href=\"lookup?op=vindex&search=0x%016"
165 PRIX64 "\">%s</a>\n",
171 } else if (html && uid == NULL) {
172 printf("%s 0x%016" PRIX64 " "
173 "[User id not found]\n",
177 printf("%s 0x%016" PRIX64
181 (uid != NULL) ? uid :
182 "[User id not found]");
194 int list_uids(struct onak_dbctx *dbctx,
195 uint64_t keyid, struct openpgp_signedpacket_list *uids,
196 bool verbose, bool html)
201 while (uids != NULL) {
202 if (uids->packet->tag == OPENPGP_PACKET_UID) {
203 snprintf(buf, 1023, "%.*s",
204 (int) uids->packet->length,
207 (html) ? txt2html(buf) : buf);
208 } else if (uids->packet->tag == OPENPGP_PACKET_UAT) {
211 printf("<img src=\"lookup?op=photo&search="
212 "0x%016" PRIX64 "&idx=%d\" alt=\""
218 printf("[photo id]\n");
222 list_sigs(dbctx, uids->sigs, html);
230 int list_subkeys(struct onak_dbctx *dbctx,
231 struct openpgp_signedpacket_list *subkeys, bool verbose,
234 struct tm *created = NULL;
235 time_t created_time = 0;
240 while (subkeys != NULL) {
241 if (subkeys->packet->tag == OPENPGP_PACKET_PUBLICSUBKEY) {
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);
249 switch (subkeys->packet->data[0]) {
252 type = subkeys->packet->data[7];
256 type = subkeys->packet->data[5];
259 logthing(LOGTHING_ERROR,
260 "Unknown key version: %d",
261 subkeys->packet->data[0]);
263 length = keylength(subkeys->packet);
265 if (get_packetid(subkeys->packet,
266 &keyid) != ONAK_E_OK) {
267 logthing(LOGTHING_ERROR, "Couldn't get keyid.");
269 printf("sub %5d%c/0x%016" PRIX64 " %04d/%02d/%02d\n",
273 created->tm_year + 1900,
279 list_sigs(dbctx, subkeys->sigs, html);
281 subkeys = subkeys->next;
287 void display_fingerprint(struct openpgp_publickey *key)
290 struct openpgp_fingerprint fingerprint;
292 get_fingerprint(key->publickey, &fingerprint);
293 printf(" Key fingerprint =");
294 for (i = 0; i < fingerprint.length; i++) {
295 if ((fingerprint.length == 16) ||
299 if (fingerprint.length == 20 &&
300 (i * 2) == fingerprint.length) {
301 /* Extra space in the middle of a SHA1 fingerprint */
304 printf("%02X", fingerprint.fp[i]);
311 void display_skshash(struct openpgp_publickey *key, bool html)
316 get_skshash(key, &hash);
317 printf(" Key hash = ");
319 printf("<a href=\"lookup?op=hget&search=");
320 for (i = 0; i < sizeof(hash.hash); i++) {
321 printf("%02X", hash.hash[i]);
325 for (i = 0; i < sizeof(hash.hash); i++) {
326 printf("%02X", hash.hash[i]);
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?
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.
346 int key_index(struct onak_dbctx *dbctx,
347 struct openpgp_publickey *keys, bool verbose, bool fingerprint,
348 bool skshash, bool html)
350 struct openpgp_signedpacket_list *curuid = NULL;
351 struct tm *created = NULL;
352 time_t created_time = 0;
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);
369 switch (keys->publickey->data[0]) {
372 type = keys->publickey->data[7];
376 type = keys->publickey->data[5];
379 logthing(LOGTHING_ERROR, "Unknown key version: %d",
380 keys->publickey->data[0]);
382 length = keylength(keys->publickey);
384 if (get_keyid(keys, &keyid) != ONAK_E_OK) {
385 logthing(LOGTHING_ERROR, "Couldn't get keyid.");
389 printf("pub %5d%c/<a href=\"lookup?op=get&"
390 "search=0x%016" PRIX64 "\">0x%016" PRIX64
391 "</a> %04d/%02d/%02d ",
396 created->tm_year + 1900,
400 printf("pub %5d%c/0x%016" PRIX64 " %04d/%02d/%02d ",
404 created->tm_year + 1900,
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);
416 printf("<a href=\"lookup?op=vindex&"
417 "search=0x%016" PRIX64 "\">",
421 (html) ? txt2html(buf) : buf,
422 (html) ? "</a>" : "",
423 (keys->revoked) ? " *** REVOKED ***" : "");
425 display_skshash(keys, html);
428 display_fingerprint(keys);
431 list_sigs(dbctx, curuid->sigs, html);
433 curuid = curuid->next;
436 (keys->revoked) ? "*** REVOKED ***": "");
438 display_fingerprint(keys);
442 list_uids(dbctx, keyid, curuid, verbose, html);
444 list_subkeys(dbctx, keys->subkeys, verbose, html);
458 * mrkey_index - List a set of OpenPGP keys in the MRHKP format.
459 * @keys: The keys to display.
461 * This function takes a list of OpenPGP public keys and displays a
462 * machine readable list of them.
464 int mrkey_index(struct openpgp_publickey *keys)
466 struct openpgp_signedpacket_list *curuid = NULL;
467 time_t created_time = 0;
473 struct openpgp_fingerprint fingerprint;
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];
483 switch (keys->publickey->data[0]) {
486 if (get_keyid(keys, &keyid) != ONAK_E_OK) {
487 logthing(LOGTHING_ERROR, "Couldn't get keyid");
489 printf("%016" PRIX64, keyid);
490 type = keys->publickey->data[7];
494 (void) get_fingerprint(keys->publickey, &fingerprint);
496 for (i = 0; i < fingerprint.length; i++) {
497 printf("%02X", fingerprint.fp[i]);
500 type = keys->publickey->data[5];
503 logthing(LOGTHING_ERROR, "Unknown key version: %d",
504 keys->publickey->data[0]);
506 length = keylength(keys->publickey);
508 printf(":%d:%d:%ld::%s\n",
512 (keys->revoked) ? "r" : "");
514 for (curuid = keys->uids; curuid != NULL;
515 curuid = curuid->next) {
517 if (curuid->packet->tag == OPENPGP_PACKET_UID) {
519 for (i = 0; i < (int) curuid->packet->length;
521 c = curuid->packet->data[i];
525 } else if (c == ':' || c > 127) {