Annotation of embedaddon/strongswan/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2008 Tobias Brunner
! 3: * Copyright (C) 2006-2009 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 "ike_cert_pre.h"
! 18:
! 19: #include <daemon.h>
! 20: #include <sa/ike_sa.h>
! 21: #include <encoding/payloads/cert_payload.h>
! 22: #include <encoding/payloads/certreq_payload.h>
! 23: #include <credentials/certificates/x509.h>
! 24:
! 25:
! 26: typedef struct private_ike_cert_pre_t private_ike_cert_pre_t;
! 27:
! 28: /**
! 29: * Private members of a ike_cert_pre_t task.
! 30: */
! 31: struct private_ike_cert_pre_t {
! 32:
! 33: /**
! 34: * Public methods and task_t interface.
! 35: */
! 36: ike_cert_pre_t public;
! 37:
! 38: /**
! 39: * Assigned IKE_SA.
! 40: */
! 41: ike_sa_t *ike_sa;
! 42:
! 43: /**
! 44: * Are we the initiator?
! 45: */
! 46: bool initiator;
! 47:
! 48: /**
! 49: * Do we accept HTTP certificate lookup requests
! 50: */
! 51: bool do_http_lookup;
! 52:
! 53: /**
! 54: * whether this is the final authentication round
! 55: */
! 56: bool final;
! 57: };
! 58:
! 59: /**
! 60: * Process a single certificate request payload
! 61: */
! 62: static void process_certreq(private_ike_cert_pre_t *this,
! 63: certreq_payload_t *certreq, auth_cfg_t *auth)
! 64: {
! 65: enumerator_t *enumerator;
! 66: u_int unknown = 0;
! 67: chunk_t keyid;
! 68:
! 69: this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE);
! 70:
! 71: if (certreq->get_cert_type(certreq) != CERT_X509)
! 72: {
! 73: DBG1(DBG_IKE, "cert payload %N not supported - ignored",
! 74: certificate_type_names, certreq->get_cert_type(certreq));
! 75: return;
! 76: }
! 77:
! 78: enumerator = certreq->create_keyid_enumerator(certreq);
! 79: while (enumerator->enumerate(enumerator, &keyid))
! 80: {
! 81: identification_t *id;
! 82: certificate_t *cert;
! 83:
! 84: id = identification_create_from_encoding(ID_KEY_ID, keyid);
! 85: cert = lib->credmgr->get_cert(lib->credmgr,
! 86: CERT_X509, KEY_ANY, id, TRUE);
! 87: if (cert)
! 88: {
! 89: DBG1(DBG_IKE, "received cert request for \"%Y\"",
! 90: cert->get_subject(cert));
! 91: auth->add(auth, AUTH_RULE_CA_CERT, cert);
! 92: }
! 93: else
! 94: {
! 95: DBG2(DBG_IKE, "received cert request for unknown ca with keyid %Y",
! 96: id);
! 97: unknown++;
! 98: }
! 99: id->destroy(id);
! 100: }
! 101: enumerator->destroy(enumerator);
! 102: if (unknown)
! 103: {
! 104: DBG1(DBG_IKE, "received %u cert requests for an unknown ca",
! 105: unknown);
! 106: }
! 107: }
! 108:
! 109: /**
! 110: * Process a single notify payload
! 111: */
! 112: static void process_notify(private_ike_cert_pre_t *this,
! 113: notify_payload_t *notify)
! 114: {
! 115: switch (notify->get_notify_type(notify))
! 116: {
! 117: case HTTP_CERT_LOOKUP_SUPPORTED:
! 118: this->ike_sa->enable_extension(this->ike_sa, EXT_HASH_AND_URL);
! 119: break;
! 120: default:
! 121: break;
! 122: }
! 123: }
! 124:
! 125: /**
! 126: * read certificate requests
! 127: */
! 128: static void process_certreqs(private_ike_cert_pre_t *this, message_t *message)
! 129: {
! 130: enumerator_t *enumerator;
! 131: payload_t *payload;
! 132: auth_cfg_t *auth;
! 133:
! 134: auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
! 135:
! 136: enumerator = message->create_payload_enumerator(message);
! 137: while (enumerator->enumerate(enumerator, &payload))
! 138: {
! 139: switch (payload->get_type(payload))
! 140: {
! 141: case PLV2_CERTREQ:
! 142: process_certreq(this, (certreq_payload_t*)payload, auth);
! 143: break;
! 144: case PLV2_NOTIFY:
! 145: process_notify(this, (notify_payload_t*)payload);
! 146: break;
! 147: default:
! 148: /* ignore other payloads here, these are handled elsewhere */
! 149: break;
! 150: }
! 151: }
! 152: enumerator->destroy(enumerator);
! 153: }
! 154:
! 155: /**
! 156: * tries to extract a certificate from the cert payload or the credential
! 157: * manager (based on the hash of a "Hash and URL" encoded cert).
! 158: * Note: the returned certificate (if any) has to be destroyed
! 159: */
! 160: static certificate_t *try_get_cert(cert_payload_t *cert_payload)
! 161: {
! 162: certificate_t *cert = NULL;
! 163:
! 164: switch (cert_payload->get_cert_encoding(cert_payload))
! 165: {
! 166: case ENC_X509_SIGNATURE:
! 167: {
! 168: cert = cert_payload->get_cert(cert_payload);
! 169: break;
! 170: }
! 171: case ENC_X509_HASH_AND_URL:
! 172: {
! 173: identification_t *id;
! 174: chunk_t hash = cert_payload->get_hash(cert_payload);
! 175: if (!hash.ptr)
! 176: {
! 177: /* invalid "Hash and URL" data (logged elsewhere) */
! 178: break;
! 179: }
! 180: id = identification_create_from_encoding(ID_KEY_ID, hash);
! 181: cert = lib->credmgr->get_cert(lib->credmgr,
! 182: CERT_X509, KEY_ANY, id, FALSE);
! 183: id->destroy(id);
! 184: break;
! 185: }
! 186: default:
! 187: {
! 188: break;
! 189: }
! 190: }
! 191: return cert;
! 192: }
! 193:
! 194: /**
! 195: * Process a X509 certificate payload
! 196: */
! 197: static void process_x509(cert_payload_t *payload, auth_cfg_t *auth,
! 198: cert_encoding_t encoding, bool *first)
! 199: {
! 200: certificate_t *cert;
! 201: char *url;
! 202:
! 203: cert = try_get_cert(payload);
! 204: if (cert)
! 205: {
! 206: if (*first)
! 207: { /* the first is an end entity certificate */
! 208: DBG1(DBG_IKE, "received end entity cert \"%Y\"",
! 209: cert->get_subject(cert));
! 210: auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert);
! 211: *first = FALSE;
! 212: }
! 213: else
! 214: {
! 215: DBG1(DBG_IKE, "received issuer cert \"%Y\"",
! 216: cert->get_subject(cert));
! 217: auth->add(auth, AUTH_HELPER_IM_CERT, cert);
! 218: }
! 219: }
! 220: else if (encoding == ENC_X509_HASH_AND_URL)
! 221: {
! 222: /* we fetch the certificate not yet, but only if
! 223: * it is really needed during authentication */
! 224: url = payload->get_url(payload);
! 225: if (!url)
! 226: {
! 227: DBG1(DBG_IKE, "received invalid hash-and-url "
! 228: "encoded cert, ignore");
! 229: return;
! 230: }
! 231: url = strdup(url);
! 232: if (*first)
! 233: { /* first URL is for an end entity certificate */
! 234: DBG1(DBG_IKE, "received hash-and-url for end entity cert \"%s\"",
! 235: url);
! 236: auth->add(auth, AUTH_HELPER_SUBJECT_HASH_URL, url);
! 237: *first = FALSE;
! 238: }
! 239: else
! 240: {
! 241: DBG1(DBG_IKE, "received hash-and-url for issuer cert \"%s\"", url);
! 242: auth->add(auth, AUTH_HELPER_IM_HASH_URL, url);
! 243: }
! 244: }
! 245: }
! 246:
! 247: /**
! 248: * Process a CRL certificate payload
! 249: */
! 250: static void process_crl(cert_payload_t *payload, auth_cfg_t *auth)
! 251: {
! 252: certificate_t *cert;
! 253:
! 254: cert = payload->get_cert(payload);
! 255: if (cert)
! 256: {
! 257: DBG1(DBG_IKE, "received CRL \"%Y\"", cert->get_subject(cert));
! 258: auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert);
! 259: }
! 260: }
! 261:
! 262: /**
! 263: * Process an attribute certificate payload
! 264: */
! 265: static void process_ac(cert_payload_t *payload, auth_cfg_t *auth)
! 266: {
! 267: certificate_t *cert;
! 268:
! 269: cert = payload->get_cert(payload);
! 270: if (cert)
! 271: {
! 272: if (cert->get_issuer(cert))
! 273: {
! 274: DBG1(DBG_IKE, "received attribute certificate issued by \"%Y\"",
! 275: cert->get_issuer(cert));
! 276: }
! 277: else if (cert->get_subject(cert))
! 278: {
! 279: DBG1(DBG_IKE, "received attribute certificate for \"%Y\"",
! 280: cert->get_subject(cert));
! 281: }
! 282: auth->add(auth, AUTH_HELPER_AC_CERT, cert);
! 283: }
! 284: }
! 285:
! 286: /**
! 287: * Process certificate payloads
! 288: */
! 289: static void process_certs(private_ike_cert_pre_t *this, message_t *message)
! 290: {
! 291: enumerator_t *enumerator;
! 292: payload_t *payload;
! 293: auth_cfg_t *auth;
! 294: bool first = TRUE;
! 295:
! 296: auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
! 297:
! 298: enumerator = message->create_payload_enumerator(message);
! 299: while (enumerator->enumerate(enumerator, &payload))
! 300: {
! 301: if (payload->get_type(payload) == PLV2_CERTIFICATE)
! 302: {
! 303: cert_payload_t *cert_payload;
! 304: cert_encoding_t encoding;
! 305:
! 306: cert_payload = (cert_payload_t*)payload;
! 307: encoding = cert_payload->get_cert_encoding(cert_payload);
! 308:
! 309: switch (encoding)
! 310: {
! 311: case ENC_X509_HASH_AND_URL:
! 312: if (!this->do_http_lookup)
! 313: {
! 314: DBG1(DBG_IKE, "received hash-and-url encoded cert, but "
! 315: "we don't accept them, ignore");
! 316: break;
! 317: }
! 318: /* FALL */
! 319: case ENC_X509_SIGNATURE:
! 320: process_x509(cert_payload, auth, encoding, &first);
! 321: break;
! 322: case ENC_CRL:
! 323: process_crl(cert_payload, auth);
! 324: break;
! 325: case ENC_X509_ATTRIBUTE:
! 326: process_ac(cert_payload, auth);
! 327: break;
! 328: case ENC_PKCS7_WRAPPED_X509:
! 329: case ENC_PGP:
! 330: case ENC_DNS_SIGNED_KEY:
! 331: case ENC_KERBEROS_TOKEN:
! 332: case ENC_ARL:
! 333: case ENC_SPKI:
! 334: case ENC_RAW_RSA_KEY:
! 335: case ENC_X509_HASH_AND_URL_BUNDLE:
! 336: case ENC_OCSP_CONTENT:
! 337: default:
! 338: DBG1(DBG_ENC, "certificate encoding %N not supported",
! 339: cert_encoding_names, encoding);
! 340: }
! 341: }
! 342: }
! 343: enumerator->destroy(enumerator);
! 344: }
! 345:
! 346: /**
! 347: * add the keyid of a certificate to the certificate request payload
! 348: */
! 349: static void add_certreq(certreq_payload_t **req, certificate_t *cert)
! 350: {
! 351: switch (cert->get_type(cert))
! 352: {
! 353: case CERT_X509:
! 354: {
! 355: public_key_t *public;
! 356: chunk_t keyid;
! 357: x509_t *x509 = (x509_t*)cert;
! 358:
! 359: if (!(x509->get_flags(x509) & X509_CA))
! 360: { /* no CA cert, skip */
! 361: break;
! 362: }
! 363: public = cert->get_public_key(cert);
! 364: if (!public)
! 365: {
! 366: break;
! 367: }
! 368: if (*req == NULL)
! 369: {
! 370: *req = certreq_payload_create_type(CERT_X509);
! 371: }
! 372: if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid))
! 373: {
! 374: (*req)->add_keyid(*req, keyid);
! 375: DBG1(DBG_IKE, "sending cert request for \"%Y\"",
! 376: cert->get_subject(cert));
! 377: }
! 378: public->destroy(public);
! 379: break;
! 380: }
! 381: default:
! 382: break;
! 383: }
! 384: }
! 385:
! 386: /**
! 387: * add a auth_cfg's CA certificates to the certificate request
! 388: */
! 389: static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth)
! 390: {
! 391: enumerator_t *enumerator;
! 392: auth_rule_t type;
! 393: void *value;
! 394:
! 395: enumerator = auth->create_enumerator(auth);
! 396: while (enumerator->enumerate(enumerator, &type, &value))
! 397: {
! 398: switch (type)
! 399: {
! 400: case AUTH_RULE_CA_CERT:
! 401: add_certreq(req, (certificate_t*)value);
! 402: break;
! 403: default:
! 404: break;
! 405: }
! 406: }
! 407: enumerator->destroy(enumerator);
! 408: }
! 409:
! 410: /**
! 411: * build certificate requests
! 412: */
! 413: static void build_certreqs(private_ike_cert_pre_t *this, message_t *message)
! 414: {
! 415: enumerator_t *enumerator;
! 416: ike_cfg_t *ike_cfg;
! 417: peer_cfg_t *peer_cfg;
! 418: certificate_t *cert;
! 419: auth_cfg_t *auth;
! 420: certreq_payload_t *req = NULL;
! 421:
! 422: ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
! 423: if (!ike_cfg->send_certreq(ike_cfg))
! 424: {
! 425: return;
! 426: }
! 427:
! 428: /* check if we require a specific CA for that peer */
! 429: peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
! 430: if (peer_cfg)
! 431: {
! 432: enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
! 433: while (enumerator->enumerate(enumerator, &auth))
! 434: {
! 435: add_certreqs(&req, auth);
! 436: }
! 437: enumerator->destroy(enumerator);
! 438: }
! 439:
! 440: if (!req)
! 441: {
! 442: /* otherwise add all trusted CA certificates */
! 443: enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
! 444: CERT_ANY, KEY_ANY, NULL, TRUE);
! 445: while (enumerator->enumerate(enumerator, &cert))
! 446: {
! 447: add_certreq(&req, cert);
! 448: }
! 449: enumerator->destroy(enumerator);
! 450: }
! 451:
! 452: if (req)
! 453: {
! 454: message->add_payload(message, (payload_t*)req);
! 455:
! 456: if (lib->settings->get_bool(lib->settings,
! 457: "%s.hash_and_url", FALSE, lib->ns))
! 458: {
! 459: message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED,
! 460: chunk_empty);
! 461: this->do_http_lookup = TRUE;
! 462: }
! 463: }
! 464: }
! 465:
! 466: /**
! 467: * Check if this is the final authentication round
! 468: */
! 469: static bool final_auth(message_t *message)
! 470: {
! 471: /* we check for an AUTH payload without a ANOTHER_AUTH_FOLLOWS notify */
! 472: if (message->get_payload(message, PLV2_AUTH) == NULL)
! 473: {
! 474: return FALSE;
! 475: }
! 476: if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS))
! 477: {
! 478: return FALSE;
! 479: }
! 480: return TRUE;
! 481: }
! 482:
! 483: METHOD(task_t, build_i, status_t,
! 484: private_ike_cert_pre_t *this, message_t *message)
! 485: {
! 486: if (message->get_message_id(message) == 1)
! 487: { /* initiator sends CERTREQs in first IKE_AUTH */
! 488: build_certreqs(this, message);
! 489: }
! 490: return NEED_MORE;
! 491: }
! 492:
! 493: METHOD(task_t, process_r, status_t,
! 494: private_ike_cert_pre_t *this, message_t *message)
! 495: {
! 496: if (message->get_exchange_type(message) != IKE_SA_INIT)
! 497: { /* handle certreqs/certs in any IKE_AUTH, just in case */
! 498: process_certreqs(this, message);
! 499: process_certs(this, message);
! 500: }
! 501: this->final = final_auth(message);
! 502: return NEED_MORE;
! 503: }
! 504:
! 505: METHOD(task_t, build_r, status_t,
! 506: private_ike_cert_pre_t *this, message_t *message)
! 507: {
! 508: if (message->get_exchange_type(message) == IKE_SA_INIT)
! 509: {
! 510: build_certreqs(this, message);
! 511: }
! 512: if (this->final)
! 513: {
! 514: return SUCCESS;
! 515: }
! 516: return NEED_MORE;
! 517: }
! 518:
! 519: METHOD(task_t, process_i, status_t,
! 520: private_ike_cert_pre_t *this, message_t *message)
! 521: {
! 522: if (message->get_exchange_type(message) == IKE_SA_INIT)
! 523: {
! 524: process_certreqs(this, message);
! 525: }
! 526: process_certs(this, message);
! 527:
! 528: if (final_auth(message))
! 529: {
! 530: return SUCCESS;
! 531: }
! 532: return NEED_MORE;
! 533: }
! 534:
! 535: METHOD(task_t, get_type, task_type_t,
! 536: private_ike_cert_pre_t *this)
! 537: {
! 538: return TASK_IKE_CERT_PRE;
! 539: }
! 540:
! 541: METHOD(task_t, migrate, void,
! 542: private_ike_cert_pre_t *this, ike_sa_t *ike_sa)
! 543: {
! 544: this->ike_sa = ike_sa;
! 545: }
! 546:
! 547: METHOD(task_t, destroy, void,
! 548: private_ike_cert_pre_t *this)
! 549: {
! 550: free(this);
! 551: }
! 552:
! 553: /*
! 554: * Described in header.
! 555: */
! 556: ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator)
! 557: {
! 558: private_ike_cert_pre_t *this;
! 559:
! 560: INIT(this,
! 561: .public = {
! 562: .task = {
! 563: .get_type = _get_type,
! 564: .migrate = _migrate,
! 565: .destroy = _destroy,
! 566: },
! 567: },
! 568: .ike_sa = ike_sa,
! 569: .initiator = initiator,
! 570: );
! 571:
! 572: if (initiator)
! 573: {
! 574: this->public.task.build = _build_i;
! 575: this->public.task.process = _process_i;
! 576: }
! 577: else
! 578: {
! 579: this->public.task.build = _build_r;
! 580: this->public.task.process = _process_r;
! 581: }
! 582:
! 583: return &this->public;
! 584: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>