xref: /openbsd-src/usr.sbin/ikectl/ikeca.c (revision 7c9b6f9dcfded1e5b02818e807215522de7c655c)
1*7c9b6f9dSpascal /*	$OpenBSD: ikeca.c,v 1.52 2024/12/12 17:29:33 pascal Exp $	*/
2901ee4f0Sreyk 
3901ee4f0Sreyk /*
43fbc3006Sreyk  * Copyright (c) 2010 Jonathan Gray <jsg@openbsd.org>
5901ee4f0Sreyk  *
6901ee4f0Sreyk  * Permission to use, copy, modify, and distribute this software for any
7901ee4f0Sreyk  * purpose with or without fee is hereby granted, provided that the above
8901ee4f0Sreyk  * copyright notice and this permission notice appear in all copies.
9901ee4f0Sreyk  *
10901ee4f0Sreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11901ee4f0Sreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12901ee4f0Sreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13901ee4f0Sreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14901ee4f0Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15901ee4f0Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16901ee4f0Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17901ee4f0Sreyk  */
18901ee4f0Sreyk 
19901ee4f0Sreyk #include <sys/types.h>
20901ee4f0Sreyk #include <sys/stat.h>
21731c78a3Stedu #include <sys/wait.h>
22901ee4f0Sreyk #include <stdio.h>
23901ee4f0Sreyk #include <unistd.h>
24901ee4f0Sreyk #include <err.h>
25901ee4f0Sreyk #include <errno.h>
26901ee4f0Sreyk #include <string.h>
27901ee4f0Sreyk #include <stdlib.h>
28901ee4f0Sreyk #include <pwd.h>
29901ee4f0Sreyk #include <fcntl.h>
30901ee4f0Sreyk #include <fts.h>
31901ee4f0Sreyk #include <dirent.h>
32b9fc9a72Sderaadt #include <limits.h>
33901ee4f0Sreyk 
34901ee4f0Sreyk #include <openssl/rand.h>
35901ee4f0Sreyk #include <openssl/rsa.h>
36901ee4f0Sreyk #include <openssl/pem.h>
37901ee4f0Sreyk 
38477ac106Sderaadt #include "types.h"
39901ee4f0Sreyk #include "parser.h"
40901ee4f0Sreyk 
41ddb14f44Sreyk #ifndef PREFIX
42ddb14f44Sreyk #define PREFIX		""
43ddb14f44Sreyk #endif
44ddb14f44Sreyk #ifndef SSLDIR
45ddb14f44Sreyk #define SSLDIR		PREFIX "/etc/ssl"
46ddb14f44Sreyk #endif
47ddb14f44Sreyk #define SSL_CNF		SSLDIR "/openssl.cnf"
48ddb14f44Sreyk #define X509_CNF	SSLDIR "/x509v3.cnf"
49ddb14f44Sreyk #define IKECA_CNF	SSLDIR "/ikeca.cnf"
50ddb14f44Sreyk #define KEYBASE		PREFIX "/etc/iked"
51ddb14f44Sreyk #ifndef EXPDIR
52ddb14f44Sreyk #define EXPDIR		PREFIX "/usr/share/iked"
53ddb14f44Sreyk #endif
54901ee4f0Sreyk 
55ddb14f44Sreyk #ifndef PATH_OPENSSL
56dab3f910Sjsing #define PATH_OPENSSL	"/usr/bin/openssl"
57ddb14f44Sreyk #endif
58ddb14f44Sreyk #ifndef PATH_ZIP
59901ee4f0Sreyk #define PATH_ZIP	"/usr/local/bin/zip"
60ddb14f44Sreyk #endif
61ddb14f44Sreyk #ifndef PATH_TAR
62901ee4f0Sreyk #define PATH_TAR	"/bin/tar"
63ddb14f44Sreyk #endif
64901ee4f0Sreyk 
65901ee4f0Sreyk struct ca {
66901ee4f0Sreyk 	char	 sslpath[PATH_MAX];
67731c78a3Stedu 	char	 passfile[PATH_MAX + 5]; /* Includes the "file:" prefix */
688e3cf88fSjsg 	char	 index[PATH_MAX];
698e3cf88fSjsg 	char	 serial[PATH_MAX];
70901ee4f0Sreyk 	char	 sslcnf[PATH_MAX];
71901ee4f0Sreyk 	char	 extcnf[PATH_MAX];
72731c78a3Stedu 	char	*batch;
73901ee4f0Sreyk 	char	*caname;
74901ee4f0Sreyk };
75901ee4f0Sreyk 
767638a50cSjsg struct {
777638a50cSjsg 	char	*dir;
787638a50cSjsg 	mode_t	 mode;
792746af23Sjsg } hier[] = {
802746af23Sjsg 	{ "",		0755 },
817638a50cSjsg 	{ "/ca",	0755 },
827638a50cSjsg 	{ "/certs",	0755 },
837638a50cSjsg 	{ "/crls",	0755 },
847638a50cSjsg 	{ "/export",	0755 },
857638a50cSjsg 	{ "/private",	0700 }
867638a50cSjsg };
877638a50cSjsg 
884f23bdabSreyk /* explicitly list allowed variables */
898068c079Spatrick char *ca_env[][2] = {
904f23bdabSreyk 	{ "$ENV::CADB", NULL },
918e3cf88fSjsg 	{ "$ENV::CASERIAL", NULL },
924f23bdabSreyk 	{ "$ENV::CERTFQDN", NULL },
934f23bdabSreyk 	{ "$ENV::CERTIP", NULL },
944f23bdabSreyk 	{ "$ENV::CERTPATHLEN", NULL },
954f23bdabSreyk 	{ "$ENV::CERTUSAGE", NULL },
964f23bdabSreyk 	{ "$ENV::CERT_C", NULL },
974f23bdabSreyk 	{ "$ENV::CERT_CN", NULL },
984f23bdabSreyk 	{ "$ENV::CERT_EMAIL", NULL },
994f23bdabSreyk 	{ "$ENV::CERT_L", NULL },
1004f23bdabSreyk 	{ "$ENV::CERT_O", NULL },
1014f23bdabSreyk 	{ "$ENV::CERT_OU", NULL },
1024f23bdabSreyk 	{ "$ENV::CERT_ST", NULL },
1034f23bdabSreyk 	{ "$ENV::EXTCERTUSAGE", NULL },
1044f23bdabSreyk 	{ "$ENV::NSCERTTYPE", NULL },
10537c7452dSsthen 	{ "$ENV::REQ_EXT", NULL },
1064f23bdabSreyk 	{ NULL }
1074f23bdabSreyk };
1084f23bdabSreyk 
1094f23bdabSreyk int		 ca_sign(struct ca *, char *, int);
11037c7452dSsthen int		 ca_request(struct ca *, char *, int);
11147e28f79Sreyk void		 ca_newpass(char *, char *);
1123da6623bSjsg int		 fcopy(char *, char *, mode_t);
113bfcdcf42Sreyk void		 fcopy_env(const char *, const char *, mode_t);
114901ee4f0Sreyk int		 rm_dir(char *);
11547e28f79Sreyk void		 ca_hier(char *);
1164f23bdabSreyk void		 ca_setenv(const char *, const char *);
1174f23bdabSreyk void		 ca_clrenv(void);
1184f23bdabSreyk void		 ca_setcnf(struct ca *, const char *);
1198e3cf88fSjsg void		 ca_create_index(struct ca *);
120731c78a3Stedu int static	 ca_execv(char *const []);
1214f23bdabSreyk 
1224f23bdabSreyk /* util.c */
1234f23bdabSreyk int		 expand_string(char *, size_t, const char *, const char *);
124901ee4f0Sreyk 
125901ee4f0Sreyk int
126901ee4f0Sreyk ca_delete(struct ca *ca)
127901ee4f0Sreyk {
128901ee4f0Sreyk 	return (rm_dir(ca->sslpath));
129901ee4f0Sreyk }
130901ee4f0Sreyk 
131901ee4f0Sreyk int
1321dbb1d4aSjsg ca_key_create(struct ca *ca, char *keyname)
133901ee4f0Sreyk {
1341dbb1d4aSjsg 	struct stat		 st;
135901ee4f0Sreyk 	char			 path[PATH_MAX];
136c03e9c27Stobhe 	int			 len;
137901ee4f0Sreyk 
138c03e9c27Stobhe 	len = snprintf(path, sizeof(path), "%s/private/%s.key",
139c03e9c27Stobhe 	    ca->sslpath, keyname);
140c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(path))
141c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
1421dbb1d4aSjsg 
1431dbb1d4aSjsg 	/* don't recreate key if one is already present */
1441dbb1d4aSjsg 	if (stat(path, &st) == 0) {
1451dbb1d4aSjsg 		return (0);
1461dbb1d4aSjsg 	}
147901ee4f0Sreyk 
148731c78a3Stedu 	char *cmd[] = { PATH_OPENSSL, "genrsa", "-out", path, "2048", NULL };
149731c78a3Stedu 	ca_execv(cmd);
150901ee4f0Sreyk 	chmod(path, 0600);
151901ee4f0Sreyk 
152901ee4f0Sreyk 	return (0);
153901ee4f0Sreyk }
154901ee4f0Sreyk 
155901ee4f0Sreyk int
1561dbb1d4aSjsg ca_key_import(struct ca *ca, char *keyname, char *import)
1571dbb1d4aSjsg {
1581dbb1d4aSjsg 	struct stat		 st;
1591dbb1d4aSjsg 	char			 dst[PATH_MAX];
160c03e9c27Stobhe 	int			 len;
1611dbb1d4aSjsg 
1621dbb1d4aSjsg 	if (stat(import, &st) != 0) {
1631dbb1d4aSjsg 		warn("could not access keyfile %s", import);
1641dbb1d4aSjsg 		return (1);
1651dbb1d4aSjsg 	}
1661dbb1d4aSjsg 
167c03e9c27Stobhe 	len = snprintf(dst, sizeof(dst), "%s/private/%s.key", ca->sslpath, keyname);
168c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(dst))
169c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
170c03e9c27Stobhe 
1711dbb1d4aSjsg 	fcopy(import, dst, 0600);
1721dbb1d4aSjsg 
1731dbb1d4aSjsg 	return (0);
1741dbb1d4aSjsg }
1751dbb1d4aSjsg 
1761dbb1d4aSjsg int
1771dbb1d4aSjsg ca_key_delete(struct ca *ca, char *keyname)
1781dbb1d4aSjsg {
1791dbb1d4aSjsg 	char			 path[PATH_MAX];
180c03e9c27Stobhe 	int			 len;
1811dbb1d4aSjsg 
182c03e9c27Stobhe 	len = snprintf(path, sizeof(path), "%s/private/%s.key",
183c03e9c27Stobhe 	    ca->sslpath, keyname);
184c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(path))
185c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
1861dbb1d4aSjsg 	unlink(path);
1871dbb1d4aSjsg 
1881dbb1d4aSjsg 	return (0);
1891dbb1d4aSjsg }
1901dbb1d4aSjsg 
1911dbb1d4aSjsg int
192901ee4f0Sreyk ca_delkey(struct ca *ca, char *keyname)
193901ee4f0Sreyk {
194901ee4f0Sreyk 	char		file[PATH_MAX];
195c03e9c27Stobhe 	int		len;
196901ee4f0Sreyk 
197c03e9c27Stobhe 	len = snprintf(file, sizeof(file), "%s/%s.crt", ca->sslpath, keyname);
198c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(file))
199c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
200901ee4f0Sreyk 	unlink(file);
201901ee4f0Sreyk 
202c03e9c27Stobhe 	len = snprintf(file, sizeof(file), "%s/private/%s.key", ca->sslpath, keyname);
203c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(file))
204c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
205901ee4f0Sreyk 	unlink(file);
206901ee4f0Sreyk 
207c03e9c27Stobhe 	len = snprintf(file, sizeof(file), "%s/private/%s.csr", ca->sslpath, keyname);
208c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(file))
209c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
210901ee4f0Sreyk 	unlink(file);
211901ee4f0Sreyk 
212c03e9c27Stobhe 	len = snprintf(file, sizeof(file), "%s/private/%s.pfx", ca->sslpath, keyname);
213c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(file))
214c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
215901ee4f0Sreyk 	unlink(file);
216901ee4f0Sreyk 
217901ee4f0Sreyk 	return (0);
218901ee4f0Sreyk }
219901ee4f0Sreyk 
220901ee4f0Sreyk int
22137c7452dSsthen ca_request(struct ca *ca, char *keyname, int type)
222901ee4f0Sreyk {
22337c7452dSsthen 	char		hostname[HOST_NAME_MAX+1];
22437c7452dSsthen 	char		name[128];
225731c78a3Stedu 	char		key[PATH_MAX];
226901ee4f0Sreyk 	char		path[PATH_MAX];
227c03e9c27Stobhe 	int		len;
228901ee4f0Sreyk 
2294f23bdabSreyk 	ca_setenv("$ENV::CERT_CN", keyname);
23037c7452dSsthen 
23137c7452dSsthen 	strlcpy(name, keyname, sizeof(name));
23237c7452dSsthen 
23337c7452dSsthen 	if (type == HOST_IPADDR) {
23437c7452dSsthen 		ca_setenv("$ENV::CERTIP", name);
23537c7452dSsthen 		ca_setenv("$ENV::REQ_EXT", "x509v3_IPAddr");
23637c7452dSsthen 	} else if (type == HOST_FQDN) {
23737c7452dSsthen 		if (!strcmp(keyname, "local")) {
23837c7452dSsthen 			if (gethostname(hostname, sizeof(hostname)))
23937c7452dSsthen 				err(1, "gethostname");
24037c7452dSsthen 			strlcpy(name, hostname, sizeof(name));
24137c7452dSsthen 		}
24237c7452dSsthen 		ca_setenv("$ENV::CERTFQDN", name);
24337c7452dSsthen 		ca_setenv("$ENV::REQ_EXT", "x509v3_FQDN");
24437c7452dSsthen 	} else {
24537c7452dSsthen 		errx(1, "unknown host type %d", type);
24637c7452dSsthen 	}
24737c7452dSsthen 
2484f23bdabSreyk 	ca_setcnf(ca, keyname);
2494f23bdabSreyk 
250c03e9c27Stobhe 	len = snprintf(key, sizeof(key), "%s/private/%s.key", ca->sslpath, keyname);
251c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(key))
252c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
253c03e9c27Stobhe 	len = snprintf(path, sizeof(path), "%s/private/%s.csr", ca->sslpath, keyname);
254c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(path))
255c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
256cfd26ebdSreyk 
257731c78a3Stedu 	char *cmd[] = { PATH_OPENSSL, "req", "-new", "-key", key, "-out", path,
258731c78a3Stedu 	    "-config", ca->sslcnf, ca->batch, NULL };
259731c78a3Stedu 	ca_execv(cmd);
260901ee4f0Sreyk 	chmod(path, 0600);
261901ee4f0Sreyk 
262901ee4f0Sreyk 	return (0);
263901ee4f0Sreyk }
264901ee4f0Sreyk 
265901ee4f0Sreyk int
2664f23bdabSreyk ca_sign(struct ca *ca, char *keyname, int type)
267901ee4f0Sreyk {
268731c78a3Stedu 	char		cakey[PATH_MAX];
269731c78a3Stedu 	char		cacrt[PATH_MAX];
270731c78a3Stedu 	char		out[PATH_MAX];
271731c78a3Stedu 	char		in[PATH_MAX];
272731c78a3Stedu 	char		*extensions = NULL;
273c03e9c27Stobhe 	int		len;
274901ee4f0Sreyk 
275901ee4f0Sreyk 	if (type == HOST_IPADDR) {
2764f23bdabSreyk 		extensions = "x509v3_IPAddr";
277901ee4f0Sreyk 	} else if (type == HOST_FQDN) {
2784f23bdabSreyk 		extensions = "x509v3_FQDN";
2794f23bdabSreyk 	} else {
2804f23bdabSreyk 		errx(1, "unknown host type %d", type);
2814f23bdabSreyk 	}
2824f23bdabSreyk 
2838e3cf88fSjsg 	ca_create_index(ca);
2848e3cf88fSjsg 
2858e3cf88fSjsg 	ca_setenv("$ENV::CADB", ca->index);
2868e3cf88fSjsg 	ca_setenv("$ENV::CASERIAL", ca->serial);
2874f23bdabSreyk 	ca_setcnf(ca, keyname);
2884f23bdabSreyk 
289c03e9c27Stobhe 	len = snprintf(cakey, sizeof(cakey), "%s/private/ca.key", ca->sslpath);
290c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(cakey))
291c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
292c03e9c27Stobhe 	len = snprintf(cacrt, sizeof(cacrt), "%s/ca.crt", ca->sslpath);
293c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(cacrt))
294c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
295c03e9c27Stobhe 	len = snprintf(out, sizeof(out), "%s/%s.crt", ca->sslpath, keyname);
296c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(out))
297c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
298c03e9c27Stobhe 	len = snprintf(in, sizeof(in), "%s/private/%s.csr", ca->sslpath, keyname);
299c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(in))
300c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
301901ee4f0Sreyk 
302731c78a3Stedu 	char *cmd[] = { PATH_OPENSSL, "ca", "-config", ca->sslcnf,
303731c78a3Stedu 	    "-keyfile", cakey, "-cert", cacrt, "-extfile", ca->extcnf,
304731c78a3Stedu 	    "-extensions", extensions, "-out", out, "-in", in,
305731c78a3Stedu 	    "-passin", ca->passfile, "-outdir", ca->sslpath, "-batch", NULL };
306731c78a3Stedu 	ca_execv(cmd);
307901ee4f0Sreyk 
308901ee4f0Sreyk 	return (0);
309901ee4f0Sreyk }
310901ee4f0Sreyk 
311901ee4f0Sreyk int
312cfd26ebdSreyk ca_certificate(struct ca *ca, char *keyname, int type, int action)
313901ee4f0Sreyk {
3144f23bdabSreyk 	ca_clrenv();
315cfd26ebdSreyk 
316cfd26ebdSreyk 	switch (action) {
317cfd26ebdSreyk 	case CA_SERVER:
3184f23bdabSreyk 		ca_setenv("$ENV::EXTCERTUSAGE", "serverAuth");
3194f23bdabSreyk 		ca_setenv("$ENV::NSCERTTYPE", "server");
3204f23bdabSreyk 		ca_setenv("$ENV::CERTUSAGE",
3214f23bdabSreyk 		    "digitalSignature,keyEncipherment");
322cfd26ebdSreyk 		break;
323cfd26ebdSreyk 	case CA_CLIENT:
3244f23bdabSreyk 		ca_setenv("$ENV::EXTCERTUSAGE", "clientAuth");
3254f23bdabSreyk 		ca_setenv("$ENV::NSCERTTYPE", "client");
3264f23bdabSreyk 		ca_setenv("$ENV::CERTUSAGE",
3274f23bdabSreyk 		    "digitalSignature,keyAgreement");
328cfd26ebdSreyk 		break;
329ab7171b1Sjsg 	case CA_OCSP:
330ab7171b1Sjsg 		ca_setenv("$ENV::EXTCERTUSAGE", "OCSPSigning");
331ab7171b1Sjsg 		ca_setenv("$ENV::CERTUSAGE",
332ab7171b1Sjsg 		    "nonRepudiation,digitalSignature,keyEncipherment");
333ab7171b1Sjsg 		break;
334cfd26ebdSreyk 	default:
335cfd26ebdSreyk 		break;
336cfd26ebdSreyk 	}
337cfd26ebdSreyk 
3381dbb1d4aSjsg 	ca_key_create(ca, keyname);
33937c7452dSsthen 	ca_request(ca, keyname, type);
3404f23bdabSreyk 	ca_sign(ca, keyname, type);
341901ee4f0Sreyk 
342901ee4f0Sreyk 	return (0);
343901ee4f0Sreyk }
344901ee4f0Sreyk 
345901ee4f0Sreyk int
3467638a50cSjsg ca_key_install(struct ca *ca, char *keyname, char *dir)
347901ee4f0Sreyk {
348901ee4f0Sreyk 	struct stat	 st;
349901ee4f0Sreyk 	char		 src[PATH_MAX];
350901ee4f0Sreyk 	char		 dst[PATH_MAX];
351731c78a3Stedu 	char		 out[PATH_MAX];
3527638a50cSjsg 	char		*p = NULL;
353c03e9c27Stobhe 	int		 len;
354901ee4f0Sreyk 
355c03e9c27Stobhe 	len = snprintf(src, sizeof(src), "%s/private/%s.key", ca->sslpath, keyname);
356c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(src))
357c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
358901ee4f0Sreyk 	if (stat(src, &st) == -1) {
359901ee4f0Sreyk 		if (errno == ENOENT)
360901ee4f0Sreyk 			printf("key for '%s' does not exist\n", ca->caname);
361901ee4f0Sreyk 		else
362901ee4f0Sreyk 			warn("could not access key");
363901ee4f0Sreyk 		return (1);
364901ee4f0Sreyk 	}
365901ee4f0Sreyk 
3667638a50cSjsg 	if (dir == NULL)
3677638a50cSjsg 		p = dir = strdup(KEYBASE);
3687638a50cSjsg 
3697638a50cSjsg 	ca_hier(dir);
3707638a50cSjsg 
371c03e9c27Stobhe 	len = snprintf(dst, sizeof(dst), "%s/private/local.key", dir);
372c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(dst))
373c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
3743da6623bSjsg 	fcopy(src, dst, 0600);
375901ee4f0Sreyk 
376c03e9c27Stobhe 	len = snprintf(out, sizeof(out), "%s/local.pub", dir);
377c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(out))
378c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
379731c78a3Stedu 
380731c78a3Stedu 	char *cmd[] = { PATH_OPENSSL, "rsa", "-out", out, "-in", dst,
381731c78a3Stedu 	    "-pubout", NULL };
382731c78a3Stedu 	ca_execv(cmd);
383901ee4f0Sreyk 
3847638a50cSjsg 	free(p);
3851dbb1d4aSjsg 
3860dd4c7c3Sjsg 	return (0);
3871dbb1d4aSjsg }
3881dbb1d4aSjsg 
3891dbb1d4aSjsg int
3907638a50cSjsg ca_cert_install(struct ca *ca, char *keyname, char *dir)
3911dbb1d4aSjsg {
3921dbb1d4aSjsg 	char		 src[PATH_MAX];
3931dbb1d4aSjsg 	char		 dst[PATH_MAX];
3941dbb1d4aSjsg 	int		 r;
3957638a50cSjsg 	char		*p = NULL;
396c03e9c27Stobhe 	int		 len;
3971dbb1d4aSjsg 
3987638a50cSjsg 	if (dir == NULL)
3997638a50cSjsg 		p = dir = strdup(KEYBASE);
4007638a50cSjsg 
4017638a50cSjsg 	ca_hier(dir);
4027638a50cSjsg 
4037638a50cSjsg 	if ((r = ca_key_install(ca, keyname, dir)) != 0) {
4047638a50cSjsg 		free(dir);
4051dbb1d4aSjsg 		return (r);
4067638a50cSjsg 	}
4071dbb1d4aSjsg 
408c03e9c27Stobhe 	len = snprintf(src, sizeof(src), "%s/%s.crt", ca->sslpath, keyname);
409c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(src))
410c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
411c03e9c27Stobhe 	len = snprintf(dst, sizeof(dst), "%s/certs/%s.crt", dir, keyname);
412c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(dst))
413c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
4143da6623bSjsg 	fcopy(src, dst, 0644);
4153da6623bSjsg 
4167638a50cSjsg 	free(p);
4177638a50cSjsg 
418901ee4f0Sreyk 	return (0);
419901ee4f0Sreyk }
420901ee4f0Sreyk 
42147e28f79Sreyk void
422cfd26ebdSreyk ca_newpass(char *passfile, char *password)
423901ee4f0Sreyk {
424901ee4f0Sreyk 	FILE	*f;
425901ee4f0Sreyk 	char	*pass;
426901ee4f0Sreyk 	char	 prev[_PASSWORD_LEN + 1];
427901ee4f0Sreyk 
428cfd26ebdSreyk 	if (password != NULL) {
429cfd26ebdSreyk 		pass = password;
430cfd26ebdSreyk 		goto done;
431cfd26ebdSreyk 	}
432cfd26ebdSreyk 
433901ee4f0Sreyk 	pass = getpass("CA passphrase:");
434901ee4f0Sreyk 	if (pass == NULL || *pass == '\0')
435901ee4f0Sreyk 		err(1, "password not set");
436901ee4f0Sreyk 
437901ee4f0Sreyk 	strlcpy(prev, pass, sizeof(prev));
438901ee4f0Sreyk 	pass = getpass("Retype CA passphrase:");
439901ee4f0Sreyk 	if (pass == NULL || strcmp(prev, pass) != 0)
440901ee4f0Sreyk 		errx(1, "passphrase does not match!");
441901ee4f0Sreyk 
442cfd26ebdSreyk  done:
443901ee4f0Sreyk 	if ((f = fopen(passfile, "wb")) == NULL)
444901ee4f0Sreyk 		err(1, "could not open passfile %s", passfile);
445901ee4f0Sreyk 	chmod(passfile, 0600);
446901ee4f0Sreyk 
447901ee4f0Sreyk 	fprintf(f, "%s\n%s\n", pass, pass);
448901ee4f0Sreyk 
449901ee4f0Sreyk 	fclose(f);
450901ee4f0Sreyk }
451901ee4f0Sreyk 
452901ee4f0Sreyk int
453901ee4f0Sreyk ca_create(struct ca *ca)
454901ee4f0Sreyk {
455731c78a3Stedu 	char			 key[PATH_MAX];
456731c78a3Stedu 	char			 csr[PATH_MAX];
457731c78a3Stedu 	char			 crt[PATH_MAX];
458c03e9c27Stobhe 	int			 len;
459901ee4f0Sreyk 
4604f23bdabSreyk 	ca_clrenv();
4614f23bdabSreyk 
462c03e9c27Stobhe 	len = snprintf(key, sizeof(key), "%s/private/ca.key", ca->sslpath);
463c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(key))
464c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
465731c78a3Stedu 	char *genrsa[] = { PATH_OPENSSL, "genrsa", "-aes256", "-out", key,
466731c78a3Stedu 	    "-passout", ca->passfile, "2048", NULL };
467731c78a3Stedu 	ca_execv(genrsa);
468731c78a3Stedu 
469731c78a3Stedu 	chmod(key, 0600);
470901ee4f0Sreyk 
4714f23bdabSreyk 	ca_setenv("$ENV::CERT_CN", "VPN CA");
4727cc3ce1dSsthen 	ca_setenv("$ENV::REQ_EXT", "x509v3_CA");
4734f23bdabSreyk 	ca_setcnf(ca, "ca");
4744f23bdabSreyk 
475c03e9c27Stobhe 	len = snprintf(csr, sizeof(csr), "%s/private/ca.csr", ca->sslpath);
476c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(csr))
477c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
478731c78a3Stedu 	char *reqcmd[] = { PATH_OPENSSL, "req", "-new", "-key", key,
479731c78a3Stedu 	    "-config", ca->sslcnf, "-out", csr,
480731c78a3Stedu 	    "-passin", ca->passfile, ca->batch, NULL };
481731c78a3Stedu 	ca_execv(reqcmd);
482731c78a3Stedu 	chmod(csr, 0600);
483901ee4f0Sreyk 
484c03e9c27Stobhe 	len = snprintf(crt, sizeof(crt), "%s/ca.crt", ca->sslpath);
485c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(crt))
486c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
487731c78a3Stedu 	char *x509[] = { PATH_OPENSSL, "x509", "-req", "-days", "4500",
488731c78a3Stedu 	    "-in", csr, "-signkey", key, "-sha256",
489731c78a3Stedu 	    "-extfile", ca->extcnf, "-extensions", "x509v3_CA",
490731c78a3Stedu 	    "-out", crt, "-passin", ca->passfile, NULL };
491731c78a3Stedu 	ca_execv(x509);
492901ee4f0Sreyk 
4937430271cSphessler 	/* Create the CRL revocation list */
4947430271cSphessler 	ca_revoke(ca, NULL);
4957430271cSphessler 
496901ee4f0Sreyk 	return (0);
497901ee4f0Sreyk }
498901ee4f0Sreyk 
499901ee4f0Sreyk int
5007638a50cSjsg ca_install(struct ca *ca, char *dir)
501901ee4f0Sreyk {
502901ee4f0Sreyk 	struct stat	 st;
503901ee4f0Sreyk 	char		 src[PATH_MAX];
504901ee4f0Sreyk 	char		 dst[PATH_MAX];
5057638a50cSjsg 	char		*p = NULL;
506c03e9c27Stobhe 	int		 len;
507901ee4f0Sreyk 
508c03e9c27Stobhe 	len = snprintf(src, sizeof(src), "%s/ca.crt", ca->sslpath);
509c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(src))
510c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
511901ee4f0Sreyk 	if (stat(src, &st) == -1) {
512901ee4f0Sreyk 		printf("CA '%s' does not exist\n", ca->caname);
513901ee4f0Sreyk 		return (1);
514901ee4f0Sreyk 	}
515901ee4f0Sreyk 
5167638a50cSjsg 	if (dir == NULL)
5177638a50cSjsg 		p = dir = strdup(KEYBASE);
5187638a50cSjsg 
5197638a50cSjsg 	ca_hier(dir);
5207638a50cSjsg 
521c03e9c27Stobhe 	len = snprintf(dst, sizeof(dst), "%s/ca/ca.crt", dir);
522c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(dst))
523c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
5243da6623bSjsg 	if (fcopy(src, dst, 0644) == 0)
525c3cc2c5eSjsg 		printf("certificate for CA '%s' installed into %s\n",
526c3cc2c5eSjsg 		    ca->caname, dst);
527c3cc2c5eSjsg 
528c03e9c27Stobhe 	len = snprintf(src, sizeof(src), "%s/ca.crl", ca->sslpath);
529c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(src))
530c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
531c3cc2c5eSjsg 	if (stat(src, &st) == 0) {
532c03e9c27Stobhe 		len = snprintf(dst, sizeof(dst), "%s/crls/ca.crl", dir);
533c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(dst))
534c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
535c3cc2c5eSjsg 		if (fcopy(src, dst, 0644) == 0)
536c3cc2c5eSjsg 			printf("CRL for CA '%s' installed to %s\n",
537c3cc2c5eSjsg 			    ca->caname, dst);
538c3cc2c5eSjsg 	}
539901ee4f0Sreyk 
5407638a50cSjsg 	free(p);
5417638a50cSjsg 
542901ee4f0Sreyk 	return (0);
543901ee4f0Sreyk }
544901ee4f0Sreyk 
545901ee4f0Sreyk int
54669ffd282Sreyk ca_show_certs(struct ca *ca, char *name)
547901ee4f0Sreyk {
548901ee4f0Sreyk 	DIR		*dir;
549901ee4f0Sreyk 	struct dirent	*de;
550901ee4f0Sreyk 	char		 path[PATH_MAX];
551901ee4f0Sreyk 	char		*p;
55269ffd282Sreyk 	struct stat	 st;
553c03e9c27Stobhe 	int		 len;
55469ffd282Sreyk 
55569ffd282Sreyk 	if (name != NULL) {
556c03e9c27Stobhe 		len = snprintf(path, sizeof(path), "%s/%s.crt",
55769ffd282Sreyk 		    ca->sslpath, name);
558c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(path))
559c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
56069ffd282Sreyk 		if (stat(path, &st) != 0)
56169ffd282Sreyk 			err(1, "could not open file %s.crt", name);
562731c78a3Stedu 		char *cmd[] = { PATH_OPENSSL, "x509", "-text",
563731c78a3Stedu 		    "-in", path, NULL };
564731c78a3Stedu 		ca_execv(cmd);
56569ffd282Sreyk 		printf("\n");
56669ffd282Sreyk 		return (0);
56769ffd282Sreyk 	}
568901ee4f0Sreyk 
569901ee4f0Sreyk 	if ((dir = opendir(ca->sslpath)) == NULL)
570901ee4f0Sreyk 		err(1, "could not open directory %s", ca->sslpath);
571901ee4f0Sreyk 
572901ee4f0Sreyk 	while ((de = readdir(dir)) != NULL) {
573901ee4f0Sreyk 		if (de->d_namlen > 4) {
574901ee4f0Sreyk 			p = de->d_name + de->d_namlen - 4;
575901ee4f0Sreyk 			if (strcmp(".crt", p) != 0)
576901ee4f0Sreyk 				continue;
577c03e9c27Stobhe 			len = snprintf(path, sizeof(path), "%s/%s", ca->sslpath,
578901ee4f0Sreyk 			    de->d_name);
579c03e9c27Stobhe 			if (len < 0 || (size_t)len >= sizeof(path))
580c03e9c27Stobhe 				err(1, "%s: snprintf", __func__);
581731c78a3Stedu 			char *cmd[] = { PATH_OPENSSL, "x509", "-subject",
582731c78a3Stedu 			    "-fingerprint", "-dates", "-noout", "-in", path,
583731c78a3Stedu 			    NULL };
584731c78a3Stedu 			ca_execv(cmd);
585901ee4f0Sreyk 			printf("\n");
586901ee4f0Sreyk 		}
587901ee4f0Sreyk 	}
588901ee4f0Sreyk 
589901ee4f0Sreyk 	closedir(dir);
590901ee4f0Sreyk 
591901ee4f0Sreyk 	return (0);
592901ee4f0Sreyk }
593901ee4f0Sreyk 
594901ee4f0Sreyk int
5953da6623bSjsg fcopy(char *src, char *dst, mode_t mode)
596901ee4f0Sreyk {
597901ee4f0Sreyk 	int		ifd, ofd;
598ef316c85Sreyk 	uint8_t		buf[BUFSIZ];
599901ee4f0Sreyk 	ssize_t		r;
600901ee4f0Sreyk 
601901ee4f0Sreyk 	if ((ifd = open(src, O_RDONLY)) == -1)
602901ee4f0Sreyk 		err(1, "open %s", src);
603901ee4f0Sreyk 
6041dbb1d4aSjsg 	if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) {
605ffb4dd05Sguenther 		int saved_errno = errno;
606901ee4f0Sreyk 		close(ifd);
607ffb4dd05Sguenther 		errc(1, saved_errno, "open %s", dst);
608901ee4f0Sreyk 	}
609901ee4f0Sreyk 
610901ee4f0Sreyk 	while ((r = read(ifd, buf, sizeof(buf))) > 0) {
6112a5bbc1bStobhe 		if (write(ofd, buf, r) == -1)
6122a5bbc1bStobhe 			err(1, "%s: write", __func__);
613901ee4f0Sreyk 	}
614901ee4f0Sreyk 
615901ee4f0Sreyk 	close(ofd);
616901ee4f0Sreyk 	close(ifd);
617901ee4f0Sreyk 
618901ee4f0Sreyk 	return (r == -1);
619901ee4f0Sreyk }
620901ee4f0Sreyk 
621bfcdcf42Sreyk void
6224f23bdabSreyk fcopy_env(const char *src, const char *dst, mode_t mode)
6234f23bdabSreyk {
6244f23bdabSreyk 	int		 ofd = -1, i;
625ef316c85Sreyk 	uint8_t		 buf[BUFSIZ];
6264f23bdabSreyk 	ssize_t		 r = -1, len;
6274f23bdabSreyk 	FILE		*ifp = NULL;
6284f23bdabSreyk 	int		 saved_errno;
6294f23bdabSreyk 
6304f23bdabSreyk 	if ((ifp = fopen(src, "r")) == NULL)
6314f23bdabSreyk 		err(1, "fopen %s", src);
6324f23bdabSreyk 
6334f23bdabSreyk 	if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1)
6344f23bdabSreyk 		goto done;
6354f23bdabSreyk 
6364f23bdabSreyk 	while (fgets(buf, sizeof(buf), ifp) != NULL) {
6374f23bdabSreyk 		for (i = 0; ca_env[i][0] != NULL; i++) {
6384f23bdabSreyk 			if (ca_env[i][1] == NULL)
6394f23bdabSreyk 				continue;
6404f23bdabSreyk 			if (expand_string(buf, sizeof(buf),
6414f23bdabSreyk 			    ca_env[i][0], ca_env[i][1]) == -1)
6424f23bdabSreyk 				errx(1, "env %s value too long", ca_env[i][0]);
6434f23bdabSreyk 		}
6444f23bdabSreyk 		len = strlen(buf);
6454f23bdabSreyk 		if (write(ofd, buf, len) != len)
6464f23bdabSreyk 			goto done;
6474f23bdabSreyk 	}
6484f23bdabSreyk 
6494f23bdabSreyk 	r = 0;
6504f23bdabSreyk 
6514f23bdabSreyk  done:
6524f23bdabSreyk 	saved_errno = errno;
6534f23bdabSreyk 	close(ofd);
6544f23bdabSreyk 	if (ifp != NULL)
6554f23bdabSreyk 		fclose(ifp);
6564f23bdabSreyk 	if (r == -1)
6574f23bdabSreyk 		errc(1, saved_errno, "open %s", dst);
6584f23bdabSreyk }
6594f23bdabSreyk 
6604f23bdabSreyk int
661901ee4f0Sreyk rm_dir(char *path)
662901ee4f0Sreyk {
663901ee4f0Sreyk 	FTS		*fts;
664901ee4f0Sreyk 	FTSENT		*p;
665901ee4f0Sreyk 	static char	*fpath[] = { NULL, NULL };
666901ee4f0Sreyk 
667901ee4f0Sreyk 	fpath[0] = path;
668901ee4f0Sreyk 	if ((fts = fts_open(fpath, FTS_PHYSICAL, NULL)) == NULL) {
669901ee4f0Sreyk 		warn("fts_open %s", path);
670901ee4f0Sreyk 		return (1);
671901ee4f0Sreyk 	}
672901ee4f0Sreyk 
673901ee4f0Sreyk 	while ((p = fts_read(fts)) != NULL) {
674901ee4f0Sreyk 		switch (p->fts_info) {
675901ee4f0Sreyk 		case FTS_DP:
676901ee4f0Sreyk 		case FTS_DNR:
677901ee4f0Sreyk 			if (rmdir(p->fts_accpath) == -1)
678901ee4f0Sreyk 				warn("rmdir %s", p->fts_accpath);
679901ee4f0Sreyk 			break;
680901ee4f0Sreyk 		case FTS_F:
681901ee4f0Sreyk 			if (unlink(p->fts_accpath) == -1)
682901ee4f0Sreyk 				warn("unlink %s", p->fts_accpath);
683901ee4f0Sreyk 			break;
684901ee4f0Sreyk 		case FTS_D:
685901ee4f0Sreyk 		case FTS_DOT:
686901ee4f0Sreyk 		default:
687901ee4f0Sreyk 			continue;
688901ee4f0Sreyk 		}
689901ee4f0Sreyk 	}
690901ee4f0Sreyk 	fts_close(fts);
691901ee4f0Sreyk 
692901ee4f0Sreyk 	return (0);
693901ee4f0Sreyk }
694901ee4f0Sreyk 
69547e28f79Sreyk void
6967638a50cSjsg ca_hier(char *path)
6977638a50cSjsg {
6987638a50cSjsg 	struct stat	 st;
6997638a50cSjsg 	char		 dst[PATH_MAX];
700ef316c85Sreyk 	unsigned int	 i;
7017638a50cSjsg 
7022746af23Sjsg 	for (i = 0; i < nitems(hier); i++) {
7037638a50cSjsg 		strlcpy(dst, path, sizeof(dst));
7042746af23Sjsg 		strlcat(dst, hier[i].dir, sizeof(dst));
7057638a50cSjsg 		if (stat(dst, &st) != 0 && errno == ENOENT &&
7062746af23Sjsg 		    mkdir(dst, hier[i].mode) != 0)
7077638a50cSjsg 			err(1, "failed to create dir %s", dst);
7087638a50cSjsg 	}
7097638a50cSjsg }
7107638a50cSjsg 
711901ee4f0Sreyk int
712cfe372e4Sreyk ca_export(struct ca *ca, char *keyname, char *myname, char *password)
713901ee4f0Sreyk {
7140dd4c7c3Sjsg 	DIR		*dexp;
7150dd4c7c3Sjsg 	struct dirent	*de;
716901ee4f0Sreyk 	struct stat	 st;
717901ee4f0Sreyk 	char		*pass;
718901ee4f0Sreyk 	char		 prev[_PASSWORD_LEN + 1];
719731c78a3Stedu 	char		 passenv[_PASSWORD_LEN + 8];
720901ee4f0Sreyk 	char		 oname[PATH_MAX];
721901ee4f0Sreyk 	char		 src[PATH_MAX];
722901ee4f0Sreyk 	char		 dst[PATH_MAX];
723731c78a3Stedu 	char		 cacrt[PATH_MAX];
724731c78a3Stedu 	char		 capfx[PATH_MAX];
725731c78a3Stedu 	char		 key[PATH_MAX];
726731c78a3Stedu 	char		 crt[PATH_MAX];
727731c78a3Stedu 	char		 pfx[PATH_MAX];
728901ee4f0Sreyk 	char		*p;
729901ee4f0Sreyk 	char		 tpl[] = "/tmp/ikectl.XXXXXXXXXX";
730ef316c85Sreyk 	unsigned int	 i;
7310dd4c7c3Sjsg 	int		 fd;
732c03e9c27Stobhe 	int		 len;
7330dd4c7c3Sjsg 
734f614af3bSjsg 	if (keyname != NULL) {
7350dd4c7c3Sjsg 		if (strlcpy(oname, keyname, sizeof(oname)) >= sizeof(oname))
73612d9f607Ssemarie 			errx(1, "name too long");
737f614af3bSjsg 	} else {
738f614af3bSjsg 		strlcpy(oname, "ca", sizeof(oname));
739f614af3bSjsg 	}
740901ee4f0Sreyk 
741901ee4f0Sreyk 	/* colons are not valid characters in windows filenames... */
742901ee4f0Sreyk 	while ((p = strchr(oname, ':')) != NULL)
743901ee4f0Sreyk 		*p = '_';
744901ee4f0Sreyk 
745cfe372e4Sreyk 	if (password != NULL)
746cfe372e4Sreyk 		pass = password;
747cfe372e4Sreyk 	else {
748901ee4f0Sreyk 		pass = getpass("Export passphrase:");
749901ee4f0Sreyk 		if (pass == NULL || *pass == '\0')
750901ee4f0Sreyk 			err(1, "password not set");
751901ee4f0Sreyk 
752901ee4f0Sreyk 		strlcpy(prev, pass, sizeof(prev));
753901ee4f0Sreyk 		pass = getpass("Retype export passphrase:");
754901ee4f0Sreyk 		if (pass == NULL || strcmp(prev, pass) != 0)
755901ee4f0Sreyk 			errx(1, "passphrase does not match!");
756cfe372e4Sreyk 	}
757901ee4f0Sreyk 
758c03e9c27Stobhe 	len = snprintf(cacrt, sizeof(cacrt), "%s/ca.crt", ca->sslpath);
759c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(cacrt))
760c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
761c03e9c27Stobhe 	len = snprintf(capfx, sizeof(capfx), "%s/ca.pfx", ca->sslpath);
762c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(capfx))
763c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
764c03e9c27Stobhe 	len = snprintf(key, sizeof(key), "%s/private/%s.key", ca->sslpath, keyname);
765c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(key))
766c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
767c03e9c27Stobhe 	len = snprintf(crt, sizeof(crt), "%s/%s.crt", ca->sslpath, keyname);
768c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(crt))
769c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
770c03e9c27Stobhe 	len = snprintf(pfx, sizeof(pfx), "%s/private/%s.pfx", ca->sslpath, oname);
771c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(pfx))
772c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
773731c78a3Stedu 
774c03e9c27Stobhe 	len = snprintf(passenv, sizeof(passenv), "EXPASS=%s", pass);
775c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(passenv))
776c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
777731c78a3Stedu 	putenv(passenv);
778731c78a3Stedu 
7790dd4c7c3Sjsg 	if (keyname != NULL) {
780731c78a3Stedu 		char *cmd[] = { PATH_OPENSSL, "pkcs12", "-export",
781731c78a3Stedu 		    "-name", keyname, "-CAfile", cacrt, "-inkey", key,
782731c78a3Stedu 		    "-in", crt, "-out", pfx, "-passout", "env:EXPASS",
783731c78a3Stedu 		    "-passin", ca->passfile, NULL };
784731c78a3Stedu 		ca_execv(cmd);
7850dd4c7c3Sjsg 	}
786901ee4f0Sreyk 
787731c78a3Stedu 	char *pkcscmd[] = { PATH_OPENSSL, "pkcs12", "-export",
788731c78a3Stedu 	    "-caname", ca->caname, "-name", ca->caname, "-cacerts",
789731c78a3Stedu 	    "-nokeys", "-in", cacrt, "-out", capfx,
790731c78a3Stedu 	    "-passout", "env:EXPASS", "-passin", ca->passfile, NULL };
791731c78a3Stedu 	ca_execv(pkcscmd);
792731c78a3Stedu 
793731c78a3Stedu 	unsetenv("EXPASS");
794731c78a3Stedu 	explicit_bzero(passenv, sizeof(passenv));
795901ee4f0Sreyk 
796901ee4f0Sreyk 	if ((p = mkdtemp(tpl)) == NULL)
797901ee4f0Sreyk 		err(1, "could not create temp dir");
798901ee4f0Sreyk 
799a718290cSphessler 	chmod(p, 0755);
800a718290cSphessler 
8012746af23Sjsg 	for (i = 0; i < nitems(hier); i++) {
802901ee4f0Sreyk 		strlcpy(dst, p, sizeof(dst));
8032746af23Sjsg 		strlcat(dst, hier[i].dir, sizeof(dst));
804465ad9d7Sjsg 		if (stat(dst, &st) != 0 && errno == ENOENT &&
805465ad9d7Sjsg 		    mkdir(dst, hier[i].mode) != 0)
806901ee4f0Sreyk 			err(1, "failed to create dir %s", dst);
807901ee4f0Sreyk 	}
808901ee4f0Sreyk 
8090dd4c7c3Sjsg 	/* create a file with the address of the peer to connect to */
8100dd4c7c3Sjsg 	if (myname != NULL) {
811c03e9c27Stobhe 		len = snprintf(dst, sizeof(dst), "%s/export/peer.txt", p);
812c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(dst))
813c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
8140dd4c7c3Sjsg 		if ((fd = open(dst, O_WRONLY|O_CREAT, 0644)) == -1)
8150dd4c7c3Sjsg 			err(1, "open %s", dst);
8162a5bbc1bStobhe 		if (write(fd, myname, strlen(myname)) == -1)
8172a5bbc1bStobhe 			err(1, "%s: write", __func__);
8180dd4c7c3Sjsg 		close(fd);
8190dd4c7c3Sjsg 	}
820901ee4f0Sreyk 
821c03e9c27Stobhe 	len = snprintf(src, sizeof(src), "%s/ca.pfx", ca->sslpath);
822c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(src))
823c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
824c03e9c27Stobhe 	len = snprintf(dst, sizeof(dst), "%s/export/ca.pfx", p);
825c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(dst))
826c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
8273da6623bSjsg 	fcopy(src, dst, 0644);
828901ee4f0Sreyk 
829c03e9c27Stobhe 	len = snprintf(src, sizeof(src), "%s/ca.crt", ca->sslpath);
830c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(src))
831c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
832c03e9c27Stobhe 	len = snprintf(dst, sizeof(dst), "%s/ca/ca.crt", p);
833c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(dst))
834c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
8353da6623bSjsg 	fcopy(src, dst, 0644);
836901ee4f0Sreyk 
837c03e9c27Stobhe 	len = snprintf(src, sizeof(src), "%s/ca.crl", ca->sslpath);
838c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(src))
839c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
8400dd4c7c3Sjsg 	if (stat(src, &st) == 0) {
841c03e9c27Stobhe 		len = snprintf(dst, sizeof(dst), "%s/crls/ca.crl", p);
842c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(dst))
843c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
8440dd4c7c3Sjsg 		fcopy(src, dst, 0644);
8450dd4c7c3Sjsg 	}
8460dd4c7c3Sjsg 
8470dd4c7c3Sjsg 	if (keyname != NULL) {
848c03e9c27Stobhe 		len = snprintf(src, sizeof(src), "%s/private/%s.pfx",
849c03e9c27Stobhe 		    ca->sslpath, oname);
850c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(src))
851c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
852c03e9c27Stobhe 		len = snprintf(dst, sizeof(dst), "%s/export/%s.pfx", p, oname);
853c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(dst))
854c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
8550dd4c7c3Sjsg 		fcopy(src, dst, 0644);
8560dd4c7c3Sjsg 
857c03e9c27Stobhe 		len = snprintf(src, sizeof(src), "%s/private/%s.key",
858c03e9c27Stobhe 		    ca->sslpath, keyname);
859c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(src))
860c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
861c03e9c27Stobhe 		len = snprintf(dst, sizeof(dst), "%s/private/%s.key", p, keyname);
862c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(dst))
863c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
864c03e9c27Stobhe 		fcopy(src, dst, 0600);
865c03e9c27Stobhe 		len = snprintf(dst, sizeof(dst), "%s/private/local.key", p);
866c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(dst))
867c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
868c03e9c27Stobhe 		fcopy(src, dst, 0600);
869c03e9c27Stobhe 
870c03e9c27Stobhe 		len = snprintf(src, sizeof(src), "%s/%s.crt", ca->sslpath,
8710dd4c7c3Sjsg 		    keyname);
872c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(src))
873c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
874c03e9c27Stobhe 		len = snprintf(dst, sizeof(dst), "%s/certs/%s.crt", p, keyname);
875c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(dst))
876c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
8773da6623bSjsg 		fcopy(src, dst, 0644);
878901ee4f0Sreyk 
879c03e9c27Stobhe 		len = snprintf(dst, sizeof(dst), "%s/local.pub", p);
880c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(dst))
881c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
882731c78a3Stedu 		char *cmd[] = { PATH_OPENSSL, "rsa", "-out", dst, "-in", key,
883731c78a3Stedu 		    "-pubout", NULL };
884731c78a3Stedu 		ca_execv(cmd);
8850dd4c7c3Sjsg 	}
886901ee4f0Sreyk 
887901ee4f0Sreyk 	if (stat(PATH_TAR, &st) == 0) {
888c03e9c27Stobhe 		len = snprintf(src, sizeof(src), "%s.tgz", oname);
889c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(src))
890c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
891731c78a3Stedu 		if (keyname == NULL) {
892731c78a3Stedu 			char *cmd[] = { PATH_TAR, "-zcf", src,
893731c78a3Stedu 			    "-C", ca->sslpath, ".", NULL };
894731c78a3Stedu 			ca_execv(cmd);
895731c78a3Stedu 		} else {
896731c78a3Stedu 			char *cmd[] = { PATH_TAR, "-zcf", src, "-C", p, ".",
897731c78a3Stedu 			    NULL };
898731c78a3Stedu 			ca_execv(cmd);
899731c78a3Stedu 		}
900901ee4f0Sreyk 		if (realpath(src, dst) != NULL)
901901ee4f0Sreyk 			printf("exported files in %s\n", dst);
902901ee4f0Sreyk 	}
903901ee4f0Sreyk 
904901ee4f0Sreyk 	if (stat(PATH_ZIP, &st) == 0) {
9050dd4c7c3Sjsg 		dexp = opendir(EXPDIR);
9060dd4c7c3Sjsg 		if (dexp) {
9070dd4c7c3Sjsg 			while ((de = readdir(dexp)) != NULL) {
9080dd4c7c3Sjsg 				if (!strcmp(de->d_name, ".") ||
9090dd4c7c3Sjsg 				    !strcmp(de->d_name, ".."))
9100dd4c7c3Sjsg 					continue;
911c03e9c27Stobhe 				len = snprintf(src, sizeof(src), "%s/%s",
912c03e9c27Stobhe 				    EXPDIR, de->d_name);
913c03e9c27Stobhe 				if (len < 0 || (size_t)len >= sizeof(src))
914c03e9c27Stobhe 					err(1, "%s: snprintf", __func__);
915c03e9c27Stobhe 				len = snprintf(dst, sizeof(dst), "%s/export/%s",
916c03e9c27Stobhe 				    p, de->d_name);
917c03e9c27Stobhe 				if (len < 0 || (size_t)len >= sizeof(dst))
918c03e9c27Stobhe 					err(1, "%s: snprintf", __func__);
919d513b0f4Ssemarie 				fcopy(src, dst, 0644);
9200dd4c7c3Sjsg 			}
9210dd4c7c3Sjsg 			closedir(dexp);
9220dd4c7c3Sjsg 		}
9230dd4c7c3Sjsg 
924c03e9c27Stobhe 		len = snprintf(dst, sizeof(dst), "%s/export", p);
925c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(dst))
926c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
927901ee4f0Sreyk 		if (getcwd(src, sizeof(src)) == NULL)
928901ee4f0Sreyk 			err(1, "could not get cwd");
929901ee4f0Sreyk 
930901ee4f0Sreyk 		if (chdir(dst) == -1)
931901ee4f0Sreyk 			err(1, "could not change %s", dst);
932901ee4f0Sreyk 
933c03e9c27Stobhe 		len = snprintf(dst, sizeof(dst), "%s/%s.zip", src, oname);
934c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(dst))
935c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
936731c78a3Stedu 		char *cmd[] = { PATH_ZIP, "-qr", dst, ".", NULL };
937731c78a3Stedu 		ca_execv(cmd);
938901ee4f0Sreyk 		printf("exported files in %s\n", dst);
939901ee4f0Sreyk 
940901ee4f0Sreyk 		if (chdir(src) == -1)
941901ee4f0Sreyk 			err(1, "could not change %s", dst);
942901ee4f0Sreyk 	}
943901ee4f0Sreyk 
944901ee4f0Sreyk 	rm_dir(p);
945901ee4f0Sreyk 
946901ee4f0Sreyk 	return (0);
947901ee4f0Sreyk }
948901ee4f0Sreyk 
9498e3cf88fSjsg /* create index if it doesn't already exist */
9508e3cf88fSjsg void
9518e3cf88fSjsg ca_create_index(struct ca *ca)
9528e3cf88fSjsg {
9538e3cf88fSjsg 	struct stat	 st;
9548e3cf88fSjsg 	int		 fd;
955c03e9c27Stobhe 	int		 len;
9568e3cf88fSjsg 
957c03e9c27Stobhe 	len = snprintf(ca->index, sizeof(ca->index), "%s/index.txt",
958c03e9c27Stobhe 	    ca->sslpath);
959c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(ca->index))
960c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
9618e3cf88fSjsg 	if (stat(ca->index, &st) != 0) {
9628e3cf88fSjsg 		if  (errno == ENOENT) {
9638e3cf88fSjsg 			if ((fd = open(ca->index, O_WRONLY | O_CREAT, 0644))
9648e3cf88fSjsg 			    == -1)
9658e3cf88fSjsg 				err(1, "could not create file %s", ca->index);
9668e3cf88fSjsg 			close(fd);
9678e3cf88fSjsg 		} else
9688e3cf88fSjsg 			err(1, "could not access %s", ca->index);
9698e3cf88fSjsg 	}
9708e3cf88fSjsg 
971c03e9c27Stobhe 	len = snprintf(ca->serial, sizeof(ca->serial), "%s/serial.txt",
972c03e9c27Stobhe 	    ca->sslpath);
973c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(ca->serial))
974c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
9758e3cf88fSjsg 	if (stat(ca->serial, &st) != 0) {
9768e3cf88fSjsg 		if  (errno == ENOENT) {
9778e3cf88fSjsg 			if ((fd = open(ca->serial, O_WRONLY | O_CREAT, 0644))
9788e3cf88fSjsg 			    == -1)
9798e3cf88fSjsg 				err(1, "could not create file %s", ca->serial);
9808e3cf88fSjsg 			/* serial file must be created with a number */
9818e3cf88fSjsg 			if (write(fd, "01\n", 3) != 3)
9828e3cf88fSjsg 				err(1, "write %s", ca->serial);
9838e3cf88fSjsg 			close(fd);
9848e3cf88fSjsg 		} else
9858e3cf88fSjsg 			err(1, "could not access %s", ca->serial);
9868e3cf88fSjsg 	}
9878e3cf88fSjsg }
9888e3cf88fSjsg 
989c3cc2c5eSjsg int
990c3cc2c5eSjsg ca_revoke(struct ca *ca, char *keyname)
991c3cc2c5eSjsg {
992c3cc2c5eSjsg 	struct stat	 st;
993c3cc2c5eSjsg 	char		 path[PATH_MAX];
994731c78a3Stedu 	char		 cakey[PATH_MAX];
995731c78a3Stedu 	char		 cacrt[PATH_MAX];
996c03e9c27Stobhe 	size_t		 len;
997c3cc2c5eSjsg 
9987430271cSphessler 	if (keyname) {
999c03e9c27Stobhe 		len = snprintf(path, sizeof(path), "%s/%s.crt",
1000c3cc2c5eSjsg 		    ca->sslpath, keyname);
1001c03e9c27Stobhe 		if (len < 0 || (size_t)len >= sizeof(path))
1002c03e9c27Stobhe 			err(1, "%s: snprintf", __func__);
1003c3cc2c5eSjsg 		if (stat(path, &st) != 0) {
1004c3cc2c5eSjsg 			warn("Problem with certificate for '%s'", keyname);
1005c3cc2c5eSjsg 			return (1);
1006c3cc2c5eSjsg 		}
10077430271cSphessler 	}
1008c3cc2c5eSjsg 
10098e3cf88fSjsg 	ca_create_index(ca);
1010c3cc2c5eSjsg 
10118e3cf88fSjsg 	ca_setenv("$ENV::CADB", ca->index);
10128e3cf88fSjsg 	ca_setenv("$ENV::CASERIAL", ca->serial);
101355ace1c0Sjsg 	if (keyname)
101455ace1c0Sjsg 		ca_setenv("$ENV::REQ_EXT", "");
101555ace1c0Sjsg 
10164f23bdabSreyk 	ca_setcnf(ca, "ca-revoke");
10174f23bdabSreyk 
1018c03e9c27Stobhe 	len = snprintf(cakey, sizeof(cakey), "%s/private/ca.key", ca->sslpath);
1019c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(cakey))
1020c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
1021c03e9c27Stobhe 	len = snprintf(cacrt, sizeof(cacrt), "%s/ca.crt", ca->sslpath);
1022c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(cacrt))
1023c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
1024731c78a3Stedu 
10257430271cSphessler 	if (keyname) {
1026731c78a3Stedu 		char *cmd[] = { PATH_OPENSSL, "ca", "-config", ca->sslcnf,
1027731c78a3Stedu 		    "-keyfile", cakey, "-passin", ca->passfile, "-cert", cacrt,
1028731c78a3Stedu 		    "-revoke", path, ca->batch, NULL };
1029731c78a3Stedu 		ca_execv(cmd);
10307430271cSphessler 	}
1031c3cc2c5eSjsg 
1032c03e9c27Stobhe 	len = snprintf(path, sizeof(path), "%s/ca.crl", ca->sslpath);
1033c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(path))
1034c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
1035731c78a3Stedu 	char *cmd[] = { PATH_OPENSSL, "ca", "-config", ca->sslcnf,
1036731c78a3Stedu 	    "-keyfile", cakey, "-passin", ca->passfile, "-gencrl",
1037*7c9b6f9dSpascal 	    "-cert", cacrt, "-out", path, ca->batch, NULL };
1038731c78a3Stedu 	ca_execv(cmd);
1039c3cc2c5eSjsg 
1040c3cc2c5eSjsg 	return (0);
1041c3cc2c5eSjsg }
1042c3cc2c5eSjsg 
10434f23bdabSreyk void
10444f23bdabSreyk ca_clrenv(void)
10454f23bdabSreyk {
10464f23bdabSreyk 	int	 i;
10478068c079Spatrick 	for (i = 0; ca_env[i][0] != NULL; i++) {
10488068c079Spatrick 		free(ca_env[i][1]);
10494f23bdabSreyk 		ca_env[i][1] = NULL;
10504f23bdabSreyk 	}
10518068c079Spatrick }
10524f23bdabSreyk 
10534f23bdabSreyk void
10544f23bdabSreyk ca_setenv(const char *key, const char *value)
10554f23bdabSreyk {
10564f23bdabSreyk 	int	 i;
10578068c079Spatrick 	char	*p = NULL;
10584f23bdabSreyk 
10594f23bdabSreyk 	for (i = 0; ca_env[i][0] != NULL; i++) {
10604f23bdabSreyk 		if (strcmp(ca_env[i][0], key) == 0) {
10614f23bdabSreyk 			if (ca_env[i][1] != NULL)
10624f23bdabSreyk 				errx(1, "env %s already set: %s", key, value);
10638068c079Spatrick 			p = strdup(value);
10648068c079Spatrick 			if (p == NULL)
10658068c079Spatrick 				err(1, NULL);
10668068c079Spatrick 			ca_env[i][1] = p;
10674f23bdabSreyk 			return;
10684f23bdabSreyk 		}
10694f23bdabSreyk 	}
10704f23bdabSreyk 	errx(1, "env %s invalid", key);
10714f23bdabSreyk }
10724f23bdabSreyk 
10734f23bdabSreyk void
10744f23bdabSreyk ca_setcnf(struct ca *ca, const char *keyname)
10754f23bdabSreyk {
10764f23bdabSreyk 	struct stat	 st;
10774f23bdabSreyk 	const char	*extcnf, *sslcnf;
1078c03e9c27Stobhe 	int		 len;
10794f23bdabSreyk 
10804f23bdabSreyk 	if (stat(IKECA_CNF, &st) == 0) {
10814f23bdabSreyk 		extcnf = IKECA_CNF;
10824f23bdabSreyk 		sslcnf = IKECA_CNF;
10834f23bdabSreyk 	} else {
10844f23bdabSreyk 		extcnf = X509_CNF;
10854f23bdabSreyk 		sslcnf = SSL_CNF;
10864f23bdabSreyk 	}
10874f23bdabSreyk 
1088c03e9c27Stobhe 	len = snprintf(ca->extcnf, sizeof(ca->extcnf), "%s/%s-ext.cnf",
10894f23bdabSreyk 	    ca->sslpath, keyname);
1090c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(ca->extcnf))
1091c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
1092c03e9c27Stobhe 	len = snprintf(ca->sslcnf, sizeof(ca->sslcnf), "%s/%s-ssl.cnf",
10934f23bdabSreyk 	    ca->sslpath, keyname);
1094c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(ca->sslcnf))
1095c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
10964f23bdabSreyk 
10974f23bdabSreyk 	fcopy_env(extcnf, ca->extcnf, 0400);
10984f23bdabSreyk 	fcopy_env(sslcnf, ca->sslcnf, 0400);
10994f23bdabSreyk }
11004f23bdabSreyk 
1101901ee4f0Sreyk struct ca *
1102cfd26ebdSreyk ca_setup(char *caname, int create, int quiet, char *pass)
1103901ee4f0Sreyk {
1104901ee4f0Sreyk 	struct stat	 st;
1105901ee4f0Sreyk 	struct ca	*ca;
1106901ee4f0Sreyk 	char		 path[PATH_MAX];
1107c03e9c27Stobhe 	int		 len;
1108901ee4f0Sreyk 
1109901ee4f0Sreyk 	if (stat(PATH_OPENSSL, &st) == -1)
1110901ee4f0Sreyk 		err(1, "openssl binary not available");
1111901ee4f0Sreyk 
1112901ee4f0Sreyk 	if ((ca = calloc(1, sizeof(struct ca))) == NULL)
1113901ee4f0Sreyk 		err(1, "calloc");
1114901ee4f0Sreyk 
1115901ee4f0Sreyk 	ca->caname = strdup(caname);
1116c03e9c27Stobhe 	len = snprintf(ca->sslpath, sizeof(ca->sslpath), SSLDIR "/%s", caname);
1117c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(ca->sslpath))
1118c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
1119901ee4f0Sreyk 
1120cfd26ebdSreyk 	if (quiet)
1121731c78a3Stedu 		ca->batch = "-batch";
1122cfd26ebdSreyk 
1123901ee4f0Sreyk 	if (create == 0 && stat(ca->sslpath, &st) == -1) {
1124901ee4f0Sreyk 		free(ca->caname);
1125901ee4f0Sreyk 		free(ca);
1126901ee4f0Sreyk 		errx(1, "CA '%s' does not exist", caname);
1127901ee4f0Sreyk 	}
1128901ee4f0Sreyk 
1129901ee4f0Sreyk 	strlcpy(path, ca->sslpath, sizeof(path));
1130901ee4f0Sreyk 	if (mkdir(path, 0777) == -1 && errno != EEXIST)
1131901ee4f0Sreyk 		err(1, "failed to create dir %s", path);
1132901ee4f0Sreyk 	strlcat(path, "/private", sizeof(path));
1133901ee4f0Sreyk 	if (mkdir(path, 0700) == -1 && errno != EEXIST)
1134901ee4f0Sreyk 		err(1, "failed to create dir %s", path);
1135901ee4f0Sreyk 
1136c03e9c27Stobhe 	len = snprintf(path, sizeof(path), "%s/ikeca.passwd", ca->sslpath);
1137c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(path))
1138c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
1139731c78a3Stedu 	if (create && stat(path, &st) == -1 && errno == ENOENT)
1140731c78a3Stedu 		ca_newpass(path, pass);
1141c03e9c27Stobhe 	len = snprintf(ca->passfile, sizeof(ca->passfile), "file:%s", path);
1142c03e9c27Stobhe 	if (len < 0 || (size_t)len >= sizeof(ca->passfile))
1143c03e9c27Stobhe 		err(1, "%s: snprintf", __func__);
1144901ee4f0Sreyk 
1145901ee4f0Sreyk 	return (ca);
1146901ee4f0Sreyk }
1147731c78a3Stedu 
1148731c78a3Stedu int static
1149731c78a3Stedu ca_execv(char *const argv[])
1150731c78a3Stedu {
1151731c78a3Stedu 	pid_t pid, cpid;
1152731c78a3Stedu 	int status;
1153731c78a3Stedu 
1154731c78a3Stedu 	switch (cpid = fork()) {
1155731c78a3Stedu 	case -1:
1156731c78a3Stedu 		return -1;
1157731c78a3Stedu 	case 0:
1158731c78a3Stedu 		execv(argv[0], argv);
1159731c78a3Stedu 		_exit(127);
1160731c78a3Stedu 	}
1161731c78a3Stedu 
1162731c78a3Stedu 	do {
1163731c78a3Stedu 		pid = waitpid(cpid, &status, 0);
1164731c78a3Stedu 	} while (pid == -1 && errno == EINTR);
1165731c78a3Stedu 
1166731c78a3Stedu 	return (pid == -1 ? -1 : WEXITSTATUS(status));
1167731c78a3Stedu }
1168