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