Annotation of embedaddon/strongswan/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2011 Martin Willi
! 3: * Copyright (C) 2011 revosec AG
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: /*
! 17: * Copyright (C) 2013 Volker RĂ¼melin
! 18: *
! 19: * Permission is hereby granted, free of charge, to any person obtaining a copy
! 20: * of this software and associated documentation files (the "Software"), to deal
! 21: * in the Software without restriction, including without limitation the rights
! 22: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
! 23: * copies of the Software, and to permit persons to whom the Software is
! 24: * furnished to do so, subject to the following conditions:
! 25: *
! 26: * The above copyright notice and this permission notice shall be included in
! 27: * all copies or substantial portions of the Software.
! 28: *
! 29: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! 30: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! 31: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
! 32: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
! 33: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
! 34: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
! 35: * THE SOFTWARE.
! 36: */
! 37:
! 38: #include "isakmp_cert_pre.h"
! 39:
! 40: #include <daemon.h>
! 41: #include <sa/ike_sa.h>
! 42: #include <encoding/payloads/cert_payload.h>
! 43: #include <encoding/payloads/sa_payload.h>
! 44: #include <encoding/payloads/certreq_payload.h>
! 45: #include <credentials/certificates/x509.h>
! 46: #include <credentials/containers/pkcs7.h>
! 47:
! 48:
! 49: typedef struct private_isakmp_cert_pre_t private_isakmp_cert_pre_t;
! 50:
! 51: /**
! 52: * Private members of a isakmp_cert_pre_t task.
! 53: */
! 54: struct private_isakmp_cert_pre_t {
! 55:
! 56: /**
! 57: * Public methods and task_t interface.
! 58: */
! 59: isakmp_cert_pre_t public;
! 60:
! 61: /**
! 62: * Assigned IKE_SA.
! 63: */
! 64: ike_sa_t *ike_sa;
! 65:
! 66: /**
! 67: * Are we the initiator?
! 68: */
! 69: bool initiator;
! 70:
! 71: /**
! 72: * Send certificate requests?
! 73: */
! 74: bool send_req;
! 75:
! 76: /** next message we expect */
! 77: enum {
! 78: CR_SA,
! 79: CR_KE,
! 80: CR_AUTH,
! 81: } state;
! 82: };
! 83:
! 84: /**
! 85: * Find the CA certificate for a given certreq payload
! 86: */
! 87: static certificate_t* find_certificate(private_isakmp_cert_pre_t *this,
! 88: certreq_payload_t *certreq)
! 89: {
! 90: identification_t *id;
! 91: certificate_t *cert;
! 92:
! 93: if (certreq->get_cert_type(certreq) != CERT_X509)
! 94: {
! 95: DBG1(DBG_IKE, "%N CERTREQ not supported - ignored",
! 96: certificate_type_names, certreq->get_cert_type(certreq));
! 97: return NULL;
! 98: }
! 99: id = certreq->get_dn(certreq);
! 100: if (!id)
! 101: {
! 102: DBG1(DBG_IKE, "ignoring certificate request without data",
! 103: certificate_type_names, certreq->get_cert_type(certreq));
! 104: return NULL;
! 105: }
! 106: cert = lib->credmgr->get_cert(lib->credmgr, CERT_X509, KEY_ANY, id, TRUE);
! 107: if (cert)
! 108: {
! 109: DBG1(DBG_IKE, "received cert request for '%Y'",
! 110: cert->get_subject(cert));
! 111: }
! 112: else
! 113: {
! 114: DBG1(DBG_IKE, "received cert request for unknown ca '%Y'", id);
! 115: }
! 116: id->destroy(id);
! 117:
! 118: return cert;
! 119: }
! 120:
! 121: /**
! 122: * read certificate requests
! 123: */
! 124: static void process_certreqs(private_isakmp_cert_pre_t *this, message_t *message)
! 125: {
! 126: enumerator_t *enumerator;
! 127: payload_t *payload;
! 128: auth_cfg_t *auth;
! 129:
! 130: auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
! 131:
! 132: enumerator = message->create_payload_enumerator(message);
! 133: while (enumerator->enumerate(enumerator, &payload))
! 134: {
! 135: switch (payload->get_type(payload))
! 136: {
! 137: case PLV1_CERTREQ:
! 138: {
! 139: certificate_t *cert;
! 140:
! 141: this->ike_sa->set_condition(this->ike_sa,
! 142: COND_CERTREQ_SEEN, TRUE);
! 143: cert = find_certificate(this, (certreq_payload_t*)payload);
! 144: if (cert)
! 145: {
! 146: auth->add(auth, AUTH_RULE_CA_CERT, cert);
! 147: }
! 148: break;
! 149: }
! 150: default:
! 151: break;
! 152: }
! 153: }
! 154: enumerator->destroy(enumerator);
! 155: }
! 156:
! 157: /**
! 158: * Process an X509 certificate payload
! 159: */
! 160: static void process_x509(cert_payload_t *payload, auth_cfg_t *auth, bool *first)
! 161: {
! 162: certificate_t *cert;
! 163:
! 164: cert = payload->get_cert(payload);
! 165: if (cert)
! 166: {
! 167: if (*first)
! 168: { /* the first is an end entity certificate */
! 169: DBG1(DBG_IKE, "received end entity cert \"%Y\"",
! 170: cert->get_subject(cert));
! 171: auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert);
! 172: *first = FALSE;
! 173: }
! 174: else
! 175: {
! 176: DBG1(DBG_IKE, "received issuer cert \"%Y\"",
! 177: cert->get_subject(cert));
! 178: auth->add(auth, AUTH_HELPER_IM_CERT, cert);
! 179: }
! 180: }
! 181: }
! 182:
! 183: /**
! 184: * Process a CRL certificate payload
! 185: */
! 186: static void process_crl(cert_payload_t *payload, auth_cfg_t *auth)
! 187: {
! 188: certificate_t *cert;
! 189:
! 190: cert = payload->get_cert(payload);
! 191: if (cert)
! 192: {
! 193: DBG1(DBG_IKE, "received CRL \"%Y\"", cert->get_subject(cert));
! 194: auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert);
! 195: }
! 196: }
! 197:
! 198: /**
! 199: * Process a PKCS7 certificate payload
! 200: */
! 201: static void process_pkcs7(cert_payload_t *payload, auth_cfg_t *auth)
! 202: {
! 203: enumerator_t *enumerator;
! 204: container_t *container;
! 205: certificate_t *cert;
! 206: pkcs7_t *pkcs7;
! 207:
! 208: container = payload->get_container(payload);
! 209: if (!container)
! 210: {
! 211: return;
! 212: }
! 213: switch (container->get_type(container))
! 214: {
! 215: case CONTAINER_PKCS7_DATA:
! 216: case CONTAINER_PKCS7_SIGNED_DATA:
! 217: case CONTAINER_PKCS7_ENVELOPED_DATA:
! 218: break;
! 219: default:
! 220: container->destroy(container);
! 221: return;
! 222: }
! 223:
! 224: pkcs7 = (pkcs7_t *)container;
! 225: enumerator = pkcs7->create_cert_enumerator(pkcs7);
! 226: while (enumerator->enumerate(enumerator, &cert))
! 227: {
! 228: if (cert->get_type(cert) == CERT_X509)
! 229: {
! 230: x509_t *x509 = (x509_t*)cert;
! 231:
! 232: if (x509->get_flags(x509) & X509_CA)
! 233: {
! 234: DBG1(DBG_IKE, "received issuer cert \"%Y\"",
! 235: cert->get_subject(cert));
! 236: auth->add(auth, AUTH_HELPER_IM_CERT, cert->get_ref(cert));
! 237: }
! 238: else
! 239: {
! 240: DBG1(DBG_IKE, "received end entity cert \"%Y\"",
! 241: cert->get_subject(cert));
! 242: auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert->get_ref(cert));
! 243: }
! 244: }
! 245: else
! 246: {
! 247: DBG1(DBG_IKE, "received unsupported cert type %N",
! 248: certificate_type_names, cert->get_type(cert));
! 249: }
! 250: }
! 251: enumerator->destroy(enumerator);
! 252:
! 253: container->destroy(container);
! 254: }
! 255:
! 256: /**
! 257: * Import received certificates
! 258: */
! 259: static void process_certs(private_isakmp_cert_pre_t *this, message_t *message)
! 260: {
! 261: enumerator_t *enumerator;
! 262: payload_t *payload;
! 263: auth_cfg_t *auth;
! 264: bool first = TRUE;
! 265:
! 266: auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
! 267:
! 268: enumerator = message->create_payload_enumerator(message);
! 269: while (enumerator->enumerate(enumerator, &payload))
! 270: {
! 271: if (payload->get_type(payload) == PLV1_CERTIFICATE)
! 272: {
! 273: cert_payload_t *cert_payload;
! 274: cert_encoding_t encoding;
! 275:
! 276: cert_payload = (cert_payload_t*)payload;
! 277: encoding = cert_payload->get_cert_encoding(cert_payload);
! 278:
! 279: switch (encoding)
! 280: {
! 281: case ENC_X509_SIGNATURE:
! 282: process_x509(cert_payload, auth, &first);
! 283: break;
! 284: case ENC_CRL:
! 285: process_crl(cert_payload, auth);
! 286: break;
! 287: case ENC_PKCS7_WRAPPED_X509:
! 288: process_pkcs7(cert_payload, auth);
! 289: break;
! 290: case ENC_PGP:
! 291: case ENC_DNS_SIGNED_KEY:
! 292: case ENC_KERBEROS_TOKEN:
! 293: case ENC_ARL:
! 294: case ENC_SPKI:
! 295: case ENC_X509_ATTRIBUTE:
! 296: case ENC_RAW_RSA_KEY:
! 297: case ENC_X509_HASH_AND_URL_BUNDLE:
! 298: case ENC_OCSP_CONTENT:
! 299: default:
! 300: DBG1(DBG_ENC, "certificate encoding %N not supported",
! 301: cert_encoding_names, encoding);
! 302: }
! 303: }
! 304: }
! 305: enumerator->destroy(enumerator);
! 306: }
! 307:
! 308: /**
! 309: * Add the subject of a CA certificate a message
! 310: */
! 311: static void add_certreq(private_isakmp_cert_pre_t *this, message_t *message,
! 312: certificate_t *cert)
! 313: {
! 314: if (cert->get_type(cert) == CERT_X509)
! 315: {
! 316: x509_t *x509 = (x509_t*)cert;
! 317:
! 318: if (x509->get_flags(x509) & X509_CA)
! 319: {
! 320: DBG1(DBG_IKE, "sending cert request for \"%Y\"",
! 321: cert->get_subject(cert));
! 322: message->add_payload(message, (payload_t*)
! 323: certreq_payload_create_dn(cert->get_subject(cert)));
! 324: }
! 325: }
! 326: }
! 327:
! 328: /**
! 329: * Add auth_cfg's CA certificates to the certificate request
! 330: */
! 331: static void add_certreqs(private_isakmp_cert_pre_t *this,
! 332: auth_cfg_t *auth, message_t *message)
! 333: {
! 334: enumerator_t *enumerator;
! 335: auth_rule_t type;
! 336: void *value;
! 337:
! 338: enumerator = auth->create_enumerator(auth);
! 339: while (enumerator->enumerate(enumerator, &type, &value))
! 340: {
! 341: switch (type)
! 342: {
! 343: case AUTH_RULE_CA_CERT:
! 344: add_certreq(this, message, (certificate_t*)value);
! 345: break;
! 346: default:
! 347: break;
! 348: }
! 349: }
! 350: enumerator->destroy(enumerator);
! 351: }
! 352:
! 353: /**
! 354: * Build certificate requests
! 355: */
! 356: static void build_certreqs(private_isakmp_cert_pre_t *this, message_t *message)
! 357: {
! 358: enumerator_t *enumerator;
! 359: ike_cfg_t *ike_cfg;
! 360: peer_cfg_t *peer_cfg;
! 361: certificate_t *cert;
! 362: auth_cfg_t *auth;
! 363:
! 364: ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
! 365: if (!ike_cfg->send_certreq(ike_cfg))
! 366: {
! 367: return;
! 368: }
! 369: /* check if we require a specific CA for that peer */
! 370: peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
! 371: if (peer_cfg)
! 372: {
! 373: enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
! 374: if (enumerator->enumerate(enumerator, &auth))
! 375: {
! 376: add_certreqs(this, auth, message);
! 377: }
! 378: enumerator->destroy(enumerator);
! 379: }
! 380: if (!message->get_payload(message, PLV1_CERTREQ))
! 381: {
! 382: /* otherwise add all trusted CA certificates */
! 383: enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
! 384: CERT_ANY, KEY_ANY, NULL, TRUE);
! 385: while (enumerator->enumerate(enumerator, &cert))
! 386: {
! 387: add_certreq(this, message, cert);
! 388: }
! 389: enumerator->destroy(enumerator);
! 390: }
! 391: }
! 392:
! 393: /**
! 394: * Check if we actually use certificates for authentication
! 395: */
! 396: static bool use_certs(private_isakmp_cert_pre_t *this, message_t *message)
! 397: {
! 398: enumerator_t *enumerator;
! 399: payload_t *payload;
! 400: bool use = FALSE;
! 401:
! 402: enumerator = message->create_payload_enumerator(message);
! 403: while (enumerator->enumerate(enumerator, &payload))
! 404: {
! 405: if (payload->get_type(payload) == PLV1_SECURITY_ASSOCIATION)
! 406: {
! 407: sa_payload_t *sa_payload = (sa_payload_t*)payload;
! 408:
! 409: switch (sa_payload->get_auth_method(sa_payload))
! 410: {
! 411: case AUTH_HYBRID_INIT_RSA:
! 412: case AUTH_HYBRID_RESP_RSA:
! 413: if (!this->initiator)
! 414: {
! 415: this->send_req = FALSE;
! 416: }
! 417: /* FALL */
! 418: case AUTH_RSA:
! 419: case AUTH_ECDSA_256:
! 420: case AUTH_ECDSA_384:
! 421: case AUTH_ECDSA_521:
! 422: case AUTH_XAUTH_INIT_RSA:
! 423: case AUTH_XAUTH_RESP_RSA:
! 424: use = TRUE;
! 425: break;
! 426: default:
! 427: break;
! 428: }
! 429: break;
! 430: }
! 431: }
! 432: enumerator->destroy(enumerator);
! 433:
! 434: return use;
! 435: }
! 436:
! 437: /**
! 438: * Check if we should send a certificate request
! 439: */
! 440: static bool send_certreq(private_isakmp_cert_pre_t *this)
! 441: {
! 442: enumerator_t *enumerator;
! 443: peer_cfg_t *peer_cfg;
! 444: auth_cfg_t *auth;
! 445: bool req = FALSE;
! 446: auth_class_t class;
! 447:
! 448: peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
! 449: if (peer_cfg)
! 450: {
! 451: enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
! 452: if (enumerator->enumerate(enumerator, &auth))
! 453: {
! 454: class = (intptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS);
! 455: if (class == AUTH_CLASS_PUBKEY)
! 456: {
! 457: req = TRUE;
! 458: }
! 459: }
! 460: enumerator->destroy(enumerator);
! 461: }
! 462: return req;
! 463: }
! 464:
! 465: METHOD(task_t, build_i, status_t,
! 466: private_isakmp_cert_pre_t *this, message_t *message)
! 467: {
! 468: switch (message->get_exchange_type(message))
! 469: {
! 470: case ID_PROT:
! 471: if (this->state == CR_AUTH)
! 472: {
! 473: build_certreqs(this, message);
! 474: }
! 475: return NEED_MORE;
! 476: case AGGRESSIVE:
! 477: if (this->state == CR_SA)
! 478: {
! 479: if (send_certreq(this))
! 480: {
! 481: build_certreqs(this, message);
! 482: }
! 483: }
! 484: return NEED_MORE;
! 485: default:
! 486: return FAILED;
! 487: }
! 488: }
! 489:
! 490: METHOD(task_t, process_r, status_t,
! 491: private_isakmp_cert_pre_t *this, message_t *message)
! 492: {
! 493: switch (message->get_exchange_type(message))
! 494: {
! 495: case ID_PROT:
! 496: {
! 497: switch (this->state)
! 498: {
! 499: case CR_SA:
! 500: if (!use_certs(this, message))
! 501: {
! 502: return SUCCESS;
! 503: }
! 504: return NEED_MORE;
! 505: case CR_KE:
! 506: process_certreqs(this, message);
! 507: return NEED_MORE;
! 508: case CR_AUTH:
! 509: process_certreqs(this, message);
! 510: process_certs(this, message);
! 511: return SUCCESS;
! 512: default:
! 513: return FAILED;
! 514: }
! 515: }
! 516: case AGGRESSIVE:
! 517: {
! 518: switch (this->state)
! 519: {
! 520: case CR_SA:
! 521: if (!use_certs(this, message))
! 522: {
! 523: return SUCCESS;
! 524: }
! 525: process_certreqs(this, message);
! 526: return NEED_MORE;
! 527: case CR_AUTH:
! 528: process_certs(this, message);
! 529: return SUCCESS;
! 530: default:
! 531: return FAILED;
! 532: }
! 533: }
! 534: default:
! 535: return FAILED;
! 536: }
! 537: }
! 538:
! 539: METHOD(task_t, build_r, status_t,
! 540: private_isakmp_cert_pre_t *this, message_t *message)
! 541: {
! 542: switch (message->get_exchange_type(message))
! 543: {
! 544: case ID_PROT:
! 545: switch (this->state)
! 546: {
! 547: case CR_SA:
! 548: this->state = CR_KE;
! 549: return NEED_MORE;
! 550: case CR_KE:
! 551: if (this->send_req)
! 552: {
! 553: build_certreqs(this, message);
! 554: }
! 555: this->state = CR_AUTH;
! 556: return NEED_MORE;
! 557: case CR_AUTH:
! 558: return NEED_MORE;
! 559: default:
! 560: return FAILED;
! 561: }
! 562: case AGGRESSIVE:
! 563: switch (this->state)
! 564: {
! 565: case CR_SA:
! 566: if (this->send_req)
! 567: {
! 568: build_certreqs(this, message);
! 569: }
! 570: this->state = CR_AUTH;
! 571: return NEED_MORE;
! 572: case CR_AUTH:
! 573: return SUCCESS;
! 574: default:
! 575: return FAILED;
! 576: }
! 577: default:
! 578: return FAILED;
! 579: }
! 580: }
! 581:
! 582: METHOD(task_t, process_i, status_t,
! 583: private_isakmp_cert_pre_t *this, message_t *message)
! 584: {
! 585: switch (message->get_exchange_type(message))
! 586: {
! 587: case ID_PROT:
! 588: {
! 589: switch (this->state)
! 590: {
! 591: case CR_SA:
! 592: if (!use_certs(this, message))
! 593: {
! 594: return SUCCESS;
! 595: }
! 596: this->state = CR_KE;
! 597: return NEED_MORE;
! 598: case CR_KE:
! 599: process_certreqs(this, message);
! 600: this->state = CR_AUTH;
! 601: return NEED_MORE;
! 602: case CR_AUTH:
! 603: process_certs(this, message);
! 604: return SUCCESS;
! 605: default:
! 606: return FAILED;
! 607: }
! 608: }
! 609: case AGGRESSIVE:
! 610: {
! 611: if (!use_certs(this, message))
! 612: {
! 613: return SUCCESS;
! 614: }
! 615: process_certreqs(this, message);
! 616: process_certs(this, message);
! 617: this->state = CR_AUTH;
! 618: return SUCCESS;
! 619: }
! 620: default:
! 621: return FAILED;
! 622: }
! 623: }
! 624:
! 625: METHOD(task_t, get_type, task_type_t,
! 626: private_isakmp_cert_pre_t *this)
! 627: {
! 628: return TASK_ISAKMP_CERT_PRE;
! 629: }
! 630:
! 631: METHOD(task_t, migrate, void,
! 632: private_isakmp_cert_pre_t *this, ike_sa_t *ike_sa)
! 633: {
! 634: this->ike_sa = ike_sa;
! 635: this->state = CR_SA;
! 636: this->send_req = TRUE;
! 637: }
! 638:
! 639: METHOD(task_t, destroy, void,
! 640: private_isakmp_cert_pre_t *this)
! 641: {
! 642: free(this);
! 643: }
! 644:
! 645: /*
! 646: * Described in header.
! 647: */
! 648: isakmp_cert_pre_t *isakmp_cert_pre_create(ike_sa_t *ike_sa, bool initiator)
! 649: {
! 650: private_isakmp_cert_pre_t *this;
! 651:
! 652: INIT(this,
! 653: .public = {
! 654: .task = {
! 655: .get_type = _get_type,
! 656: .migrate = _migrate,
! 657: .destroy = _destroy,
! 658: },
! 659: },
! 660: .ike_sa = ike_sa,
! 661: .initiator = initiator,
! 662: .state = CR_SA,
! 663: .send_req = TRUE,
! 664: );
! 665: if (initiator)
! 666: {
! 667: this->public.task.build = _build_i;
! 668: this->public.task.process = _process_i;
! 669: }
! 670: else
! 671: {
! 672: this->public.task.build = _build_r;
! 673: this->public.task.process = _process_r;
! 674: }
! 675: return &this->public;
! 676: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>