X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Flibtls%2Ftls_crypto.c;h=0ec2f5cbef21ff3573634fff975e25fc530818a2;hb=2db6d5b8b378a1f460a073b71e1c178bc997861b;hp=89cf1a54c301baf57a48985113a3d5dca8f655a4;hpb=2066918da2c85e3d9c3adc52d93484816ae2ee62;p=thirdparty%2Fstrongswan.git diff --git a/src/libtls/tls_crypto.c b/src/libtls/tls_crypto.c index 89cf1a54c3..0ec2f5cbef 100644 --- a/src/libtls/tls_crypto.c +++ b/src/libtls/tls_crypto.c @@ -1,6 +1,6 @@ /* - * Copyright (C) 2010 Martin Willi - * Copyright (C) 2010 revosec AG + * Copyright (C) 2010-2014 Martin Willi + * Copyright (C) 2010-2014 revosec AG * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -15,7 +15,8 @@ #include "tls_crypto.h" -#include +#include +#include ENUM_BEGIN(tls_cipher_suite_names, TLS_NULL_WITH_NULL_NULL, TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, @@ -80,7 +81,7 @@ ENUM_NEXT(tls_cipher_suite_names, TLS_KRB5_WITH_DES_CBC_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DH_anon_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_NULL_SHA256", - "TLS_RSA_WITH_AES_128_CBC_SHA256 ", + "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_DH_DSS_WITH_AES_128_CBC_SHA256", "TLS_DH_RSA_WITH_AES_128_CBC_SHA256", @@ -111,13 +112,13 @@ ENUM_NEXT(tls_cipher_suite_names, TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", "TLS_PSK_WITH_RC4_128_SHA", - "TLS_PSK_WITH_3DES_EDE_CBC_SHA2", + "TLS_PSK_WITH_3DES_EDE_CBC_SHA", "TLS_PSK_WITH_AES_128_CBC_SHA", "TLS_PSK_WITH_AES_256_CBC_SHA", "TLS_DHE_PSK_WITH_RC4_128_SHA", "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", "TLS_DHE_PSK_WITH_AES_128_CBC_SHA", - "TLS_DHE_PSK_WITH_AES_256_CBC_SHA2", + "TLS_DHE_PSK_WITH_AES_256_CBC_SHA", "TLS_RSA_PSK_WITH_RC4_128_SHA", "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", "TLS_RSA_PSK_WITH_AES_128_CBC_SHA", @@ -306,6 +307,21 @@ ENUM(tls_named_curve_names, TLS_SECT163K1, TLS_SECP521R1, "SECP521R1", ); +ENUM(tls_ansi_point_format_names, TLS_ANSI_COMPRESSED, TLS_ANSI_HYBRID_Y, + "compressed", + "compressed y", + "uncompressed", + "uncompressed y", + "hybrid", + "hybrid y", +); + +ENUM(tls_ec_point_format_names, + TLS_EC_POINT_UNCOMPRESSED, TLS_EC_POINT_ANSIX962_COMPRESSED_CHAR2, + "uncompressed", + "ansiX962 compressed prime", + "ansiX962 compressed char2", +); typedef struct private_tls_crypto_t private_tls_crypto_t; @@ -340,49 +356,44 @@ struct private_tls_crypto_t { tls_cipher_suite_t suite; /** - * TLS context + * RSA supported? */ - tls_t *tls; + bool rsa; /** - * All handshake data concatentated + * ECDSA supported? */ - chunk_t handshake; + bool ecdsa; /** - * Connection state TLS PRF - */ - tls_prf_t *prf; - - /** - * Signer instance for inbound traffic + * TLS context */ - signer_t *signer_in; + tls_t *tls; /** - * Signer instance for outbound traffic + * TLS session cache */ - signer_t *signer_out; + tls_cache_t *cache; /** - * Crypter instance for inbound traffic + * All handshake data concatenated */ - crypter_t *crypter_in; + chunk_t handshake; /** - * Crypter instance for outbound traffic + * Connection state TLS PRF */ - crypter_t *crypter_out; + tls_prf_t *prf; /** - * IV for input decryption, if < TLSv1.2 + * AEAD transform for inbound traffic */ - chunk_t iv_in; + tls_aead_t *aead_in; /** - * IV for output decryption, if < TLSv1.2 + * AEAD transform for outbound traffic */ - chunk_t iv_out; + tls_aead_t *aead_out; /** * EAP-[T]TLS MSK @@ -412,7 +423,7 @@ typedef struct { static suite_algs_t suite_algs[] = { { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, KEY_ECDSA, ECP_256_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16 }, { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, @@ -422,7 +433,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, KEY_ECDSA, ECP_384_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32 }, { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, @@ -430,29 +441,49 @@ static suite_algs_t suite_algs[] = { HASH_SHA384, PRF_HMAC_SHA2_384, AUTH_HMAC_SHA2_384_384, ENCR_AES_CBC, 32 }, - { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, KEY_ECDSA, ECP_256_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, + AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16 + }, + { TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + KEY_ECDSA, ECP_384_BIT, + HASH_SHA384, PRF_HMAC_SHA2_384, + AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32 + }, + { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + KEY_RSA, ECP_256_BIT, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16 }, { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - KEY_ECDSA, ECP_256_BIT, + KEY_RSA, ECP_256_BIT, HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 16 }, { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - KEY_ECDSA, ECP_384_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + KEY_RSA, ECP_384_BIT, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32 }, { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, - KEY_ECDSA, ECP_384_BIT, + KEY_RSA, ECP_384_BIT, HASH_SHA384, PRF_HMAC_SHA2_384, AUTH_HMAC_SHA2_384_384, ENCR_AES_CBC, 32 }, + { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + KEY_RSA, ECP_256_BIT, + HASH_SHA256, PRF_HMAC_SHA2_256, + AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16 + }, + { TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + KEY_RSA, ECP_384_BIT, + HASH_SHA384, PRF_HMAC_SHA2_384, + AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32 + }, { TLS_DHE_RSA_WITH_AES_128_CBC_SHA, KEY_RSA, MODP_2048_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256,PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16 }, { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, @@ -462,7 +493,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, KEY_RSA, MODP_3072_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32 }, { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, @@ -470,9 +501,19 @@ static suite_algs_t suite_algs[] = { HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 32 }, + { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + KEY_RSA, MODP_3072_BIT, + HASH_SHA256, PRF_HMAC_SHA2_256, + AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16 + }, + { TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, + KEY_RSA, MODP_4096_BIT, + HASH_SHA384, PRF_HMAC_SHA2_384, + AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32 + }, { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, KEY_RSA, MODP_2048_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 16 }, { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, @@ -482,7 +523,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, KEY_RSA, MODP_3072_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 32 }, { TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, @@ -492,12 +533,12 @@ static suite_algs_t suite_algs[] = { }, { TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, KEY_RSA, MODP_2048_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_3DES, 0 }, { TLS_RSA_WITH_AES_128_CBC_SHA, KEY_RSA, MODP_NONE, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16 }, { TLS_RSA_WITH_AES_128_CBC_SHA256, @@ -507,7 +548,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_RSA_WITH_AES_256_CBC_SHA, KEY_RSA, MODP_NONE, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32 }, { TLS_RSA_WITH_AES_256_CBC_SHA256, @@ -515,9 +556,19 @@ static suite_algs_t suite_algs[] = { HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 32 }, + { TLS_RSA_WITH_AES_128_GCM_SHA256, + KEY_RSA, MODP_NONE, + HASH_SHA256, PRF_HMAC_SHA2_256, + AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16 + }, + { TLS_RSA_WITH_AES_256_GCM_SHA384, + KEY_RSA, MODP_NONE, + HASH_SHA384, PRF_HMAC_SHA2_384, + AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32 + }, { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, KEY_RSA, MODP_NONE, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 16 }, { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, @@ -527,7 +578,7 @@ static suite_algs_t suite_algs[] = { }, { TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, KEY_RSA, MODP_NONE, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 32 }, { TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, @@ -537,32 +588,32 @@ static suite_algs_t suite_algs[] = { }, { TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, KEY_ECDSA, ECP_256_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_3DES, 0 }, { TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - KEY_ECDSA, ECP_256_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + KEY_RSA, ECP_256_BIT, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_3DES, 0 }, { TLS_RSA_WITH_3DES_EDE_CBC_SHA, KEY_RSA, MODP_NONE, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_3DES, 0 }, { TLS_ECDHE_ECDSA_WITH_NULL_SHA, KEY_ECDSA, ECP_256_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_NULL, 0 }, { TLS_ECDHE_RSA_WITH_NULL_SHA, KEY_ECDSA, ECP_256_BIT, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_NULL, 0 }, { TLS_RSA_WITH_NULL_SHA, KEY_RSA, MODP_NONE, - HASH_SHA1, PRF_HMAC_SHA1, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA1_160, ENCR_NULL, 0 }, { TLS_RSA_WITH_NULL_SHA256, @@ -572,13 +623,13 @@ static suite_algs_t suite_algs[] = { }, { TLS_RSA_WITH_NULL_MD5, KEY_RSA, MODP_NONE, - HASH_MD5, PRF_HMAC_MD5, + HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_MD5_128, ENCR_NULL, 0 }, }; /** - * Look up algoritms by a suite + * Look up algorithms by a suite */ static suite_algs_t *find_suite(tls_cipher_suite_t suite) { @@ -597,30 +648,69 @@ static suite_algs_t *find_suite(tls_cipher_suite_t suite) /** * Filter a suite list using a transform enumerator */ -static void filter_suite(private_tls_crypto_t *this, - suite_algs_t suites[], int *count, int offset, +static void filter_suite(suite_algs_t suites[], int *count, int offset, enumerator_t*(*create_enumerator)(crypto_factory_t*)) { + const char *plugin_name; suite_algs_t current; - int i, remaining = 0; + int *current_alg, i, remaining = 0; enumerator_t *enumerator; memset(¤t, 0, sizeof(current)); + current_alg = (int*)((char*)¤t + offset); + for (i = 0; i < *count; i++) { + if (create_enumerator == lib->crypto->create_crypter_enumerator && + encryption_algorithm_is_aead(suites[i].encr)) + { /* filtering crypters, but current suite uses an AEAD, apply */ + suites[remaining] = suites[i]; + remaining++; + continue; + } + if (create_enumerator == lib->crypto->create_aead_enumerator && + !encryption_algorithm_is_aead(suites[i].encr)) + { /* filtering AEADs, but current suite doesn't use one, apply */ + suites[remaining] = suites[i]; + remaining++; + continue; + } enumerator = create_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, ((char*)¤t) + offset)) + while (enumerator->enumerate(enumerator, current_alg, &plugin_name)) { - if ((suites[i].encr == ENCR_NULL || - !current.encr || current.encr == suites[i].encr) && - (!current.mac || current.mac == suites[i].mac) && - (!current.prf || current.prf == suites[i].prf) && - (!current.hash || current.hash == suites[i].hash)) + if (current.encr && current.encr != suites[i].encr) { - suites[remaining] = suites[i]; - remaining++; - break; + if (suites[i].encr != ENCR_NULL) + { /* skip, ENCR does not match nor is NULL */ + continue; + } + } + if (current.mac && current.mac != suites[i].mac) + { + if (suites[i].mac != AUTH_UNDEFINED) + { /* skip, MAC does not match nor is it undefined */ + continue; + } } + if (current.prf && current.prf != suites[i].prf) + { /* skip, PRF does not match */ + continue; + } + if (current.hash && current.hash != suites[i].hash) + { /* skip, hash does not match */ + continue; + } + if (current.dh && current.dh != suites[i].dh) + { + if (suites[i].dh != MODP_NONE) + { /* skip DH group, does not match nor NONE */ + continue; + } + } + /* suite supported, apply */ + suites[remaining] = suites[i]; + remaining++; + break; } enumerator->destroy(enumerator); } @@ -630,8 +720,7 @@ static void filter_suite(private_tls_crypto_t *this, /** * Purge NULL encryption cipher suites from list */ -static void filter_null_suites(private_tls_crypto_t *this, - suite_algs_t suites[], int *count) +static void filter_null_suites(suite_algs_t suites[], int *count) { int i, remaining = 0; @@ -646,6 +735,263 @@ static void filter_null_suites(private_tls_crypto_t *this, *count = remaining; } +/** + * Purge suites using a given key type + */ +static void filter_key_suites(private_tls_crypto_t *this, + suite_algs_t suites[], int *count, key_type_t key) +{ + int i, remaining = 0; + + DBG2(DBG_TLS, "disabling %N suites, no backend found", key_type_names, key); + for (i = 0; i < *count; i++) + { + if (suites[i].key != key) + { + suites[remaining] = suites[i]; + remaining++; + } + } + *count = remaining; +} + +/** + * Filter suites by key exchange user config + */ +static void filter_key_exchange_config_suites(private_tls_crypto_t *this, + suite_algs_t suites[], int *count) +{ + enumerator_t *enumerator; + int i, remaining = 0; + char *token, *config; + + config = lib->settings->get_str(lib->settings, "%s.tls.key_exchange", NULL, + lib->ns); + if (config) + { + for (i = 0; i < *count; i++) + { + enumerator = enumerator_create_token(config, ",", " "); + while (enumerator->enumerate(enumerator, &token)) + { + if (strcaseeq(token, "ecdhe-ecdsa") && + diffie_hellman_group_is_ec(suites[i].dh) && + suites[i].key == KEY_ECDSA) + { + suites[remaining++] = suites[i]; + break; + } + if (strcaseeq(token, "ecdhe-rsa") && + diffie_hellman_group_is_ec(suites[i].dh) && + suites[i].key == KEY_RSA) + { + suites[remaining++] = suites[i]; + break; + } + if (strcaseeq(token, "dhe-rsa") && + !diffie_hellman_group_is_ec(suites[i].dh) && + suites[i].dh != MODP_NONE && + suites[i].key == KEY_RSA) + { + suites[remaining++] = suites[i]; + break; + } + if (strcaseeq(token, "rsa") && + suites[i].dh == MODP_NONE && + suites[i].key == KEY_RSA) + { + suites[remaining++] = suites[i]; + break; + } + } + enumerator->destroy(enumerator); + } + *count = remaining; + } +} + +/** + * Filter suites by cipher user config + */ +static void filter_cipher_config_suites(private_tls_crypto_t *this, + suite_algs_t suites[], int *count) +{ + enumerator_t *enumerator; + int i, remaining = 0; + char *token, *config; + + config = lib->settings->get_str(lib->settings, "%s.tls.cipher", NULL, + lib->ns); + if (config) + { + for (i = 0; i < *count; i++) + { + enumerator = enumerator_create_token(config, ",", " "); + while (enumerator->enumerate(enumerator, &token)) + { + if (strcaseeq(token, "aes128") && + suites[i].encr == ENCR_AES_CBC && + suites[i].encr_size == 16) + { + suites[remaining++] = suites[i]; + break; + } + if (strcaseeq(token, "aes256") && + suites[i].encr == ENCR_AES_CBC && + suites[i].encr_size == 32) + { + suites[remaining++] = suites[i]; + break; + } + if (strcaseeq(token, "aes128gcm") && + suites[i].encr == ENCR_AES_GCM_ICV16 && + suites[i].encr_size == 16) + { + suites[remaining++] = suites[i]; + break; + } + if (strcaseeq(token, "aes256gcm") && + suites[i].encr == ENCR_AES_GCM_ICV16 && + suites[i].encr_size == 32) + { + suites[remaining++] = suites[i]; + break; + } + if (strcaseeq(token, "camellia128") && + suites[i].encr == ENCR_CAMELLIA_CBC && + suites[i].encr_size == 16) + { + suites[remaining++] = suites[i]; + break; + } + if (strcaseeq(token, "camellia256") && + suites[i].encr == ENCR_CAMELLIA_CBC && + suites[i].encr_size == 32) + { + suites[remaining++] = suites[i]; + break; + } + if (strcaseeq(token, "3des") && + suites[i].encr == ENCR_3DES) + { + suites[remaining++] = suites[i]; + break; + } + if (strcaseeq(token, "null") && + suites[i].encr == ENCR_NULL) + { + suites[remaining++] = suites[i]; + break; + } + } + enumerator->destroy(enumerator); + } + *count = remaining; + } +} + +/** + * Filter suites by mac user config + */ +static void filter_mac_config_suites(private_tls_crypto_t *this, + suite_algs_t suites[], int *count) +{ + enumerator_t *enumerator; + int i, remaining = 0; + char *token, *config; + + config = lib->settings->get_str(lib->settings, "%s.tls.mac", NULL, + lib->ns); + if (config) + { + for (i = 0; i < *count; i++) + { + enumerator = enumerator_create_token(config, ",", " "); + while (enumerator->enumerate(enumerator, &token)) + { + if (strcaseeq(token, "md5") && + suites[i].mac == AUTH_HMAC_MD5_128) + { + suites[remaining++] = suites[i]; + break; + } + if (strcaseeq(token, "sha1") && + suites[i].mac == AUTH_HMAC_SHA1_160) + { + suites[remaining++] = suites[i]; + break; + } + if (strcaseeq(token, "sha256") && + suites[i].mac == AUTH_HMAC_SHA2_256_256) + { + suites[remaining++] = suites[i]; + break; + } + if (strcaseeq(token, "sha384") && + suites[i].mac == AUTH_HMAC_SHA2_384_384) + { + suites[remaining++] = suites[i]; + break; + } + } + enumerator->destroy(enumerator); + } + *count = remaining; + } +} + +/** + * Filter for specific suites specified in strongswan.conf + */ +static void filter_specific_config_suites(private_tls_crypto_t *this, + suite_algs_t suites[], int *count) +{ + enumerator_t *enumerator; + int i, remaining = 0, suite; + char *token, *config; + + config = lib->settings->get_str(lib->settings, "%s.tls.suites", NULL, + lib->ns); + if (config) + { + for (i = 0; i < *count; i++) + { + enumerator = enumerator_create_token(config, ",", " "); + while (enumerator->enumerate(enumerator, &token)) + { + if (enum_from_name(tls_cipher_suite_names, token, &suite) && + suite == suites[i].suite) + { + suites[remaining++] = suites[i]; + break; + } + } + enumerator->destroy(enumerator); + } + *count = remaining; + } +} + +/** + * Filter out unsupported suites on given suite array + */ +static void filter_unsupported_suites(suite_algs_t suites[], int *count) +{ + /* filter suite list by each algorithm */ + filter_suite(suites, count, offsetof(suite_algs_t, encr), + lib->crypto->create_crypter_enumerator); + filter_suite(suites, count, offsetof(suite_algs_t, encr), + lib->crypto->create_aead_enumerator); + filter_suite(suites, count, offsetof(suite_algs_t, mac), + lib->crypto->create_signer_enumerator); + filter_suite(suites, count, offsetof(suite_algs_t, prf), + lib->crypto->create_prf_enumerator); + filter_suite(suites, count, offsetof(suite_algs_t, hash), + lib->crypto->create_hasher_enumerator); + filter_suite(suites, count, offsetof(suite_algs_t, dh), + lib->crypto->create_dh_enumerator); +} + /** * Initialize the cipher suite list */ @@ -660,19 +1006,27 @@ static void build_cipher_suite_list(private_tls_crypto_t *this, { suites[i] = suite_algs[i]; } + if (require_encryption) { - filter_null_suites(this, suites, &count); + filter_null_suites(suites, &count); } - /* filter suite list by each algorithm */ - filter_suite(this, suites, &count, offsetof(suite_algs_t, encr), - lib->crypto->create_crypter_enumerator); - filter_suite(this, suites, &count, offsetof(suite_algs_t, mac), - lib->crypto->create_signer_enumerator); - filter_suite(this, suites, &count, offsetof(suite_algs_t, prf), - lib->crypto->create_prf_enumerator); - filter_suite(this, suites, &count, offsetof(suite_algs_t, hash), - lib->crypto->create_hasher_enumerator); + if (!this->rsa) + { + filter_key_suites(this, suites, &count, KEY_RSA); + } + if (!this->ecdsa) + { + filter_key_suites(this, suites, &count, KEY_ECDSA); + } + + filter_unsupported_suites(suites, &count); + + /* filter suites with strongswan.conf options */ + filter_key_exchange_config_suites(this, suites, &count); + filter_cipher_config_suites(this, suites, &count); + filter_mac_config_suites(this, suites, &count); + filter_specific_config_suites(this, suites, &count); free(this->suites); this->suite_count = count; @@ -693,11 +1047,83 @@ METHOD(tls_crypto_t, get_cipher_suites, int, return this->suite_count; } +/** + * Create NULL encryption transforms + */ +static bool create_null(private_tls_crypto_t *this, suite_algs_t *algs) +{ + this->aead_in = tls_aead_create_null(algs->mac); + this->aead_out = tls_aead_create_null(algs->mac); + if (!this->aead_in || !this->aead_out) + { + DBG1(DBG_TLS, "selected TLS MAC %N not supported", + integrity_algorithm_names, algs->mac); + return FALSE; + } + return TRUE; +} + +/** + * Create traditional transforms + */ +static bool create_traditional(private_tls_crypto_t *this, suite_algs_t *algs) +{ + if (this->tls->get_version(this->tls) < TLS_1_1) + { + this->aead_in = tls_aead_create_implicit(algs->mac, + algs->encr, algs->encr_size); + this->aead_out = tls_aead_create_implicit(algs->mac, + algs->encr, algs->encr_size); + } + else + { + this->aead_in = tls_aead_create_explicit(algs->mac, + algs->encr, algs->encr_size); + this->aead_out = tls_aead_create_explicit(algs->mac, + algs->encr, algs->encr_size); + } + if (!this->aead_in || !this->aead_out) + { + DBG1(DBG_TLS, "selected TLS transforms %N-%u-%N not supported", + encryption_algorithm_names, algs->encr, algs->encr_size * 8, + integrity_algorithm_names, algs->mac); + return FALSE; + } + return TRUE; +} + +/** + * Create AEAD transforms + */ +static bool create_aead(private_tls_crypto_t *this, suite_algs_t *algs) +{ + this->aead_in = tls_aead_create_aead(algs->encr, algs->encr_size); + this->aead_out = tls_aead_create_aead(algs->encr, algs->encr_size); + if (!this->aead_in || !this->aead_out) + { + DBG1(DBG_TLS, "selected TLS transforms %N-%u not supported", + encryption_algorithm_names, algs->encr, algs->encr_size * 8); + return FALSE; + } + return TRUE; +} + +/** + * Clean up and unset AEAD transforms + */ +static void destroy_aeads(private_tls_crypto_t *this) +{ + DESTROY_IF(this->aead_in); + DESTROY_IF(this->aead_out); + this->aead_in = this->aead_out = NULL; +} + /** * Create crypto primitives */ static bool create_ciphers(private_tls_crypto_t *this, suite_algs_t *algs) { + destroy_aeads(this); DESTROY_IF(this->prf); if (this->tls->get_version(this->tls) < TLS_1_2) { @@ -712,38 +1138,29 @@ static bool create_ciphers(private_tls_crypto_t *this, suite_algs_t *algs) DBG1(DBG_TLS, "selected TLS PRF not supported"); return FALSE; } - - DESTROY_IF(this->signer_in); - DESTROY_IF(this->signer_out); - this->signer_in = lib->crypto->create_signer(lib->crypto, algs->mac); - this->signer_out = lib->crypto->create_signer(lib->crypto, algs->mac); - if (!this->signer_in || !this->signer_out) + if (algs->encr == ENCR_NULL) { - DBG1(DBG_TLS, "selected TLS MAC %N not supported", - integrity_algorithm_names, algs->mac); - return FALSE; + if (create_null(this, algs)) + { + return TRUE; + } } - - DESTROY_IF(this->crypter_in); - DESTROY_IF(this->crypter_out); - if (algs->encr == ENCR_NULL) + else if (encryption_algorithm_is_aead(algs->encr)) { - this->crypter_in = this->crypter_out = NULL; + if (create_aead(this, algs)) + { + return TRUE; + } } else { - this->crypter_in = lib->crypto->create_crypter(lib->crypto, - algs->encr, algs->encr_size); - this->crypter_out = lib->crypto->create_crypter(lib->crypto, - algs->encr, algs->encr_size); - if (!this->crypter_in || !this->crypter_out) + if (create_traditional(this, algs)) { - DBG1(DBG_TLS, "selected TLS crypter %N not supported", - encryption_algorithm_names, algs->encr); - return FALSE; + return TRUE; } } - return TRUE; + destroy_aeads(this); + return FALSE; } METHOD(tls_crypto_t, select_cipher_suite, tls_cipher_suite_t, @@ -790,66 +1207,132 @@ METHOD(tls_crypto_t, get_dh_group, diffie_hellman_group_t, return MODP_NONE; } +/** + * Map signature schemes to TLS key types and hashes, ordered by preference + */ +static struct { + tls_signature_algorithm_t sig; + tls_hash_algorithm_t hash; + signature_scheme_t scheme; +} schemes[] = { + { TLS_SIG_ECDSA, TLS_HASH_SHA256, SIGN_ECDSA_WITH_SHA256_DER }, + { TLS_SIG_ECDSA, TLS_HASH_SHA384, SIGN_ECDSA_WITH_SHA384_DER }, + { TLS_SIG_ECDSA, TLS_HASH_SHA512, SIGN_ECDSA_WITH_SHA512_DER }, + { TLS_SIG_ECDSA, TLS_HASH_SHA1, SIGN_ECDSA_WITH_SHA1_DER }, + { TLS_SIG_RSA, TLS_HASH_SHA256, SIGN_RSA_EMSA_PKCS1_SHA2_256 }, + { TLS_SIG_RSA, TLS_HASH_SHA384, SIGN_RSA_EMSA_PKCS1_SHA2_384 }, + { TLS_SIG_RSA, TLS_HASH_SHA512, SIGN_RSA_EMSA_PKCS1_SHA2_512 }, + { TLS_SIG_RSA, TLS_HASH_SHA224, SIGN_RSA_EMSA_PKCS1_SHA2_224 }, + { TLS_SIG_RSA, TLS_HASH_SHA1, SIGN_RSA_EMSA_PKCS1_SHA1 }, + { TLS_SIG_RSA, TLS_HASH_MD5, SIGN_RSA_EMSA_PKCS1_MD5 }, +}; + METHOD(tls_crypto_t, get_signature_algorithms, void, - private_tls_crypto_t *this, tls_writer_t *writer) + private_tls_crypto_t *this, bio_writer_t *writer) { - tls_writer_t *supported; - enumerator_t *enumerator; - hash_algorithm_t alg; - tls_hash_algorithm_t hash; + bio_writer_t *supported; + int i; - supported = tls_writer_create(32); - enumerator = lib->crypto->create_hasher_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, &alg)) + supported = bio_writer_create(32); + + for (i = 0; i < countof(schemes); i++) { - switch (alg) + if (schemes[i].sig == TLS_SIG_RSA && !this->rsa) { - case HASH_MD5: - hash = TLS_HASH_MD5; - break; - case HASH_SHA1: - hash = TLS_HASH_SHA1; - break; - case HASH_SHA224: - hash = TLS_HASH_SHA224; - break; - case HASH_SHA256: - hash = TLS_HASH_SHA256; - break; - case HASH_SHA384: - hash = TLS_HASH_SHA384; - break; - case HASH_SHA512: - hash = TLS_HASH_SHA512; - break; - default: - continue; + continue; } - supported->write_uint8(supported, hash); - supported->write_uint8(supported, TLS_SIG_RSA); - if (alg != HASH_MD5 && alg != HASH_SHA224) + if (schemes[i].sig == TLS_SIG_ECDSA && !this->ecdsa) { - supported->write_uint8(supported, hash); - supported->write_uint8(supported, TLS_SIG_ECDSA); + continue; } + if (!lib->plugins->has_feature(lib->plugins, + PLUGIN_PROVIDE(PUBKEY_VERIFY, schemes[i].scheme))) + { + continue; + } + supported->write_uint8(supported, schemes[i].hash); + supported->write_uint8(supported, schemes[i].sig); } - enumerator->destroy(enumerator); + supported->wrap16(supported); writer->write_data16(writer, supported->get_buf(supported)); supported->destroy(supported); } -METHOD(tls_crypto_t, get_curves, void, - private_tls_crypto_t *this, tls_writer_t *writer) +/** + * Get the signature scheme from a TLS 1.2 hash/sig algorithm pair + */ +static signature_scheme_t hashsig_to_scheme(key_type_t type, + tls_hash_algorithm_t hash, + tls_signature_algorithm_t sig) { - u_int16_t curves[] = { - htons(TLS_SECP256R1), - htons(TLS_SECP384R1), - htons(TLS_SECP521R1), - htons(TLS_SECP192R1), - htons(TLS_SECP224R1), - }; - writer->write_data16(writer, chunk_from_thing(curves)); + int i; + + if ((sig == TLS_SIG_RSA && type == KEY_RSA) || + (sig == TLS_SIG_ECDSA && type == KEY_ECDSA)) + { + for (i = 0; i < countof(schemes); i++) + { + if (schemes[i].sig == sig && schemes[i].hash == hash) + { + return schemes[i].scheme; + } + } + } + return SIGN_UNKNOWN; +} + +/** + * Mapping groups to TLS named curves + */ +static struct { + diffie_hellman_group_t group; + tls_named_curve_t curve; +} curves[] = { + { ECP_256_BIT, TLS_SECP256R1}, + { ECP_384_BIT, TLS_SECP384R1}, + { ECP_521_BIT, TLS_SECP521R1}, + { ECP_224_BIT, TLS_SECP224R1}, + { ECP_192_BIT, TLS_SECP192R1}, +}; + +CALLBACK(group_filter, bool, + void *null, enumerator_t *orig, va_list args) +{ + diffie_hellman_group_t group, *out; + tls_named_curve_t *curve; + char *plugin; + int i; + + VA_ARGS_VGET(args, out, curve); + + while (orig->enumerate(orig, &group, &plugin)) + { + for (i = 0; i < countof(curves); i++) + { + if (curves[i].group == group) + { + if (out) + { + *out = curves[i].group; + } + if (curve) + { + *curve = curves[i].curve; + } + return TRUE; + } + } + } + return FALSE; +} + +METHOD(tls_crypto_t, create_ec_enumerator, enumerator_t*, + private_tls_crypto_t *this) +{ + return enumerator_create_filter( + lib->crypto->create_dh_enumerator(lib->crypto), + group_filter, NULL, NULL); } METHOD(tls_crypto_t, set_protection, void, @@ -861,7 +1344,7 @@ METHOD(tls_crypto_t, set_protection, void, METHOD(tls_crypto_t, append_handshake, void, private_tls_crypto_t *this, tls_handshake_type_t type, chunk_t data) { - u_int32_t header; + uint32_t header; /* reconstruct handshake header */ header = htonl(data.len | (type << 24)); @@ -885,12 +1368,12 @@ static bool hash_data(private_tls_crypto_t *this, chunk_t data, chunk_t *hash) return FALSE; } hasher = lib->crypto->create_hasher(lib->crypto, alg->hash); - if (!hasher) + if (!hasher || !hasher->allocate_hash(hasher, data, hash)) { DBG1(DBG_TLS, "%N not supported", hash_algorithm_names, alg->hash); + DESTROY_IF(hasher); return FALSE; } - hasher->allocate_hash(hasher, data, hash); hasher->destroy(hasher); } else @@ -899,20 +1382,20 @@ static bool hash_data(private_tls_crypto_t *this, chunk_t data, chunk_t *hash) char buf[HASH_SIZE_MD5 + HASH_SIZE_SHA1]; md5 = lib->crypto->create_hasher(lib->crypto, HASH_MD5); - if (!md5) + if (!md5 || !md5->get_hash(md5, data, buf)) { DBG1(DBG_TLS, "%N not supported", hash_algorithm_names, HASH_MD5); + DESTROY_IF(md5); return FALSE; } - md5->get_hash(md5, data, buf); md5->destroy(md5); sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!sha1) + if (!sha1 || !sha1->get_hash(sha1, data, buf + HASH_SIZE_MD5)) { DBG1(DBG_TLS, "%N not supported", hash_algorithm_names, HASH_SHA1); + DESTROY_IF(sha1); return FALSE; } - sha1->get_hash(sha1, data, buf + HASH_SIZE_MD5); sha1->destroy(sha1); *hash = chunk_clone(chunk_from_thing(buf)); @@ -920,68 +1403,15 @@ static bool hash_data(private_tls_crypto_t *this, chunk_t data, chunk_t *hash) return TRUE; } -/** - * Get the signature scheme from a TLS 1.2 hash/sig algorithm pair - */ -static signature_scheme_t hashsig_to_scheme(key_type_t type, - tls_hash_algorithm_t hash, tls_signature_algorithm_t sig) -{ - switch (sig) - { - case TLS_SIG_RSA: - if (type != KEY_RSA) - { - return SIGN_UNKNOWN; - } - switch (hash) - { - case TLS_HASH_MD5: - return SIGN_RSA_EMSA_PKCS1_MD5; - case TLS_HASH_SHA1: - return SIGN_RSA_EMSA_PKCS1_SHA1; - case TLS_HASH_SHA224: - return SIGN_RSA_EMSA_PKCS1_SHA224; - case TLS_HASH_SHA256: - return SIGN_RSA_EMSA_PKCS1_SHA256; - case TLS_HASH_SHA384: - return SIGN_RSA_EMSA_PKCS1_SHA384; - case TLS_HASH_SHA512: - return SIGN_RSA_EMSA_PKCS1_SHA512; - default: - return SIGN_UNKNOWN; - } - case TLS_SIG_ECDSA: - if (type != KEY_ECDSA) - { - return SIGN_UNKNOWN; - } - switch (hash) - { - case TLS_HASH_SHA224: - return SIGN_ECDSA_WITH_SHA1_DER; - case TLS_HASH_SHA256: - return SIGN_ECDSA_WITH_SHA256_DER; - case TLS_HASH_SHA384: - return SIGN_ECDSA_WITH_SHA384_DER; - case TLS_HASH_SHA512: - return SIGN_ECDSA_WITH_SHA512_DER; - default: - return SIGN_UNKNOWN; - } - default: - return SIGN_UNKNOWN; - } -} - METHOD(tls_crypto_t, sign, bool, - private_tls_crypto_t *this, private_key_t *key, tls_writer_t *writer, + private_tls_crypto_t *this, private_key_t *key, bio_writer_t *writer, chunk_t data, chunk_t hashsig) { if (this->tls->get_version(this->tls) >= TLS_1_2) { signature_scheme_t scheme; - tls_reader_t *reader; - u_int8_t hash, alg; + bio_reader_t *reader; + uint8_t hash, alg; chunk_t sig; bool done = FALSE; @@ -990,7 +1420,7 @@ METHOD(tls_crypto_t, sign, bool, hashsig = chunk_from_chars( TLS_HASH_SHA1, TLS_SIG_RSA, TLS_HASH_SHA1, TLS_SIG_ECDSA); } - reader = tls_reader_create(hashsig); + reader = bio_reader_create(hashsig); while (reader->remaining(reader) >= 2) { if (reader->read_uint8(reader, &hash) && @@ -998,7 +1428,7 @@ METHOD(tls_crypto_t, sign, bool, { scheme = hashsig_to_scheme(key->get_type(key), hash, alg); if (scheme != SIGN_UNKNOWN && - key->sign(key, scheme, data, &sig)) + key->sign(key, scheme, NULL, data, &sig)) { done = TRUE; break; @@ -1030,7 +1460,8 @@ METHOD(tls_crypto_t, sign, bool, { return FALSE; } - done = key->sign(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig); + done = key->sign(key, SIGN_RSA_EMSA_PKCS1_NULL, NULL, hash, + &sig); free(hash.ptr); if (!done) { @@ -1039,7 +1470,7 @@ METHOD(tls_crypto_t, sign, bool, DBG2(DBG_TLS, "created signature with MD5+SHA1/RSA"); break; case KEY_ECDSA: - if (!key->sign(key, SIGN_ECDSA_WITH_SHA1_DER, data, &sig)) + if (!key->sign(key, SIGN_ECDSA_WITH_SHA1_DER, NULL, data, &sig)) { return FALSE; } @@ -1055,13 +1486,13 @@ METHOD(tls_crypto_t, sign, bool, } METHOD(tls_crypto_t, verify, bool, - private_tls_crypto_t *this, public_key_t *key, tls_reader_t *reader, + private_tls_crypto_t *this, public_key_t *key, bio_reader_t *reader, chunk_t data) { if (this->tls->get_version(this->tls) >= TLS_1_2) { signature_scheme_t scheme = SIGN_UNKNOWN; - u_int8_t hash, alg; + uint8_t hash, alg; chunk_t sig; if (!reader->read_uint8(reader, &hash) || @@ -1079,7 +1510,7 @@ METHOD(tls_crypto_t, verify, bool, tls_signature_algorithm_names, alg); return FALSE; } - if (!key->verify(key, scheme, data, sig)) + if (!key->verify(key, scheme, NULL, data, sig)) { return FALSE; } @@ -1103,7 +1534,8 @@ METHOD(tls_crypto_t, verify, bool, { return FALSE; } - done = key->verify(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, sig); + done = key->verify(key, SIGN_RSA_EMSA_PKCS1_NULL, NULL, hash, + sig); free(hash.ptr); if (!done) { @@ -1112,7 +1544,8 @@ METHOD(tls_crypto_t, verify, bool, DBG2(DBG_TLS, "verified signature data with MD5+SHA1/RSA"); break; case KEY_ECDSA: - if (!key->verify(key, SIGN_ECDSA_WITH_SHA1_DER, data, sig)) + if (!key->verify(key, SIGN_ECDSA_WITH_SHA1_DER, NULL, data, + sig)) { return FALSE; } @@ -1126,14 +1559,14 @@ METHOD(tls_crypto_t, verify, bool, } METHOD(tls_crypto_t, sign_handshake, bool, - private_tls_crypto_t *this, private_key_t *key, tls_writer_t *writer, + private_tls_crypto_t *this, private_key_t *key, bio_writer_t *writer, chunk_t hashsig) { return sign(this, key, writer, this->handshake, hashsig); } METHOD(tls_crypto_t, verify_handshake, bool, - private_tls_crypto_t *this, public_key_t *key, tls_reader_t *reader) + private_tls_crypto_t *this, public_key_t *key, bio_reader_t *reader) { return verify(this, key, reader, this->handshake); } @@ -1151,95 +1584,166 @@ METHOD(tls_crypto_t, calculate_finished, bool, { return FALSE; } - this->prf->get_bytes(this->prf, label, seed, 12, out); + if (!this->prf->get_bytes(this->prf, label, seed, 12, out)) + { + free(seed.ptr); + return FALSE; + } free(seed.ptr); return TRUE; } -METHOD(tls_crypto_t, derive_secrets, void, - private_tls_crypto_t *this, chunk_t premaster, - chunk_t client_random, chunk_t server_random) +/** + * Derive master secret from premaster, optionally save session + */ +static bool derive_master(private_tls_crypto_t *this, chunk_t premaster, + chunk_t session, identification_t *id, + chunk_t client_random, chunk_t server_random) { char master[48]; - chunk_t seed, block, client_write, server_write; - int mks, eks = 0, ivs = 0; + chunk_t seed; /* derive master secret */ seed = chunk_cata("cc", client_random, server_random); - this->prf->set_key(this->prf, premaster); - this->prf->get_bytes(this->prf, "master secret", seed, - sizeof(master), master); - - this->prf->set_key(this->prf, chunk_from_thing(master)); - memset(master, 0, sizeof(master)); - /* derive key block for key expansion */ - mks = this->signer_out->get_key_size(this->signer_out); - if (this->crypter_out) + if (!this->prf->set_key(this->prf, premaster) || + !this->prf->get_bytes(this->prf, "master secret", seed, + sizeof(master), master) || + !this->prf->set_key(this->prf, chunk_from_thing(master))) { - eks = this->crypter_out->get_key_size(this->crypter_out); - if (this->tls->get_version(this->tls) < TLS_1_1) - { - ivs = this->crypter_out->get_iv_size(this->crypter_out); - } + return FALSE; } - seed = chunk_cata("cc", server_random, client_random); - block = chunk_alloca((mks + eks + ivs) * 2); - this->prf->get_bytes(this->prf, "key expansion", seed, block.len, block.ptr); - - /* signer keys */ - client_write = chunk_create(block.ptr, mks); - block = chunk_skip(block, mks); - server_write = chunk_create(block.ptr, mks); - block = chunk_skip(block, mks); - if (this->tls->is_server(this->tls)) + + if (this->cache && session.len) { - this->signer_in->set_key(this->signer_in, client_write); - this->signer_out->set_key(this->signer_out, server_write); + this->cache->create(this->cache, session, id, chunk_from_thing(master), + this->suite); } - else + memwipe(master, sizeof(master)); + return TRUE; +} + +/** + * Expand key material from master secret + */ +static bool expand_keys(private_tls_crypto_t *this, + chunk_t client_random, chunk_t server_random) +{ + chunk_t seed, block; + chunk_t cw_mac, cw, cw_iv; + chunk_t sw_mac, sw, sw_iv; + int mklen, eklen, ivlen; + + if (!this->aead_in || !this->aead_out) { - this->signer_out->set_key(this->signer_out, client_write); - this->signer_in->set_key(this->signer_in, server_write); + return FALSE; } - /* crypter keys, and IVs if < TLSv1.2 */ - if (this->crypter_out && this->crypter_in) + /* derive key block for key expansion */ + mklen = this->aead_in->get_mac_key_size(this->aead_in); + eklen = this->aead_in->get_encr_key_size(this->aead_in); + ivlen = this->aead_in->get_iv_size(this->aead_in); + seed = chunk_cata("cc", server_random, client_random); + block = chunk_alloca((mklen + eklen + ivlen) * 2); + if (!this->prf->get_bytes(this->prf, "key expansion", seed, + block.len, block.ptr)) { - client_write = chunk_create(block.ptr, eks); - block = chunk_skip(block, eks); - server_write = chunk_create(block.ptr, eks); - block = chunk_skip(block, eks); + return FALSE; + } + + /* client/server write signer keys */ + cw_mac = chunk_create(block.ptr, mklen); + block = chunk_skip(block, mklen); + sw_mac = chunk_create(block.ptr, mklen); + block = chunk_skip(block, mklen); + + /* client/server write encryption keys */ + cw = chunk_create(block.ptr, eklen); + block = chunk_skip(block, eklen); + sw = chunk_create(block.ptr, eklen); + block = chunk_skip(block, eklen); - if (this->tls->is_server(this->tls)) + /* client/server write IV; TLS 1.0 implicit IVs or AEAD salt, if any */ + cw_iv = chunk_create(block.ptr, ivlen); + block = chunk_skip(block, ivlen); + sw_iv = chunk_create(block.ptr, ivlen); + block = chunk_skip(block, ivlen); + + if (this->tls->is_server(this->tls)) + { + if (!this->aead_in->set_keys(this->aead_in, cw_mac, cw, cw_iv) || + !this->aead_out->set_keys(this->aead_out, sw_mac, sw, sw_iv)) { - this->crypter_in->set_key(this->crypter_in, client_write); - this->crypter_out->set_key(this->crypter_out, server_write); + return FALSE; } - else + } + else + { + if (!this->aead_out->set_keys(this->aead_out, cw_mac, cw, cw_iv) || + !this->aead_in->set_keys(this->aead_in, sw_mac, sw, sw_iv)) { - this->crypter_out->set_key(this->crypter_out, client_write); - this->crypter_in->set_key(this->crypter_in, server_write); + return FALSE; } - if (ivs) + } + + /* EAP-MSK */ + if (this->msk_label) + { + seed = chunk_cata("cc", client_random, server_random); + this->msk = chunk_alloc(64); + if (!this->prf->get_bytes(this->prf, this->msk_label, seed, + this->msk.len, this->msk.ptr)) { - client_write = chunk_create(block.ptr, ivs); - block = chunk_skip(block, ivs); - server_write = chunk_create(block.ptr, ivs); - block = chunk_skip(block, ivs); + return FALSE; + } + } + return TRUE; +} - if (this->tls->is_server(this->tls)) - { - this->iv_in = chunk_clone(client_write); - this->iv_out = chunk_clone(server_write); - } - else +METHOD(tls_crypto_t, derive_secrets, bool, + private_tls_crypto_t *this, chunk_t premaster, chunk_t session, + identification_t *id, chunk_t client_random, chunk_t server_random) +{ + return derive_master(this, premaster, session, id, + client_random, server_random) && + expand_keys(this, client_random, server_random); +} + +METHOD(tls_crypto_t, resume_session, tls_cipher_suite_t, + private_tls_crypto_t *this, chunk_t session, identification_t *id, + chunk_t client_random, chunk_t server_random) +{ + chunk_t master; + + if (this->cache && session.len) + { + this->suite = this->cache->lookup(this->cache, session, id, &master); + if (this->suite) + { + this->suite = select_cipher_suite(this, &this->suite, 1, KEY_ANY); + if (this->suite) { - this->iv_out = chunk_clone(client_write); - this->iv_in = chunk_clone(server_write); + if (!this->prf->set_key(this->prf, master) || + !expand_keys(this, client_random, server_random)) + { + this->suite = 0; + } } + chunk_clear(&master); } + return this->suite; } + return 0; +} + +METHOD(tls_crypto_t, get_session, chunk_t, + private_tls_crypto_t *this, identification_t *server) +{ + if (this->cache) + { + return this->cache->check(this->cache, server); + } + return chunk_empty; } METHOD(tls_crypto_t, change_cipher, void, @@ -1249,32 +1753,15 @@ METHOD(tls_crypto_t, change_cipher, void, { if (inbound) { - this->protection->set_cipher(this->protection, TRUE, - this->signer_in, this->crypter_in, this->iv_in); + this->protection->set_cipher(this->protection, TRUE, this->aead_in); } else { - this->protection->set_cipher(this->protection, FALSE, - this->signer_out, this->crypter_out, this->iv_out); + this->protection->set_cipher(this->protection, FALSE, this->aead_out); } } } -METHOD(tls_crypto_t, derive_eap_msk, void, - private_tls_crypto_t *this, chunk_t client_random, chunk_t server_random) -{ - if (this->msk_label) - { - chunk_t seed; - - seed = chunk_cata("cc", client_random, server_random); - free(this->msk.ptr); - this->msk = chunk_alloc(64); - this->prf->get_bytes(this->prf, this->msk_label, seed, - this->msk.len, this->msk.ptr); - } -} - METHOD(tls_crypto_t, get_eap_msk, chunk_t, private_tls_crypto_t *this) { @@ -1284,12 +1771,7 @@ METHOD(tls_crypto_t, get_eap_msk, chunk_t, METHOD(tls_crypto_t, destroy, void, private_tls_crypto_t *this) { - DESTROY_IF(this->signer_in); - DESTROY_IF(this->signer_out); - DESTROY_IF(this->crypter_in); - DESTROY_IF(this->crypter_out); - free(this->iv_in.ptr); - free(this->iv_out.ptr); + destroy_aeads(this); free(this->handshake.ptr); free(this->msk.ptr); DESTROY_IF(this->prf); @@ -1300,9 +1782,12 @@ METHOD(tls_crypto_t, destroy, void, /** * See header */ -tls_crypto_t *tls_crypto_create(tls_t *tls) +tls_crypto_t *tls_crypto_create(tls_t *tls, tls_cache_t *cache) { private_tls_crypto_t *this; + enumerator_t *enumerator; + credential_type_t type; + int subtype; INIT(this, .public = { @@ -1310,7 +1795,7 @@ tls_crypto_t *tls_crypto_create(tls_t *tls) .select_cipher_suite = _select_cipher_suite, .get_dh_group = _get_dh_group, .get_signature_algorithms = _get_signature_algorithms, - .get_curves = _get_curves, + .create_ec_enumerator = _create_ec_enumerator, .set_protection = _set_protection, .append_handshake = _append_handshake, .sign = _sign, @@ -1319,14 +1804,36 @@ tls_crypto_t *tls_crypto_create(tls_t *tls) .verify_handshake = _verify_handshake, .calculate_finished = _calculate_finished, .derive_secrets = _derive_secrets, + .resume_session = _resume_session, + .get_session = _get_session, .change_cipher = _change_cipher, - .derive_eap_msk = _derive_eap_msk, .get_eap_msk = _get_eap_msk, .destroy = _destroy, }, .tls = tls, + .cache = cache, ); + enumerator = lib->creds->create_builder_enumerator(lib->creds); + while (enumerator->enumerate(enumerator, &type, &subtype)) + { + if (type == CRED_PUBLIC_KEY) + { + switch (subtype) + { + case KEY_RSA: + this->rsa = TRUE; + break; + case KEY_ECDSA: + this->ecdsa = TRUE; + break; + default: + break; + } + } + } + enumerator->destroy(enumerator); + switch (tls->get_purpose(tls)) { case TLS_PURPOSE_EAP_TLS: @@ -1334,6 +1841,10 @@ tls_crypto_t *tls_crypto_create(tls_t *tls) this->msk_label = "client EAP encryption"; build_cipher_suite_list(this, FALSE); break; + case TLS_PURPOSE_EAP_PEAP: + this->msk_label = "client EAP encryption"; + build_cipher_suite_list(this, TRUE); + break; case TLS_PURPOSE_EAP_TTLS: /* MSK PRF ASCII constant label according to EAP-TTLS RFC 5281 */ this->msk_label = "ttls keying material"; @@ -1342,6 +1853,43 @@ tls_crypto_t *tls_crypto_create(tls_t *tls) case TLS_PURPOSE_GENERIC: build_cipher_suite_list(this, TRUE); break; + case TLS_PURPOSE_GENERIC_NULLOK: + build_cipher_suite_list(this, FALSE); + break; + default: + break; } return &this->public; } + +/** + * See header. + */ +int tls_crypto_get_supported_suites(bool null, tls_cipher_suite_t **out) +{ + suite_algs_t suites[countof(suite_algs)]; + int count = countof(suite_algs), i; + + /* initialize copy of suite list */ + for (i = 0; i < count; i++) + { + suites[i] = suite_algs[i]; + } + + filter_unsupported_suites(suites, &count); + + if (!null) + { + filter_null_suites(suites, &count); + } + + if (out) + { + *out = calloc(count, sizeof(tls_cipher_suite_t)); + for (i = 0; i < count; i++) + { + (*out)[i] = suites[i].suite; + } + } + return count; +}