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)
85 switch (keydata->data[0]) {
88 length = (keydata->data[8] << 8) +
93 /* v5 has an additional 4 bytes of key length data */
94 keyofs = (keydata->data[0] == 4) ? 6 : 10;
95 switch (keydata->data[5]) {
96 case OPENPGP_PKALGO_EC:
97 case OPENPGP_PKALGO_ECDSA:
98 case OPENPGP_PKALGO_EDDSA:
99 /* Elliptic curve key size is based on OID */
100 /* Curve25519 / 1.3.6.1.4.1.3029.1.5.1 */
101 if ((keydata->data[keyofs] == 10) &&
102 (keydata->data[keyofs + 1] == 0x2B) &&
103 (keydata->data[keyofs + 2] == 0x06) &&
104 (keydata->data[keyofs + 3] == 0x01) &&
105 (keydata->data[keyofs + 4] == 0x04) &&
106 (keydata->data[keyofs + 5] == 0x01) &&
107 (keydata->data[keyofs + 6] == 0x97) &&
108 (keydata->data[keyofs + 7] == 0x55) &&
109 (keydata->data[keyofs + 8] == 0x01) &&
110 (keydata->data[keyofs + 9] == 0x05) &&
111 (keydata->data[keyofs + 10] == 0x01)) {
113 /* Ed25519 / 1.3.6.1.4.1.11591.15.1 */
114 } else if ((keydata->data[keyofs] == 9) &&
115 (keydata->data[keyofs + 1] == 0x2B) &&
116 (keydata->data[keyofs + 2] == 0x06) &&
117 (keydata->data[keyofs + 3] == 0x01) &&
118 (keydata->data[keyofs + 4] == 0x04) &&
119 (keydata->data[keyofs + 5] == 0x01) &&
120 (keydata->data[keyofs + 6] == 0xDA) &&
121 (keydata->data[keyofs + 7] == 0x47) &&
122 (keydata->data[keyofs + 8] == 0x0F) &&
123 (keydata->data[keyofs + 9] == 0x01)) {
125 /* nistp256 / 1.2.840.10045.3.1.7 */
126 } else if ((keydata->data[keyofs] == 8) &&
127 (keydata->data[keyofs + 1] == 0x2A) &&
128 (keydata->data[keyofs + 2] == 0x86) &&
129 (keydata->data[keyofs + 3] == 0x48) &&
130 (keydata->data[keyofs + 4] == 0xCE) &&
131 (keydata->data[keyofs + 5] == 0x3D) &&
132 (keydata->data[keyofs + 6] == 0x03) &&
133 (keydata->data[keyofs + 7] == 0x01) &&
134 (keydata->data[keyofs + 8] == 0x07)) {
136 /* nistp384 / 1.3.132.0.34 */
137 } else if ((keydata->data[keyofs] == 5) &&
138 (keydata->data[keyofs + 1] == 0x2B) &&
139 (keydata->data[keyofs + 2] == 0x81) &&
140 (keydata->data[keyofs + 3] == 0x04) &&
141 (keydata->data[keyofs + 4] == 0x00) &&
142 (keydata->data[keyofs + 5] == 0x22)) {
144 /* nistp521 / 1.3.132.0.35 */
145 } else if ((keydata->data[keyofs] == 5) &&
146 (keydata->data[keyofs + 1] == 0x2B) &&
147 (keydata->data[keyofs + 2] == 0x81) &&
148 (keydata->data[keyofs + 3] == 0x04) &&
149 (keydata->data[keyofs + 4] == 0x00) &&
150 (keydata->data[keyofs + 5] == 0x23)) {
152 /* brainpoolP256r1 / 1.3.36.3.3.2.8.1.1.7 */
153 } else if ((keydata->data[keyofs] == 9) &&
154 (keydata->data[keyofs + 1] == 0x2B) &&
155 (keydata->data[keyofs + 2] == 0x24) &&
156 (keydata->data[keyofs + 3] == 0x03) &&
157 (keydata->data[keyofs + 4] == 0x03) &&
158 (keydata->data[keyofs + 5] == 0x02) &&
159 (keydata->data[keyofs + 6] == 0x08) &&
160 (keydata->data[keyofs + 7] == 0x01) &&
161 (keydata->data[keyofs + 8] == 0x01) &&
162 (keydata->data[keyofs + 9] == 0x07)) {
164 /* brainpoolP384r1 / 1.3.36.3.3.2.8.1.1.11 */
165 } else if ((keydata->data[keyofs] == 9) &&
166 (keydata->data[keyofs + 1] == 0x2B) &&
167 (keydata->data[keyofs + 2] == 0x24) &&
168 (keydata->data[keyofs + 3] == 0x03) &&
169 (keydata->data[keyofs + 4] == 0x03) &&
170 (keydata->data[keyofs + 5] == 0x02) &&
171 (keydata->data[keyofs + 6] == 0x08) &&
172 (keydata->data[keyofs + 7] == 0x01) &&
173 (keydata->data[keyofs + 8] == 0x01) &&
174 (keydata->data[keyofs + 9] == 0x0B)) {
176 /* brainpoolP512r1 / 1.3.36.3.3.2.8.1.1.13 */
177 } else if ((keydata->data[keyofs] == 9) &&
178 (keydata->data[keyofs + 1] == 0x2B) &&
179 (keydata->data[keyofs + 2] == 0x24) &&
180 (keydata->data[keyofs + 3] == 0x03) &&
181 (keydata->data[keyofs + 4] == 0x03) &&
182 (keydata->data[keyofs + 5] == 0x02) &&
183 (keydata->data[keyofs + 6] == 0x08) &&
184 (keydata->data[keyofs + 7] == 0x01) &&
185 (keydata->data[keyofs + 8] == 0x01) &&
186 (keydata->data[keyofs + 9] == 0x0D)) {
188 /* secp256k1 / 1.3.132.0.10 */
189 } else if ((keydata->data[keyofs] == 5) &&
190 (keydata->data[keyofs + 1] == 0x2B) &&
191 (keydata->data[keyofs + 2] == 0x81) &&
192 (keydata->data[keyofs + 3] == 0x04) &&
193 (keydata->data[keyofs + 4] == 0x00) &&
194 (keydata->data[keyofs + 5] == 0x0A)) {
197 logthing(LOGTHING_ERROR,
198 "Unknown elliptic curve size");
203 length = (keydata->data[keyofs] << 8) +
204 keydata->data[keyofs + 1];
208 logthing(LOGTHING_ERROR, "Unknown key version: %d",
216 int list_sigs(struct onak_dbctx *dbctx,
217 struct openpgp_packet_list *sigs, bool html)
223 while (sigs != NULL) {
224 sigid = sig_keyid(sigs->packet);
226 uid = dbctx->keyid2uid(dbctx, sigid);
228 if (sigs->packet->data[0] == 4 &&
229 sigs->packet->data[1] == 0x30) {
230 /* It's a Type 4 sig revocation */
235 if (html && uid != NULL) {
236 printf("%s <a href=\"lookup?op=get&"
237 "search=0x%016" PRIX64 "\">0x%016" PRIX64
239 "<a href=\"lookup?op=vindex&search=0x%016"
240 PRIX64 "\">%s</a>\n",
246 } else if (html && uid == NULL) {
247 printf("%s 0x%016" PRIX64 " "
248 "[User id not found]\n",
252 printf("%s 0x%016" PRIX64
256 (uid != NULL) ? uid :
257 "[User id not found]");
269 int list_uids(struct onak_dbctx *dbctx,
270 uint64_t keyid, struct openpgp_signedpacket_list *uids,
271 bool verbose, bool html)
276 while (uids != NULL) {
277 if (uids->packet->tag == OPENPGP_PACKET_UID) {
278 snprintf(buf, 1023, "%.*s",
279 (int) uids->packet->length,
282 (html) ? txt2html(buf) : buf);
283 } else if (uids->packet->tag == OPENPGP_PACKET_UAT) {
286 printf("<img src=\"lookup?op=photo&search="
287 "0x%016" PRIX64 "&idx=%d\" alt=\""
293 printf("[photo id]\n");
297 list_sigs(dbctx, uids->sigs, html);
305 int list_subkeys(struct onak_dbctx *dbctx,
306 struct openpgp_signedpacket_list *subkeys, bool verbose,
309 struct tm *created = NULL;
310 time_t created_time = 0;
315 while (subkeys != NULL) {
316 if (subkeys->packet->tag == OPENPGP_PACKET_PUBLICSUBKEY) {
318 created_time = (subkeys->packet->data[1] << 24) +
319 (subkeys->packet->data[2] << 16) +
320 (subkeys->packet->data[3] << 8) +
321 subkeys->packet->data[4];
322 created = gmtime(&created_time);
324 switch (subkeys->packet->data[0]) {
327 type = subkeys->packet->data[7];
331 type = subkeys->packet->data[5];
334 logthing(LOGTHING_ERROR,
335 "Unknown key version: %d",
336 subkeys->packet->data[0]);
338 length = keylength(subkeys->packet);
340 if (get_packetid(subkeys->packet,
341 &keyid) != ONAK_E_OK) {
342 logthing(LOGTHING_ERROR, "Couldn't get keyid.");
344 printf("sub %5d%c/0x%016" PRIX64 " %04d/%02d/%02d\n",
348 created->tm_year + 1900,
354 list_sigs(dbctx, subkeys->sigs, html);
356 subkeys = subkeys->next;
362 void display_fingerprint(struct openpgp_publickey *key)
365 struct openpgp_fingerprint fingerprint;
367 get_fingerprint(key->publickey, &fingerprint);
368 printf(" Key fingerprint =");
369 for (i = 0; i < fingerprint.length; i++) {
370 if ((fingerprint.length == 16) ||
374 if (fingerprint.length == 20 &&
375 (i * 2) == fingerprint.length) {
376 /* Extra space in the middle of a SHA1 fingerprint */
379 printf("%02X", fingerprint.fp[i]);
386 void display_skshash(struct openpgp_publickey *key, bool html)
391 get_skshash(key, &hash);
392 printf(" Key hash = ");
394 printf("<a href=\"lookup?op=hget&search=");
395 for (i = 0; i < sizeof(hash.hash); i++) {
396 printf("%02X", hash.hash[i]);
400 for (i = 0; i < sizeof(hash.hash); i++) {
401 printf("%02X", hash.hash[i]);
412 * key_index - List a set of OpenPGP keys.
413 * @keys: The keys to display.
414 * @verbose: Should we list sigs as well?
415 * @fingerprint: List the fingerprint?
416 * @html: Should the output be tailored for HTML?
418 * This function takes a list of OpenPGP public keys and displays an index
419 * of them. Useful for debugging or the keyserver Index function.
421 int key_index(struct onak_dbctx *dbctx,
422 struct openpgp_publickey *keys, bool verbose, bool fingerprint,
423 bool skshash, bool html)
425 struct openpgp_signedpacket_list *curuid = NULL;
426 struct tm *created = NULL;
427 time_t created_time = 0;
436 puts("Type bits/keyID Date User ID");
437 while (keys != NULL) {
438 created_time = (keys->publickey->data[1] << 24) +
439 (keys->publickey->data[2] << 16) +
440 (keys->publickey->data[3] << 8) +
441 keys->publickey->data[4];
442 created = gmtime(&created_time);
444 switch (keys->publickey->data[0]) {
447 type = keys->publickey->data[7];
451 type = keys->publickey->data[5];
454 logthing(LOGTHING_ERROR, "Unknown key version: %d",
455 keys->publickey->data[0]);
457 length = keylength(keys->publickey);
459 if (get_keyid(keys, &keyid) != ONAK_E_OK) {
460 logthing(LOGTHING_ERROR, "Couldn't get keyid.");
464 printf("pub %5d%c/<a href=\"lookup?op=get&"
465 "search=0x%016" PRIX64 "\">0x%016" PRIX64
466 "</a> %04d/%02d/%02d ",
471 created->tm_year + 1900,
475 printf("pub %5d%c/0x%016" PRIX64 " %04d/%02d/%02d ",
479 created->tm_year + 1900,
485 if (curuid != NULL &&
486 curuid->packet->tag == OPENPGP_PACKET_UID) {
487 snprintf(buf, 1023, "%.*s",
488 (int) curuid->packet->length,
489 curuid->packet->data);
491 printf("<a href=\"lookup?op=vindex&"
492 "search=0x%016" PRIX64 "\">",
496 (html) ? txt2html(buf) : buf,
497 (html) ? "</a>" : "",
498 (keys->revoked) ? " *** REVOKED ***" : "");
500 display_skshash(keys, html);
503 display_fingerprint(keys);
506 list_sigs(dbctx, curuid->sigs, html);
508 curuid = curuid->next;
511 (keys->revoked) ? "*** REVOKED ***": "");
513 display_fingerprint(keys);
517 list_uids(dbctx, keyid, curuid, verbose, html);
519 list_subkeys(dbctx, keys->subkeys, verbose, html);
533 * mrkey_index - List a set of OpenPGP keys in the MRHKP format.
534 * @keys: The keys to display.
536 * This function takes a list of OpenPGP public keys and displays a
537 * machine readable list of them.
539 int mrkey_index(struct openpgp_publickey *keys)
541 struct openpgp_signedpacket_list *curuid = NULL;
542 time_t created_time = 0;
548 struct openpgp_fingerprint fingerprint;
550 while (keys != NULL) {
551 created_time = (keys->publickey->data[1] << 24) +
552 (keys->publickey->data[2] << 16) +
553 (keys->publickey->data[3] << 8) +
554 keys->publickey->data[4];
558 switch (keys->publickey->data[0]) {
561 if (get_keyid(keys, &keyid) != ONAK_E_OK) {
562 logthing(LOGTHING_ERROR, "Couldn't get keyid");
564 printf("%016" PRIX64, keyid);
565 type = keys->publickey->data[7];
569 (void) get_fingerprint(keys->publickey, &fingerprint);
571 for (i = 0; i < fingerprint.length; i++) {
572 printf("%02X", fingerprint.fp[i]);
575 type = keys->publickey->data[5];
578 logthing(LOGTHING_ERROR, "Unknown key version: %d",
579 keys->publickey->data[0]);
581 length = keylength(keys->publickey);
583 printf(":%d:%d:%ld::%s\n",
587 (keys->revoked) ? "r" : "");
589 for (curuid = keys->uids; curuid != NULL;
590 curuid = curuid->next) {
592 if (curuid->packet->tag == OPENPGP_PACKET_UID) {
594 for (i = 0; i < (int) curuid->packet->length;
596 c = curuid->packet->data[i];
600 } else if (c == ':' || c > 127) {