xref: /freebsd/crypto/heimdal/lib/hx509/collector.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
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 }
331