Annotation of embedaddon/strongswan/src/libtls/tls_peer.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2010 Martin Willi
! 3: * Copyright (C) 2010 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: #include "tls_peer.h"
! 17:
! 18: #include <utils/debug.h>
! 19: #include <credentials/certificates/x509.h>
! 20:
! 21: #include <time.h>
! 22:
! 23: typedef struct private_tls_peer_t private_tls_peer_t;
! 24:
! 25: typedef enum {
! 26: STATE_INIT,
! 27: STATE_HELLO_SENT,
! 28: STATE_HELLO_RECEIVED,
! 29: STATE_HELLO_DONE,
! 30: STATE_CERT_SENT,
! 31: STATE_CERT_RECEIVED,
! 32: STATE_KEY_EXCHANGE_RECEIVED,
! 33: STATE_CERTREQ_RECEIVED,
! 34: STATE_KEY_EXCHANGE_SENT,
! 35: STATE_VERIFY_SENT,
! 36: STATE_CIPHERSPEC_CHANGED_OUT,
! 37: STATE_FINISHED_SENT,
! 38: STATE_CIPHERSPEC_CHANGED_IN,
! 39: STATE_FINISHED_RECEIVED,
! 40: } peer_state_t;
! 41:
! 42: /**
! 43: * Private data of an tls_peer_t object.
! 44: */
! 45: struct private_tls_peer_t {
! 46:
! 47: /**
! 48: * Public tls_peer_t interface.
! 49: */
! 50: tls_peer_t public;
! 51:
! 52: /**
! 53: * TLS stack
! 54: */
! 55: tls_t *tls;
! 56:
! 57: /**
! 58: * TLS crypto context
! 59: */
! 60: tls_crypto_t *crypto;
! 61:
! 62: /**
! 63: * TLS alert handler
! 64: */
! 65: tls_alert_t *alert;
! 66:
! 67: /**
! 68: * Peer identity, NULL for no client authentication
! 69: */
! 70: identification_t *peer;
! 71:
! 72: /**
! 73: * Server identity
! 74: */
! 75: identification_t *server;
! 76:
! 77: /**
! 78: * State we are in
! 79: */
! 80: peer_state_t state;
! 81:
! 82: /**
! 83: * TLS version we offered in hello
! 84: */
! 85: tls_version_t hello_version;
! 86:
! 87: /**
! 88: * Hello random data selected by client
! 89: */
! 90: char client_random[32];
! 91:
! 92: /**
! 93: * Hello random data selected by server
! 94: */
! 95: char server_random[32];
! 96:
! 97: /**
! 98: * Auth helper for peer authentication
! 99: */
! 100: auth_cfg_t *peer_auth;
! 101:
! 102: /**
! 103: * Auth helper for server authentication
! 104: */
! 105: auth_cfg_t *server_auth;
! 106:
! 107: /**
! 108: * Peer private key
! 109: */
! 110: private_key_t *private;
! 111:
! 112: /**
! 113: * DHE exchange
! 114: */
! 115: diffie_hellman_t *dh;
! 116:
! 117: /**
! 118: * Resuming a session?
! 119: */
! 120: bool resume;
! 121:
! 122: /**
! 123: * TLS session identifier
! 124: */
! 125: chunk_t session;
! 126:
! 127: /**
! 128: * List of server-supported hashsig algorithms
! 129: */
! 130: chunk_t hashsig;
! 131:
! 132: /**
! 133: * List of server-supported client certificate types
! 134: */
! 135: chunk_t cert_types;
! 136: };
! 137:
! 138: /**
! 139: * Process a server hello message
! 140: */
! 141: static status_t process_server_hello(private_tls_peer_t *this,
! 142: bio_reader_t *reader)
! 143: {
! 144: uint8_t compression;
! 145: uint16_t version, cipher;
! 146: chunk_t random, session, ext = chunk_empty;
! 147: tls_cipher_suite_t suite = 0;
! 148:
! 149: this->crypto->append_handshake(this->crypto,
! 150: TLS_SERVER_HELLO, reader->peek(reader));
! 151:
! 152: if (!reader->read_uint16(reader, &version) ||
! 153: !reader->read_data(reader, sizeof(this->server_random), &random) ||
! 154: !reader->read_data8(reader, &session) ||
! 155: !reader->read_uint16(reader, &cipher) ||
! 156: !reader->read_uint8(reader, &compression) ||
! 157: (reader->remaining(reader) && !reader->read_data16(reader, &ext)))
! 158: {
! 159: DBG1(DBG_TLS, "received invalid ServerHello");
! 160: this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
! 161: return NEED_MORE;
! 162: }
! 163:
! 164: memcpy(this->server_random, random.ptr, sizeof(this->server_random));
! 165:
! 166: if (!this->tls->set_version(this->tls, version))
! 167: {
! 168: DBG1(DBG_TLS, "negotiated version %N not supported",
! 169: tls_version_names, version);
! 170: this->alert->add(this->alert, TLS_FATAL, TLS_PROTOCOL_VERSION);
! 171: return NEED_MORE;
! 172: }
! 173:
! 174: if (chunk_equals(this->session, session))
! 175: {
! 176: suite = this->crypto->resume_session(this->crypto, session, this->server,
! 177: chunk_from_thing(this->client_random),
! 178: chunk_from_thing(this->server_random));
! 179: if (suite)
! 180: {
! 181: DBG1(DBG_TLS, "resumed %N using suite %N",
! 182: tls_version_names, version, tls_cipher_suite_names, suite);
! 183: this->resume = TRUE;
! 184: }
! 185: }
! 186: if (!suite)
! 187: {
! 188: suite = cipher;
! 189: if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1, KEY_ANY))
! 190: {
! 191: DBG1(DBG_TLS, "received TLS cipher suite %N unacceptable",
! 192: tls_cipher_suite_names, suite);
! 193: this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
! 194: return NEED_MORE;
! 195: }
! 196: DBG1(DBG_TLS, "negotiated %N using suite %N",
! 197: tls_version_names, version, tls_cipher_suite_names, suite);
! 198: free(this->session.ptr);
! 199: this->session = chunk_clone(session);
! 200: }
! 201: this->state = STATE_HELLO_RECEIVED;
! 202: return NEED_MORE;
! 203: }
! 204:
! 205: /**
! 206: * Check if a server certificate is acceptable for the given server identity
! 207: */
! 208: static bool check_certificate(private_tls_peer_t *this, certificate_t *cert)
! 209: {
! 210: identification_t *id;
! 211:
! 212: if (cert->has_subject(cert, this->server))
! 213: {
! 214: return TRUE;
! 215: }
! 216: id = cert->get_subject(cert);
! 217: if (id->matches(id, this->server))
! 218: {
! 219: return TRUE;
! 220: }
! 221: if (cert->get_type(cert) == CERT_X509)
! 222: {
! 223: x509_t *x509 = (x509_t*)cert;
! 224: enumerator_t *enumerator;
! 225:
! 226: enumerator = x509->create_subjectAltName_enumerator(x509);
! 227: while (enumerator->enumerate(enumerator, &id))
! 228: {
! 229: if (id->matches(id, this->server))
! 230: {
! 231: enumerator->destroy(enumerator);
! 232: return TRUE;
! 233: }
! 234: }
! 235: enumerator->destroy(enumerator);
! 236: }
! 237: DBG1(DBG_TLS, "server certificate does not match to '%Y'", this->server);
! 238: return FALSE;
! 239: }
! 240:
! 241: /**
! 242: * Process a Certificate message
! 243: */
! 244: static status_t process_certificate(private_tls_peer_t *this,
! 245: bio_reader_t *reader)
! 246: {
! 247: certificate_t *cert;
! 248: bio_reader_t *certs;
! 249: chunk_t data;
! 250: bool first = TRUE;
! 251:
! 252: this->crypto->append_handshake(this->crypto,
! 253: TLS_CERTIFICATE, reader->peek(reader));
! 254:
! 255: if (!reader->read_data24(reader, &data))
! 256: {
! 257: DBG1(DBG_TLS, "certificate message header invalid");
! 258: this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
! 259: return NEED_MORE;
! 260: }
! 261: certs = bio_reader_create(data);
! 262: while (certs->remaining(certs))
! 263: {
! 264: if (!certs->read_data24(certs, &data))
! 265: {
! 266: DBG1(DBG_TLS, "certificate message invalid");
! 267: this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
! 268: certs->destroy(certs);
! 269: return NEED_MORE;
! 270: }
! 271: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
! 272: BUILD_BLOB_ASN1_DER, data, BUILD_END);
! 273: if (cert)
! 274: {
! 275: if (first)
! 276: {
! 277: if (!check_certificate(this, cert))
! 278: {
! 279: cert->destroy(cert);
! 280: certs->destroy(certs);
! 281: this->alert->add(this->alert, TLS_FATAL, TLS_ACCESS_DENIED);
! 282: return NEED_MORE;
! 283: }
! 284: this->server_auth->add(this->server_auth,
! 285: AUTH_HELPER_SUBJECT_CERT, cert);
! 286: DBG1(DBG_TLS, "received TLS server certificate '%Y'",
! 287: cert->get_subject(cert));
! 288: first = FALSE;
! 289: }
! 290: else
! 291: {
! 292: DBG1(DBG_TLS, "received TLS intermediate certificate '%Y'",
! 293: cert->get_subject(cert));
! 294: this->server_auth->add(this->server_auth,
! 295: AUTH_HELPER_IM_CERT, cert);
! 296: }
! 297: }
! 298: else
! 299: {
! 300: DBG1(DBG_TLS, "parsing TLS certificate failed, skipped");
! 301: this->alert->add(this->alert, TLS_WARNING, TLS_BAD_CERTIFICATE);
! 302: }
! 303: }
! 304: certs->destroy(certs);
! 305: this->state = STATE_CERT_RECEIVED;
! 306: return NEED_MORE;
! 307: }
! 308:
! 309: /**
! 310: * Find a trusted public key to encrypt/verify key exchange data
! 311: */
! 312: static public_key_t *find_public_key(private_tls_peer_t *this)
! 313: {
! 314: public_key_t *public = NULL, *current;
! 315: certificate_t *cert, *found;
! 316: enumerator_t *enumerator;
! 317: auth_cfg_t *auth;
! 318:
! 319: cert = this->server_auth->get(this->server_auth, AUTH_HELPER_SUBJECT_CERT);
! 320: if (cert)
! 321: {
! 322: enumerator = lib->credmgr->create_public_enumerator(lib->credmgr,
! 323: KEY_ANY, cert->get_subject(cert),
! 324: this->server_auth, TRUE);
! 325: while (enumerator->enumerate(enumerator, ¤t, &auth))
! 326: {
! 327: found = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
! 328: if (found && cert->equals(cert, found))
! 329: {
! 330: public = current->get_ref(current);
! 331: this->server_auth->merge(this->server_auth, auth, FALSE);
! 332: break;
! 333: }
! 334: }
! 335: enumerator->destroy(enumerator);
! 336: }
! 337: return public;
! 338: }
! 339:
! 340: /**
! 341: * Process a Key Exchange message using MODP Diffie Hellman
! 342: */
! 343: static status_t process_modp_key_exchange(private_tls_peer_t *this,
! 344: bio_reader_t *reader)
! 345: {
! 346: chunk_t prime, generator, pub, chunk;
! 347: public_key_t *public;
! 348:
! 349: chunk = reader->peek(reader);
! 350: if (!reader->read_data16(reader, &prime) ||
! 351: !reader->read_data16(reader, &generator) ||
! 352: !reader->read_data16(reader, &pub))
! 353: {
! 354: DBG1(DBG_TLS, "received invalid Server Key Exchange");
! 355: this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
! 356: return NEED_MORE;
! 357: }
! 358: /* reject (export) DH groups using primes smaller than 1024 bit */
! 359: if (prime.len < 1024 / 8)
! 360: {
! 361: DBG1(DBG_TLS, "short DH prime received (%zu bytes)", prime.len);
! 362: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 363: return NEED_MORE;
! 364: }
! 365: public = find_public_key(this);
! 366: if (!public)
! 367: {
! 368: DBG1(DBG_TLS, "no TLS public key found for server '%Y'", this->server);
! 369: this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN);
! 370: return NEED_MORE;
! 371: }
! 372:
! 373: chunk.len = 2 + prime.len + 2 + generator.len + 2 + pub.len;
! 374: chunk = chunk_cat("ccc", chunk_from_thing(this->client_random),
! 375: chunk_from_thing(this->server_random), chunk);
! 376: if (!this->crypto->verify(this->crypto, public, reader, chunk))
! 377: {
! 378: public->destroy(public);
! 379: free(chunk.ptr);
! 380: DBG1(DBG_TLS, "verifying DH parameters failed");
! 381: this->alert->add(this->alert, TLS_FATAL, TLS_BAD_CERTIFICATE);
! 382: return NEED_MORE;
! 383: }
! 384: public->destroy(public);
! 385: free(chunk.ptr);
! 386:
! 387: this->dh = lib->crypto->create_dh(lib->crypto, MODP_CUSTOM,
! 388: generator, prime);
! 389: if (!this->dh)
! 390: {
! 391: DBG1(DBG_TLS, "custom DH parameters not supported");
! 392: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 393: return NEED_MORE;
! 394: }
! 395: if (!this->dh->set_other_public_value(this->dh, pub))
! 396: {
! 397: DBG1(DBG_TLS, "applying DH public value failed");
! 398: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 399: return NEED_MORE;
! 400: }
! 401:
! 402: this->state = STATE_KEY_EXCHANGE_RECEIVED;
! 403: return NEED_MORE;
! 404: }
! 405:
! 406: /**
! 407: * Get the EC group for a TLS named curve
! 408: */
! 409: static diffie_hellman_group_t curve_to_ec_group(private_tls_peer_t *this,
! 410: tls_named_curve_t curve)
! 411: {
! 412: diffie_hellman_group_t group;
! 413: tls_named_curve_t current;
! 414: enumerator_t *enumerator;
! 415:
! 416: enumerator = this->crypto->create_ec_enumerator(this->crypto);
! 417: while (enumerator->enumerate(enumerator, &group, ¤t))
! 418: {
! 419: if (current == curve)
! 420: {
! 421: enumerator->destroy(enumerator);
! 422: return group;
! 423: }
! 424: }
! 425: enumerator->destroy(enumerator);
! 426: return 0;
! 427: }
! 428:
! 429: /**
! 430: * Process a Key Exchange message using EC Diffie Hellman
! 431: */
! 432: static status_t process_ec_key_exchange(private_tls_peer_t *this,
! 433: bio_reader_t *reader)
! 434: {
! 435: diffie_hellman_group_t group;
! 436: public_key_t *public;
! 437: uint8_t type;
! 438: uint16_t curve;
! 439: chunk_t pub, chunk;
! 440:
! 441: chunk = reader->peek(reader);
! 442: if (!reader->read_uint8(reader, &type))
! 443: {
! 444: DBG1(DBG_TLS, "received invalid Server Key Exchange");
! 445: this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
! 446: return NEED_MORE;
! 447: }
! 448: if (type != TLS_ECC_NAMED_CURVE)
! 449: {
! 450: DBG1(DBG_TLS, "ECDH curve type %N not supported",
! 451: tls_ecc_curve_type_names, type);
! 452: this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
! 453: return NEED_MORE;
! 454: }
! 455: if (!reader->read_uint16(reader, &curve) ||
! 456: !reader->read_data8(reader, &pub) || pub.len == 0)
! 457: {
! 458: DBG1(DBG_TLS, "received invalid Server Key Exchange");
! 459: this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
! 460: return NEED_MORE;
! 461: }
! 462:
! 463: group = curve_to_ec_group(this, curve);
! 464: if (!group)
! 465: {
! 466: DBG1(DBG_TLS, "ECDH curve %N not supported",
! 467: tls_named_curve_names, curve);
! 468: this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
! 469: return NEED_MORE;
! 470: }
! 471:
! 472: public = find_public_key(this);
! 473: if (!public)
! 474: {
! 475: DBG1(DBG_TLS, "no TLS public key found for server '%Y'", this->server);
! 476: this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN);
! 477: return NEED_MORE;
! 478: }
! 479:
! 480: chunk.len = 4 + pub.len;
! 481: chunk = chunk_cat("ccc", chunk_from_thing(this->client_random),
! 482: chunk_from_thing(this->server_random), chunk);
! 483: if (!this->crypto->verify(this->crypto, public, reader, chunk))
! 484: {
! 485: public->destroy(public);
! 486: free(chunk.ptr);
! 487: DBG1(DBG_TLS, "verifying DH parameters failed");
! 488: this->alert->add(this->alert, TLS_FATAL, TLS_BAD_CERTIFICATE);
! 489: return NEED_MORE;
! 490: }
! 491: public->destroy(public);
! 492: free(chunk.ptr);
! 493:
! 494: this->dh = lib->crypto->create_dh(lib->crypto, group);
! 495: if (!this->dh)
! 496: {
! 497: DBG1(DBG_TLS, "DH group %N not supported",
! 498: diffie_hellman_group_names, group);
! 499: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 500: return NEED_MORE;
! 501: }
! 502:
! 503: if (pub.ptr[0] != TLS_ANSI_UNCOMPRESSED)
! 504: {
! 505: DBG1(DBG_TLS, "DH point format '%N' not supported",
! 506: tls_ansi_point_format_names, pub.ptr[0]);
! 507: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 508: return NEED_MORE;
! 509: }
! 510: if (!this->dh->set_other_public_value(this->dh, chunk_skip(pub, 1)))
! 511: {
! 512: DBG1(DBG_TLS, "applying DH public value failed");
! 513: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 514: return NEED_MORE;
! 515: }
! 516:
! 517: this->state = STATE_KEY_EXCHANGE_RECEIVED;
! 518: return NEED_MORE;
! 519: }
! 520:
! 521: /**
! 522: * Process a Server Key Exchange
! 523: */
! 524: static status_t process_key_exchange(private_tls_peer_t *this,
! 525: bio_reader_t *reader)
! 526: {
! 527: diffie_hellman_group_t group;
! 528:
! 529: this->crypto->append_handshake(this->crypto,
! 530: TLS_SERVER_KEY_EXCHANGE, reader->peek(reader));
! 531:
! 532: group = this->crypto->get_dh_group(this->crypto);
! 533: if (group == MODP_NONE)
! 534: {
! 535: DBG1(DBG_TLS, "received Server Key Exchange, but not required "
! 536: "for current suite");
! 537: this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
! 538: return NEED_MORE;
! 539: }
! 540: if (diffie_hellman_group_is_ec(group))
! 541: {
! 542: return process_ec_key_exchange(this, reader);
! 543: }
! 544: return process_modp_key_exchange(this, reader);
! 545: }
! 546:
! 547: /**
! 548: * Process a Certificate Request message
! 549: */
! 550: static status_t process_certreq(private_tls_peer_t *this, bio_reader_t *reader)
! 551: {
! 552: chunk_t types, hashsig, data;
! 553: bio_reader_t *authorities;
! 554: identification_t *id;
! 555: certificate_t *cert;
! 556:
! 557: if (!this->peer)
! 558: {
! 559: DBG1(DBG_TLS, "server requested a certificate, but client "
! 560: "authentication disabled");
! 561: }
! 562: this->crypto->append_handshake(this->crypto,
! 563: TLS_CERTIFICATE_REQUEST, reader->peek(reader));
! 564:
! 565: if (!reader->read_data8(reader, &types))
! 566: {
! 567: DBG1(DBG_TLS, "certreq message header invalid");
! 568: this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
! 569: return NEED_MORE;
! 570: }
! 571: this->cert_types = chunk_clone(types);
! 572: if (this->tls->get_version(this->tls) >= TLS_1_2)
! 573: {
! 574: if (!reader->read_data16(reader, &hashsig))
! 575: {
! 576: DBG1(DBG_TLS, "certreq message invalid");
! 577: this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
! 578: return NEED_MORE;
! 579: }
! 580: this->hashsig = chunk_clone(hashsig);
! 581: }
! 582: if (!reader->read_data16(reader, &data))
! 583: {
! 584: DBG1(DBG_TLS, "certreq message invalid");
! 585: this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
! 586: return NEED_MORE;
! 587: }
! 588: authorities = bio_reader_create(data);
! 589: while (authorities->remaining(authorities))
! 590: {
! 591: if (!authorities->read_data16(authorities, &data))
! 592: {
! 593: DBG1(DBG_TLS, "certreq message invalid");
! 594: this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
! 595: authorities->destroy(authorities);
! 596: return NEED_MORE;
! 597: }
! 598: if (this->peer)
! 599: {
! 600: id = identification_create_from_encoding(ID_DER_ASN1_DN, data);
! 601: cert = lib->credmgr->get_cert(lib->credmgr,
! 602: CERT_X509, KEY_ANY, id, TRUE);
! 603: if (cert)
! 604: {
! 605: DBG1(DBG_TLS, "received TLS cert request for '%Y", id);
! 606: this->peer_auth->add(this->peer_auth, AUTH_RULE_CA_CERT, cert);
! 607: }
! 608: else
! 609: {
! 610: DBG1(DBG_TLS, "received TLS cert request for unknown CA '%Y'", id);
! 611: }
! 612: id->destroy(id);
! 613: }
! 614: }
! 615: authorities->destroy(authorities);
! 616: this->state = STATE_CERTREQ_RECEIVED;
! 617: return NEED_MORE;
! 618: }
! 619:
! 620: /**
! 621: * Process Hello Done message
! 622: */
! 623: static status_t process_hello_done(private_tls_peer_t *this,
! 624: bio_reader_t *reader)
! 625: {
! 626: this->crypto->append_handshake(this->crypto,
! 627: TLS_SERVER_HELLO_DONE, reader->peek(reader));
! 628: this->state = STATE_HELLO_DONE;
! 629: return NEED_MORE;
! 630: }
! 631:
! 632: /**
! 633: * Process finished message
! 634: */
! 635: static status_t process_finished(private_tls_peer_t *this, bio_reader_t *reader)
! 636: {
! 637: chunk_t received;
! 638: char buf[12];
! 639:
! 640: if (!reader->read_data(reader, sizeof(buf), &received))
! 641: {
! 642: DBG1(DBG_TLS, "received server finished too short");
! 643: this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
! 644: return NEED_MORE;
! 645: }
! 646: if (!this->crypto->calculate_finished(this->crypto, "server finished", buf))
! 647: {
! 648: DBG1(DBG_TLS, "calculating server finished failed");
! 649: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 650: return NEED_MORE;
! 651: }
! 652: if (!chunk_equals_const(received, chunk_from_thing(buf)))
! 653: {
! 654: DBG1(DBG_TLS, "received server finished invalid");
! 655: this->alert->add(this->alert, TLS_FATAL, TLS_DECRYPT_ERROR);
! 656: return NEED_MORE;
! 657: }
! 658: this->state = STATE_FINISHED_RECEIVED;
! 659: this->crypto->append_handshake(this->crypto, TLS_FINISHED, received);
! 660:
! 661: return NEED_MORE;
! 662: }
! 663:
! 664: METHOD(tls_handshake_t, process, status_t,
! 665: private_tls_peer_t *this, tls_handshake_type_t type, bio_reader_t *reader)
! 666: {
! 667: tls_handshake_type_t expected;
! 668:
! 669: switch (this->state)
! 670: {
! 671: case STATE_HELLO_SENT:
! 672: if (type == TLS_SERVER_HELLO)
! 673: {
! 674: return process_server_hello(this, reader);
! 675: }
! 676: expected = TLS_SERVER_HELLO;
! 677: break;
! 678: case STATE_HELLO_RECEIVED:
! 679: if (type == TLS_CERTIFICATE)
! 680: {
! 681: return process_certificate(this, reader);
! 682: }
! 683: expected = TLS_CERTIFICATE;
! 684: break;
! 685: case STATE_CERT_RECEIVED:
! 686: if (type == TLS_SERVER_KEY_EXCHANGE)
! 687: {
! 688: return process_key_exchange(this, reader);
! 689: }
! 690: /* fall through since TLS_SERVER_KEY_EXCHANGE is optional */
! 691: case STATE_KEY_EXCHANGE_RECEIVED:
! 692: if (type == TLS_CERTIFICATE_REQUEST)
! 693: {
! 694: return process_certreq(this, reader);
! 695: }
! 696: /* no cert request, server does not want to authenticate us */
! 697: DESTROY_IF(this->peer);
! 698: this->peer = NULL;
! 699: /* fall through since TLS_CERTIFICATE_REQUEST is optional */
! 700: case STATE_CERTREQ_RECEIVED:
! 701: if (type == TLS_SERVER_HELLO_DONE)
! 702: {
! 703: return process_hello_done(this, reader);
! 704: }
! 705: expected = TLS_SERVER_HELLO_DONE;
! 706: break;
! 707: case STATE_CIPHERSPEC_CHANGED_IN:
! 708: if (type == TLS_FINISHED)
! 709: {
! 710: return process_finished(this, reader);
! 711: }
! 712: expected = TLS_FINISHED;
! 713: break;
! 714: default:
! 715: DBG1(DBG_TLS, "TLS %N not expected in current state",
! 716: tls_handshake_type_names, type);
! 717: this->alert->add(this->alert, TLS_FATAL, TLS_UNEXPECTED_MESSAGE);
! 718: return NEED_MORE;
! 719: }
! 720: DBG1(DBG_TLS, "TLS %N expected, but received %N",
! 721: tls_handshake_type_names, expected, tls_handshake_type_names, type);
! 722: this->alert->add(this->alert, TLS_FATAL, TLS_UNEXPECTED_MESSAGE);
! 723: return NEED_MORE;
! 724: }
! 725:
! 726: /**
! 727: * Send a client hello
! 728: */
! 729: static status_t send_client_hello(private_tls_peer_t *this,
! 730: tls_handshake_type_t *type, bio_writer_t *writer)
! 731: {
! 732: tls_cipher_suite_t *suites;
! 733: bio_writer_t *extensions, *curves = NULL;
! 734: tls_version_t version;
! 735: tls_named_curve_t curve;
! 736: enumerator_t *enumerator;
! 737: int count, i;
! 738: rng_t *rng;
! 739:
! 740: htoun32(&this->client_random, time(NULL));
! 741: rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
! 742: if (!rng ||
! 743: !rng->get_bytes(rng, sizeof(this->client_random) - 4,
! 744: this->client_random + 4))
! 745: {
! 746: DBG1(DBG_TLS, "failed to generate client random");
! 747: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 748: DESTROY_IF(rng);
! 749: return NEED_MORE;
! 750: }
! 751: rng->destroy(rng);
! 752:
! 753: /* TLS version */
! 754: version = this->tls->get_version(this->tls);
! 755: this->hello_version = version;
! 756: writer->write_uint16(writer, version);
! 757: writer->write_data(writer, chunk_from_thing(this->client_random));
! 758:
! 759: /* session identifier */
! 760: this->session = this->crypto->get_session(this->crypto, this->server);
! 761: writer->write_data8(writer, this->session);
! 762:
! 763: /* add TLS cipher suites */
! 764: count = this->crypto->get_cipher_suites(this->crypto, &suites);
! 765: writer->write_uint16(writer, count * 2);
! 766: for (i = 0; i < count; i++)
! 767: {
! 768: writer->write_uint16(writer, suites[i]);
! 769: }
! 770:
! 771: /* NULL compression only */
! 772: writer->write_uint8(writer, 1);
! 773: writer->write_uint8(writer, 0);
! 774:
! 775: extensions = bio_writer_create(32);
! 776:
! 777: extensions->write_uint16(extensions, TLS_EXT_SIGNATURE_ALGORITHMS);
! 778: this->crypto->get_signature_algorithms(this->crypto, extensions);
! 779:
! 780: /* add supported Elliptic Curves, if any */
! 781: enumerator = this->crypto->create_ec_enumerator(this->crypto);
! 782: while (enumerator->enumerate(enumerator, NULL, &curve))
! 783: {
! 784: if (!curves)
! 785: {
! 786: extensions->write_uint16(extensions, TLS_EXT_ELLIPTIC_CURVES);
! 787: curves = bio_writer_create(16);
! 788: }
! 789: curves->write_uint16(curves, curve);
! 790: }
! 791: enumerator->destroy(enumerator);
! 792: if (curves)
! 793: {
! 794: curves->wrap16(curves);
! 795: extensions->write_data16(extensions, curves->get_buf(curves));
! 796: curves->destroy(curves);
! 797:
! 798: /* if we support curves, add point format extension */
! 799: extensions->write_uint16(extensions, TLS_EXT_EC_POINT_FORMATS);
! 800: extensions->write_uint16(extensions, 2);
! 801: extensions->write_uint8(extensions, 1);
! 802: extensions->write_uint8(extensions, TLS_EC_POINT_UNCOMPRESSED);
! 803: }
! 804: if (this->server->get_type(this->server) == ID_FQDN)
! 805: {
! 806: bio_writer_t *names;
! 807:
! 808: DBG2(DBG_TLS, "sending Server Name Indication for '%Y'", this->server);
! 809:
! 810: names = bio_writer_create(8);
! 811: names->write_uint8(names, TLS_NAME_TYPE_HOST_NAME);
! 812: names->write_data16(names, this->server->get_encoding(this->server));
! 813: names->wrap16(names);
! 814: extensions->write_uint16(extensions, TLS_EXT_SERVER_NAME);
! 815: extensions->write_data16(extensions, names->get_buf(names));
! 816: names->destroy(names);
! 817: }
! 818:
! 819: writer->write_data16(writer, extensions->get_buf(extensions));
! 820: extensions->destroy(extensions);
! 821:
! 822: *type = TLS_CLIENT_HELLO;
! 823: this->state = STATE_HELLO_SENT;
! 824: this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
! 825: return NEED_MORE;
! 826: }
! 827:
! 828: /**
! 829: * Find a private key suitable to sign Certificate Verify
! 830: */
! 831: static private_key_t *find_private_key(private_tls_peer_t *this)
! 832: {
! 833: private_key_t *key = NULL;
! 834: bio_reader_t *reader;
! 835: key_type_t type;
! 836: uint8_t cert;
! 837:
! 838: if (!this->peer)
! 839: {
! 840: return NULL;
! 841: }
! 842: reader = bio_reader_create(this->cert_types);
! 843: while (reader->remaining(reader) && reader->read_uint8(reader, &cert))
! 844: {
! 845: switch (cert)
! 846: {
! 847: case TLS_RSA_SIGN:
! 848: type = KEY_RSA;
! 849: break;
! 850: case TLS_ECDSA_SIGN:
! 851: type = KEY_ECDSA;
! 852: break;
! 853: default:
! 854: continue;
! 855: }
! 856: key = lib->credmgr->get_private(lib->credmgr, type,
! 857: this->peer, this->peer_auth);
! 858: if (key)
! 859: {
! 860: break;
! 861: }
! 862: }
! 863: reader->destroy(reader);
! 864: return key;
! 865: }
! 866:
! 867: /**
! 868: * Send Certificate
! 869: */
! 870: static status_t send_certificate(private_tls_peer_t *this,
! 871: tls_handshake_type_t *type, bio_writer_t *writer)
! 872: {
! 873: enumerator_t *enumerator;
! 874: certificate_t *cert;
! 875: auth_rule_t rule;
! 876: bio_writer_t *certs;
! 877: chunk_t data;
! 878:
! 879: this->private = find_private_key(this);
! 880: if (!this->private)
! 881: {
! 882: DBG1(DBG_TLS, "no TLS peer certificate found for '%Y', "
! 883: "skipping client authentication", this->peer);
! 884: this->peer->destroy(this->peer);
! 885: this->peer = NULL;
! 886: }
! 887:
! 888: /* generate certificate payload */
! 889: certs = bio_writer_create(256);
! 890: if (this->peer)
! 891: {
! 892: cert = this->peer_auth->get(this->peer_auth, AUTH_RULE_SUBJECT_CERT);
! 893: if (cert)
! 894: {
! 895: if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
! 896: {
! 897: DBG1(DBG_TLS, "sending TLS peer certificate '%Y'",
! 898: cert->get_subject(cert));
! 899: certs->write_data24(certs, data);
! 900: free(data.ptr);
! 901: }
! 902: }
! 903: enumerator = this->peer_auth->create_enumerator(this->peer_auth);
! 904: while (enumerator->enumerate(enumerator, &rule, &cert))
! 905: {
! 906: if (rule == AUTH_RULE_IM_CERT)
! 907: {
! 908: if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
! 909: {
! 910: DBG1(DBG_TLS, "sending TLS intermediate certificate '%Y'",
! 911: cert->get_subject(cert));
! 912: certs->write_data24(certs, data);
! 913: free(data.ptr);
! 914: }
! 915: }
! 916: }
! 917: enumerator->destroy(enumerator);
! 918: }
! 919:
! 920: writer->write_data24(writer, certs->get_buf(certs));
! 921: certs->destroy(certs);
! 922:
! 923: *type = TLS_CERTIFICATE;
! 924: this->state = STATE_CERT_SENT;
! 925: this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
! 926: return NEED_MORE;
! 927: }
! 928:
! 929: /**
! 930: * Send client key exchange, using premaster encryption
! 931: */
! 932: static status_t send_key_exchange_encrypt(private_tls_peer_t *this,
! 933: tls_handshake_type_t *type, bio_writer_t *writer)
! 934: {
! 935: public_key_t *public;
! 936: rng_t *rng;
! 937: char premaster[48];
! 938: chunk_t encrypted;
! 939:
! 940: rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
! 941: if (!rng || !rng->get_bytes(rng, sizeof(premaster) - 2, premaster + 2))
! 942: {
! 943: DBG1(DBG_TLS, "failed to generate TLS premaster secret");
! 944: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 945: DESTROY_IF(rng);
! 946: return NEED_MORE;
! 947: }
! 948: rng->destroy(rng);
! 949: htoun16(premaster, this->hello_version);
! 950:
! 951: if (!this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
! 952: this->session, this->server,
! 953: chunk_from_thing(this->client_random),
! 954: chunk_from_thing(this->server_random)))
! 955: {
! 956: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 957: return NEED_MORE;
! 958: }
! 959:
! 960: public = find_public_key(this);
! 961: if (!public)
! 962: {
! 963: DBG1(DBG_TLS, "no TLS public key found for server '%Y'", this->server);
! 964: this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN);
! 965: return NEED_MORE;
! 966: }
! 967: if (!public->encrypt(public, ENCRYPT_RSA_PKCS1,
! 968: chunk_from_thing(premaster), &encrypted))
! 969: {
! 970: public->destroy(public);
! 971: DBG1(DBG_TLS, "encrypting TLS premaster secret failed");
! 972: this->alert->add(this->alert, TLS_FATAL, TLS_BAD_CERTIFICATE);
! 973: return NEED_MORE;
! 974: }
! 975: public->destroy(public);
! 976:
! 977: writer->write_data16(writer, encrypted);
! 978: free(encrypted.ptr);
! 979:
! 980: *type = TLS_CLIENT_KEY_EXCHANGE;
! 981: this->state = STATE_KEY_EXCHANGE_SENT;
! 982: this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
! 983: return NEED_MORE;
! 984: }
! 985:
! 986: /**
! 987: * Send client key exchange, using DHE exchange
! 988: */
! 989: static status_t send_key_exchange_dhe(private_tls_peer_t *this,
! 990: tls_handshake_type_t *type, bio_writer_t *writer)
! 991: {
! 992: chunk_t premaster, pub;
! 993:
! 994: if (!this->dh->get_shared_secret(this->dh, &premaster))
! 995: {
! 996: DBG1(DBG_TLS, "calculating premaster from DH failed");
! 997: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 998: return NEED_MORE;
! 999: }
! 1000: if (!this->crypto->derive_secrets(this->crypto, premaster,
! 1001: this->session, this->server,
! 1002: chunk_from_thing(this->client_random),
! 1003: chunk_from_thing(this->server_random)))
! 1004: {
! 1005: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 1006: chunk_clear(&premaster);
! 1007: return NEED_MORE;
! 1008: }
! 1009: chunk_clear(&premaster);
! 1010:
! 1011: if (!this->dh->get_my_public_value(this->dh, &pub))
! 1012: {
! 1013: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 1014: return NEED_MORE;
! 1015: }
! 1016: if (this->dh->get_dh_group(this->dh) == MODP_CUSTOM)
! 1017: {
! 1018: writer->write_data16(writer, pub);
! 1019: }
! 1020: else
! 1021: { /* ECP uses 8bit length header only, but a point format */
! 1022: writer->write_uint8(writer, pub.len + 1);
! 1023: writer->write_uint8(writer, TLS_ANSI_UNCOMPRESSED);
! 1024: writer->write_data(writer, pub);
! 1025: }
! 1026: free(pub.ptr);
! 1027:
! 1028: *type = TLS_CLIENT_KEY_EXCHANGE;
! 1029: this->state = STATE_KEY_EXCHANGE_SENT;
! 1030: this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
! 1031: return NEED_MORE;
! 1032: }
! 1033:
! 1034: /**
! 1035: * Send client key exchange, depending on suite
! 1036: */
! 1037: static status_t send_key_exchange(private_tls_peer_t *this,
! 1038: tls_handshake_type_t *type, bio_writer_t *writer)
! 1039: {
! 1040: if (this->dh)
! 1041: {
! 1042: return send_key_exchange_dhe(this, type, writer);
! 1043: }
! 1044: return send_key_exchange_encrypt(this, type, writer);
! 1045: }
! 1046:
! 1047: /**
! 1048: * Send certificate verify
! 1049: */
! 1050: static status_t send_certificate_verify(private_tls_peer_t *this,
! 1051: tls_handshake_type_t *type, bio_writer_t *writer)
! 1052: {
! 1053: if (!this->private ||
! 1054: !this->crypto->sign_handshake(this->crypto, this->private,
! 1055: writer, this->hashsig))
! 1056: {
! 1057: DBG1(DBG_TLS, "creating TLS Certificate Verify signature failed");
! 1058: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 1059: return NEED_MORE;
! 1060: }
! 1061:
! 1062: *type = TLS_CERTIFICATE_VERIFY;
! 1063: this->state = STATE_VERIFY_SENT;
! 1064: this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
! 1065: return NEED_MORE;
! 1066: }
! 1067:
! 1068: /**
! 1069: * Send Finished
! 1070: */
! 1071: static status_t send_finished(private_tls_peer_t *this,
! 1072: tls_handshake_type_t *type, bio_writer_t *writer)
! 1073: {
! 1074: char buf[12];
! 1075:
! 1076: if (!this->crypto->calculate_finished(this->crypto, "client finished", buf))
! 1077: {
! 1078: DBG1(DBG_TLS, "calculating client finished data failed");
! 1079: this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
! 1080: return NEED_MORE;
! 1081: }
! 1082:
! 1083: writer->write_data(writer, chunk_from_thing(buf));
! 1084:
! 1085: *type = TLS_FINISHED;
! 1086: this->state = STATE_FINISHED_SENT;
! 1087: this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
! 1088: return NEED_MORE;
! 1089: }
! 1090:
! 1091: METHOD(tls_handshake_t, build, status_t,
! 1092: private_tls_peer_t *this, tls_handshake_type_t *type, bio_writer_t *writer)
! 1093: {
! 1094: switch (this->state)
! 1095: {
! 1096: case STATE_INIT:
! 1097: return send_client_hello(this, type, writer);
! 1098: case STATE_HELLO_DONE:
! 1099: if (this->peer)
! 1100: {
! 1101: return send_certificate(this, type, writer);
! 1102: }
! 1103: /* otherwise fall through to next state */
! 1104: case STATE_CERT_SENT:
! 1105: return send_key_exchange(this, type, writer);
! 1106: case STATE_KEY_EXCHANGE_SENT:
! 1107: if (this->peer)
! 1108: {
! 1109: return send_certificate_verify(this, type, writer);
! 1110: }
! 1111: else
! 1112: {
! 1113: return INVALID_STATE;
! 1114: }
! 1115: case STATE_CIPHERSPEC_CHANGED_OUT:
! 1116: return send_finished(this, type, writer);
! 1117: default:
! 1118: return INVALID_STATE;
! 1119: }
! 1120: }
! 1121:
! 1122: METHOD(tls_handshake_t, cipherspec_changed, bool,
! 1123: private_tls_peer_t *this, bool inbound)
! 1124: {
! 1125: if (inbound)
! 1126: {
! 1127: if (this->resume)
! 1128: {
! 1129: return this->state == STATE_HELLO_RECEIVED;
! 1130: }
! 1131: return this->state == STATE_FINISHED_SENT;
! 1132: }
! 1133: else
! 1134: {
! 1135: if (this->resume)
! 1136: {
! 1137: return this->state == STATE_FINISHED_RECEIVED;
! 1138: }
! 1139: if (this->peer)
! 1140: {
! 1141: return this->state == STATE_VERIFY_SENT;
! 1142: }
! 1143: return this->state == STATE_KEY_EXCHANGE_SENT;
! 1144: }
! 1145: }
! 1146:
! 1147: METHOD(tls_handshake_t, change_cipherspec, void,
! 1148: private_tls_peer_t *this, bool inbound)
! 1149: {
! 1150: this->crypto->change_cipher(this->crypto, inbound);
! 1151: if (inbound)
! 1152: {
! 1153: this->state = STATE_CIPHERSPEC_CHANGED_IN;
! 1154: }
! 1155: else
! 1156: {
! 1157: this->state = STATE_CIPHERSPEC_CHANGED_OUT;
! 1158: }
! 1159: }
! 1160:
! 1161: METHOD(tls_handshake_t, finished, bool,
! 1162: private_tls_peer_t *this)
! 1163: {
! 1164: if (this->resume)
! 1165: {
! 1166: return this->state == STATE_FINISHED_SENT;
! 1167: }
! 1168: return this->state == STATE_FINISHED_RECEIVED;
! 1169: }
! 1170:
! 1171: METHOD(tls_handshake_t, get_peer_id, identification_t*,
! 1172: private_tls_peer_t *this)
! 1173: {
! 1174: return this->peer;
! 1175: }
! 1176:
! 1177: METHOD(tls_handshake_t, get_server_id, identification_t*,
! 1178: private_tls_peer_t *this)
! 1179: {
! 1180: return this->server;
! 1181: }
! 1182:
! 1183: METHOD(tls_handshake_t, get_auth, auth_cfg_t*,
! 1184: private_tls_peer_t *this)
! 1185: {
! 1186: return this->server_auth;
! 1187: }
! 1188:
! 1189: METHOD(tls_handshake_t, destroy, void,
! 1190: private_tls_peer_t *this)
! 1191: {
! 1192: DESTROY_IF(this->private);
! 1193: DESTROY_IF(this->dh);
! 1194: DESTROY_IF(this->peer);
! 1195: this->server->destroy(this->server);
! 1196: this->peer_auth->destroy(this->peer_auth);
! 1197: this->server_auth->destroy(this->server_auth);
! 1198: free(this->hashsig.ptr);
! 1199: free(this->cert_types.ptr);
! 1200: free(this->session.ptr);
! 1201: free(this);
! 1202: }
! 1203:
! 1204: /**
! 1205: * See header
! 1206: */
! 1207: tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto, tls_alert_t *alert,
! 1208: identification_t *peer, identification_t *server)
! 1209: {
! 1210: private_tls_peer_t *this;
! 1211:
! 1212: INIT(this,
! 1213: .public = {
! 1214: .handshake = {
! 1215: .process = _process,
! 1216: .build = _build,
! 1217: .cipherspec_changed = _cipherspec_changed,
! 1218: .change_cipherspec = _change_cipherspec,
! 1219: .finished = _finished,
! 1220: .get_peer_id = _get_peer_id,
! 1221: .get_server_id = _get_server_id,
! 1222: .get_auth = _get_auth,
! 1223: .destroy = _destroy,
! 1224: },
! 1225: },
! 1226: .state = STATE_INIT,
! 1227: .tls = tls,
! 1228: .crypto = crypto,
! 1229: .alert = alert,
! 1230: .peer = peer ? peer->clone(peer) : NULL,
! 1231: .server = server->clone(server),
! 1232: .peer_auth = auth_cfg_create(),
! 1233: .server_auth = auth_cfg_create(),
! 1234: );
! 1235:
! 1236: return &this->public;
! 1237: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>