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