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"
35RCSID("$Id: collector.c 20778 2007-06-01 22:04:13Z lha $");
36
37struct private_key {
38    AlgorithmIdentifier alg;
39    hx509_private_key private_key;
40    heim_octet_string localKeyId;
41};
42
43struct 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
54int
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
89hx509_lock
90_hx509_collector_get_lock(struct hx509_collector *c)
91{
92    return c->lock;
93}
94
95
96int
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
104static void
105free_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
114int
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
166out:
167    if (ret)
168	free_private_key(key);
169
170    return ret;
171}
172
173static int
174match_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
203static int
204match_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
250int
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
284int
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
315void
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}
330