Annotation of embedaddon/strongswan/src/libcharon/plugins/stroke/stroke_cred.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2008-2017 Tobias Brunner
! 3: * Copyright (C) 2008 Martin Willi
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 6: * This program is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2 of the License, or (at your
! 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 10: *
! 11: * This program is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 14: * for more details.
! 15: */
! 16:
! 17: #include <sys/types.h>
! 18: #include <sys/stat.h>
! 19: #include <limits.h>
! 20: #include <fcntl.h>
! 21: #include <errno.h>
! 22: #include <unistd.h>
! 23:
! 24: #ifdef HAVE_GLOB_H
! 25: #include <glob.h>
! 26: #endif
! 27:
! 28: #include "stroke_cred.h"
! 29:
! 30: #include <credentials/certificates/x509.h>
! 31: #include <credentials/certificates/crl.h>
! 32: #include <credentials/certificates/ac.h>
! 33: #include <credentials/containers/pkcs12.h>
! 34: #include <credentials/sets/mem_cred.h>
! 35: #include <credentials/sets/callback_cred.h>
! 36: #include <collections/linked_list.h>
! 37: #include <utils/lexparser.h>
! 38: #include <threading/rwlock.h>
! 39: #include <daemon.h>
! 40:
! 41: /* configuration directories and files */
! 42: #define CONFIG_DIR IPSEC_CONFDIR
! 43: #define IPSEC_D_DIR CONFIG_DIR "/ipsec.d"
! 44: #define PRIVATE_KEY_DIR IPSEC_D_DIR "/private"
! 45: #define CERTIFICATE_DIR IPSEC_D_DIR "/certs"
! 46: #define CA_CERTIFICATE_DIR IPSEC_D_DIR "/cacerts"
! 47: #define AA_CERTIFICATE_DIR IPSEC_D_DIR "/aacerts"
! 48: #define ATTR_CERTIFICATE_DIR IPSEC_D_DIR "/acerts"
! 49: #define OCSP_CERTIFICATE_DIR IPSEC_D_DIR "/ocspcerts"
! 50: #define CRL_DIR IPSEC_D_DIR "/crls"
! 51: #define SECRETS_FILE CONFIG_DIR "/ipsec.secrets"
! 52:
! 53: #define MAX_SECRETS_RECURSION 10
! 54:
! 55: typedef struct private_stroke_cred_t private_stroke_cred_t;
! 56:
! 57: /**
! 58: * private data of stroke_cred
! 59: */
! 60: struct private_stroke_cred_t {
! 61:
! 62: /**
! 63: * public functions
! 64: */
! 65: stroke_cred_t public;
! 66:
! 67: /**
! 68: * secrets file with credential information
! 69: */
! 70: char *secrets_file;
! 71:
! 72: /**
! 73: * credentials: end entity certs, attribute certs, CRLs, etc.
! 74: */
! 75: mem_cred_t *creds;
! 76:
! 77: /**
! 78: * Attribute Authority certificates
! 79: */
! 80: mem_cred_t *aacerts;
! 81:
! 82: /**
! 83: * ignore missing CA basic constraint (i.e. treat all certificates in
! 84: * ipsec.conf ca sections and ipsec.d/cacerts as CA certificates)
! 85: */
! 86: bool force_ca_cert;
! 87:
! 88: /**
! 89: * cache CRLs to disk?
! 90: */
! 91: bool cachecrl;
! 92:
! 93: /**
! 94: * CA certificate store
! 95: */
! 96: stroke_ca_t *ca;
! 97: };
! 98:
! 99: /** Length of smartcard specifier parts (module, keyid) */
! 100: #define SC_PART_LEN 128
! 101:
! 102: /**
! 103: * Kind of smartcard specifier token
! 104: */
! 105: typedef enum {
! 106: SC_FORMAT_SLOT_MODULE_KEYID,
! 107: SC_FORMAT_SLOT_KEYID,
! 108: SC_FORMAT_KEYID,
! 109: SC_FORMAT_INVALID,
! 110: } smartcard_format_t;
! 111:
! 112: /**
! 113: * Parse a smartcard specifier token
! 114: */
! 115: static smartcard_format_t parse_smartcard(char *smartcard, u_int *slot,
! 116: char *module, char *keyid)
! 117: {
! 118: /* The token has one of the following three formats:
! 119: * - %smartcard<slot>@<module>:<keyid>
! 120: * - %smartcard<slot>:<keyid>
! 121: * - %smartcard:<keyid>
! 122: */
! 123: char buf[2 * SC_PART_LEN], *pos;
! 124:
! 125: if (sscanf(smartcard, "%%smartcard%u@%255s", slot, buf) == 2)
! 126: {
! 127: pos = strchr(buf, ':');
! 128: if (!pos)
! 129: {
! 130: return SC_FORMAT_INVALID;
! 131: }
! 132: *pos++ = '\0';
! 133: snprintf(module, SC_PART_LEN, "%s", buf);
! 134: snprintf(keyid, SC_PART_LEN, "%s", pos);
! 135: return SC_FORMAT_SLOT_MODULE_KEYID;
! 136: }
! 137: if (sscanf(smartcard, "%%smartcard%u:%127s", slot, keyid) == 2)
! 138: {
! 139: return SC_FORMAT_SLOT_KEYID;
! 140: }
! 141: if (sscanf(smartcard, "%%smartcard:%127s", keyid) == 1)
! 142: {
! 143: return SC_FORMAT_KEYID;
! 144: }
! 145: return SC_FORMAT_INVALID;
! 146: }
! 147:
! 148: /**
! 149: * Load a credential from a smartcard
! 150: */
! 151: static certificate_t *load_from_smartcard(smartcard_format_t format,
! 152: u_int slot, char *module, char *keyid,
! 153: credential_type_t type, int subtype)
! 154: {
! 155: chunk_t chunk;
! 156: void *cred;
! 157:
! 158: chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
! 159: switch (format)
! 160: {
! 161: case SC_FORMAT_SLOT_MODULE_KEYID:
! 162: cred = lib->creds->create(lib->creds, type, subtype,
! 163: BUILD_PKCS11_SLOT, slot,
! 164: BUILD_PKCS11_MODULE, module,
! 165: BUILD_PKCS11_KEYID, chunk, BUILD_END);
! 166: break;
! 167: case SC_FORMAT_SLOT_KEYID:
! 168: cred = lib->creds->create(lib->creds, type, subtype,
! 169: BUILD_PKCS11_SLOT, slot,
! 170: BUILD_PKCS11_KEYID, chunk, BUILD_END);
! 171: break;
! 172: case SC_FORMAT_KEYID:
! 173: cred = lib->creds->create(lib->creds, type, subtype,
! 174: BUILD_PKCS11_KEYID, chunk, BUILD_END);
! 175: break;
! 176: default:
! 177: cred = NULL;
! 178: break;
! 179: }
! 180: free(chunk.ptr);
! 181:
! 182: return cred;
! 183: }
! 184:
! 185: METHOD(stroke_cred_t, load_peer, certificate_t*,
! 186: private_stroke_cred_t *this, char *filename)
! 187: {
! 188: certificate_t *cert = NULL;
! 189: char path[PATH_MAX];
! 190:
! 191: if (strpfx(filename, "%smartcard"))
! 192: {
! 193: smartcard_format_t format;
! 194: char module[SC_PART_LEN], keyid[SC_PART_LEN];
! 195: u_int slot;
! 196:
! 197: format = parse_smartcard(filename, &slot, module, keyid);
! 198: if (format != SC_FORMAT_INVALID)
! 199: {
! 200: cert = (certificate_t*)load_from_smartcard(format,
! 201: slot, module, keyid, CRED_CERTIFICATE, CERT_X509);
! 202: }
! 203: }
! 204: else
! 205: {
! 206: if (*filename == '/')
! 207: {
! 208: snprintf(path, sizeof(path), "%s", filename);
! 209: }
! 210: else
! 211: {
! 212: snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
! 213: }
! 214:
! 215: cert = lib->creds->create(lib->creds,
! 216: CRED_CERTIFICATE, CERT_ANY,
! 217: BUILD_FROM_FILE, path,
! 218: BUILD_END);
! 219: }
! 220: if (cert)
! 221: {
! 222: cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
! 223: DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
! 224: cert->get_subject(cert), filename);
! 225: return cert;
! 226: }
! 227: DBG1(DBG_CFG, " loading certificate from '%s' failed", filename);
! 228: return NULL;
! 229: }
! 230:
! 231: METHOD(stroke_cred_t, load_pubkey, certificate_t*,
! 232: private_stroke_cred_t *this, char *filename, identification_t *identity)
! 233: {
! 234: certificate_t *cert;
! 235: public_key_t *key;
! 236: char path[PATH_MAX];
! 237: builder_part_t build_part;
! 238: key_type_t type = KEY_ANY;
! 239:
! 240: if (streq(filename, "%dns"))
! 241: {
! 242: return NULL;
! 243: }
! 244: if (strncaseeq(filename, "dns:", 4))
! 245: { /* RFC 3110 format */
! 246: build_part = BUILD_BLOB_DNSKEY;
! 247: /* not a complete RR, only RSA supported */
! 248: type = KEY_RSA;
! 249: filename += 4;
! 250: }
! 251: else if (strncaseeq(filename, "ssh:", 4))
! 252: { /* SSH key */
! 253: build_part = BUILD_BLOB_SSHKEY;
! 254: filename += 4;
! 255: }
! 256: else
! 257: { /* try PKCS#1 by default */
! 258: build_part = BUILD_BLOB_ASN1_DER;
! 259: }
! 260: if (strncaseeq(filename, "0x", 2) || strncaseeq(filename, "0s", 2))
! 261: {
! 262: chunk_t printable_key, raw_key;
! 263:
! 264: printable_key = chunk_create(filename + 2, strlen(filename) - 2);
! 265: raw_key = strncaseeq(filename, "0x", 2) ?
! 266: chunk_from_hex(printable_key, NULL) :
! 267: chunk_from_base64(printable_key, NULL);
! 268: key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, type,
! 269: build_part, raw_key, BUILD_END);
! 270: chunk_free(&raw_key);
! 271: if (key)
! 272: {
! 273: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
! 274: CERT_TRUSTED_PUBKEY,
! 275: BUILD_PUBLIC_KEY, key,
! 276: BUILD_SUBJECT, identity,
! 277: BUILD_END);
! 278: type = key->get_type(key);
! 279: key->destroy(key);
! 280: if (cert)
! 281: {
! 282: cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
! 283: DBG1(DBG_CFG, " loaded %N public key for \"%Y\"",
! 284: key_type_names, type, identity);
! 285: return cert;
! 286: }
! 287: }
! 288: DBG1(DBG_CFG, " loading public key for \"%Y\" failed", identity);
! 289: }
! 290: else
! 291: {
! 292: if (*filename == '/')
! 293: {
! 294: snprintf(path, sizeof(path), "%s", filename);
! 295: }
! 296: else
! 297: {
! 298: snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename);
! 299: }
! 300:
! 301: cert = lib->creds->create(lib->creds,
! 302: CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY,
! 303: BUILD_FROM_FILE, path,
! 304: BUILD_SUBJECT, identity,
! 305: BUILD_END);
! 306: if (cert)
! 307: {
! 308: cert = this->creds->add_cert_ref(this->creds, TRUE, cert);
! 309: key = cert->get_public_key(cert);
! 310: type = key->get_type(key);
! 311: key->destroy(key);
! 312: DBG1(DBG_CFG, " loaded %N public key for \"%Y\" from '%s'",
! 313: key_type_names, type, identity, filename);
! 314: return cert;
! 315: }
! 316: DBG1(DBG_CFG, " loading public key for \"%Y\" from '%s' failed",
! 317: identity, filename);
! 318: }
! 319: return NULL;
! 320: }
! 321:
! 322: /**
! 323: * Load a CA certificate, optionally force it to be one
! 324: */
! 325: static certificate_t *load_ca_cert(char *filename, bool force_ca_cert)
! 326: {
! 327: certificate_t *cert = NULL;
! 328: char path[PATH_MAX];
! 329:
! 330: if (strpfx(filename, "%smartcard"))
! 331: {
! 332: smartcard_format_t format;
! 333: char module[SC_PART_LEN], keyid[SC_PART_LEN];
! 334: u_int slot;
! 335:
! 336: format = parse_smartcard(filename, &slot, module, keyid);
! 337: if (format != SC_FORMAT_INVALID)
! 338: {
! 339: cert = (certificate_t*)load_from_smartcard(format,
! 340: slot, module, keyid, CRED_CERTIFICATE, CERT_X509);
! 341: }
! 342: }
! 343: else
! 344: {
! 345: if (*filename == '/')
! 346: {
! 347: snprintf(path, sizeof(path), "%s", filename);
! 348: }
! 349: else
! 350: {
! 351: snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename);
! 352: }
! 353:
! 354: if (force_ca_cert)
! 355: { /* we treat this certificate as a CA certificate even if it has no
! 356: * CA basic constraint */
! 357: cert = lib->creds->create(lib->creds,
! 358: CRED_CERTIFICATE, CERT_X509,
! 359: BUILD_FROM_FILE, path, BUILD_X509_FLAG, X509_CA,
! 360: BUILD_END);
! 361: }
! 362: else
! 363: {
! 364: cert = lib->creds->create(lib->creds,
! 365: CRED_CERTIFICATE, CERT_X509,
! 366: BUILD_FROM_FILE, path,
! 367: BUILD_END);
! 368: }
! 369: }
! 370: if (cert)
! 371: {
! 372: x509_t *x509 = (x509_t*)cert;
! 373:
! 374: if (!(x509->get_flags(x509) & X509_CA))
! 375: {
! 376: DBG1(DBG_CFG, " ca certificate \"%Y\" lacks ca basic constraint, "
! 377: "discarded", cert->get_subject(cert));
! 378: cert->destroy(cert);
! 379: return NULL;
! 380: }
! 381: DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
! 382: cert->get_subject(cert), filename);
! 383: return cert;
! 384: }
! 385: return NULL;
! 386: }
! 387:
! 388: /**
! 389: * Used by stroke_ca.c
! 390: */
! 391: certificate_t *stroke_load_ca_cert(char *filename)
! 392: {
! 393: bool force_ca_cert;
! 394:
! 395: force_ca_cert = lib->settings->get_bool(lib->settings,
! 396: "%s.plugins.stroke.ignore_missing_ca_basic_constraint",
! 397: FALSE, lib->ns);
! 398: return load_ca_cert(filename, force_ca_cert);
! 399: }
! 400:
! 401: /**
! 402: * Load a CA certificate from disk
! 403: */
! 404: static void load_x509_ca(private_stroke_cred_t *this, char *file,
! 405: mem_cred_t *creds)
! 406: {
! 407: certificate_t *cert;
! 408:
! 409: cert = load_ca_cert(file, this->force_ca_cert);
! 410: if (cert)
! 411: {
! 412: cert = this->ca->get_cert_ref(this->ca, cert);
! 413: creds->add_cert(creds, TRUE, cert);
! 414: }
! 415: else
! 416: {
! 417: DBG1(DBG_CFG, " loading ca certificate from '%s' failed", file);
! 418: }
! 419: }
! 420:
! 421: /**
! 422: * Load AA certificate with flags from disk
! 423: */
! 424: static void load_x509_aa(private_stroke_cred_t *this,char *file,
! 425: mem_cred_t *creds)
! 426: {
! 427: certificate_t *cert;
! 428:
! 429: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
! 430: BUILD_FROM_FILE, file,
! 431: BUILD_X509_FLAG, X509_AA, BUILD_END);
! 432: if (cert)
! 433: {
! 434: DBG1(DBG_CFG, " loaded AA certificate \"%Y\" from '%s'",
! 435: cert->get_subject(cert), file);
! 436: creds->add_cert(creds, TRUE, cert);
! 437: }
! 438: else
! 439: {
! 440: DBG1(DBG_CFG, " loading AA certificate from '%s' failed", file);
! 441: }
! 442: }
! 443:
! 444: /**
! 445: * Load a certificate with flags from disk
! 446: */
! 447: static void load_x509(private_stroke_cred_t *this, char *file, x509_flag_t flag,
! 448: mem_cred_t *creds)
! 449: {
! 450: certificate_t *cert;
! 451:
! 452: /* for all other flags, we add them to the certificate. */
! 453: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
! 454: BUILD_FROM_FILE, file,
! 455: BUILD_X509_FLAG, flag, BUILD_END);
! 456: if (cert)
! 457: {
! 458: DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
! 459: cert->get_subject(cert), file);
! 460: creds->add_cert(creds, TRUE, cert);
! 461: }
! 462: else
! 463: {
! 464: DBG1(DBG_CFG, " loading certificate from '%s' failed", file);
! 465: }
! 466: }
! 467:
! 468: /**
! 469: * Load a CRL from a file
! 470: */
! 471: static void load_x509_crl(private_stroke_cred_t *this, char *file,
! 472: mem_cred_t *creds)
! 473: {
! 474: certificate_t *cert;
! 475:
! 476: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
! 477: BUILD_FROM_FILE, file, BUILD_END);
! 478: if (cert)
! 479: {
! 480: DBG1(DBG_CFG, " loaded crl from '%s'", file);
! 481: creds->add_crl(creds, (crl_t*)cert);
! 482: }
! 483: else
! 484: {
! 485: DBG1(DBG_CFG, " loading crl from '%s' failed", file);
! 486: }
! 487: }
! 488:
! 489: /**
! 490: * Load an attribute certificate from a file
! 491: */
! 492: static void load_x509_ac(private_stroke_cred_t *this, char *file,
! 493: mem_cred_t *creds)
! 494: {
! 495: certificate_t *cert;
! 496:
! 497: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC,
! 498: BUILD_FROM_FILE, file, BUILD_END);
! 499: if (cert)
! 500: {
! 501: DBG1(DBG_CFG, " loaded attribute certificate from '%s'", file);
! 502: creds->add_cert(creds, FALSE, cert);
! 503: }
! 504: else
! 505: {
! 506: DBG1(DBG_CFG, " loading attribute certificate from '%s' failed", file);
! 507: }
! 508: }
! 509:
! 510: /**
! 511: * load trusted certificates from a directory
! 512: */
! 513: static void load_certdir(private_stroke_cred_t *this, char *path,
! 514: certificate_type_t type, x509_flag_t flag,
! 515: mem_cred_t *creds)
! 516: {
! 517: enumerator_t *enumerator;
! 518: struct stat st;
! 519: char *file;
! 520:
! 521: enumerator = enumerator_create_directory(path);
! 522: if (enumerator)
! 523: {
! 524: while (enumerator->enumerate(enumerator, NULL, &file, &st))
! 525: {
! 526: if (!S_ISREG(st.st_mode))
! 527: {
! 528: /* skip special file */
! 529: continue;
! 530: }
! 531: switch (type)
! 532: {
! 533: case CERT_X509:
! 534: if (flag & X509_CA)
! 535: {
! 536: load_x509_ca(this, file, creds);
! 537: }
! 538: else if (flag & X509_AA)
! 539: {
! 540: load_x509_aa(this, file, creds);
! 541: }
! 542: else
! 543: {
! 544: load_x509(this, file, flag, creds);
! 545: }
! 546: break;
! 547: case CERT_X509_CRL:
! 548: load_x509_crl(this, file, creds);
! 549: break;
! 550: case CERT_X509_AC:
! 551: load_x509_ac(this, file, creds);
! 552: break;
! 553: default:
! 554: break;
! 555: }
! 556: }
! 557: enumerator->destroy(enumerator);
! 558: }
! 559: else
! 560: {
! 561: DBG1(DBG_CFG, " reading directory failed");
! 562: }
! 563: }
! 564:
! 565: METHOD(credential_set_t, cache_cert, void,
! 566: private_stroke_cred_t *this, certificate_t *cert)
! 567: {
! 568: if (cert->get_type(cert) == CERT_X509_CRL && this->cachecrl)
! 569: {
! 570: /* CRLs get written to /etc/ipsec.d/crls/<authkeyId>.crl */
! 571: crl_t *crl = (crl_t*)cert;
! 572:
! 573: cert->get_ref(cert);
! 574: if (this->creds->add_crl(this->creds, crl))
! 575: {
! 576: char buf[BUF_LEN];
! 577: chunk_t chunk, hex;
! 578: bool is_delta_crl;
! 579:
! 580: is_delta_crl = crl->is_delta_crl(crl, NULL);
! 581:
! 582: chunk = crl->get_authKeyIdentifier(crl);
! 583: hex = chunk_to_hex(chunk, NULL, FALSE);
! 584: snprintf(buf, sizeof(buf), "%s/%s%s.crl", CRL_DIR, hex.ptr,
! 585: is_delta_crl ? "_delta" : "");
! 586: free(hex.ptr);
! 587:
! 588: if (cert->get_encoding(cert, CERT_ASN1_DER, &chunk))
! 589: {
! 590: if (chunk_write(chunk, buf, 022, TRUE))
! 591: {
! 592: DBG1(DBG_CFG, " written crl file '%s' (%d bytes)",
! 593: buf, chunk.len);
! 594: }
! 595: else
! 596: {
! 597: DBG1(DBG_CFG, " writing crl file '%s' failed: %s",
! 598: buf, strerror(errno));
! 599: }
! 600: free(chunk.ptr);
! 601: }
! 602: }
! 603: }
! 604: }
! 605:
! 606: METHOD(stroke_cred_t, cachecrl, void,
! 607: private_stroke_cred_t *this, bool enabled)
! 608: {
! 609: DBG1(DBG_CFG, "crl caching to %s %s",
! 610: CRL_DIR, enabled ? "enabled" : "disabled");
! 611: this->cachecrl = enabled;
! 612: }
! 613:
! 614:
! 615: /**
! 616: * Convert a string of characters into a binary secret
! 617: * A string between single or double quotes is treated as ASCII characters
! 618: * A string prepended by 0x is treated as HEX and prepended by 0s as Base64
! 619: */
! 620: static err_t extract_secret(chunk_t *secret, chunk_t *line)
! 621: {
! 622: chunk_t raw_secret;
! 623: char delimiter = ' ';
! 624: bool quotes = FALSE;
! 625:
! 626: if (!eat_whitespace(line))
! 627: {
! 628: return "missing secret";
! 629: }
! 630:
! 631: if (*line->ptr == '\'' || *line->ptr == '"')
! 632: {
! 633: quotes = TRUE;
! 634: delimiter = *line->ptr;
! 635: line->ptr++; line->len--;
! 636: }
! 637:
! 638: if (!extract_token(&raw_secret, delimiter, line))
! 639: {
! 640: if (delimiter == ' ')
! 641: {
! 642: raw_secret = *line;
! 643: }
! 644: else
! 645: {
! 646: return "missing second delimiter";
! 647: }
! 648: }
! 649:
! 650: if (quotes)
! 651: {
! 652: /* treat as an ASCII string */
! 653: *secret = chunk_clone(raw_secret);
! 654: return NULL;
! 655: }
! 656: /* treat 0x as hex, 0s as base64 */
! 657: if (raw_secret.len > 2)
! 658: {
! 659: if (strncasecmp("0x", raw_secret.ptr, 2) == 0)
! 660: {
! 661: *secret = chunk_from_hex(chunk_skip(raw_secret, 2), NULL);
! 662: return NULL;
! 663: }
! 664: if (strncasecmp("0s", raw_secret.ptr, 2) == 0)
! 665: {
! 666: *secret = chunk_from_base64(chunk_skip(raw_secret, 2), NULL);
! 667: return NULL;
! 668: }
! 669: }
! 670: *secret = chunk_clone(raw_secret);
! 671: return NULL;
! 672: }
! 673:
! 674: /**
! 675: * Data for passphrase callback
! 676: */
! 677: typedef struct {
! 678: /** cached passphrases */
! 679: mem_cred_t *cache;
! 680: /** socket we use for prompting */
! 681: FILE *prompt;
! 682: /** type of secret to unlock */
! 683: int type;
! 684: /** private key file */
! 685: char *path;
! 686: /** number of tries */
! 687: int try;
! 688: } passphrase_cb_data_t;
! 689:
! 690: /**
! 691: * Callback function to receive passphrases
! 692: */
! 693: static shared_key_t* passphrase_cb(passphrase_cb_data_t *data,
! 694: shared_key_type_t type, identification_t *me,
! 695: identification_t *other, id_match_t *match_me,
! 696: id_match_t *match_other)
! 697: {
! 698: static const int max_tries = 3;
! 699: shared_key_t *shared;
! 700: chunk_t secret;
! 701: char buf[256];
! 702:
! 703: if (type != SHARED_ANY && type != SHARED_PRIVATE_KEY_PASS)
! 704: {
! 705: return NULL;
! 706: }
! 707:
! 708: data->try++;
! 709: if (data->try > max_tries + 1)
! 710: { /* another builder might call this after we gave up, fail silently */
! 711: return NULL;
! 712: }
! 713: if (data->try > max_tries)
! 714: {
! 715: fprintf(data->prompt, "Passphrase invalid, giving up.\n");
! 716: return NULL;
! 717: }
! 718: if (data->try > 1)
! 719: {
! 720: fprintf(data->prompt, "Passphrase invalid!\n");
! 721: }
! 722: fprintf(data->prompt, "%s '%s' is encrypted.\n",
! 723: data->type == CRED_PRIVATE_KEY ? "Private key" : "PKCS#12 file",
! 724: data->path);
! 725: fprintf(data->prompt, "Passphrase:\n");
! 726: if (fgets(buf, sizeof(buf), data->prompt))
! 727: {
! 728: secret = chunk_create(buf, strlen(buf));
! 729: if (secret.len > 1)
! 730: { /* trim appended \n */
! 731: secret.len--;
! 732: if (match_me)
! 733: {
! 734: *match_me = ID_MATCH_PERFECT;
! 735: }
! 736: if (match_other)
! 737: {
! 738: *match_other = ID_MATCH_NONE;
! 739: }
! 740: shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
! 741: chunk_clone(secret));
! 742: data->cache->add_shared(data->cache, shared->get_ref(shared), NULL);
! 743: return shared;
! 744: }
! 745: }
! 746: return NULL;
! 747: }
! 748:
! 749: /**
! 750: * Data for PIN callback
! 751: */
! 752: typedef struct {
! 753: /** socket we use for prompting */
! 754: FILE *prompt;
! 755: /** card label */
! 756: char *card;
! 757: /** card keyid */
! 758: chunk_t keyid;
! 759: /** number of tries */
! 760: int try;
! 761: /** provided PIN */
! 762: shared_key_t *shared;
! 763: } pin_cb_data_t;
! 764:
! 765: /**
! 766: * Callback function to receive PINs
! 767: */
! 768: static shared_key_t* pin_cb(pin_cb_data_t *data, shared_key_type_t type,
! 769: identification_t *me, identification_t *other,
! 770: id_match_t *match_me, id_match_t *match_other)
! 771: {
! 772: chunk_t secret;
! 773: char buf[256];
! 774:
! 775: if (type != SHARED_ANY && type != SHARED_PIN)
! 776: {
! 777: return NULL;
! 778: }
! 779:
! 780: if (!me || !chunk_equals(me->get_encoding(me), data->keyid))
! 781: {
! 782: return NULL;
! 783: }
! 784:
! 785: data->try++;
! 786: if (data->try > 1)
! 787: {
! 788: fprintf(data->prompt, "PIN invalid, aborting.\n");
! 789: return NULL;
! 790: }
! 791: fprintf(data->prompt, "Login to '%s' required\n", data->card);
! 792: fprintf(data->prompt, "PIN:\n");
! 793: if (fgets(buf, sizeof(buf), data->prompt))
! 794: {
! 795: secret = chunk_create(buf, strlen(buf));
! 796: if (secret.len > 1)
! 797: { /* trim appended \n */
! 798: secret.len--;
! 799: if (match_me)
! 800: {
! 801: *match_me = ID_MATCH_PERFECT;
! 802: }
! 803: if (match_other)
! 804: {
! 805: *match_other = ID_MATCH_NONE;
! 806: }
! 807: DESTROY_IF(data->shared);
! 808: data->shared = shared_key_create(SHARED_PIN, chunk_clone(secret));
! 809: return data->shared->get_ref(data->shared);
! 810: }
! 811: }
! 812: return NULL;
! 813: }
! 814:
! 815: /**
! 816: * Load a smartcard with a PIN
! 817: */
! 818: static bool load_pin(mem_cred_t *secrets, chunk_t line, int line_nr,
! 819: FILE *prompt)
! 820: {
! 821: chunk_t sc = chunk_empty, secret = chunk_empty;
! 822: char smartcard[BUF_LEN], keyid[SC_PART_LEN], module[SC_PART_LEN];
! 823: private_key_t *key = NULL;
! 824: u_int slot;
! 825: chunk_t chunk;
! 826: shared_key_t *shared = NULL;
! 827: identification_t *id;
! 828: mem_cred_t *mem = NULL;
! 829: callback_cred_t *cb = NULL;
! 830: pin_cb_data_t pin_data;
! 831: smartcard_format_t format;
! 832:
! 833: err_t ugh = extract_value(&sc, &line);
! 834:
! 835: if (ugh != NULL)
! 836: {
! 837: DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
! 838: return FALSE;
! 839: }
! 840: if (sc.len == 0)
! 841: {
! 842: DBG1(DBG_CFG, "line %d: expected %%smartcard specifier", line_nr);
! 843: return FALSE;
! 844: }
! 845: snprintf(smartcard, sizeof(smartcard), "%.*s", (int)sc.len, sc.ptr);
! 846: smartcard[sizeof(smartcard) - 1] = '\0';
! 847:
! 848: format = parse_smartcard(smartcard, &slot, module, keyid);
! 849: if (format == SC_FORMAT_INVALID)
! 850: {
! 851: DBG1(DBG_CFG, "line %d: the given %%smartcard specifier is not"
! 852: " supported or invalid", line_nr);
! 853: return FALSE;
! 854: }
! 855:
! 856: if (!eat_whitespace(&line))
! 857: {
! 858: DBG1(DBG_CFG, "line %d: expected PIN", line_nr);
! 859: return FALSE;
! 860: }
! 861: ugh = extract_secret(&secret, &line);
! 862: if (ugh != NULL)
! 863: {
! 864: DBG1(DBG_CFG, "line %d: malformed PIN: %s", line_nr, ugh);
! 865: return FALSE;
! 866: }
! 867:
! 868: chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
! 869: if (secret.len == 7 && strpfx(secret.ptr, "%prompt"))
! 870: {
! 871: free(secret.ptr);
! 872: if (!prompt)
! 873: { /* no IO channel to prompt, skip */
! 874: chunk_clear(&chunk);
! 875: return TRUE;
! 876: }
! 877: /* use callback credential set to prompt for the pin */
! 878: pin_data = (pin_cb_data_t){
! 879: .prompt = prompt,
! 880: .card = smartcard,
! 881: .keyid = chunk,
! 882: };
! 883: cb = callback_cred_create_shared((void*)pin_cb, &pin_data);
! 884: lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
! 885: }
! 886: else
! 887: {
! 888: /* provide our pin in a temporary credential set */
! 889: shared = shared_key_create(SHARED_PIN, secret);
! 890: id = identification_create_from_encoding(ID_KEY_ID, chunk);
! 891: mem = mem_cred_create();
! 892: mem->add_shared(mem, shared->get_ref(shared), id, NULL);
! 893: lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
! 894: }
! 895:
! 896: /* unlock: smartcard needs the pin and potentially calls public set */
! 897: key = (private_key_t*)load_from_smartcard(format, slot, module, keyid,
! 898: CRED_PRIVATE_KEY, KEY_ANY);
! 899:
! 900: if (key)
! 901: {
! 902: DBG1(DBG_CFG, " loaded private key from %.*s", (int)sc.len, sc.ptr);
! 903: secrets->add_key(secrets, key);
! 904: }
! 905: if (mem)
! 906: {
! 907: if (!key)
! 908: {
! 909: shared->destroy(shared);
! 910: shared = NULL;
! 911: }
! 912: lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
! 913: mem->destroy(mem);
! 914: }
! 915: if (cb)
! 916: {
! 917: if (key)
! 918: {
! 919: shared = pin_data.shared;
! 920: }
! 921: else
! 922: {
! 923: DESTROY_IF(pin_data.shared);
! 924: }
! 925: lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
! 926: cb->destroy(cb);
! 927: }
! 928: if (shared)
! 929: {
! 930: id = identification_create_from_encoding(ID_KEY_ID, chunk);
! 931: secrets->add_shared(secrets, shared, id, NULL);
! 932: }
! 933: chunk_clear(&chunk);
! 934: return TRUE;
! 935: }
! 936:
! 937: /**
! 938: * Load a private key or PKCS#12 container from a file
! 939: */
! 940: static bool load_from_file(chunk_t line, int line_nr, FILE *prompt,
! 941: char *path, int type, int subtype,
! 942: void **result)
! 943: {
! 944: chunk_t filename;
! 945: chunk_t secret = chunk_empty;
! 946:
! 947: err_t ugh = extract_value(&filename, &line);
! 948:
! 949: if (ugh != NULL)
! 950: {
! 951: DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
! 952: return FALSE;
! 953: }
! 954: if (filename.len == 0)
! 955: {
! 956: DBG1(DBG_CFG, "line %d: empty filename", line_nr);
! 957: return FALSE;
! 958: }
! 959: if (*filename.ptr == '/')
! 960: {
! 961: /* absolute path name */
! 962: snprintf(path, PATH_MAX, "%.*s", (int)filename.len, filename.ptr);
! 963: }
! 964: else
! 965: {
! 966: /* relative path name */
! 967: snprintf(path, PATH_MAX, "%s/%.*s", PRIVATE_KEY_DIR,
! 968: (int)filename.len, filename.ptr);
! 969: }
! 970:
! 971: /* check for optional passphrase */
! 972: if (eat_whitespace(&line))
! 973: {
! 974: ugh = extract_secret(&secret, &line);
! 975: if (ugh != NULL)
! 976: {
! 977: DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh);
! 978: return FALSE;
! 979: }
! 980: }
! 981: if (secret.len == 7 && strpfx(secret.ptr, "%prompt"))
! 982: {
! 983: callback_cred_t *cb;
! 984: passphrase_cb_data_t pp_data = {
! 985: .prompt = prompt,
! 986: .type = type,
! 987: .path = path,
! 988: .try = 0,
! 989: };
! 990:
! 991: free(secret.ptr);
! 992: if (!prompt)
! 993: {
! 994: *result = NULL;
! 995: return TRUE;
! 996: }
! 997: /* add cache first so if valid passphrases are needed multiple times
! 998: * the callback is not called anymore */
! 999: pp_data.cache = mem_cred_create();
! 1000: lib->credmgr->add_local_set(lib->credmgr, &pp_data.cache->set, FALSE);
! 1001: /* use callback credential set to prompt for the passphrase */
! 1002: cb = callback_cred_create_shared((void*)passphrase_cb, &pp_data);
! 1003: lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
! 1004:
! 1005: *result = lib->creds->create(lib->creds, type, subtype,
! 1006: BUILD_FROM_FILE, path, BUILD_END);
! 1007:
! 1008: lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
! 1009: cb->destroy(cb);
! 1010: lib->credmgr->remove_local_set(lib->credmgr, &pp_data.cache->set);
! 1011: pp_data.cache->destroy(pp_data.cache);
! 1012: }
! 1013: else
! 1014: {
! 1015: mem_cred_t *mem = NULL;
! 1016: shared_key_t *shared;
! 1017:
! 1018: /* provide our pin in a temporary credential set */
! 1019: shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret);
! 1020: mem = mem_cred_create();
! 1021: mem->add_shared(mem, shared, NULL);
! 1022: if (eat_whitespace(&line))
! 1023: { /* if there is a second passphrase add that too, could be needed for
! 1024: * PKCS#12 files using different passwords for MAC and encryption */
! 1025: ugh = extract_secret(&secret, &line);
! 1026: if (ugh != NULL)
! 1027: {
! 1028: DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh);
! 1029: mem->destroy(mem);
! 1030: return FALSE;
! 1031: }
! 1032: shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret);
! 1033: mem->add_shared(mem, shared, NULL);
! 1034: }
! 1035: lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
! 1036:
! 1037: *result = lib->creds->create(lib->creds, type, subtype,
! 1038: BUILD_FROM_FILE, path, BUILD_END);
! 1039:
! 1040: lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
! 1041: mem->destroy(mem);
! 1042: }
! 1043: return TRUE;
! 1044: }
! 1045:
! 1046: /**
! 1047: * Load a private key
! 1048: */
! 1049: static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
! 1050: FILE *prompt, key_type_t key_type)
! 1051: {
! 1052: char path[PATH_MAX];
! 1053: private_key_t *key;
! 1054:
! 1055: if (!load_from_file(line, line_nr, prompt, path, CRED_PRIVATE_KEY,
! 1056: key_type, (void**)&key))
! 1057: {
! 1058: return FALSE;
! 1059: }
! 1060: if (key)
! 1061: {
! 1062: DBG1(DBG_CFG, " loaded %N private key from '%s'",
! 1063: key_type_names, key->get_type(key), path);
! 1064: secrets->add_key(secrets, key);
! 1065: }
! 1066: else
! 1067: {
! 1068: DBG1(DBG_CFG, " loading private key from '%s' failed", path);
! 1069: }
! 1070: return TRUE;
! 1071: }
! 1072:
! 1073: /**
! 1074: * Load a PKCS#12 container
! 1075: */
! 1076: static bool load_pkcs12(private_stroke_cred_t *this, mem_cred_t *secrets,
! 1077: chunk_t line, int line_nr, FILE *prompt)
! 1078: {
! 1079: enumerator_t *enumerator;
! 1080: char path[PATH_MAX];
! 1081: certificate_t *cert;
! 1082: private_key_t *key;
! 1083: pkcs12_t *pkcs12;
! 1084:
! 1085: if (!load_from_file(line, line_nr, prompt, path, CRED_CONTAINER,
! 1086: CONTAINER_PKCS12, (void**)&pkcs12))
! 1087: {
! 1088: return FALSE;
! 1089: }
! 1090: if (!pkcs12)
! 1091: {
! 1092: DBG1(DBG_CFG, " loading credentials from '%s' failed", path);
! 1093: return TRUE;
! 1094: }
! 1095: enumerator = pkcs12->create_cert_enumerator(pkcs12);
! 1096: while (enumerator->enumerate(enumerator, &cert))
! 1097: {
! 1098: x509_t *x509 = (x509_t*)cert;
! 1099:
! 1100: if (x509->get_flags(x509) & X509_CA)
! 1101: {
! 1102: DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
! 1103: cert->get_subject(cert), path);
! 1104: }
! 1105: else
! 1106: {
! 1107: DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
! 1108: cert->get_subject(cert), path);
! 1109: }
! 1110: this->creds->add_cert(this->creds, TRUE, cert->get_ref(cert));
! 1111: }
! 1112: enumerator->destroy(enumerator);
! 1113: enumerator = pkcs12->create_key_enumerator(pkcs12);
! 1114: while (enumerator->enumerate(enumerator, &key))
! 1115: {
! 1116: DBG1(DBG_CFG, " loaded %N private key from '%s'",
! 1117: key_type_names, key->get_type(key), path);
! 1118: secrets->add_key(secrets, key->get_ref(key));
! 1119: }
! 1120: enumerator->destroy(enumerator);
! 1121: pkcs12->container.destroy(&pkcs12->container);
! 1122: return TRUE;
! 1123: }
! 1124:
! 1125: /**
! 1126: * Load a shared key
! 1127: */
! 1128: static bool load_shared(mem_cred_t *secrets, chunk_t line, int line_nr,
! 1129: shared_key_type_t type, chunk_t ids)
! 1130: {
! 1131: shared_key_t *shared_key;
! 1132: linked_list_t *owners;
! 1133: chunk_t secret = chunk_empty;
! 1134:
! 1135: err_t ugh = extract_secret(&secret, &line);
! 1136: if (ugh != NULL)
! 1137: {
! 1138: DBG1(DBG_CFG, "line %d: malformed secret: %s", line_nr, ugh);
! 1139: return FALSE;
! 1140: }
! 1141: shared_key = shared_key_create(type, secret);
! 1142: DBG1(DBG_CFG, " loaded %N secret for %s", shared_key_type_names, type,
! 1143: ids.len > 0 ? (char*)ids.ptr : "%any");
! 1144: DBG4(DBG_CFG, " secret: %#B", &secret);
! 1145:
! 1146: owners = linked_list_create();
! 1147: while (ids.len > 0)
! 1148: {
! 1149: chunk_t id;
! 1150:
! 1151: ugh = extract_value(&id, &ids);
! 1152: if (ugh != NULL)
! 1153: {
! 1154: DBG1(DBG_CFG, "line %d: %s", line_nr, ugh);
! 1155: shared_key->destroy(shared_key);
! 1156: owners->destroy_offset(owners, offsetof(identification_t, destroy));
! 1157: return FALSE;
! 1158: }
! 1159: if (id.len == 0)
! 1160: {
! 1161: continue;
! 1162: }
! 1163:
! 1164: /* NULL terminate the ID string */
! 1165: *(id.ptr + id.len) = '\0';
! 1166: owners->insert_last(owners, identification_create_from_string(id.ptr));
! 1167: }
! 1168: if (!owners->get_count(owners))
! 1169: {
! 1170: owners->insert_last(owners,
! 1171: identification_create_from_encoding(ID_ANY, chunk_empty));
! 1172: }
! 1173: secrets->add_shared_list(secrets, shared_key, owners);
! 1174: return TRUE;
! 1175: }
! 1176:
! 1177: /**
! 1178: * reload ipsec.secrets
! 1179: */
! 1180: static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
! 1181: char *file, int level, FILE *prompt)
! 1182: {
! 1183: int line_nr = 0;
! 1184: chunk_t *src, line;
! 1185:
! 1186: DBG1(DBG_CFG, "loading secrets from '%s'", file);
! 1187: src = chunk_map(file, FALSE);
! 1188: if (!src)
! 1189: {
! 1190: DBG1(DBG_CFG, "opening secrets file '%s' failed: %s", file,
! 1191: strerror(errno));
! 1192: return;
! 1193: }
! 1194:
! 1195: if (!secrets)
! 1196: {
! 1197: secrets = mem_cred_create();
! 1198: }
! 1199:
! 1200: while (fetchline(src, &line))
! 1201: {
! 1202: chunk_t ids, token;
! 1203: key_type_t key_type;
! 1204: shared_key_type_t type;
! 1205:
! 1206: line_nr++;
! 1207:
! 1208: if (!eat_whitespace(&line))
! 1209: {
! 1210: continue;
! 1211: }
! 1212: if (line.len > strlen("include ") && strpfx(line.ptr, "include "))
! 1213: {
! 1214: char **expanded, *dir, pattern[PATH_MAX];
! 1215: u_char *pos;
! 1216:
! 1217: if (level > MAX_SECRETS_RECURSION)
! 1218: {
! 1219: DBG1(DBG_CFG, "maximum level of %d includes reached, ignored",
! 1220: MAX_SECRETS_RECURSION);
! 1221: continue;
! 1222: }
! 1223: /* terminate filename by space */
! 1224: line = chunk_skip(line, strlen("include "));
! 1225: pos = memchr(line.ptr, ' ', line.len);
! 1226: if (pos)
! 1227: {
! 1228: line.len = pos - line.ptr;
! 1229: }
! 1230: if (line.len && line.ptr[0] == '/')
! 1231: {
! 1232: if (line.len + 1 > sizeof(pattern))
! 1233: {
! 1234: DBG1(DBG_CFG, "include pattern too long, ignored");
! 1235: continue;
! 1236: }
! 1237: snprintf(pattern, sizeof(pattern), "%.*s",
! 1238: (int)line.len, line.ptr);
! 1239: }
! 1240: else
! 1241: { /* use directory of current file if relative */
! 1242: dir = path_dirname(file);
! 1243:
! 1244: if (line.len + 1 + strlen(dir) + 1 > sizeof(pattern))
! 1245: {
! 1246: DBG1(DBG_CFG, "include pattern too long, ignored");
! 1247: free(dir);
! 1248: continue;
! 1249: }
! 1250: snprintf(pattern, sizeof(pattern), "%s/%.*s",
! 1251: dir, (int)line.len, line.ptr);
! 1252: free(dir);
! 1253: }
! 1254: #ifdef HAVE_GLOB_H
! 1255: {
! 1256: glob_t buf;
! 1257: if (glob(pattern, GLOB_ERR, NULL, &buf) != 0)
! 1258: {
! 1259: DBG1(DBG_CFG, "expanding file expression '%s' failed",
! 1260: pattern);
! 1261: }
! 1262: else
! 1263: {
! 1264: for (expanded = buf.gl_pathv; *expanded != NULL; expanded++)
! 1265: {
! 1266: load_secrets(this, secrets, *expanded, level + 1,
! 1267: prompt);
! 1268: }
! 1269: }
! 1270: globfree(&buf);
! 1271: }
! 1272: #else /* HAVE_GLOB_H */
! 1273: /* if glob(3) is not available, try to load pattern directly */
! 1274: load_secrets(this, secrets, pattern, level + 1, prompt);
! 1275: #endif /* HAVE_GLOB_H */
! 1276: continue;
! 1277: }
! 1278:
! 1279: if (line.len > 2 && strpfx(line.ptr, ": "))
! 1280: {
! 1281: /* no ids, skip the ':' */
! 1282: ids = chunk_empty;
! 1283: line.ptr++;
! 1284: line.len--;
! 1285: }
! 1286: else if (extract_token_str(&ids, " : ", &line))
! 1287: {
! 1288: /* NULL terminate the extracted id string */
! 1289: *(ids.ptr + ids.len) = '\0';
! 1290: }
! 1291: else
! 1292: {
! 1293: DBG1(DBG_CFG, "line %d: missing ' : ' separator", line_nr);
! 1294: break;
! 1295: }
! 1296:
! 1297: if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
! 1298: {
! 1299: DBG1(DBG_CFG, "line %d: missing token", line_nr);
! 1300: break;
! 1301: }
! 1302: if (match("RSA", &token) || match("ECDSA", &token) ||
! 1303: match("BLISS", &token) || match("PKCS8", &token))
! 1304: {
! 1305: if (match("RSA", &token))
! 1306: {
! 1307: key_type = KEY_RSA;
! 1308: }
! 1309: else if (match("ECDSA", &token))
! 1310: {
! 1311: key_type = KEY_ECDSA;
! 1312: }
! 1313: else if (match("BLISS", &token))
! 1314: {
! 1315: key_type = KEY_BLISS;
! 1316: }
! 1317: else
! 1318: {
! 1319: key_type = KEY_ANY;
! 1320: }
! 1321: if (!load_private(secrets, line, line_nr, prompt, key_type))
! 1322: {
! 1323: break;
! 1324: }
! 1325: }
! 1326: else if (match("P12", &token))
! 1327: {
! 1328: if (!load_pkcs12(this, secrets, line, line_nr, prompt))
! 1329: {
! 1330: break;
! 1331: }
! 1332: }
! 1333: else if (match("PIN", &token))
! 1334: {
! 1335: if (!load_pin(secrets, line, line_nr, prompt))
! 1336: {
! 1337: break;
! 1338: }
! 1339: }
! 1340: else if ((match("PSK", &token) && (type = SHARED_IKE)) ||
! 1341: (match("EAP", &token) && (type = SHARED_EAP)) ||
! 1342: (match("NTLM", &token) && (type = SHARED_NT_HASH)) ||
! 1343: (match("XAUTH", &token) && (type = SHARED_EAP)))
! 1344: {
! 1345: if (!load_shared(secrets, line, line_nr, type, ids))
! 1346: {
! 1347: break;
! 1348: }
! 1349: }
! 1350: else
! 1351: {
! 1352: DBG1(DBG_CFG, "line %d: token must be either RSA, ECDSA, BLISS, "
! 1353: "PKCS8 P12, PIN, PSK, EAP, XAUTH or NTLM", line_nr);
! 1354: break;
! 1355: }
! 1356: }
! 1357: chunk_unmap(src);
! 1358:
! 1359: if (level == 0)
! 1360: { /* replace secrets in active credential set */
! 1361: this->creds->replace_secrets(this->creds, secrets, FALSE);
! 1362: secrets->destroy(secrets);
! 1363: }
! 1364: }
! 1365:
! 1366: /**
! 1367: * load all certificates from ipsec.d
! 1368: */
! 1369: static void load_certs(private_stroke_cred_t *this)
! 1370: {
! 1371: mem_cred_t *creds;
! 1372:
! 1373: DBG1(DBG_CFG, "loading ca certificates from '%s'",
! 1374: CA_CERTIFICATE_DIR);
! 1375: creds = mem_cred_create();
! 1376: load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA, creds);
! 1377: this->ca->replace_certs(this->ca, creds);
! 1378: creds->destroy(creds);
! 1379:
! 1380: DBG1(DBG_CFG, "loading aa certificates from '%s'",
! 1381: AA_CERTIFICATE_DIR);
! 1382: load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA, this->aacerts);
! 1383:
! 1384: DBG1(DBG_CFG, "loading ocsp signer certificates from '%s'",
! 1385: OCSP_CERTIFICATE_DIR);
! 1386: load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509, X509_OCSP_SIGNER,
! 1387: this->creds);
! 1388:
! 1389: DBG1(DBG_CFG, "loading attribute certificates from '%s'",
! 1390: ATTR_CERTIFICATE_DIR);
! 1391: load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0, this->creds);
! 1392:
! 1393: DBG1(DBG_CFG, "loading crls from '%s'",
! 1394: CRL_DIR);
! 1395: load_certdir(this, CRL_DIR, CERT_X509_CRL, 0, this->creds);
! 1396: }
! 1397:
! 1398: METHOD(stroke_cred_t, reread, void,
! 1399: private_stroke_cred_t *this, stroke_msg_t *msg, FILE *prompt)
! 1400: {
! 1401: mem_cred_t *creds;
! 1402:
! 1403: if (msg->reread.flags & REREAD_SECRETS)
! 1404: {
! 1405: DBG1(DBG_CFG, "rereading secrets");
! 1406: load_secrets(this, NULL, this->secrets_file, 0, prompt);
! 1407: }
! 1408: if (msg->reread.flags & REREAD_CACERTS)
! 1409: {
! 1410: /* first reload certificates in ca sections, so we can refer to them */
! 1411: this->ca->reload_certs(this->ca);
! 1412:
! 1413: DBG1(DBG_CFG, "rereading ca certificates from '%s'",
! 1414: CA_CERTIFICATE_DIR);
! 1415: creds = mem_cred_create();
! 1416: load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA, creds);
! 1417: this->ca->replace_certs(this->ca, creds);
! 1418: creds->destroy(creds);
! 1419: }
! 1420: if (msg->reread.flags & REREAD_AACERTS)
! 1421: {
! 1422: DBG1(DBG_CFG, "rereading aa certificates from '%s'",
! 1423: AA_CERTIFICATE_DIR);
! 1424: creds = mem_cred_create();
! 1425: load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA, creds);
! 1426: this->aacerts->replace_certs(this->aacerts, creds, FALSE);
! 1427: creds->destroy(creds);
! 1428: lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
! 1429: }
! 1430: if (msg->reread.flags & REREAD_OCSPCERTS)
! 1431: {
! 1432: DBG1(DBG_CFG, "rereading ocsp signer certificates from '%s'",
! 1433: OCSP_CERTIFICATE_DIR);
! 1434: load_certdir(this, OCSP_CERTIFICATE_DIR, CERT_X509,
! 1435: X509_OCSP_SIGNER, this->creds);
! 1436: }
! 1437: if (msg->reread.flags & REREAD_ACERTS)
! 1438: {
! 1439: DBG1(DBG_CFG, "rereading attribute certificates from '%s'",
! 1440: ATTR_CERTIFICATE_DIR);
! 1441: load_certdir(this, ATTR_CERTIFICATE_DIR, CERT_X509_AC, 0, this->creds);
! 1442: }
! 1443: if (msg->reread.flags & REREAD_CRLS)
! 1444: {
! 1445: DBG1(DBG_CFG, "rereading crls from '%s'",
! 1446: CRL_DIR);
! 1447: load_certdir(this, CRL_DIR, CERT_X509_CRL, 0, this->creds);
! 1448: }
! 1449: }
! 1450:
! 1451: METHOD(stroke_cred_t, add_shared, void,
! 1452: private_stroke_cred_t *this, shared_key_t *shared, linked_list_t *owners)
! 1453: {
! 1454: this->creds->add_shared_list(this->creds, shared, owners);
! 1455: }
! 1456:
! 1457: METHOD(stroke_cred_t, destroy, void,
! 1458: private_stroke_cred_t *this)
! 1459: {
! 1460: lib->credmgr->remove_set(lib->credmgr, &this->aacerts->set);
! 1461: lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
! 1462: this->aacerts->destroy(this->aacerts);
! 1463: this->creds->destroy(this->creds);
! 1464: free(this);
! 1465: }
! 1466:
! 1467: /*
! 1468: * see header file
! 1469: */
! 1470: stroke_cred_t *stroke_cred_create(stroke_ca_t *ca)
! 1471: {
! 1472: private_stroke_cred_t *this;
! 1473:
! 1474: INIT(this,
! 1475: .public = {
! 1476: .set = {
! 1477: .create_private_enumerator = (void*)return_null,
! 1478: .create_cert_enumerator = (void*)return_null,
! 1479: .create_shared_enumerator = (void*)return_null,
! 1480: .create_cdp_enumerator = (void*)return_null,
! 1481: .cache_cert = (void*)_cache_cert,
! 1482: },
! 1483: .reread = _reread,
! 1484: .load_peer = _load_peer,
! 1485: .load_pubkey = _load_pubkey,
! 1486: .add_shared = _add_shared,
! 1487: .cachecrl = _cachecrl,
! 1488: .destroy = _destroy,
! 1489: },
! 1490: .secrets_file = lib->settings->get_str(lib->settings,
! 1491: "%s.plugins.stroke.secrets_file", SECRETS_FILE,
! 1492: lib->ns),
! 1493: .creds = mem_cred_create(),
! 1494: .aacerts = mem_cred_create(),
! 1495: .ca = ca,
! 1496: );
! 1497:
! 1498: if (lib->settings->get_bool(lib->settings, "%s.cache_crls", FALSE, lib->ns))
! 1499: {
! 1500: cachecrl(this, TRUE);
! 1501: }
! 1502: lib->credmgr->add_set(lib->credmgr, &this->creds->set);
! 1503: lib->credmgr->add_set(lib->credmgr, &this->aacerts->set);
! 1504:
! 1505: this->force_ca_cert = lib->settings->get_bool(lib->settings,
! 1506: "%s.plugins.stroke.ignore_missing_ca_basic_constraint",
! 1507: FALSE, lib->ns);
! 1508:
! 1509: load_certs(this);
! 1510: load_secrets(this, NULL, this->secrets_file, 0, NULL);
! 1511:
! 1512: return &this->public;
! 1513: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>