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