]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - crypto/heimdal/lib/hx509/collector.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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
36 struct private_key {
37     AlgorithmIdentifier alg;
38     hx509_private_key private_key;
39     heim_octet_string localKeyId;
40 };
41
42 struct hx509_collector {
43     hx509_lock lock;
44     hx509_certs unenvelop_certs;
45     hx509_certs certs;
46     struct {
47         struct private_key **data;
48         size_t len;
49     } val;
50 };
51
52
53 int
54 _hx509_collector_alloc(hx509_context context, hx509_lock lock, struct hx509_collector **collector)
55 {
56     struct hx509_collector *c;
57     int ret;
58
59     *collector = NULL;
60
61     c = calloc(1, sizeof(*c));
62     if (c == NULL) {
63         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
64         return ENOMEM;
65     }
66     c->lock = lock;
67
68     ret = hx509_certs_init(context, "MEMORY:collector-unenvelop-cert",
69                            0,NULL, &c->unenvelop_certs);
70     if (ret) {
71         free(c);
72         return ret;
73     }
74     c->val.data = NULL;
75     c->val.len = 0;
76     ret = hx509_certs_init(context, "MEMORY:collector-tmp-store",
77                            0, NULL, &c->certs);
78     if (ret) {
79         hx509_certs_free(&c->unenvelop_certs);
80         free(c);
81         return ret;
82     }
83
84     *collector = c;
85     return 0;
86 }
87
88 hx509_lock
89 _hx509_collector_get_lock(struct hx509_collector *c)
90 {
91     return c->lock;
92 }
93
94
95 int
96 _hx509_collector_certs_add(hx509_context context,
97                            struct hx509_collector *c,
98                            hx509_cert cert)
99 {
100     return hx509_certs_add(context, c->certs, cert);
101 }
102
103 static void
104 free_private_key(struct private_key *key)
105 {
106     free_AlgorithmIdentifier(&key->alg);
107     if (key->private_key)
108         hx509_private_key_free(&key->private_key);
109     der_free_octet_string(&key->localKeyId);
110     free(key);
111 }
112
113 int
114 _hx509_collector_private_key_add(hx509_context context,
115                                  struct hx509_collector *c,
116                                  const AlgorithmIdentifier *alg,
117                                  hx509_private_key private_key,
118                                  const heim_octet_string *key_data,
119                                  const heim_octet_string *localKeyId)
120 {
121     struct private_key *key;
122     void *d;
123     int ret;
124
125     key = calloc(1, sizeof(*key));
126     if (key == NULL)
127         return ENOMEM;
128
129     d = realloc(c->val.data, (c->val.len + 1) * sizeof(c->val.data[0]));
130     if (d == NULL) {
131         free(key);
132         hx509_set_error_string(context, 0, ENOMEM, "Out of memory");
133         return ENOMEM;
134     }
135     c->val.data = d;
136
137     ret = copy_AlgorithmIdentifier(alg, &key->alg);
138     if (ret) {
139         hx509_set_error_string(context, 0, ret, "Failed to copy "
140                                "AlgorithmIdentifier");
141         goto out;
142     }
143     if (private_key) {
144         key->private_key = private_key;
145     } else {
146         ret = hx509_parse_private_key(context, alg,
147                                        key_data->data, key_data->length,
148                                        HX509_KEY_FORMAT_DER,
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;
257     size_t i;
258
259     *ret_certs = NULL;
260
261     ret = hx509_certs_init(context, "MEMORY:collector-store", 0, NULL, &certs);
262     if (ret)
263         return ret;
264
265     ret = hx509_certs_merge(context, certs, c->certs);
266     if (ret) {
267         hx509_certs_free(&certs);
268         return ret;
269     }
270
271     for (i = 0; i < c->val.len; i++) {
272         ret = match_localkeyid(context, c->val.data[i], certs);
273         if (ret == 0)
274             continue;
275         ret = match_keys(context, c->val.data[i], certs);
276         if (ret == 0)
277             continue;
278     }
279
280     *ret_certs = certs;
281
282     return 0;
283 }
284
285 int
286 _hx509_collector_collect_private_keys(hx509_context context,
287                                       struct hx509_collector *c,
288                                       hx509_private_key **keys)
289 {
290     size_t i, nkeys;
291
292     *keys = NULL;
293
294     for (i = 0, nkeys = 0; i < c->val.len; i++)
295         if (c->val.data[i]->private_key)
296             nkeys++;
297
298     *keys = calloc(nkeys + 1, sizeof(**keys));
299     if (*keys == NULL) {
300         hx509_set_error_string(context, 0, ENOMEM, "malloc - out of memory");
301         return ENOMEM;
302     }
303
304     for (i = 0, nkeys = 0; i < c->val.len; i++) {
305         if (c->val.data[i]->private_key) {
306             (*keys)[nkeys++] = c->val.data[i]->private_key;
307             c->val.data[i]->private_key = NULL;
308         }
309     }
310     (*keys)[nkeys] = NULL;
311
312     return 0;
313 }
314
315
316 void
317 _hx509_collector_free(struct hx509_collector *c)
318 {
319     size_t i;
320
321     if (c->unenvelop_certs)
322         hx509_certs_free(&c->unenvelop_certs);
323     if (c->certs)
324         hx509_certs_free(&c->certs);
325     for (i = 0; i < c->val.len; i++)
326         free_private_key(c->val.data[i]);
327     if (c->val.data)
328         free(c->val.data);
329     free(c);
330 }