Return to stroke_ca.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / stroke |
1.1 misho 1: /* 2: * Copyright (C) 2008-2019 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 "stroke_ca.h" 18: #include "stroke_cred.h" 19: 20: #include <threading/rwlock.h> 21: #include <collections/linked_list.h> 22: #include <crypto/hashers/hasher.h> 23: 24: #include <daemon.h> 25: 26: typedef struct private_stroke_ca_t private_stroke_ca_t; 27: typedef struct ca_section_t ca_section_t; 28: typedef struct ca_cert_t ca_cert_t; 29: 30: /** 31: * Provided by stroke_cred.c 32: */ 33: certificate_t *stroke_load_ca_cert(char *filename); 34: 35: /** 36: * private data of stroke_ca 37: */ 38: struct private_stroke_ca_t { 39: 40: /** 41: * public functions 42: */ 43: stroke_ca_t public; 44: 45: /** 46: * read-write lock to lists 47: */ 48: rwlock_t *lock; 49: 50: /** 51: * list of CA sections and their certificates (ca_section_t) 52: */ 53: linked_list_t *sections; 54: 55: /** 56: * list of all loaded CA certificates (ca_cert_t) 57: */ 58: linked_list_t *certs; 59: }; 60: 61: 62: /** 63: * loaded ipsec.conf CA sections 64: */ 65: struct ca_section_t { 66: 67: /** 68: * name of the CA section 69: */ 70: char *name; 71: 72: /** 73: * path/name of the certificate 74: */ 75: char *path; 76: 77: /** 78: * reference to cert 79: */ 80: certificate_t *cert; 81: 82: /** 83: * CRL URIs 84: */ 85: linked_list_t *crl; 86: 87: /** 88: * OCSP URIs 89: */ 90: linked_list_t *ocsp; 91: 92: /** 93: * Base URI used for certificates from this CA 94: */ 95: char *certuribase; 96: }; 97: 98: /** 99: * loaded CA certificate 100: */ 101: struct ca_cert_t { 102: 103: /** 104: * reference to cert 105: */ 106: certificate_t *cert; 107: 108: /** 109: * The number of CA sections referring to this certificate 110: */ 111: u_int count; 112: 113: /** 114: * TRUE if this certificate was automatically loaded 115: */ 116: bool automatic; 117: }; 118: 119: /** 120: * create a new CA section 121: */ 122: static ca_section_t *ca_section_create(char *name, char *path) 123: { 124: ca_section_t *ca = malloc_thing(ca_section_t); 125: 126: ca->name = strdup(name); 127: ca->path = strdup(path); 128: ca->crl = linked_list_create(); 129: ca->ocsp = linked_list_create(); 130: ca->certuribase = NULL; 131: return ca; 132: } 133: 134: /** 135: * destroy a ca section entry 136: */ 137: static void ca_section_destroy(ca_section_t *this) 138: { 139: this->crl->destroy_function(this->crl, free); 140: this->ocsp->destroy_function(this->ocsp, free); 141: this->cert->destroy(this->cert); 142: free(this->certuribase); 143: free(this->path); 144: free(this->name); 145: free(this); 146: } 147: 148: /** 149: * Destroy a ca cert entry 150: */ 151: static void ca_cert_destroy(ca_cert_t *this) 152: { 153: this->cert->destroy(this->cert); 154: free(this); 155: } 156: 157: /** 158: * Data for the certificate enumerator 159: */ 160: typedef struct { 161: private_stroke_ca_t *this; 162: certificate_type_t cert; 163: key_type_t key; 164: identification_t *id; 165: } cert_data_t; 166: 167: CALLBACK(cert_data_destroy, void, 168: cert_data_t *data) 169: { 170: data->this->lock->unlock(data->this->lock); 171: free(data); 172: } 173: 174: CALLBACK(certs_filter, bool, 175: cert_data_t *data, enumerator_t *orig, va_list args) 176: { 177: ca_cert_t *cacert; 178: certificate_t **out; 179: 180: VA_ARGS_VGET(args, out); 181: 182: while (orig->enumerate(orig, &cacert)) 183: { 1.1.1.2 ! misho 184: if (certificate_matches(cacert->cert, data->cert, data->key, data->id)) 1.1 misho 185: { 1.1.1.2 ! misho 186: *out = cacert->cert; 1.1 misho 187: return TRUE; 188: } 189: } 190: return FALSE; 191: } 192: 193: METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, 194: private_stroke_ca_t *this, certificate_type_t cert, key_type_t key, 195: identification_t *id, bool trusted) 196: { 197: enumerator_t *enumerator; 198: cert_data_t *data; 199: 200: INIT(data, 201: .this = this, 202: .cert = cert, 203: .key = key, 204: .id = id, 205: ); 206: 207: this->lock->read_lock(this->lock); 208: enumerator = this->certs->create_enumerator(this->certs); 209: return enumerator_create_filter(enumerator, certs_filter, data, 210: cert_data_destroy); 211: } 212: 213: /** 214: * data to pass to create_inner_cdp 215: */ 216: typedef struct { 217: private_stroke_ca_t *this; 218: certificate_type_t type; 219: identification_t *id; 220: } cdp_data_t; 221: 222: /** 223: * destroy cdp enumerator data and unlock list 224: */ 225: static void cdp_data_destroy(cdp_data_t *data) 226: { 227: data->this->lock->unlock(data->this->lock); 228: free(data); 229: } 230: 231: /** 232: * inner enumerator constructor for CDP URIs 233: */ 234: static enumerator_t *create_inner_cdp(ca_section_t *section, cdp_data_t *data) 235: { 236: public_key_t *public; 237: enumerator_t *enumerator = NULL; 238: linked_list_t *list; 239: 240: if (data->type == CERT_X509_OCSP_RESPONSE) 241: { 242: list = section->ocsp; 243: } 244: else 245: { 246: list = section->crl; 247: } 248: 249: public = section->cert->get_public_key(section->cert); 250: if (public) 251: { 252: if (!data->id) 253: { 254: enumerator = list->create_enumerator(list); 255: } 256: else 257: { 258: if (public->has_fingerprint(public, data->id->get_encoding(data->id))) 259: { 260: enumerator = list->create_enumerator(list); 261: } 262: } 263: public->destroy(public); 264: } 265: return enumerator; 266: } 267: 268: /** 269: * inner enumerator constructor for "Hash and URL" 270: */ 271: static enumerator_t *create_inner_cdp_hashandurl(ca_section_t *section, cdp_data_t *data) 272: { 273: enumerator_t *enumerator = NULL; 274: 275: if (!data->id || !section->certuribase) 276: { 277: return NULL; 278: } 279: 280: if (section->cert->has_subject(section->cert, data->id) != ID_MATCH_NONE) 281: { 282: enumerator = enumerator_create_single(strdup(section->certuribase), 283: free); 284: } 285: return enumerator; 286: } 287: 288: METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*, 289: private_stroke_ca_t *this, certificate_type_t type, identification_t *id) 290: { 291: cdp_data_t *data; 292: 293: switch (type) 294: { /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */ 295: case CERT_X509: 296: case CERT_X509_CRL: 297: case CERT_X509_OCSP_RESPONSE: 298: case CERT_ANY: 299: break; 300: default: 301: return NULL; 302: } 303: data = malloc_thing(cdp_data_t); 304: data->this = this; 305: data->type = type; 306: data->id = id; 307: 308: this->lock->read_lock(this->lock); 309: return enumerator_create_nested(this->sections->create_enumerator(this->sections), 310: (type == CERT_X509) ? (void*)create_inner_cdp_hashandurl : (void*)create_inner_cdp, 311: data, (void*)cdp_data_destroy); 312: } 313: 314: CALLBACK(match_cert, bool, 315: ca_cert_t *item, va_list args) 316: { 317: certificate_t *cert; 318: 319: VA_ARGS_VGET(args, cert); 320: return cert->equals(cert, item->cert); 321: } 322: 323: /** 324: * Match automatically added certificates and remove/destroy them if they are 325: * not referenced by CA sections. 326: */ 327: static bool remove_auto_certs(ca_cert_t *item, void *not_used) 328: { 329: if (item->automatic) 330: { 331: item->automatic = FALSE; 332: if (!item->count) 333: { 334: ca_cert_destroy(item); 335: return TRUE; 336: } 337: } 338: return FALSE; 339: } 340: 341: /** 342: * Find the given certificate that was referenced by a section and remove it 343: * unless it was also loaded automatically or is used by other CA sections. 344: */ 345: static bool remove_cert(ca_cert_t *item, certificate_t *cert) 346: { 347: if (item->count && cert->equals(cert, item->cert)) 348: { 349: if (--item->count == 0 && !item->automatic) 350: { 351: ca_cert_destroy(item); 352: return TRUE; 353: } 354: } 355: return FALSE; 356: } 357: 358: /** 359: * Adds a certificate to the certificate store 360: */ 361: static certificate_t *add_cert_internal(private_stroke_ca_t *this, 362: certificate_t *cert, bool automatic) 363: { 364: ca_cert_t *found; 365: 366: if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert)) 367: { 368: cert->destroy(cert); 369: cert = found->cert->get_ref(found->cert); 370: } 371: else 372: { 373: INIT(found, 374: .cert = cert->get_ref(cert) 375: ); 376: this->certs->insert_first(this->certs, found); 377: } 378: if (automatic) 379: { 380: found->automatic = TRUE; 381: } 382: else 383: { 384: found->count++; 385: } 386: return cert; 387: } 388: 389: METHOD(stroke_ca_t, add, void, 390: private_stroke_ca_t *this, stroke_msg_t *msg) 391: { 392: certificate_t *cert; 393: ca_section_t *ca; 394: 395: if (msg->add_ca.cacert == NULL) 396: { 397: DBG1(DBG_CFG, "missing cacert parameter"); 398: return; 399: } 400: cert = stroke_load_ca_cert(msg->add_ca.cacert); 401: if (cert) 402: { 403: ca = ca_section_create(msg->add_ca.name, msg->add_ca.cacert); 404: if (msg->add_ca.crluri) 405: { 406: ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri)); 407: } 408: if (msg->add_ca.crluri2) 409: { 410: ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri2)); 411: } 412: if (msg->add_ca.ocspuri) 413: { 414: ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri)); 415: } 416: if (msg->add_ca.ocspuri2) 417: { 418: ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri2)); 419: } 420: if (msg->add_ca.certuribase) 421: { 422: ca->certuribase = strdup(msg->add_ca.certuribase); 423: } 424: this->lock->write_lock(this->lock); 425: ca->cert = add_cert_internal(this, cert, FALSE); 426: this->sections->insert_last(this->sections, ca); 427: this->lock->unlock(this->lock); 428: DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name); 429: } 430: } 431: 432: METHOD(stroke_ca_t, del, void, 433: private_stroke_ca_t *this, stroke_msg_t *msg) 434: { 435: enumerator_t *enumerator; 436: ca_section_t *ca = NULL; 437: 438: this->lock->write_lock(this->lock); 439: enumerator = this->sections->create_enumerator(this->sections); 440: while (enumerator->enumerate(enumerator, &ca)) 441: { 442: if (streq(ca->name, msg->del_ca.name)) 443: { 444: this->sections->remove_at(this->sections, enumerator); 445: break; 446: } 447: ca = NULL; 448: } 449: enumerator->destroy(enumerator); 450: if (ca) 451: { 452: this->certs->remove(this->certs, ca->cert, (void*)remove_cert); 453: } 454: this->lock->unlock(this->lock); 455: if (!ca) 456: { 457: DBG1(DBG_CFG, "no ca named '%s' found\n", msg->del_ca.name); 458: return; 459: } 460: ca_section_destroy(ca); 461: 462: lib->credmgr->flush_cache(lib->credmgr, CERT_ANY); 463: } 464: 465: METHOD(stroke_ca_t, get_cert_ref, certificate_t*, 466: private_stroke_ca_t *this, certificate_t *cert) 467: { 468: ca_cert_t *found; 469: 470: this->lock->read_lock(this->lock); 471: if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert)) 472: { 473: cert->destroy(cert); 474: cert = found->cert->get_ref(found->cert); 475: } 476: this->lock->unlock(this->lock); 477: return cert; 478: } 479: 480: METHOD(stroke_ca_t, reload_certs, void, 481: private_stroke_ca_t *this) 482: { 483: enumerator_t *enumerator; 484: certificate_t *cert; 485: ca_section_t *ca; 486: certificate_type_t type = CERT_X509; 487: 488: /* holding the write lock while loading/parsing certificates is not optimal, 489: * however, there usually are not that many ca sections configured */ 490: this->lock->write_lock(this->lock); 491: if (this->sections->get_count(this->sections)) 492: { 493: DBG1(DBG_CFG, "rereading ca certificates in ca sections"); 494: } 495: enumerator = this->sections->create_enumerator(this->sections); 496: while (enumerator->enumerate(enumerator, &ca)) 497: { 498: cert = stroke_load_ca_cert(ca->path); 499: if (cert) 500: { 501: if (cert->equals(cert, ca->cert)) 502: { 503: cert->destroy(cert); 504: } 505: else 506: { 507: this->certs->remove(this->certs, ca->cert, (void*)remove_cert); 508: ca->cert->destroy(ca->cert); 509: ca->cert = add_cert_internal(this, cert, FALSE); 510: } 511: } 512: else 513: { 514: DBG1(DBG_CFG, "failed to reload certificate '%s', removing ca '%s'", 515: ca->path, ca->name); 516: this->sections->remove_at(this->sections, enumerator); 517: this->certs->remove(this->certs, ca->cert, (void*)remove_cert); 518: ca_section_destroy(ca); 519: type = CERT_ANY; 520: } 521: } 522: enumerator->destroy(enumerator); 523: this->lock->unlock(this->lock); 524: lib->credmgr->flush_cache(lib->credmgr, type); 525: } 526: 527: METHOD(stroke_ca_t, replace_certs, void, 528: private_stroke_ca_t *this, mem_cred_t *certs) 529: { 530: enumerator_t *enumerator; 531: certificate_t *cert; 532: 533: enumerator = certs->set.create_cert_enumerator(&certs->set, CERT_X509, 534: KEY_ANY, NULL, TRUE); 535: this->lock->write_lock(this->lock); 536: this->certs->remove(this->certs, NULL, (void*)remove_auto_certs); 537: while (enumerator->enumerate(enumerator, &cert)) 538: { 539: cert = add_cert_internal(this, cert->get_ref(cert), TRUE); 540: cert->destroy(cert); 541: } 542: this->lock->unlock(this->lock); 543: enumerator->destroy(enumerator); 544: lib->credmgr->flush_cache(lib->credmgr, CERT_X509); 545: } 546: /** 547: * list crl or ocsp URIs 548: */ 549: static void list_uris(linked_list_t *list, char *label, FILE *out) 550: { 551: bool first = TRUE; 552: char *uri; 553: enumerator_t *enumerator; 554: 555: enumerator = list->create_enumerator(list); 556: while (enumerator->enumerate(enumerator, (void**)&uri)) 557: { 558: if (first) 559: { 560: fprintf(out, "%s", label); 561: first = FALSE; 562: } 563: else 564: { 565: fprintf(out, " "); 566: } 567: fprintf(out, "'%s'\n", uri); 568: } 569: enumerator->destroy(enumerator); 570: } 571: 572: METHOD(stroke_ca_t, list, void, 573: private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out) 574: { 575: bool first = TRUE; 576: ca_section_t *section; 577: enumerator_t *enumerator; 578: 579: this->lock->read_lock(this->lock); 580: enumerator = this->sections->create_enumerator(this->sections); 581: while (enumerator->enumerate(enumerator, (void**)§ion)) 582: { 583: certificate_t *cert = section->cert; 584: public_key_t *public = cert->get_public_key(cert); 585: chunk_t chunk; 586: 587: if (first) 588: { 589: fprintf(out, "\n"); 590: fprintf(out, "List of CA Information Sections:\n"); 591: first = FALSE; 592: } 593: fprintf(out, "\n"); 594: fprintf(out, " authname: \"%Y\"\n", cert->get_subject(cert)); 595: 596: /* list authkey and keyid */ 597: if (public) 598: { 599: if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk)) 600: { 601: fprintf(out, " authkey: %#B\n", &chunk); 602: } 603: if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &chunk)) 604: { 605: fprintf(out, " keyid: %#B\n", &chunk); 606: } 607: public->destroy(public); 608: } 609: list_uris(section->crl, " crluris: ", out); 610: list_uris(section->ocsp, " ocspuris: ", out); 611: if (section->certuribase) 612: { 613: fprintf(out, " certuribase: '%s'\n", section->certuribase); 614: } 615: } 616: enumerator->destroy(enumerator); 617: this->lock->unlock(this->lock); 618: } 619: 620: METHOD(stroke_ca_t, destroy, void, 621: private_stroke_ca_t *this) 622: { 623: this->sections->destroy_function(this->sections, (void*)ca_section_destroy); 624: this->certs->destroy_function(this->certs, (void*)ca_cert_destroy); 625: this->lock->destroy(this->lock); 626: free(this); 627: } 628: 629: /* 630: * see header file 631: */ 632: stroke_ca_t *stroke_ca_create() 633: { 634: private_stroke_ca_t *this; 635: 636: INIT(this, 637: .public = { 638: .set = { 639: .create_private_enumerator = (void*)return_null, 640: .create_cert_enumerator = _create_cert_enumerator, 641: .create_shared_enumerator = (void*)return_null, 642: .create_cdp_enumerator = _create_cdp_enumerator, 643: .cache_cert = (void*)nop, 644: }, 645: .add = _add, 646: .del = _del, 647: .list = _list, 648: .get_cert_ref = _get_cert_ref, 649: .reload_certs = _reload_certs, 650: .replace_certs = _replace_certs, 651: .destroy = _destroy, 652: }, 653: .sections = linked_list_create(), 654: .certs = linked_list_create(), 655: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), 656: ); 657: 658: return &this->public; 659: }