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