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: public_key_t *public; 179: certificate_t **out; 180: 181: VA_ARGS_VGET(args, out); 182: 183: while (orig->enumerate(orig, &cacert)) 184: { 185: certificate_t *cert = cacert->cert; 186: 187: if (data->cert != CERT_ANY && data->cert != cert->get_type(cert)) 188: { 189: continue; 190: } 191: public = cert->get_public_key(cert); 192: if (public) 193: { 194: if (data->key == KEY_ANY || data->key == public->get_type(public)) 195: { 196: if (data->id && public->has_fingerprint(public, 197: data->id->get_encoding(data->id))) 198: { 199: public->destroy(public); 200: *out = cert; 201: return TRUE; 202: } 203: } 204: else 205: { 206: public->destroy(public); 207: continue; 208: } 209: public->destroy(public); 210: } 211: else if (data->key != KEY_ANY) 212: { 213: continue; 214: } 215: if (!data->id || cert->has_subject(cert, data->id)) 216: { 217: *out = cert; 218: return TRUE; 219: } 220: } 221: return FALSE; 222: } 223: 224: METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, 225: private_stroke_ca_t *this, certificate_type_t cert, key_type_t key, 226: identification_t *id, bool trusted) 227: { 228: enumerator_t *enumerator; 229: cert_data_t *data; 230: 231: INIT(data, 232: .this = this, 233: .cert = cert, 234: .key = key, 235: .id = id, 236: ); 237: 238: this->lock->read_lock(this->lock); 239: enumerator = this->certs->create_enumerator(this->certs); 240: return enumerator_create_filter(enumerator, certs_filter, data, 241: cert_data_destroy); 242: } 243: 244: /** 245: * data to pass to create_inner_cdp 246: */ 247: typedef struct { 248: private_stroke_ca_t *this; 249: certificate_type_t type; 250: identification_t *id; 251: } cdp_data_t; 252: 253: /** 254: * destroy cdp enumerator data and unlock list 255: */ 256: static void cdp_data_destroy(cdp_data_t *data) 257: { 258: data->this->lock->unlock(data->this->lock); 259: free(data); 260: } 261: 262: /** 263: * inner enumerator constructor for CDP URIs 264: */ 265: static enumerator_t *create_inner_cdp(ca_section_t *section, cdp_data_t *data) 266: { 267: public_key_t *public; 268: enumerator_t *enumerator = NULL; 269: linked_list_t *list; 270: 271: if (data->type == CERT_X509_OCSP_RESPONSE) 272: { 273: list = section->ocsp; 274: } 275: else 276: { 277: list = section->crl; 278: } 279: 280: public = section->cert->get_public_key(section->cert); 281: if (public) 282: { 283: if (!data->id) 284: { 285: enumerator = list->create_enumerator(list); 286: } 287: else 288: { 289: if (public->has_fingerprint(public, data->id->get_encoding(data->id))) 290: { 291: enumerator = list->create_enumerator(list); 292: } 293: } 294: public->destroy(public); 295: } 296: return enumerator; 297: } 298: 299: /** 300: * inner enumerator constructor for "Hash and URL" 301: */ 302: static enumerator_t *create_inner_cdp_hashandurl(ca_section_t *section, cdp_data_t *data) 303: { 304: enumerator_t *enumerator = NULL; 305: 306: if (!data->id || !section->certuribase) 307: { 308: return NULL; 309: } 310: 311: if (section->cert->has_subject(section->cert, data->id) != ID_MATCH_NONE) 312: { 313: enumerator = enumerator_create_single(strdup(section->certuribase), 314: free); 315: } 316: return enumerator; 317: } 318: 319: METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*, 320: private_stroke_ca_t *this, certificate_type_t type, identification_t *id) 321: { 322: cdp_data_t *data; 323: 324: switch (type) 325: { /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */ 326: case CERT_X509: 327: case CERT_X509_CRL: 328: case CERT_X509_OCSP_RESPONSE: 329: case CERT_ANY: 330: break; 331: default: 332: return NULL; 333: } 334: data = malloc_thing(cdp_data_t); 335: data->this = this; 336: data->type = type; 337: data->id = id; 338: 339: this->lock->read_lock(this->lock); 340: return enumerator_create_nested(this->sections->create_enumerator(this->sections), 341: (type == CERT_X509) ? (void*)create_inner_cdp_hashandurl : (void*)create_inner_cdp, 342: data, (void*)cdp_data_destroy); 343: } 344: 345: CALLBACK(match_cert, bool, 346: ca_cert_t *item, va_list args) 347: { 348: certificate_t *cert; 349: 350: VA_ARGS_VGET(args, cert); 351: return cert->equals(cert, item->cert); 352: } 353: 354: /** 355: * Match automatically added certificates and remove/destroy them if they are 356: * not referenced by CA sections. 357: */ 358: static bool remove_auto_certs(ca_cert_t *item, void *not_used) 359: { 360: if (item->automatic) 361: { 362: item->automatic = FALSE; 363: if (!item->count) 364: { 365: ca_cert_destroy(item); 366: return TRUE; 367: } 368: } 369: return FALSE; 370: } 371: 372: /** 373: * Find the given certificate that was referenced by a section and remove it 374: * unless it was also loaded automatically or is used by other CA sections. 375: */ 376: static bool remove_cert(ca_cert_t *item, certificate_t *cert) 377: { 378: if (item->count && cert->equals(cert, item->cert)) 379: { 380: if (--item->count == 0 && !item->automatic) 381: { 382: ca_cert_destroy(item); 383: return TRUE; 384: } 385: } 386: return FALSE; 387: } 388: 389: /** 390: * Adds a certificate to the certificate store 391: */ 392: static certificate_t *add_cert_internal(private_stroke_ca_t *this, 393: certificate_t *cert, bool automatic) 394: { 395: ca_cert_t *found; 396: 397: if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert)) 398: { 399: cert->destroy(cert); 400: cert = found->cert->get_ref(found->cert); 401: } 402: else 403: { 404: INIT(found, 405: .cert = cert->get_ref(cert) 406: ); 407: this->certs->insert_first(this->certs, found); 408: } 409: if (automatic) 410: { 411: found->automatic = TRUE; 412: } 413: else 414: { 415: found->count++; 416: } 417: return cert; 418: } 419: 420: METHOD(stroke_ca_t, add, void, 421: private_stroke_ca_t *this, stroke_msg_t *msg) 422: { 423: certificate_t *cert; 424: ca_section_t *ca; 425: 426: if (msg->add_ca.cacert == NULL) 427: { 428: DBG1(DBG_CFG, "missing cacert parameter"); 429: return; 430: } 431: cert = stroke_load_ca_cert(msg->add_ca.cacert); 432: if (cert) 433: { 434: ca = ca_section_create(msg->add_ca.name, msg->add_ca.cacert); 435: if (msg->add_ca.crluri) 436: { 437: ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri)); 438: } 439: if (msg->add_ca.crluri2) 440: { 441: ca->crl->insert_last(ca->crl, strdup(msg->add_ca.crluri2)); 442: } 443: if (msg->add_ca.ocspuri) 444: { 445: ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri)); 446: } 447: if (msg->add_ca.ocspuri2) 448: { 449: ca->ocsp->insert_last(ca->ocsp, strdup(msg->add_ca.ocspuri2)); 450: } 451: if (msg->add_ca.certuribase) 452: { 453: ca->certuribase = strdup(msg->add_ca.certuribase); 454: } 455: this->lock->write_lock(this->lock); 456: ca->cert = add_cert_internal(this, cert, FALSE); 457: this->sections->insert_last(this->sections, ca); 458: this->lock->unlock(this->lock); 459: DBG1(DBG_CFG, "added ca '%s'", msg->add_ca.name); 460: } 461: } 462: 463: METHOD(stroke_ca_t, del, void, 464: private_stroke_ca_t *this, stroke_msg_t *msg) 465: { 466: enumerator_t *enumerator; 467: ca_section_t *ca = NULL; 468: 469: this->lock->write_lock(this->lock); 470: enumerator = this->sections->create_enumerator(this->sections); 471: while (enumerator->enumerate(enumerator, &ca)) 472: { 473: if (streq(ca->name, msg->del_ca.name)) 474: { 475: this->sections->remove_at(this->sections, enumerator); 476: break; 477: } 478: ca = NULL; 479: } 480: enumerator->destroy(enumerator); 481: if (ca) 482: { 483: this->certs->remove(this->certs, ca->cert, (void*)remove_cert); 484: } 485: this->lock->unlock(this->lock); 486: if (!ca) 487: { 488: DBG1(DBG_CFG, "no ca named '%s' found\n", msg->del_ca.name); 489: return; 490: } 491: ca_section_destroy(ca); 492: 493: lib->credmgr->flush_cache(lib->credmgr, CERT_ANY); 494: } 495: 496: METHOD(stroke_ca_t, get_cert_ref, certificate_t*, 497: private_stroke_ca_t *this, certificate_t *cert) 498: { 499: ca_cert_t *found; 500: 501: this->lock->read_lock(this->lock); 502: if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert)) 503: { 504: cert->destroy(cert); 505: cert = found->cert->get_ref(found->cert); 506: } 507: this->lock->unlock(this->lock); 508: return cert; 509: } 510: 511: METHOD(stroke_ca_t, reload_certs, void, 512: private_stroke_ca_t *this) 513: { 514: enumerator_t *enumerator; 515: certificate_t *cert; 516: ca_section_t *ca; 517: certificate_type_t type = CERT_X509; 518: 519: /* holding the write lock while loading/parsing certificates is not optimal, 520: * however, there usually are not that many ca sections configured */ 521: this->lock->write_lock(this->lock); 522: if (this->sections->get_count(this->sections)) 523: { 524: DBG1(DBG_CFG, "rereading ca certificates in ca sections"); 525: } 526: enumerator = this->sections->create_enumerator(this->sections); 527: while (enumerator->enumerate(enumerator, &ca)) 528: { 529: cert = stroke_load_ca_cert(ca->path); 530: if (cert) 531: { 532: if (cert->equals(cert, ca->cert)) 533: { 534: cert->destroy(cert); 535: } 536: else 537: { 538: this->certs->remove(this->certs, ca->cert, (void*)remove_cert); 539: ca->cert->destroy(ca->cert); 540: ca->cert = add_cert_internal(this, cert, FALSE); 541: } 542: } 543: else 544: { 545: DBG1(DBG_CFG, "failed to reload certificate '%s', removing ca '%s'", 546: ca->path, ca->name); 547: this->sections->remove_at(this->sections, enumerator); 548: this->certs->remove(this->certs, ca->cert, (void*)remove_cert); 549: ca_section_destroy(ca); 550: type = CERT_ANY; 551: } 552: } 553: enumerator->destroy(enumerator); 554: this->lock->unlock(this->lock); 555: lib->credmgr->flush_cache(lib->credmgr, type); 556: } 557: 558: METHOD(stroke_ca_t, replace_certs, void, 559: private_stroke_ca_t *this, mem_cred_t *certs) 560: { 561: enumerator_t *enumerator; 562: certificate_t *cert; 563: 564: enumerator = certs->set.create_cert_enumerator(&certs->set, CERT_X509, 565: KEY_ANY, NULL, TRUE); 566: this->lock->write_lock(this->lock); 567: this->certs->remove(this->certs, NULL, (void*)remove_auto_certs); 568: while (enumerator->enumerate(enumerator, &cert)) 569: { 570: cert = add_cert_internal(this, cert->get_ref(cert), TRUE); 571: cert->destroy(cert); 572: } 573: this->lock->unlock(this->lock); 574: enumerator->destroy(enumerator); 575: lib->credmgr->flush_cache(lib->credmgr, CERT_X509); 576: } 577: /** 578: * list crl or ocsp URIs 579: */ 580: static void list_uris(linked_list_t *list, char *label, FILE *out) 581: { 582: bool first = TRUE; 583: char *uri; 584: enumerator_t *enumerator; 585: 586: enumerator = list->create_enumerator(list); 587: while (enumerator->enumerate(enumerator, (void**)&uri)) 588: { 589: if (first) 590: { 591: fprintf(out, "%s", label); 592: first = FALSE; 593: } 594: else 595: { 596: fprintf(out, " "); 597: } 598: fprintf(out, "'%s'\n", uri); 599: } 600: enumerator->destroy(enumerator); 601: } 602: 603: METHOD(stroke_ca_t, list, void, 604: private_stroke_ca_t *this, stroke_msg_t *msg, FILE *out) 605: { 606: bool first = TRUE; 607: ca_section_t *section; 608: enumerator_t *enumerator; 609: 610: this->lock->read_lock(this->lock); 611: enumerator = this->sections->create_enumerator(this->sections); 612: while (enumerator->enumerate(enumerator, (void**)§ion)) 613: { 614: certificate_t *cert = section->cert; 615: public_key_t *public = cert->get_public_key(cert); 616: chunk_t chunk; 617: 618: if (first) 619: { 620: fprintf(out, "\n"); 621: fprintf(out, "List of CA Information Sections:\n"); 622: first = FALSE; 623: } 624: fprintf(out, "\n"); 625: fprintf(out, " authname: \"%Y\"\n", cert->get_subject(cert)); 626: 627: /* list authkey and keyid */ 628: if (public) 629: { 630: if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk)) 631: { 632: fprintf(out, " authkey: %#B\n", &chunk); 633: } 634: if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &chunk)) 635: { 636: fprintf(out, " keyid: %#B\n", &chunk); 637: } 638: public->destroy(public); 639: } 640: list_uris(section->crl, " crluris: ", out); 641: list_uris(section->ocsp, " ocspuris: ", out); 642: if (section->certuribase) 643: { 644: fprintf(out, " certuribase: '%s'\n", section->certuribase); 645: } 646: } 647: enumerator->destroy(enumerator); 648: this->lock->unlock(this->lock); 649: } 650: 651: METHOD(stroke_ca_t, destroy, void, 652: private_stroke_ca_t *this) 653: { 654: this->sections->destroy_function(this->sections, (void*)ca_section_destroy); 655: this->certs->destroy_function(this->certs, (void*)ca_cert_destroy); 656: this->lock->destroy(this->lock); 657: free(this); 658: } 659: 660: /* 661: * see header file 662: */ 663: stroke_ca_t *stroke_ca_create() 664: { 665: private_stroke_ca_t *this; 666: 667: INIT(this, 668: .public = { 669: .set = { 670: .create_private_enumerator = (void*)return_null, 671: .create_cert_enumerator = _create_cert_enumerator, 672: .create_shared_enumerator = (void*)return_null, 673: .create_cdp_enumerator = _create_cdp_enumerator, 674: .cache_cert = (void*)nop, 675: }, 676: .add = _add, 677: .del = _del, 678: .list = _list, 679: .get_cert_ref = _get_cert_ref, 680: .reload_certs = _reload_certs, 681: .replace_certs = _replace_certs, 682: .destroy = _destroy, 683: }, 684: .sections = linked_list_create(), 685: .certs = linked_list_create(), 686: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), 687: ); 688: 689: return &this->public; 690: }