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