]> the.earth.li Git - onak.git/blob - parsekey.c
Cleanup various includes
[onak.git] / parsekey.c
1 /*
2  * parsekey.c - Routines to parse an OpenPGP key.
3  *
4  * Copyright 2002-2004,2007-2008,2011 Jonathan McDowell <noodles@earth.li>
5  *
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.
9  *
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
13  * more details.
14  *
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.
18  */
19
20 #include <stdbool.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "keystructs.h"
26 #include "ll.h"
27 #include "mem.h"
28 #include "onak.h"
29 #include "openpgp.h"
30 #include "parsekey.h"
31
32 /**
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.
36  *
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.
39  *
40  *      Returns a count of how many keys we parsed.
41  */
42 int parse_keys(struct openpgp_packet_list *packets,
43                 struct openpgp_publickey **keys)
44 {
45         struct openpgp_publickey *curkey = NULL;
46         int count;
47
48         count = 0;
49
50         /*
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.
53          */
54         for (curkey = *keys; curkey != NULL && curkey->next != NULL;
55                         curkey = curkey->next) ;
56
57         while (packets != NULL) {
58                 switch (packets->packet->tag) {
59                 case OPENPGP_PACKET_SIGNATURE:
60                         /*
61                          * It's a signature packet. Add it to either the public
62                          * key, to the current UID or the current subkey.
63                          */
64                         if (curkey == NULL)
65                                 return ONAK_E_INVALID_PARAM;
66                         if (curkey->subkeys != NULL) {
67                                 ADD_PACKET_TO_LIST_END(curkey->last_subkey,
68                                         sig,
69                                         packet_dup(packets->packet));
70                         } else if (curkey->uids != NULL) {
71                                 ADD_PACKET_TO_LIST_END(curkey->last_uid,
72                                         sig,
73                                         packet_dup(packets->packet));
74                         } else {
75                                 ADD_PACKET_TO_LIST_END(curkey,
76                                         sig,
77                                         packet_dup(packets->packet));
78                                 /*
79                                  * This is a signature on the public key; check
80                                  * if it's a revocation.
81                                  */
82                                 if (packets->packet->data[0] == 3 &&
83                                         packets->packet->data[2] ==
84                                                 OPENPGP_SIGTYPE_KEY_REV) {
85                                         /*
86                                          * Type 3 key, 0x20 == revocation
87                                          */
88                                         curkey->revoked = true;
89                                 } else if (packets->packet->data[0] == 4 &&
90                                         packets->packet->data[1] ==
91                                                 OPENPGP_SIGTYPE_KEY_REV) {
92                                         /*
93                                          * Type 4 key, 0x20 == revocation
94                                          */
95                                         curkey->revoked = true;
96                                 }
97                         }
98                         break;
99                 case OPENPGP_PACKET_PUBLICKEY:
100                         /*
101                          * It's a public key packet, so start a new key in our
102                          * list.
103                          */
104                         if (curkey != NULL) {
105                                 curkey->next = malloc(sizeof (*curkey));
106                                 curkey = curkey->next;
107                         } else {
108                                 *keys = curkey =
109                                         malloc(sizeof (*curkey));
110                         }
111                         memset(curkey, 0, sizeof(*curkey));
112                         curkey->publickey = packet_dup(packets->packet);
113                         count++;
114                         break;
115                 case OPENPGP_PACKET_UID:
116                 case OPENPGP_PACKET_UAT:
117                         /*
118                          * It's a UID packet (or a photo id, which is similar).
119                          */
120                         if (curkey == NULL)
121                                 return ONAK_E_INVALID_PARAM;
122                         if (curkey->subkeys != NULL)
123                                 return ONAK_E_INVALID_PARAM;
124                         ADD_PACKET_TO_LIST_END(curkey,
125                                 uid,
126                                 packet_dup(packets->packet));
127                         break;
128                 case OPENPGP_PACKET_PUBLICSUBKEY:
129                         /*
130                          * It's a subkey packet.
131                          */
132                         if (curkey == NULL)
133                                 return ONAK_E_INVALID_PARAM;
134                         ADD_PACKET_TO_LIST_END(curkey,
135                                 subkey,
136                                 packet_dup(packets->packet));
137                         break;
138                 case OPENPGP_PACKET_TRUST:
139                 case OPENPGP_PACKET_COMMENT:
140                         /*
141                          * One of:
142                          *
143                          * Trust packet. Ignore.
144                          * Comment packet. Ignore.
145                          */
146                         break;
147                 default:
148                         /* Unsupported packet. Do what? Ignore for now. */
149                         break;
150                 }
151                 packets = packets->next;
152         }
153
154         return count;
155 }
156
157 /**
158  *      debug_packet - Print debug info about a packet
159  *      @packet: The packet to display.
160  *
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.
164  */
165 int debug_packet(struct openpgp_packet *packet)
166 {
167         printf("\tNew format: %d, Tag: %u, Length: %zd\n",
168                         packet->newformat,
169                         packet->tag,
170                         packet->length);
171
172         return 0;
173 }
174
175 /**
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.
181  *
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.
185  */
186 onak_status_t read_openpgp_stream(int (*getchar_func)(void *ctx, size_t count,
187                                 void *c),
188                                 void *ctx,
189                                 struct openpgp_packet_list **packets,
190                                 int maxnum)
191 {
192         unsigned char                    curchar = 0;
193         struct openpgp_packet_list      *curpacket = NULL, **packetend = NULL;
194         onak_status_t                    rc = ONAK_E_OK;
195         int                              keys = 0;
196
197         if (packets == NULL)
198                 return ONAK_E_INVALID_PARAM;
199
200         curpacket = *packets;
201         if (curpacket != NULL) {
202                 while (curpacket->next != NULL) {
203                         curpacket = curpacket->next;
204                 }
205         }
206
207         while (rc == ONAK_E_OK && (maxnum == 0 || keys < maxnum) &&
208                         !getchar_func(ctx, 1, &curchar)) {
209                 if (curchar & 0x80) {
210                         /*
211                          * New packet. Allocate memory for it.
212                          */
213                         if (curpacket != NULL) {
214                                 curpacket->next = malloc(sizeof (*curpacket));
215                                 packetend = &curpacket->next;
216                                 curpacket = curpacket->next;
217                         } else {
218                                 *packets = curpacket =
219                                         malloc(sizeof (*curpacket));
220                                 packetend = packets;
221                         }
222                         memset(curpacket, 0, sizeof(*curpacket));
223                         curpacket->packet =
224                                 malloc(sizeof (*curpacket->packet));
225                         memset(curpacket->packet, 0,
226                                         sizeof(*curpacket->packet));
227
228                         curpacket->packet->newformat = (curchar & 0x40);
229
230                         /*
231                          * TODO: Better error checking on getchar_func.
232                          */
233                         if (curpacket->packet->newformat) {
234                                 curpacket->packet->tag = (curchar & 0x3F);
235                                 if (getchar_func(ctx, 1, &curchar)) {
236                                         rc = ONAK_E_INVALID_PKT;
237                                         break;
238                                 }
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) {
253                                         /*
254                                          * 5 byte length; ie 255 followed by 3
255                                          * bytes of MSB length.
256                                          */
257                                         if (getchar_func(ctx, 1, &curchar)) {
258                                                 rc = ONAK_E_INVALID_PKT;
259                                                 break;
260                                         }
261                                         curpacket->packet->length = curchar;
262                                         curpacket->packet->length <<= 8;
263                                         if (getchar_func(ctx, 1, &curchar)) {
264                                                 rc = ONAK_E_INVALID_PKT;
265                                                 break;
266                                         }
267                                         curpacket->packet->length += curchar;
268                                         curpacket->packet->length <<= 8;
269                                         if (getchar_func(ctx, 1, &curchar)) {
270                                                 rc = ONAK_E_INVALID_PKT;
271                                                 break;
272                                         }
273                                         curpacket->packet->length += curchar;
274                                         curpacket->packet->length <<= 8;
275                                         if (getchar_func(ctx, 1, &curchar)) {
276                                                 rc = ONAK_E_INVALID_PKT;
277                                                 break;
278                                         }
279                                         curpacket->packet->length += curchar;
280                                 }
281                         } else {
282                                 curpacket->packet->tag = (curchar & 0x3C) >> 2;
283                                 switch (curchar & 3) {
284                                 case 0:
285                                         if (getchar_func(ctx, 1, &curchar)) {
286                                                 rc = ONAK_E_INVALID_PKT;
287                                                 break;
288                                         }
289                                         curpacket->packet->length = curchar;
290                                         break;
291                                 case 1:
292                                         if (getchar_func(ctx, 1, &curchar)) {
293                                                 rc = ONAK_E_INVALID_PKT;
294                                                 break;
295                                         }
296                                         curpacket->packet->length = curchar;
297                                         curpacket->packet->length <<= 8;
298                                         if (getchar_func(ctx, 1, &curchar)) {
299                                                 rc = ONAK_E_INVALID_PKT;
300                                                 break;
301                                         }
302                                         curpacket->packet->length += curchar;
303                                         break;
304                                 case 2:
305                                         if (getchar_func(ctx, 1, &curchar)) {
306                                                 rc = ONAK_E_INVALID_PKT;
307                                                 break;
308                                         }
309                                         curpacket->packet->length = 
310                                                 ((unsigned) curchar << 24);
311                                         if (getchar_func(ctx, 1, &curchar)) {
312                                                 rc = ONAK_E_INVALID_PKT;
313                                                 break;
314                                         }
315                                         curpacket->packet->length +=
316                                                 (curchar << 16);
317                                         if (getchar_func(ctx, 1, &curchar)) {
318                                                 rc = ONAK_E_INVALID_PKT;
319                                                 break;
320                                         }
321                                         curpacket->packet->length +=
322                                                 (curchar << 8);
323                                         if (getchar_func(ctx, 1, &curchar)) {
324                                                 rc = ONAK_E_INVALID_PKT;
325                                                 break;
326                                         }
327                                         curpacket->packet->length += curchar;
328                                         break;
329                                 case 3:
330                                         rc = ONAK_E_UNSUPPORTED_FEATURE;
331                                         free(curpacket->packet);
332                                         curpacket->packet = NULL;
333                                         break;
334                                 }
335                         }
336
337                         if (rc == 0) {
338                                 if (curpacket->packet->tag ==
339                                                 OPENPGP_PACKET_PUBLICKEY) {
340                                         keys++;
341                                 }
342                                 curpacket->packet->data =
343                                         malloc(curpacket->packet->length *
344                                         sizeof(unsigned char));
345                                 if (curpacket->packet->data == NULL) {
346                                         rc = ONAK_E_NOMEM;
347                                 } else {
348                                         rc = getchar_func(ctx,
349                                                 curpacket->packet->length,
350                                                 curpacket->packet->data);
351                                 }
352                         }
353                 } else {
354                         rc = ONAK_E_INVALID_PKT;
355                 }
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;
363                                 }
364                                 break;
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;
370                                 }
371                                 break;
372                         case OPENPGP_PACKET_SYMSESSIONKEY:
373                                 /* These packets must be v4 */
374                                 if (curpacket->packet->data[0] != 4) {
375                                         rc = ONAK_E_INVALID_PKT;
376                                 }
377                                 break;
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;
385                                 }
386                                 break;
387                         default:
388                                 break;
389                         }
390                 }
391         }
392
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 &&
397                                         rc != ONAK_E_OK) {
398                                 free((*packetend)->packet->data);
399                                 (*packetend)->packet->data = NULL;
400                         }
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;
405                         }
406                 }
407                 /* Trim the last packet if it doesn't actually exist */
408                 if ((*packetend)->packet == NULL) {
409                         free(*packetend);
410                         *packetend = NULL;
411                 }
412         }
413
414         return (rc);
415 }
416
417 /**
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.
422  *
423  *      This function uses putchar_func to write characters to an OpenPGP
424  *      packet stream from a linked list of packets.
425  */
426 onak_status_t write_openpgp_stream(int (*putchar_func)(void *ctx, size_t count,
427                                                 void *c),
428                                 void *ctx,
429                                 struct openpgp_packet_list *packets)
430 {
431         unsigned char   curchar = 0;
432
433         while (packets != NULL) {
434                 curchar = 0x80;
435                 if (packets->packet->newformat) {
436                         curchar |= 0x40;
437                         curchar |= packets->packet->tag;
438                         putchar_func(ctx, 1, &curchar);
439
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) &
446                                          0xFF00) >> 8) + 192;
447                                 putchar_func(ctx, 1, &curchar);
448
449                                 curchar = (packets->packet->length - 192) &
450                                          0xFF;
451                                 putchar_func(ctx, 1, &curchar);
452                         } else if (packets->packet->length > 8382 &&
453                                 packets->packet->length < 0xFFFFFFFF) {
454                                 curchar = 255;
455                                 putchar_func(ctx, 1, &curchar);
456                                 
457                                 curchar = (packets->packet->length >> 24);
458                                 curchar &= 0xFF;
459                                 putchar_func(ctx, 1, &curchar);
460                                 
461                                 curchar = (packets->packet->length >> 16);
462                                 curchar &= 0xFF;
463                                 putchar_func(ctx, 1, &curchar);
464                                 
465                                 curchar = (packets->packet->length >> 8);
466                                 curchar &= 0xFF;
467                                 putchar_func(ctx, 1, &curchar);
468                                 
469                                 curchar = packets->packet->length;
470                                 curchar &= 0xFF;
471                                 putchar_func(ctx, 1, &curchar);
472                         } else {
473                                 return ONAK_E_UNSUPPORTED_FEATURE;
474                         }
475                 } else {
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) {
482                                 curchar |= 1;
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);
488                         } else {
489                                 curchar |= 2;
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);
499                         }
500                 }
501
502                 putchar_func(ctx, packets->packet->length,
503                                 packets->packet->data);
504                 packets = packets->next;
505         }
506
507         return ONAK_E_OK;
508 }
509
510 /**
511  *      flatten_publickey - Convert a publickey to an OpenPGP packet list.
512  *      @key: The public key.
513  *      @packets: The outputted packet list.
514  *
515  *      This function converts public key structure to a linked list of OpenPGP
516  *      packets ready for outputing or storage.
517  */
518 int flatten_publickey(struct openpgp_publickey *key,
519                         struct openpgp_packet_list **packets,
520                         struct openpgp_packet_list **list_end)
521 {
522         struct openpgp_signedpacket_list        *tmpsignedlist = NULL;
523         struct openpgp_packet_list              *tmplist = NULL;
524
525         while (key != NULL) {
526                 /*
527                  * First write the public key packet out.
528                  */
529                 ADD_PACKET_TO_LIST((*list_end), packet_dup(key->publickey));
530                 if (*packets == NULL) {
531                         *packets = *list_end;
532                 }
533
534                 /*
535                  * Now do any signatures on the main key.
536                  */
537                 for (tmplist = key->sigs; tmplist != NULL;
538                                 tmplist = tmplist->next) {
539                         ADD_PACKET_TO_LIST((*list_end),
540                                         packet_dup(tmplist->packet));
541                 }
542
543                 /*
544                  * Output any UIDs along with their signatures.
545                  */
546                 for (tmpsignedlist = key->uids; tmpsignedlist != NULL;
547                                 tmpsignedlist = tmpsignedlist->next) {
548
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));
555                         }
556                 }
557
558                 /*
559                  * Output any subkeys along with their signatures.
560                  */
561                 for (tmpsignedlist = key->subkeys; tmpsignedlist != NULL;
562                                 tmpsignedlist = tmpsignedlist->next) {
563
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));
570                         }
571                 }
572                 key = key->next;
573         }
574         return 0;
575 }