2 * parsekey.c - Routines to parse an OpenPGP key.
4 * Copyright 2002-2004,2007-2008,2011 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/>.
24 #include "keystructs.h"
32 * parse_keys - Process a stream of packets for public keys + sigs.
33 * @packets: The packet list to parse.
34 * @keys: The returned list of public keys.
36 * This function takes an list of OpenPGP packets and attempts to parse it
37 * into a list of public keys with signatures and subkeys.
39 * Returns a count of how many keys we parsed.
41 int parse_keys(struct openpgp_packet_list *packets,
42 struct openpgp_publickey **keys)
44 struct openpgp_publickey *curkey = NULL;
50 * If keys already has some keys in it then set curkey to the last one
51 * so we add to the end of the list.
53 for (curkey = *keys; curkey != NULL && curkey->next != NULL;
54 curkey = curkey->next) ;
56 while (packets != NULL) {
57 switch (packets->packet->tag) {
58 case OPENPGP_PACKET_SIGNATURE:
60 * It's a signature packet. Add it to either the public
61 * key, to the current UID or the current subkey.
64 return ONAK_E_INVALID_PARAM;
65 if (curkey->subkeys != NULL) {
66 ADD_PACKET_TO_LIST_END(curkey->last_subkey,
68 packet_dup(packets->packet));
69 } else if (curkey->uids != NULL) {
70 ADD_PACKET_TO_LIST_END(curkey->last_uid,
72 packet_dup(packets->packet));
74 ADD_PACKET_TO_LIST_END(curkey,
76 packet_dup(packets->packet));
78 * This is a signature on the public key; check
79 * if it's a revocation.
81 if (packets->packet->data[0] == 3 &&
82 packets->packet->data[2] ==
83 OPENPGP_SIGTYPE_KEY_REV) {
85 * Type 3 key, 0x20 == revocation
87 curkey->revoked = true;
88 } else if (packets->packet->data[0] == 4 &&
89 packets->packet->data[1] ==
90 OPENPGP_SIGTYPE_KEY_REV) {
92 * Type 4 key, 0x20 == revocation
94 curkey->revoked = true;
98 case OPENPGP_PACKET_PUBLICKEY:
100 * It's a public key packet, so start a new key in our
103 if (curkey != NULL) {
104 curkey->next = malloc(sizeof (*curkey));
105 curkey = curkey->next;
108 malloc(sizeof (*curkey));
110 memset(curkey, 0, sizeof(*curkey));
111 curkey->publickey = packet_dup(packets->packet);
114 case OPENPGP_PACKET_UID:
115 case OPENPGP_PACKET_UAT:
117 * It's a UID packet (or a photo id, which is similar).
120 return ONAK_E_INVALID_PARAM;
121 if (curkey->subkeys != NULL)
122 return ONAK_E_INVALID_PARAM;
123 ADD_PACKET_TO_LIST_END(curkey,
125 packet_dup(packets->packet));
127 case OPENPGP_PACKET_PUBLICSUBKEY:
129 * It's a subkey packet.
132 return ONAK_E_INVALID_PARAM;
133 ADD_PACKET_TO_LIST_END(curkey,
135 packet_dup(packets->packet));
137 case OPENPGP_PACKET_TRUST:
138 case OPENPGP_PACKET_COMMENT:
142 * Trust packet. Ignore.
143 * Comment packet. Ignore.
147 /* Unsupported packet. Do what? Ignore for now. */
150 packets = packets->next;
157 * debug_packet - Print debug info about a packet
158 * @packet: The packet to display.
160 * This function takes an OpenPGP packet and displays some information
161 * about it to stdout. Useful for debugging purposes or curiousity about
162 * an OpenPGP packet stream.
164 int debug_packet(struct openpgp_packet *packet)
166 printf("\tNew format: %d, Tag: %u, Length: %zd\n",
175 * read_openpgp_stream - Reads a stream of OpenPGP packets.
176 * @getchar_func: The function to get the next character from the stream.
177 * @ctx: A pointer to the context structure for getchar_func.
178 * @packets: The outputted list of packets.
179 * @maxnum: The maximum number of keys to read. 0 means unlimited.
181 * This function uses getchar_func to read characters from an OpenPGP
182 * packet stream and reads the packets into a linked list of packets
183 * ready for parsing as a public key or whatever.
185 onak_status_t read_openpgp_stream(size_t (*getchar_func)(void *ctx, size_t count,
188 struct openpgp_packet_list **packets,
191 unsigned char curchar = 0;
192 struct openpgp_packet_list *curpacket = NULL, **packetend = NULL;
193 onak_status_t rc = ONAK_E_OK;
197 return ONAK_E_INVALID_PARAM;
199 curpacket = *packets;
200 if (curpacket != NULL) {
201 while (curpacket->next != NULL) {
202 curpacket = curpacket->next;
206 while (rc == ONAK_E_OK && (maxnum == 0 || keys < maxnum) &&
207 (getchar_func(ctx, 1, &curchar) == 1)) {
208 if (curchar & 0x80) {
210 * New packet. Allocate memory for it.
212 if (curpacket != NULL) {
213 curpacket->next = malloc(sizeof (*curpacket));
214 packetend = &curpacket->next;
215 curpacket = curpacket->next;
217 *packets = curpacket =
218 malloc(sizeof (*curpacket));
221 memset(curpacket, 0, sizeof(*curpacket));
223 malloc(sizeof (*curpacket->packet));
224 memset(curpacket->packet, 0,
225 sizeof(*curpacket->packet));
227 curpacket->packet->newformat = (curchar & 0x40);
230 * TODO: Better error checking on getchar_func.
232 if (curpacket->packet->newformat) {
233 curpacket->packet->tag = (curchar & 0x3F);
234 if (getchar_func(ctx, 1, &curchar) == 0) {
235 rc = ONAK_E_INVALID_PKT;
238 curpacket->packet->length = curchar;
239 if (curpacket->packet->length > 191 &&
240 curpacket->packet->length < 224) {
241 rc = getchar_func(ctx, 1, &curchar) ? ONAK_E_OK : ONAK_E_IO_ERROR;
242 curpacket->packet->length -= 192;
243 curpacket->packet->length <<= 8;
244 curpacket->packet->length += curchar;
245 curpacket->packet->length += 192;
246 } else if (curpacket->packet->length > 223 &&
247 curpacket->packet->length < 255) {
248 free(curpacket->packet);
249 curpacket->packet = NULL;
250 rc = ONAK_E_UNSUPPORTED_FEATURE;
251 } else if (curpacket->packet->length == 255) {
253 * 5 byte length; ie 255 followed by 4
254 * bytes of MSB length.
256 if (getchar_func(ctx, 1, &curchar) != 1) {
257 rc = ONAK_E_INVALID_PKT;
260 curpacket->packet->length = curchar;
261 curpacket->packet->length <<= 8;
262 if (getchar_func(ctx, 1, &curchar) != 1) {
263 rc = ONAK_E_INVALID_PKT;
266 curpacket->packet->length += curchar;
267 curpacket->packet->length <<= 8;
268 if (getchar_func(ctx, 1, &curchar) != 1) {
269 rc = ONAK_E_INVALID_PKT;
272 curpacket->packet->length += curchar;
273 curpacket->packet->length <<= 8;
274 if (getchar_func(ctx, 1, &curchar) != 1) {
275 rc = ONAK_E_INVALID_PKT;
278 curpacket->packet->length += curchar;
281 curpacket->packet->tag = (curchar & 0x3C) >> 2;
282 switch (curchar & 3) {
284 if (getchar_func(ctx, 1, &curchar) != 1) {
285 rc = ONAK_E_INVALID_PKT;
288 curpacket->packet->length = curchar;
291 if (getchar_func(ctx, 1, &curchar) != 1) {
292 rc = ONAK_E_INVALID_PKT;
295 curpacket->packet->length = curchar;
296 curpacket->packet->length <<= 8;
297 if (getchar_func(ctx, 1, &curchar) != 1) {
298 rc = ONAK_E_INVALID_PKT;
301 curpacket->packet->length += curchar;
304 if (getchar_func(ctx, 1, &curchar) != 1) {
305 rc = ONAK_E_INVALID_PKT;
308 curpacket->packet->length =
309 ((unsigned) curchar << 24);
310 if (getchar_func(ctx, 1, &curchar) != 1) {
311 rc = ONAK_E_INVALID_PKT;
314 curpacket->packet->length +=
316 if (getchar_func(ctx, 1, &curchar) != 1) {
317 rc = ONAK_E_INVALID_PKT;
320 curpacket->packet->length +=
322 if (getchar_func(ctx, 1, &curchar) != 1) {
323 rc = ONAK_E_INVALID_PKT;
326 curpacket->packet->length += curchar;
329 rc = ONAK_E_UNSUPPORTED_FEATURE;
330 free(curpacket->packet);
331 curpacket->packet = NULL;
337 if (curpacket->packet->tag ==
338 OPENPGP_PACKET_PUBLICKEY) {
341 curpacket->packet->data =
342 malloc(curpacket->packet->length *
343 sizeof(unsigned char));
344 if (curpacket->packet->data == NULL) {
347 rc = getchar_func(ctx,
348 curpacket->packet->length,
349 curpacket->packet->data) ?
350 ONAK_E_OK : ONAK_E_IO_ERROR;
354 rc = ONAK_E_INVALID_PKT;
356 if (rc == ONAK_E_OK) {
357 /* Make sure the packet version is sane */
358 switch (curpacket->packet->tag) {
359 case OPENPGP_PACKET_ENCRYPTED_MDC:
360 /* These packets must be v1 */
361 if (curpacket->packet->data[0] != 1) {
362 rc = ONAK_E_INVALID_PKT;
365 case OPENPGP_PACKET_PKSESSIONKEY:
366 case OPENPGP_PACKET_ONEPASSSIG:
367 /* These packets must be v3 */
368 if (curpacket->packet->data[0] != 3) {
369 rc = ONAK_E_INVALID_PKT;
372 case OPENPGP_PACKET_SYMSESSIONKEY:
373 /* These packets must be v4 */
374 if (curpacket->packet->data[0] != 4) {
375 rc = ONAK_E_INVALID_PKT;
378 case OPENPGP_PACKET_SIGNATURE:
379 case OPENPGP_PACKET_SECRETKEY:
380 case OPENPGP_PACKET_PUBLICKEY:
381 /* Must be v2 onwards */
382 if (curpacket->packet->data[0] < 2) {
383 rc = ONAK_E_INVALID_PKT;
392 if (packetend != NULL) {
393 if ((*packetend)->packet != NULL) {
394 /* If we got an invalid final packet, discard it. */
395 if ((*packetend)->packet->data != NULL &&
397 free((*packetend)->packet->data);
398 (*packetend)->packet->data = NULL;
400 /* If we didn't get any data, clean it up. */
401 if ((*packetend)->packet->data == NULL) {
402 free((*packetend)->packet);
403 (*packetend)->packet = NULL;
406 /* Trim the last packet if it doesn't actually exist */
407 if ((*packetend)->packet == NULL) {
417 * write_openpgp_stream - Reads a stream of OpenPGP packets.
418 * @putchar_func: The function to put the next character to the stream.
419 * @ctx: A pointer to the context structure for putchar_func.
420 * @packets: The list of packets.
422 * This function uses putchar_func to write characters to an OpenPGP
423 * packet stream from a linked list of packets.
425 onak_status_t write_openpgp_stream(size_t (*putchar_func)(void *ctx, size_t count,
428 struct openpgp_packet_list *packets)
430 unsigned char curchar = 0;
432 while (packets != NULL) {
434 if (packets->packet->newformat) {
436 curchar |= packets->packet->tag;
437 putchar_func(ctx, 1, &curchar);
439 if (packets->packet->length < 192) {
440 curchar = packets->packet->length;
441 putchar_func(ctx, 1, &curchar);
442 } else if (packets->packet->length > 191 &&
443 packets->packet->length < 8383) {
444 curchar = (((packets->packet->length - 192) &
446 putchar_func(ctx, 1, &curchar);
448 curchar = (packets->packet->length - 192) &
450 putchar_func(ctx, 1, &curchar);
451 } else if (packets->packet->length > 8382 &&
452 packets->packet->length < 0xFFFFFFFF) {
454 putchar_func(ctx, 1, &curchar);
456 curchar = (packets->packet->length >> 24);
458 putchar_func(ctx, 1, &curchar);
460 curchar = (packets->packet->length >> 16);
462 putchar_func(ctx, 1, &curchar);
464 curchar = (packets->packet->length >> 8);
466 putchar_func(ctx, 1, &curchar);
468 curchar = packets->packet->length;
470 putchar_func(ctx, 1, &curchar);
472 return ONAK_E_UNSUPPORTED_FEATURE;
475 curchar |= (packets->packet->tag << 2);
476 if (packets->packet->length < 256) {
477 putchar_func(ctx, 1, &curchar);
478 curchar = packets->packet->length;
479 putchar_func(ctx, 1, &curchar);
480 } else if (packets->packet->length < 0x10000) {
482 putchar_func(ctx, 1, &curchar);
483 curchar = packets->packet->length >> 8;
484 putchar_func(ctx, 1, &curchar);
485 curchar = packets->packet->length & 0xFF;
486 putchar_func(ctx, 1, &curchar);
489 putchar_func(ctx, 1, &curchar);
490 curchar = packets->packet->length >> 24;
491 putchar_func(ctx, 1, &curchar);
492 curchar = (packets->packet->length >> 16) & 0xFF;
493 putchar_func(ctx, 1, &curchar);
494 curchar = (packets->packet->length >> 8) & 0xFF;
495 putchar_func(ctx, 1, &curchar);
496 curchar = packets->packet->length & 0xFF;
497 putchar_func(ctx, 1, &curchar);
501 putchar_func(ctx, packets->packet->length,
502 packets->packet->data);
503 packets = packets->next;
510 * flatten_publickey - Convert a publickey to an OpenPGP packet list.
511 * @key: The public key.
512 * @packets: The outputted packet list.
514 * This function converts public key structure to a linked list of OpenPGP
515 * packets ready for outputing or storage.
517 int flatten_publickey(struct openpgp_publickey *key,
518 struct openpgp_packet_list **packets,
519 struct openpgp_packet_list **list_end)
521 struct openpgp_signedpacket_list *tmpsignedlist = NULL;
522 struct openpgp_packet_list *tmplist = NULL;
524 while (key != NULL) {
526 * First write the public key packet out.
528 ADD_PACKET_TO_LIST((*list_end), packet_dup(key->publickey));
529 if (*packets == NULL) {
530 *packets = *list_end;
534 * Now do any signatures on the main key.
536 for (tmplist = key->sigs; tmplist != NULL;
537 tmplist = tmplist->next) {
538 ADD_PACKET_TO_LIST((*list_end),
539 packet_dup(tmplist->packet));
543 * Output any UIDs along with their signatures.
545 for (tmpsignedlist = key->uids; tmpsignedlist != NULL;
546 tmpsignedlist = tmpsignedlist->next) {
548 ADD_PACKET_TO_LIST((*list_end),
549 packet_dup(tmpsignedlist->packet));
550 for (tmplist = tmpsignedlist->sigs; tmplist != NULL;
551 tmplist = tmplist->next) {
552 ADD_PACKET_TO_LIST((*list_end),
553 packet_dup(tmplist->packet));
558 * Output any subkeys along with their signatures.
560 for (tmpsignedlist = key->subkeys; tmpsignedlist != NULL;
561 tmpsignedlist = tmpsignedlist->next) {
563 ADD_PACKET_TO_LIST((*list_end),
564 packet_dup(tmpsignedlist->packet));
565 for (tmplist = tmpsignedlist->sigs; tmplist != NULL;
566 tmplist = tmplist->next) {
567 ADD_PACKET_TO_LIST((*list_end),
568 packet_dup(tmplist->packet));