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 65struct 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 76struct { 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 */ 89char *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 109int ca_sign(struct ca *, char *, int); 110int ca_request(struct ca *, char *, int); 111void ca_newpass(char *, char *); 112int fcopy(char *, char *, mode_t); 113void fcopy_env(const char *, const char *, mode_t); 114int rm_dir(char *); 115void ca_hier(char *); 116void ca_setenv(const char *, const char *); 117void ca_clrenv(void); 118void ca_setcnf(struct ca *, const char *); 119void ca_create_index(struct ca *); 120int static ca_execv(char *const []); 121 122/* util.c */ 123int expand_string(char *, size_t, const char *, const char *); 124 125int 126ca_delete(struct ca *ca) 127{ 128 return (rm_dir(ca->sslpath)); 129} 130 131int 132ca_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 155int 156ca_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 176int 177ca_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 191int 192ca_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 220int 221ca_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 265int 266ca_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 311int 312ca_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 345int 346ca_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 389int 390ca_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 421void 422ca_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 452int 453ca_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 499int 500ca_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 545int 546ca_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 594int 595fcopy(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 621void 622fcopy_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 660int 661rm_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 695void 696ca_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 711int 712ca_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 */ 950void 951ca_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 989int 990ca_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 1043void 1044ca_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 1053void 1054ca_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 1073void 1074ca_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 1101struct ca * 1102ca_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 1148int static 1149ca_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