Annotation of embedaddon/strongswan/src/libcharon/plugins/stroke/stroke_ca.c, revision 1.1
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>