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