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