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, write to the Free Software Foundation, Inc., 51
17 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include "keystructs.h"
33 * parse_keys - Process a stream of packets for public keys + sigs.
34 * @packets: The packet list to parse.
35 * @keys: The returned list of public keys.
37 * This function takes an list of OpenPGP packets and attempts to parse it
38 * into a list of public keys with signatures and subkeys.
40 * Returns a count of how many keys we parsed.
42 int parse_keys(struct openpgp_packet_list *packets,
43 struct openpgp_publickey **keys)
45 struct openpgp_publickey *curkey = NULL;
51 * If keys already has some keys in it then set curkey to the last one
52 * so we add to the end of the list.
54 for (curkey = *keys; curkey != NULL && curkey->next != NULL;
55 curkey = curkey->next) ;
57 while (packets != NULL) {
58 switch (packets->packet->tag) {
59 case OPENPGP_PACKET_SIGNATURE:
61 * It's a signature packet. Add it to either the public
62 * key, to the current UID or the current subkey.
65 return ONAK_E_INVALID_PARAM;
66 if (curkey->subkeys != NULL) {
67 ADD_PACKET_TO_LIST_END(curkey->last_subkey,
69 packet_dup(packets->packet));
70 } else if (curkey->uids != NULL) {
71 ADD_PACKET_TO_LIST_END(curkey->last_uid,
73 packet_dup(packets->packet));
75 ADD_PACKET_TO_LIST_END(curkey,
77 packet_dup(packets->packet));
79 * This is a signature on the public key; check
80 * if it's a revocation.
82 if (packets->packet->data[0] == 3 &&
83 packets->packet->data[2] ==
84 OPENPGP_SIGTYPE_KEY_REV) {
86 * Type 3 key, 0x20 == revocation
88 curkey->revoked = true;
89 } else if (packets->packet->data[0] == 4 &&
90 packets->packet->data[1] ==
91 OPENPGP_SIGTYPE_KEY_REV) {
93 * Type 4 key, 0x20 == revocation
95 curkey->revoked = true;
99 case OPENPGP_PACKET_PUBLICKEY:
101 * It's a public key packet, so start a new key in our
104 if (curkey != NULL) {
105 curkey->next = malloc(sizeof (*curkey));
106 curkey = curkey->next;
109 malloc(sizeof (*curkey));
111 memset(curkey, 0, sizeof(*curkey));
112 curkey->publickey = packet_dup(packets->packet);
115 case OPENPGP_PACKET_UID:
116 case OPENPGP_PACKET_UAT:
118 * It's a UID packet (or a photo id, which is similar).
121 return ONAK_E_INVALID_PARAM;
122 if (curkey->subkeys != NULL)
123 return ONAK_E_INVALID_PARAM;
124 ADD_PACKET_TO_LIST_END(curkey,
126 packet_dup(packets->packet));
128 case OPENPGP_PACKET_PUBLICSUBKEY:
130 * It's a subkey packet.
133 return ONAK_E_INVALID_PARAM;
134 ADD_PACKET_TO_LIST_END(curkey,
136 packet_dup(packets->packet));
138 case OPENPGP_PACKET_TRUST:
139 case OPENPGP_PACKET_COMMENT:
143 * Trust packet. Ignore.
144 * Comment packet. Ignore.
148 /* Unsupported packet. Do what? Ignore for now. */
151 packets = packets->next;
158 * debug_packet - Print debug info about a packet
159 * @packet: The packet to display.
161 * This function takes an OpenPGP packet and displays some information
162 * about it to stdout. Useful for debugging purposes or curiousity about
163 * an OpenPGP packet stream.
165 int debug_packet(struct openpgp_packet *packet)
167 printf("\tNew format: %d, Tag: %u, Length: %zd\n",
176 * read_openpgp_stream - Reads a stream of OpenPGP packets.
177 * @getchar_func: The function to get the next character from the stream.
178 * @ctx: A pointer to the context structure for getchar_func.
179 * @packets: The outputted list of packets.
180 * @maxnum: The maximum number of keys to read. 0 means unlimited.
182 * This function uses getchar_func to read characters from an OpenPGP
183 * packet stream and reads the packets into a linked list of packets
184 * ready for parsing as a public key or whatever.
186 onak_status_t read_openpgp_stream(int (*getchar_func)(void *ctx, size_t count,
189 struct openpgp_packet_list **packets,
192 unsigned char curchar = 0;
193 struct openpgp_packet_list *curpacket = NULL, **packetend = NULL;
194 onak_status_t rc = ONAK_E_OK;
198 return ONAK_E_INVALID_PARAM;
200 curpacket = *packets;
201 if (curpacket != NULL) {
202 while (curpacket->next != NULL) {
203 curpacket = curpacket->next;
207 while (rc == ONAK_E_OK && (maxnum == 0 || keys < maxnum) &&
208 !getchar_func(ctx, 1, &curchar)) {
209 if (curchar & 0x80) {
211 * New packet. Allocate memory for it.
213 if (curpacket != NULL) {
214 curpacket->next = malloc(sizeof (*curpacket));
215 packetend = &curpacket->next;
216 curpacket = curpacket->next;
218 *packets = curpacket =
219 malloc(sizeof (*curpacket));
222 memset(curpacket, 0, sizeof(*curpacket));
224 malloc(sizeof (*curpacket->packet));
225 memset(curpacket->packet, 0,
226 sizeof(*curpacket->packet));
228 curpacket->packet->newformat = (curchar & 0x40);
231 * TODO: Better error checking on getchar_func.
233 if (curpacket->packet->newformat) {
234 curpacket->packet->tag = (curchar & 0x3F);
235 if (getchar_func(ctx, 1, &curchar)) {
236 rc = ONAK_E_INVALID_PKT;
239 curpacket->packet->length = curchar;
240 if (curpacket->packet->length > 191 &&
241 curpacket->packet->length < 224) {
242 rc = getchar_func(ctx, 1, &curchar);
243 curpacket->packet->length -= 192;
244 curpacket->packet->length <<= 8;
245 curpacket->packet->length += curchar;
246 curpacket->packet->length += 192;
247 } else if (curpacket->packet->length > 223 &&
248 curpacket->packet->length < 255) {
249 free(curpacket->packet);
250 curpacket->packet = NULL;
251 rc = ONAK_E_UNSUPPORTED_FEATURE;
252 } else if (curpacket->packet->length == 255) {
254 * 5 byte length; ie 255 followed by 3
255 * bytes of MSB length.
257 if (getchar_func(ctx, 1, &curchar)) {
258 rc = ONAK_E_INVALID_PKT;
261 curpacket->packet->length = curchar;
262 curpacket->packet->length <<= 8;
263 if (getchar_func(ctx, 1, &curchar)) {
264 rc = ONAK_E_INVALID_PKT;
267 curpacket->packet->length += curchar;
268 curpacket->packet->length <<= 8;
269 if (getchar_func(ctx, 1, &curchar)) {
270 rc = ONAK_E_INVALID_PKT;
273 curpacket->packet->length += curchar;
274 curpacket->packet->length <<= 8;
275 if (getchar_func(ctx, 1, &curchar)) {
276 rc = ONAK_E_INVALID_PKT;
279 curpacket->packet->length += curchar;
282 curpacket->packet->tag = (curchar & 0x3C) >> 2;
283 switch (curchar & 3) {
285 if (getchar_func(ctx, 1, &curchar)) {
286 rc = ONAK_E_INVALID_PKT;
289 curpacket->packet->length = curchar;
292 if (getchar_func(ctx, 1, &curchar)) {
293 rc = ONAK_E_INVALID_PKT;
296 curpacket->packet->length = curchar;
297 curpacket->packet->length <<= 8;
298 if (getchar_func(ctx, 1, &curchar)) {
299 rc = ONAK_E_INVALID_PKT;
302 curpacket->packet->length += curchar;
305 if (getchar_func(ctx, 1, &curchar)) {
306 rc = ONAK_E_INVALID_PKT;
309 curpacket->packet->length =
310 ((unsigned) curchar << 24);
311 if (getchar_func(ctx, 1, &curchar)) {
312 rc = ONAK_E_INVALID_PKT;
315 curpacket->packet->length +=
317 if (getchar_func(ctx, 1, &curchar)) {
318 rc = ONAK_E_INVALID_PKT;
321 curpacket->packet->length +=
323 if (getchar_func(ctx, 1, &curchar)) {
324 rc = ONAK_E_INVALID_PKT;
327 curpacket->packet->length += curchar;
330 rc = ONAK_E_UNSUPPORTED_FEATURE;
331 free(curpacket->packet);
332 curpacket->packet = NULL;
338 if (curpacket->packet->tag ==
339 OPENPGP_PACKET_PUBLICKEY) {
342 curpacket->packet->data =
343 malloc(curpacket->packet->length *
344 sizeof(unsigned char));
345 if (curpacket->packet->data == NULL) {
348 rc = getchar_func(ctx,
349 curpacket->packet->length,
350 curpacket->packet->data);
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 -> v4 */
382 if (curpacket->packet->data[0] < 2 ||
383 curpacket->packet->data[0] > 4) {
384 rc = ONAK_E_INVALID_PKT;
393 if (packetend != NULL) {
394 if ((*packetend)->packet != NULL) {
395 /* If we got an invalid final packet, discard it. */
396 if ((*packetend)->packet->data != NULL &&
398 free((*packetend)->packet->data);
399 (*packetend)->packet->data = NULL;
401 /* If we didn't get any data, clean it up. */
402 if ((*packetend)->packet->data == NULL) {
403 free((*packetend)->packet);
404 (*packetend)->packet = NULL;
407 /* Trim the last packet if it doesn't actually exist */
408 if ((*packetend)->packet == NULL) {
418 * write_openpgp_stream - Reads a stream of OpenPGP packets.
419 * @putchar_func: The function to put the next character to the stream.
420 * @ctx: A pointer to the context structure for putchar_func.
421 * @packets: The list of packets.
423 * This function uses putchar_func to write characters to an OpenPGP
424 * packet stream from a linked list of packets.
426 onak_status_t write_openpgp_stream(int (*putchar_func)(void *ctx, size_t count,
429 struct openpgp_packet_list *packets)
431 unsigned char curchar = 0;
433 while (packets != NULL) {
435 if (packets->packet->newformat) {
437 curchar |= packets->packet->tag;
438 putchar_func(ctx, 1, &curchar);
440 if (packets->packet->length < 192) {
441 curchar = packets->packet->length;
442 putchar_func(ctx, 1, &curchar);
443 } else if (packets->packet->length > 191 &&
444 packets->packet->length < 8383) {
445 curchar = (((packets->packet->length - 192) &
447 putchar_func(ctx, 1, &curchar);
449 curchar = (packets->packet->length - 192) &
451 putchar_func(ctx, 1, &curchar);
452 } else if (packets->packet->length > 8382 &&
453 packets->packet->length < 0xFFFFFFFF) {
455 putchar_func(ctx, 1, &curchar);
457 curchar = (packets->packet->length >> 24);
459 putchar_func(ctx, 1, &curchar);
461 curchar = (packets->packet->length >> 16);
463 putchar_func(ctx, 1, &curchar);
465 curchar = (packets->packet->length >> 8);
467 putchar_func(ctx, 1, &curchar);
469 curchar = packets->packet->length;
471 putchar_func(ctx, 1, &curchar);
473 return ONAK_E_UNSUPPORTED_FEATURE;
476 curchar |= (packets->packet->tag << 2);
477 if (packets->packet->length < 256) {
478 putchar_func(ctx, 1, &curchar);
479 curchar = packets->packet->length;
480 putchar_func(ctx, 1, &curchar);
481 } else if (packets->packet->length < 0x10000) {
483 putchar_func(ctx, 1, &curchar);
484 curchar = packets->packet->length >> 8;
485 putchar_func(ctx, 1, &curchar);
486 curchar = packets->packet->length & 0xFF;
487 putchar_func(ctx, 1, &curchar);
490 putchar_func(ctx, 1, &curchar);
491 curchar = packets->packet->length >> 24;
492 putchar_func(ctx, 1, &curchar);
493 curchar = (packets->packet->length >> 16) & 0xFF;
494 putchar_func(ctx, 1, &curchar);
495 curchar = (packets->packet->length >> 8) & 0xFF;
496 putchar_func(ctx, 1, &curchar);
497 curchar = packets->packet->length & 0xFF;
498 putchar_func(ctx, 1, &curchar);
502 putchar_func(ctx, packets->packet->length,
503 packets->packet->data);
504 packets = packets->next;
511 * flatten_publickey - Convert a publickey to an OpenPGP packet list.
512 * @key: The public key.
513 * @packets: The outputted packet list.
515 * This function converts public key structure to a linked list of OpenPGP
516 * packets ready for outputing or storage.
518 int flatten_publickey(struct openpgp_publickey *key,
519 struct openpgp_packet_list **packets,
520 struct openpgp_packet_list **list_end)
522 struct openpgp_signedpacket_list *tmpsignedlist = NULL;
523 struct openpgp_packet_list *tmplist = NULL;
525 while (key != NULL) {
527 * First write the public key packet out.
529 ADD_PACKET_TO_LIST((*list_end), packet_dup(key->publickey));
530 if (*packets == NULL) {
531 *packets = *list_end;
535 * Now do any signatures on the main key.
537 for (tmplist = key->sigs; tmplist != NULL;
538 tmplist = tmplist->next) {
539 ADD_PACKET_TO_LIST((*list_end),
540 packet_dup(tmplist->packet));
544 * Output any UIDs along with their signatures.
546 for (tmpsignedlist = key->uids; tmpsignedlist != NULL;
547 tmpsignedlist = tmpsignedlist->next) {
549 ADD_PACKET_TO_LIST((*list_end),
550 packet_dup(tmpsignedlist->packet));
551 for (tmplist = tmpsignedlist->sigs; tmplist != NULL;
552 tmplist = tmplist->next) {
553 ADD_PACKET_TO_LIST((*list_end),
554 packet_dup(tmplist->packet));
559 * Output any subkeys along with their signatures.
561 for (tmpsignedlist = key->subkeys; tmpsignedlist != NULL;
562 tmpsignedlist = tmpsignedlist->next) {
564 ADD_PACKET_TO_LIST((*list_end),
565 packet_dup(tmpsignedlist->packet));
566 for (tmplist = tmpsignedlist->sigs; tmplist != NULL;
567 tmplist = tmplist->next) {
568 ADD_PACKET_TO_LIST((*list_end),
569 packet_dup(tmplist->packet));