1 /* $OpenBSD: ikeca.c,v 1.26 2014/04/18 21:29:20 tedu 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/param.h> 20 #include <sys/types.h> 21 #include <sys/stat.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 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/sbin/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 sslcnf[PATH_MAX]; 68 char extcnf[PATH_MAX]; 69 char batch[PATH_MAX]; 70 char *caname; 71 }; 72 73 struct { 74 char *dir; 75 mode_t mode; 76 } hier[] = { 77 { "", 0755 }, 78 { "/ca", 0755 }, 79 { "/certs", 0755 }, 80 { "/crls", 0755 }, 81 { "/export", 0755 }, 82 { "/private", 0700 } 83 }; 84 85 int ca_sign(struct ca *, char *, int, char *); 86 int ca_request(struct ca *, char *); 87 int ca_newpass(char *, char *); 88 char * ca_readpass(char *, size_t *); 89 int fcopy(char *, char *, mode_t); 90 int rm_dir(char *); 91 int ca_hier(char *); 92 93 int 94 ca_delete(struct ca *ca) 95 { 96 return (rm_dir(ca->sslpath)); 97 } 98 99 int 100 ca_key_create(struct ca *ca, char *keyname) 101 { 102 struct stat st; 103 char cmd[PATH_MAX * 2]; 104 char path[PATH_MAX]; 105 106 snprintf(path, sizeof(path), "%s/private/%s.key", ca->sslpath, keyname); 107 108 /* don't recreate key if one is already present */ 109 if (stat(path, &st) == 0) { 110 return (0); 111 } 112 113 snprintf(cmd, sizeof(cmd), 114 "%s genrsa -out %s 2048", 115 PATH_OPENSSL, path); 116 system(cmd); 117 chmod(path, 0600); 118 119 return (0); 120 } 121 122 int 123 ca_key_import(struct ca *ca, char *keyname, char *import) 124 { 125 struct stat st; 126 char dst[PATH_MAX]; 127 128 if (stat(import, &st) != 0) { 129 warn("could not access keyfile %s", import); 130 return (1); 131 } 132 133 snprintf(dst, sizeof(dst), "%s/private/%s.key", ca->sslpath, keyname); 134 fcopy(import, dst, 0600); 135 136 return (0); 137 } 138 139 int 140 ca_key_delete(struct ca *ca, char *keyname) 141 { 142 char path[PATH_MAX]; 143 144 snprintf(path, sizeof(path), "%s/private/%s.key", ca->sslpath, keyname); 145 unlink(path); 146 147 return (0); 148 } 149 150 int 151 ca_delkey(struct ca *ca, char *keyname) 152 { 153 char file[PATH_MAX]; 154 155 snprintf(file, sizeof(file), "%s/%s.crt", ca->sslpath, keyname); 156 unlink(file); 157 158 snprintf(file, sizeof(file), "%s/private/%s.key", ca->sslpath, keyname); 159 unlink(file); 160 161 snprintf(file, sizeof(file), "%s/private/%s.csr", ca->sslpath, keyname); 162 unlink(file); 163 164 snprintf(file, sizeof(file), "%s/private/%s.pfx", ca->sslpath, keyname); 165 unlink(file); 166 167 return (0); 168 } 169 170 int 171 ca_request(struct ca *ca, char *keyname) 172 { 173 char cmd[PATH_MAX * 2]; 174 char path[PATH_MAX]; 175 176 snprintf(path, sizeof(path), "%s/private/%s.csr", ca->sslpath, keyname); 177 snprintf(cmd, sizeof(cmd), "env CERT_CN=%s %s req %s-new" 178 " -key %s/private/%s.key -out %s -config %s", 179 keyname, PATH_OPENSSL, ca->batch, ca->sslpath, keyname, 180 path, ca->sslcnf); 181 182 system(cmd); 183 chmod(path, 0600); 184 185 return (0); 186 } 187 188 int 189 ca_sign(struct ca *ca, char *keyname, int type, char *envargs) 190 { 191 char cmd[PATH_MAX * 2]; 192 char hostname[MAXHOSTNAMELEN]; 193 char name[128]; 194 195 strlcpy(name, keyname, sizeof(name)); 196 197 if (envargs == NULL) 198 envargs = ""; 199 200 if (type == HOST_IPADDR) { 201 snprintf(cmd, sizeof(cmd), "env CERTIP=%s%s %s x509 -req" 202 " -days 365 -in %s/private/%s.csr" 203 " -CA %s/ca.crt -CAkey %s/private/ca.key -CAcreateserial" 204 " -extfile %s -extensions x509v3_IPAddr -out %s/%s.crt" 205 " -passin file:%s", name, envargs, PATH_OPENSSL, 206 ca->sslpath, keyname, ca->sslpath, ca->sslpath, 207 ca->extcnf, ca->sslpath, keyname, ca->passfile); 208 } else if (type == HOST_FQDN) { 209 if (!strcmp(keyname, "local")) { 210 if (gethostname(hostname, sizeof(hostname))) 211 err(1, "gethostname"); 212 strlcpy(name, hostname, sizeof(name)); 213 } 214 snprintf(cmd, sizeof(cmd), "env CERTFQDN=%s%s %s x509 -req" 215 " -days 365 -in %s/private/%s.csr" 216 " -CA %s/ca.crt -CAkey %s/private/ca.key -CAcreateserial" 217 " -extfile %s -extensions x509v3_FQDN -out %s/%s.crt" 218 " -passin file:%s", name, envargs, PATH_OPENSSL, 219 ca->sslpath, keyname, ca->sslpath, ca->sslpath, 220 ca->extcnf, ca->sslpath, keyname, ca->passfile); 221 } else 222 err(1, "unknown host type %d", type); 223 224 system(cmd); 225 226 return (0); 227 } 228 229 int 230 ca_certificate(struct ca *ca, char *keyname, int type, int action) 231 { 232 char *envargs = ""; 233 234 switch (action) { 235 case CA_SERVER: 236 envargs = " EXTCERTUSAGE=serverAuth NSCERTTYPE=server" 237 " CERTUSAGE=digitalSignature,keyEncipherment"; 238 break; 239 case CA_CLIENT: 240 envargs = " EXTCERTUSAGE=clientAuth NSCERTTYPE=client" 241 " CERTUSAGE=digitalSignature,keyAgreement"; 242 break; 243 default: 244 break; 245 } 246 247 ca_key_create(ca, keyname); 248 ca_request(ca, keyname); 249 ca_sign(ca, keyname, type, envargs); 250 251 return (0); 252 } 253 254 int 255 ca_key_install(struct ca *ca, char *keyname, char *dir) 256 { 257 struct stat st; 258 char cmd[PATH_MAX * 2]; 259 char src[PATH_MAX]; 260 char dst[PATH_MAX]; 261 char *p = NULL; 262 263 snprintf(src, sizeof(src), "%s/private/%s.key", ca->sslpath, keyname); 264 if (stat(src, &st) == -1) { 265 if (errno == ENOENT) 266 printf("key for '%s' does not exist\n", ca->caname); 267 else 268 warn("could not access key"); 269 return (1); 270 } 271 272 if (dir == NULL) 273 p = dir = strdup(KEYBASE); 274 275 ca_hier(dir); 276 277 snprintf(dst, sizeof(dst), "%s/private/local.key", dir); 278 fcopy(src, dst, 0600); 279 280 snprintf(cmd, sizeof(cmd), "%s rsa -out %s/local.pub" 281 " -in %s/private/local.key -pubout", PATH_OPENSSL, dir, dir); 282 system(cmd); 283 284 free(p); 285 286 return (0); 287 } 288 289 int 290 ca_cert_install(struct ca *ca, char *keyname, char *dir) 291 { 292 char src[PATH_MAX]; 293 char dst[PATH_MAX]; 294 int r; 295 char *p = NULL; 296 297 if (dir == NULL) 298 p = dir = strdup(KEYBASE); 299 300 ca_hier(dir); 301 302 if ((r = ca_key_install(ca, keyname, dir)) != 0) { 303 free(dir); 304 return (r); 305 } 306 307 snprintf(src, sizeof(src), "%s/%s.crt", ca->sslpath, keyname); 308 snprintf(dst, sizeof(dst), "%s/certs/%s.crt", dir, keyname); 309 fcopy(src, dst, 0644); 310 311 free(p); 312 313 return (0); 314 } 315 316 int 317 ca_newpass(char *passfile, char *password) 318 { 319 FILE *f; 320 char *pass; 321 char prev[_PASSWORD_LEN + 1]; 322 323 if (password != NULL) { 324 pass = password; 325 goto done; 326 } 327 328 pass = getpass("CA passphrase:"); 329 if (pass == NULL || *pass == '\0') 330 err(1, "password not set"); 331 332 strlcpy(prev, pass, sizeof(prev)); 333 pass = getpass("Retype CA passphrase:"); 334 if (pass == NULL || strcmp(prev, pass) != 0) 335 errx(1, "passphrase does not match!"); 336 337 done: 338 if ((f = fopen(passfile, "wb")) == NULL) 339 err(1, "could not open passfile %s", passfile); 340 chmod(passfile, 0600); 341 342 fprintf(f, "%s\n%s\n", pass, pass); 343 344 fclose(f); 345 346 return (0); 347 } 348 349 int 350 ca_create(struct ca *ca) 351 { 352 char cmd[PATH_MAX * 2]; 353 char path[PATH_MAX]; 354 355 snprintf(path, sizeof(path), "%s/private/ca.key", ca->sslpath); 356 snprintf(cmd, sizeof(cmd), "%s genrsa -aes256 -out" 357 " %s -passout file:%s 2048", PATH_OPENSSL, 358 path, ca->passfile); 359 system(cmd); 360 chmod(path, 0600); 361 362 snprintf(path, sizeof(path), "%s/private/ca.csr", ca->sslpath); 363 snprintf(cmd, sizeof(cmd), "env CERT_CN='VPN CA' %s req %s-new" 364 " -key %s/private/ca.key" 365 " -config %s -out %s -passin file:%s", PATH_OPENSSL, 366 ca->batch, ca->sslpath, ca->sslcnf, path, ca->passfile); 367 system(cmd); 368 chmod(path, 0600); 369 370 snprintf(cmd, sizeof(cmd), "%s x509 -req -days 365" 371 " -in %s/private/ca.csr -signkey %s/private/ca.key" 372 " -extfile %s -extensions x509v3_CA -out %s/ca.crt -passin file:%s", 373 PATH_OPENSSL, ca->sslpath, ca->sslpath, ca->extcnf, ca->sslpath, 374 ca->passfile); 375 system(cmd); 376 377 /* Create the CRL revocation list */ 378 ca_revoke(ca, NULL); 379 380 return (0); 381 } 382 383 int 384 ca_install(struct ca *ca, char *dir) 385 { 386 struct stat st; 387 char src[PATH_MAX]; 388 char dst[PATH_MAX]; 389 char *p = NULL; 390 391 snprintf(src, sizeof(src), "%s/ca.crt", ca->sslpath); 392 if (stat(src, &st) == -1) { 393 printf("CA '%s' does not exist\n", ca->caname); 394 return (1); 395 } 396 397 if (dir == NULL) 398 p = dir = strdup(KEYBASE); 399 400 ca_hier(dir); 401 402 snprintf(dst, sizeof(dst), "%s/ca/ca.crt", dir); 403 if (fcopy(src, dst, 0644) == 0) 404 printf("certificate for CA '%s' installed into %s\n", 405 ca->caname, dst); 406 407 snprintf(src, sizeof(src), "%s/ca.crl", ca->sslpath); 408 if (stat(src, &st) == 0) { 409 snprintf(dst, sizeof(dst), "%s/crls/ca.crl", dir); 410 if (fcopy(src, dst, 0644) == 0) 411 printf("CRL for CA '%s' installed to %s\n", 412 ca->caname, dst); 413 } 414 415 free(p); 416 417 return (0); 418 } 419 420 int 421 ca_show_certs(struct ca *ca, char *name) 422 { 423 DIR *dir; 424 struct dirent *de; 425 char cmd[PATH_MAX * 2]; 426 char path[PATH_MAX]; 427 char *p; 428 struct stat st; 429 430 if (name != NULL) { 431 snprintf(path, sizeof(path), "%s/%s.crt", 432 ca->sslpath, name); 433 if (stat(path, &st) != 0) 434 err(1, "could not open file %s.crt", name); 435 snprintf(cmd, sizeof(cmd), "%s x509 -text" 436 " -in %s", PATH_OPENSSL, path); 437 system(cmd); 438 printf("\n"); 439 return (0); 440 } 441 442 if ((dir = opendir(ca->sslpath)) == NULL) 443 err(1, "could not open directory %s", ca->sslpath); 444 445 while ((de = readdir(dir)) != NULL) { 446 if (de->d_namlen > 4) { 447 p = de->d_name + de->d_namlen - 4; 448 if (strcmp(".crt", p) != 0) 449 continue; 450 snprintf(path, sizeof(path), "%s/%s", ca->sslpath, 451 de->d_name); 452 snprintf(cmd, sizeof(cmd), "%s x509 -subject" 453 " -fingerprint -dates -noout -in %s", 454 PATH_OPENSSL, path); 455 system(cmd); 456 printf("\n"); 457 } 458 } 459 460 closedir(dir); 461 462 return (0); 463 } 464 465 int 466 fcopy(char *src, char *dst, mode_t mode) 467 { 468 int ifd, ofd; 469 u_int8_t buf[BUFSIZ]; 470 ssize_t r; 471 472 if ((ifd = open(src, O_RDONLY)) == -1) 473 err(1, "open %s", src); 474 475 if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) { 476 close(ifd); 477 err(1, "open %s", dst); 478 } 479 480 while ((r = read(ifd, buf, sizeof(buf))) > 0) { 481 write(ofd, buf, r); 482 } 483 484 close(ofd); 485 close(ifd); 486 487 return (r == -1); 488 } 489 490 int 491 rm_dir(char *path) 492 { 493 FTS *fts; 494 FTSENT *p; 495 static char *fpath[] = { NULL, NULL }; 496 497 fpath[0] = path; 498 if ((fts = fts_open(fpath, FTS_PHYSICAL, NULL)) == NULL) { 499 warn("fts_open %s", path); 500 return (1); 501 } 502 503 while ((p = fts_read(fts)) != NULL) { 504 switch (p->fts_info) { 505 case FTS_DP: 506 case FTS_DNR: 507 if (rmdir(p->fts_accpath) == -1) 508 warn("rmdir %s", p->fts_accpath); 509 break; 510 case FTS_F: 511 if (unlink(p->fts_accpath) == -1) 512 warn("unlink %s", p->fts_accpath); 513 break; 514 case FTS_D: 515 case FTS_DOT: 516 default: 517 continue; 518 } 519 } 520 fts_close(fts); 521 522 return (0); 523 } 524 525 526 int 527 ca_hier(char *path) 528 { 529 struct stat st; 530 char dst[PATH_MAX]; 531 u_int i; 532 533 for (i = 0; i < nitems(hier); i++) { 534 strlcpy(dst, path, sizeof(dst)); 535 strlcat(dst, hier[i].dir, sizeof(dst)); 536 if (stat(dst, &st) != 0 && errno == ENOENT && 537 mkdir(dst, hier[i].mode) != 0) 538 err(1, "failed to create dir %s", dst); 539 } 540 541 return (0); 542 } 543 544 int 545 ca_export(struct ca *ca, char *keyname, char *myname, char *password) 546 { 547 DIR *dexp; 548 struct dirent *de; 549 struct stat st; 550 char *pass; 551 char prev[_PASSWORD_LEN + 1]; 552 char cmd[PATH_MAX * 2]; 553 char oname[PATH_MAX]; 554 char src[PATH_MAX]; 555 char dst[PATH_MAX]; 556 char *p; 557 char tpl[] = "/tmp/ikectl.XXXXXXXXXX"; 558 u_int i; 559 int fd; 560 561 if (keyname != NULL) { 562 if (strlcpy(oname, keyname, sizeof(oname)) >= sizeof(oname)) 563 err(1, "name too long"); 564 } else { 565 strlcpy(oname, "ca", sizeof(oname)); 566 } 567 568 /* colons are not valid characters in windows filenames... */ 569 while ((p = strchr(oname, ':')) != NULL) 570 *p = '_'; 571 572 if (password != NULL) 573 pass = password; 574 else { 575 pass = getpass("Export passphrase:"); 576 if (pass == NULL || *pass == '\0') 577 err(1, "password not set"); 578 579 strlcpy(prev, pass, sizeof(prev)); 580 pass = getpass("Retype export passphrase:"); 581 if (pass == NULL || strcmp(prev, pass) != 0) 582 errx(1, "passphrase does not match!"); 583 } 584 585 if (keyname != NULL) { 586 snprintf(cmd, sizeof(cmd), "env EXPASS=%s %s pkcs12 -export" 587 " -name %s -CAfile %s/ca.crt -inkey %s/private/%s.key" 588 " -in %s/%s.crt -out %s/private/%s.pfx -passout env:EXPASS" 589 " -passin file:%s", pass, PATH_OPENSSL, keyname, 590 ca->sslpath, ca->sslpath, keyname, ca->sslpath, keyname, 591 ca->sslpath, oname, ca->passfile); 592 system(cmd); 593 } 594 595 snprintf(cmd, sizeof(cmd), "env EXPASS=%s %s pkcs12 -export" 596 " -caname '%s' -name '%s' -cacerts -nokeys" 597 " -in %s/ca.crt -out %s/ca.pfx -passout env:EXPASS -passin file:%s", 598 pass, PATH_OPENSSL, ca->caname, ca->caname, ca->sslpath, 599 ca->sslpath, ca->passfile); 600 system(cmd); 601 602 if ((p = mkdtemp(tpl)) == NULL) 603 err(1, "could not create temp dir"); 604 605 chmod(p, 0755); 606 607 for (i = 0; i < nitems(hier); i++) { 608 strlcpy(dst, p, sizeof(dst)); 609 strlcat(dst, hier[i].dir, sizeof(dst)); 610 if (stat(dst, &st) != 0 && errno == ENOENT && 611 mkdir(dst, hier[i].mode) != 0) 612 err(1, "failed to create dir %s", dst); 613 } 614 615 /* create a file with the address of the peer to connect to */ 616 if (myname != NULL) { 617 snprintf(dst, sizeof(dst), "%s/export/peer.txt", p); 618 if ((fd = open(dst, O_WRONLY|O_CREAT, 0644)) == -1) 619 err(1, "open %s", dst); 620 write(fd, myname, strlen(myname)); 621 close(fd); 622 } 623 624 snprintf(src, sizeof(src), "%s/ca.pfx", ca->sslpath); 625 snprintf(dst, sizeof(dst), "%s/export/ca.pfx", p); 626 fcopy(src, dst, 0644); 627 628 snprintf(src, sizeof(src), "%s/ca.crt", ca->sslpath); 629 snprintf(dst, sizeof(dst), "%s/ca/ca.crt", p); 630 fcopy(src, dst, 0644); 631 632 snprintf(src, sizeof(src), "%s/ca.crl", ca->sslpath); 633 if (stat(src, &st) == 0) { 634 snprintf(dst, sizeof(dst), "%s/crls/ca.crl", p); 635 fcopy(src, dst, 0644); 636 } 637 638 if (keyname != NULL) { 639 snprintf(src, sizeof(src), "%s/private/%s.pfx", ca->sslpath, 640 oname); 641 snprintf(dst, sizeof(dst), "%s/export/%s.pfx", p, oname); 642 fcopy(src, dst, 0644); 643 644 snprintf(src, sizeof(src), "%s/private/%s.key", ca->sslpath, 645 keyname); 646 snprintf(dst, sizeof(dst), "%s/private/%s.key", p, keyname); 647 fcopy(src, dst, 0600); 648 snprintf(dst, sizeof(dst), "%s/private/local.key", p); 649 fcopy(src, dst, 0600); 650 651 snprintf(src, sizeof(src), "%s/%s.crt", ca->sslpath, keyname); 652 snprintf(dst, sizeof(dst), "%s/certs/%s.crt", p, keyname); 653 fcopy(src, dst, 0644); 654 655 snprintf(cmd, sizeof(cmd), "%s rsa -out %s/local.pub" 656 " -in %s/private/%s.key -pubout", PATH_OPENSSL, p, 657 ca->sslpath, keyname); 658 system(cmd); 659 } 660 661 if (stat(PATH_TAR, &st) == 0) { 662 if (keyname == NULL) 663 snprintf(cmd, sizeof(cmd), "%s -zcf %s.tgz -C %s .", 664 PATH_TAR, oname, ca->sslpath); 665 else 666 snprintf(cmd, sizeof(cmd), "%s -zcf %s.tgz -C %s .", 667 PATH_TAR, oname, p); 668 system(cmd); 669 snprintf(src, sizeof(src), "%s.tgz", oname); 670 if (realpath(src, dst) != NULL) 671 printf("exported files in %s\n", dst); 672 } 673 674 if (stat(PATH_ZIP, &st) == 0) { 675 dexp = opendir(EXPDIR); 676 if (dexp) { 677 while ((de = readdir(dexp)) != NULL) { 678 if (!strcmp(de->d_name, ".") || 679 !strcmp(de->d_name, "..")) 680 continue; 681 snprintf(src, sizeof(src), "%s/%s", EXPDIR, 682 de->d_name); 683 snprintf(dst, sizeof(dst), "%s/export/%s", p, 684 de->d_name); 685 fcopy(src, dst, 644); 686 } 687 closedir(dexp); 688 } 689 690 snprintf(dst, sizeof(dst), "%s/export", p); 691 if (getcwd(src, sizeof(src)) == NULL) 692 err(1, "could not get cwd"); 693 694 if (chdir(dst) == -1) 695 err(1, "could not change %s", dst); 696 697 snprintf(dst, sizeof(dst), "%s/%s.zip", src, oname); 698 snprintf(cmd, sizeof(cmd), "%s -qr %s .", PATH_ZIP, dst); 699 system(cmd); 700 printf("exported files in %s\n", dst); 701 702 if (chdir(src) == -1) 703 err(1, "could not change %s", dst); 704 } 705 706 rm_dir(p); 707 708 return (0); 709 } 710 711 char * 712 ca_readpass(char *path, size_t *len) 713 { 714 FILE *f; 715 char *p, *r; 716 717 if ((f = fopen(path, "r")) == NULL) { 718 warn("fopen %s", path); 719 return (NULL); 720 } 721 722 if ((p = fgetln(f, len)) != NULL) { 723 if ((r = malloc(*len + 1)) == NULL) 724 err(1, "malloc"); 725 memcpy(r, p, *len); 726 if (r[*len - 1] == '\n') 727 r[*len - 1] = '\0'; 728 else 729 r[*len] = '\0'; 730 } else 731 r = NULL; 732 733 fclose(f); 734 735 return (r); 736 } 737 738 int 739 ca_revoke(struct ca *ca, char *keyname) 740 { 741 struct stat st; 742 char cmd[PATH_MAX * 2]; 743 char path[PATH_MAX]; 744 int fd; 745 char *pass; 746 size_t len; 747 748 if (keyname) { 749 snprintf(path, sizeof(path), "%s/%s.crt", 750 ca->sslpath, keyname); 751 if (stat(path, &st) != 0) { 752 warn("Problem with certificate for '%s'", keyname); 753 return (1); 754 } 755 } 756 757 snprintf(path, sizeof(path), "%s/ikeca.passwd", ca->sslpath); 758 pass = ca_readpass(path, &len); 759 if (pass == NULL) 760 err(1, "could not open passphrase file"); 761 762 /* create index if it doesn't already exist */ 763 snprintf(path, sizeof(path), "%s/index.txt", ca->sslpath); 764 if (stat(path, &st) != 0) { 765 if (errno == ENOENT) { 766 if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) == -1) 767 err(1, "could not create file %s", path); 768 close(fd); 769 } else 770 err(1, "could not access %s", path); 771 } 772 773 if (keyname) { 774 snprintf(cmd, sizeof(cmd), "env CADB='%s/index.txt' " 775 " %s ca %s-config %s -keyfile %s/private/ca.key" 776 " -key %s" 777 " -cert %s/ca.crt" 778 " -md sha1" 779 " -revoke %s/%s.crt", 780 ca->sslpath, PATH_OPENSSL, ca->batch, ca->sslcnf, 781 ca->sslpath, pass, ca->sslpath, ca->sslpath, keyname); 782 system(cmd); 783 } 784 785 snprintf(cmd, sizeof(cmd), "env CADB='%s/index.txt' " 786 " %s ca %s-config %s -keyfile %s/private/ca.key" 787 " -key %s" 788 " -gencrl" 789 " -cert %s/ca.crt" 790 " -md sha1" 791 " -crldays 365" 792 " -out %s/ca.crl", 793 ca->sslpath, PATH_OPENSSL, ca->batch, ca->sslcnf, ca->sslpath, 794 pass, ca->sslpath, ca->sslpath); 795 system(cmd); 796 797 bzero(pass, len); 798 free(pass); 799 800 return (0); 801 } 802 803 struct ca * 804 ca_setup(char *caname, int create, int quiet, char *pass) 805 { 806 struct stat st; 807 struct ca *ca; 808 char path[PATH_MAX]; 809 810 if (stat(PATH_OPENSSL, &st) == -1) 811 err(1, "openssl binary not available"); 812 813 if ((ca = calloc(1, sizeof(struct ca))) == NULL) 814 err(1, "calloc"); 815 816 ca->caname = strdup(caname); 817 snprintf(ca->sslpath, sizeof(ca->sslpath), SSLDIR "/%s", caname); 818 strlcpy(ca->passfile, ca->sslpath, sizeof(ca->passfile)); 819 strlcat(ca->passfile, "/ikeca.passwd", sizeof(ca->passfile)); 820 821 if (quiet) 822 strlcpy(ca->batch, "-batch ", sizeof(ca->batch)); 823 824 if (stat(IKECA_CNF, &st) == 0) { 825 strlcpy(ca->extcnf, IKECA_CNF, sizeof(ca->extcnf)); 826 strlcpy(ca->sslcnf, IKECA_CNF, sizeof(ca->sslcnf)); 827 } else { 828 strlcpy(ca->extcnf, X509_CNF, sizeof(ca->extcnf)); 829 strlcpy(ca->sslcnf, SSL_CNF, sizeof(ca->sslcnf)); 830 } 831 832 if (create == 0 && stat(ca->sslpath, &st) == -1) { 833 free(ca->caname); 834 free(ca); 835 errx(1, "CA '%s' does not exist", caname); 836 } 837 838 strlcpy(path, ca->sslpath, sizeof(path)); 839 if (mkdir(path, 0777) == -1 && errno != EEXIST) 840 err(1, "failed to create dir %s", path); 841 strlcat(path, "/private", sizeof(path)); 842 if (mkdir(path, 0700) == -1 && errno != EEXIST) 843 err(1, "failed to create dir %s", path); 844 845 if (create && stat(ca->passfile, &st) == -1 && errno == ENOENT) 846 ca_newpass(ca->passfile, pass); 847 848 return (ca); 849 } 850