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