Return to vici_authority.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / vici |
1.1 misho 1: /* 2: * Copyright (C) 2016-2019 Tobias Brunner 3: * Copyright (C) 2015 Andreas Steffen 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: #define _GNU_SOURCE 18: 19: #include "vici_authority.h" 20: #include "vici_builder.h" 21: 22: #include <threading/rwlock.h> 23: #include <collections/linked_list.h> 24: #include <credentials/certificates/x509.h> 25: #include <utils/debug.h> 26: 27: #include <stdio.h> 28: 29: typedef struct private_vici_authority_t private_vici_authority_t; 30: 31: /** 32: * Private data of an vici_authority_t object. 33: */ 34: struct private_vici_authority_t { 35: 36: /** 37: * Public vici_authority_t interface. 38: */ 39: vici_authority_t public; 40: 41: /** 42: * Dispatcher 43: */ 44: vici_dispatcher_t *dispatcher; 45: 46: /** 47: * credential backend managed by VICI used for our ca certificates 48: */ 49: vici_cred_t *cred; 50: 51: /** 52: * List of certification authorities 53: */ 54: linked_list_t *authorities; 55: 56: /** 57: * rwlock to lock access to certification authorities 58: */ 59: rwlock_t *lock; 60: 61: }; 62: 63: typedef struct authority_t authority_t; 64: 65: /** 66: * loaded certification authorities 67: */ 68: struct authority_t { 69: 70: /** 71: * Name of the certification authority 72: */ 73: char *name; 74: 75: /** 76: * Reference to CA certificate 77: */ 78: certificate_t *cert; 79: 80: /** 81: * CRL URIs 82: */ 83: linked_list_t *crl_uris; 84: 85: /** 86: * OCSP URIs 87: */ 88: linked_list_t *ocsp_uris; 89: 90: /** 91: * Base URI used for certificates from this CA 92: */ 93: char *cert_uri_base; 94: }; 95: 96: /** 97: * create a new certification authority 98: */ 99: static authority_t *authority_create(char *name) 100: { 101: authority_t *authority; 102: 103: INIT(authority, 104: .name = strdup(name), 105: .crl_uris = linked_list_create(), 106: .ocsp_uris = linked_list_create(), 107: ); 108: 109: return authority; 110: } 111: 112: /** 113: * destroy a certification authority 114: */ 115: static void authority_destroy(authority_t *this) 116: { 117: this->crl_uris->destroy_function(this->crl_uris, free); 118: this->ocsp_uris->destroy_function(this->ocsp_uris, free); 119: DESTROY_IF(this->cert); 120: free(this->cert_uri_base); 121: free(this->name); 122: free(this); 123: } 124: 125: 126: /** 127: * Create a (error) reply message 128: */ 129: static vici_message_t* create_reply(char *fmt, ...) 130: { 131: vici_builder_t *builder; 132: va_list args; 133: 134: builder = vici_builder_create(); 135: builder->add_kv(builder, "success", fmt ? "no" : "yes"); 136: if (fmt) 137: { 138: va_start(args, fmt); 139: builder->vadd_kv(builder, "errmsg", fmt, args); 140: va_end(args); 141: } 142: return builder->finalize(builder); 143: } 144: 145: /** 146: * A rule to parse a key/value or list item 147: */ 148: typedef struct { 149: /** name of the key/value or list */ 150: char *name; 151: /** function to parse value */ 152: bool (*parse)(void *out, chunk_t value); 153: /** result, passed to parse() */ 154: void *out; 155: } parse_rule_t; 156: 157: /** 158: * Parse key/values using a rule-set 159: */ 160: static bool parse_rules(parse_rule_t *rules, int count, char *name, 161: chunk_t value, vici_message_t **reply) 162: { 163: int i; 164: 165: for (i = 0; i < count; i++) 166: { 167: if (streq(name, rules[i].name)) 168: { 169: if (rules[i].parse(rules[i].out, value)) 170: { 171: return TRUE; 172: } 173: *reply = create_reply("invalid value for: %s, authority discarded", 174: name); 175: return FALSE; 176: } 177: } 178: *reply = create_reply("unknown option: %s, authority discarded", name); 179: return FALSE; 180: } 181: 182: /** 183: * Parse callback data, passed to each callback 184: */ 185: typedef struct { 186: private_vici_authority_t *this; 187: vici_message_t *reply; 188: } request_data_t; 189: 190: /** 191: * Data associated with an authority load 192: */ 193: typedef struct { 194: request_data_t *request; 195: authority_t *authority; 196: char *handle; 197: uint32_t slot; 198: char *module; 199: char *file; 200: } load_data_t; 201: 202: /** 203: * Clean up data associated with an authority load 204: */ 205: static void free_load_data(load_data_t *data) 206: { 207: if (data->authority) 208: { 209: authority_destroy(data->authority); 210: } 211: free(data->handle); 212: free(data->module); 213: free(data->file); 214: free(data); 215: } 216: 217: /** 218: * Parse a string 219: */ 220: CALLBACK(parse_string, bool, 221: char **str, chunk_t v) 222: { 223: if (!chunk_printable(v, NULL, ' ')) 224: { 225: return FALSE; 226: } 227: *str = strndup(v.ptr, v.len); 228: 229: return TRUE; 230: } 231: 232: /** 233: * Parse a uint32_t 234: */ 235: CALLBACK(parse_uint32, bool, 236: uint32_t *out, chunk_t v) 237: { 238: char buf[16], *end; 239: u_long l; 240: 241: if (!vici_stringify(v, buf, sizeof(buf))) 242: { 243: return FALSE; 244: } 245: l = strtoul(buf, &end, 0); 246: if (*end == 0) 247: { 248: *out = l; 249: return TRUE; 250: } 251: return FALSE; 252: } 253: 254: /** 255: * Parse list of URIs 256: */ 257: CALLBACK(parse_uris, bool, 258: linked_list_t *out, chunk_t v) 259: { 260: char *uri; 261: 262: if (!chunk_printable(v, NULL, ' ')) 263: { 264: return FALSE; 265: } 266: uri = strndup(v.ptr, v.len); 267: out->insert_last(out, uri); 268: 269: return TRUE; 270: } 271: 272: /** 273: * Parse a CA certificate 274: */ 275: CALLBACK(parse_cacert, bool, 276: certificate_t **cacert, chunk_t v) 277: { 278: certificate_t *cert; 279: x509_t *x509; 280: 281: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, 282: BUILD_BLOB_PEM, v, BUILD_END); 283: if (!cert) 284: { 285: return create_reply("parsing %N certificate failed", 286: certificate_type_names, CERT_X509); 287: } 288: x509 = (x509_t*)cert; 289: 290: if ((x509->get_flags(x509) & X509_CA) != X509_CA) 291: { 292: cert->destroy(cert); 293: return create_reply("certificate without CA flag, rejected"); 294: } 295: *cacert = cert; 296: 297: return TRUE; 298: } 299: 300: CALLBACK(authority_kv, bool, 301: load_data_t *data, vici_message_t *message, char *name, chunk_t value) 302: { 303: parse_rule_t rules[] = { 304: { "cacert", parse_cacert, &data->authority->cert }, 305: { "file", parse_string, &data->file }, 306: { "handle", parse_string, &data->handle }, 307: { "slot", parse_uint32, &data->slot }, 308: { "module", parse_string, &data->module }, 309: { "cert_uri_base", parse_string, &data->authority->cert_uri_base }, 310: }; 311: 312: return parse_rules(rules, countof(rules), name, value, 313: &data->request->reply); 314: } 315: 316: CALLBACK(authority_li, bool, 317: load_data_t *data, vici_message_t *message, char *name, chunk_t value) 318: { 319: parse_rule_t rules[] = { 320: { "crl_uris", parse_uris, data->authority->crl_uris }, 321: { "ocsp_uris", parse_uris, data->authority->ocsp_uris }, 322: }; 323: 324: return parse_rules(rules, countof(rules), name, value, 325: &data->request->reply); 326: } 327: 328: static void log_authority_data(authority_t *authority) 329: { 330: enumerator_t *enumerator; 331: identification_t *subject; 332: bool first = TRUE; 333: char *uri; 334: 335: subject = authority->cert->get_subject(authority->cert); 336: DBG2(DBG_CFG, " cacert = %Y", subject); 337: 338: enumerator = authority->crl_uris->create_enumerator(authority->crl_uris); 339: while (enumerator->enumerate(enumerator, &uri)) 340: { 341: if (first) 342: { 343: DBG2(DBG_CFG, " crl_uris = %s", uri); 344: first = FALSE; 345: } 346: else 347: { 348: DBG2(DBG_CFG, " %s", uri); 349: } 350: } 351: enumerator->destroy(enumerator); 352: 353: first = TRUE; 354: enumerator = authority->ocsp_uris->create_enumerator(authority->ocsp_uris); 355: while (enumerator->enumerate(enumerator, &uri)) 356: { 357: if (first) 358: { 359: DBG2(DBG_CFG, " ocsp_uris = %s", uri); 360: first = FALSE; 361: } 362: else 363: { 364: DBG2(DBG_CFG, " %s", uri); 365: } 366: } 367: enumerator->destroy(enumerator); 368: 369: if (authority->cert_uri_base) 370: { 371: DBG2(DBG_CFG, " cert_uri_base = %s", authority->cert_uri_base); 372: } 373: } 374: 375: CALLBACK(authority_sn, bool, 376: request_data_t *request, vici_message_t *message, 377: vici_parse_context_t *ctx, char *name) 378: { 379: enumerator_t *enumerator; 380: linked_list_t *authorities; 381: authority_t *authority; 382: vici_cred_t *cred; 383: load_data_t *data; 384: chunk_t handle; 385: 386: INIT(data, 387: .request = request, 388: .authority = authority_create(name), 389: .slot = -1, 390: ); 391: 392: DBG2(DBG_CFG, " authority %s:", name); 393: 394: if (!message->parse(message, ctx, NULL, authority_kv, authority_li, data)) 395: { 396: free_load_data(data); 397: return FALSE; 398: } 399: if (!data->authority->cert) 400: { 401: if (data->file) 402: { 403: data->authority->cert = lib->creds->create(lib->creds, 404: CRED_CERTIFICATE, CERT_X509, 405: BUILD_FROM_FILE, data->file, BUILD_END); 406: } 407: else if (data->handle) 408: { 409: handle = chunk_from_hex(chunk_from_str(data->handle), NULL); 410: if (data->slot != -1) 411: { 412: data->authority->cert = lib->creds->create(lib->creds, 413: CRED_CERTIFICATE, CERT_X509, 414: BUILD_PKCS11_KEYID, handle, 415: BUILD_PKCS11_SLOT, data->slot, 416: data->module ? BUILD_PKCS11_MODULE : BUILD_END, 417: data->module, BUILD_END); 418: } 419: else 420: { 421: data->authority->cert = lib->creds->create(lib->creds, 422: CRED_CERTIFICATE, CERT_X509, 423: BUILD_PKCS11_KEYID, handle, 424: data->module ? BUILD_PKCS11_MODULE : BUILD_END, 425: data->module, BUILD_END); 426: } 427: chunk_free(&handle); 428: } 429: } 430: if (!data->authority->cert) 431: { 432: request->reply = create_reply("CA certificate missing: %s", name); 433: free_load_data(data); 434: return FALSE; 435: } 436: log_authority_data(data->authority); 437: 438: request->this->lock->write_lock(request->this->lock); 439: 440: authorities = request->this->authorities; 441: enumerator = authorities->create_enumerator(authorities); 442: while (enumerator->enumerate(enumerator, &authority)) 443: { 444: if (streq(authority->name, name)) 445: { 446: /* remove the old authority definition */ 447: authorities->remove_at(authorities, enumerator); 448: authority_destroy(authority); 449: break; 450: } 451: } 452: enumerator->destroy(enumerator); 453: authorities->insert_last(authorities, data->authority); 454: 455: cred = request->this->cred; 456: data->authority->cert = cred->add_cert(cred, data->authority->cert); 457: data->authority = NULL; 458: 459: request->this->lock->unlock(request->this->lock); 460: free_load_data(data); 461: 462: return TRUE; 463: } 464: 465: CALLBACK(load_authority, vici_message_t*, 466: private_vici_authority_t *this, char *name, u_int id, vici_message_t *message) 467: { 468: request_data_t request = { 469: .this = this, 470: }; 471: 472: if (!message->parse(message, NULL, authority_sn, NULL, NULL, &request)) 473: { 474: if (request.reply) 475: { 476: return request.reply; 477: } 478: return create_reply("parsing request failed"); 479: } 480: return create_reply(NULL); 481: } 482: 483: CALLBACK(unload_authority, vici_message_t*, 484: private_vici_authority_t *this, char *name, u_int id, vici_message_t *message) 485: { 486: enumerator_t *enumerator; 487: authority_t *authority; 488: char *authority_name; 489: bool found = FALSE; 490: 491: authority_name = message->get_str(message, NULL, "name"); 492: if (!authority_name) 493: { 494: return create_reply("unload: missing authority name"); 495: } 496: 497: this->lock->write_lock(this->lock); 498: enumerator = this->authorities->create_enumerator(this->authorities); 499: while (enumerator->enumerate(enumerator, &authority)) 500: { 501: if (streq(authority->name, authority_name)) 502: { 503: this->authorities->remove_at(this->authorities, enumerator); 504: authority_destroy(authority); 505: found = TRUE; 506: break; 507: } 508: } 509: enumerator->destroy(enumerator); 510: this->lock->unlock(this->lock); 511: 512: if (!found) 513: { 514: return create_reply("unload: authority '%s' not found", authority_name); 515: } 516: return create_reply(NULL); 517: } 518: 519: CALLBACK(get_authorities, vici_message_t*, 520: private_vici_authority_t *this, char *name, u_int id, 521: vici_message_t *message) 522: { 523: vici_builder_t *builder; 524: enumerator_t *enumerator; 525: authority_t *authority; 526: 527: builder = vici_builder_create(); 528: builder->begin_list(builder, "authorities"); 529: 530: this->lock->read_lock(this->lock); 531: enumerator = this->authorities->create_enumerator(this->authorities); 532: while (enumerator->enumerate(enumerator, &authority)) 533: { 534: builder->add_li(builder, "%s", authority->name); 535: } 536: enumerator->destroy(enumerator); 537: this->lock->unlock(this->lock); 538: 539: builder->end_list(builder); 540: 541: return builder->finalize(builder); 542: } 543: 544: CALLBACK(list_authorities, vici_message_t*, 545: private_vici_authority_t *this, char *name, u_int id, vici_message_t *request) 546: { 547: enumerator_t *enumerator, *e; 548: authority_t *authority; 549: vici_builder_t *b; 550: char *str, *uri; 551: 552: str = request->get_str(request, NULL, "name"); 553: 554: this->lock->read_lock(this->lock); 555: enumerator = this->authorities->create_enumerator(this->authorities); 556: while (enumerator->enumerate(enumerator, &authority)) 557: { 558: if (str && !streq(str, authority->name)) 559: { 560: continue; 561: } 562: b = vici_builder_create(); 563: 564: /* open authority section */ 565: b->begin_section(b, authority->name); 566: 567: /* subject DN of cacert */ 568: b->add_kv(b, "cacert", "%Y", 569: authority->cert->get_subject(authority->cert)); 570: 571: /* list of crl_uris */ 572: b->begin_list(b, "crl_uris"); 573: e = authority->crl_uris->create_enumerator(authority->crl_uris); 574: while (e->enumerate(e, &uri)) 575: { 576: b->add_li(b, "%s", uri); 577: } 578: e->destroy(e); 579: b->end_list(b); 580: 581: /* list of ocsp_uris */ 582: b->begin_list(b, "ocsp_uris"); 583: e = authority->ocsp_uris->create_enumerator(authority->ocsp_uris); 584: while (e->enumerate(e, &uri)) 585: { 586: b->add_li(b, "%s", uri); 587: } 588: e->destroy(e); 589: b->end_list(b); 590: 591: /* cert_uri_base */ 592: if (authority->cert_uri_base) 593: { 594: b->add_kv(b, "cert_uri_base", "%s", authority->cert_uri_base); 595: } 596: 597: /* close authority and raise event */ 598: b->end_section(b); 599: this->dispatcher->raise_event(this->dispatcher, "list-authority", id, 600: b->finalize(b)); 601: } 602: enumerator->destroy(enumerator); 603: this->lock->unlock(this->lock); 604: 605: b = vici_builder_create(); 606: return b->finalize(b); 607: } 608: 609: static void manage_command(private_vici_authority_t *this, 610: char *name, vici_command_cb_t cb, bool reg) 611: { 612: this->dispatcher->manage_command(this->dispatcher, name, 613: reg ? cb : NULL, this); 614: } 615: 616: /** 617: * (Un-)register dispatcher functions 618: */ 619: static void manage_commands(private_vici_authority_t *this, bool reg) 620: { 621: this->dispatcher->manage_event(this->dispatcher, "list-authority", reg); 622: 623: manage_command(this, "load-authority", load_authority, reg); 624: manage_command(this, "unload-authority", unload_authority, reg); 625: manage_command(this, "get-authorities", get_authorities, reg); 626: manage_command(this, "list-authorities", list_authorities, reg); 627: } 628: 629: /** 630: * data to pass to create_inner_cdp 631: */ 632: typedef struct { 633: private_vici_authority_t *this; 634: certificate_type_t type; 635: identification_t *id; 636: } cdp_data_t; 637: 638: /** 639: * destroy cdp enumerator data and unlock list 640: */ 641: static void cdp_data_destroy(cdp_data_t *data) 642: { 643: data->this->lock->unlock(data->this->lock); 644: free(data); 645: } 646: 647: /** 648: * inner enumerator constructor for CDP URIs 649: */ 650: static enumerator_t *create_inner_cdp(authority_t *authority, cdp_data_t *data) 651: { 652: public_key_t *public; 653: enumerator_t *enumerator = NULL; 654: linked_list_t *list; 655: 656: if (data->type == CERT_X509_OCSP_RESPONSE) 657: { 658: list = authority->ocsp_uris; 659: } 660: else 661: { 662: list = authority->crl_uris; 663: } 664: 665: public = authority->cert->get_public_key(authority->cert); 666: if (public) 667: { 668: if (!data->id) 669: { 670: enumerator = list->create_enumerator(list); 671: } 672: else 673: { 674: if (public->has_fingerprint(public, data->id->get_encoding(data->id))) 675: { 676: enumerator = list->create_enumerator(list); 677: } 678: } 679: public->destroy(public); 680: } 681: return enumerator; 682: } 683: 684: /** 685: * inner enumerator constructor for "Hash and URL" 686: */ 687: static enumerator_t *create_inner_cdp_hashandurl(authority_t *authority, 688: cdp_data_t *data) 689: { 690: enumerator_t *enumerator = NULL; 691: 692: if (!data->id || !authority->cert_uri_base) 693: { 694: return NULL; 695: } 696: 697: if (authority->cert->has_subject(authority->cert, data->id) != ID_MATCH_NONE) 698: { 699: enumerator = enumerator_create_single(strdup(authority->cert_uri_base), 700: free); 701: } 702: return enumerator; 703: } 704: 705: METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*, 706: private_vici_authority_t *this, certificate_type_t type, 707: identification_t *id) 708: { 709: cdp_data_t *data; 710: 711: switch (type) 712: { /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */ 713: case CERT_X509: 714: case CERT_X509_CRL: 715: case CERT_X509_OCSP_RESPONSE: 716: case CERT_ANY: 717: break; 718: default: 719: return NULL; 720: } 721: data = malloc_thing(cdp_data_t); 722: data->this = this; 723: data->type = type; 724: data->id = id; 725: 726: this->lock->read_lock(this->lock); 727: 728: return enumerator_create_nested( 729: this->authorities->create_enumerator(this->authorities), 730: (type == CERT_X509) ? (void*)create_inner_cdp_hashandurl : 731: (void*)create_inner_cdp, data, (void*)cdp_data_destroy); 732: } 733: 734: METHOD(vici_authority_t, destroy, void, 735: private_vici_authority_t *this) 736: { 737: manage_commands(this, FALSE); 738: 739: this->authorities->destroy_function(this->authorities, 740: (void*)authority_destroy); 741: this->lock->destroy(this->lock); 742: free(this); 743: } 744: 745: /** 746: * See header 747: */ 748: vici_authority_t *vici_authority_create(vici_dispatcher_t *dispatcher, 749: vici_cred_t *cred) 750: { 751: private_vici_authority_t *this; 752: 753: INIT(this, 754: .public = { 755: .set = { 756: .create_private_enumerator = (void*)return_null, 757: .create_cert_enumerator = (void*)return_null, 758: .create_shared_enumerator = (void*)return_null, 759: .create_cdp_enumerator = _create_cdp_enumerator, 760: .cache_cert = (void*)nop, 761: }, 762: .destroy = _destroy, 763: }, 764: .dispatcher = dispatcher, 765: .cred = cred, 766: .authorities = linked_list_create(), 767: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), 768: ); 769: 770: manage_commands(this, TRUE); 771: 772: return &this->public; 773: }