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