xref: /openbsd/sbin/isakmpd/x509.c (revision b205d946)
1 /* $OpenBSD: x509.c,v 1.126 2024/04/28 16:43:42 florian Exp $	 */
2 /* $EOM: x509.c,v 1.54 2001/01/16 18:42:16 ho Exp $	 */
3 
4 /*
5  * Copyright (c) 1998, 1999 Niels Provos.  All rights reserved.
6  * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist.  All rights reserved.
7  * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * This code was written under funding by Ericsson Radio Systems.
32  */
33 
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <dirent.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <limits.h>
44 
45 #include <regex.h>
46 #include <keynote.h>
47 
48 #include "cert.h"
49 #include "conf.h"
50 #include "exchange.h"
51 #include "hash.h"
52 #include "ike_auth.h"
53 #include "ipsec.h"
54 #include "log.h"
55 #include "dh.h"
56 #include "monitor.h"
57 #include "policy.h"
58 #include "sa.h"
59 #include "util.h"
60 #include "x509.h"
61 
62 static u_int16_t x509_hash(u_int8_t *, size_t);
63 static void	 x509_hash_init(void);
64 static X509	*x509_hash_find(u_int8_t *, size_t);
65 static int	 x509_hash_enter(X509 *);
66 
67 /*
68  * X509_STOREs do not support subjectAltNames, so we have to build
69  * our own hash table.
70  */
71 
72 /*
73  * XXX Actually this store is not really useful, we never use it as we have
74  * our own hash table.  It also gets collisions if we have several certificates
75  * only differing in subjectAltName.
76  */
77 static X509_STORE *x509_certs = 0;
78 static X509_STORE *x509_cas = 0;
79 
80 static int n_x509_cas = 0;
81 
82 /* Initial number of bits used as hash.  */
83 #define INITIAL_BUCKET_BITS 6
84 
85 struct x509_hash {
86 	LIST_ENTRY(x509_hash) link;
87 
88 	X509		*cert;
89 };
90 
91 static LIST_HEAD(x509_list, x509_hash) *x509_tab = 0;
92 
93 /* Works both as a maximum index and a mask.  */
94 static int	bucket_mask;
95 
96 /*
97  * Given an X509 certificate, create a KeyNote assertion where
98  * Issuer/Subject -> Authorizer/Licensees.
99  * XXX RSA-specific.
100  */
101 int
x509_generate_kn(int id,X509 * cert)102 x509_generate_kn(int id, X509 *cert)
103 {
104 	static const char fmt[] = "Authorizer: \"rsa-hex:%s\"\nLicensees: \"rsa-hex:%s"
105 		    "\"\nConditions: %s >= \"%s\" && %s <= \"%s\";\n";
106 	char	*ikey = NULL, *skey = NULL, *buf = NULL;
107 	char	isname[256], subname[256];
108 	static const char fmt2[] = "Authorizer: \"DN:%s\"\nLicensees: \"DN:%s\"\n"
109 		    "Conditions: %s >= \"%s\" && %s <= \"%s\";\n";
110 	X509_NAME *issuer, *subject;
111 	struct keynote_deckey dc;
112 	X509_STORE_CTX *csc = NULL;
113 	X509_OBJECT *obj = NULL;
114 	X509	*icert;
115 	RSA	*key = NULL;
116 	time_t	tt;
117 	char	before[15], after[15], *timecomp, *timecomp2;
118 	ASN1_TIME *tm;
119 	int	i;
120 
121 	LOG_DBG((LOG_POLICY, 90,
122 	    "x509_generate_kn: generating KeyNote policy for certificate %p",
123 	    cert));
124 
125 	issuer = X509_get_issuer_name(cert);
126 	subject = X509_get_subject_name(cert);
127 
128 	/* Missing or self-signed, ignore cert but don't report failure.  */
129 	if (!issuer || !subject || !X509_NAME_cmp(issuer, subject))
130 		return 1;
131 
132 	if (!x509_cert_get_key(cert, &key)) {
133 		LOG_DBG((LOG_POLICY, 30,
134 		    "x509_generate_kn: failed to get public key from cert"));
135 		return 0;
136 	}
137 	dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA;
138 	dc.dec_key = key;
139 	ikey = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX,
140 	    KEYNOTE_PUBLIC_KEY);
141 	if (keynote_errno == ERROR_MEMORY) {
142 		log_print("x509_generate_kn: failed to get memory for "
143 		    "public key");
144 		LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get "
145 		    "subject key"));
146 		goto fail;
147 	}
148 	if (!ikey) {
149 		LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get "
150 		    "subject key"));
151 		goto fail;
152 	}
153 
154 	RSA_free(key);
155 	key = NULL;
156 
157 	csc = X509_STORE_CTX_new();
158 	if (csc == NULL) {
159 		log_print("x509_generate_kn: failed to get memory for "
160 		    "certificate store");
161 		goto fail;
162 	}
163 	obj = X509_OBJECT_new();
164 	if (obj == NULL) {
165 		log_print("x509_generate_kn: failed to get memory for "
166 		    "certificate object");
167 		goto fail;
168 	}
169 
170 	/* Now find issuer's certificate so we can get the public key.  */
171 	X509_STORE_CTX_init(csc, x509_cas, cert, NULL);
172 	if (X509_STORE_get_by_subject(csc, X509_LU_X509, issuer, obj) !=
173 	    X509_LU_X509) {
174 		X509_STORE_CTX_cleanup(csc);
175 		X509_STORE_CTX_init(csc, x509_certs, cert, NULL);
176 		if (X509_STORE_get_by_subject(csc, X509_LU_X509, issuer, obj)
177 		    != X509_LU_X509) {
178 			X509_STORE_CTX_cleanup(csc);
179 			LOG_DBG((LOG_POLICY, 30,
180 			    "x509_generate_kn: no certificate found for "
181 			    "issuer"));
182 			goto fail;
183 		}
184 	}
185 	X509_STORE_CTX_free(csc);
186 	csc = NULL;
187 
188 	icert = X509_OBJECT_get0_X509(obj);
189 	if (icert == NULL) {
190 		LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: "
191 		    "missing certificates, cannot construct X509 chain"));
192 		goto fail;
193 	}
194 	if (!x509_cert_get_key(icert, &key)) {
195 		LOG_DBG((LOG_POLICY, 30,
196 		    "x509_generate_kn: failed to get public key from cert"));
197 		goto fail;
198 	}
199 	X509_OBJECT_free(obj);
200 	obj = NULL;
201 
202 	dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA;
203 	dc.dec_key = key;
204 	skey = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX,
205 	    KEYNOTE_PUBLIC_KEY);
206 	if (keynote_errno == ERROR_MEMORY) {
207 		log_error("x509_generate_kn: failed to get memory for public "
208 		    "key");
209 		LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer "
210 		    "key"));
211 		goto fail;
212 	}
213 	if (!skey) {
214 		LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer "
215 		    "key"));
216 		goto fail;
217 	}
218 
219 	RSA_free(key);
220 	key = NULL;
221 
222 	if (((tm = X509_get_notBefore(cert)) == NULL) ||
223 	    (tm->type != V_ASN1_UTCTIME &&
224 		tm->type != V_ASN1_GENERALIZEDTIME)) {
225 		struct tm *ltm;
226 
227 		tt = time(NULL);
228 		if ((ltm = localtime(&tt)) == NULL) {
229 			LOG_DBG((LOG_POLICY, 30,
230 			    "x509_generate_kn: invalid local time"));
231 			goto fail;
232 		}
233 		strftime(before, 14, "%Y%m%d%H%M%S", ltm);
234 		timecomp = "LocalTimeOfDay";
235 	} else {
236 		if (tm->data[tm->length - 1] == 'Z') {
237 			timecomp = "GMTTimeOfDay";
238 			i = tm->length - 2;
239 		} else {
240 			timecomp = "LocalTimeOfDay";
241 			i = tm->length - 1;
242 		}
243 
244 		for (; i >= 0; i--) {
245 			if (tm->data[i] < '0' || tm->data[i] > '9') {
246 				LOG_DBG((LOG_POLICY, 30,
247 				    "x509_generate_kn: invalid data in "
248 				    "NotValidBefore time field"));
249 				goto fail;
250 			}
251 		}
252 
253 		if (tm->type == V_ASN1_UTCTIME) {
254 			if ((tm->length < 10) || (tm->length > 13)) {
255 				LOG_DBG((LOG_POLICY, 30,
256 				    "x509_generate_kn: invalid length "
257 				    "of NotValidBefore time field (%d)",
258 				    tm->length));
259 				goto fail;
260 			}
261 			/* Validity checks.  */
262 			if ((tm->data[2] != '0' && tm->data[2] != '1') ||
263 			    (tm->data[2] == '0' && tm->data[3] == '0') ||
264 			    (tm->data[2] == '1' && tm->data[3] > '2') ||
265 			    (tm->data[4] > '3') ||
266 			    (tm->data[4] == '0' && tm->data[5] == '0') ||
267 			    (tm->data[4] == '3' && tm->data[5] > '1') ||
268 			    (tm->data[6] > '2') ||
269 			    (tm->data[6] == '2' && tm->data[7] > '3') ||
270 			    (tm->data[8] > '5')) {
271 				LOG_DBG((LOG_POLICY, 30,
272 				    "x509_generate_kn: invalid value in "
273 				    "NotValidBefore time field"));
274 				goto fail;
275 			}
276 			/* Stupid UTC tricks.  */
277 			if (tm->data[0] < '5')
278 				snprintf(before, sizeof before, "20%s",
279 				    tm->data);
280 			else
281 				snprintf(before, sizeof before, "19%s",
282 				    tm->data);
283 		} else {	/* V_ASN1_GENERICTIME */
284 			if ((tm->length < 12) || (tm->length > 15)) {
285 				LOG_DBG((LOG_POLICY, 30,
286 				    "x509_generate_kn: invalid length of "
287 				    "NotValidBefore time field (%d)",
288 				    tm->length));
289 				goto fail;
290 			}
291 			/* Validity checks.  */
292 			if ((tm->data[4] != '0' && tm->data[4] != '1') ||
293 			    (tm->data[4] == '0' && tm->data[5] == '0') ||
294 			    (tm->data[4] == '1' && tm->data[5] > '2') ||
295 			    (tm->data[6] > '3') ||
296 			    (tm->data[6] == '0' && tm->data[7] == '0') ||
297 			    (tm->data[6] == '3' && tm->data[7] > '1') ||
298 			    (tm->data[8] > '2') ||
299 			    (tm->data[8] == '2' && tm->data[9] > '3') ||
300 			    (tm->data[10] > '5')) {
301 				LOG_DBG((LOG_POLICY, 30,
302 				    "x509_generate_kn: invalid value in "
303 				    "NotValidBefore time field"));
304 				goto fail;
305 			}
306 			snprintf(before, sizeof before, "%s", tm->data);
307 		}
308 
309 		/* Fix missing seconds.  */
310 		if (tm->length < 12) {
311 			before[12] = '0';
312 			before[13] = '0';
313 		}
314 		/* This will overwrite trailing 'Z'.  */
315 		before[14] = '\0';
316 	}
317 
318 	tm = X509_get_notAfter(cert);
319 	if (tm == NULL ||
320 	    (tm->type != V_ASN1_UTCTIME &&
321 		tm->type != V_ASN1_GENERALIZEDTIME)) {
322 		struct tm *ltm;
323 
324 		tt = time(0);
325 		if ((ltm = localtime(&tt)) == NULL) {
326 			LOG_DBG((LOG_POLICY, 30,
327 			    "x509_generate_kn: invalid local time"));
328 			goto fail;
329 		}
330 		strftime(after, 14, "%Y%m%d%H%M%S", ltm);
331 		timecomp2 = "LocalTimeOfDay";
332 	} else {
333 		if (tm->data[tm->length - 1] == 'Z') {
334 			timecomp2 = "GMTTimeOfDay";
335 			i = tm->length - 2;
336 		} else {
337 			timecomp2 = "LocalTimeOfDay";
338 			i = tm->length - 1;
339 		}
340 
341 		for (; i >= 0; i--) {
342 			if (tm->data[i] < '0' || tm->data[i] > '9') {
343 				LOG_DBG((LOG_POLICY, 30,
344 				    "x509_generate_kn: invalid data in "
345 				    "NotValidAfter time field"));
346 				goto fail;
347 			}
348 		}
349 
350 		if (tm->type == V_ASN1_UTCTIME) {
351 			if ((tm->length < 10) || (tm->length > 13)) {
352 				LOG_DBG((LOG_POLICY, 30,
353 				    "x509_generate_kn: invalid length of "
354 				    "NotValidAfter time field (%d)",
355 				    tm->length));
356 				goto fail;
357 			}
358 			/* Validity checks. */
359 			if ((tm->data[2] != '0' && tm->data[2] != '1') ||
360 			    (tm->data[2] == '0' && tm->data[3] == '0') ||
361 			    (tm->data[2] == '1' && tm->data[3] > '2') ||
362 			    (tm->data[4] > '3') ||
363 			    (tm->data[4] == '0' && tm->data[5] == '0') ||
364 			    (tm->data[4] == '3' && tm->data[5] > '1') ||
365 			    (tm->data[6] > '2') ||
366 			    (tm->data[6] == '2' && tm->data[7] > '3') ||
367 			    (tm->data[8] > '5')) {
368 				LOG_DBG((LOG_POLICY, 30,
369 				    "x509_generate_kn: invalid value in "
370 				    "NotValidAfter time field"));
371 				goto fail;
372 			}
373 			/* Stupid UTC tricks.  */
374 			if (tm->data[0] < '5')
375 				snprintf(after, sizeof after, "20%s",
376 				    tm->data);
377 			else
378 				snprintf(after, sizeof after, "19%s",
379 				    tm->data);
380 		} else {	/* V_ASN1_GENERICTIME */
381 			if ((tm->length < 12) || (tm->length > 15)) {
382 				LOG_DBG((LOG_POLICY, 30,
383 				    "x509_generate_kn: invalid length of "
384 				    "NotValidAfter time field (%d)",
385 				    tm->length));
386 				goto fail;
387 			}
388 			/* Validity checks.  */
389 			if ((tm->data[4] != '0' && tm->data[4] != '1') ||
390 			    (tm->data[4] == '0' && tm->data[5] == '0') ||
391 			    (tm->data[4] == '1' && tm->data[5] > '2') ||
392 			    (tm->data[6] > '3') ||
393 			    (tm->data[6] == '0' && tm->data[7] == '0') ||
394 			    (tm->data[6] == '3' && tm->data[7] > '1') ||
395 			    (tm->data[8] > '2') ||
396 			    (tm->data[8] == '2' && tm->data[9] > '3') ||
397 			    (tm->data[10] > '5')) {
398 				LOG_DBG((LOG_POLICY, 30,
399 				    "x509_generate_kn: invalid value in "
400 				    "NotValidAfter time field"));
401 				goto fail;
402 			}
403 			snprintf(after, sizeof after, "%s", tm->data);
404 		}
405 
406 		/* Fix missing seconds.  */
407 		if (tm->length < 12) {
408 			after[12] = '0';
409 			after[13] = '0';
410 		}
411 		after[14] = '\0';	/* This will overwrite trailing 'Z' */
412 	}
413 
414 	if (asprintf(&buf, fmt, skey, ikey, timecomp, before, timecomp2,
415 	    after) == -1) {
416 		log_error("x509_generate_kn: "
417 		    "failed to allocate memory for KeyNote credential");
418 		goto fail;
419 	}
420 
421 	free(ikey);
422 	ikey = NULL;
423 	free(skey);
424 	skey = NULL;
425 
426 	if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL) == -1) {
427 		LOG_DBG((LOG_POLICY, 30,
428 		    "x509_generate_kn: failed to add new KeyNote credential"));
429 		goto fail;
430 	}
431 	/* We could print the assertion here, but log_print() truncates...  */
432 	LOG_DBG((LOG_POLICY, 60, "x509_generate_kn: added credential"));
433 
434 	free(buf);
435 	buf = NULL;
436 
437 	if (!X509_NAME_oneline(issuer, isname, 256)) {
438 		LOG_DBG((LOG_POLICY, 50,
439 		    "x509_generate_kn: "
440 		    "X509_NAME_oneline (issuer, ...) failed"));
441 		goto fail;
442 	}
443 	if (!X509_NAME_oneline(subject, subname, 256)) {
444 		LOG_DBG((LOG_POLICY, 50,
445 		    "x509_generate_kn: "
446 		    "X509_NAME_oneline (subject, ...) failed"));
447 		goto fail;
448 	}
449 	if (asprintf(&buf, fmt2, isname, subname, timecomp, before,
450 	    timecomp2, after) == -1) {
451 		log_error("x509_generate_kn: malloc failed");
452 		return 0;
453 	}
454 
455 	if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL) == -1) {
456 		LOG_DBG((LOG_POLICY, 30,
457 		    "x509_generate_kn: failed to add new KeyNote credential"));
458 		goto fail;
459 	}
460 	LOG_DBG((LOG_POLICY, 80, "x509_generate_kn: added credential:\n%s",
461 	    buf));
462 
463 	free(buf);
464 	return 1;
465 
466 fail:
467 	X509_STORE_CTX_free(csc);
468 	X509_OBJECT_free(obj);
469 	free(buf);
470 	free(skey);
471 	free(ikey);
472 	if (key)
473 		RSA_free(key);
474 
475 	return 0;
476 }
477 
478 static u_int16_t
x509_hash(u_int8_t * id,size_t len)479 x509_hash(u_int8_t *id, size_t len)
480 {
481 	u_int16_t bucket = 0;
482 	size_t	i;
483 
484 	/* XXX We might resize if we are crossing a certain threshold.  */
485 	for (i = 4; i < (len & ~1); i += 2) {
486 		/* Doing it this way avoids alignment problems.  */
487 		bucket ^= (id[i] + 1) * (id[i + 1] + 257);
488 	}
489 	/* Hash in the last character of odd length IDs too.  */
490 	if (i < len)
491 		bucket ^= (id[i] + 1) * (id[i] + 257);
492 
493 	bucket &= bucket_mask;
494 	return bucket;
495 }
496 
497 static void
x509_hash_init(void)498 x509_hash_init(void)
499 {
500 	struct x509_hash *certh;
501 	int	i;
502 
503 	bucket_mask = (1 << INITIAL_BUCKET_BITS) - 1;
504 
505 	/* If reinitializing, free existing entries.  */
506 	if (x509_tab) {
507 		for (i = 0; i <= bucket_mask; i++)
508 			for (certh = LIST_FIRST(&x509_tab[i]); certh;
509 			    certh = LIST_FIRST(&x509_tab[i])) {
510 				LIST_REMOVE(certh, link);
511 				free(certh);
512 			}
513 		free(x509_tab);
514 	}
515 	x509_tab = calloc(bucket_mask + 1, sizeof(struct x509_list));
516 	if (!x509_tab)
517 		log_fatal("x509_hash_init: malloc (%lu) failed",
518 		    (bucket_mask + 1) *
519 		    (unsigned long)sizeof(struct x509_list));
520 	for (i = 0; i <= bucket_mask; i++) {
521 		LIST_INIT(&x509_tab[i]);
522 	}
523 }
524 
525 /* Lookup a certificate by an ID blob.  */
526 static X509 *
x509_hash_find(u_int8_t * id,size_t len)527 x509_hash_find(u_int8_t *id, size_t len)
528 {
529 	struct x509_hash *cert;
530 	u_int8_t	**cid;
531 	u_int32_t	*clen;
532 	int	n, i, id_found;
533 
534 	for (cert = LIST_FIRST(&x509_tab[x509_hash(id, len)]); cert;
535 	    cert = LIST_NEXT(cert, link)) {
536 		if (!x509_cert_get_subjects(cert->cert, &n, &cid, &clen))
537 			continue;
538 
539 		id_found = 0;
540 		for (i = 0; i < n; i++) {
541 			LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", id, len));
542 			LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", cid[i],
543 			    clen[i]));
544 			/*
545 			 * XXX This identity predicate needs to be
546 			 * understood.
547 			 */
548 			if (clen[i] == len && id[0] == cid[i][0] &&
549 			    memcmp(id + 4, cid[i] + 4, len - 4) == 0) {
550 				id_found++;
551 				break;
552 			}
553 		}
554 		cert_free_subjects(n, cid, clen);
555 		if (!id_found)
556 			continue;
557 
558 		LOG_DBG((LOG_CRYPTO, 70, "x509_hash_find: return X509 %p",
559 		    cert->cert));
560 		return cert->cert;
561 	}
562 
563 	LOG_DBG((LOG_CRYPTO, 70,
564 	    "x509_hash_find: no certificate matched query"));
565 	return 0;
566 }
567 
568 static int
x509_hash_enter(X509 * cert)569 x509_hash_enter(X509 *cert)
570 {
571 	u_int16_t	bucket = 0;
572 	u_int8_t	**id;
573 	u_int32_t	*len;
574 	struct x509_hash *certh;
575 	int	n, i;
576 
577 	if (!x509_cert_get_subjects(cert, &n, &id, &len)) {
578 		log_print("x509_hash_enter: cannot retrieve subjects");
579 		return 0;
580 	}
581 	for (i = 0; i < n; i++) {
582 		certh = calloc(1, sizeof *certh);
583 		if (!certh) {
584 			cert_free_subjects(n, id, len);
585 			log_error("x509_hash_enter: calloc (1, %lu) failed",
586 			    (unsigned long)sizeof *certh);
587 			return 0;
588 		}
589 		certh->cert = cert;
590 
591 		bucket = x509_hash(id[i], len[i]);
592 
593 		LIST_INSERT_HEAD(&x509_tab[bucket], certh, link);
594 		LOG_DBG((LOG_CRYPTO, 70,
595 		    "x509_hash_enter: cert %p added to bucket %d",
596 		    cert, bucket));
597 	}
598 	cert_free_subjects(n, id, len);
599 
600 	return 1;
601 }
602 
603 /* X509 Certificate Handling functions.  */
604 
605 int
x509_read_from_dir(X509_STORE * ctx,char * name,int hash,int * pcount)606 x509_read_from_dir(X509_STORE *ctx, char *name, int hash, int *pcount)
607 {
608 	FILE		*certfp;
609 	X509		*cert;
610 	struct stat	sb;
611 	char		fullname[PATH_MAX];
612 	char		file[PATH_MAX];
613 	int		fd;
614 
615 	if (strlen(name) >= sizeof fullname - 1) {
616 		log_print("x509_read_from_dir: directory name too long");
617 		return 0;
618 	}
619 	LOG_DBG((LOG_CRYPTO, 40, "x509_read_from_dir: reading certs from %s",
620 	    name));
621 
622 	if (monitor_req_readdir(name) == -1) {
623 		LOG_DBG((LOG_CRYPTO, 10,
624 		    "x509_read_from_dir: opendir (\"%s\") failed: %s",
625 		    name, strerror(errno)));
626 		return 0;
627 	}
628 
629 	while ((fd = monitor_readdir(file, sizeof file)) != -1) {
630 		LOG_DBG((LOG_CRYPTO, 60,
631 		    "x509_read_from_dir: reading certificate %s",
632 		    file));
633 
634 		if (fstat(fd, &sb) == -1) {
635 			log_error("x509_read_from_dir: fstat failed");
636 			close(fd);
637 			continue;
638 		}
639 
640 		if (!S_ISREG(sb.st_mode)) {
641 			close(fd);
642 			continue;
643 		}
644 
645 		if ((certfp = fdopen(fd, "r")) == NULL) {
646 			log_error("x509_read_from_dir: fdopen failed");
647 			close(fd);
648 			continue;
649 		}
650 
651 #if SSLEAY_VERSION_NUMBER >= 0x00904100L
652 		cert = PEM_read_X509(certfp, NULL, NULL, NULL);
653 #else
654 		cert = PEM_read_X509(certfp, NULL, NULL);
655 #endif
656 		fclose(certfp);
657 
658 		if (cert == NULL) {
659 			log_print("x509_read_from_dir: PEM_read_X509 "
660 			    "failed for %s", file);
661 			continue;
662 		}
663 
664 		if (pcount != NULL)
665 			(*pcount)++;
666 
667 		if (!X509_STORE_add_cert(ctx, cert)) {
668 			/*
669 			 * This is actually expected if we have several
670 			 * certificates only differing in subjectAltName,
671 			 * which is not an something that is strange.
672 			 * Consider multi-homed machines.
673 			*/
674 			LOG_DBG((LOG_CRYPTO, 50,
675 			    "x509_read_from_dir: X509_STORE_add_cert failed "
676 			    "for %s", file));
677 		}
678 		if (hash)
679 			if (!x509_hash_enter(cert))
680 				log_print("x509_read_from_dir: "
681 				    "x509_hash_enter (%s) failed",
682 				    file);
683 	}
684 
685 	return 1;
686 }
687 
688 /* XXX share code with x509_read_from_dir() ?  */
689 int
x509_read_crls_from_dir(X509_STORE * ctx,char * name)690 x509_read_crls_from_dir(X509_STORE *ctx, char *name)
691 {
692 	FILE		*crlfp;
693 	X509_CRL	*crl;
694 	struct stat	sb;
695 	char		fullname[PATH_MAX];
696 	char		file[PATH_MAX];
697 	int		fd;
698 
699 	if (strlen(name) >= sizeof fullname - 1) {
700 		log_print("x509_read_crls_from_dir: directory name too long");
701 		return 0;
702 	}
703 	LOG_DBG((LOG_CRYPTO, 40, "x509_read_crls_from_dir: reading CRLs "
704 	    "from %s", name));
705 
706 	if (monitor_req_readdir(name) == -1) {
707 		LOG_DBG((LOG_CRYPTO, 10, "x509_read_crls_from_dir: opendir "
708 		    "(\"%s\") failed: %s", name, strerror(errno)));
709 		return 0;
710 	}
711 	strlcpy(fullname, name, sizeof fullname);
712 
713 	while ((fd = monitor_readdir(file, sizeof file)) != -1) {
714 		LOG_DBG((LOG_CRYPTO, 60, "x509_read_crls_from_dir: reading "
715 		    "CRL %s", file));
716 
717 		if (fstat(fd, &sb) == -1) {
718 			log_error("x509_read_crls_from_dir: fstat failed");
719 			close(fd);
720 			continue;
721 		}
722 
723 		if (!S_ISREG(sb.st_mode)) {
724 			close(fd);
725 			continue;
726 		}
727 
728 		if ((crlfp = fdopen(fd, "r")) == NULL) {
729 			log_error("x509_read_crls_from_dir: fdopen failed");
730 			close(fd);
731 			continue;
732 		}
733 
734 		crl = PEM_read_X509_CRL(crlfp, NULL, NULL, NULL);
735 
736 		fclose(crlfp);
737 
738 		if (crl == NULL) {
739 			log_print("x509_read_crls_from_dir: "
740 			    "PEM_read_X509_CRL failed for %s",
741 			    file);
742 			continue;
743 		}
744 		if (!X509_STORE_add_crl(ctx, crl)) {
745 			LOG_DBG((LOG_CRYPTO, 50, "x509_read_crls_from_dir: "
746 			    "X509_STORE_add_crl failed for %s", file));
747 			continue;
748 		}
749 		/*
750 		 * XXX This is to make x509_cert_validate set this (and
751 		 * XXX another) flag when validating certificates. Currently,
752 		 * XXX OpenSSL defaults to reject an otherwise valid
753 		 * XXX certificate (chain) if these flags are set but there
754 		 * XXX are no CRLs to check. The current workaround is to only
755 		 * XXX set the flags if we actually loaded some CRL data.
756 		 */
757 		X509_STORE_set_flags(ctx, X509_V_FLAG_CRL_CHECK);
758 	}
759 
760 	return 1;
761 }
762 
763 /* Initialize our databases and load our own certificates.  */
764 int
x509_cert_init(void)765 x509_cert_init(void)
766 {
767 	char	*dirname;
768 
769 	x509_hash_init();
770 
771 	/* Process CA certificates we will trust.  */
772 	dirname = conf_get_str("X509-certificates", "CA-directory");
773 	if (!dirname) {
774 		log_print("x509_cert_init: no CA-directory");
775 		return 0;
776 	}
777 	/* Free if already initialized.  */
778 	if (x509_cas)
779 		X509_STORE_free(x509_cas);
780 
781 	x509_cas = X509_STORE_new();
782 	if (!x509_cas) {
783 		log_print("x509_cert_init: creating new X509_STORE failed");
784 		return 0;
785 	}
786 	if (!x509_read_from_dir(x509_cas, dirname, 0, &n_x509_cas)) {
787 		log_print("x509_cert_init: x509_read_from_dir failed");
788 		return 0;
789 	}
790 	/* Process client certificates we will accept.  */
791 	dirname = conf_get_str("X509-certificates", "Cert-directory");
792 	if (!dirname) {
793 		log_print("x509_cert_init: no Cert-directory");
794 		return 0;
795 	}
796 	/* Free if already initialized.  */
797 	if (x509_certs)
798 		X509_STORE_free(x509_certs);
799 
800 	x509_certs = X509_STORE_new();
801 	if (!x509_certs) {
802 		log_print("x509_cert_init: creating new X509_STORE failed");
803 		return 0;
804 	}
805 	if (!x509_read_from_dir(x509_certs, dirname, 1, NULL)) {
806 		log_print("x509_cert_init: x509_read_from_dir failed");
807 		return 0;
808 	}
809 	return 1;
810 }
811 
812 int
x509_crl_init(void)813 x509_crl_init(void)
814 {
815 	/*
816 	 * XXX I'm not sure if the method to use CRLs in certificate validation
817 	 * is valid for OpenSSL versions prior to 0.9.7. For now, simply do not
818 	 * support it.
819 	 */
820 	char	*dirname;
821 	dirname = conf_get_str("X509-certificates", "CRL-directory");
822 	if (!dirname) {
823 		log_print("x509_crl_init: no CRL-directory");
824 		return 0;
825 	}
826 	if (!x509_read_crls_from_dir(x509_cas, dirname)) {
827 		LOG_DBG((LOG_MISC, 10,
828 		    "x509_crl_init: x509_read_crls_from_dir failed"));
829 		return 0;
830 	}
831 
832 	return 1;
833 }
834 
835 void *
x509_cert_get(u_int8_t * asn,u_int32_t len)836 x509_cert_get(u_int8_t *asn, u_int32_t len)
837 {
838 	return x509_from_asn(asn, len);
839 }
840 
841 int
x509_cert_validate(void * scert)842 x509_cert_validate(void *scert)
843 {
844 	X509_STORE_CTX	*csc;
845 	X509_NAME	*issuer, *subject;
846 	X509		*cert = (X509 *) scert;
847 	EVP_PKEY	*key;
848 	int		res, err, flags;
849 
850 	/*
851 	 * Validate the peer certificate by checking with the CA certificates
852 	 * we trust.
853 	 */
854 	csc = X509_STORE_CTX_new();
855 	if (csc == NULL) {
856 		log_print("x509_cert_validate: failed to get memory for "
857 		    "certificate store");
858 		return 0;
859 	}
860 	X509_STORE_CTX_init(csc, x509_cas, cert, NULL);
861 	/* XXX See comment in x509_read_crls_from_dir.  */
862 	flags = X509_VERIFY_PARAM_get_flags(X509_STORE_get0_param(x509_cas));
863 	if (flags & X509_V_FLAG_CRL_CHECK) {
864 		X509_STORE_CTX_set_flags(csc, X509_V_FLAG_CRL_CHECK);
865 		X509_STORE_CTX_set_flags(csc, X509_V_FLAG_CRL_CHECK_ALL);
866 	}
867 	res = X509_verify_cert(csc);
868 	err = X509_STORE_CTX_get_error(csc);
869 	X509_STORE_CTX_free(csc);
870 
871 	/*
872 	 * Return if validation succeeded or self-signed certs are not
873 	 * accepted.
874 	 *
875 	 * XXX X509_verify_cert seems to return -1 if the validation should be
876 	 * retried somehow.  We take this as an error and give up.
877 	 */
878 	if (res > 0)
879 		return 1;
880 	else if (res < 0 ||
881 	    (res == 0 && err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)) {
882 		if (err)
883 			log_print("x509_cert_validate: %.100s",
884 			    X509_verify_cert_error_string(err));
885 		return 0;
886 	} else if (!conf_get_str("X509-certificates", "Accept-self-signed")) {
887 		if (err)
888 			log_print("x509_cert_validate: %.100s",
889 			    X509_verify_cert_error_string(err));
890 		return 0;
891 	}
892 	issuer = X509_get_issuer_name(cert);
893 	subject = X509_get_subject_name(cert);
894 
895 	if (!issuer || !subject || X509_NAME_cmp(issuer, subject))
896 		return 0;
897 
898 	key = X509_get_pubkey(cert);
899 	if (!key) {
900 		log_print("x509_cert_validate: could not get public key from "
901 		    "self-signed cert");
902 		return 0;
903 	}
904 	if (X509_verify(cert, key) == -1) {
905 		log_print("x509_cert_validate: self-signed cert is bad");
906 		return 0;
907 	}
908 	return 1;
909 }
910 
911 int
x509_cert_insert(int id,void * scert)912 x509_cert_insert(int id, void *scert)
913 {
914 	X509	*cert;
915 	int	 res;
916 
917 	cert = X509_dup((X509 *)scert);
918 	if (!cert) {
919 		log_print("x509_cert_insert: X509_dup failed");
920 		return 0;
921 	}
922 	if (x509_generate_kn(id, cert) == 0) {
923 		LOG_DBG((LOG_POLICY, 50,
924 		    "x509_cert_insert: x509_generate_kn failed"));
925 		X509_free(cert);
926 		return 0;
927 	}
928 
929 	res = x509_hash_enter(cert);
930 	if (!res)
931 		X509_free(cert);
932 
933 	return res;
934 }
935 
936 static struct x509_hash *
x509_hash_lookup(X509 * cert)937 x509_hash_lookup(X509 *cert)
938 {
939 	struct x509_hash *certh;
940 	int	i;
941 
942 	for (i = 0; i <= bucket_mask; i++)
943 		for (certh = LIST_FIRST(&x509_tab[i]); certh;
944 		    certh = LIST_NEXT(certh, link))
945 			if (certh->cert == cert)
946 				return certh;
947 	return 0;
948 }
949 
950 void
x509_cert_free(void * cert)951 x509_cert_free(void *cert)
952 {
953 	struct x509_hash *certh = x509_hash_lookup((X509 *) cert);
954 
955 	if (certh)
956 		LIST_REMOVE(certh, link);
957 	X509_free((X509 *) cert);
958 }
959 
960 /* Validate the BER Encoding of a RDNSequence in the CERT_REQ payload.  */
961 int
x509_certreq_validate(u_int8_t * asn,u_int32_t len)962 x509_certreq_validate(u_int8_t *asn, u_int32_t len)
963 {
964 	int	res = 1;
965 #if 0
966 	struct norm_type name = SEQOF("issuer", RDNSequence);
967 
968 	if (!asn_template_clone(&name, 1) ||
969 	    (asn = asn_decode_sequence(asn, len, &name)) == 0) {
970 		log_print("x509_certreq_validate: can not decode 'acceptable "
971 		    "CA' info");
972 		res = 0;
973 	}
974 	asn_free(&name);
975 #endif
976 
977 	/* XXX - not supported directly in SSL - later.  */
978 
979 	return res;
980 }
981 
982 /* Decode the BER Encoding of a RDNSequence in the CERT_REQ payload.  */
983 int
x509_certreq_decode(void ** pdata,u_int8_t * asn,u_int32_t len)984 x509_certreq_decode(void **pdata, u_int8_t *asn, u_int32_t len)
985 {
986 #if 0
987 	/* XXX This needs to be done later.  */
988 	struct norm_type aca = SEQOF("aca", RDNSequence);
989 	struct norm_type *tmp;
990 	struct x509_aca naca, *ret;
991 
992 	if (!asn_template_clone(&aca, 1) ||
993 	    (asn = asn_decode_sequence(asn, len, &aca)) == 0) {
994 		log_print("x509_certreq_decode: can not decode 'acceptable "
995 		    "CA' info");
996 		goto fail;
997 	}
998 	bzero(&naca, sizeof(naca));
999 
1000 	tmp = asn_decompose("aca.RelativeDistinguishedName."
1001 	    "AttributeValueAssertion", &aca);
1002 	if (!tmp)
1003 		goto fail;
1004 	x509_get_attribval(tmp, &naca.name1);
1005 
1006 	tmp = asn_decompose("aca.RelativeDistinguishedName[1]"
1007 	    ".AttributeValueAssertion", &aca);
1008 	if (tmp)
1009 		x509_get_attribval(tmp, &naca.name2);
1010 
1011 	asn_free(&aca);
1012 
1013 	ret = malloc(sizeof(struct x509_aca));
1014 	if (ret)
1015 		memcpy(ret, &naca, sizeof(struct x509_aca));
1016 	else {
1017 		log_error("x509_certreq_decode: malloc (%lu) failed",
1018 		    (unsigned long) sizeof(struct x509_aca));
1019 		x509_free_aca(&aca);
1020 	}
1021 
1022 	return ret;
1023 
1024 fail:
1025 	asn_free(&aca);
1026 #endif
1027 	return 1;
1028 }
1029 
1030 void
x509_free_aca(void * blob)1031 x509_free_aca(void *blob)
1032 {
1033 	struct x509_aca *aca = blob;
1034 
1035 	if (aca != NULL) {
1036 		free(aca->name1.type);
1037 		free(aca->name1.val);
1038 
1039 		free(aca->name2.type);
1040 		free(aca->name2.val);
1041 	}
1042 }
1043 
1044 X509 *
x509_from_asn(u_char * asn,u_int len)1045 x509_from_asn(u_char *asn, u_int len)
1046 {
1047 	BIO		*certh;
1048 	X509		*scert = 0;
1049 
1050 	certh = BIO_new(BIO_s_mem());
1051 	if (!certh) {
1052 		log_error("x509_from_asn: BIO_new (BIO_s_mem ()) failed");
1053 		return 0;
1054 	}
1055 	if (BIO_write(certh, asn, len) == -1) {
1056 		log_error("x509_from_asn: BIO_write failed\n");
1057 		goto end;
1058 	}
1059 	scert = d2i_X509_bio(certh, NULL);
1060 	if (!scert) {
1061 		log_print("x509_from_asn: d2i_X509_bio failed\n");
1062 		goto end;
1063 	}
1064 end:
1065 	BIO_free(certh);
1066 	return scert;
1067 }
1068 
1069 /*
1070  * Obtain a certificate from an acceptable CA.
1071  * XXX We don't check if the certificate we find is from an accepted CA.
1072  */
1073 int
x509_cert_obtain(u_int8_t * id,size_t id_len,void * data,u_int8_t ** cert,u_int32_t * certlen)1074 x509_cert_obtain(u_int8_t *id, size_t id_len, void *data, u_int8_t **cert,
1075     u_int32_t *certlen)
1076 {
1077 	struct x509_aca *aca = data;
1078 	X509		*scert;
1079 
1080 	if (aca)
1081 		LOG_DBG((LOG_CRYPTO, 60, "x509_cert_obtain: "
1082 		    "acceptable certificate authorities here"));
1083 
1084 	/* We need our ID to find a certificate.  */
1085 	if (!id) {
1086 		log_print("x509_cert_obtain: ID is missing");
1087 		return 0;
1088 	}
1089 	scert = x509_hash_find(id, id_len);
1090 	if (!scert)
1091 		return 0;
1092 
1093 	x509_serialize(scert, cert, certlen);
1094 	if (!*cert)
1095 		return 0;
1096 	return 1;
1097 }
1098 
1099 /* Returns a pointer to the subjectAltName information of X509 certificate.  */
1100 int
x509_cert_subjectaltname(X509 * scert,u_int8_t ** altname,u_int32_t * len)1101 x509_cert_subjectaltname(X509 *scert, u_int8_t **altname, u_int32_t *len)
1102 {
1103 	X509_EXTENSION		*subjectaltname;
1104 	ASN1_OCTET_STRING	*sanasn1data;
1105 	u_int8_t		*sandata;
1106 	int			 extpos, santype, sanlen;
1107 
1108 	extpos = X509_get_ext_by_NID(scert, NID_subject_alt_name, -1);
1109 	if (extpos == -1) {
1110 		log_print("x509_cert_subjectaltname: "
1111 		    "certificate does not contain subjectAltName");
1112 		return 0;
1113 	}
1114 	subjectaltname = X509_get_ext(scert, extpos);
1115 	sanasn1data = X509_EXTENSION_get_data(subjectaltname);
1116 
1117 	if (!subjectaltname || !sanasn1data || !sanasn1data->data ||
1118 	    sanasn1data->length < 4) {
1119 		log_print("x509_cert_subjectaltname: invalid "
1120 		    "subjectaltname extension");
1121 		return 0;
1122 	}
1123 	/* SSL does not handle unknown ASN stuff well, do it by hand.  */
1124 	sandata = sanasn1data->data;
1125 	santype = sandata[2] & 0x3f;
1126 	sanlen = sandata[3];
1127 	sandata += 4;
1128 
1129 	/*
1130 	 * The test here used to be !=, but some certificates can include
1131 	 * extra stuff in subjectAltName, so we will just take the first
1132 	 * salen bytes, and not worry about what follows.
1133 	 */
1134 	if (sanlen + 4 > sanasn1data->length) {
1135 		log_print("x509_cert_subjectaltname: subjectaltname invalid "
1136 		    "length");
1137 		return 0;
1138 	}
1139 	*len = sanlen;
1140 	*altname = sandata;
1141 	return santype;
1142 }
1143 
1144 int
x509_cert_get_subjects(void * scert,int * cnt,u_int8_t *** id,u_int32_t ** id_len)1145 x509_cert_get_subjects(void *scert, int *cnt, u_int8_t ***id,
1146     u_int32_t **id_len)
1147 {
1148 	X509		*cert = scert;
1149 	X509_NAME	*subject;
1150 	int		type;
1151 	u_int8_t	*altname;
1152 	u_int32_t	altlen;
1153 	u_int8_t	*buf = 0;
1154 	unsigned char	*ubuf;
1155 	int		i;
1156 
1157 	*id = 0;
1158 	*id_len = 0;
1159 
1160 	/*
1161 	 * XXX There can be a collection of subjectAltNames, but for now I
1162 	 * only return the subjectName and a single subjectAltName, if
1163 	 * present.
1164 	 */
1165 	type = x509_cert_subjectaltname(cert, &altname, &altlen);
1166 	if (!type) {
1167 		*cnt = 1;
1168 		altlen = 0;
1169 	} else
1170 		*cnt = 2;
1171 
1172 	*id = calloc(*cnt, sizeof **id);
1173 	if (!*id) {
1174 		log_print("x509_cert_get_subject: malloc (%lu) failed",
1175 		    *cnt * (unsigned long)sizeof **id);
1176 		*cnt = 0;
1177 		goto fail;
1178 	}
1179 	*id_len = calloc(*cnt, sizeof **id_len);
1180 	if (!*id_len) {
1181 		log_print("x509_cert_get_subject: malloc (%lu) failed",
1182 		    *cnt * (unsigned long)sizeof **id_len);
1183 		goto fail;
1184 	}
1185 	/* Stash the subjectName into the first slot.  */
1186 	subject = X509_get_subject_name(cert);
1187 	if (!subject)
1188 		goto fail;
1189 
1190 	(*id_len)[0] =
1191 		ISAKMP_ID_DATA_OFF + i2d_X509_NAME(subject, NULL) -
1192 		    ISAKMP_GEN_SZ;
1193 	(*id)[0] = malloc((*id_len)[0]);
1194 	if (!(*id)[0]) {
1195 		log_print("x509_cert_get_subject: malloc (%d) failed",
1196 		    (*id_len)[0]);
1197 		goto fail;
1198 	}
1199 	SET_ISAKMP_ID_TYPE((*id)[0] - ISAKMP_GEN_SZ, IPSEC_ID_DER_ASN1_DN);
1200 	ubuf = (*id)[0] + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
1201 	i2d_X509_NAME(subject, &ubuf);
1202 
1203 	if (altlen) {
1204 		/* Stash the subjectAltName into the second slot.  */
1205 		buf = malloc(altlen + ISAKMP_ID_DATA_OFF);
1206 		if (!buf) {
1207 			log_print("x509_cert_get_subject: malloc (%d) failed",
1208 			    altlen + ISAKMP_ID_DATA_OFF);
1209 			goto fail;
1210 		}
1211 		switch (type) {
1212 		case X509v3_DNS_NAME:
1213 			SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_FQDN);
1214 			break;
1215 
1216 		case X509v3_RFC_NAME:
1217 			SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_USER_FQDN);
1218 			break;
1219 
1220 		case X509v3_IP_ADDR:
1221 			/*
1222 			 * XXX I dislike the numeric constants, but I don't
1223 			 * know what we should use otherwise.
1224 			 */
1225 			switch (altlen) {
1226 			case 4:
1227 				SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV4_ADDR);
1228 				break;
1229 
1230 			case 16:
1231 				SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV6_ADDR);
1232 				break;
1233 
1234 			default:
1235 				log_print("x509_cert_get_subject: invalid "
1236 				    "subjectAltName IPaddress length %d ",
1237 				    altlen);
1238 				goto fail;
1239 			}
1240 			break;
1241 		}
1242 
1243 		SET_IPSEC_ID_PROTO(buf + ISAKMP_ID_DOI_DATA_OFF, 0);
1244 		SET_IPSEC_ID_PORT(buf + ISAKMP_ID_DOI_DATA_OFF, 0);
1245 		memcpy(buf + ISAKMP_ID_DATA_OFF, altname, altlen);
1246 
1247 		(*id_len)[1] = ISAKMP_ID_DATA_OFF + altlen - ISAKMP_GEN_SZ;
1248 		(*id)[1] = malloc((*id_len)[1]);
1249 		if (!(*id)[1]) {
1250 			log_print("x509_cert_get_subject: malloc (%d) failed",
1251 			    (*id_len)[1]);
1252 			goto fail;
1253 		}
1254 		memcpy((*id)[1], buf + ISAKMP_GEN_SZ, (*id_len)[1]);
1255 
1256 		free(buf);
1257 		buf = 0;
1258 	}
1259 	return 1;
1260 
1261 fail:
1262 	for (i = 0; i < *cnt; i++)
1263 		free((*id)[i]);
1264 	free(*id);
1265 	free(*id_len);
1266 	free(buf);
1267 	return 0;
1268 }
1269 
1270 int
x509_cert_get_key(void * scert,void * keyp)1271 x509_cert_get_key(void *scert, void *keyp)
1272 {
1273 	X509		*cert = scert;
1274 	EVP_PKEY	*key;
1275 
1276 	key = X509_get_pubkey(cert);
1277 
1278 	/* Check if we got the right key type.  */
1279 	if (EVP_PKEY_id(key) != EVP_PKEY_RSA) {
1280 		log_print("x509_cert_get_key: public key is not a RSA key");
1281 		X509_free(cert);
1282 		return 0;
1283 	}
1284 	*(RSA **)keyp = RSAPublicKey_dup(EVP_PKEY_get0_RSA(key));
1285 
1286 	return *(RSA **)keyp == NULL ? 0 : 1;
1287 }
1288 
1289 void *
x509_cert_dup(void * scert)1290 x509_cert_dup(void *scert)
1291 {
1292 	return X509_dup(scert);
1293 }
1294 
1295 void
x509_serialize(void * scert,u_int8_t ** data,u_int32_t * datalen)1296 x509_serialize(void *scert, u_int8_t **data, u_int32_t *datalen)
1297 {
1298 	u_int8_t	*p;
1299 
1300 	*datalen = i2d_X509((X509 *)scert, NULL);
1301 	*data = p = malloc(*datalen);
1302 	if (!p) {
1303 		log_error("x509_serialize: malloc (%d) failed", *datalen);
1304 		return;
1305 	}
1306 	*datalen = i2d_X509((X509 *)scert, &p);
1307 }
1308 
1309 /* From cert to printable */
1310 char *
x509_printable(void * cert)1311 x509_printable(void *cert)
1312 {
1313 	char		*s;
1314 	u_int8_t	*data;
1315 	u_int32_t	datalen;
1316 
1317 	x509_serialize(cert, &data, &datalen);
1318 	if (!data)
1319 		return 0;
1320 
1321 	s = raw2hex(data, datalen);
1322 	free(data);
1323 	return s;
1324 }
1325 
1326 /* From printable to cert */
1327 void *
x509_from_printable(char * cert)1328 x509_from_printable(char *cert)
1329 {
1330 	u_int8_t	*buf;
1331 	int		plen, ret;
1332 	void		*foo;
1333 
1334 	plen = (strlen(cert) + 1) / 2;
1335 	buf = malloc(plen);
1336 	if (!buf) {
1337 		log_error("x509_from_printable: malloc (%d) failed", plen);
1338 		return 0;
1339 	}
1340 	ret = hex2raw(cert, buf, plen);
1341 	if (ret == -1) {
1342 		free(buf);
1343 		log_print("x509_from_printable: badly formatted cert");
1344 		return 0;
1345 	}
1346 	foo = x509_cert_get(buf, plen);
1347 	free(buf);
1348 	if (!foo)
1349 		log_print("x509_from_printable: "
1350 		    "could not retrieve certificate");
1351 	return foo;
1352 }
1353 
1354 char *
x509_DN_string(u_int8_t * asn1,size_t sz)1355 x509_DN_string(u_int8_t *asn1, size_t sz)
1356 {
1357 	X509_NAME	*name;
1358 	const u_int8_t	*p = asn1;
1359 	char		buf[256];	/* XXX Just a guess at a maximum length.  */
1360 	long len = sz;
1361 
1362 	name = d2i_X509_NAME(NULL, &p, len);
1363 	if (!name) {
1364 		log_print("x509_DN_string: d2i_X509_NAME failed");
1365 		return 0;
1366 	}
1367 	if (!X509_NAME_oneline(name, buf, sizeof buf - 1)) {
1368 		log_print("x509_DN_string: X509_NAME_oneline failed");
1369 		X509_NAME_free(name);
1370 		return 0;
1371 	}
1372 	X509_NAME_free(name);
1373 	buf[sizeof buf - 1] = '\0';
1374 	return strdup(buf);
1375 }
1376 
1377 /* Number of CAs we trust (to decide whether we can send CERT_REQ) */
1378 int
x509_ca_count(void)1379 x509_ca_count(void)
1380 {
1381 	return n_x509_cas;
1382 }
1383