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