]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/lib/hx509/collector.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / lib / hx509 / collector.c
1 /*
2  * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors 
18  *    may be used to endorse or promote products derived from this software 
19  *    without specific prior written permission. 
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
31  * SUCH DAMAGE. 
32  */
33
34 #include "hx_locl.h"
35 RCSID("$Id: collector.c 20778 2007-06-01 22:04:13Z lha $");
36
37 struct private_key {
38     AlgorithmIdentifier alg;
39     hx509_private_key private_key;
40     heim_octet_string localKeyId;
41 };
42
43 struct hx509_collector {
44     hx509_lock lock;
45     hx509_certs unenvelop_certs;
46     hx509_certs certs;
47     struct {
48         struct private_key **data;
49         size_t len;
50     } val;
51 };
52
53
54 int
55 _hx509_collector_alloc(hx509_context context, hx509_lock lock, struct hx509_collector **collector)
56 {
57     struct hx509_collector *c;
58     int ret;
59
60     *collector = NULL;
61
62     c = calloc(1, sizeof(*c));
63     if (c == NULL) {
64         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
65         return ENOMEM;
66     }
67     c->lock = lock;
68
69     ret = hx509_certs_init(context, "MEMORY:collector-unenvelop-cert",
70                            0,NULL, &c->unenvelop_certs);
71     if (ret) {
72         free(c);
73         return ret;
74     }
75     c->val.data = NULL;
76     c->val.len = 0;
77     ret = hx509_certs_init(context, "MEMORY:collector-tmp-store",
78                            0, NULL, &c->certs);
79     if (ret) {
80         hx509_certs_free(&c->unenvelop_certs);
81         free(c);
82         return ret;
83     }
84
85     *collector = c;
86     return 0;
87 }
88
89 hx509_lock
90 _hx509_collector_get_lock(struct hx509_collector *c)
91 {
92     return c->lock;
93 }
94
95
96 int
97 _hx509_collector_certs_add(hx509_context context,
98                            struct hx509_collector *c,
99                            hx509_cert cert)
100 {
101     return hx509_certs_add(context, c->certs, cert);
102 }
103
104 static void
105 free_private_key(struct private_key *key)
106 {
107     free_AlgorithmIdentifier(&key->alg);
108     if (key->private_key)
109         _hx509_private_key_free(&key->private_key);
110     der_free_octet_string(&key->localKeyId);
111     free(key);
112 }
113
114 int
115 _hx509_collector_private_key_add(hx509_context context,
116                                  struct hx509_collector *c, 
117                                  const AlgorithmIdentifier *alg,
118                                  hx509_private_key private_key,
119                                  const heim_octet_string *key_data,
120                                  const heim_octet_string *localKeyId)
121 {
122     struct private_key *key;
123     void *d;
124     int ret;
125
126     key = calloc(1, sizeof(*key));
127     if (key == NULL)
128         return ENOMEM;
129
130     d = realloc(c->val.data, (c->val.len + 1) * sizeof(c->val.data[0]));
131     if (d == NULL) {
132         free(key);
133         hx509_set_error_string(context, 0, ENOMEM, "Out of memory");
134         return ENOMEM;
135     }
136     c->val.data = d;
137         
138     ret = copy_AlgorithmIdentifier(alg, &key->alg);
139     if (ret) {
140         hx509_set_error_string(context, 0, ret, "Failed to copy "
141                                "AlgorithmIdentifier");
142         goto out;
143     }
144     if (private_key) {
145         key->private_key = private_key;
146     } else {
147         ret = _hx509_parse_private_key(context, &alg->algorithm,
148                                        key_data->data, key_data->length,
149                                        &key->private_key);
150         if (ret)
151             goto out;
152     }
153     if (localKeyId) {
154         ret = der_copy_octet_string(localKeyId, &key->localKeyId);
155         if (ret) {
156             hx509_set_error_string(context, 0, ret, 
157                                    "Failed to copy localKeyId");
158             goto out;
159         }
160     } else
161         memset(&key->localKeyId, 0, sizeof(key->localKeyId));
162
163     c->val.data[c->val.len] = key;
164     c->val.len++;
165
166 out:
167     if (ret)
168         free_private_key(key);
169
170     return ret;
171 }
172
173 static int
174 match_localkeyid(hx509_context context,
175                  struct private_key *value,
176                  hx509_certs certs)
177 {
178     hx509_cert cert;
179     hx509_query q;
180     int ret;
181
182     if (value->localKeyId.length == 0) {
183         hx509_set_error_string(context, 0, HX509_LOCAL_ATTRIBUTE_MISSING,
184                                "No local key attribute on private key");
185         return HX509_LOCAL_ATTRIBUTE_MISSING;
186     }
187
188     _hx509_query_clear(&q);
189     q.match |= HX509_QUERY_MATCH_LOCAL_KEY_ID;
190     
191     q.local_key_id = &value->localKeyId;
192     
193     ret = hx509_certs_find(context, certs, &q, &cert);
194     if (ret == 0) {
195         
196         if (value->private_key)
197             _hx509_cert_assign_key(cert, value->private_key);
198         hx509_cert_free(cert);
199     }
200     return ret;
201 }
202
203 static int
204 match_keys(hx509_context context, struct private_key *value, hx509_certs certs)
205 {
206     hx509_cursor cursor;
207     hx509_cert c;
208     int ret, found = HX509_CERT_NOT_FOUND;
209
210     if (value->private_key == NULL) {
211         hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, 
212                                "No private key to compare with");
213         return HX509_PRIVATE_KEY_MISSING;
214     }
215
216     ret = hx509_certs_start_seq(context, certs, &cursor);
217     if (ret)
218         return ret;
219
220     c = NULL;
221     while (1) {
222         ret = hx509_certs_next_cert(context, certs, cursor, &c);
223         if (ret)
224             break;
225         if (c == NULL)
226             break;
227         if (_hx509_cert_private_key(c)) {
228             hx509_cert_free(c);
229             continue;
230         }
231
232         ret = _hx509_match_keys(c, value->private_key);
233         if (ret) {
234             _hx509_cert_assign_key(c, value->private_key);
235             hx509_cert_free(c);
236             found = 0;
237             break;
238         }
239         hx509_cert_free(c);
240     }
241
242     hx509_certs_end_seq(context, certs, cursor);
243
244     if (found)
245         hx509_clear_error_string(context);
246
247     return found;
248 }
249
250 int
251 _hx509_collector_collect_certs(hx509_context context, 
252                                struct hx509_collector *c,
253                                hx509_certs *ret_certs)
254 {
255     hx509_certs certs;
256     int ret, i;
257
258     *ret_certs = NULL;
259
260     ret = hx509_certs_init(context, "MEMORY:collector-store", 0, NULL, &certs);
261     if (ret)
262         return ret;
263
264     ret = hx509_certs_merge(context, certs, c->certs);
265     if (ret) {
266         hx509_certs_free(&certs);
267         return ret;
268     }
269
270     for (i = 0; i < c->val.len; i++) {
271         ret = match_localkeyid(context, c->val.data[i], certs);
272         if (ret == 0)
273             continue;
274         ret = match_keys(context, c->val.data[i], certs);
275         if (ret == 0)
276             continue;
277     }
278
279     *ret_certs = certs;
280
281     return 0;
282 }
283
284 int
285 _hx509_collector_collect_private_keys(hx509_context context, 
286                                       struct hx509_collector *c,
287                                       hx509_private_key **keys)
288 {
289     int i, nkeys;
290
291     *keys = NULL;
292
293     for (i = 0, nkeys = 0; i < c->val.len; i++)
294         if (c->val.data[i]->private_key)
295             nkeys++;
296
297     *keys = calloc(nkeys + 1, sizeof(**keys));
298     if (*keys == NULL) {
299         hx509_set_error_string(context, 0, ENOMEM, "malloc - out of memory");
300         return ENOMEM;
301     }
302
303     for (i = 0, nkeys = 0; i < c->val.len; i++) {
304         if (c->val.data[i]->private_key) {
305             (*keys)[nkeys++] = c->val.data[i]->private_key;
306             c->val.data[i]->private_key = NULL;
307         }
308     }
309     (*keys)[nkeys++] = NULL;
310
311     return 0;
312 }
313
314
315 void
316 _hx509_collector_free(struct hx509_collector *c)
317 {
318     int i;
319
320     if (c->unenvelop_certs)
321         hx509_certs_free(&c->unenvelop_certs);
322     if (c->certs)
323         hx509_certs_free(&c->certs);
324     for (i = 0; i < c->val.len; i++)
325         free_private_key(c->val.data[i]);
326     if (c->val.data)
327         free(c->val.data);
328     free(c);
329 }