xref: /openbsd-src/usr.sbin/ikectl/ikeca.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: ikeca.c,v 1.40 2015/11/02 12:21:27 jsg Exp $	*/
2 
3 /*
4  * Copyright (c) 2010 Jonathan Gray <jsg@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <err.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <pwd.h>
28 #include <fcntl.h>
29 #include <fts.h>
30 #include <dirent.h>
31 #include <limits.h>
32 
33 #include <openssl/rand.h>
34 #include <openssl/rsa.h>
35 #include <openssl/pem.h>
36 
37 #include "types.h"
38 #include "parser.h"
39 
40 #ifndef PREFIX
41 #define PREFIX		""
42 #endif
43 #ifndef SSLDIR
44 #define SSLDIR		PREFIX "/etc/ssl"
45 #endif
46 #define SSL_CNF		SSLDIR "/openssl.cnf"
47 #define X509_CNF	SSLDIR "/x509v3.cnf"
48 #define IKECA_CNF	SSLDIR "/ikeca.cnf"
49 #define KEYBASE		PREFIX "/etc/iked"
50 #ifndef EXPDIR
51 #define EXPDIR		PREFIX "/usr/share/iked"
52 #endif
53 
54 #ifndef PATH_OPENSSL
55 #define PATH_OPENSSL	"/usr/bin/openssl"
56 #endif
57 #ifndef PATH_ZIP
58 #define PATH_ZIP	"/usr/local/bin/zip"
59 #endif
60 #ifndef PATH_TAR
61 #define PATH_TAR	"/bin/tar"
62 #endif
63 
64 struct ca {
65 	char		 sslpath[PATH_MAX];
66 	char		 passfile[PATH_MAX];
67 	char		 index[PATH_MAX];
68 	char		 serial[PATH_MAX];
69 	char		 sslcnf[PATH_MAX];
70 	char		 extcnf[PATH_MAX];
71 	char		 batch[PATH_MAX];
72 	char		*caname;
73 };
74 
75 struct {
76 	char	*dir;
77 	mode_t	 mode;
78 } hier[] = {
79 	{ "",		0755 },
80 	{ "/ca",	0755 },
81 	{ "/certs",	0755 },
82 	{ "/crls",	0755 },
83 	{ "/export",	0755 },
84 	{ "/private",	0700 }
85 };
86 
87 /* explicitly list allowed variables */
88 const char *ca_env[][2] = {
89 	{ "$ENV::CADB", NULL },
90 	{ "$ENV::CASERIAL", NULL },
91 	{ "$ENV::CERTFQDN", NULL },
92 	{ "$ENV::CERTIP", NULL },
93 	{ "$ENV::CERTPATHLEN", NULL },
94 	{ "$ENV::CERTUSAGE", NULL },
95 	{ "$ENV::CERT_C", NULL },
96 	{ "$ENV::CERT_CN", NULL },
97 	{ "$ENV::CERT_EMAIL", NULL },
98 	{ "$ENV::CERT_L", NULL },
99 	{ "$ENV::CERT_O", NULL },
100 	{ "$ENV::CERT_OU", NULL },
101 	{ "$ENV::CERT_ST", NULL },
102 	{ "$ENV::EXTCERTUSAGE", NULL },
103 	{ "$ENV::NSCERTTYPE", NULL },
104 	{ NULL }
105 };
106 
107 int		 ca_sign(struct ca *, char *, int);
108 int		 ca_request(struct ca *, char *);
109 void		 ca_newpass(char *, char *);
110 char		*ca_readpass(char *, size_t *);
111 int		 fcopy(char *, char *, mode_t);
112 void		 fcopy_env(const char *, const char *, mode_t);
113 int		 rm_dir(char *);
114 void		 ca_hier(char *);
115 void		 ca_setenv(const char *, const char *);
116 void		 ca_clrenv(void);
117 void		 ca_setcnf(struct ca *, const char *);
118 void		 ca_create_index(struct ca *);
119 
120 /* util.c */
121 int		 expand_string(char *, size_t, const char *, const char *);
122 
123 int
124 ca_delete(struct ca *ca)
125 {
126 	return (rm_dir(ca->sslpath));
127 }
128 
129 int
130 ca_key_create(struct ca *ca, char *keyname)
131 {
132 	struct stat		 st;
133 	char			 cmd[PATH_MAX * 2];
134 	char			 path[PATH_MAX];
135 
136 	snprintf(path, sizeof(path), "%s/private/%s.key", ca->sslpath, keyname);
137 
138 	/* don't recreate key if one is already present */
139 	if (stat(path, &st) == 0) {
140 		return (0);
141 	}
142 
143 	snprintf(cmd, sizeof(cmd),
144 	    "%s genrsa -out %s 2048",
145 	    PATH_OPENSSL, path);
146 	system(cmd);
147 	chmod(path, 0600);
148 
149 	return (0);
150 }
151 
152 int
153 ca_key_import(struct ca *ca, char *keyname, char *import)
154 {
155 	struct stat		 st;
156 	char			 dst[PATH_MAX];
157 
158 	if (stat(import, &st) != 0) {
159 		warn("could not access keyfile %s", import);
160 		return (1);
161 	}
162 
163 	snprintf(dst, sizeof(dst), "%s/private/%s.key", ca->sslpath, keyname);
164 	fcopy(import, dst, 0600);
165 
166 	return (0);
167 }
168 
169 int
170 ca_key_delete(struct ca *ca, char *keyname)
171 {
172 	char			 path[PATH_MAX];
173 
174 	snprintf(path, sizeof(path), "%s/private/%s.key", ca->sslpath, keyname);
175 	unlink(path);
176 
177 	return (0);
178 }
179 
180 int
181 ca_delkey(struct ca *ca, char *keyname)
182 {
183 	char		file[PATH_MAX];
184 
185 	snprintf(file, sizeof(file), "%s/%s.crt", ca->sslpath, keyname);
186 	unlink(file);
187 
188 	snprintf(file, sizeof(file), "%s/private/%s.key", ca->sslpath, keyname);
189 	unlink(file);
190 
191 	snprintf(file, sizeof(file), "%s/private/%s.csr", ca->sslpath, keyname);
192 	unlink(file);
193 
194 	snprintf(file, sizeof(file), "%s/private/%s.pfx", ca->sslpath, keyname);
195 	unlink(file);
196 
197 	return (0);
198 }
199 
200 int
201 ca_request(struct ca *ca, char *keyname)
202 {
203 	char		cmd[PATH_MAX * 2];
204 	char		path[PATH_MAX];
205 
206 	ca_setenv("$ENV::CERT_CN", keyname);
207 	ca_setcnf(ca, keyname);
208 
209 	snprintf(path, sizeof(path), "%s/private/%s.csr", ca->sslpath, keyname);
210 	snprintf(cmd, sizeof(cmd), "%s req %s-new"
211 	    " -key %s/private/%s.key -out %s -config %s",
212 	    PATH_OPENSSL, ca->batch, ca->sslpath, keyname,
213 	    path, ca->sslcnf);
214 
215 	system(cmd);
216 	chmod(path, 0600);
217 
218 	return (0);
219 }
220 
221 int
222 ca_sign(struct ca *ca, char *keyname, int type)
223 {
224 	char		cmd[PATH_MAX * 2];
225 	char		hostname[HOST_NAME_MAX+1];
226 	char		name[128];
227 	const char	*extensions = NULL;
228 
229 	strlcpy(name, keyname, sizeof(name));
230 
231 	if (type == HOST_IPADDR) {
232 		ca_setenv("$ENV::CERTIP", name);
233 		extensions = "x509v3_IPAddr";
234 	} else if (type == HOST_FQDN) {
235 		if (!strcmp(keyname, "local")) {
236 			if (gethostname(hostname, sizeof(hostname)))
237 				err(1, "gethostname");
238 			strlcpy(name, hostname, sizeof(name));
239 		}
240 		ca_setenv("$ENV::CERTFQDN", name);
241 		extensions = "x509v3_FQDN";
242 	} else {
243 		errx(1, "unknown host type %d", type);
244 	}
245 
246 	ca_create_index(ca);
247 
248 	ca_setenv("$ENV::CADB", ca->index);
249 	ca_setenv("$ENV::CASERIAL", ca->serial);
250 	ca_setcnf(ca, keyname);
251 
252 	snprintf(cmd, sizeof(cmd),
253 	    "%s ca -config %s -keyfile %s/private/ca.key"
254 	    " -cert %s/ca.crt"
255 	    " -extfile %s -extensions %s -out %s/%s.crt"
256 	    " -in %s/private/%s.csr"
257 	    " -passin file:%s -outdir %s -batch",
258 	    PATH_OPENSSL, ca->sslcnf, ca->sslpath,
259 	    ca->sslpath,
260 	    ca->extcnf, extensions, ca->sslpath, keyname,
261 	    ca->sslpath, keyname,
262 	    ca->passfile, ca->sslpath);
263 
264 	system(cmd);
265 
266 	return (0);
267 }
268 
269 int
270 ca_certificate(struct ca *ca, char *keyname, int type, int action)
271 {
272 	ca_clrenv();
273 
274 	switch (action) {
275 	case CA_SERVER:
276 		ca_setenv("$ENV::EXTCERTUSAGE", "serverAuth");
277 		ca_setenv("$ENV::NSCERTTYPE", "server");
278 		ca_setenv("$ENV::CERTUSAGE",
279 		    "digitalSignature,keyEncipherment");
280 		break;
281 	case CA_CLIENT:
282 		ca_setenv("$ENV::EXTCERTUSAGE", "clientAuth");
283 		ca_setenv("$ENV::NSCERTTYPE", "client");
284 		ca_setenv("$ENV::CERTUSAGE",
285 		    "digitalSignature,keyAgreement");
286 		break;
287 	case CA_OCSP:
288 		ca_setenv("$ENV::EXTCERTUSAGE", "OCSPSigning");
289 		ca_setenv("$ENV::CERTUSAGE",
290 		    "nonRepudiation,digitalSignature,keyEncipherment");
291 		break;
292 	default:
293 		break;
294 	}
295 
296 	ca_key_create(ca, keyname);
297 	ca_request(ca, keyname);
298 	ca_sign(ca, keyname, type);
299 
300 	return (0);
301 }
302 
303 int
304 ca_key_install(struct ca *ca, char *keyname, char *dir)
305 {
306 	struct stat	 st;
307 	char		 cmd[PATH_MAX * 2];
308 	char		 src[PATH_MAX];
309 	char		 dst[PATH_MAX];
310 	char		*p = NULL;
311 
312 	snprintf(src, sizeof(src), "%s/private/%s.key", ca->sslpath, keyname);
313 	if (stat(src, &st) == -1) {
314 		if (errno == ENOENT)
315 			printf("key for '%s' does not exist\n", ca->caname);
316 		else
317 			warn("could not access key");
318 		return (1);
319 	}
320 
321 	if (dir == NULL)
322 		p = dir = strdup(KEYBASE);
323 
324 	ca_hier(dir);
325 
326 	snprintf(dst, sizeof(dst), "%s/private/local.key", dir);
327 	fcopy(src, dst, 0600);
328 
329 	snprintf(cmd, sizeof(cmd), "%s rsa -out %s/local.pub"
330 	    " -in %s/private/local.key -pubout", PATH_OPENSSL, dir, dir);
331 	system(cmd);
332 
333 	free(p);
334 
335 	return (0);
336 }
337 
338 int
339 ca_cert_install(struct ca *ca, char *keyname, char *dir)
340 {
341 	char		 src[PATH_MAX];
342 	char		 dst[PATH_MAX];
343 	int		 r;
344 	char		*p = NULL;
345 
346 	if (dir == NULL)
347 		p = dir = strdup(KEYBASE);
348 
349 	ca_hier(dir);
350 
351 	if ((r = ca_key_install(ca, keyname, dir)) != 0) {
352 		free(dir);
353 		return (r);
354 	}
355 
356 	snprintf(src, sizeof(src), "%s/%s.crt", ca->sslpath, keyname);
357 	snprintf(dst, sizeof(dst), "%s/certs/%s.crt", dir, keyname);
358 	fcopy(src, dst, 0644);
359 
360 	free(p);
361 
362 	return (0);
363 }
364 
365 void
366 ca_newpass(char *passfile, char *password)
367 {
368 	FILE	*f;
369 	char	*pass;
370 	char	 prev[_PASSWORD_LEN + 1];
371 
372 	if (password != NULL) {
373 		pass = password;
374 		goto done;
375 	}
376 
377 	pass = getpass("CA passphrase:");
378 	if (pass == NULL || *pass == '\0')
379 		err(1, "password not set");
380 
381 	strlcpy(prev, pass, sizeof(prev));
382 	pass = getpass("Retype CA passphrase:");
383 	if (pass == NULL || strcmp(prev, pass) != 0)
384 		errx(1, "passphrase does not match!");
385 
386  done:
387 	if ((f = fopen(passfile, "wb")) == NULL)
388 		err(1, "could not open passfile %s", passfile);
389 	chmod(passfile, 0600);
390 
391 	fprintf(f, "%s\n%s\n", pass, pass);
392 
393 	fclose(f);
394 }
395 
396 int
397 ca_create(struct ca *ca)
398 {
399 	char			 cmd[PATH_MAX * 2];
400 	char			 path[PATH_MAX];
401 
402 	ca_clrenv();
403 
404 	snprintf(path, sizeof(path), "%s/private/ca.key", ca->sslpath);
405 	snprintf(cmd, sizeof(cmd), "%s genrsa -aes256 -out"
406 	    " %s -passout file:%s 2048", PATH_OPENSSL,
407 	    path, ca->passfile);
408 	system(cmd);
409 	chmod(path, 0600);
410 
411 	ca_setenv("$ENV::CERT_CN", "VPN CA");
412 	ca_setcnf(ca, "ca");
413 
414 	snprintf(path, sizeof(path), "%s/private/ca.csr", ca->sslpath);
415 	snprintf(cmd, sizeof(cmd), "%s req %s-new"
416 	    " -key %s/private/ca.key"
417 	    " -config %s -out %s -passin file:%s", PATH_OPENSSL,
418 	    ca->batch, ca->sslpath, ca->sslcnf, path, ca->passfile);
419 	system(cmd);
420 	chmod(path, 0600);
421 
422 	snprintf(cmd, sizeof(cmd), "%s x509 -req -days 365"
423 	    " -in %s/private/ca.csr -signkey %s/private/ca.key"
424 	    " -sha256"
425 	    " -extfile %s -extensions x509v3_CA -out %s/ca.crt -passin file:%s",
426 	    PATH_OPENSSL, ca->sslpath, ca->sslpath, ca->extcnf, ca->sslpath,
427 	    ca->passfile);
428 	system(cmd);
429 
430 	/* Create the CRL revocation list */
431 	ca_revoke(ca, NULL);
432 
433 	return (0);
434 }
435 
436 int
437 ca_install(struct ca *ca, char *dir)
438 {
439 	struct stat	 st;
440 	char		 src[PATH_MAX];
441 	char		 dst[PATH_MAX];
442 	char		*p = NULL;
443 
444 	snprintf(src, sizeof(src), "%s/ca.crt", ca->sslpath);
445 	if (stat(src, &st) == -1) {
446 		printf("CA '%s' does not exist\n", ca->caname);
447 		return (1);
448 	}
449 
450 	if (dir == NULL)
451 		p = dir = strdup(KEYBASE);
452 
453 	ca_hier(dir);
454 
455 	snprintf(dst, sizeof(dst), "%s/ca/ca.crt", dir);
456 	if (fcopy(src, dst, 0644) == 0)
457 		printf("certificate for CA '%s' installed into %s\n",
458 		    ca->caname, dst);
459 
460 	snprintf(src, sizeof(src), "%s/ca.crl", ca->sslpath);
461 	if (stat(src, &st) == 0) {
462 		snprintf(dst, sizeof(dst), "%s/crls/ca.crl", dir);
463 		if (fcopy(src, dst, 0644) == 0)
464 			printf("CRL for CA '%s' installed to %s\n",
465 			    ca->caname, dst);
466 	}
467 
468 	free(p);
469 
470 	return (0);
471 }
472 
473 int
474 ca_show_certs(struct ca *ca, char *name)
475 {
476 	DIR		*dir;
477 	struct dirent	*de;
478 	char		 cmd[PATH_MAX * 2];
479 	char		 path[PATH_MAX];
480 	char		*p;
481 	struct stat	 st;
482 
483 	if (name != NULL) {
484 		snprintf(path, sizeof(path), "%s/%s.crt",
485 		    ca->sslpath, name);
486 		if (stat(path, &st) != 0)
487 			err(1, "could not open file %s.crt", name);
488 		snprintf(cmd, sizeof(cmd), "%s x509 -text"
489 		    " -in %s", PATH_OPENSSL, path);
490 		system(cmd);
491 		printf("\n");
492 		return (0);
493 	}
494 
495 	if ((dir = opendir(ca->sslpath)) == NULL)
496 		err(1, "could not open directory %s", ca->sslpath);
497 
498 	while ((de = readdir(dir)) != NULL) {
499 		if (de->d_namlen > 4) {
500 			p = de->d_name + de->d_namlen - 4;
501 			if (strcmp(".crt", p) != 0)
502 				continue;
503 			snprintf(path, sizeof(path), "%s/%s", ca->sslpath,
504 			    de->d_name);
505 			snprintf(cmd, sizeof(cmd), "%s x509 -subject"
506 			    " -fingerprint -dates -noout -in %s",
507 			    PATH_OPENSSL, path);
508 			system(cmd);
509 			printf("\n");
510 		}
511 	}
512 
513 	closedir(dir);
514 
515 	return (0);
516 }
517 
518 int
519 fcopy(char *src, char *dst, mode_t mode)
520 {
521 	int		ifd, ofd;
522 	uint8_t		buf[BUFSIZ];
523 	ssize_t		r;
524 
525 	if ((ifd = open(src, O_RDONLY)) == -1)
526 		err(1, "open %s", src);
527 
528 	if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) {
529 		int saved_errno = errno;
530 		close(ifd);
531 		errc(1, saved_errno, "open %s", dst);
532 	}
533 
534 	while ((r = read(ifd, buf, sizeof(buf))) > 0) {
535 		write(ofd, buf, r);
536 	}
537 
538 	close(ofd);
539 	close(ifd);
540 
541 	return (r == -1);
542 }
543 
544 void
545 fcopy_env(const char *src, const char *dst, mode_t mode)
546 {
547 	int		 ofd = -1, i;
548 	uint8_t		 buf[BUFSIZ];
549 	ssize_t		 r = -1, len;
550 	FILE		*ifp = NULL;
551 	int		 saved_errno;
552 
553 	if ((ifp = fopen(src, "r")) == NULL)
554 		err(1, "fopen %s", src);
555 
556 	if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1)
557 		goto done;
558 
559 	while (fgets(buf, sizeof(buf), ifp) != NULL) {
560 		for (i = 0; ca_env[i][0] != NULL; i++) {
561 			if (ca_env[i][1] == NULL)
562 				continue;
563 			if (expand_string(buf, sizeof(buf),
564 			    ca_env[i][0], ca_env[i][1]) == -1)
565 				errx(1, "env %s value too long", ca_env[i][0]);
566 		}
567 		len = strlen(buf);
568 		if (write(ofd, buf, len) != len)
569 			goto done;
570 	}
571 
572 	r = 0;
573 
574  done:
575 	saved_errno = errno;
576 	close(ofd);
577 	if (ifp != NULL)
578 		fclose(ifp);
579 	if (r == -1)
580 		errc(1, saved_errno, "open %s", dst);
581 }
582 
583 int
584 rm_dir(char *path)
585 {
586 	FTS		*fts;
587 	FTSENT		*p;
588 	static char	*fpath[] = { NULL, NULL };
589 
590 	fpath[0] = path;
591 	if ((fts = fts_open(fpath, FTS_PHYSICAL, NULL)) == NULL) {
592 		warn("fts_open %s", path);
593 		return (1);
594 	}
595 
596 	while ((p = fts_read(fts)) != NULL) {
597 		switch (p->fts_info) {
598 		case FTS_DP:
599 		case FTS_DNR:
600 			if (rmdir(p->fts_accpath) == -1)
601 				warn("rmdir %s", p->fts_accpath);
602 			break;
603 		case FTS_F:
604 			if (unlink(p->fts_accpath) == -1)
605 				warn("unlink %s", p->fts_accpath);
606 			break;
607 		case FTS_D:
608 		case FTS_DOT:
609 		default:
610 			continue;
611 		}
612 	}
613 	fts_close(fts);
614 
615 	return (0);
616 }
617 
618 void
619 ca_hier(char *path)
620 {
621 	struct stat	 st;
622 	char		 dst[PATH_MAX];
623 	unsigned int	 i;
624 
625 	for (i = 0; i < nitems(hier); i++) {
626 		strlcpy(dst, path, sizeof(dst));
627 		strlcat(dst, hier[i].dir, sizeof(dst));
628 		if (stat(dst, &st) != 0 && errno == ENOENT &&
629 		    mkdir(dst, hier[i].mode) != 0)
630 			err(1, "failed to create dir %s", dst);
631 	}
632 }
633 
634 int
635 ca_export(struct ca *ca, char *keyname, char *myname, char *password)
636 {
637 	DIR		*dexp;
638 	struct dirent	*de;
639 	struct stat	 st;
640 	char		*pass;
641 	char		 prev[_PASSWORD_LEN + 1];
642 	char		 cmd[PATH_MAX * 2];
643 	char		 oname[PATH_MAX];
644 	char		 src[PATH_MAX];
645 	char		 dst[PATH_MAX];
646 	char		*p;
647 	char		 tpl[] = "/tmp/ikectl.XXXXXXXXXX";
648 	unsigned int	 i;
649 	int		 fd;
650 
651 	if (keyname != NULL) {
652 		if (strlcpy(oname, keyname, sizeof(oname)) >= sizeof(oname))
653 			errx(1, "name too long");
654 	} else {
655 		strlcpy(oname, "ca", sizeof(oname));
656 	}
657 
658 	/* colons are not valid characters in windows filenames... */
659 	while ((p = strchr(oname, ':')) != NULL)
660 		*p = '_';
661 
662 	if (password != NULL)
663 		pass = password;
664 	else {
665 		pass = getpass("Export passphrase:");
666 		if (pass == NULL || *pass == '\0')
667 			err(1, "password not set");
668 
669 		strlcpy(prev, pass, sizeof(prev));
670 		pass = getpass("Retype export passphrase:");
671 		if (pass == NULL || strcmp(prev, pass) != 0)
672 			errx(1, "passphrase does not match!");
673 	}
674 
675 	if (keyname != NULL) {
676 		snprintf(cmd, sizeof(cmd), "env EXPASS=%s %s pkcs12 -export"
677 		    " -name %s -CAfile %s/ca.crt -inkey %s/private/%s.key"
678 		    " -in %s/%s.crt -out %s/private/%s.pfx -passout env:EXPASS"
679 		    " -passin file:%s", pass, PATH_OPENSSL, keyname,
680 		    ca->sslpath, ca->sslpath, keyname, ca->sslpath, keyname,
681 		    ca->sslpath, oname, ca->passfile);
682 		system(cmd);
683 	}
684 
685 	snprintf(cmd, sizeof(cmd), "env EXPASS=%s %s pkcs12 -export"
686 	    " -caname '%s' -name '%s' -cacerts -nokeys"
687 	    " -in %s/ca.crt -out %s/ca.pfx -passout env:EXPASS -passin file:%s",
688 	    pass, PATH_OPENSSL, ca->caname, ca->caname, ca->sslpath,
689 	    ca->sslpath, ca->passfile);
690 	system(cmd);
691 
692 	if ((p = mkdtemp(tpl)) == NULL)
693 		err(1, "could not create temp dir");
694 
695 	chmod(p, 0755);
696 
697 	for (i = 0; i < nitems(hier); i++) {
698 		strlcpy(dst, p, sizeof(dst));
699 		strlcat(dst, hier[i].dir, sizeof(dst));
700 		if (stat(dst, &st) != 0 && errno == ENOENT &&
701 		    mkdir(dst, hier[i].mode) != 0)
702 			err(1, "failed to create dir %s", dst);
703 	}
704 
705 	/* create a file with the address of the peer to connect to */
706 	if (myname != NULL) {
707 		snprintf(dst, sizeof(dst), "%s/export/peer.txt", p);
708 		if ((fd = open(dst, O_WRONLY|O_CREAT, 0644)) == -1)
709 			err(1, "open %s", dst);
710 		write(fd, myname, strlen(myname));
711 		close(fd);
712 	}
713 
714 	snprintf(src, sizeof(src), "%s/ca.pfx", ca->sslpath);
715 	snprintf(dst, sizeof(dst), "%s/export/ca.pfx", p);
716 	fcopy(src, dst, 0644);
717 
718 	snprintf(src, sizeof(src), "%s/ca.crt", ca->sslpath);
719 	snprintf(dst, sizeof(dst), "%s/ca/ca.crt", p);
720 	fcopy(src, dst, 0644);
721 
722 	snprintf(src, sizeof(src), "%s/ca.crl", ca->sslpath);
723 	if (stat(src, &st) == 0) {
724 		snprintf(dst, sizeof(dst), "%s/crls/ca.crl", p);
725 		fcopy(src, dst, 0644);
726 	}
727 
728 	if (keyname != NULL) {
729 		snprintf(src, sizeof(src), "%s/private/%s.pfx", ca->sslpath,
730 		    oname);
731 		snprintf(dst, sizeof(dst), "%s/export/%s.pfx", p, oname);
732 		fcopy(src, dst, 0644);
733 
734 		snprintf(src, sizeof(src), "%s/private/%s.key", ca->sslpath,
735 		    keyname);
736 		snprintf(dst, sizeof(dst), "%s/private/%s.key", p, keyname);
737 		fcopy(src, dst, 0600);
738 		snprintf(dst, sizeof(dst), "%s/private/local.key", p);
739 		fcopy(src, dst, 0600);
740 
741 		snprintf(src, sizeof(src), "%s/%s.crt", ca->sslpath, keyname);
742 		snprintf(dst, sizeof(dst), "%s/certs/%s.crt", p, keyname);
743 		fcopy(src, dst, 0644);
744 
745 		snprintf(cmd, sizeof(cmd), "%s rsa -out %s/local.pub"
746 		    " -in %s/private/%s.key -pubout", PATH_OPENSSL, p,
747 		    ca->sslpath, keyname);
748 		system(cmd);
749 	}
750 
751 	if (stat(PATH_TAR, &st) == 0) {
752 		if (keyname == NULL)
753 			snprintf(cmd, sizeof(cmd), "%s -zcf %s.tgz -C %s .",
754 			    PATH_TAR, oname, ca->sslpath);
755 		else
756 			snprintf(cmd, sizeof(cmd), "%s -zcf %s.tgz -C %s .",
757 			    PATH_TAR, oname, p);
758 		system(cmd);
759 		snprintf(src, sizeof(src), "%s.tgz", oname);
760 		if (realpath(src, dst) != NULL)
761 			printf("exported files in %s\n", dst);
762 	}
763 
764 	if (stat(PATH_ZIP, &st) == 0) {
765 		dexp = opendir(EXPDIR);
766 		if (dexp) {
767 			while ((de = readdir(dexp)) != NULL) {
768 				if (!strcmp(de->d_name, ".") ||
769 				    !strcmp(de->d_name, ".."))
770 					continue;
771 				snprintf(src, sizeof(src), "%s/%s", EXPDIR,
772 				    de->d_name);
773 				snprintf(dst, sizeof(dst), "%s/export/%s", p,
774 				    de->d_name);
775 				fcopy(src, dst, 0644);
776 			}
777 			closedir(dexp);
778 		}
779 
780 		snprintf(dst, sizeof(dst), "%s/export", p);
781 		if (getcwd(src, sizeof(src)) == NULL)
782 			err(1, "could not get cwd");
783 
784 		if (chdir(dst) == -1)
785 			err(1, "could not change %s", dst);
786 
787 		snprintf(dst, sizeof(dst), "%s/%s.zip", src, oname);
788 		snprintf(cmd, sizeof(cmd), "%s -qr %s .", PATH_ZIP, dst);
789 		system(cmd);
790 		printf("exported files in %s\n", dst);
791 
792 		if (chdir(src) == -1)
793 			err(1, "could not change %s", dst);
794 	}
795 
796 	rm_dir(p);
797 
798 	return (0);
799 }
800 
801 char *
802 ca_readpass(char *path, size_t *len)
803 {
804 	FILE		*f;
805 	char		*p, *r;
806 
807 	if ((f = fopen(path, "r")) == NULL) {
808 		warn("fopen %s", path);
809 		return (NULL);
810 	}
811 
812 	if ((p = fgetln(f, len)) != NULL) {
813 		if ((r = malloc(*len + 1)) == NULL)
814 			err(1, "malloc");
815 		memcpy(r, p, *len);
816 		if (r[*len - 1] == '\n')
817 			r[*len - 1] = '\0';
818 		else
819 			r[*len] = '\0';
820 	} else
821 		r = NULL;
822 
823 	fclose(f);
824 
825 	return (r);
826 }
827 
828 /* create index if it doesn't already exist */
829 void
830 ca_create_index(struct ca *ca)
831 {
832 	struct stat	 st;
833 	int		 fd;
834 
835 	if (snprintf(ca->index, sizeof(ca->index), "%s/index.txt",
836 	    ca->sslpath) < 0)
837 		err(1, "snprintf");
838 	if (stat(ca->index, &st) != 0) {
839 		if  (errno == ENOENT) {
840 			if ((fd = open(ca->index, O_WRONLY | O_CREAT, 0644))
841 			    == -1)
842 				err(1, "could not create file %s", ca->index);
843 			close(fd);
844 		} else
845 			err(1, "could not access %s", ca->index);
846 	}
847 
848 	if (snprintf(ca->serial, sizeof(ca->serial), "%s/serial.txt",
849 	    ca->sslpath) < 0)
850 		err(1, "snprintf");
851 	if (stat(ca->serial, &st) != 0) {
852 		if  (errno == ENOENT) {
853 			if ((fd = open(ca->serial, O_WRONLY | O_CREAT, 0644))
854 			    == -1)
855 				err(1, "could not create file %s", ca->serial);
856 			/* serial file must be created with a number */
857 			if (write(fd, "01\n", 3) != 3)
858 				err(1, "write %s", ca->serial);
859 			close(fd);
860 		} else
861 			err(1, "could not access %s", ca->serial);
862 	}
863 }
864 
865 int
866 ca_revoke(struct ca *ca, char *keyname)
867 {
868 	struct stat	 st;
869 	char		 cmd[PATH_MAX * 2];
870 	char		 path[PATH_MAX];
871 	char		*pass;
872 	size_t		 len;
873 
874 	if (keyname) {
875 		snprintf(path, sizeof(path), "%s/%s.crt",
876 		    ca->sslpath, keyname);
877 		if (stat(path, &st) != 0) {
878 			warn("Problem with certificate for '%s'", keyname);
879 			return (1);
880 		}
881 	}
882 
883 	snprintf(path, sizeof(path), "%s/ikeca.passwd", ca->sslpath);
884 	pass = ca_readpass(path, &len);
885 	if (pass == NULL)
886 		errx(1, "could not open passphrase file");
887 
888 	ca_create_index(ca);
889 
890 	ca_setenv("$ENV::CADB", ca->index);
891 	ca_setenv("$ENV::CASERIAL", ca->serial);
892 	ca_setcnf(ca, "ca-revoke");
893 
894 	if (keyname) {
895 		snprintf(cmd, sizeof(cmd),
896 		    "%s ca %s-config %s -keyfile %s/private/ca.key"
897 		    " -key %s"
898 		    " -cert %s/ca.crt"
899 		    " -revoke %s/%s.crt",
900 		    PATH_OPENSSL, ca->batch, ca->sslcnf,
901 		    ca->sslpath, pass, ca->sslpath, ca->sslpath, keyname);
902 		system(cmd);
903 	}
904 
905 	snprintf(cmd, sizeof(cmd),
906 	    "%s ca %s-config %s -keyfile %s/private/ca.key"
907 	    " -key %s"
908 	    " -gencrl"
909 	    " -cert %s/ca.crt"
910 	    " -crldays 365"
911 	    " -out %s/ca.crl",
912 	    PATH_OPENSSL, ca->batch, ca->sslcnf, ca->sslpath,
913 	    pass, ca->sslpath, ca->sslpath);
914 	system(cmd);
915 
916 	explicit_bzero(pass, len);
917 	free(pass);
918 
919 	return (0);
920 }
921 
922 void
923 ca_clrenv(void)
924 {
925 	int	 i;
926 	for (i = 0; ca_env[i][0] != NULL; i++)
927 		ca_env[i][1] = NULL;
928 }
929 
930 void
931 ca_setenv(const char *key, const char *value)
932 {
933 	int	 i;
934 
935 	for (i = 0; ca_env[i][0] != NULL; i++) {
936 		if (strcmp(ca_env[i][0], key) == 0) {
937 			if (ca_env[i][1] != NULL)
938 				errx(1, "env %s already set: %s", key, value);
939 			ca_env[i][1] = value;
940 			return;
941 		}
942 	}
943 	errx(1, "env %s invalid", key);
944 }
945 
946 void
947 ca_setcnf(struct ca *ca, const char *keyname)
948 {
949 	struct stat	 st;
950 	const char	*extcnf, *sslcnf;
951 
952 	if (stat(IKECA_CNF, &st) == 0) {
953 		extcnf = IKECA_CNF;
954 		sslcnf = IKECA_CNF;
955 	} else {
956 		extcnf = X509_CNF;
957 		sslcnf = SSL_CNF;
958 	}
959 
960 	snprintf(ca->extcnf, sizeof(ca->extcnf), "%s/%s-ext.cnf",
961 	    ca->sslpath, keyname);
962 	snprintf(ca->sslcnf, sizeof(ca->sslcnf), "%s/%s-ssl.cnf",
963 	    ca->sslpath, keyname);
964 
965 	fcopy_env(extcnf, ca->extcnf, 0400);
966 	fcopy_env(sslcnf, ca->sslcnf, 0400);
967 }
968 
969 struct ca *
970 ca_setup(char *caname, int create, int quiet, char *pass)
971 {
972 	struct stat	 st;
973 	struct ca	*ca;
974 	char		 path[PATH_MAX];
975 
976 	if (stat(PATH_OPENSSL, &st) == -1)
977 		err(1, "openssl binary not available");
978 
979 	if ((ca = calloc(1, sizeof(struct ca))) == NULL)
980 		err(1, "calloc");
981 
982 	ca->caname = strdup(caname);
983 	snprintf(ca->sslpath, sizeof(ca->sslpath), SSLDIR "/%s", caname);
984 	strlcpy(ca->passfile, ca->sslpath, sizeof(ca->passfile));
985 	strlcat(ca->passfile, "/ikeca.passwd", sizeof(ca->passfile));
986 
987 	if (quiet)
988 		strlcpy(ca->batch, "-batch ", sizeof(ca->batch));
989 
990 	if (create == 0 && stat(ca->sslpath, &st) == -1) {
991 		free(ca->caname);
992 		free(ca);
993 		errx(1, "CA '%s' does not exist", caname);
994 	}
995 
996 	strlcpy(path, ca->sslpath, sizeof(path));
997 	if (mkdir(path, 0777) == -1 && errno != EEXIST)
998 		err(1, "failed to create dir %s", path);
999 	strlcat(path, "/private", sizeof(path));
1000 	if (mkdir(path, 0700) == -1 && errno != EEXIST)
1001 		err(1, "failed to create dir %s", path);
1002 
1003 	if (create && stat(ca->passfile, &st) == -1 && errno == ENOENT)
1004 		ca_newpass(ca->passfile, pass);
1005 
1006 	return (ca);
1007 }
1008