1178825Sdfr/*
2233294Sstas * Copyright (c) 2004 - 2007 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825Sdfr
36178825Sdfrstruct private_key {
37178825Sdfr    AlgorithmIdentifier alg;
38178825Sdfr    hx509_private_key private_key;
39178825Sdfr    heim_octet_string localKeyId;
40178825Sdfr};
41178825Sdfr
42178825Sdfrstruct hx509_collector {
43178825Sdfr    hx509_lock lock;
44178825Sdfr    hx509_certs unenvelop_certs;
45178825Sdfr    hx509_certs certs;
46178825Sdfr    struct {
47178825Sdfr	struct private_key **data;
48178825Sdfr	size_t len;
49178825Sdfr    } val;
50178825Sdfr};
51178825Sdfr
52178825Sdfr
53178825Sdfrint
54178825Sdfr_hx509_collector_alloc(hx509_context context, hx509_lock lock, struct hx509_collector **collector)
55178825Sdfr{
56178825Sdfr    struct hx509_collector *c;
57178825Sdfr    int ret;
58178825Sdfr
59178825Sdfr    *collector = NULL;
60178825Sdfr
61178825Sdfr    c = calloc(1, sizeof(*c));
62178825Sdfr    if (c == NULL) {
63178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
64178825Sdfr	return ENOMEM;
65178825Sdfr    }
66178825Sdfr    c->lock = lock;
67178825Sdfr
68178825Sdfr    ret = hx509_certs_init(context, "MEMORY:collector-unenvelop-cert",
69178825Sdfr			   0,NULL, &c->unenvelop_certs);
70178825Sdfr    if (ret) {
71178825Sdfr	free(c);
72178825Sdfr	return ret;
73178825Sdfr    }
74178825Sdfr    c->val.data = NULL;
75178825Sdfr    c->val.len = 0;
76178825Sdfr    ret = hx509_certs_init(context, "MEMORY:collector-tmp-store",
77178825Sdfr			   0, NULL, &c->certs);
78178825Sdfr    if (ret) {
79178825Sdfr	hx509_certs_free(&c->unenvelop_certs);
80178825Sdfr	free(c);
81178825Sdfr	return ret;
82178825Sdfr    }
83178825Sdfr
84178825Sdfr    *collector = c;
85178825Sdfr    return 0;
86178825Sdfr}
87178825Sdfr
88178825Sdfrhx509_lock
89178825Sdfr_hx509_collector_get_lock(struct hx509_collector *c)
90178825Sdfr{
91178825Sdfr    return c->lock;
92178825Sdfr}
93178825Sdfr
94178825Sdfr
95178825Sdfrint
96178825Sdfr_hx509_collector_certs_add(hx509_context context,
97178825Sdfr			   struct hx509_collector *c,
98178825Sdfr			   hx509_cert cert)
99178825Sdfr{
100178825Sdfr    return hx509_certs_add(context, c->certs, cert);
101178825Sdfr}
102178825Sdfr
103178825Sdfrstatic void
104178825Sdfrfree_private_key(struct private_key *key)
105178825Sdfr{
106178825Sdfr    free_AlgorithmIdentifier(&key->alg);
107178825Sdfr    if (key->private_key)
108233294Sstas	hx509_private_key_free(&key->private_key);
109178825Sdfr    der_free_octet_string(&key->localKeyId);
110178825Sdfr    free(key);
111178825Sdfr}
112178825Sdfr
113178825Sdfrint
114178825Sdfr_hx509_collector_private_key_add(hx509_context context,
115233294Sstas				 struct hx509_collector *c,
116178825Sdfr				 const AlgorithmIdentifier *alg,
117178825Sdfr				 hx509_private_key private_key,
118178825Sdfr				 const heim_octet_string *key_data,
119178825Sdfr				 const heim_octet_string *localKeyId)
120178825Sdfr{
121178825Sdfr    struct private_key *key;
122178825Sdfr    void *d;
123178825Sdfr    int ret;
124178825Sdfr
125178825Sdfr    key = calloc(1, sizeof(*key));
126178825Sdfr    if (key == NULL)
127178825Sdfr	return ENOMEM;
128178825Sdfr
129178825Sdfr    d = realloc(c->val.data, (c->val.len + 1) * sizeof(c->val.data[0]));
130178825Sdfr    if (d == NULL) {
131178825Sdfr	free(key);
132178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "Out of memory");
133178825Sdfr	return ENOMEM;
134178825Sdfr    }
135178825Sdfr    c->val.data = d;
136233294Sstas
137178825Sdfr    ret = copy_AlgorithmIdentifier(alg, &key->alg);
138178825Sdfr    if (ret) {
139178825Sdfr	hx509_set_error_string(context, 0, ret, "Failed to copy "
140178825Sdfr			       "AlgorithmIdentifier");
141178825Sdfr	goto out;
142178825Sdfr    }
143178825Sdfr    if (private_key) {
144178825Sdfr	key->private_key = private_key;
145178825Sdfr    } else {
146233294Sstas	ret = hx509_parse_private_key(context, alg,
147178825Sdfr				       key_data->data, key_data->length,
148233294Sstas				       HX509_KEY_FORMAT_DER,
149178825Sdfr				       &key->private_key);
150178825Sdfr	if (ret)
151178825Sdfr	    goto out;
152178825Sdfr    }
153178825Sdfr    if (localKeyId) {
154178825Sdfr	ret = der_copy_octet_string(localKeyId, &key->localKeyId);
155178825Sdfr	if (ret) {
156233294Sstas	    hx509_set_error_string(context, 0, ret,
157178825Sdfr				   "Failed to copy localKeyId");
158178825Sdfr	    goto out;
159178825Sdfr	}
160178825Sdfr    } else
161178825Sdfr	memset(&key->localKeyId, 0, sizeof(key->localKeyId));
162178825Sdfr
163178825Sdfr    c->val.data[c->val.len] = key;
164178825Sdfr    c->val.len++;
165178825Sdfr
166178825Sdfrout:
167178825Sdfr    if (ret)
168178825Sdfr	free_private_key(key);
169178825Sdfr
170178825Sdfr    return ret;
171178825Sdfr}
172178825Sdfr
173178825Sdfrstatic int
174178825Sdfrmatch_localkeyid(hx509_context context,
175178825Sdfr		 struct private_key *value,
176178825Sdfr		 hx509_certs certs)
177178825Sdfr{
178178825Sdfr    hx509_cert cert;
179178825Sdfr    hx509_query q;
180178825Sdfr    int ret;
181178825Sdfr
182178825Sdfr    if (value->localKeyId.length == 0) {
183178825Sdfr	hx509_set_error_string(context, 0, HX509_LOCAL_ATTRIBUTE_MISSING,
184178825Sdfr			       "No local key attribute on private key");
185178825Sdfr	return HX509_LOCAL_ATTRIBUTE_MISSING;
186178825Sdfr    }
187178825Sdfr
188178825Sdfr    _hx509_query_clear(&q);
189178825Sdfr    q.match |= HX509_QUERY_MATCH_LOCAL_KEY_ID;
190233294Sstas
191178825Sdfr    q.local_key_id = &value->localKeyId;
192233294Sstas
193178825Sdfr    ret = hx509_certs_find(context, certs, &q, &cert);
194178825Sdfr    if (ret == 0) {
195233294Sstas
196178825Sdfr	if (value->private_key)
197178825Sdfr	    _hx509_cert_assign_key(cert, value->private_key);
198178825Sdfr	hx509_cert_free(cert);
199178825Sdfr    }
200178825Sdfr    return ret;
201178825Sdfr}
202178825Sdfr
203178825Sdfrstatic int
204178825Sdfrmatch_keys(hx509_context context, struct private_key *value, hx509_certs certs)
205178825Sdfr{
206178825Sdfr    hx509_cursor cursor;
207178825Sdfr    hx509_cert c;
208178825Sdfr    int ret, found = HX509_CERT_NOT_FOUND;
209178825Sdfr
210178825Sdfr    if (value->private_key == NULL) {
211233294Sstas	hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
212178825Sdfr			       "No private key to compare with");
213178825Sdfr	return HX509_PRIVATE_KEY_MISSING;
214178825Sdfr    }
215178825Sdfr
216178825Sdfr    ret = hx509_certs_start_seq(context, certs, &cursor);
217178825Sdfr    if (ret)
218178825Sdfr	return ret;
219178825Sdfr
220178825Sdfr    c = NULL;
221178825Sdfr    while (1) {
222178825Sdfr	ret = hx509_certs_next_cert(context, certs, cursor, &c);
223178825Sdfr	if (ret)
224178825Sdfr	    break;
225178825Sdfr	if (c == NULL)
226178825Sdfr	    break;
227178825Sdfr	if (_hx509_cert_private_key(c)) {
228178825Sdfr	    hx509_cert_free(c);
229178825Sdfr	    continue;
230178825Sdfr	}
231178825Sdfr
232178825Sdfr	ret = _hx509_match_keys(c, value->private_key);
233178825Sdfr	if (ret) {
234178825Sdfr	    _hx509_cert_assign_key(c, value->private_key);
235178825Sdfr	    hx509_cert_free(c);
236178825Sdfr	    found = 0;
237178825Sdfr	    break;
238178825Sdfr	}
239178825Sdfr	hx509_cert_free(c);
240178825Sdfr    }
241178825Sdfr
242178825Sdfr    hx509_certs_end_seq(context, certs, cursor);
243178825Sdfr
244178825Sdfr    if (found)
245178825Sdfr	hx509_clear_error_string(context);
246178825Sdfr
247178825Sdfr    return found;
248178825Sdfr}
249178825Sdfr
250178825Sdfrint
251233294Sstas_hx509_collector_collect_certs(hx509_context context,
252178825Sdfr			       struct hx509_collector *c,
253178825Sdfr			       hx509_certs *ret_certs)
254178825Sdfr{
255178825Sdfr    hx509_certs certs;
256233294Sstas    int ret;
257233294Sstas    size_t i;
258178825Sdfr
259178825Sdfr    *ret_certs = NULL;
260178825Sdfr
261178825Sdfr    ret = hx509_certs_init(context, "MEMORY:collector-store", 0, NULL, &certs);
262178825Sdfr    if (ret)
263178825Sdfr	return ret;
264178825Sdfr
265178825Sdfr    ret = hx509_certs_merge(context, certs, c->certs);
266178825Sdfr    if (ret) {
267178825Sdfr	hx509_certs_free(&certs);
268178825Sdfr	return ret;
269178825Sdfr    }
270178825Sdfr
271178825Sdfr    for (i = 0; i < c->val.len; i++) {
272178825Sdfr	ret = match_localkeyid(context, c->val.data[i], certs);
273178825Sdfr	if (ret == 0)
274178825Sdfr	    continue;
275178825Sdfr	ret = match_keys(context, c->val.data[i], certs);
276178825Sdfr	if (ret == 0)
277178825Sdfr	    continue;
278178825Sdfr    }
279178825Sdfr
280178825Sdfr    *ret_certs = certs;
281178825Sdfr
282178825Sdfr    return 0;
283178825Sdfr}
284178825Sdfr
285178825Sdfrint
286233294Sstas_hx509_collector_collect_private_keys(hx509_context context,
287178825Sdfr				      struct hx509_collector *c,
288178825Sdfr				      hx509_private_key **keys)
289178825Sdfr{
290233294Sstas    size_t i, nkeys;
291178825Sdfr
292178825Sdfr    *keys = NULL;
293178825Sdfr
294178825Sdfr    for (i = 0, nkeys = 0; i < c->val.len; i++)
295178825Sdfr	if (c->val.data[i]->private_key)
296178825Sdfr	    nkeys++;
297178825Sdfr
298178825Sdfr    *keys = calloc(nkeys + 1, sizeof(**keys));
299178825Sdfr    if (*keys == NULL) {
300178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "malloc - out of memory");
301178825Sdfr	return ENOMEM;
302178825Sdfr    }
303178825Sdfr
304178825Sdfr    for (i = 0, nkeys = 0; i < c->val.len; i++) {
305178825Sdfr 	if (c->val.data[i]->private_key) {
306178825Sdfr	    (*keys)[nkeys++] = c->val.data[i]->private_key;
307178825Sdfr	    c->val.data[i]->private_key = NULL;
308178825Sdfr	}
309178825Sdfr    }
310233294Sstas    (*keys)[nkeys] = NULL;
311178825Sdfr
312178825Sdfr    return 0;
313178825Sdfr}
314178825Sdfr
315178825Sdfr
316178825Sdfrvoid
317178825Sdfr_hx509_collector_free(struct hx509_collector *c)
318178825Sdfr{
319233294Sstas    size_t i;
320178825Sdfr
321178825Sdfr    if (c->unenvelop_certs)
322178825Sdfr	hx509_certs_free(&c->unenvelop_certs);
323178825Sdfr    if (c->certs)
324178825Sdfr	hx509_certs_free(&c->certs);
325178825Sdfr    for (i = 0; i < c->val.len; i++)
326178825Sdfr	free_private_key(c->val.data[i]);
327178825Sdfr    if (c->val.data)
328178825Sdfr	free(c->val.data);
329178825Sdfr    free(c);
330178825Sdfr}
331