Line data Source code
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 : HX509_LIB_FUNCTION int HX509_LIB_CALL
54 288 : _hx509_collector_alloc(hx509_context context, hx509_lock lock, struct hx509_collector **collector)
55 : {
56 16 : struct hx509_collector *c;
57 16 : int ret;
58 :
59 288 : *collector = NULL;
60 :
61 288 : c = calloc(1, sizeof(*c));
62 288 : if (c == NULL) {
63 0 : hx509_set_error_string(context, 0, ENOMEM, "out of memory");
64 0 : return ENOMEM;
65 : }
66 288 : c->lock = lock;
67 :
68 288 : ret = hx509_certs_init(context, "MEMORY:collector-unenvelop-cert",
69 : 0,NULL, &c->unenvelop_certs);
70 288 : if (ret) {
71 0 : free(c);
72 0 : return ret;
73 : }
74 288 : c->val.data = NULL;
75 288 : c->val.len = 0;
76 288 : ret = hx509_certs_init(context, "MEMORY:collector-tmp-store",
77 : 0, NULL, &c->certs);
78 288 : if (ret) {
79 0 : hx509_certs_free(&c->unenvelop_certs);
80 0 : free(c);
81 0 : return ret;
82 : }
83 :
84 288 : *collector = c;
85 288 : return 0;
86 : }
87 :
88 : HX509_LIB_FUNCTION hx509_lock HX509_LIB_CALL
89 0 : _hx509_collector_get_lock(struct hx509_collector *c)
90 : {
91 0 : return c->lock;
92 : }
93 :
94 :
95 : HX509_LIB_FUNCTION int HX509_LIB_CALL
96 249 : _hx509_collector_certs_add(hx509_context context,
97 : struct hx509_collector *c,
98 : hx509_cert cert)
99 : {
100 249 : return hx509_certs_add(context, c->certs, cert);
101 : }
102 :
103 : static void
104 74 : free_private_key(struct private_key *key)
105 : {
106 74 : free_AlgorithmIdentifier(&key->alg);
107 74 : if (key->private_key)
108 0 : hx509_private_key_free(&key->private_key);
109 74 : der_free_octet_string(&key->localKeyId);
110 74 : free(key);
111 74 : }
112 :
113 : HX509_LIB_FUNCTION int HX509_LIB_CALL
114 74 : _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 8 : struct private_key *key;
122 8 : void *d;
123 8 : int ret;
124 :
125 74 : key = calloc(1, sizeof(*key));
126 74 : if (key == NULL)
127 0 : return ENOMEM;
128 :
129 74 : d = realloc(c->val.data, (c->val.len + 1) * sizeof(c->val.data[0]));
130 74 : if (d == NULL) {
131 0 : free(key);
132 0 : hx509_set_error_string(context, 0, ENOMEM, "Out of memory");
133 0 : return ENOMEM;
134 : }
135 74 : c->val.data = d;
136 :
137 74 : ret = copy_AlgorithmIdentifier(alg, &key->alg);
138 74 : if (ret) {
139 0 : hx509_set_error_string(context, 0, ret, "Failed to copy "
140 : "AlgorithmIdentifier");
141 0 : goto out;
142 : }
143 74 : if (private_key) {
144 0 : key->private_key = private_key;
145 : } else {
146 82 : ret = hx509_parse_private_key(context, alg,
147 74 : key_data->data, key_data->length,
148 : HX509_KEY_FORMAT_DER,
149 : &key->private_key);
150 74 : if (ret && localKeyId) {
151 0 : int ret2;
152 :
153 0 : ret2 = hx509_parse_private_key(context, alg,
154 0 : localKeyId->data, localKeyId->length,
155 : HX509_KEY_FORMAT_PKCS8,
156 : &key->private_key);
157 0 : if (ret2 == 0)
158 0 : ret = 0;
159 : }
160 74 : if (ret)
161 0 : goto out;
162 : }
163 74 : if (localKeyId) {
164 0 : ret = der_copy_octet_string(localKeyId, &key->localKeyId);
165 0 : if (ret) {
166 0 : hx509_set_error_string(context, 0, ret,
167 : "Failed to copy localKeyId");
168 0 : goto out;
169 : }
170 : } else
171 74 : memset(&key->localKeyId, 0, sizeof(key->localKeyId));
172 :
173 74 : c->val.data[c->val.len] = key;
174 74 : c->val.len++;
175 :
176 74 : out:
177 74 : if (ret)
178 0 : free_private_key(key);
179 :
180 66 : return ret;
181 : }
182 :
183 : static int
184 74 : match_localkeyid(hx509_context context,
185 : struct private_key *value,
186 : hx509_certs certs)
187 : {
188 8 : hx509_cert cert;
189 8 : hx509_query q;
190 8 : int ret;
191 :
192 74 : if (value->localKeyId.length == 0) {
193 74 : hx509_set_error_string(context, 0, HX509_LOCAL_ATTRIBUTE_MISSING,
194 : "No local key attribute on private key");
195 74 : return HX509_LOCAL_ATTRIBUTE_MISSING;
196 : }
197 :
198 0 : _hx509_query_clear(&q);
199 0 : q.match |= HX509_QUERY_MATCH_LOCAL_KEY_ID;
200 :
201 0 : q.local_key_id = &value->localKeyId;
202 :
203 0 : ret = hx509_certs_find(context, certs, &q, &cert);
204 0 : if (ret == 0 && cert == NULL)
205 0 : ret = HX509_CERT_NOT_FOUND;
206 0 : if (ret == 0) {
207 0 : if (value->private_key)
208 0 : _hx509_cert_assign_key(cert, value->private_key);
209 0 : hx509_cert_free(cert);
210 : }
211 0 : return ret;
212 : }
213 :
214 : static int
215 74 : match_keys(hx509_context context, struct private_key *value, hx509_certs certs)
216 : {
217 8 : hx509_cursor cursor;
218 8 : hx509_cert c;
219 74 : int ret, found = HX509_CERT_NOT_FOUND;
220 :
221 74 : if (value->private_key == NULL) {
222 0 : hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
223 : "No private key to compare with");
224 0 : return HX509_PRIVATE_KEY_MISSING;
225 : }
226 :
227 74 : ret = hx509_certs_start_seq(context, certs, &cursor);
228 74 : if (ret)
229 0 : return ret;
230 :
231 74 : c = NULL;
232 8 : while (1) {
233 74 : ret = hx509_certs_next_cert(context, certs, cursor, &c);
234 74 : if (ret)
235 0 : break;
236 74 : if (c == NULL)
237 0 : break;
238 74 : if (_hx509_cert_private_key(c)) {
239 0 : hx509_cert_free(c);
240 0 : continue;
241 : }
242 :
243 74 : ret = _hx509_match_keys(c, value->private_key);
244 74 : if (ret) {
245 74 : _hx509_cert_assign_key(c, value->private_key);
246 74 : hx509_cert_free(c);
247 74 : found = 0;
248 74 : break;
249 : }
250 0 : hx509_cert_free(c);
251 : }
252 :
253 74 : hx509_certs_end_seq(context, certs, cursor);
254 :
255 74 : if (found)
256 0 : hx509_clear_error_string(context);
257 :
258 66 : return found;
259 : }
260 :
261 : HX509_LIB_FUNCTION int HX509_LIB_CALL
262 249 : _hx509_collector_collect_certs(hx509_context context,
263 : struct hx509_collector *c,
264 : hx509_certs *ret_certs)
265 : {
266 16 : hx509_certs certs;
267 16 : int ret;
268 16 : size_t i;
269 :
270 249 : *ret_certs = NULL;
271 :
272 249 : ret = hx509_certs_init(context, "MEMORY:collector-store", 0, NULL, &certs);
273 249 : if (ret)
274 0 : return ret;
275 :
276 249 : ret = hx509_certs_merge(context, certs, c->certs);
277 249 : if (ret) {
278 0 : hx509_certs_free(&certs);
279 0 : return ret;
280 : }
281 :
282 323 : for (i = 0; i < c->val.len; i++) {
283 74 : ret = match_localkeyid(context, c->val.data[i], certs);
284 74 : if (ret == 0)
285 0 : continue;
286 74 : ret = match_keys(context, c->val.data[i], certs);
287 74 : if (ret == 0)
288 66 : continue;
289 : }
290 :
291 249 : *ret_certs = certs;
292 :
293 249 : return 0;
294 : }
295 :
296 : HX509_LIB_FUNCTION int HX509_LIB_CALL
297 249 : _hx509_collector_collect_private_keys(hx509_context context,
298 : struct hx509_collector *c,
299 : hx509_private_key **keys)
300 : {
301 16 : size_t i, nkeys;
302 :
303 249 : *keys = NULL;
304 :
305 323 : for (i = 0, nkeys = 0; i < c->val.len; i++)
306 74 : if (c->val.data[i]->private_key)
307 74 : nkeys++;
308 :
309 249 : *keys = calloc(nkeys + 1, sizeof(**keys));
310 249 : if (*keys == NULL) {
311 0 : hx509_set_error_string(context, 0, ENOMEM, "malloc - out of memory");
312 0 : return ENOMEM;
313 : }
314 :
315 323 : for (i = 0, nkeys = 0; i < c->val.len; i++) {
316 74 : if (c->val.data[i]->private_key) {
317 74 : (*keys)[nkeys++] = c->val.data[i]->private_key;
318 74 : c->val.data[i]->private_key = NULL;
319 : }
320 : }
321 249 : (*keys)[nkeys] = NULL;
322 :
323 249 : return 0;
324 : }
325 :
326 :
327 : HX509_LIB_FUNCTION void HX509_LIB_CALL
328 288 : _hx509_collector_free(struct hx509_collector *c)
329 : {
330 16 : size_t i;
331 :
332 288 : if (c->unenvelop_certs)
333 288 : hx509_certs_free(&c->unenvelop_certs);
334 288 : if (c->certs)
335 288 : hx509_certs_free(&c->certs);
336 362 : for (i = 0; i < c->val.len; i++)
337 74 : free_private_key(c->val.data[i]);
338 288 : if (c->val.data)
339 74 : free(c->val.data);
340 288 : free(c);
341 288 : }
|