2 * parsekey.c - Routines to parse an OpenPGP key.
4 * Jonathan McDowell <noodles@earth.li>
6 * Copyright 2002 Project Purple
16 #include "keystructs.h"
22 * add_key - Takes a key and adds it to the keyserver.
23 * @key: The public key to add.
25 * This function takes a public key and adds it to the keyserver.
26 * It first of all sees if we already have the key locally. If we do then
27 * we retrieve it and merge the two keys. We then store the resulting key
28 * (or just the original we received if we don't already have it). We then
29 * send out the appropriate updates to our keyserver peers.
31 int add_key(struct openpgp_publickey *key) {
36 * parse_keys - Process a stream of packets for public keys + sigs.
37 * @packets: The packet list to parse.
38 * @keys: The returned list of public keys.
40 * This function takes an list of OpenPGP packets and attempts to parse it
41 * into a list of public keys with signatures and subkeys.
43 int parse_keys(struct openpgp_packet_list *packets,
44 struct openpgp_publickey **keys)
46 struct openpgp_publickey *curkey = NULL;
49 * If keys already has some keys in it then set curkey to the last one
50 * so we add to the end of the list.
52 for (curkey = *keys; curkey != NULL && curkey->next != NULL;
53 curkey = curkey->next) ;
55 while (packets != NULL) {
56 switch (packets->packet->tag) {
59 * It's a signature packet. Add it to either the public
60 * key (it should be a revocation), to the current UID
61 * or the current subkey.
63 assert(curkey != NULL);
64 if (curkey->subkeys != NULL) {
65 ADD_PACKET_TO_LIST_END(curkey->last_subkey,
67 packet_dup(packets->packet));
68 } else if (curkey->uids != NULL) {
69 ADD_PACKET_TO_LIST_END(curkey->last_uid,
71 packet_dup(packets->packet));
73 ADD_PACKET_TO_LIST_END(curkey,
75 packet_dup(packets->packet));
80 * It's a public key packet, so start a new key in our
84 curkey->next = malloc(sizeof (*curkey));
85 curkey = curkey->next;
88 malloc(sizeof (*curkey));
90 memset(curkey, 0, sizeof(*curkey));
91 curkey->publickey = packet_dup(packets->packet);
96 * It's a UID packet (or a photo id, which is similar).
98 assert(curkey != NULL);
99 assert(curkey->subkeys == NULL);
100 ADD_PACKET_TO_LIST_END(curkey,
102 packet_dup(packets->packet));
106 * It's a subkey packet.
108 assert(curkey != NULL);
109 ADD_PACKET_TO_LIST_END(curkey,
111 packet_dup(packets->packet));
118 * Trust packet. Ignore.
119 * Comment packet. Ignore.
123 fprintf(stderr, "Unsupported packet type: %d\n",
124 packets->packet->tag);
126 packets = packets->next;
133 * debug_packet - Print debug info about a packet
134 * @packet: The packet to display.
136 * This function takes an OpenPGP packet and displays some information
137 * about it to stdout. Useful for debugging purposes or curiousity about
138 * an OpenPGP packet stream.
140 int debug_packet(struct openpgp_packet *packet)
142 printf("\tNew format: %d, Tag: %d, Length: %d\n",
151 * read_openpgp_stream - Reads a stream of OpenPGP packets.
152 * @getchar_func: The function to get the next character from the stream.
153 * @ctx: A pointer to the context structure for getchar_func.
154 * @packets: The outputted list of packets.
156 * This function uses getchar_func to read characters from an OpenPGP
157 * packet stream and reads the packets into a linked list of packets
158 * ready for parsing as a public key or whatever.
160 int read_openpgp_stream(int (*getchar_func)(void *ctx, size_t count,
163 struct openpgp_packet_list **packets)
165 unsigned char curchar = 0;
166 unsigned long count = 0;
167 struct openpgp_packet_list *curpacket = NULL;
169 bool inpacket = false;
171 assert(packets != NULL);
173 while (!rc && !getchar_func(ctx, 1, &curchar)) {
174 if (!inpacket && (curchar & 0x80)) {
176 * New packet. Record the fact we're in a packet and
177 * allocate memory for it.
181 if (curpacket != NULL) {
182 curpacket->next = malloc(sizeof (*curpacket));
183 curpacket = curpacket->next;
185 *packets = curpacket =
186 malloc(sizeof (*curpacket));
188 memset(curpacket, 0, sizeof(*curpacket));
190 malloc(sizeof (*curpacket->packet));
191 memset(curpacket->packet, 0,
192 sizeof(*curpacket->packet));
194 curpacket->packet->newformat = (curchar & 0x40);
196 // TODO: Better error checking on getchar_func.
197 if (curpacket->packet->newformat) {
198 curpacket->packet->tag = (curchar & 0x3F);
199 rc = getchar_func(ctx, 1, &curchar);
200 curpacket->packet->length = curchar;
201 if (curpacket->packet->length > 191 &&
202 curpacket->packet->length < 224) {
203 rc = getchar_func(ctx, 1, &curchar);
204 curpacket->packet->length -= 192;
205 curpacket->packet->length <<= 8;
206 curpacket->packet->length += curchar;
207 curpacket->packet->length += 192;
208 } else if (curpacket->packet->length > 223 &&
209 curpacket->packet->length < 255) {
210 printf("Partial length; not supported.\n");
211 } else if (curpacket->packet->length == 255) {
213 * 5 byte length; ie 255 followed by 3
214 * bytes of MSB length.
216 rc = getchar_func(ctx, 1, &curchar);
217 curpacket->packet->length = curchar;
218 curpacket->packet->length <<= 8;
219 rc = getchar_func(ctx, 1, &curchar);
220 curpacket->packet->length = curchar;
221 curpacket->packet->length <<= 8;
222 rc = getchar_func(ctx, 1, &curchar);
223 curpacket->packet->length = curchar;
224 curpacket->packet->length <<= 8;
225 rc = getchar_func(ctx, 1, &curchar);
226 curpacket->packet->length = curchar;
229 curpacket->packet->tag = (curchar & 0x3C) >> 2;
230 switch (curchar & 3) {
232 rc = getchar_func(ctx, 1, &curchar);
233 curpacket->packet->length = curchar;
236 rc = getchar_func(ctx, 1, &curchar);
237 curpacket->packet->length = curchar;
238 curpacket->packet->length <<= 8;
239 rc = getchar_func(ctx, 1, &curchar);
240 curpacket->packet->length += curchar;
243 rc = getchar_func(ctx, 1, &curchar);
244 curpacket->packet->length =
246 rc = getchar_func(ctx, 1, &curchar);
247 curpacket->packet->length +=
249 rc = getchar_func(ctx, 1, &curchar);
250 curpacket->packet->length +=
252 rc = getchar_func(ctx, 1, &curchar);
253 curpacket->packet->length += curchar;
256 fprintf(stderr, "Unsupported length type 3.\n");
260 curpacket->packet->data =
261 malloc(curpacket->packet->length *
262 sizeof(unsigned char));
263 rc = getchar_func(ctx, curpacket->packet->length,
264 curpacket->packet->data);
267 fprintf(stderr, "Unexpected character: 0x%X\n",
276 * write_openpgp_stream - Reads a stream of OpenPGP packets.
277 * @putchar_func: The function to put the next character to the stream.
278 * @ctx: A pointer to the context structure for putchar_func.
279 * @packets: The list of packets.
281 * This function uses putchar_func to write characters to an OpenPGP
282 * packet stream from a linked list of packets.
284 int write_openpgp_stream(int (*putchar_func)(void *ctx, unsigned char c),
286 struct openpgp_packet_list *packets)
288 unsigned char curchar = 0;
291 while (packets != NULL) {
293 if (packets->packet->newformat) {
295 curchar |= packets->packet->tag;
296 putchar_func(ctx, curchar);
298 if (packets->packet->length < 192) {
299 putchar_func(ctx, packets->packet->length);
300 } else if (packets->packet->length > 191 &&
301 packets->packet->length < 8383) {
302 // fputs("Potentially dodgy code here.\n", stderr);
304 (((packets->packet->length - 192) &
305 0xFF00) >> 8) + 192);
308 (packets->packet->length - 192) &
312 fputs("Unsupported new format length.\n", stderr);
315 curchar |= (packets->packet->tag << 2);
316 if (packets->packet->length < 256) {
317 putchar_func(ctx, curchar);
318 putchar_func(ctx, packets->packet->length);
319 } else if (packets->packet->length < 0x10000) {
321 putchar_func(ctx, curchar);
322 putchar_func(ctx, packets->packet->length >> 8);
324 packets->packet->length & 0xFF);
327 putchar_func(ctx, curchar);
329 packets->packet->length >> 24);
331 (packets->packet->length >> 16) & 0xFF);
333 (packets->packet->length >> 8) & 0xFF);
335 packets->packet->length & 0xFF);
339 for (i = 0; i < packets->packet->length; i++) {
340 putchar_func(ctx, packets->packet->data[i]);
342 packets = packets->next;
348 * flatten_publickey - Convert a publickey to an OpenPGP packet list.
349 * @key: The public key.
350 * @packets: The outputted packet list.
352 * This function converts public key structure to a linked list of OpenPGP
353 * packets ready for outputing or storage.
355 int flatten_publickey(struct openpgp_publickey *key,
356 struct openpgp_packet_list **packets,
357 struct openpgp_packet_list **list_end)
359 struct openpgp_signedpacket_list *tmpsignedlist = NULL;
360 struct openpgp_packet_list *tmplist = NULL;
362 while (key != NULL) {
364 * First write the public key packet out.
366 ADD_PACKET_TO_LIST((*list_end), packet_dup(key->publickey));
367 if (*packets == NULL) {
368 *packets = *list_end;
372 * Now do any revocation signatures on the main key.
374 for (tmplist = key->revocations; tmplist != NULL;
375 tmplist = tmplist->next) {
376 ADD_PACKET_TO_LIST((*list_end),
377 packet_dup(tmplist->packet));
381 * Output any UIDs along with their signatures.
383 for (tmpsignedlist = key->uids; tmpsignedlist != NULL;
384 tmpsignedlist = tmpsignedlist->next) {
386 ADD_PACKET_TO_LIST((*list_end),
387 packet_dup(tmpsignedlist->packet));
388 for (tmplist = tmpsignedlist->sigs; tmplist != NULL;
389 tmplist = tmplist->next) {
390 ADD_PACKET_TO_LIST((*list_end),
391 packet_dup(tmplist->packet));
396 * Output any subkeys along with their signatures.
398 for (tmpsignedlist = key->subkeys; tmpsignedlist != NULL;
399 tmpsignedlist = tmpsignedlist->next) {
401 ADD_PACKET_TO_LIST((*list_end),
402 packet_dup(tmpsignedlist->packet));
403 for (tmplist = tmpsignedlist->sigs; tmplist != NULL;
404 tmplist = tmplist->next) {
405 ADD_PACKET_TO_LIST((*list_end),
406 packet_dup(tmplist->packet));