Move over to log_assert.
[onak.git] / decodekey.c
1 /*
2  * decodekey.c - Routines to further decode an OpenPGP key.
3  *
4  * Jonathan McDowell <noodles@earth.li>
5  *
6  * Copyright 2002 Project Purple
7  */
8
9 #include <stdbool.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <time.h>
14
15 #include "decodekey.h"
16 #include "hash.h"
17 #include "keyid.h"
18 #include "keystructs.h"
19 #include "ll.h"
20 #include "log.h"
21
22 /*
23  *      parse_subpackets - Parse the subpackets of a Type 4 signature.
24  *      @data: The subpacket data.
25  *      @keyid: A pointer to where we should return the keyid.
26  *
27  *      This function parses the subkey data of a Type 4 signature and fills
28  *      in the supplied variables. It also returns the length of the data
29  *      processed.
30  */
31 int parse_subpackets(unsigned char *data, uint64_t *keyid)
32 {
33         int offset = 0;
34         int length = 0;
35         int packetlen = 0;
36
37         log_assert(data != NULL);
38
39         length = (data[0] << 8) + data[1] + 2;
40
41         offset = 2;
42         while (offset < length) {
43                 packetlen = data[offset++];
44                 if (packetlen > 191 && packetlen < 255) {
45                         packetlen = ((packetlen - 192) << 8) +
46                                         data[offset++] + 192;
47                 } else if (packetlen == 255) {
48                         packetlen = data[offset++];
49                         packetlen <<= 8;
50                         packetlen = data[offset++];
51                         packetlen <<= 8;
52                         packetlen = data[offset++];
53                         packetlen <<= 8;
54                         packetlen = data[offset++];
55                 }
56                 switch (data[offset] & 0x7F) {
57                 case 2:
58                         /*
59                          * Signature creation time. Might want to output this?
60                          */
61                         break;
62                 case 3:
63                         /*
64                          * Signature expiration time. Might want to output this?
65                          */
66                         break;
67                 case 16:
68                         *keyid = data[offset+packetlen - 8];
69                         *keyid <<= 8;
70                         *keyid += data[offset+packetlen - 7];
71                         *keyid <<= 8;
72                         *keyid += data[offset+packetlen - 6];
73                         *keyid <<= 8;
74                         *keyid += data[offset+packetlen - 5];
75                         *keyid <<= 8;
76                         *keyid += data[offset+packetlen - 4];
77                         *keyid <<= 8;
78                         *keyid += data[offset+packetlen - 3];
79                         *keyid <<= 8;
80                         *keyid += data[offset+packetlen - 2];
81                         *keyid <<= 8;
82                         *keyid += data[offset+packetlen - 1];
83                         break;
84                 case 20:
85                         /*
86                          * Annotation data.
87                          */
88                         break;
89
90                 case 23:
91                         /*
92                          * Key server preferences. Including no-modify.
93                          */
94                         break;
95                 case 25:
96                         /*
97                          * Primary UID.
98                          */
99                         break;
100                 default:
101                         /*
102                          * We don't care about unrecognized packets unless bit
103                          * 7 is set in which case we log a major error.
104                          */
105                         if (data[offset] & 0x80) {
106                                 logthing(LOGTHING_CRITICAL,
107                                 "Critical subpacket type not parsed: 0x%X",
108                                         data[offset]);
109                         }
110                                 
111                 }
112                 offset += packetlen;
113         }
114
115         return length;
116 }
117
118 /**
119  *      keysigs - Return the sigs on a given OpenPGP signature list.
120  *      @curll: The current linked list. Can be NULL to create a new list.
121  *      @sigs: The signature list we want the sigs on.
122  *
123  *      Returns a linked list of stats_key elements containing the sigs on the
124  *      supplied OpenPGP packet list.
125  */
126 struct ll *keysigs(struct ll *curll,
127                 struct openpgp_packet_list *sigs)
128 {
129         uint64_t keyid = 0;
130         
131         while (sigs != NULL) {
132                 keyid = sig_keyid(sigs->packet);
133                 sigs = sigs->next;
134                 curll = lladd(curll, createandaddtohash(keyid));
135         }
136
137         return curll;
138 }
139
140 /**
141  *      sig_keyid - Return the keyid for a given OpenPGP signature packet.
142  *      @packet: The signature packet.
143  *
144  *      Returns the keyid for the supplied signature packet.
145  */
146 uint64_t sig_keyid(struct openpgp_packet *packet)
147 {
148         int length = 0;
149         uint64_t keyid = 0;
150         
151         if (packet != NULL) {
152                 keyid = 0;
153                 switch (packet->data[0]) {
154                 case 2:
155                 case 3:
156                         keyid = packet->data[7];
157                         keyid <<= 8;
158                         keyid += packet->data[8];
159                         keyid <<= 8;
160                         keyid += packet->data[9];
161                         keyid <<= 8;
162                         keyid += packet->data[10];
163                         keyid <<= 8;
164                         keyid += packet->data[11];
165                         keyid <<= 8;
166                         keyid += packet->data[12];
167                         keyid <<= 8;
168                         keyid += packet->data[13];
169                         keyid <<= 8;
170                         keyid += packet->data[14];
171                         break;
172                 case 4:
173                         length = parse_subpackets(&packet->data[4],
174                                         &keyid);
175                         parse_subpackets(&packet->data[length + 4],
176                                         &keyid);
177                         /*
178                          * Don't bother to look at the unsigned packets.
179                          */
180                         break;
181                 default:
182                         break;
183                 }
184         }
185
186         return keyid;
187 }
188
189 /*
190  * TODO: Abstract out; all our linked lists should be generic and then we can
191  * llsize them.
192  */
193 int spsize(struct openpgp_signedpacket_list *list)
194 {
195         int size = 0;
196         struct openpgp_signedpacket_list *cur;
197
198         for (cur = list; cur != NULL; cur = cur->next, size++) ;
199
200         return size;
201 }
202
203 /**
204  *      keyuids - Takes a key and returns an array of its UIDs
205  *      @key: The key to get the uids of.
206  *      @primary: A pointer to store the primary UID in.
207  *
208  *      keyuids takes a public key structure and builds an array of the UIDs 
209  *      on the key. It also attempts to work out the primary UID and returns a
210  *      separate pointer to that particular element of the array.
211  */
212 char **keyuids(struct openpgp_publickey *key, char **primary)
213 {
214         struct openpgp_signedpacket_list *curuid = NULL;
215         char buf[1024];
216         char **uids = NULL;
217         int count = 0;
218         
219         if (primary != NULL) {
220                 *primary = NULL;
221         }
222
223         if (key != NULL && key->uids != NULL) {
224                 uids = malloc((spsize(key->uids) + 1) * sizeof (char *));
225         
226                 curuid = key->uids;
227                 while (curuid != NULL) {
228                         buf[0] = 0;
229                         if (curuid->packet->tag == 13) {
230                                 snprintf(buf, 1023, "%.*s",
231                                                 (int) curuid->packet->length,
232                                                 curuid->packet->data);
233                                 uids[count++] = strdup(buf);
234                         }
235                         curuid = curuid -> next;
236                 }
237                 uids[count] = NULL;
238
239                 /*
240                  * TODO: Parse subpackets for real primary ID (v4 keys)
241                  */
242                 if (primary != NULL) {
243                         *primary = uids[0];
244                 }
245         }
246
247         return uids;
248 }
249
250 /**
251  *      keysubkeys - Takes a key and returns an array of its subkey keyids.
252  *      @key: The key to get the subkeys of.
253  *
254  *      keysubkeys takes a public key structure and returns an array of the
255  *      subkey keyids for that key.
256  */
257 uint64_t *keysubkeys(struct openpgp_publickey *key)
258 {
259         struct openpgp_signedpacket_list *cursubkey = NULL;
260         uint64_t                         *subkeys = NULL;
261         int                               count = 0;
262         
263         if (key != NULL && key->subkeys != NULL) {
264                 subkeys = malloc((spsize(key->subkeys) + 1) *
265                                 sizeof (uint64_t));
266                 cursubkey = key->subkeys;
267                 while (cursubkey != NULL) {
268                         subkeys[count++] = get_packetid(cursubkey->packet);
269                         cursubkey = cursubkey -> next;
270                 }
271                 subkeys[count] = 0;
272         }
273
274         return subkeys;
275 }