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