/* * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 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 * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "tls_crypto.h" #include ENUM_BEGIN(tls_cipher_suite_names, TLS_NULL_WITH_NULL_NULL, TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, "TLS_NULL_WITH_NULL_NULL", "TLS_RSA_WITH_NULL_MD5", "TLS_RSA_WITH_NULL_SHA", "TLS_RSA_EXPORT_WITH_RC4_40_MD5", "TLS_RSA_WITH_RC4_128_MD5", "TLS_RSA_WITH_RC4_128_SHA", "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5", "TLS_RSA_WITH_IDEA_CBC_SHA", "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", "TLS_RSA_WITH_DES_CBC_SHA", "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", "TLS_DH_DSS_WITH_DES_CBC_SHA", "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", "TLS_DH_RSA_WITH_DES_CBC_SHA", "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", "TLS_DHE_DSS_WITH_DES_CBC_SHA", "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "TLS_DHE_RSA_WITH_DES_CBC_SHA", "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5", "TLS_DH_anon_WITH_RC4_128_MD5", "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA", "TLS_DH_anon_WITH_DES_CBC_SHA", "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"); ENUM_NEXT(tls_cipher_suite_names, TLS_KRB5_WITH_DES_CBC_SHA, TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA, TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, "TLS_KRB5_WITH_DES_CBC_SHA", "TLS_KRB5_WITH_3DES_EDE_CBC_SHA", "TLS_KRB5_WITH_RC4_128_SHA", "TLS_KRB5_WITH_IDEA_CBC_SHA", "TLS_KRB5_WITH_DES_CBC_MD5", "TLS_KRB5_WITH_3DES_EDE_CBC_MD5", "TLS_KRB5_WITH_RC4_128_MD5", "TLS_KRB5_WITH_IDEA_CBC_MD5", "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", "TLS_KRB5_EXPORT_WITH_RC4_40_SHA", "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", "TLS_KRB5_EXPORT_WITH_RC4_40_MD5", "TLS_PSK_WITH_NULL_SHA", "TLS_DHE_PSK_WITH_NULL_SHA", "TLS_RSA_PSK_WITH_NULL_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_DH_DSS_WITH_AES_128_CBC_SHA", "TLS_DH_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DH_anon_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_DH_DSS_WITH_AES_256_CBC_SHA", "TLS_DH_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_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_256_CBC_SHA256", "TLS_DH_DSS_WITH_AES_128_CBC_SHA256", "TLS_DH_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA"); ENUM_NEXT(tls_cipher_suite_names, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DH_DSS_WITH_AES_256_CBC_SHA256", "TLS_DH_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DH_anon_WITH_AES_128_CBC_SHA256", "TLS_DH_anon_WITH_AES_256_CBC_SHA256"); ENUM_NEXT(tls_cipher_suite_names, TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256, TLS_DH_anon_WITH_AES_256_CBC_SHA256, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", "TLS_DHE_DSS_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_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_RSA_PSK_WITH_RC4_128_SHA", "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", "TLS_RSA_PSK_WITH_AES_128_CBC_SHA", "TLS_RSA_PSK_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_SEED_CBC_SHA", "TLS_DH_DSS_WITH_SEED_CBC_SHA", "TLS_DH_RSA_WITH_SEED_CBC_SHA", "TLS_DHE_DSS_WITH_SEED_CBC_SHA", "TLS_DHE_RSA_WITH_SEED_CBC_SHA", "TLS_DH_anon_WITH_SEED_CBC_SHA", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DH_RSA_WITH_AES_128_GCM_SHA256", "TLS_DH_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_DH_DSS_WITH_AES_128_GCM_SHA256", "TLS_DH_DSS_WITH_AES_256_GCM_SHA384", "TLS_DH_anon_WITH_AES_128_GCM_SHA256", "TLS_DH_anon_WITH_AES_256_GCM_SHA384", "TLS_PSK_WITH_AES_128_GCM_SHA256", "TLS_PSK_WITH_AES_256_GCM_SHA384", "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", "TLS_PSK_WITH_AES_128_CBC_SHA256", "TLS_PSK_WITH_AES_256_CBC_SHA384", "TLS_PSK_WITH_NULL_SHA256", "TLS_PSK_WITH_NULL_SHA384", "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", "TLS_DHE_PSK_WITH_NULL_SHA256", "TLS_DHE_PSK_WITH_NULL_SHA384", "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", "TLS_RSA_PSK_WITH_NULL_SHA256", "TLS_RSA_PSK_WITH_NULL_SHA384", "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256", "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256"); ENUM_NEXT(tls_cipher_suite_names, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"); ENUM_NEXT(tls_cipher_suite_names, TLS_ECDH_ECDSA_WITH_NULL_SHA, TLS_ECDHE_PSK_WITH_NULL_SHA384, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, "TLS_ECDH_ECDSA_WITH_NULL_SHA", "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_NULL_SHA", "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDH_RSA_WITH_NULL_SHA", "TLS_ECDH_RSA_WITH_RC4_128_SHA", "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_NULL_SHA", "TLS_ECDHE_RSA_WITH_RC4_128_SHA", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDH_anon_WITH_NULL_SHA", "TLS_ECDH_anon_WITH_RC4_128_SHA", "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", "TLS_ECDH_anon_WITH_AES_128_CBC_SHA", "TLS_ECDH_anon_WITH_AES_256_CBC_SHA", "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_PSK_WITH_RC4_128_SHA", "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_PSK_WITH_NULL_SHA", "TLS_ECDHE_PSK_WITH_NULL_SHA256", "TLS_ECDHE_PSK_WITH_NULL_SHA384"); ENUM_END(tls_cipher_suite_names, TLS_ECDHE_PSK_WITH_NULL_SHA384); typedef struct private_tls_crypto_t private_tls_crypto_t; /** * Private data of an tls_crypto_t object. */ struct private_tls_crypto_t { /** * Public tls_crypto_t interface. */ tls_crypto_t public; /** * Protection layer */ tls_protection_t *protection; /** * List of supported/acceptable cipher suites */ tls_cipher_suite_t *suites; /** * Number of supported suites */ int suite_count; /** * Selected cipher suite */ tls_cipher_suite_t suite; /** * TLS context */ tls_t *tls; /** * All handshake data concatentated */ chunk_t handshake; /** * Connection state TLS PRF */ tls_prf_t *prf; /** * Signer instance for inbound traffic */ signer_t *signer_in; /** * Signer instance for outbound traffic */ signer_t *signer_out; /** * Crypter instance for inbound traffic */ crypter_t *crypter_in; /** * Crypter instance for outbound traffic */ crypter_t *crypter_out; /** * IV for input decryption, if < TLSv1.2 */ chunk_t iv_in; /** * IV for output decryption, if < TLSv1.2 */ chunk_t iv_out; /** * EAP-[T]TLS MSK */ chunk_t msk; /** * ASCII string constant used as seed for EAP-[T]TLS MSK PRF */ char *msk_label; }; typedef struct { tls_cipher_suite_t suite; hash_algorithm_t hash; pseudo_random_function_t prf; integrity_algorithm_t mac; encryption_algorithm_t encr; size_t encr_size; } suite_algs_t; /** * Mapping suites to a set of algorithms */ static suite_algs_t suite_algs[] = { { TLS_RSA_WITH_NULL_MD5, HASH_MD5, PRF_HMAC_MD5, AUTH_HMAC_MD5_128, ENCR_NULL, 0 }, { TLS_RSA_WITH_NULL_SHA, HASH_SHA1, PRF_HMAC_SHA1, AUTH_HMAC_SHA1_160, ENCR_NULL, 0 }, { TLS_RSA_WITH_NULL_SHA256, HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_256, ENCR_NULL, 0 }, { TLS_RSA_WITH_3DES_EDE_CBC_SHA, HASH_SHA1, PRF_HMAC_SHA1, AUTH_HMAC_SHA1_160, ENCR_3DES, 0 }, { TLS_RSA_WITH_AES_128_CBC_SHA, HASH_SHA1, PRF_HMAC_SHA1, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16 }, { TLS_RSA_WITH_AES_128_CBC_SHA256, HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 16 }, { TLS_RSA_WITH_AES_256_CBC_SHA, HASH_SHA1, PRF_HMAC_SHA1, AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32 }, { TLS_RSA_WITH_AES_256_CBC_SHA256, HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 32 }, { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, HASH_SHA1, PRF_HMAC_SHA1, AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 16 }, { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_256, ENCR_CAMELLIA_CBC, 16 }, { TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, HASH_SHA1, PRF_HMAC_SHA1, AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 32 }, { TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, HASH_SHA256, PRF_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_256, ENCR_CAMELLIA_CBC, 32 }, }; /** * Look up algoritms by a suite */ static suite_algs_t *find_suite(tls_cipher_suite_t suite) { int i; for (i = 0; i < countof(suite_algs); i++) { if (suite_algs[i].suite == suite) { return &suite_algs[i]; } } return NULL; } /** * 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, enumerator_t*(*create_enumerator)(crypto_factory_t*)) { suite_algs_t current; int i, remaining = 0; enumerator_t *enumerator; memset(¤t, 0, sizeof(current)); for (i = 0; i < *count; i++) { enumerator = create_enumerator(lib->crypto); while (enumerator->enumerate(enumerator, ((char*)¤t) + offset)) { 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)) { suites[remaining] = suites[i]; remaining++; break; } } enumerator->destroy(enumerator); } *count = remaining; } /** * Purge NULL encryption cipher suites from list */ static void filter_null_suites(private_tls_crypto_t *this, suite_algs_t suites[], int *count) { int i, remaining = 0; for (i = 0; i < *count; i++) { if (suites[i].encr != ENCR_NULL) { suites[remaining] = suites[i]; remaining++; } } *count = remaining; } /** * Initialize the cipher suite list */ static void build_cipher_suite_list(private_tls_crypto_t *this, bool require_encryption) { suite_algs_t suites[countof(suite_algs)]; int count = countof(suite_algs), i; /* copy all suites */ for (i = 0; i < count; i++) { suites[i] = suite_algs[i]; } if (require_encryption) { filter_null_suites(this, 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); free(this->suites); this->suite_count = count; this->suites = malloc(sizeof(tls_cipher_suite_t) * count); DBG2(DBG_CFG, "%d supported TLS cipher suites:", count); for (i = 0; i < count; i++) { DBG2(DBG_CFG, " %N", tls_cipher_suite_names, suites[i].suite); this->suites[i] = suites[i].suite; } } METHOD(tls_crypto_t, get_cipher_suites, int, private_tls_crypto_t *this, tls_cipher_suite_t **suites) { *suites = this->suites; return this->suite_count; } /** * Create crypto primitives */ static bool create_ciphers(private_tls_crypto_t *this, tls_cipher_suite_t suite) { suite_algs_t *algs; algs = find_suite(suite); if (!algs) { DBG1(DBG_IKE, "selected TLS suite not supported"); return FALSE; } DESTROY_IF(this->prf); if (this->tls->get_version(this->tls) < TLS_1_2) { this->prf = tls_prf_create_10(); } else { this->prf = tls_prf_create_12(algs->prf); } if (!this->prf) { DBG1(DBG_IKE, "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) { DBG1(DBG_IKE, "selected TLS MAC %N not supported", integrity_algorithm_names, algs->mac); return FALSE; } DESTROY_IF(this->crypter_in); DESTROY_IF(this->crypter_out); if (algs->encr == ENCR_NULL) { this->crypter_in = this->crypter_out = NULL; } 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) { DBG1(DBG_IKE, "selected TLS crypter %N not supported", encryption_algorithm_names, algs->encr); return FALSE; } } return TRUE; } METHOD(tls_crypto_t, select_cipher_suite, tls_cipher_suite_t, private_tls_crypto_t *this, tls_cipher_suite_t *suites, int count) { int i, j; for (i = 0; i < this->suite_count; i++) { for (j = 0; j < count; j++) { if (this->suites[i] == suites[j]) { if (create_ciphers(this, this->suites[i])) { this->suite = this->suites[i]; return this->suite; } } } } return 0; } METHOD(tls_crypto_t, set_protection, void, private_tls_crypto_t *this, tls_protection_t *protection) { this->protection = protection; } METHOD(tls_crypto_t, append_handshake, void, private_tls_crypto_t *this, tls_handshake_type_t type, chunk_t data) { u_int32_t header; /* reconstruct handshake header */ header = htonl(data.len | (type << 24)); this->handshake = chunk_cat("mcc", this->handshake, chunk_from_thing(header), data); } /** * Create a hash of the stored handshake data */ static bool hash_handshake(private_tls_crypto_t *this, chunk_t *hash) { if (this->tls->get_version(this->tls) >= TLS_1_2) { hasher_t *hasher; suite_algs_t *alg; alg = find_suite(this->suite); if (!alg) { return FALSE; } hasher = lib->crypto->create_hasher(lib->crypto, alg->hash); if (!hasher) { DBG1(DBG_IKE, "%N not supported", hash_algorithm_names, alg->hash); return FALSE; } hasher->allocate_hash(hasher, this->handshake, hash); hasher->destroy(hasher); } else { hasher_t *md5, *sha1; char buf[HASH_SIZE_MD5 + HASH_SIZE_SHA1]; md5 = lib->crypto->create_hasher(lib->crypto, HASH_MD5); if (!md5) { DBG1(DBG_IKE, "%N not supported", hash_algorithm_names, HASH_MD5); return FALSE; } md5->get_hash(md5, this->handshake, buf); md5->destroy(md5); sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (!sha1) { DBG1(DBG_IKE, "%N not supported", hash_algorithm_names, HASH_SHA1); return FALSE; } sha1->get_hash(sha1, this->handshake, buf + HASH_SIZE_MD5); sha1->destroy(sha1); *hash = chunk_clone(chunk_from_thing(buf)); } return TRUE; } METHOD(tls_crypto_t, sign_handshake, bool, private_tls_crypto_t *this, private_key_t *key, tls_writer_t *writer) { chunk_t sig, hash; if (this->tls->get_version(this->tls) >= TLS_1_2) { /* TODO: use supported algorithms instead of fixed SHA1/RSA */ if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_SHA1, this->handshake, &sig)) { return FALSE; } writer->write_uint8(writer, 2); writer->write_uint8(writer, 1); writer->write_data16(writer, sig); free(sig.ptr); } else { if (!hash_handshake(this, &hash)) { return FALSE; } if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig)) { free(hash.ptr); return FALSE; } writer->write_data16(writer, sig); free(hash.ptr); free(sig.ptr); } return TRUE; } METHOD(tls_crypto_t, verify_handshake, bool, private_tls_crypto_t *this, public_key_t *key, tls_reader_t *reader) { if (this->tls->get_version(this->tls) >= TLS_1_2) { u_int8_t hash, alg; chunk_t sig; if (!reader->read_uint8(reader, &hash) || !reader->read_uint8(reader, &alg) || !reader->read_data16(reader, &sig)) { DBG1(DBG_IKE, "received invalid Certificate Verify"); return FALSE; } /* TODO: map received hash/sig alg to signature scheme */ if (hash != 2 || alg != 1 || !key->verify(key, SIGN_RSA_EMSA_PKCS1_SHA1, this->handshake, sig)) { return FALSE; } } else { chunk_t sig, hash; if (!reader->read_data16(reader, &sig)) { DBG1(DBG_IKE, "received invalid Certificate Verify"); return FALSE; } if (!hash_handshake(this, &hash)) { return FALSE; } if (!key->verify(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, sig)) { free(hash.ptr); return FALSE; } free(hash.ptr); } return TRUE; } METHOD(tls_crypto_t, calculate_finished, bool, private_tls_crypto_t *this, char *label, char out[12]) { chunk_t seed; if (!this->prf) { return FALSE; } if (!hash_handshake(this, &seed)) { return FALSE; } this->prf->get_bytes(this->prf, label, seed, 12, out); 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) { char master[48]; chunk_t seed, block, client_write, server_write; int mks, eks = 0, ivs = 0; /* 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) { 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); } } 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)) { this->signer_in->set_key(this->signer_in, client_write); this->signer_out->set_key(this->signer_out, server_write); } else { this->signer_out->set_key(this->signer_out, client_write); this->signer_in->set_key(this->signer_in, server_write); } /* crypter keys, and IVs if < TLSv1.2 */ if (this->crypter_out && this->crypter_in) { client_write = chunk_create(block.ptr, eks); block = chunk_skip(block, eks); server_write = chunk_create(block.ptr, eks); block = chunk_skip(block, eks); if (this->tls->is_server(this->tls)) { this->crypter_in->set_key(this->crypter_in, client_write); this->crypter_out->set_key(this->crypter_out, server_write); } else { this->crypter_out->set_key(this->crypter_out, client_write); this->crypter_in->set_key(this->crypter_in, server_write); } if (ivs) { client_write = chunk_create(block.ptr, ivs); block = chunk_skip(block, ivs); server_write = chunk_create(block.ptr, ivs); block = chunk_skip(block, ivs); if (this->tls->is_server(this->tls)) { this->iv_in = chunk_clone(client_write); this->iv_out = chunk_clone(server_write); } else { this->iv_out = chunk_clone(client_write); this->iv_in = chunk_clone(server_write); } } } } METHOD(tls_crypto_t, change_cipher, void, private_tls_crypto_t *this, bool inbound) { if (this->protection) { if (inbound) { this->protection->set_cipher(this->protection, TRUE, this->signer_in, this->crypter_in, this->iv_in); } else { this->protection->set_cipher(this->protection, FALSE, this->signer_out, this->crypter_out, this->iv_out); } } } METHOD(tls_crypto_t, derive_eap_msk, void, private_tls_crypto_t *this, chunk_t client_random, chunk_t server_random) { 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) { return this->msk; } 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); free(this->handshake.ptr); free(this->msk.ptr); DESTROY_IF(this->prf); free(this->suites); free(this); } /** * See header */ tls_crypto_t *tls_crypto_create(tls_t *tls) { private_tls_crypto_t *this; INIT(this, .public = { .get_cipher_suites = _get_cipher_suites, .select_cipher_suite = _select_cipher_suite, .set_protection = _set_protection, .append_handshake = _append_handshake, .sign_handshake = _sign_handshake, .verify_handshake = _verify_handshake, .calculate_finished = _calculate_finished, .derive_secrets = _derive_secrets, .change_cipher = _change_cipher, .derive_eap_msk = _derive_eap_msk, .get_eap_msk = _get_eap_msk, .destroy = _destroy, }, .tls = tls, ); switch (tls->get_purpose(tls)) { case TLS_PURPOSE_EAP_TLS: /* MSK PRF ASCII constant label according to EAP-TLS RFC 5216 */ this->msk_label = "client EAP encryption"; build_cipher_suite_list(this, FALSE); break; case TLS_PURPOSE_EAP_TTLS: /* MSK PRF ASCII constant label according to EAP-TTLS RFC 5281 */ this->msk_label = "ttls keying material"; build_cipher_suite_list(this, TRUE); break; } return &this->public; }