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, write to the Free Software Foundation, Inc., 51
17 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include "decodekey.h"
32 #include "keystructs.h"
38 * Convert a Public Key algorithm to its single character representation.
40 char pkalgo2char(uint8_t algo)
45 case OPENPGP_PKALGO_DSA:
48 case OPENPGP_PKALGO_ECDSA:
49 case OPENPGP_PKALGO_EDDSA:
52 case OPENPGP_PKALGO_EC:
55 case OPENPGP_PKALGO_ELGAMAL_SIGN:
58 case OPENPGP_PKALGO_ELGAMAL_ENC:
61 case OPENPGP_PKALGO_RSA:
64 case OPENPGP_PKALGO_RSA_ENC:
67 case OPENPGP_PKALGO_RSA_SIGN:
79 * Given a public key/subkey packet return the key length.
81 unsigned int keylength(struct openpgp_packet *keydata)
85 switch (keydata->data[0]) {
88 length = (keydata->data[8] << 8) +
92 switch (keydata->data[5]) {
93 case OPENPGP_PKALGO_EC:
94 case OPENPGP_PKALGO_ECDSA:
95 case OPENPGP_PKALGO_EDDSA:
96 /* Elliptic curve key size is based on OID */
97 /* Curve25519 / 1.3.6.1.4.1.3029.1.5.1 */
98 if ((keydata->data[6] == 10) &&
99 (keydata->data[7] == 0x2B) &&
100 (keydata->data[8] == 0x06) &&
101 (keydata->data[9] == 0x01) &&
102 (keydata->data[10] == 0x04) &&
103 (keydata->data[11] == 0x01) &&
104 (keydata->data[12] == 0x97) &&
105 (keydata->data[13] == 0x55) &&
106 (keydata->data[14] == 0x01) &&
107 (keydata->data[15] == 0x05) &&
108 (keydata->data[16] == 0x01)) {
110 /* Ed25519 / 1.3.6.1.4.1.11591.15.1 */
111 } else if ((keydata->data[6] == 9) &&
112 (keydata->data[7] == 0x2B) &&
113 (keydata->data[8] == 0x06) &&
114 (keydata->data[9] == 0x01) &&
115 (keydata->data[10] == 0x04) &&
116 (keydata->data[11] == 0x01) &&
117 (keydata->data[12] == 0xDA) &&
118 (keydata->data[13] == 0x47) &&
119 (keydata->data[14] == 0x0F) &&
120 (keydata->data[15] == 0x01)) {
122 /* nistp256 / 1.2.840.10045.3.1.7 */
123 } else if ((keydata->data[6] == 8) &&
124 (keydata->data[7] == 0x2A) &&
125 (keydata->data[8] == 0x86) &&
126 (keydata->data[9] == 0x48) &&
127 (keydata->data[10] == 0xCE) &&
128 (keydata->data[11] == 0x3D) &&
129 (keydata->data[12] == 0x03) &&
130 (keydata->data[13] == 0x01) &&
131 (keydata->data[14] == 0x07)) {
133 /* nistp384 / 1.3.132.0.34 */
134 } else if ((keydata->data[6] == 5) &&
135 (keydata->data[7] == 0x2B) &&
136 (keydata->data[8] == 0x81) &&
137 (keydata->data[9] == 0x04) &&
138 (keydata->data[10] == 0x00) &&
139 (keydata->data[11] == 0x22)) {
141 /* nistp521 / 1.3.132.0.35 */
142 } else if ((keydata->data[6] == 5) &&
143 (keydata->data[7] == 0x2B) &&
144 (keydata->data[8] == 0x81) &&
145 (keydata->data[9] == 0x04) &&
146 (keydata->data[10] == 0x00) &&
147 (keydata->data[11] == 0x23)) {
149 /* brainpoolP256r1 / 1.3.36.3.3.2.8.1.1.7 */
150 } else if ((keydata->data[6] == 9) &&
151 (keydata->data[7] == 0x2B) &&
152 (keydata->data[8] == 0x24) &&
153 (keydata->data[9] == 0x03) &&
154 (keydata->data[10] == 0x03) &&
155 (keydata->data[11] == 0x02) &&
156 (keydata->data[12] == 0x08) &&
157 (keydata->data[13] == 0x01) &&
158 (keydata->data[14] == 0x01) &&
159 (keydata->data[15] == 0x07)) {
161 /* brainpoolP384r1 / 1.3.36.3.3.2.8.1.1.11 */
162 } else if ((keydata->data[6] == 9) &&
163 (keydata->data[7] == 0x2B) &&
164 (keydata->data[8] == 0x24) &&
165 (keydata->data[9] == 0x03) &&
166 (keydata->data[10] == 0x03) &&
167 (keydata->data[11] == 0x02) &&
168 (keydata->data[12] == 0x08) &&
169 (keydata->data[13] == 0x01) &&
170 (keydata->data[14] == 0x01) &&
171 (keydata->data[15] == 0x0B)) {
173 /* brainpoolP512r1 / 1.3.36.3.3.2.8.1.1.13 */
174 } else if ((keydata->data[6] == 9) &&
175 (keydata->data[7] == 0x2B) &&
176 (keydata->data[8] == 0x24) &&
177 (keydata->data[9] == 0x03) &&
178 (keydata->data[10] == 0x03) &&
179 (keydata->data[11] == 0x02) &&
180 (keydata->data[12] == 0x08) &&
181 (keydata->data[13] == 0x01) &&
182 (keydata->data[14] == 0x01) &&
183 (keydata->data[15] == 0x0D)) {
185 /* secp256k1 / 1.3.132.0.10 */
186 } else if ((keydata->data[6] == 5) &&
187 (keydata->data[7] == 0x2B) &&
188 (keydata->data[8] == 0x81) &&
189 (keydata->data[9] == 0x04) &&
190 (keydata->data[10] == 0x00) &&
191 (keydata->data[11] == 0x0A)) {
194 logthing(LOGTHING_ERROR,
195 "Unknown elliptic curve size");
200 length = (keydata->data[6] << 8) +
205 logthing(LOGTHING_ERROR, "Unknown key version: %d",
213 int list_sigs(struct onak_dbctx *dbctx,
214 struct openpgp_packet_list *sigs, bool html)
220 while (sigs != NULL) {
221 sigid = sig_keyid(sigs->packet);
222 uid = dbctx->keyid2uid(dbctx, sigid);
223 if (sigs->packet->data[0] == 4 &&
224 sigs->packet->data[1] == 0x30) {
225 /* It's a Type 4 sig revocation */
230 if (html && uid != NULL) {
231 printf("%s <a href=\"lookup?op=get&"
232 "search=0x%016" PRIX64 "\">%08" PRIX64
234 "<a href=\"lookup?op=vindex&search=0x%016"
235 PRIX64 "\">%s</a>\n",
241 } else if (html && uid == NULL) {
242 printf("%s %08" PRIX64 " "
243 "[User id not found]\n",
247 printf("%s %08" PRIX64
251 (uid != NULL) ? uid :
252 "[User id not found]");
264 int list_uids(struct onak_dbctx *dbctx,
265 uint64_t keyid, struct openpgp_signedpacket_list *uids,
266 bool verbose, bool html)
271 while (uids != NULL) {
272 if (uids->packet->tag == OPENPGP_PACKET_UID) {
273 snprintf(buf, 1023, "%.*s",
274 (int) uids->packet->length,
277 (html) ? txt2html(buf) : buf);
278 } else if (uids->packet->tag == OPENPGP_PACKET_UAT) {
281 printf("<img src=\"lookup?op=photo&search="
282 "0x%016" PRIX64 "&idx=%d\" alt=\""
288 printf("[photo id]\n");
292 list_sigs(dbctx, uids->sigs, html);
300 int list_subkeys(struct onak_dbctx *dbctx,
301 struct openpgp_signedpacket_list *subkeys, bool verbose,
304 struct tm *created = NULL;
305 time_t created_time = 0;
310 while (subkeys != NULL) {
311 if (subkeys->packet->tag == OPENPGP_PACKET_PUBLICSUBKEY) {
313 created_time = (subkeys->packet->data[1] << 24) +
314 (subkeys->packet->data[2] << 16) +
315 (subkeys->packet->data[3] << 8) +
316 subkeys->packet->data[4];
317 created = gmtime(&created_time);
319 switch (subkeys->packet->data[0]) {
322 type = subkeys->packet->data[7];
325 type = subkeys->packet->data[5];
328 logthing(LOGTHING_ERROR,
329 "Unknown key type: %d",
330 subkeys->packet->data[0]);
332 length = keylength(subkeys->packet);
334 if (get_packetid(subkeys->packet,
335 &keyid) != ONAK_E_OK) {
336 logthing(LOGTHING_ERROR, "Couldn't get keyid.");
338 printf("sub %5d%c/%08X %04d/%02d/%02d\n",
341 (uint32_t) (keyid & 0xFFFFFFFF),
342 created->tm_year + 1900,
348 list_sigs(dbctx, subkeys->sigs, html);
350 subkeys = subkeys->next;
356 void display_fingerprint(struct openpgp_publickey *key)
359 struct openpgp_fingerprint fingerprint;
361 get_fingerprint(key->publickey, &fingerprint);
362 printf(" Key fingerprint =");
363 for (i = 0; i < fingerprint.length; i++) {
364 if ((fingerprint.length == 16) ||
368 if (fingerprint.length == 20 &&
369 (i * 2) == fingerprint.length) {
370 /* Extra space in the middle of a SHA1 fingerprint */
373 printf("%02X", fingerprint.fp[i]);
380 void display_skshash(struct openpgp_publickey *key, bool html)
385 get_skshash(key, &hash);
386 printf(" Key hash = ");
388 printf("<a href=\"lookup?op=hget&search=");
389 for (i = 0; i < sizeof(hash.hash); i++) {
390 printf("%02X", hash.hash[i]);
394 for (i = 0; i < sizeof(hash.hash); i++) {
395 printf("%02X", hash.hash[i]);
406 * key_index - List a set of OpenPGP keys.
407 * @keys: The keys to display.
408 * @verbose: Should we list sigs as well?
409 * @fingerprint: List the fingerprint?
410 * @html: Should the output be tailored for HTML?
412 * This function takes a list of OpenPGP public keys and displays an index
413 * of them. Useful for debugging or the keyserver Index function.
415 int key_index(struct onak_dbctx *dbctx,
416 struct openpgp_publickey *keys, bool verbose, bool fingerprint,
417 bool skshash, bool html)
419 struct openpgp_signedpacket_list *curuid = NULL;
420 struct tm *created = NULL;
421 time_t created_time = 0;
430 puts("Type bits/keyID Date User ID");
431 while (keys != NULL) {
432 created_time = (keys->publickey->data[1] << 24) +
433 (keys->publickey->data[2] << 16) +
434 (keys->publickey->data[3] << 8) +
435 keys->publickey->data[4];
436 created = gmtime(&created_time);
438 switch (keys->publickey->data[0]) {
441 type = keys->publickey->data[7];
444 type = keys->publickey->data[5];
447 logthing(LOGTHING_ERROR, "Unknown key type: %d",
448 keys->publickey->data[0]);
450 length = keylength(keys->publickey);
452 if (get_keyid(keys, &keyid) != ONAK_E_OK) {
453 logthing(LOGTHING_ERROR, "Couldn't get keyid.");
457 printf("pub %5d%c/<a href=\"lookup?op=get&"
458 "search=0x%016" PRIX64 "\">%08" PRIX64
459 "</a> %04d/%02d/%02d ",
464 created->tm_year + 1900,
468 printf("pub %5d%c/%08" PRIX64 " %04d/%02d/%02d ",
472 created->tm_year + 1900,
478 if (curuid != NULL &&
479 curuid->packet->tag == OPENPGP_PACKET_UID) {
480 snprintf(buf, 1023, "%.*s",
481 (int) curuid->packet->length,
482 curuid->packet->data);
484 printf("<a href=\"lookup?op=vindex&"
485 "search=0x%016" PRIX64 "\">",
489 (html) ? txt2html(buf) : buf,
490 (html) ? "</a>" : "",
491 (keys->revoked) ? " *** REVOKED ***" : "");
493 display_skshash(keys, html);
496 display_fingerprint(keys);
499 list_sigs(dbctx, curuid->sigs, html);
501 curuid = curuid->next;
504 (keys->revoked) ? "*** REVOKED ***": "");
506 display_fingerprint(keys);
510 list_uids(dbctx, keyid, curuid, verbose, html);
512 list_subkeys(dbctx, keys->subkeys, verbose, html);
526 * mrkey_index - List a set of OpenPGP keys in the MRHKP format.
527 * @keys: The keys to display.
529 * This function takes a list of OpenPGP public keys and displays a
530 * machine readable list of them.
532 int mrkey_index(struct openpgp_publickey *keys)
534 struct openpgp_signedpacket_list *curuid = NULL;
535 time_t created_time = 0;
541 struct openpgp_fingerprint fingerprint;
543 while (keys != NULL) {
544 created_time = (keys->publickey->data[1] << 24) +
545 (keys->publickey->data[2] << 16) +
546 (keys->publickey->data[3] << 8) +
547 keys->publickey->data[4];
551 switch (keys->publickey->data[0]) {
554 if (get_keyid(keys, &keyid) != ONAK_E_OK) {
555 logthing(LOGTHING_ERROR, "Couldn't get keyid");
557 printf("%016" PRIX64, keyid);
558 type = keys->publickey->data[7];
561 (void) get_fingerprint(keys->publickey, &fingerprint);
563 for (i = 0; i < fingerprint.length; i++) {
564 printf("%02X", fingerprint.fp[i]);
567 type = keys->publickey->data[5];
570 logthing(LOGTHING_ERROR, "Unknown key type: %d",
571 keys->publickey->data[0]);
573 length = keylength(keys->publickey);
575 printf(":%d:%d:%ld::%s\n",
579 (keys->revoked) ? "r" : "");
581 for (curuid = keys->uids; curuid != NULL;
582 curuid = curuid->next) {
584 if (curuid->packet->tag == OPENPGP_PACKET_UID) {
586 for (i = 0; i < (int) curuid->packet->length;
588 c = curuid->packet->data[i];
592 } else if (c == ':' || c > 127) {