xref: /openbsd/usr.sbin/ikectl/ikeca.c (revision 2a5bbc1b)
1 /*	$OpenBSD: ikeca.c,v 1.51 2021/01/23 22:04:55 tobhe Exp $	*/
2 
3 /*
4  * Copyright (c) 2010 Jonathan Gray <jsg@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/wait.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 #include <limits.h>
33 
34 #include <openssl/rand.h>
35 #include <openssl/rsa.h>
36 #include <openssl/pem.h>
37 
38 #include "types.h"
39 #include "parser.h"
40 
41 #ifndef PREFIX
42 #define PREFIX		""
43 #endif
44 #ifndef SSLDIR
45 #define SSLDIR		PREFIX "/etc/ssl"
46 #endif
47 #define SSL_CNF		SSLDIR "/openssl.cnf"
48 #define X509_CNF	SSLDIR "/x509v3.cnf"
49 #define IKECA_CNF	SSLDIR "/ikeca.cnf"
50 #define KEYBASE		PREFIX "/etc/iked"
51 #ifndef EXPDIR
52 #define EXPDIR		PREFIX "/usr/share/iked"
53 #endif
54 
55 #ifndef PATH_OPENSSL
56 #define PATH_OPENSSL	"/usr/bin/openssl"
57 #endif
58 #ifndef PATH_ZIP
59 #define PATH_ZIP	"/usr/local/bin/zip"
60 #endif
61 #ifndef PATH_TAR
62 #define PATH_TAR	"/bin/tar"
63 #endif
64 
65 struct ca {
66 	char	 sslpath[PATH_MAX];
67 	char	 passfile[PATH_MAX + 5]; /* Includes the "file:" prefix */
68 	char	 index[PATH_MAX];
69 	char	 serial[PATH_MAX];
70 	char	 sslcnf[PATH_MAX];
71 	char	 extcnf[PATH_MAX];
72 	char	*batch;
73 	char	*caname;
74 };
75 
76 struct {
77 	char	*dir;
78 	mode_t	 mode;
79 } hier[] = {
80 	{ "",		0755 },
81 	{ "/ca",	0755 },
82 	{ "/certs",	0755 },
83 	{ "/crls",	0755 },
84 	{ "/export",	0755 },
85 	{ "/private",	0700 }
86 };
87 
88 /* explicitly list allowed variables */
89 char *ca_env[][2] = {
90 	{ "$ENV::CADB", NULL },
91 	{ "$ENV::CASERIAL", NULL },
92 	{ "$ENV::CERTFQDN", NULL },
93 	{ "$ENV::CERTIP", NULL },
94 	{ "$ENV::CERTPATHLEN", NULL },
95 	{ "$ENV::CERTUSAGE", NULL },
96 	{ "$ENV::CERT_C", NULL },
97 	{ "$ENV::CERT_CN", NULL },
98 	{ "$ENV::CERT_EMAIL", NULL },
99 	{ "$ENV::CERT_L", NULL },
100 	{ "$ENV::CERT_O", NULL },
101 	{ "$ENV::CERT_OU", NULL },
102 	{ "$ENV::CERT_ST", NULL },
103 	{ "$ENV::EXTCERTUSAGE", NULL },
104 	{ "$ENV::NSCERTTYPE", NULL },
105 	{ "$ENV::REQ_EXT", NULL },
106 	{ NULL }
107 };
108 
109 int		 ca_sign(struct ca *, char *, int);
110 int		 ca_request(struct ca *, char *, int);
111 void		 ca_newpass(char *, char *);
112 int		 fcopy(char *, char *, mode_t);
113 void		 fcopy_env(const char *, const char *, mode_t);
114 int		 rm_dir(char *);
115 void		 ca_hier(char *);
116 void		 ca_setenv(const char *, const char *);
117 void		 ca_clrenv(void);
118 void		 ca_setcnf(struct ca *, const char *);
119 void		 ca_create_index(struct ca *);
120 int static	 ca_execv(char *const []);
121 
122 /* util.c */
123 int		 expand_string(char *, size_t, const char *, const char *);
124 
125 int
ca_delete(struct ca * ca)126 ca_delete(struct ca *ca)
127 {
128 	return (rm_dir(ca->sslpath));
129 }
130 
131 int
ca_key_create(struct ca * ca,char * keyname)132 ca_key_create(struct ca *ca, char *keyname)
133 {
134 	struct stat		 st;
135 	char			 path[PATH_MAX];
136 	int			 len;
137 
138 	len = snprintf(path, sizeof(path), "%s/private/%s.key",
139 	    ca->sslpath, keyname);
140 	if (len < 0 || (size_t)len >= sizeof(path))
141 		err(1, "%s: snprintf", __func__);
142 
143 	/* don't recreate key if one is already present */
144 	if (stat(path, &st) == 0) {
145 		return (0);
146 	}
147 
148 	char *cmd[] = { PATH_OPENSSL, "genrsa", "-out", path, "2048", NULL };
149 	ca_execv(cmd);
150 	chmod(path, 0600);
151 
152 	return (0);
153 }
154 
155 int
ca_key_import(struct ca * ca,char * keyname,char * import)156 ca_key_import(struct ca *ca, char *keyname, char *import)
157 {
158 	struct stat		 st;
159 	char			 dst[PATH_MAX];
160 	int			 len;
161 
162 	if (stat(import, &st) != 0) {
163 		warn("could not access keyfile %s", import);
164 		return (1);
165 	}
166 
167 	len = snprintf(dst, sizeof(dst), "%s/private/%s.key", ca->sslpath, keyname);
168 	if (len < 0 || (size_t)len >= sizeof(dst))
169 		err(1, "%s: snprintf", __func__);
170 
171 	fcopy(import, dst, 0600);
172 
173 	return (0);
174 }
175 
176 int
ca_key_delete(struct ca * ca,char * keyname)177 ca_key_delete(struct ca *ca, char *keyname)
178 {
179 	char			 path[PATH_MAX];
180 	int			 len;
181 
182 	len = snprintf(path, sizeof(path), "%s/private/%s.key",
183 	    ca->sslpath, keyname);
184 	if (len < 0 || (size_t)len >= sizeof(path))
185 		err(1, "%s: snprintf", __func__);
186 	unlink(path);
187 
188 	return (0);
189 }
190 
191 int
ca_delkey(struct ca * ca,char * keyname)192 ca_delkey(struct ca *ca, char *keyname)
193 {
194 	char		file[PATH_MAX];
195 	int		len;
196 
197 	len = snprintf(file, sizeof(file), "%s/%s.crt", ca->sslpath, keyname);
198 	if (len < 0 || (size_t)len >= sizeof(file))
199 		err(1, "%s: snprintf", __func__);
200 	unlink(file);
201 
202 	len = snprintf(file, sizeof(file), "%s/private/%s.key", ca->sslpath, keyname);
203 	if (len < 0 || (size_t)len >= sizeof(file))
204 		err(1, "%s: snprintf", __func__);
205 	unlink(file);
206 
207 	len = snprintf(file, sizeof(file), "%s/private/%s.csr", ca->sslpath, keyname);
208 	if (len < 0 || (size_t)len >= sizeof(file))
209 		err(1, "%s: snprintf", __func__);
210 	unlink(file);
211 
212 	len = snprintf(file, sizeof(file), "%s/private/%s.pfx", ca->sslpath, keyname);
213 	if (len < 0 || (size_t)len >= sizeof(file))
214 		err(1, "%s: snprintf", __func__);
215 	unlink(file);
216 
217 	return (0);
218 }
219 
220 int
ca_request(struct ca * ca,char * keyname,int type)221 ca_request(struct ca *ca, char *keyname, int type)
222 {
223 	char		hostname[HOST_NAME_MAX+1];
224 	char		name[128];
225 	char		key[PATH_MAX];
226 	char		path[PATH_MAX];
227 	int		len;
228 
229 	ca_setenv("$ENV::CERT_CN", keyname);
230 
231 	strlcpy(name, keyname, sizeof(name));
232 
233 	if (type == HOST_IPADDR) {
234 		ca_setenv("$ENV::CERTIP", name);
235 		ca_setenv("$ENV::REQ_EXT", "x509v3_IPAddr");
236 	} else if (type == HOST_FQDN) {
237 		if (!strcmp(keyname, "local")) {
238 			if (gethostname(hostname, sizeof(hostname)))
239 				err(1, "gethostname");
240 			strlcpy(name, hostname, sizeof(name));
241 		}
242 		ca_setenv("$ENV::CERTFQDN", name);
243 		ca_setenv("$ENV::REQ_EXT", "x509v3_FQDN");
244 	} else {
245 		errx(1, "unknown host type %d", type);
246 	}
247 
248 	ca_setcnf(ca, keyname);
249 
250 	len = snprintf(key, sizeof(key), "%s/private/%s.key", ca->sslpath, keyname);
251 	if (len < 0 || (size_t)len >= sizeof(key))
252 		err(1, "%s: snprintf", __func__);
253 	len = snprintf(path, sizeof(path), "%s/private/%s.csr", ca->sslpath, keyname);
254 	if (len < 0 || (size_t)len >= sizeof(path))
255 		err(1, "%s: snprintf", __func__);
256 
257 	char *cmd[] = { PATH_OPENSSL, "req", "-new", "-key", key, "-out", path,
258 	    "-config", ca->sslcnf, ca->batch, NULL };
259 	ca_execv(cmd);
260 	chmod(path, 0600);
261 
262 	return (0);
263 }
264 
265 int
ca_sign(struct ca * ca,char * keyname,int type)266 ca_sign(struct ca *ca, char *keyname, int type)
267 {
268 	char		cakey[PATH_MAX];
269 	char		cacrt[PATH_MAX];
270 	char		out[PATH_MAX];
271 	char		in[PATH_MAX];
272 	char		*extensions = NULL;
273 	int		len;
274 
275 	if (type == HOST_IPADDR) {
276 		extensions = "x509v3_IPAddr";
277 	} else if (type == HOST_FQDN) {
278 		extensions = "x509v3_FQDN";
279 	} else {
280 		errx(1, "unknown host type %d", type);
281 	}
282 
283 	ca_create_index(ca);
284 
285 	ca_setenv("$ENV::CADB", ca->index);
286 	ca_setenv("$ENV::CASERIAL", ca->serial);
287 	ca_setcnf(ca, keyname);
288 
289 	len = snprintf(cakey, sizeof(cakey), "%s/private/ca.key", ca->sslpath);
290 	if (len < 0 || (size_t)len >= sizeof(cakey))
291 		err(1, "%s: snprintf", __func__);
292 	len = snprintf(cacrt, sizeof(cacrt), "%s/ca.crt", ca->sslpath);
293 	if (len < 0 || (size_t)len >= sizeof(cacrt))
294 		err(1, "%s: snprintf", __func__);
295 	len = snprintf(out, sizeof(out), "%s/%s.crt", ca->sslpath, keyname);
296 	if (len < 0 || (size_t)len >= sizeof(out))
297 		err(1, "%s: snprintf", __func__);
298 	len = snprintf(in, sizeof(in), "%s/private/%s.csr", ca->sslpath, keyname);
299 	if (len < 0 || (size_t)len >= sizeof(in))
300 		err(1, "%s: snprintf", __func__);
301 
302 	char *cmd[] = { PATH_OPENSSL, "ca", "-config", ca->sslcnf,
303 	    "-keyfile", cakey, "-cert", cacrt, "-extfile", ca->extcnf,
304 	    "-extensions", extensions, "-out", out, "-in", in,
305 	    "-passin", ca->passfile, "-outdir", ca->sslpath, "-batch", NULL };
306 	ca_execv(cmd);
307 
308 	return (0);
309 }
310 
311 int
ca_certificate(struct ca * ca,char * keyname,int type,int action)312 ca_certificate(struct ca *ca, char *keyname, int type, int action)
313 {
314 	ca_clrenv();
315 
316 	switch (action) {
317 	case CA_SERVER:
318 		ca_setenv("$ENV::EXTCERTUSAGE", "serverAuth");
319 		ca_setenv("$ENV::NSCERTTYPE", "server");
320 		ca_setenv("$ENV::CERTUSAGE",
321 		    "digitalSignature,keyEncipherment");
322 		break;
323 	case CA_CLIENT:
324 		ca_setenv("$ENV::EXTCERTUSAGE", "clientAuth");
325 		ca_setenv("$ENV::NSCERTTYPE", "client");
326 		ca_setenv("$ENV::CERTUSAGE",
327 		    "digitalSignature,keyAgreement");
328 		break;
329 	case CA_OCSP:
330 		ca_setenv("$ENV::EXTCERTUSAGE", "OCSPSigning");
331 		ca_setenv("$ENV::CERTUSAGE",
332 		    "nonRepudiation,digitalSignature,keyEncipherment");
333 		break;
334 	default:
335 		break;
336 	}
337 
338 	ca_key_create(ca, keyname);
339 	ca_request(ca, keyname, type);
340 	ca_sign(ca, keyname, type);
341 
342 	return (0);
343 }
344 
345 int
ca_key_install(struct ca * ca,char * keyname,char * dir)346 ca_key_install(struct ca *ca, char *keyname, char *dir)
347 {
348 	struct stat	 st;
349 	char		 src[PATH_MAX];
350 	char		 dst[PATH_MAX];
351 	char		 out[PATH_MAX];
352 	char		*p = NULL;
353 	int		 len;
354 
355 	len = snprintf(src, sizeof(src), "%s/private/%s.key", ca->sslpath, keyname);
356 	if (len < 0 || (size_t)len >= sizeof(src))
357 		err(1, "%s: snprintf", __func__);
358 	if (stat(src, &st) == -1) {
359 		if (errno == ENOENT)
360 			printf("key for '%s' does not exist\n", ca->caname);
361 		else
362 			warn("could not access key");
363 		return (1);
364 	}
365 
366 	if (dir == NULL)
367 		p = dir = strdup(KEYBASE);
368 
369 	ca_hier(dir);
370 
371 	len = snprintf(dst, sizeof(dst), "%s/private/local.key", dir);
372 	if (len < 0 || (size_t)len >= sizeof(dst))
373 		err(1, "%s: snprintf", __func__);
374 	fcopy(src, dst, 0600);
375 
376 	len = snprintf(out, sizeof(out), "%s/local.pub", dir);
377 	if (len < 0 || (size_t)len >= sizeof(out))
378 		err(1, "%s: snprintf", __func__);
379 
380 	char *cmd[] = { PATH_OPENSSL, "rsa", "-out", out, "-in", dst,
381 	    "-pubout", NULL };
382 	ca_execv(cmd);
383 
384 	free(p);
385 
386 	return (0);
387 }
388 
389 int
ca_cert_install(struct ca * ca,char * keyname,char * dir)390 ca_cert_install(struct ca *ca, char *keyname, char *dir)
391 {
392 	char		 src[PATH_MAX];
393 	char		 dst[PATH_MAX];
394 	int		 r;
395 	char		*p = NULL;
396 	int		 len;
397 
398 	if (dir == NULL)
399 		p = dir = strdup(KEYBASE);
400 
401 	ca_hier(dir);
402 
403 	if ((r = ca_key_install(ca, keyname, dir)) != 0) {
404 		free(dir);
405 		return (r);
406 	}
407 
408 	len = snprintf(src, sizeof(src), "%s/%s.crt", ca->sslpath, keyname);
409 	if (len < 0 || (size_t)len >= sizeof(src))
410 		err(1, "%s: snprintf", __func__);
411 	len = snprintf(dst, sizeof(dst), "%s/certs/%s.crt", dir, keyname);
412 	if (len < 0 || (size_t)len >= sizeof(dst))
413 		err(1, "%s: snprintf", __func__);
414 	fcopy(src, dst, 0644);
415 
416 	free(p);
417 
418 	return (0);
419 }
420 
421 void
ca_newpass(char * passfile,char * password)422 ca_newpass(char *passfile, char *password)
423 {
424 	FILE	*f;
425 	char	*pass;
426 	char	 prev[_PASSWORD_LEN + 1];
427 
428 	if (password != NULL) {
429 		pass = password;
430 		goto done;
431 	}
432 
433 	pass = getpass("CA passphrase:");
434 	if (pass == NULL || *pass == '\0')
435 		err(1, "password not set");
436 
437 	strlcpy(prev, pass, sizeof(prev));
438 	pass = getpass("Retype CA passphrase:");
439 	if (pass == NULL || strcmp(prev, pass) != 0)
440 		errx(1, "passphrase does not match!");
441 
442  done:
443 	if ((f = fopen(passfile, "wb")) == NULL)
444 		err(1, "could not open passfile %s", passfile);
445 	chmod(passfile, 0600);
446 
447 	fprintf(f, "%s\n%s\n", pass, pass);
448 
449 	fclose(f);
450 }
451 
452 int
ca_create(struct ca * ca)453 ca_create(struct ca *ca)
454 {
455 	char			 key[PATH_MAX];
456 	char			 csr[PATH_MAX];
457 	char			 crt[PATH_MAX];
458 	int			 len;
459 
460 	ca_clrenv();
461 
462 	len = snprintf(key, sizeof(key), "%s/private/ca.key", ca->sslpath);
463 	if (len < 0 || (size_t)len >= sizeof(key))
464 		err(1, "%s: snprintf", __func__);
465 	char *genrsa[] = { PATH_OPENSSL, "genrsa", "-aes256", "-out", key,
466 	    "-passout", ca->passfile, "2048", NULL };
467 	ca_execv(genrsa);
468 
469 	chmod(key, 0600);
470 
471 	ca_setenv("$ENV::CERT_CN", "VPN CA");
472 	ca_setenv("$ENV::REQ_EXT", "x509v3_CA");
473 	ca_setcnf(ca, "ca");
474 
475 	len = snprintf(csr, sizeof(csr), "%s/private/ca.csr", ca->sslpath);
476 	if (len < 0 || (size_t)len >= sizeof(csr))
477 		err(1, "%s: snprintf", __func__);
478 	char *reqcmd[] = { PATH_OPENSSL, "req", "-new", "-key", key,
479 	    "-config", ca->sslcnf, "-out", csr,
480 	    "-passin", ca->passfile, ca->batch, NULL };
481 	ca_execv(reqcmd);
482 	chmod(csr, 0600);
483 
484 	len = snprintf(crt, sizeof(crt), "%s/ca.crt", ca->sslpath);
485 	if (len < 0 || (size_t)len >= sizeof(crt))
486 		err(1, "%s: snprintf", __func__);
487 	char *x509[] = { PATH_OPENSSL, "x509", "-req", "-days", "4500",
488 	    "-in", csr, "-signkey", key, "-sha256",
489 	    "-extfile", ca->extcnf, "-extensions", "x509v3_CA",
490 	    "-out", crt, "-passin", ca->passfile, NULL };
491 	ca_execv(x509);
492 
493 	/* Create the CRL revocation list */
494 	ca_revoke(ca, NULL);
495 
496 	return (0);
497 }
498 
499 int
ca_install(struct ca * ca,char * dir)500 ca_install(struct ca *ca, char *dir)
501 {
502 	struct stat	 st;
503 	char		 src[PATH_MAX];
504 	char		 dst[PATH_MAX];
505 	char		*p = NULL;
506 	int		 len;
507 
508 	len = snprintf(src, sizeof(src), "%s/ca.crt", ca->sslpath);
509 	if (len < 0 || (size_t)len >= sizeof(src))
510 		err(1, "%s: snprintf", __func__);
511 	if (stat(src, &st) == -1) {
512 		printf("CA '%s' does not exist\n", ca->caname);
513 		return (1);
514 	}
515 
516 	if (dir == NULL)
517 		p = dir = strdup(KEYBASE);
518 
519 	ca_hier(dir);
520 
521 	len = snprintf(dst, sizeof(dst), "%s/ca/ca.crt", dir);
522 	if (len < 0 || (size_t)len >= sizeof(dst))
523 		err(1, "%s: snprintf", __func__);
524 	if (fcopy(src, dst, 0644) == 0)
525 		printf("certificate for CA '%s' installed into %s\n",
526 		    ca->caname, dst);
527 
528 	len = snprintf(src, sizeof(src), "%s/ca.crl", ca->sslpath);
529 	if (len < 0 || (size_t)len >= sizeof(src))
530 		err(1, "%s: snprintf", __func__);
531 	if (stat(src, &st) == 0) {
532 		len = snprintf(dst, sizeof(dst), "%s/crls/ca.crl", dir);
533 		if (len < 0 || (size_t)len >= sizeof(dst))
534 			err(1, "%s: snprintf", __func__);
535 		if (fcopy(src, dst, 0644) == 0)
536 			printf("CRL for CA '%s' installed to %s\n",
537 			    ca->caname, dst);
538 	}
539 
540 	free(p);
541 
542 	return (0);
543 }
544 
545 int
ca_show_certs(struct ca * ca,char * name)546 ca_show_certs(struct ca *ca, char *name)
547 {
548 	DIR		*dir;
549 	struct dirent	*de;
550 	char		 path[PATH_MAX];
551 	char		*p;
552 	struct stat	 st;
553 	int		 len;
554 
555 	if (name != NULL) {
556 		len = snprintf(path, sizeof(path), "%s/%s.crt",
557 		    ca->sslpath, name);
558 		if (len < 0 || (size_t)len >= sizeof(path))
559 			err(1, "%s: snprintf", __func__);
560 		if (stat(path, &st) != 0)
561 			err(1, "could not open file %s.crt", name);
562 		char *cmd[] = { PATH_OPENSSL, "x509", "-text",
563 		    "-in", path, NULL };
564 		ca_execv(cmd);
565 		printf("\n");
566 		return (0);
567 	}
568 
569 	if ((dir = opendir(ca->sslpath)) == NULL)
570 		err(1, "could not open directory %s", ca->sslpath);
571 
572 	while ((de = readdir(dir)) != NULL) {
573 		if (de->d_namlen > 4) {
574 			p = de->d_name + de->d_namlen - 4;
575 			if (strcmp(".crt", p) != 0)
576 				continue;
577 			len = snprintf(path, sizeof(path), "%s/%s", ca->sslpath,
578 			    de->d_name);
579 			if (len < 0 || (size_t)len >= sizeof(path))
580 				err(1, "%s: snprintf", __func__);
581 			char *cmd[] = { PATH_OPENSSL, "x509", "-subject",
582 			    "-fingerprint", "-dates", "-noout", "-in", path,
583 			    NULL };
584 			ca_execv(cmd);
585 			printf("\n");
586 		}
587 	}
588 
589 	closedir(dir);
590 
591 	return (0);
592 }
593 
594 int
fcopy(char * src,char * dst,mode_t mode)595 fcopy(char *src, char *dst, mode_t mode)
596 {
597 	int		ifd, ofd;
598 	uint8_t		buf[BUFSIZ];
599 	ssize_t		r;
600 
601 	if ((ifd = open(src, O_RDONLY)) == -1)
602 		err(1, "open %s", src);
603 
604 	if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) {
605 		int saved_errno = errno;
606 		close(ifd);
607 		errc(1, saved_errno, "open %s", dst);
608 	}
609 
610 	while ((r = read(ifd, buf, sizeof(buf))) > 0) {
611 		if (write(ofd, buf, r) == -1)
612 			err(1, "%s: write", __func__);
613 	}
614 
615 	close(ofd);
616 	close(ifd);
617 
618 	return (r == -1);
619 }
620 
621 void
fcopy_env(const char * src,const char * dst,mode_t mode)622 fcopy_env(const char *src, const char *dst, mode_t mode)
623 {
624 	int		 ofd = -1, i;
625 	uint8_t		 buf[BUFSIZ];
626 	ssize_t		 r = -1, len;
627 	FILE		*ifp = NULL;
628 	int		 saved_errno;
629 
630 	if ((ifp = fopen(src, "r")) == NULL)
631 		err(1, "fopen %s", src);
632 
633 	if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1)
634 		goto done;
635 
636 	while (fgets(buf, sizeof(buf), ifp) != NULL) {
637 		for (i = 0; ca_env[i][0] != NULL; i++) {
638 			if (ca_env[i][1] == NULL)
639 				continue;
640 			if (expand_string(buf, sizeof(buf),
641 			    ca_env[i][0], ca_env[i][1]) == -1)
642 				errx(1, "env %s value too long", ca_env[i][0]);
643 		}
644 		len = strlen(buf);
645 		if (write(ofd, buf, len) != len)
646 			goto done;
647 	}
648 
649 	r = 0;
650 
651  done:
652 	saved_errno = errno;
653 	close(ofd);
654 	if (ifp != NULL)
655 		fclose(ifp);
656 	if (r == -1)
657 		errc(1, saved_errno, "open %s", dst);
658 }
659 
660 int
rm_dir(char * path)661 rm_dir(char *path)
662 {
663 	FTS		*fts;
664 	FTSENT		*p;
665 	static char	*fpath[] = { NULL, NULL };
666 
667 	fpath[0] = path;
668 	if ((fts = fts_open(fpath, FTS_PHYSICAL, NULL)) == NULL) {
669 		warn("fts_open %s", path);
670 		return (1);
671 	}
672 
673 	while ((p = fts_read(fts)) != NULL) {
674 		switch (p->fts_info) {
675 		case FTS_DP:
676 		case FTS_DNR:
677 			if (rmdir(p->fts_accpath) == -1)
678 				warn("rmdir %s", p->fts_accpath);
679 			break;
680 		case FTS_F:
681 			if (unlink(p->fts_accpath) == -1)
682 				warn("unlink %s", p->fts_accpath);
683 			break;
684 		case FTS_D:
685 		case FTS_DOT:
686 		default:
687 			continue;
688 		}
689 	}
690 	fts_close(fts);
691 
692 	return (0);
693 }
694 
695 void
ca_hier(char * path)696 ca_hier(char *path)
697 {
698 	struct stat	 st;
699 	char		 dst[PATH_MAX];
700 	unsigned int	 i;
701 
702 	for (i = 0; i < nitems(hier); i++) {
703 		strlcpy(dst, path, sizeof(dst));
704 		strlcat(dst, hier[i].dir, sizeof(dst));
705 		if (stat(dst, &st) != 0 && errno == ENOENT &&
706 		    mkdir(dst, hier[i].mode) != 0)
707 			err(1, "failed to create dir %s", dst);
708 	}
709 }
710 
711 int
ca_export(struct ca * ca,char * keyname,char * myname,char * password)712 ca_export(struct ca *ca, char *keyname, char *myname, char *password)
713 {
714 	DIR		*dexp;
715 	struct dirent	*de;
716 	struct stat	 st;
717 	char		*pass;
718 	char		 prev[_PASSWORD_LEN + 1];
719 	char		 passenv[_PASSWORD_LEN + 8];
720 	char		 oname[PATH_MAX];
721 	char		 src[PATH_MAX];
722 	char		 dst[PATH_MAX];
723 	char		 cacrt[PATH_MAX];
724 	char		 capfx[PATH_MAX];
725 	char		 key[PATH_MAX];
726 	char		 crt[PATH_MAX];
727 	char		 pfx[PATH_MAX];
728 	char		*p;
729 	char		 tpl[] = "/tmp/ikectl.XXXXXXXXXX";
730 	unsigned int	 i;
731 	int		 fd;
732 	int		 len;
733 
734 	if (keyname != NULL) {
735 		if (strlcpy(oname, keyname, sizeof(oname)) >= sizeof(oname))
736 			errx(1, "name too long");
737 	} else {
738 		strlcpy(oname, "ca", sizeof(oname));
739 	}
740 
741 	/* colons are not valid characters in windows filenames... */
742 	while ((p = strchr(oname, ':')) != NULL)
743 		*p = '_';
744 
745 	if (password != NULL)
746 		pass = password;
747 	else {
748 		pass = getpass("Export passphrase:");
749 		if (pass == NULL || *pass == '\0')
750 			err(1, "password not set");
751 
752 		strlcpy(prev, pass, sizeof(prev));
753 		pass = getpass("Retype export passphrase:");
754 		if (pass == NULL || strcmp(prev, pass) != 0)
755 			errx(1, "passphrase does not match!");
756 	}
757 
758 	len = snprintf(cacrt, sizeof(cacrt), "%s/ca.crt", ca->sslpath);
759 	if (len < 0 || (size_t)len >= sizeof(cacrt))
760 		err(1, "%s: snprintf", __func__);
761 	len = snprintf(capfx, sizeof(capfx), "%s/ca.pfx", ca->sslpath);
762 	if (len < 0 || (size_t)len >= sizeof(capfx))
763 		err(1, "%s: snprintf", __func__);
764 	len = snprintf(key, sizeof(key), "%s/private/%s.key", ca->sslpath, keyname);
765 	if (len < 0 || (size_t)len >= sizeof(key))
766 		err(1, "%s: snprintf", __func__);
767 	len = snprintf(crt, sizeof(crt), "%s/%s.crt", ca->sslpath, keyname);
768 	if (len < 0 || (size_t)len >= sizeof(crt))
769 		err(1, "%s: snprintf", __func__);
770 	len = snprintf(pfx, sizeof(pfx), "%s/private/%s.pfx", ca->sslpath, oname);
771 	if (len < 0 || (size_t)len >= sizeof(pfx))
772 		err(1, "%s: snprintf", __func__);
773 
774 	len = snprintf(passenv, sizeof(passenv), "EXPASS=%s", pass);
775 	if (len < 0 || (size_t)len >= sizeof(passenv))
776 		err(1, "%s: snprintf", __func__);
777 	putenv(passenv);
778 
779 	if (keyname != NULL) {
780 		char *cmd[] = { PATH_OPENSSL, "pkcs12", "-export",
781 		    "-name", keyname, "-CAfile", cacrt, "-inkey", key,
782 		    "-in", crt, "-out", pfx, "-passout", "env:EXPASS",
783 		    "-passin", ca->passfile, NULL };
784 		ca_execv(cmd);
785 	}
786 
787 	char *pkcscmd[] = { PATH_OPENSSL, "pkcs12", "-export",
788 	    "-caname", ca->caname, "-name", ca->caname, "-cacerts",
789 	    "-nokeys", "-in", cacrt, "-out", capfx,
790 	    "-passout", "env:EXPASS", "-passin", ca->passfile, NULL };
791 	ca_execv(pkcscmd);
792 
793 	unsetenv("EXPASS");
794 	explicit_bzero(passenv, sizeof(passenv));
795 
796 	if ((p = mkdtemp(tpl)) == NULL)
797 		err(1, "could not create temp dir");
798 
799 	chmod(p, 0755);
800 
801 	for (i = 0; i < nitems(hier); i++) {
802 		strlcpy(dst, p, sizeof(dst));
803 		strlcat(dst, hier[i].dir, sizeof(dst));
804 		if (stat(dst, &st) != 0 && errno == ENOENT &&
805 		    mkdir(dst, hier[i].mode) != 0)
806 			err(1, "failed to create dir %s", dst);
807 	}
808 
809 	/* create a file with the address of the peer to connect to */
810 	if (myname != NULL) {
811 		len = snprintf(dst, sizeof(dst), "%s/export/peer.txt", p);
812 		if (len < 0 || (size_t)len >= sizeof(dst))
813 			err(1, "%s: snprintf", __func__);
814 		if ((fd = open(dst, O_WRONLY|O_CREAT, 0644)) == -1)
815 			err(1, "open %s", dst);
816 		if (write(fd, myname, strlen(myname)) == -1)
817 			err(1, "%s: write", __func__);
818 		close(fd);
819 	}
820 
821 	len = snprintf(src, sizeof(src), "%s/ca.pfx", ca->sslpath);
822 	if (len < 0 || (size_t)len >= sizeof(src))
823 		err(1, "%s: snprintf", __func__);
824 	len = snprintf(dst, sizeof(dst), "%s/export/ca.pfx", p);
825 	if (len < 0 || (size_t)len >= sizeof(dst))
826 		err(1, "%s: snprintf", __func__);
827 	fcopy(src, dst, 0644);
828 
829 	len = snprintf(src, sizeof(src), "%s/ca.crt", ca->sslpath);
830 	if (len < 0 || (size_t)len >= sizeof(src))
831 		err(1, "%s: snprintf", __func__);
832 	len = snprintf(dst, sizeof(dst), "%s/ca/ca.crt", p);
833 	if (len < 0 || (size_t)len >= sizeof(dst))
834 		err(1, "%s: snprintf", __func__);
835 	fcopy(src, dst, 0644);
836 
837 	len = snprintf(src, sizeof(src), "%s/ca.crl", ca->sslpath);
838 	if (len < 0 || (size_t)len >= sizeof(src))
839 		err(1, "%s: snprintf", __func__);
840 	if (stat(src, &st) == 0) {
841 		len = snprintf(dst, sizeof(dst), "%s/crls/ca.crl", p);
842 		if (len < 0 || (size_t)len >= sizeof(dst))
843 			err(1, "%s: snprintf", __func__);
844 		fcopy(src, dst, 0644);
845 	}
846 
847 	if (keyname != NULL) {
848 		len = snprintf(src, sizeof(src), "%s/private/%s.pfx",
849 		    ca->sslpath, oname);
850 		if (len < 0 || (size_t)len >= sizeof(src))
851 			err(1, "%s: snprintf", __func__);
852 		len = snprintf(dst, sizeof(dst), "%s/export/%s.pfx", p, oname);
853 		if (len < 0 || (size_t)len >= sizeof(dst))
854 			err(1, "%s: snprintf", __func__);
855 		fcopy(src, dst, 0644);
856 
857 		len = snprintf(src, sizeof(src), "%s/private/%s.key",
858 		    ca->sslpath, keyname);
859 		if (len < 0 || (size_t)len >= sizeof(src))
860 			err(1, "%s: snprintf", __func__);
861 		len = snprintf(dst, sizeof(dst), "%s/private/%s.key", p, keyname);
862 		if (len < 0 || (size_t)len >= sizeof(dst))
863 			err(1, "%s: snprintf", __func__);
864 		fcopy(src, dst, 0600);
865 		len = snprintf(dst, sizeof(dst), "%s/private/local.key", p);
866 		if (len < 0 || (size_t)len >= sizeof(dst))
867 			err(1, "%s: snprintf", __func__);
868 		fcopy(src, dst, 0600);
869 
870 		len = snprintf(src, sizeof(src), "%s/%s.crt", ca->sslpath,
871 		    keyname);
872 		if (len < 0 || (size_t)len >= sizeof(src))
873 			err(1, "%s: snprintf", __func__);
874 		len = snprintf(dst, sizeof(dst), "%s/certs/%s.crt", p, keyname);
875 		if (len < 0 || (size_t)len >= sizeof(dst))
876 			err(1, "%s: snprintf", __func__);
877 		fcopy(src, dst, 0644);
878 
879 		len = snprintf(dst, sizeof(dst), "%s/local.pub", p);
880 		if (len < 0 || (size_t)len >= sizeof(dst))
881 			err(1, "%s: snprintf", __func__);
882 		char *cmd[] = { PATH_OPENSSL, "rsa", "-out", dst, "-in", key,
883 		    "-pubout", NULL };
884 		ca_execv(cmd);
885 	}
886 
887 	if (stat(PATH_TAR, &st) == 0) {
888 		len = snprintf(src, sizeof(src), "%s.tgz", oname);
889 		if (len < 0 || (size_t)len >= sizeof(src))
890 			err(1, "%s: snprintf", __func__);
891 		if (keyname == NULL) {
892 			char *cmd[] = { PATH_TAR, "-zcf", src,
893 			    "-C", ca->sslpath, ".", NULL };
894 			ca_execv(cmd);
895 		} else {
896 			char *cmd[] = { PATH_TAR, "-zcf", src, "-C", p, ".",
897 			    NULL };
898 			ca_execv(cmd);
899 		}
900 		if (realpath(src, dst) != NULL)
901 			printf("exported files in %s\n", dst);
902 	}
903 
904 	if (stat(PATH_ZIP, &st) == 0) {
905 		dexp = opendir(EXPDIR);
906 		if (dexp) {
907 			while ((de = readdir(dexp)) != NULL) {
908 				if (!strcmp(de->d_name, ".") ||
909 				    !strcmp(de->d_name, ".."))
910 					continue;
911 				len = snprintf(src, sizeof(src), "%s/%s",
912 				    EXPDIR, de->d_name);
913 				if (len < 0 || (size_t)len >= sizeof(src))
914 					err(1, "%s: snprintf", __func__);
915 				len = snprintf(dst, sizeof(dst), "%s/export/%s",
916 				    p, de->d_name);
917 				if (len < 0 || (size_t)len >= sizeof(dst))
918 					err(1, "%s: snprintf", __func__);
919 				fcopy(src, dst, 0644);
920 			}
921 			closedir(dexp);
922 		}
923 
924 		len = snprintf(dst, sizeof(dst), "%s/export", p);
925 		if (len < 0 || (size_t)len >= sizeof(dst))
926 			err(1, "%s: snprintf", __func__);
927 		if (getcwd(src, sizeof(src)) == NULL)
928 			err(1, "could not get cwd");
929 
930 		if (chdir(dst) == -1)
931 			err(1, "could not change %s", dst);
932 
933 		len = snprintf(dst, sizeof(dst), "%s/%s.zip", src, oname);
934 		if (len < 0 || (size_t)len >= sizeof(dst))
935 			err(1, "%s: snprintf", __func__);
936 		char *cmd[] = { PATH_ZIP, "-qr", dst, ".", NULL };
937 		ca_execv(cmd);
938 		printf("exported files in %s\n", dst);
939 
940 		if (chdir(src) == -1)
941 			err(1, "could not change %s", dst);
942 	}
943 
944 	rm_dir(p);
945 
946 	return (0);
947 }
948 
949 /* create index if it doesn't already exist */
950 void
ca_create_index(struct ca * ca)951 ca_create_index(struct ca *ca)
952 {
953 	struct stat	 st;
954 	int		 fd;
955 	int		 len;
956 
957 	len = snprintf(ca->index, sizeof(ca->index), "%s/index.txt",
958 	    ca->sslpath);
959 	if (len < 0 || (size_t)len >= sizeof(ca->index))
960 		err(1, "%s: snprintf", __func__);
961 	if (stat(ca->index, &st) != 0) {
962 		if  (errno == ENOENT) {
963 			if ((fd = open(ca->index, O_WRONLY | O_CREAT, 0644))
964 			    == -1)
965 				err(1, "could not create file %s", ca->index);
966 			close(fd);
967 		} else
968 			err(1, "could not access %s", ca->index);
969 	}
970 
971 	len = snprintf(ca->serial, sizeof(ca->serial), "%s/serial.txt",
972 	    ca->sslpath);
973 	if (len < 0 || (size_t)len >= sizeof(ca->serial))
974 		err(1, "%s: snprintf", __func__);
975 	if (stat(ca->serial, &st) != 0) {
976 		if  (errno == ENOENT) {
977 			if ((fd = open(ca->serial, O_WRONLY | O_CREAT, 0644))
978 			    == -1)
979 				err(1, "could not create file %s", ca->serial);
980 			/* serial file must be created with a number */
981 			if (write(fd, "01\n", 3) != 3)
982 				err(1, "write %s", ca->serial);
983 			close(fd);
984 		} else
985 			err(1, "could not access %s", ca->serial);
986 	}
987 }
988 
989 int
ca_revoke(struct ca * ca,char * keyname)990 ca_revoke(struct ca *ca, char *keyname)
991 {
992 	struct stat	 st;
993 	char		 path[PATH_MAX];
994 	char		 cakey[PATH_MAX];
995 	char		 cacrt[PATH_MAX];
996 	size_t		 len;
997 
998 	if (keyname) {
999 		len = snprintf(path, sizeof(path), "%s/%s.crt",
1000 		    ca->sslpath, keyname);
1001 		if (len < 0 || (size_t)len >= sizeof(path))
1002 			err(1, "%s: snprintf", __func__);
1003 		if (stat(path, &st) != 0) {
1004 			warn("Problem with certificate for '%s'", keyname);
1005 			return (1);
1006 		}
1007 	}
1008 
1009 	ca_create_index(ca);
1010 
1011 	ca_setenv("$ENV::CADB", ca->index);
1012 	ca_setenv("$ENV::CASERIAL", ca->serial);
1013 	if (keyname)
1014 		ca_setenv("$ENV::REQ_EXT", "");
1015 
1016 	ca_setcnf(ca, "ca-revoke");
1017 
1018 	len = snprintf(cakey, sizeof(cakey), "%s/private/ca.key", ca->sslpath);
1019 	if (len < 0 || (size_t)len >= sizeof(cakey))
1020 		err(1, "%s: snprintf", __func__);
1021 	len = snprintf(cacrt, sizeof(cacrt), "%s/ca.crt", ca->sslpath);
1022 	if (len < 0 || (size_t)len >= sizeof(cacrt))
1023 		err(1, "%s: snprintf", __func__);
1024 
1025 	if (keyname) {
1026 		char *cmd[] = { PATH_OPENSSL, "ca", "-config", ca->sslcnf,
1027 		    "-keyfile", cakey, "-passin", ca->passfile, "-cert", cacrt,
1028 		    "-revoke", path, ca->batch, NULL };
1029 		ca_execv(cmd);
1030 	}
1031 
1032 	len = snprintf(path, sizeof(path), "%s/ca.crl", ca->sslpath);
1033 	if (len < 0 || (size_t)len >= sizeof(path))
1034 		err(1, "%s: snprintf", __func__);
1035 	char *cmd[] = { PATH_OPENSSL, "ca", "-config", ca->sslcnf,
1036 	    "-keyfile", cakey, "-passin", ca->passfile, "-gencrl",
1037 	    "-cert", cacrt, "-crldays", "365", "-out", path, ca->batch, NULL };
1038 	ca_execv(cmd);
1039 
1040 	return (0);
1041 }
1042 
1043 void
ca_clrenv(void)1044 ca_clrenv(void)
1045 {
1046 	int	 i;
1047 	for (i = 0; ca_env[i][0] != NULL; i++) {
1048 		free(ca_env[i][1]);
1049 		ca_env[i][1] = NULL;
1050 	}
1051 }
1052 
1053 void
ca_setenv(const char * key,const char * value)1054 ca_setenv(const char *key, const char *value)
1055 {
1056 	int	 i;
1057 	char	*p = NULL;
1058 
1059 	for (i = 0; ca_env[i][0] != NULL; i++) {
1060 		if (strcmp(ca_env[i][0], key) == 0) {
1061 			if (ca_env[i][1] != NULL)
1062 				errx(1, "env %s already set: %s", key, value);
1063 			p = strdup(value);
1064 			if (p == NULL)
1065 				err(1, NULL);
1066 			ca_env[i][1] = p;
1067 			return;
1068 		}
1069 	}
1070 	errx(1, "env %s invalid", key);
1071 }
1072 
1073 void
ca_setcnf(struct ca * ca,const char * keyname)1074 ca_setcnf(struct ca *ca, const char *keyname)
1075 {
1076 	struct stat	 st;
1077 	const char	*extcnf, *sslcnf;
1078 	int		 len;
1079 
1080 	if (stat(IKECA_CNF, &st) == 0) {
1081 		extcnf = IKECA_CNF;
1082 		sslcnf = IKECA_CNF;
1083 	} else {
1084 		extcnf = X509_CNF;
1085 		sslcnf = SSL_CNF;
1086 	}
1087 
1088 	len = snprintf(ca->extcnf, sizeof(ca->extcnf), "%s/%s-ext.cnf",
1089 	    ca->sslpath, keyname);
1090 	if (len < 0 || (size_t)len >= sizeof(ca->extcnf))
1091 		err(1, "%s: snprintf", __func__);
1092 	len = snprintf(ca->sslcnf, sizeof(ca->sslcnf), "%s/%s-ssl.cnf",
1093 	    ca->sslpath, keyname);
1094 	if (len < 0 || (size_t)len >= sizeof(ca->sslcnf))
1095 		err(1, "%s: snprintf", __func__);
1096 
1097 	fcopy_env(extcnf, ca->extcnf, 0400);
1098 	fcopy_env(sslcnf, ca->sslcnf, 0400);
1099 }
1100 
1101 struct ca *
ca_setup(char * caname,int create,int quiet,char * pass)1102 ca_setup(char *caname, int create, int quiet, char *pass)
1103 {
1104 	struct stat	 st;
1105 	struct ca	*ca;
1106 	char		 path[PATH_MAX];
1107 	int		 len;
1108 
1109 	if (stat(PATH_OPENSSL, &st) == -1)
1110 		err(1, "openssl binary not available");
1111 
1112 	if ((ca = calloc(1, sizeof(struct ca))) == NULL)
1113 		err(1, "calloc");
1114 
1115 	ca->caname = strdup(caname);
1116 	len = snprintf(ca->sslpath, sizeof(ca->sslpath), SSLDIR "/%s", caname);
1117 	if (len < 0 || (size_t)len >= sizeof(ca->sslpath))
1118 		err(1, "%s: snprintf", __func__);
1119 
1120 	if (quiet)
1121 		ca->batch = "-batch";
1122 
1123 	if (create == 0 && stat(ca->sslpath, &st) == -1) {
1124 		free(ca->caname);
1125 		free(ca);
1126 		errx(1, "CA '%s' does not exist", caname);
1127 	}
1128 
1129 	strlcpy(path, ca->sslpath, sizeof(path));
1130 	if (mkdir(path, 0777) == -1 && errno != EEXIST)
1131 		err(1, "failed to create dir %s", path);
1132 	strlcat(path, "/private", sizeof(path));
1133 	if (mkdir(path, 0700) == -1 && errno != EEXIST)
1134 		err(1, "failed to create dir %s", path);
1135 
1136 	len = snprintf(path, sizeof(path), "%s/ikeca.passwd", ca->sslpath);
1137 	if (len < 0 || (size_t)len >= sizeof(path))
1138 		err(1, "%s: snprintf", __func__);
1139 	if (create && stat(path, &st) == -1 && errno == ENOENT)
1140 		ca_newpass(path, pass);
1141 	len = snprintf(ca->passfile, sizeof(ca->passfile), "file:%s", path);
1142 	if (len < 0 || (size_t)len >= sizeof(ca->passfile))
1143 		err(1, "%s: snprintf", __func__);
1144 
1145 	return (ca);
1146 }
1147 
1148 int static
ca_execv(char * const argv[])1149 ca_execv(char *const argv[])
1150 {
1151 	pid_t pid, cpid;
1152 	int status;
1153 
1154 	switch (cpid = fork()) {
1155 	case -1:
1156 		return -1;
1157 	case 0:
1158 		execv(argv[0], argv);
1159 		_exit(127);
1160 	}
1161 
1162 	do {
1163 		pid = waitpid(cpid, &status, 0);
1164 	} while (pid == -1 && errno == EINTR);
1165 
1166 	return (pid == -1 ? -1 : WEXITSTATUS(status));
1167 }
1168