Return to vici_cred.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / vici |
1.1 misho 1: /* 2: * Copyright (C) 2015-2016 Andreas Steffen 3: * Copyright (C) 2016-2017 Tobias Brunner 4: * HSR Hochschule fuer Technik Rapperswil 5: * 6: * Copyright (C) 2014 Martin Willi 7: * Copyright (C) 2014 revosec AG 8: * 9: * 10: * This program is free software; you can redistribute it and/or modify it 11: * under the terms of the GNU General Public License as published by the 12: * Free Software Foundation; either version 2 of the License, or (at your 13: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. 14: * 15: * This program is distributed in the hope that it will be useful, but 16: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18: * for more details. 19: */ 20: 21: #include "vici_cred.h" 22: #include "vici_builder.h" 23: #include "vici_cert_info.h" 24: 25: #include <credentials/sets/mem_cred.h> 26: #include <credentials/certificates/ac.h> 27: #include <credentials/certificates/crl.h> 28: #include <credentials/certificates/x509.h> 29: 30: #include <errno.h> 31: 32: typedef struct private_vici_cred_t private_vici_cred_t; 33: 34: /** 35: * Directory for saved X.509 CRLs 36: */ 37: #define CRL_DIR SWANCTLDIR "/x509crl" 38: 39: /** 40: * Private data of an vici_cred_t object. 41: */ 42: struct private_vici_cred_t { 43: 44: /** 45: * Public vici_cred_t interface. 46: */ 47: vici_cred_t public; 48: 49: /** 50: * Dispatcher 51: */ 52: vici_dispatcher_t *dispatcher; 53: 54: /** 1.1.1.2 ! misho 55: * CA certificate store ! 56: */ ! 57: vici_authority_t *authority; ! 58: ! 59: /** 1.1 misho 60: * credentials 61: */ 62: mem_cred_t *creds; 63: 64: /** 65: * separate credential set for token PINs 66: */ 67: mem_cred_t *pins; 68: 69: /** 70: * cache CRLs to disk? 71: */ 72: bool cachecrl; 73: 74: }; 75: 76: METHOD(credential_set_t, cache_cert, void, 77: private_vici_cred_t *this, certificate_t *cert) 78: { 79: if (cert->get_type(cert) == CERT_X509_CRL && this->cachecrl) 80: { 81: /* CRLs get written to /etc/swanctl/x509crl/<authkeyId>.crl */ 82: crl_t *crl = (crl_t*)cert; 83: 84: cert->get_ref(cert); 85: if (this->creds->add_crl(this->creds, crl)) 86: { 87: char buf[BUF_LEN]; 88: chunk_t chunk, hex; 89: bool is_delta_crl; 90: 91: is_delta_crl = crl->is_delta_crl(crl, NULL); 92: chunk = crl->get_authKeyIdentifier(crl); 93: hex = chunk_to_hex(chunk, NULL, FALSE); 94: snprintf(buf, sizeof(buf), "%s/%s%s.crl", CRL_DIR, hex.ptr, 95: is_delta_crl ? "_delta" : ""); 96: free(hex.ptr); 97: 98: if (cert->get_encoding(cert, CERT_ASN1_DER, &chunk)) 99: { 100: if (chunk_write(chunk, buf, 022, TRUE)) 101: { 102: DBG1(DBG_CFG, " written crl file '%s' (%d bytes)", 103: buf, chunk.len); 104: } 105: else 106: { 107: DBG1(DBG_CFG, " writing crl file '%s' failed: %s", 108: buf, strerror(errno)); 109: } 110: free(chunk.ptr); 111: } 112: } 113: } 114: } 115: 116: /** 117: * Create a (error) reply message 118: */ 119: static vici_message_t* create_reply(char *fmt, ...) 120: { 121: vici_builder_t *builder; 122: va_list args; 123: 124: builder = vici_builder_create(); 125: builder->add_kv(builder, "success", fmt ? "no" : "yes"); 126: if (fmt) 127: { 128: va_start(args, fmt); 129: builder->vadd_kv(builder, "errmsg", fmt, args); 130: va_end(args); 131: } 132: return builder->finalize(builder); 133: } 134: 135: CALLBACK(load_cert, vici_message_t*, 136: private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) 137: { 138: certificate_t *cert; 139: certificate_type_t type; 140: x509_flag_t ext_flag, flag = X509_NONE; 141: x509_t *x509; 142: chunk_t data; 143: char *str; 144: 145: str = message->get_str(message, NULL, "type"); 146: if (!str) 147: { 148: return create_reply("certificate type missing"); 149: } 150: if (enum_from_name(certificate_type_names, str, &type)) 151: { 152: if (type == CERT_X509) 153: { 154: str = message->get_str(message, "NONE", "flag"); 155: if (!enum_from_name(x509_flag_names, str, &flag)) 156: { 157: return create_reply("invalid certificate flag '%s'", str); 158: } 159: } 160: } 161: else if (!vici_cert_info_from_str(str, &type, &flag)) 162: { 163: return create_reply("invalid certificate type '%s'", str); 164: } 165: 166: data = message->get_value(message, chunk_empty, "data"); 167: if (!data.len) 168: { 169: return create_reply("certificate data missing"); 170: } 171: 172: /* do not set CA flag externally */ 173: ext_flag = (flag & X509_CA) ? X509_NONE : flag; 174: 175: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, type, 176: BUILD_BLOB_PEM, data, 177: BUILD_X509_FLAG, ext_flag, 178: BUILD_END); 179: if (!cert) 180: { 181: return create_reply("parsing %N certificate failed", 182: certificate_type_names, type); 183: } 184: DBG1(DBG_CFG, "loaded certificate '%Y'", cert->get_subject(cert)); 185: 1.1.1.2 ! misho 186: if (type == CERT_X509) 1.1 misho 187: { 188: x509 = (x509_t*)cert; 1.1.1.2 ! misho 189: if (x509->get_flags(x509) & X509_CA) 1.1 misho 190: { 1.1.1.2 ! misho 191: cert = this->authority->add_ca_cert(this->authority, cert); 1.1 misho 192: cert->destroy(cert); 1.1.1.2 ! misho 193: return create_reply(NULL); ! 194: } ! 195: else if (flag & X509_CA) ! 196: { ! 197: char msg[] = "ca certificate lacks CA basic constraint, rejected"; ! 198: cert->destroy(cert); ! 199: DBG1(DBG_CFG, " %s", msg); ! 200: return create_reply(msg); 1.1 misho 201: } 202: } 1.1.1.2 ! misho 203: 1.1 misho 204: if (type == CERT_X509_CRL) 205: { 206: this->creds->add_crl(this->creds, (crl_t*)cert); 207: } 208: else 209: { 1.1.1.2 ! misho 210: this->creds->add_cert(this->creds, type != CERT_X509_AC, cert); 1.1 misho 211: } 212: return create_reply(NULL); 213: } 214: 215: CALLBACK(load_key, vici_message_t*, 216: private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) 217: { 218: vici_builder_t *builder; 219: key_type_t type; 220: private_key_t *key; 221: chunk_t data, fp; 222: char *str; 223: 224: str = message->get_str(message, NULL, "type"); 225: if (!str) 226: { 227: return create_reply("key type missing"); 228: } 1.1.1.2 ! misho 229: if (!enum_from_name(key_type_names, str, &type)) 1.1 misho 230: { 231: return create_reply("invalid key type: %s", str); 232: } 233: data = message->get_value(message, chunk_empty, "data"); 234: if (!data.len) 235: { 236: return create_reply("key data missing"); 237: } 238: key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, 239: BUILD_BLOB_PEM, data, BUILD_END); 240: if (!key) 241: { 242: return create_reply("parsing %N private key failed", 243: key_type_names, type); 244: } 245: if (!key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp)) 246: { 247: return create_reply("failed to get key id"); 248: } 249: 250: DBG1(DBG_CFG, "loaded %N private key", key_type_names, type); 251: 252: builder = vici_builder_create(); 253: builder->add_kv(builder, "success", "yes"); 254: builder->add_kv(builder, "id", "%+B", &fp); 255: this->creds->add_key(this->creds, key); 256: 257: return builder->finalize(builder); 258: } 259: 260: CALLBACK(unload_key, vici_message_t*, 261: private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) 262: { 263: chunk_t keyid; 264: char buf[BUF_LEN], *hex, *msg = NULL; 265: 266: hex = message->get_str(message, NULL, "id"); 267: if (!hex) 268: { 269: return create_reply("key id missing"); 270: } 271: keyid = chunk_from_hex(chunk_from_str(hex), NULL); 272: snprintf(buf, sizeof(buf), "%+B", &keyid); 273: DBG1(DBG_CFG, "unloaded private key with id %s", buf); 274: if (this->creds->remove_key(this->creds, keyid)) 275: { /* also remove any potential PIN associated with this id */ 276: this->pins->remove_shared_unique(this->pins, buf); 277: } 278: else 279: { 280: msg = "key not found"; 281: } 282: chunk_free(&keyid); 283: return create_reply(msg); 284: } 285: 286: CALLBACK(get_keys, vici_message_t*, 287: private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) 288: { 289: vici_builder_t *builder; 290: enumerator_t *enumerator; 291: private_key_t *private; 292: chunk_t keyid; 293: 294: builder = vici_builder_create(); 295: builder->begin_list(builder, "keys"); 296: 297: enumerator = this->creds->set.create_private_enumerator(&this->creds->set, 298: KEY_ANY, NULL); 299: while (enumerator->enumerate(enumerator, &private)) 300: { 301: if (private->get_fingerprint(private, KEYID_PUBKEY_SHA1, &keyid)) 302: { 303: builder->add_li(builder, "%+B", &keyid); 304: } 305: } 306: enumerator->destroy(enumerator); 307: 308: builder->end_list(builder); 309: return builder->finalize(builder); 310: } 311: 312: CALLBACK(load_token, vici_message_t*, 313: private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) 314: { 315: vici_builder_t *builder; 316: private_key_t *key; 317: shared_key_t *shared = NULL; 318: identification_t *owner; 319: mem_cred_t *set = NULL; 320: chunk_t handle, fp; 321: char buf[BUF_LEN], *hex, *module, *pin, *unique = NULL; 322: int slot; 323: 324: hex = message->get_str(message, NULL, "handle"); 325: if (!hex) 326: { 327: return create_reply("keyid missing"); 328: } 329: handle = chunk_from_hex(chunk_from_str(hex), NULL); 330: slot = message->get_int(message, -1, "slot"); 331: module = message->get_str(message, NULL, "module"); 332: pin = message->get_str(message, NULL, "pin"); 333: 334: if (pin) 335: { /* provide the pin in a temporary credential set to access the key */ 336: shared = shared_key_create(SHARED_PIN, chunk_clone(chunk_from_str(pin))); 337: owner = identification_create_from_encoding(ID_KEY_ID, handle); 338: set = mem_cred_create(); 339: set->add_shared(set, shared->get_ref(shared), owner, NULL); 340: lib->credmgr->add_local_set(lib->credmgr, &set->set, FALSE); 341: } 342: if (slot >= 0) 343: { 344: key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY, 345: BUILD_PKCS11_KEYID, handle, 346: BUILD_PKCS11_SLOT, slot, 347: module ? BUILD_PKCS11_MODULE : BUILD_END, module, 348: BUILD_END); 349: } 350: else 351: { 352: key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY, 353: BUILD_PKCS11_KEYID, handle, 354: module ? BUILD_PKCS11_MODULE : BUILD_END, module, 355: BUILD_END); 356: } 357: if (set) 358: { 359: lib->credmgr->remove_local_set(lib->credmgr, &set->set); 360: set->destroy(set); 361: } 362: if (!key) 363: { 364: chunk_free(&handle); 365: DESTROY_IF(shared); 366: return create_reply("loading private key from token failed"); 367: } 368: builder = vici_builder_create(); 369: builder->add_kv(builder, "success", "yes"); 370: if (key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp)) 371: { 372: snprintf(buf, sizeof(buf), "%+B", &fp); 373: builder->add_kv(builder, "id", "%s", buf); 374: unique = buf; 375: } 376: if (shared && unique) 377: { /* use the handle as owner, but the key identifier as unique ID */ 378: owner = identification_create_from_encoding(ID_KEY_ID, handle); 379: this->pins->add_shared_unique(this->pins, unique, shared, 380: linked_list_create_with_items(owner, NULL)); 381: } 382: else 383: { 384: DESTROY_IF(shared); 385: } 386: DBG1(DBG_CFG, "loaded %N private key from token", key_type_names, 387: key->get_type(key)); 388: this->creds->add_key(this->creds, key); 389: chunk_free(&handle); 390: return builder->finalize(builder); 391: } 392: 393: CALLBACK(shared_owners, bool, 394: linked_list_t *owners, vici_message_t *message, char *name, chunk_t value) 395: { 396: if (streq(name, "owners")) 397: { 398: char buf[256]; 399: 400: if (!vici_stringify(value, buf, sizeof(buf))) 401: { 402: return FALSE; 403: } 404: owners->insert_last(owners, identification_create_from_string(buf)); 405: } 406: return TRUE; 407: } 408: 409: CALLBACK(load_shared, vici_message_t*, 410: private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) 411: { 412: shared_key_type_t type; 413: linked_list_t *owners; 414: chunk_t data; 415: char *unique, *str, buf[512] = ""; 416: enumerator_t *enumerator; 417: identification_t *owner; 418: int len; 419: 420: unique = message->get_str(message, NULL, "id"); 421: str = message->get_str(message, NULL, "type"); 422: if (!str) 423: { 424: return create_reply("shared key type missing"); 425: } 426: if (strcaseeq(str, "ike")) 427: { 428: type = SHARED_IKE; 429: } 430: else if (strcaseeq(str, "eap") || strcaseeq(str, "xauth")) 431: { 432: type = SHARED_EAP; 433: } 434: else if (strcaseeq(str, "ntlm")) 435: { 436: type = SHARED_NT_HASH; 437: } 438: else if (strcaseeq(str, "ppk")) 439: { 440: type = SHARED_PPK; 441: } 442: else 443: { 444: return create_reply("invalid shared key type: %s", str); 445: } 446: data = message->get_value(message, chunk_empty, "data"); 447: if (!data.len) 448: { 449: return create_reply("shared key data missing"); 450: } 451: 452: owners = linked_list_create(); 453: if (!message->parse(message, NULL, NULL, NULL, shared_owners, owners)) 454: { 455: owners->destroy_offset(owners, offsetof(identification_t, destroy)); 456: return create_reply("parsing shared key owners failed"); 457: } 458: if (owners->get_count(owners) == 0) 459: { 460: owners->insert_last(owners, identification_create_from_string("%any")); 461: } 462: 463: enumerator = owners->create_enumerator(owners); 464: while (enumerator->enumerate(enumerator, &owner)) 465: { 466: len = strlen(buf); 467: if (len < sizeof(buf)) 468: { 469: snprintf(buf + len, sizeof(buf) - len, "%s'%Y'", 470: len ? ", " : "", owner); 471: } 472: } 473: enumerator->destroy(enumerator); 474: 475: if (unique) 476: { 477: DBG1(DBG_CFG, "loaded %N shared key with id '%s' for: %s", 478: shared_key_type_names, type, unique, buf); 479: } 480: else 481: { 482: DBG1(DBG_CFG, "loaded %N shared key for: %s", 483: shared_key_type_names, type, buf); 484: } 485: 486: this->creds->add_shared_unique(this->creds, unique, 487: shared_key_create(type, chunk_clone(data)), owners); 488: 489: return create_reply(NULL); 490: } 491: 492: CALLBACK(unload_shared, vici_message_t*, 493: private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) 494: { 495: char *unique; 496: 497: unique = message->get_str(message, NULL, "id"); 498: if (!unique) 499: { 500: return create_reply("unique identifier missing"); 501: } 502: DBG1(DBG_CFG, "unloaded shared key with id '%s'", unique); 503: this->creds->remove_shared_unique(this->creds, unique); 504: return create_reply(NULL); 505: } 506: 507: CALLBACK(get_shared, vici_message_t*, 508: private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) 509: { 510: vici_builder_t *builder; 511: enumerator_t *enumerator; 512: char *unique; 513: 514: builder = vici_builder_create(); 515: builder->begin_list(builder, "keys"); 516: 517: enumerator = this->creds->create_unique_shared_enumerator(this->creds); 518: while (enumerator->enumerate(enumerator, &unique)) 519: { 520: builder->add_li(builder, "%s", unique); 521: } 522: enumerator->destroy(enumerator); 523: 524: builder->end_list(builder); 525: return builder->finalize(builder); 526: } 527: 528: CALLBACK(clear_creds, vici_message_t*, 529: private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) 530: { 531: this->creds->clear(this->creds); 1.1.1.2 ! misho 532: this->authority->clear_ca_certs(this->authority); 1.1 misho 533: lib->credmgr->flush_cache(lib->credmgr, CERT_ANY); 534: 535: return create_reply(NULL); 536: } 537: 538: CALLBACK(flush_certs, vici_message_t*, 539: private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) 540: { 541: certificate_type_t type = CERT_ANY; 542: x509_flag_t flag = X509_NONE; 543: char *str; 544: 545: str = message->get_str(message, NULL, "type"); 546: if (str && !enum_from_name(certificate_type_names, str, &type) && 547: !vici_cert_info_from_str(str, &type, &flag)) 548: { 549: return create_reply("invalid certificate type '%s'", str); 550: } 551: lib->credmgr->flush_cache(lib->credmgr, type); 552: 553: return create_reply(NULL); 554: } 555: 556: static void manage_command(private_vici_cred_t *this, 557: char *name, vici_command_cb_t cb, bool reg) 558: { 559: this->dispatcher->manage_command(this->dispatcher, name, 560: reg ? cb : NULL, this); 561: } 562: 563: /** 564: * (Un-)register dispatcher functions 565: */ 566: static void manage_commands(private_vici_cred_t *this, bool reg) 567: { 568: manage_command(this, "clear-creds", clear_creds, reg); 569: manage_command(this, "flush-certs", flush_certs, reg); 570: manage_command(this, "load-cert", load_cert, reg); 571: manage_command(this, "load-key", load_key, reg); 572: manage_command(this, "unload-key", unload_key, reg); 573: manage_command(this, "get-keys", get_keys, reg); 574: manage_command(this, "load-token", load_token, reg); 575: manage_command(this, "load-shared", load_shared, reg); 576: manage_command(this, "unload-shared", unload_shared, reg); 577: manage_command(this, "get-shared", get_shared, reg); 578: } 579: 580: METHOD(vici_cred_t, add_cert, certificate_t*, 581: private_vici_cred_t *this, certificate_t *cert) 582: { 583: return this->creds->add_cert_ref(this->creds, TRUE, cert); 584: } 585: 586: METHOD(vici_cred_t, destroy, void, 587: private_vici_cred_t *this) 588: { 589: manage_commands(this, FALSE); 590: 591: lib->credmgr->remove_set(lib->credmgr, &this->creds->set); 592: this->creds->destroy(this->creds); 593: lib->credmgr->remove_set(lib->credmgr, &this->pins->set); 594: this->pins->destroy(this->pins); 595: free(this); 596: } 597: 598: /** 599: * See header 600: */ 1.1.1.2 ! misho 601: vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher, ! 602: vici_authority_t *authority) 1.1 misho 603: { 604: private_vici_cred_t *this; 605: 606: INIT(this, 607: .public = { 608: .set = { 609: .create_private_enumerator = (void*)return_null, 610: .create_cert_enumerator = (void*)return_null, 611: .create_shared_enumerator = (void*)return_null, 612: .create_cdp_enumerator = (void*)return_null, 613: .cache_cert = (void*)_cache_cert, 614: }, 615: .add_cert = _add_cert, 616: .destroy = _destroy, 617: }, 618: .dispatcher = dispatcher, 1.1.1.2 ! misho 619: .authority = authority, 1.1 misho 620: .creds = mem_cred_create(), 621: .pins = mem_cred_create(), 622: ); 623: 624: if (lib->settings->get_bool(lib->settings, "%s.cache_crls", FALSE, lib->ns)) 625: { 626: this->cachecrl = TRUE; 627: DBG1(DBG_CFG, "crl caching to %s enabled", CRL_DIR); 628: } 629: lib->credmgr->add_set(lib->credmgr, &this->creds->set); 630: lib->credmgr->add_set(lib->credmgr, &this->pins->set); 631: 632: manage_commands(this, TRUE); 633: 634: return &this->public; 635: }