diff -r 000000000000 -r c8830336c852 eapol/eapol_framework/eapol_common/type/tls_peap/tls/src/tls_record.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eapol/eapol_framework/eapol_common/type/tls_peap/tls/src/tls_record.cpp Thu Dec 17 08:47:43 2009 +0200 @@ -0,0 +1,20190 @@ +/* +* Copyright (c) 2001-2006 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: EAP and WLAN authentication protocols. +* +*/ + + +// This is enumeration of EAPOL source code. +#if defined(USE_EAP_MINIMUM_RELEASE_TRACES) + #undef EAP_FILE_NUMBER_ENUM + #define EAP_FILE_NUMBER_ENUM 135 + #undef EAP_FILE_NUMBER_DATE + #define EAP_FILE_NUMBER_DATE 1127594498 +#endif //#if defined(USE_EAP_MINIMUM_RELEASE_TRACES) + + + +#include "eap_am_memory.h" +#include "eap_am_export.h" +#include "eap_am_tools.h" +#include "eap_tools.h" +#include "eap_crypto_api.h" +#include "abs_tls_base_record.h" +#include "tls_base_record.h" +#include "tls_record.h" +#include "tls_am_services.h" +#include "tls_handshake_header.h" +#include "tls_peap_types.h" +#include "tls_message.h" +#include "eap_automatic_variable.h" +#include "eap_state_notification.h" +#include "eap_type_tls_peap_types.h" +#include "eap_header_string.h" + +#if defined(USE_FAST_EAP_TYPE) + #include "eap_fast_tlv_payloads.h" +#endif //#if defined(USE_FAST_EAP_TYPE) + +#if defined(USE_EAP_TLS_SESSION_TICKET) +#include "tls_extension.h" +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + +//-------------------------------------------------- + +#define EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(tools, status) \ + EAP_STATUS_RETURN(tools, eap_status_return_and_create_tls_protocol_alert((status))) + + +eap_status_e tls_record_c::eap_status_return_and_create_tls_protocol_alert( + const eap_status_e status) +{ + if (status != eap_status_ok + && status != eap_status_success + && status != eap_status_pending_request + && status != eap_status_drop_packet_quietly) + { + (void) create_tls_protocol_alert(tls_alert_description_none, tls_alert_level_none, status); + } + + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT tls_record_c::~tls_record_c() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, + (EAPL("this = 0x%08x, %s: function: starts: tls_record_c::~tls_record_c(): m_am_tls_services") + EAPL(" = 0x%08x (validity %d).\n"), + this, + (m_is_client == true ? "client": "server"), + m_am_tls_services, + m_am_tls_services->get_is_valid())); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::~tls_record_c()"); + + EAP_ASSERT(m_shutdown_was_called == true); + + completion_action_clenup(); + + if (m_free_am_tls_services == true) + { + delete m_am_tls_services; + } + m_am_tls_services = 0; + + if (m_free_application == true) + { + delete m_application; + } + m_application = 0; + + reset_block_ciphers(true); + reset_block_ciphers(false); + + reset_stream_ciphers(true); + reset_stream_ciphers(false); + + reset_hmac_algorithms(true); + reset_hmac_algorithms(false); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +#if defined(_WIN32) && !defined(__GNUC__) + #pragma warning( disable : 4355 ) // 'this' : used in base member initializer list +#endif + +EAP_FUNC_EXPORT tls_record_c::tls_record_c( + abs_eap_am_tools_c * const tools, ///< tools is pointer to the tools class. @see abs_eap_am_tools_c. + tls_am_services_c * const am_tls_services, ///< This is pointer to adaptation module of TLS. + const bool free_am_tls_services, + tls_base_application_c * const application, ///< application is pointer to application object. + const bool free_application, + const bool is_client_when_true, ///< Indicates whether this is client (true) or server (false). + const eap_type_value_e eap_type, + const eap_am_network_id_c * const receive_network_id) + : tls_base_record_c(tools /*, partner */) + , m_am_tools(tools) + , m_am_tls_services(am_tls_services) + , m_free_am_tls_services(free_am_tls_services) + , m_application(application) + , m_free_application(free_application) + , m_completion_queue(tools) + , m_received_tls_message(tools, this, this, this, is_client_when_true) + , m_new_tls_message(tools, this, this, this, is_client_when_true) + , m_message_hash_md5(tools) + , m_message_hash_sha1(tools) + , m_message_hash_md5_certificate_verify(tools) + , m_message_hash_sha1_certificate_verify(tools) + , m_client_message_hash_md5_finished(tools) + , m_client_message_hash_sha1_finished(tools) + , m_server_message_hash_md5_finished(tools) + , m_server_message_hash_sha1_finished(tools) + , m_client_handshake_random_value(tools) + , m_server_handshake_random_value(tools) + , m_session_id(tools) + , m_master_secret(tools) + , m_eap_master_session_key(tools, eap_type) + , m_new_send_mac_key(tools) + , m_new_receive_mac_key(tools) + , m_new_send_encryption_key(tools) + , m_new_receive_encryption_key(tools) + , m_new_send_iv(tools) + , m_new_receive_iv(tools) + , m_send_mac_key(tools) + , m_receive_mac_key(tools) + , m_send_encryption_key(tools) + , m_receive_encryption_key(tools) + , m_send_iv(tools) + , m_receive_iv(tools) + , m_session_key_seed(tools) + , m_mschapv2_challenges(tools) + , m_own_private_dhe_key(tools) + , m_own_public_dhe_key(tools) + , m_peer_public_dhe_key(tools) + , m_shared_dh_key(tools) + , m_dhe_prime(tools) + , m_dhe_group_generator(tools) + , m_signed_message_hash(tools) + , m_premaster_secret(tools) + , m_own_encrypted_premaster_secret(tools) +#if defined(USE_FAST_EAP_TYPE) + , m_eap_fast_pac_key(tools) +#endif //#if defined(USE_FAST_EAP_TYPE) + , m_proposed_cipher_suites(tools) + , m_proposed_compression_methods(tools) +#if defined(USE_EAP_TLS_SESSION_TICKET) + , m_supported_tls_extensions(tools) + , m_received_tls_extensions(tools) +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + , m_NAI_realm(tools) + , m_send_network_id(tools) + , m_own_certificate_chain(tools) + , m_own_certificate_types(tools) + , m_own_certificate_authorities(tools) + , m_peer_certificate_chain(tools) + , m_peer_certificate_chain_result(eap_status_illegal_certificate) + , m_verify_signature(eap_status_authentication_failure) + , m_peer_certificate_types(tools) + , m_peer_certificate_authorities(tools) + , m_resumed_cipher_suite(tls_cipher_suites_none) + , m_selected_cipher_suite(tls_cipher_suites_none) + , m_selected_compression_method(tls_compression_method_none) + , m_receive_cipher_suite(tls_cipher_suites_TLS_NULL_WITH_NULL_NULL) + , m_receive_compression_method(tls_compression_method_null) + , m_send_cipher_suite(tls_cipher_suites_TLS_NULL_WITH_NULL_NULL) + , m_send_compression_method(tls_compression_method_null) + , m_send_block_cipher(0) + , m_receive_block_cipher(0) + , m_send_stream_cipher(0) + , m_receive_stream_cipher(0) + , m_send_hmac_algorithm(0) + , m_receive_hmac_algorithm(0) + , m_send_record_sequence_number(0ul) + , m_receive_record_sequence_number(0ul) + , m_tls_peap_state(tls_peap_state_wait_tls_start) + , m_tls_session_type(tls_session_type_none) + , m_eap_type(eap_type) + , m_peap_version(peap_version_none) + , m_tunneled_eap_type_authentication_state(eap_state_none) + , m_is_valid(false) + , m_is_client(is_client_when_true) + , m_allow_message_send(true) + , m_already_in_completion_action_check(false) + , m_already_in_process_tls_records(false) + , m_pending_query_certificate_authorities_and_types(false) + , m_pending_query_certificate_chain(false) + , m_pending_query_cipher_suites_and_previous_session(false) + , m_pending_query_dh_parameters(false) + , m_pending_query_realm(false) + , m_pending_select_cipher_suite_and_check_session_id(false) + , m_pending_verify_certificate_chain(false) + , m_pending_rsa_decrypt_with_private_key(false) + , m_pending_rsa_encrypt_with_public_key(false) + , m_pending_sign_with_private_key(false) + , m_pending_verify_with_public_key(false) + , m_pending_query_tunnel_PAC(false) + , m_tls_peap_test_version(false) + , m_key_material_generated(false) + , m_tls_peap_server_authenticates_client_policy_flag(true) + , m_tls_peap_server_authenticates_client_config_server(true) + , m_tls_peap_server_authenticates_client_action(true) + , m_tls_peap_server_requested_client_certificate(false) + , m_could_send_fatal_alert_message(true) + , m_could_send_warning_alert_message(true) + , m_force_tls_message_send(false) + , m_shutdown_was_called(false) + , m_use_separate_tls_record(true) // Some vendors seems to use only separate TLS-records. Windows RAS and FreeRadius works too with this. + , m_use_extra_padding_length(false) // It seems that EAP-TLS of Microsoft Windows does not work with extra padding. + , m_client_allows_empty_certificate_authorities_list(false) + , m_server_sends_empty_certificate_authorities_list(false) + , m_use_tppd_tls_peap(true) + , m_use_tppd_peapv1_acknowledge_hack(false) + , m_server_offers_new_session_id(true) + , m_will_receive_new_session_ticket(false) + , m_send_piggypacked_eap_identity_request(true) +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + , m_tls_use_identity_privacy(false) + , m_tls_identity_privacy_handshake_state(tls_identity_privacy_handshake_state_none) +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) +#if defined(USE_FAST_EAP_TYPE) + , m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP(false) + , m_remove_tunnel_pac(false) +#endif //#if defined(USE_FAST_EAP_TYPE) + { + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: function: starts: tls_record_c::tls_record_c(): "), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::tls_record_c()"); + + if (receive_network_id == 0 + || receive_network_id->get_is_valid_data() == false) + { + // No need to delete anything here because it is done in destructor. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return; + } + + if (m_am_tls_services == 0 + || m_am_tls_services->get_is_valid() == false) + { + EAP_TRACE_ERROR(m_am_tools, TRACE_FLAGS_TLS_PEAP_ERROR, + (EAPL("ERROR: %s: function: tls_record_c::tls_record_c() failed,") + EAPL(" m_am_tls_services = 0x%08x (validity %d) is invalid.\n"), + (m_is_client == true ? "client": "server"), + m_am_tls_services, (m_am_tls_services != 0) ? m_am_tls_services->get_is_valid() : false)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return; + } + m_am_tls_services->set_tls_am_partner(this); + + // Here we swap the addresses. + eap_am_network_id_c send_network_id( + m_am_tools, + receive_network_id->get_destination_id(), + receive_network_id->get_source_id(), + receive_network_id->get_type()); + + eap_status_e status = m_send_network_id.set_copy_of_network_id(&send_network_id); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return; + } + + if (get_is_tunneled_tls() == true + && m_application == 0) + { + // Application is required in tunneled mode. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return; + } + + if (m_application != 0) + { + m_application->set_application_partner(this); + } + + if (m_is_client == false) + { + set_state(tls_peap_state_wait_handshake_type_client_hello); + } + + set_is_valid(); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT void tls_record_c::reset_block_ciphers(const bool send_when_true) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (send_when_true == true) + { + delete m_send_block_cipher; + m_send_block_cipher = 0; + } + else + { + delete m_receive_block_cipher; + m_receive_block_cipher = 0; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT void tls_record_c::reset_stream_ciphers(const bool send_when_true) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (send_when_true == true) + { + delete m_send_stream_cipher; + m_send_stream_cipher = 0; + } + else + { + delete m_receive_stream_cipher; + m_receive_stream_cipher = 0; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT void tls_record_c::reset_hmac_algorithms(const bool send_when_true) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (send_when_true == true) + { + delete m_send_hmac_algorithm; + m_send_hmac_algorithm = 0; + } + else + { + delete m_receive_hmac_algorithm; + m_receive_hmac_algorithm = 0; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT void tls_record_c::set_state(const tls_peap_state_e state) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: state_function: starts: tls_record_c::set_state() from %s to %s\n"), + this, + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string(state))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::set_state()"); + + if (m_tls_peap_state != tls_peap_state_failure) + { + m_tls_peap_state = state; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT tls_peap_state_e tls_record_c::get_state() const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return m_tls_peap_state; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT bool tls_record_c::verify_state(const tls_peap_state_e state) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + bool are_equal = false; + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: state_function: starts: tls_record_c::verify_state(): (current state %s) %s (new state %s)\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + ((m_tls_peap_state == state) ? "==" : "!="), + eap_tls_trace_string_c::get_state_string(state))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::verify_state()"); + + if (m_tls_peap_state == state) + { + are_equal = true; + } + else + { + are_equal = false; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return are_equal; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT void tls_record_c::set_is_valid() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + m_is_valid = true; + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT bool tls_record_c::get_is_tunneled_tls() +{ + return ( + m_eap_type == eap_type_peap + || m_eap_type == eap_type_ttls +#if defined(USE_FAST_EAP_TYPE) + || m_eap_type == eap_type_fast +#endif //#if defined(USE_FAST_EAP_TYPE) + ); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT void tls_record_c::set_peap_version( + const peap_version_e peap_version, + const bool use_tppd_tls_peap, + const bool use_tppd_peapv1_acknowledge_hack) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + m_peap_version = peap_version; + + m_use_tppd_tls_peap = use_tppd_tls_peap; + + m_use_tppd_peapv1_acknowledge_hack = use_tppd_peapv1_acknowledge_hack; + + m_am_tls_services->set_peap_version( + peap_version, + use_tppd_tls_peap, + use_tppd_peapv1_acknowledge_hack); + + if (m_application != 0) + { + m_application->set_peap_version( + peap_version, + use_tppd_tls_peap, + use_tppd_peapv1_acknowledge_hack); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::configure() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: function: starts: tls_record_c::configure():\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::configure()"); + + eap_status_e status = m_am_tls_services->configure(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + //---------------------------------------------------------- + + { + eap_variable_data_c test_version(m_am_tools); + + status = get_type_partner()->read_configure( + cf_str_EAP_TLS_test_version.get_field(), + &test_version); + if (status == eap_status_ok + && test_version.get_is_valid_data() == true + && test_version.get_data_length() == sizeof(u32_t) + && test_version.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast(test_version.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_tls_peap_test_version = false; + } + else + { + m_tls_peap_test_version = true; + } + } + } + + status = eap_status_ok; + } + + //---------------------------------------------------------- + + { + eap_variable_data_c use_separate_tls_record(m_am_tools); + + status = get_type_partner()->read_configure( + cf_str_TLS_use_separate_tls_record.get_field(), + &use_separate_tls_record); + if (status == eap_status_ok + && use_separate_tls_record.get_is_valid_data() == true + && use_separate_tls_record.get_data_length() == sizeof(u32_t) + && use_separate_tls_record.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + use_separate_tls_record.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_use_separate_tls_record = false; + } + else + { + m_use_separate_tls_record = true; + } + } + } + + status = eap_status_ok; + } + + //---------------------------------------------------------- + + if (m_is_client == false) + { + eap_variable_data_c server_offers_new_session_id(m_am_tools); + + status = get_type_partner()->read_configure( + cf_str_TLS_server_offers_new_session_id.get_field(), + &server_offers_new_session_id); + if (status == eap_status_ok + && server_offers_new_session_id.get_is_valid_data() == true + && server_offers_new_session_id.get_data_length() == sizeof(u32_t) + && server_offers_new_session_id.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + server_offers_new_session_id.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_server_offers_new_session_id = false; + } + else + { + m_server_offers_new_session_id = true; + } + } + } + + status = eap_status_ok; + } + + //---------------------------------------------------------- + + if (get_is_tunneled_tls() == true) + { + // Default function in PEAP and TTLS is only client authenticates server. + m_tls_peap_server_authenticates_client_config_server = false; + } + + if (m_is_client == false) + { + eap_variable_data_c server_authenticates_client(m_am_tools); + + status = get_type_partner()->read_configure( + cf_str_TLS_server_authenticates_client.get_field(), + &server_authenticates_client); + if (status == eap_status_ok + && server_authenticates_client.get_is_valid_data() == true + && server_authenticates_client.get_data_length() == sizeof(u32_t) + && server_authenticates_client.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + server_authenticates_client.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_tls_peap_server_authenticates_client_config_server = false; + } + else + { + m_tls_peap_server_authenticates_client_config_server = true; + } + } + } + + if (m_tls_peap_server_authenticates_client_config_server == false) + { + m_tls_peap_server_authenticates_client_action = false; + } + + status = eap_status_ok; + } + + //---------------------------------------------------------- + + if (get_is_tunneled_tls() == true) + { + // Default function in PEAP and TTLS is only client authenticates server. + m_tls_peap_server_authenticates_client_policy_flag = false; + } + + if (m_is_client == true) + { + eap_variable_data_c server_authenticates_client(m_am_tools); + + status = get_type_partner()->read_configure( + cf_str_TLS_server_authenticates_client_policy_in_client.get_field(), + &server_authenticates_client); + if (status == eap_status_ok + && server_authenticates_client.get_is_valid_data() == true + && server_authenticates_client.get_data_length() == sizeof(u32_t) + && server_authenticates_client.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + server_authenticates_client.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_tls_peap_server_authenticates_client_policy_flag = false; + } + else + { + m_tls_peap_server_authenticates_client_policy_flag = true; + } + } + } + + status = eap_status_ok; + } + else + { + eap_variable_data_c server_authenticates_client(m_am_tools); + + status = get_type_partner()->read_configure( + cf_str_TLS_server_authenticates_client_policy_in_server.get_field(), + &server_authenticates_client); + if (status == eap_status_ok + && server_authenticates_client.get_is_valid_data() == true + && server_authenticates_client.get_data_length() == sizeof(u32_t) + && server_authenticates_client.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + server_authenticates_client.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_tls_peap_server_authenticates_client_policy_flag = false; + } + else + { + m_tls_peap_server_authenticates_client_policy_flag = true; + } + } + } + + status = eap_status_ok; + } + + //---------------------------------------------------------- + + if (m_is_client == true) + { + eap_variable_data_c client_allows_empty_certificate_authorities_list(m_am_tools); + + status = get_type_partner()->read_configure( + cf_str_TLS_client_allows_empty_certificate_authorities_list.get_field(), + &client_allows_empty_certificate_authorities_list); + if (status == eap_status_ok + && client_allows_empty_certificate_authorities_list.get_is_valid_data() == true + && client_allows_empty_certificate_authorities_list.get_data_length() == sizeof(u32_t) + && client_allows_empty_certificate_authorities_list.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + client_allows_empty_certificate_authorities_list.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_client_allows_empty_certificate_authorities_list = false; + } + else + { + m_client_allows_empty_certificate_authorities_list = true; + } + } + } + + status = eap_status_ok; + } + else + { + eap_variable_data_c server_sends_empty_certificate_authorities_list(m_am_tools); + + status = get_type_partner()->read_configure( + cf_str_TLS_server_sends_empty_certificate_authorities_list.get_field(), + &server_sends_empty_certificate_authorities_list); + if (status == eap_status_ok + && server_sends_empty_certificate_authorities_list.get_is_valid_data() == true + && server_sends_empty_certificate_authorities_list.get_data_length() == sizeof(u32_t) + && server_sends_empty_certificate_authorities_list.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + server_sends_empty_certificate_authorities_list.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_server_sends_empty_certificate_authorities_list = false; + } + else + { + m_server_sends_empty_certificate_authorities_list = true; + } + } + } + + status = eap_status_ok; + } + + //---------------------------------------------------------- + + if (m_is_client == false) + { + eap_variable_data_c send_piggypacked_eap_identity_request(m_am_tools); + + status = get_type_partner()->read_configure( + cf_str_EAP_FAST_send_piggypacked_eap_identity_request.get_field(), + &send_piggypacked_eap_identity_request); + if (status == eap_status_ok + && send_piggypacked_eap_identity_request.get_is_valid_data() == true + && send_piggypacked_eap_identity_request.get_data_length() == sizeof(u32_t) + && send_piggypacked_eap_identity_request.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + send_piggypacked_eap_identity_request.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_send_piggypacked_eap_identity_request = false; + } + else + { + m_send_piggypacked_eap_identity_request = true; + } + } + } + + status = eap_status_ok; + } + + //---------------------------------------------------------- + +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + + { + eap_variable_data_c tls_use_privacy(m_am_tools); + + status = get_type_partner()->read_configure( + cf_str_EAP_TLS_PEAP_use_identity_privacy.get_field(), + &tls_use_privacy); + if (status == eap_status_ok + && tls_use_privacy.get_is_valid_data() == true + && tls_use_privacy.get_data_length() == sizeof(u32_t) + && tls_use_privacy.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + tls_use_privacy.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_tls_use_identity_privacy = false; + } + else + { + m_tls_use_identity_privacy = true; + } + } + } + + status = eap_status_ok; + } + + if (m_is_client == false) + { + eap_variable_data_c tls_server_use_privacy(m_am_tools); + + status = get_type_partner()->read_configure( + cf_str_EAP_TLS_PEAP_use_identity_privacy_server.get_field(), + &tls_server_use_privacy); + if (status == eap_status_ok + && tls_server_use_privacy.get_is_valid_data() == true + && tls_server_use_privacy.get_data_length() == sizeof(u32_t) + && tls_server_use_privacy.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + tls_server_use_privacy.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_tls_use_identity_privacy = false; + } + else + { + m_tls_use_identity_privacy = true; + } + } + } + + status = eap_status_ok; + } + +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + + //---------------------------------------------------------- + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast) + { + // Client and server configuration. + { + eap_variable_data_c provisioning(m_am_tools); + + status = get_type_partner()->read_configure( + cf_str_EAP_FAST_allow_server_unauthenticated_provisioning_mode_ADHP.get_field(), + &provisioning); + if (status == eap_status_ok + && provisioning.get_is_valid_data() == true + && provisioning.get_data_length() == sizeof(u32_t) + && provisioning.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + provisioning.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP = false; + } + else + { + m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP = true; + } + } + } + + status = eap_status_ok; + } + + { + eap_variable_data_c allow_server_authenticated_provisioning_mode(m_am_tools); + + status = read_configure( + cf_str_EAP_FAST_allow_server_authenticated_provisioning_mode.get_field(), + &allow_server_authenticated_provisioning_mode); + if (status == eap_status_ok + && allow_server_authenticated_provisioning_mode.get_is_valid_data() == true + && allow_server_authenticated_provisioning_mode.get_data_length() == sizeof(u32_t) + && allow_server_authenticated_provisioning_mode.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast( + allow_server_authenticated_provisioning_mode.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_fast_allow_server_authenticated_provisioning_mode = false; + } + else + { + m_fast_allow_server_authenticated_provisioning_mode = true; + } + } + } + + status = eap_status_ok; + } + + } +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + + //---------------------------------------------------------- + + status = message_hash_init(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + //---------------------------------------------------------- + + if (m_application != 0) + { + status = m_application->configure(); + } + else + { + status = eap_status_ok; + } + + //---------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::shutdown() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: function: starts: tls_record_c::shutdown():\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::shutdown()"); + + if (m_shutdown_was_called == true) + { + // Shutdown function was called already. + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); + } + m_shutdown_was_called = true; + + if (m_tls_peap_state != tls_peap_state_tls_success) + { + set_state(tls_peap_state_failure); + } + + eap_status_e status = eap_status_ok; + + if (m_application != 0) + { + status = m_application->shutdown(); + } + + + if (m_pending_query_certificate_authorities_and_types == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: function: tls_record_c::shutdown(): calls cancel_query_certificate_authorities_and_types()\n"))); + + m_am_tls_services->cancel_query_certificate_authorities_and_types(); + m_pending_query_certificate_authorities_and_types = false; + } + + if (m_pending_query_certificate_chain == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: function: tls_record_c::shutdown(): calls cancel_query_certificate_chain()\n"))); + + m_am_tls_services->cancel_query_certificate_chain(); + m_pending_query_certificate_chain = false; + } + + if (m_pending_query_cipher_suites_and_previous_session == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: function: tls_record_c::shutdown(): calls cancel_query_cipher_suites_and_previous_session()\n"))); + + m_am_tls_services->cancel_query_cipher_suites_and_previous_session(); + m_pending_query_cipher_suites_and_previous_session = false; + } + + if (m_pending_query_dh_parameters == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: function: tls_record_c::shutdown(): calls cancel_query_dh_parameters()\n"))); + + m_am_tls_services->cancel_query_dh_parameters(); + m_pending_query_dh_parameters = false; + } + + if (m_pending_query_realm == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: function: tls_record_c::shutdown(): calls cancel_query_realm()\n"))); + + m_am_tls_services->cancel_query_realm(); + m_pending_query_realm = false; + } + + if (m_pending_select_cipher_suite_and_check_session_id == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: function: tls_record_c::shutdown(): calls cancel_select_cipher_suite_and_check_session_id()\n"))); + + m_am_tls_services->cancel_select_cipher_suite_and_check_session_id(); + m_pending_select_cipher_suite_and_check_session_id = false; + } + + if (m_pending_verify_certificate_chain == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: function: tls_record_c::shutdown(): calls cancel_verify_certificate_chain()\n"))); + + m_am_tls_services->cancel_verify_certificate_chain(); + m_pending_verify_certificate_chain = false; + } + + if (m_pending_rsa_decrypt_with_private_key == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: function: tls_record_c::shutdown(): calls cancel_rsa_decrypt_with_private_key()\n"))); + + m_am_tls_services->cancel_rsa_decrypt_with_private_key(); + m_pending_rsa_decrypt_with_private_key = false; + } + + if (m_pending_rsa_encrypt_with_public_key == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: function: tls_record_c::shutdown(): calls cancel_rsa_encrypt_with_public_key()\n"))); + + m_am_tls_services->cancel_rsa_encrypt_with_public_key(); + m_pending_rsa_encrypt_with_public_key = false; + } + + if (m_pending_sign_with_private_key == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: function: tls_record_c::shutdown(): calls cancel_sign_with_private_key()\n"))); + + m_am_tls_services->cancel_sign_with_private_key(); + m_pending_sign_with_private_key = false; + } + + if (m_pending_verify_with_public_key == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: function: tls_record_c::shutdown(): calls cancel_verify_with_public_key()\n"))); + + m_am_tls_services->cancel_verify_with_public_key(); + m_pending_verify_with_public_key = false; + } + + if (m_pending_query_tunnel_PAC == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: function: tls_record_c::shutdown(): calls cancel_query_tunnel_PAC()\n"))); + + if (m_application != 0) + { + m_application->cancel_query_tunnel_PAC(); + } + m_pending_query_tunnel_PAC = false; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::set_nai_realm( + const eap_variable_data_c * const NAI_realm) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = m_NAI_realm.set_copy_of_buffer(NAI_realm); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +void tls_record_c::send_error_notification(const eap_status_e error) +{ + // Notifies the lower level of an authentication error. + + eap_general_state_variable_e general_state_variable(eap_general_state_authentication_error); + + if (error == eap_status_user_cancel_authentication) + { + general_state_variable = eap_general_state_authentication_cancelled; + } + + eap_state_notification_c notification( + m_am_tools, + &m_send_network_id, + true, + eap_state_notification_eap, + eap_protocol_layer_general, + m_eap_type, + eap_state_none, + general_state_variable, + 0, + false); + + notification.set_authentication_error(error); + + get_type_partner()->state_notification(¬ification); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::completion_action_add( + tls_completion_action_e action) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: send_function: completion_action_add()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::completion_action_add()"); + + tls_completion_c *completion_action = new tls_completion_c( + m_am_tools, + action); + + if (completion_action == 0 + || completion_action->get_is_valid() == false) + { + delete completion_action; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + // add_object() will delete completion_action if operation fails. + eap_status_e status = m_completion_queue.add_object(completion_action, true); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: send_function: completion_action_add(): action %s\n"), + (m_is_client == true ? "client": "server"), + completion_action->get_completion_action_string())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::completion_action_clenup() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: send_function: starts: tls_record_c::completion_action_clenup()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::completion_action_clenup()"); + + eap_status_e final_status = eap_status_ok; + u32_t counter = 0ul; + + while(m_completion_queue.get_object_count() > 0ul) + { + tls_completion_c * const completion_action = m_completion_queue.get_object(0ul); + EAP_UNREFERENCED_PARAMETER(completion_action); // Not referenced without trace. + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: send_function: completion_action_clenup(): ") + EAPL("action[%u] %s not completed.\n"), + (m_is_client == true ? "client": "server"), + counter, + completion_action->get_completion_action_string())); + + final_status = m_completion_queue.remove_object(0ul); + if (final_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, final_status); + } + + ++counter; + + } // while() + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, final_status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::completion_action_check() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: send_function: starts: tls_record_c::completion_action_check()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::completion_action_check()"); + + if (m_already_in_completion_action_check == true) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + // This is recursive call of completion_action_check(). + // This MUST return eap_status_ok. Other return values will skip + // further prosessing of completion action list. + EAP_TRACE_DEBUG( + m_am_tools, TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: send_function: completion_action_check(): skip recursion\n"), + (m_is_client == true ? "client": "server"))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); + } + m_already_in_completion_action_check = true; + + eap_automatic_simple_value_c restore_already_in_completion_action_check( + m_am_tools, + &m_already_in_completion_action_check, + false); + + eap_status_e status = eap_status_ok; + bool continue_with_next_action = true; + u32_t counter = 0ul; + + while(continue_with_next_action == true + && m_completion_queue.get_object_count() > 0ul) + { + status = eap_status_ok; + + tls_completion_c * const completion_action = m_completion_queue.get_object(0ul); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: send_function: completion_action_check(): action[%d] %s\n"), + (m_is_client == true ? "client": "server"), + counter, + completion_action->get_completion_action_string())); + + switch(completion_action->get_completion_action()) + { +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + case tls_completion_action_create_handshake_type_hello_request: + { + // We must send Handshake/HelloRequest message. + eap_status_e status = create_handshake_type_hello_request(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + break; + } +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + case tls_completion_action_query_cipher_suites_and_previous_session: + { + m_allow_message_send = false; + + status = m_am_tls_services->query_cipher_suites_and_previous_session(); + + m_allow_message_send = true; + + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by + // complete_query_cipher_suites_and_previous_session() call. + m_pending_query_cipher_suites_and_previous_session = true; + + // Cannot complete yet. + continue_with_next_action = false; + } + + break; + } + case tls_completion_action_create_handshake_type_client_hello: + { + if (m_pending_query_cipher_suites_and_previous_session == false + && m_proposed_cipher_suites.get_object_count() > 0ul + && m_proposed_compression_methods.get_object_count() > 0ul) + { + // We must send Handshake/ClientHello message. + eap_status_e status = create_handshake_type_client_hello(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else + { + // Cannot complete yet. + continue_with_next_action = false; + } + break; + } + case tls_completion_action_create_handshake_type_server_hello: + { + if (m_pending_select_cipher_suite_and_check_session_id == false + && m_selected_cipher_suite != tls_cipher_suites_none + && m_selected_compression_method != tls_compression_method_none) + { + // We must send Handshake/ServerHello message. + eap_status_e status = create_handshake_type_server_hello( + static_cast(m_selected_cipher_suite), + static_cast(m_selected_compression_method)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else + { + // Cannot complete yet. + continue_with_next_action = false; + } + break; + } + case tls_completion_action_create_handshake_type_certificate: + { + if (m_pending_query_certificate_chain == false + && m_pending_verify_certificate_chain == false) + { + // We must send Handshake/Certificate message. + // NOTE m_own_certificate_chain could be empty. + status = create_handshake_type_certificate(&m_own_certificate_chain); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else + { + // Cannot complete yet. + continue_with_next_action = false; + } + break; + } + case tls_completion_action_create_handshake_type_server_key_exchange: + { + if (m_pending_query_dh_parameters == false) + { + if ((cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true +#if defined(USE_FAST_EAP_TYPE) + || (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + && m_dhe_prime.get_is_valid_data() == true + && m_dhe_group_generator.get_is_valid_data() == true) + { + status = generate_dhe_keys(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + // We must send Handshake/ServerKeyExchange. + status = create_handshake_type_server_key_exchange(); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by + // complete_create_handshake_type_server_key_exchange() call. + } + else if (status == eap_status_completed_request) + { + // This is already completed by + // complete_create_handshake_type_server_key_exchange() call. + status = eap_status_ok; + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call + // is always completed on success. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_process_general_error); + } + else // All other status values means error, because this + // call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else + { + // Cannot complete yet. + continue_with_next_action = false; + } + } + else + { + // Cannot complete yet. + continue_with_next_action = false; + } + break; + } + case tls_completion_action_create_handshake_type_certificate_request: + { + if (m_pending_query_certificate_authorities_and_types == false + && m_own_certificate_types.get_object_count() != 0ul + && (m_own_certificate_authorities.get_object_count() != 0ul + || m_server_sends_empty_certificate_authorities_list == false)) + { + // We must send Handshake/CertificateRequest message. + status = create_handshake_type_certificate_request( + &m_own_certificate_types, + &m_own_certificate_authorities); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else + { + // Cannot complete yet. + continue_with_next_action = false; + } + break; + } + case tls_completion_action_create_handshake_type_server_hello_done: + { + status = create_handshake_type_server_hello_done(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + break; + } + case tls_completion_action_create_handshake_type_certificate_verify: + { + if (m_pending_query_certificate_chain == false + && m_pending_verify_certificate_chain == false + && m_own_certificate_chain.get_object_count() > 0ul) + { + // We must send Handshake/CertificateVerify. + status = create_handshake_type_certificate_verify(); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by + // complete_create_handshake_type_certificate_verify() call. + } + else if (status == eap_status_completed_request) + { + // This is already completed by + // complete_create_handshake_type_certificate_verify() call. + status = eap_status_ok; + } + else if (status == eap_status_ok) + { + // This is also an error case, because this + // call is always completed on success. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_process_general_error); + } + else // All other status values means error, because this + // call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else if (m_pending_query_certificate_chain == false + && m_pending_verify_certificate_chain == false + && m_own_certificate_chain.get_object_count() == 0ul) + { + // No user certificate. + } + else + { + // Cannot complete yet. + continue_with_next_action = false; + } + break; + } + case tls_completion_action_create_handshake_type_client_key_exchange: + { + if (m_pending_query_certificate_chain == false + && m_pending_verify_certificate_chain == false) + { + if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true +#if defined(USE_FAST_EAP_TYPE) + || (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + // DHE parameters should have been received in ServerKeyExchange message. + + if (m_dhe_prime.get_is_valid_data() == true + && m_dhe_group_generator.get_is_valid_data() == true) + { + status = generate_dhe_keys(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + status); + } + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_authentication_failure); + } + } + else if (cipher_suite_is_TLS_RSA() == true) + { + // Do nothing special. + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_not_supported); + } + + // We must generate premaster secret. + status = generate_premaster_secret(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + // We must generate master secret. + status = generate_master_secret(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + // We must generate the key material. + status = generate_key_material(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + // We must send Handshake/ClientKeyExchange. + status = create_handshake_type_client_key_exchange(); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by + // complete_create_handshake_type_client_key_exchange() call. + // Cannot complete yet. + continue_with_next_action = false; + } + else if (status == eap_status_completed_request) + { + // This is already completed by + // complete_create_handshake_type_client_key_exchange() call. + status = eap_status_ok; + } + else if (status == eap_status_ok) + { + // NOTE: This is not always an error case. + if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true +#if defined(USE_FAST_EAP_TYPE) + || (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + // Cipher suites cipher_suite_is_TLS_DHE_DSS() + // and cipher_suite_is_TLS_DHE_RSA() are syncronous. + // Do nothing special. + } + else if (cipher_suite_is_TLS_RSA() == true) + { + // Cipher suites cipher_suite_is_TLS_RSA() are asyncronous + // and they must NOT return eap_status_ok. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_process_general_error); + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_not_supported); + } + } + else // All other status values means error, because this + // call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else + { + // Cannot complete yet. + continue_with_next_action = false; + } + break; + } + case tls_completion_action_create_handshake_type_finished: + { + // We must send Handshake/Finished. + status = create_handshake_type_finished(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + break; + } + case tls_completion_action_finish_handshake: + { + // We must finish the handshake. + status = finish_handshake(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + break; + } + case tls_completion_action_create_change_cipher_spec_type_change_cipher_spec: + { + // We must send ChangeCipherSpec/ChangeCipherSpec. + status = create_change_cipher_spec_type_change_cipher_spec(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + break; + } +#if defined(USE_EAP_TLS_SESSION_TICKET) + case tls_completion_action_create_handshake_type_new_session_ticket: + { + // We must send Hanshake/NewSessionTicket. + status = create_handshake_type_new_session_ticket(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + break; + } +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + case tls_completion_action_query_dh_parameters: + { + if (m_selected_cipher_suite != tls_cipher_suites_none) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: query_dh_parameters()\n"), + (m_is_client == true ? "client": "server"))); + // Note, server does not query DH parametrs from certificate chain, + // instead server should consult it's configuration settings. + status = m_am_tls_services->query_dh_parameters(0, m_selected_cipher_suite); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed + // by complete_query_dh_parameters() call. + m_pending_query_dh_parameters = true; + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_query_dh_parameters() call. + status = eap_status_ok; + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call + // is always completed on success. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_process_general_error); + } + else // All other status values means error, because this + // call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else + { + // Cannot complete yet. + continue_with_next_action = false; + } + break; + } + case tls_completion_action_process_tls_records: + { + if (are_pending_queries_completed() == eap_status_ok) + { + status = process_tls_records(); + if (status == eap_status_ok) + { + // All pending messages processed. + // Do nothing special. + } + else if (status == eap_status_end_recursion) + { + // Break recursion. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, eap_status_ok); + } + else if (status == eap_status_pending_request) + { + // Cannot complete yet. + continue_with_next_action = false; + } + else + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + if ((get_is_tunneled_tls() == false + && m_tls_peap_state == tls_peap_state_tls_success) + || (get_is_tunneled_tls() == true + && m_tls_peap_state == tls_peap_state_peap_tunnel_ready)) + { + // TLS authentication OK. + // Note PEAP may continue. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: process_tls_records() returned, ") + EAPL("TLS authentication successfull.\n"), + (m_is_client == true ? "client": "server"))); + } + } + else + { + // Cannot complete yet. + continue_with_next_action = false; + } + break; + } + case tls_completion_action_complete_create_handshake_type_server_key_exchange: + { + if (m_signed_message_hash.get_is_valid_data() == true +#if defined(USE_FAST_EAP_TYPE) + || (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + status = complete_create_handshake_type_server_key_exchange(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else + { + // Cannot complete yet. + continue_with_next_action = false; + } + break; + } + case tls_completion_action_complete_create_handshake_type_certificate_verify: + { + if (m_signed_message_hash.get_is_valid_data() == true + && m_own_certificate_chain.get_object_count() > 0ul) + { + status = complete_create_handshake_type_certificate_verify(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else if (m_own_certificate_chain.get_object_count() == 0ul) + { + // No user certificate. + } + else + { + // Cannot complete yet. + continue_with_next_action = false; + } + break; + } + case tls_completion_action_complete_create_handshake_type_client_key_exchange: + { + if (cipher_suite_is_TLS_RSA() == true + && m_own_encrypted_premaster_secret.get_is_valid_data() == true + || ((cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true +#if defined(USE_FAST_EAP_TYPE) + || (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + && m_own_encrypted_premaster_secret.get_is_valid_data() == false)) + { + status = complete_create_handshake_type_client_key_exchange(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else + { + // Cannot complete yet. + continue_with_next_action = false; + } + break; + } + case tls_completion_action_verify_certificate_chain: + { + if (m_peer_certificate_chain.get_object_count() != 0ul + && m_selected_cipher_suite != tls_cipher_suites_none + && m_pending_query_certificate_chain == false + && m_pending_verify_certificate_chain == false) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: verify_certificate_chain()\n"), + (m_is_client == true ? "client": "server"))); + + status = m_am_tls_services->verify_certificate_chain( + &m_peer_certificate_chain, + m_selected_cipher_suite); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed + // by complete_verify_certificate_chain() call. + m_pending_verify_certificate_chain = true; + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_verify_certificate_chain() call. + status = eap_status_ok; + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call is + // always completed on success. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_process_general_error); + } + else // All other status values means error, because this + // call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else + { + // Cannot complete yet. + continue_with_next_action = false; + } + break; + } + case tls_completion_action_check_sent_tls_message: + { + // Note this call will return eap_status_pending_request if any asyncronous call is pending. + status = check_sent_tls_message(); + break; + } + case tls_completion_action_check_tunnel_authentication_runs: + { + // Check we get some tunneled authentication message and tunneled authentication runs or it did finished. + if (m_tunneled_eap_type_authentication_state == eap_state_none) + { + // Here we swap the addresses. + eap_am_network_id_c receive_network_id(m_am_tools, + m_send_network_id.get_destination_id(), + m_send_network_id.get_source_id(), + m_send_network_id.get_type()); + + status = start_peap_tunneled_authentication( + &receive_network_id, + m_received_eap_identifier, + m_tls_session_type); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + break; + } + default: + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR TLS: %s: send_function: completion_action_check(): ") + EAPL("unhandled action[%u] %s.\n"), + (m_is_client == true ? "client": "server"), + counter, + completion_action->get_completion_action_string())); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_not_supported); + } + } // switch() + + if (continue_with_next_action == true + || status == eap_status_pending_request) + { + const tls_completion_c * const removed_completion_action = m_completion_queue.get_object(0ul); + EAP_UNREFERENCED_PARAMETER(removed_completion_action); // Not referenced without trace. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: encrypt_function: starts: tls_record_c::completion_action_check(): removes action[%d] %s\n"), + (m_is_client == true ? "client": "server"), + 0ul, + removed_completion_action->get_completion_action_string())); + + eap_status_e remove_status = m_completion_queue.remove_object(0ul); + if (remove_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + + ++counter; + + } // while() + + if (continue_with_next_action == false) + { + status = eap_status_pending_request; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT u8_t tls_record_c::get_extra_padding_length( + const u8_t padding_length, + const u32_t block_size) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: encrypt_function: starts: tls_record_c::get_extra_padding_length()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::get_extra_padding_length()"); + + crypto_random_c rand(m_am_tools); + + u8_t count = 0ul; + + if (m_use_extra_padding_length == true) + { + eap_status_e status = rand.get_rand_bytes(&count, sizeof(count)); + if (status != eap_status_ok) + { + count = 3ul; + } + } + + u32_t final_padding_length = ((count * block_size) % 0xff) + padding_length; + + count = static_cast((final_padding_length-padding_length) / block_size); + + while (count > 0ul + && (count * block_size)+padding_length > 0xff) + { + --count; + } + + const u8_t final_length = static_cast((count * block_size)+padding_length); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: encrypt_function: get_extra_padding_length(): length = %d = 0x%02x\n"), + (m_is_client == true ? "client": "server"), + final_length, + final_length)); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return final_length; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::apply_send_block_cipher_suite( + eap_variable_data_c * const tls_record_message_buffer, + abs_crypto_cbc_block_algorithm_c * const encrypt, + abs_crypto_hmac_algorithm_c * const mac) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: send_function: starts: tls_record_c::apply_send_block_cipher_suite(): %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_cipher_suite_string(m_send_cipher_suite))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::apply_send_block_cipher_suite()"); + + eap_status_e status = eap_status_process_general_error; + + tls_record_header_c tmp_tls_record_header_on_tls_message_buffer( + m_am_tools, + tls_record_message_buffer->get_data(tls_record_header_c::get_header_length()), + tls_record_message_buffer->get_data_length()); + + if (tmp_tls_record_header_on_tls_message_buffer.get_is_valid() == false + || tls_record_message_buffer->get_data_length() + < tmp_tls_record_header_on_tls_message_buffer.get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("m_send_mac_key"), + m_send_mac_key.get_data(m_send_mac_key.get_data_length()), + m_send_mac_key.get_data_length())); + + status = mac->hmac_set_key(&m_send_mac_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + if (mac->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_key_error); + } + + u64_t send_record_sequence_number_network_order = eap_htonll(m_send_record_sequence_number); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("send_record_sequence_number_network_order"), + &send_record_sequence_number_network_order, + sizeof(send_record_sequence_number_network_order))); + + status = mac->hmac_update( + &send_record_sequence_number_network_order, + sizeof(send_record_sequence_number_network_order)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("verified record"), + tls_record_message_buffer->get_data(tls_record_message_buffer->get_data_length()), + tls_record_message_buffer->get_data_length())); + + status = mac->hmac_update( + tls_record_message_buffer->get_data(tls_record_message_buffer->get_data_length()), + tls_record_message_buffer->get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + eap_variable_data_c mac_data(m_am_tools); + + status = mac_data.set_buffer_length(mac->get_digest_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + mac_data.set_data_length(mac->get_digest_length()); + + u32_t mac_length = mac->get_digest_length(); + + status = mac->hmac_final( + mac_data.get_data(mac_data.get_data_length()), + &mac_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (mac_length != mac->get_digest_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("send MAC"), + mac_data.get_data(mac_data.get_data_length()), + mac_data.get_data_length())); + + status = tls_record_message_buffer->add_data(&mac_data); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // We must get the address of the record header again. A new buffer may be allocated. + tmp_tls_record_header_on_tls_message_buffer.set_header_buffer( + tls_record_message_buffer->get_data(tls_record_header_c::get_header_length()), + tls_record_message_buffer->get_data_length()); + + if (tmp_tls_record_header_on_tls_message_buffer.get_is_valid() == false + || tls_record_message_buffer->get_data_length() + < tmp_tls_record_header_on_tls_message_buffer.get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + tmp_tls_record_header_on_tls_message_buffer.set_data_length( + static_cast( + tmp_tls_record_header_on_tls_message_buffer.get_data_length() + + mac->get_digest_length())); + + + u32_t padded_data_length = encrypt->aligned_data_length( + tmp_tls_record_header_on_tls_message_buffer.get_data_length()); + u8_t padding_length = static_cast( + padded_data_length-tmp_tls_record_header_on_tls_message_buffer.get_data_length()); + + padding_length = get_extra_padding_length(padding_length, encrypt->get_block_size()); + + eap_variable_data_c padding(m_am_tools); + status = padding.set_buffer_length(padding_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + padding.set_data_length(padding_length); + + status = encrypt->add_padding_bytes( + padding.get_data(padding.get_data_length()), + padding.get_data_length(), + static_cast(padding_length-1ul)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_record_message_buffer->add_data(&padding); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // We must get the address of the record header again. A new buffer may be allocated. + tmp_tls_record_header_on_tls_message_buffer.set_header_buffer( + tls_record_message_buffer->get_data(tls_record_header_c::get_header_length()), + tls_record_message_buffer->get_data_length()); + + if (tmp_tls_record_header_on_tls_message_buffer.get_is_valid() == false + || tls_record_message_buffer->get_data_length() + < tmp_tls_record_header_on_tls_message_buffer.get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + tmp_tls_record_header_on_tls_message_buffer.set_data_length( + static_cast( + tmp_tls_record_header_on_tls_message_buffer.get_data_length() + + padding_length)); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("plain text record"), + tls_record_message_buffer->get_data(tls_record_message_buffer->get_data_length()), + tls_record_message_buffer->get_data_length())); + + status = encrypt->encrypt_data( + tmp_tls_record_header_on_tls_message_buffer.get_data( + tmp_tls_record_header_on_tls_message_buffer.get_data_length()), + tmp_tls_record_header_on_tls_message_buffer.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("encrypted record"), + tls_record_message_buffer->get_data(tls_record_message_buffer->get_data_length()), + tls_record_message_buffer->get_data_length())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::apply_receive_block_cipher_suite( + eap_variable_data_c * const tls_record_message_buffer, + abs_crypto_cbc_block_algorithm_c * const encrypt, + abs_crypto_hmac_algorithm_c * const mac) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: starts: tls_record_c::apply_receive_block_cipher_suite(): %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_cipher_suite_string(m_receive_cipher_suite))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::apply_receive_block_cipher_suite()"); + + eap_status_e status = eap_status_process_general_error; + + tls_record_header_c tmp_tls_record_header_on_tls_message_buffer( + m_am_tools, + tls_record_message_buffer->get_data(tls_record_header_c::get_header_length()), + tls_record_message_buffer->get_data_length()); + + if (tmp_tls_record_header_on_tls_message_buffer.get_is_valid() == false + || tls_record_message_buffer->get_data_length() + < tmp_tls_record_header_on_tls_message_buffer.get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("encrypted record"), + tls_record_message_buffer->get_data(tls_record_message_buffer->get_data_length()), + tls_record_message_buffer->get_data_length())); + + status = encrypt->decrypt_data( + tmp_tls_record_header_on_tls_message_buffer.get_data( + tmp_tls_record_header_on_tls_message_buffer.get_data_length()), + tmp_tls_record_header_on_tls_message_buffer.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("plain text record"), + tls_record_message_buffer->get_data(tls_record_message_buffer->get_data_length()), + tls_record_message_buffer->get_data_length())); + + // We must get the address of the record header again. A new buffer may be allocated. + tmp_tls_record_header_on_tls_message_buffer.set_header_buffer( + tls_record_message_buffer->get_data(tls_record_header_c::get_header_length()), + tls_record_message_buffer->get_data_length()); + + if (tmp_tls_record_header_on_tls_message_buffer.get_is_valid() == false + || tls_record_message_buffer->get_data_length() + < tmp_tls_record_header_on_tls_message_buffer.get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u32_t padding_length_offset + = tmp_tls_record_header_on_tls_message_buffer.get_data_length() - 1ul; + const u8_t * const p_padding_length + = tmp_tls_record_header_on_tls_message_buffer.get_data_offset(padding_length_offset, + TLS_PADDINF_LENGTH_FIELD_SIZE); + + if (p_padding_length == 0 + || (*p_padding_length)+1ul > tmp_tls_record_header_on_tls_message_buffer.get_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_padding); + } + + u32_t padding_length = (*p_padding_length) + 1ul; + + const u8_t * const p_padding + = tmp_tls_record_header_on_tls_message_buffer.get_data_offset( + tmp_tls_record_header_on_tls_message_buffer.get_data_length() - padding_length, + padding_length); + if (p_padding == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_padding); + } + + eap_status_e padding_status = encrypt->check_padding_bytes( + p_padding, + *p_padding_length, + *p_padding_length); + if (padding_status != eap_status_ok) + { + // NOTE, padding_status is checked in the end of this function. + // HMAC is checked always. + // We set the padding length to zero, so the end of the message is used as a MAC. + // This will fail anyway. + // This will make some timing attacks more difficult. + padding_length = 0ul; + } + + + + tmp_tls_record_header_on_tls_message_buffer.set_data_length( + static_cast( + tmp_tls_record_header_on_tls_message_buffer.get_data_length() - padding_length)); + + tls_record_message_buffer->set_data_length( + tls_record_message_buffer->get_data_length() + - padding_length); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + // HMAC-XXX authentication. + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("m_receive_mac_key"), + m_receive_mac_key.get_data(m_receive_mac_key.get_data_length()), + m_receive_mac_key.get_data_length())); + + status = mac->hmac_set_key(&m_receive_mac_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + if (mac->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_key_error); + } + + if (tls_record_message_buffer->get_data_length() + < (tmp_tls_record_header_on_tls_message_buffer.get_data_length() + + tmp_tls_record_header_on_tls_message_buffer.get_header_length())) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + if (tmp_tls_record_header_on_tls_message_buffer.get_data_length() < mac->get_digest_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u32_t start_offset_of_mac + = tmp_tls_record_header_on_tls_message_buffer.get_data_length() + - mac->get_digest_length(); + + const u8_t * const received_mac + = tmp_tls_record_header_on_tls_message_buffer.get_data_offset( + start_offset_of_mac, + mac->get_digest_length()); + if (received_mac == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("received MAC"), + received_mac, + mac->get_digest_length())); + + tmp_tls_record_header_on_tls_message_buffer.set_data_length( + static_cast(tmp_tls_record_header_on_tls_message_buffer.get_data_length() + - mac->get_digest_length())); + + u64_t receive_record_sequence_number_network_order + = eap_htonll(m_receive_record_sequence_number); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("receive_record_sequence_number_network_order"), + &receive_record_sequence_number_network_order, + sizeof(receive_record_sequence_number_network_order))); + + status = mac->hmac_update( + &receive_record_sequence_number_network_order, + sizeof(receive_record_sequence_number_network_order)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("verified record"), + tmp_tls_record_header_on_tls_message_buffer.get_header_buffer( + tmp_tls_record_header_on_tls_message_buffer.get_header_length() + + tmp_tls_record_header_on_tls_message_buffer.get_data_length()), + tmp_tls_record_header_on_tls_message_buffer.get_header_length() + + tmp_tls_record_header_on_tls_message_buffer.get_data_length())); + + status = mac->hmac_update( + tmp_tls_record_header_on_tls_message_buffer.get_header_buffer( + tmp_tls_record_header_on_tls_message_buffer.get_header_length() + + tmp_tls_record_header_on_tls_message_buffer.get_data_length()), + tmp_tls_record_header_on_tls_message_buffer.get_header_length() + + tmp_tls_record_header_on_tls_message_buffer.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + eap_variable_data_c mac_data(m_am_tools); + + status = mac_data.set_buffer_length(mac->get_digest_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + mac_data.set_data_length(mac->get_digest_length()); + + u32_t mac_length = mac->get_digest_length(); + + status = mac->hmac_final( + mac_data.get_data(mac_data.get_data_length()), + &mac_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (mac_length != mac->get_digest_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("verify MAC"), + mac_data.get_data(mac_data.get_data_length()), + mac_data.get_data_length())); + + if (padding_status != eap_status_ok) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: ERROR: %s: receive_function: apply_receive_cipher_suite(): ") + EAPL("padding failed\n"), + (m_is_client == true ? "client": "server"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, padding_status); + } + else if (m_am_tools->memcmp( + mac_data.get_data(mac_data.get_data_length()), + received_mac, + mac_data.get_data_length()) != 0) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: ERROR: %s: receive_function: apply_receive_cipher_suite(): MAC failed\n"), + (m_is_client == true ? "client": "server"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_authentication_failure); + } + else + { + EAP_TRACE_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: apply_receive_cipher_suite(): MAC OK\n"), + (m_is_client == true ? "client": "server"))); + } + + tls_record_message_buffer->set_data_length( + tls_record_message_buffer->get_data_length() + - mac->get_digest_length()); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::apply_send_stream_cipher_suite( + eap_variable_data_c * const tls_record_message_buffer, + abs_crypto_stream_algorithm_c * const encrypt, + abs_crypto_hmac_algorithm_c * const mac) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: send_function: starts: tls_record_c::apply_send_stream_cipher_suite(): %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_cipher_suite_string(m_send_cipher_suite))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::apply_send_stream_cipher_suite()"); + + eap_status_e status = eap_status_process_general_error; + + tls_record_header_c tmp_tls_record_header_on_tls_message_buffer( + m_am_tools, + tls_record_message_buffer->get_data(tls_record_header_c::get_header_length()), + tls_record_message_buffer->get_data_length()); + + if (tmp_tls_record_header_on_tls_message_buffer.get_is_valid() == false + || tls_record_message_buffer->get_data_length() + < tmp_tls_record_header_on_tls_message_buffer.get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("m_send_mac_key"), + m_send_mac_key.get_data(m_send_mac_key.get_data_length()), + m_send_mac_key.get_data_length())); + + status = mac->hmac_set_key(&m_send_mac_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + if (mac->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_key_error); + } + + u64_t send_record_sequence_number_network_order = eap_htonll(m_send_record_sequence_number); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("send_record_sequence_number_network_order"), + &send_record_sequence_number_network_order, + sizeof(send_record_sequence_number_network_order))); + + status = mac->hmac_update( + &send_record_sequence_number_network_order, + sizeof(send_record_sequence_number_network_order)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("verified record"), + tls_record_message_buffer->get_data(tls_record_message_buffer->get_data_length()), + tls_record_message_buffer->get_data_length())); + + status = mac->hmac_update( + tls_record_message_buffer->get_data(tls_record_message_buffer->get_data_length()), + tls_record_message_buffer->get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + eap_variable_data_c mac_data(m_am_tools); + + status = mac_data.set_buffer_length(mac->get_digest_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + mac_data.set_data_length(mac->get_digest_length()); + + u32_t mac_length = mac->get_digest_length(); + + status = mac->hmac_final( + mac_data.get_data(mac_data.get_data_length()), + &mac_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (mac_length != mac->get_digest_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("send MAC"), + mac_data.get_data(mac_data.get_data_length()), + mac_data.get_data_length())); + + status = tls_record_message_buffer->add_data(&mac_data); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // We must get the address of the record header again. A new buffer may be allocated. + tmp_tls_record_header_on_tls_message_buffer.set_header_buffer( + tls_record_message_buffer->get_data(tls_record_header_c::get_header_length()), + tls_record_message_buffer->get_data_length()); + + if (tmp_tls_record_header_on_tls_message_buffer.get_is_valid() == false + || tls_record_message_buffer->get_data_length() + < tmp_tls_record_header_on_tls_message_buffer.get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + tmp_tls_record_header_on_tls_message_buffer.set_data_length( + static_cast( + tmp_tls_record_header_on_tls_message_buffer.get_data_length() + + mac->get_digest_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("plain text record"), + tls_record_message_buffer->get_data(tls_record_message_buffer->get_data_length()), + tls_record_message_buffer->get_data_length())); + + status = encrypt->encrypt_data( + tmp_tls_record_header_on_tls_message_buffer.get_data( + tmp_tls_record_header_on_tls_message_buffer.get_data_length()), + tmp_tls_record_header_on_tls_message_buffer.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("encrypted record"), + tls_record_message_buffer->get_data(tls_record_message_buffer->get_data_length()), + tls_record_message_buffer->get_data_length())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::apply_receive_stream_cipher_suite( + eap_variable_data_c * const tls_record_message_buffer, + abs_crypto_stream_algorithm_c * const encrypt, + abs_crypto_hmac_algorithm_c * const mac) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: starts: tls_record_c::apply_receive_block_cipher_suite(): %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_cipher_suite_string(m_receive_cipher_suite))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::apply_receive_stream_cipher_suite()"); + + eap_status_e status = eap_status_process_general_error; + + tls_record_header_c tmp_tls_record_header_on_tls_message_buffer( + m_am_tools, + tls_record_message_buffer->get_data(tls_record_header_c::get_header_length()), + tls_record_message_buffer->get_data_length()); + + if (tmp_tls_record_header_on_tls_message_buffer.get_is_valid() == false + || tls_record_message_buffer->get_data_length() + < tmp_tls_record_header_on_tls_message_buffer.get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("encrypted record"), + tls_record_message_buffer->get_data(tls_record_message_buffer->get_data_length()), + tls_record_message_buffer->get_data_length())); + + status = encrypt->decrypt_data( + tmp_tls_record_header_on_tls_message_buffer.get_data( + tmp_tls_record_header_on_tls_message_buffer.get_data_length()), + tmp_tls_record_header_on_tls_message_buffer.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("plain text record"), + tls_record_message_buffer->get_data(tls_record_message_buffer->get_data_length()), + tls_record_message_buffer->get_data_length())); + + tls_record_message_buffer->set_data_length( + tls_record_message_buffer->get_data_length()); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + // HMAC-SHA1 authentication. + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("m_receive_mac_key"), + m_receive_mac_key.get_data(m_receive_mac_key.get_data_length()), + m_receive_mac_key.get_data_length())); + + status = mac->hmac_set_key(&m_receive_mac_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + if (mac->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_key_error); + } + + if (tls_record_message_buffer->get_data_length() + < (tmp_tls_record_header_on_tls_message_buffer.get_data_length() + + tmp_tls_record_header_on_tls_message_buffer.get_header_length())) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + if (tmp_tls_record_header_on_tls_message_buffer.get_data_length() < mac->get_digest_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u32_t start_offset_of_mac + = tmp_tls_record_header_on_tls_message_buffer.get_data_length() + - mac->get_digest_length(); + + const u8_t * const received_mac + = tmp_tls_record_header_on_tls_message_buffer.get_data_offset( + start_offset_of_mac, + mac->get_digest_length()); + if (received_mac == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("received MAC"), + received_mac, + mac->get_digest_length())); + + tmp_tls_record_header_on_tls_message_buffer.set_data_length( + static_cast(tmp_tls_record_header_on_tls_message_buffer.get_data_length() + - mac->get_digest_length())); + + u64_t receive_record_sequence_number_network_order + = eap_htonll(m_receive_record_sequence_number); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("receive_record_sequence_number_network_order"), + &receive_record_sequence_number_network_order, + sizeof(receive_record_sequence_number_network_order))); + + status = mac->hmac_update( + &receive_record_sequence_number_network_order, + sizeof(receive_record_sequence_number_network_order)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("verified record"), + tmp_tls_record_header_on_tls_message_buffer.get_header_buffer( + tmp_tls_record_header_on_tls_message_buffer.get_header_length() + + tmp_tls_record_header_on_tls_message_buffer.get_data_length()), + tmp_tls_record_header_on_tls_message_buffer.get_header_length() + + tmp_tls_record_header_on_tls_message_buffer.get_data_length())); + + status = mac->hmac_update( + tmp_tls_record_header_on_tls_message_buffer.get_header_buffer( + tmp_tls_record_header_on_tls_message_buffer.get_header_length() + + tmp_tls_record_header_on_tls_message_buffer.get_data_length()), + tmp_tls_record_header_on_tls_message_buffer.get_header_length() + + tmp_tls_record_header_on_tls_message_buffer.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + eap_variable_data_c mac_data(m_am_tools); + + status = mac_data.set_buffer_length(mac->get_digest_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + mac_data.set_data_length(mac->get_digest_length()); + + u32_t mac_length = mac->get_digest_length(); + + status = mac->hmac_final( + mac_data.get_data(mac_data.get_data_length()), + &mac_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (mac_length != mac->get_digest_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("verify MAC"), + mac_data.get_data(mac_data.get_data_length()), + mac_data.get_data_length())); + + if (m_am_tools->memcmp( + mac_data.get_data(mac_data.get_data_length()), + received_mac, mac_data.get_data_length()) != 0) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: apply_receive_cipher_suite(): MAC failed\n"), + (m_is_client == true ? "client": "server"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_authentication_failure); + } + else + { + EAP_TRACE_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: apply_receive_cipher_suite(): MAC OK\n"), + (m_is_client == true ? "client": "server"))); + } + + tls_record_message_buffer->set_data_length( + tls_record_message_buffer->get_data_length() + - mac->get_digest_length()); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::apply_send_cipher_suite( + eap_variable_data_c * const tls_record_message_buffer) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: send_function: starts: tls_record_c::apply_send_cipher_suite(): %d=%s\n"), + (m_is_client == true ? "client": "server"), + m_send_cipher_suite, + eap_tls_trace_string_c::get_cipher_suite_string(m_send_cipher_suite))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::apply_send_cipher_suite()"); + + eap_status_e status = eap_status_process_general_error; + + tls_record_header_c tmp_tls_record_header_on_tls_message_buffer( + m_am_tools, + tls_record_message_buffer->get_data(tls_record_header_c::get_header_length()), + tls_record_message_buffer->get_data_length()); + + if (tmp_tls_record_header_on_tls_message_buffer.get_is_valid() == false + || tls_record_message_buffer->get_data_length() + < tmp_tls_record_header_on_tls_message_buffer.get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + if (m_send_cipher_suite != tls_cipher_suites_TLS_NULL_WITH_NULL_NULL) + { + EAP_TRACE_DATA_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("plaintext TLS-record"), + tls_record_message_buffer->get_data(tls_record_message_buffer->get_data_length()), + tls_record_message_buffer->get_data_length())); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + /** + * @{ Add compression of data. Well this will be optional very long time. } + */ + if (m_send_compression_method == tls_compression_method_null) + { + // No compression. + status = eap_status_ok; + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (m_send_cipher_suite == tls_cipher_suites_TLS_NULL_WITH_NULL_NULL) + { + // No authentication. + // No encryption. + + u64_t send_record_sequence_number_network_order = eap_htonll(m_send_record_sequence_number); + EAP_UNREFERENCED_PARAMETER(send_record_sequence_number_network_order); // in release + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("send_record_sequence_number_network_order"), + &send_record_sequence_number_network_order, + sizeof(send_record_sequence_number_network_order))); + + status = eap_status_ok; + } + else if (cipher_suite_is_3DES_EDE_CBC_SHA(m_send_cipher_suite) == true + || cipher_suite_is_AES_128_CBC_SHA(m_send_cipher_suite) == true) + { + EAP_ASSERT_TOOLS(m_am_tools, m_send_block_cipher != 0); + EAP_ASSERT_TOOLS(m_am_tools, m_send_hmac_algorithm != 0); + + status = apply_send_block_cipher_suite( + tls_record_message_buffer, + m_send_block_cipher, + m_send_hmac_algorithm); + } + else if (cipher_suite_is_RC4_128_MD5(m_send_cipher_suite) == true + || cipher_suite_is_RC4_128_SHA(m_send_cipher_suite) == true) + { + EAP_ASSERT_TOOLS(m_am_tools, m_send_stream_cipher != 0); + EAP_ASSERT_TOOLS(m_am_tools, m_send_hmac_algorithm != 0); + + status = apply_send_stream_cipher_suite( + tls_record_message_buffer, + m_send_stream_cipher, + m_send_hmac_algorithm); + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (m_send_cipher_suite != tls_cipher_suites_TLS_NULL_WITH_NULL_NULL) + { + m_send_record_sequence_number = m_send_record_sequence_number + 1ul; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::apply_receive_cipher_suite( + eap_variable_data_c * const tls_record_message_buffer) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: starts: tls_record_c::apply_receive_cipher_suite(): %d=%s\n"), + (m_is_client == true ? "client": "server"), + m_receive_cipher_suite, + eap_tls_trace_string_c::get_cipher_suite_string(m_receive_cipher_suite))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::apply_receive_cipher_suite()"); + + eap_status_e status = eap_status_process_general_error; + + tls_record_header_c tmp_tls_record_header_on_tls_message_buffer( + m_am_tools, + tls_record_message_buffer->get_data(tls_record_header_c::get_header_length()), + tls_record_message_buffer->get_data_length()); + + if (tmp_tls_record_header_on_tls_message_buffer.get_is_valid() == false + || tls_record_message_buffer->get_data_length() + < tmp_tls_record_header_on_tls_message_buffer.get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (m_receive_cipher_suite == tls_cipher_suites_TLS_NULL_WITH_NULL_NULL) + { + // No decryption. + // No authentication. + + u64_t receive_record_sequence_number_network_order + = eap_htonll(m_receive_record_sequence_number); + EAP_UNREFERENCED_PARAMETER(receive_record_sequence_number_network_order); // in release + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("receive_record_sequence_number_network_order"), + &receive_record_sequence_number_network_order, + sizeof(receive_record_sequence_number_network_order))); + + status = eap_status_ok; + } + else if (cipher_suite_is_3DES_EDE_CBC_SHA(m_receive_cipher_suite) == true + || cipher_suite_is_AES_128_CBC_SHA(m_receive_cipher_suite) == true) + { + status = apply_receive_block_cipher_suite( + tls_record_message_buffer, + m_receive_block_cipher, + m_receive_hmac_algorithm); + } + else if (cipher_suite_is_RC4_128_MD5(m_receive_cipher_suite) == true + || cipher_suite_is_RC4_128_SHA(m_receive_cipher_suite) == true) + { + status = apply_receive_stream_cipher_suite( + tls_record_message_buffer, + m_receive_stream_cipher, + m_receive_hmac_algorithm); + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); + } + + if (m_receive_cipher_suite != tls_cipher_suites_TLS_NULL_WITH_NULL_NULL) + { + EAP_TRACE_DATA_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("decrypted TLS-record"), + tls_record_message_buffer->get_data(tls_record_message_buffer->get_data_length()), + tls_record_message_buffer->get_data_length())); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + /** + * @{ Add de-compression of data. Well this will be optional very long time. } + */ + if (m_send_compression_method == tls_compression_method_null) + { + // No de-compression. + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); + } + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (m_receive_cipher_suite != tls_cipher_suites_TLS_NULL_WITH_NULL_NULL) + { + m_receive_record_sequence_number = m_receive_record_sequence_number + 1ul; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// This is commented in abs_tls_base_application_c. +EAP_FUNC_EXPORT eap_status_e tls_record_c::packet_send( + eap_buf_chain_wr_c * const sent_packet, + const u32_t header_offset, + const u32_t /*data_length*/, + const u32_t /*buffer_length*/) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: starts: tls_record_c::packet_send(): %d=%s\n"), + (m_is_client == true ? "client": "server"), + m_receive_cipher_suite, + eap_tls_trace_string_c::get_cipher_suite_string(m_receive_cipher_suite))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::packet_send()"); + + eap_status_e status = create_tls_application_data( + sent_packet, + header_offset); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// This is commented in abs_tls_base_application_c. +EAP_FUNC_EXPORT u32_t tls_record_c::get_header_offset( + u32_t * const MTU_length, + u32_t * const trailer_length) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: starts: tls_record_c::get_header_offset()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::get_header_offset()"); + + if (m_eap_type == eap_type_peap + && m_peap_version == peap_version_0_xp) + { + // PEAPv0 cannot use long tunneled EAP-packets, + // bacause of the inner EAP-packets does not + // have own EAP-header. Long inner EAP-packets will be + // fragmented in outer PEAPv0 application data and that will cause + // wrong EAP-identifier values after reassembly. + u32_t offset = get_type_partner()->get_header_offset( + MTU_length, + trailer_length); + + // Here we try set MTU such the inner EAP-packets does not need fragmentation. + *MTU_length -= (offset + + 4ul*(tls_record_header_c::get_header_length() + + tls_handshake_header_c::get_header_length())); + *trailer_length = 0ul; + + return 0ul; + } + else + { + *MTU_length = EAP_TLS_PEAP_MAX_MESSAGE_LENGTH; + *trailer_length = 0ul; + + return 0ul; + } +} + +//-------------------------------------------------- + +// This is commented in abs_tls_base_application_c. +EAP_FUNC_EXPORT eap_status_e tls_record_c::read_configure( + const eap_configuration_field_c * const field, + eap_variable_data_c * const data) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + + return get_type_partner()->read_configure( + field, + data); +} + +//-------------------------------------------------- + +// This is commented in abs_tls_base_application_c. +EAP_FUNC_EXPORT eap_status_e tls_record_c::write_configure( + const eap_configuration_field_c * const field, + eap_variable_data_c * const data) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + + return get_type_partner()->write_configure( + field, + data); +} + +//-------------------------------------------------- + +// This is commented in abs_tls_base_application_c. +EAP_FUNC_EXPORT void tls_record_c::state_notification( + const abs_eap_state_notification_c * const state) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("this = 0x%08x, %s: starts: tls_record_c::state_notification(): EAP-type 0x%08x: m_tls_session_type=%d=%s, tls_state=%d=%s, notification state=%s\n"), + this, + (m_is_client == true ? "client": "server"), + convert_eap_type_to_u32_t(m_eap_type), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + m_tls_peap_state, + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_state_notification_c::get_state_string(state->get_protocol_layer(), state->get_current_state()))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::state_notification()"); + + if (state->get_protocol_layer() == eap_protocol_layer_general) + { + if (state->get_current_state() == eap_general_state_authentication_cancelled) + { + // Tunneled EAP-type terminated unsuccessfully. + m_tunneled_eap_type_authentication_state + = static_cast(state->get_current_state()); + set_state(tls_peap_state_failure); + } + } + else if (state->get_protocol_layer() == eap_protocol_layer_eap) + { + if (state->get_current_state() == eap_state_authentication_terminated_unsuccessfully +#if defined(USE_EAP_PEAPV1_EXTENSIONS) + || state->get_current_state() == eap_state_authentication_terminated_unsuccessfully_peapv1_extension +#endif //#if defined(USE_EAP_PEAPV1_EXTENSIONS) + ) + { + // Tunneled EAP-type terminated unsuccessfully. + m_tunneled_eap_type_authentication_state + = static_cast(state->get_current_state()); + set_state(tls_peap_state_failure); + + // Because we process aplication data, we do not send alert messages anymore. + m_could_send_fatal_alert_message = false; + m_could_send_warning_alert_message = false; + } + else if (state->get_current_state() + == eap_state_authentication_finished_successfully + || state->get_current_state() + == eap_state_tppd_peapv1_authentication_finished_successfully_with_tunneled_eap_success +#if defined(USE_EAP_PEAPV1_EXTENSIONS) + || state->get_current_state() + == eap_state_authentication_finished_successfully_peapv1_extension +#endif //#if defined(USE_EAP_PEAPV1_EXTENSIONS) + ) + { + // Tunneled EAP-type finished successfully. + + if ((m_eap_type == eap_type_peap + && m_peap_version >= peap_version_0_xp + && m_peap_version <= peap_version_2) + || m_eap_type == eap_type_ttls +#if defined(USE_FAST_EAP_TYPE) + || m_eap_type == eap_type_fast +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + eap_status_e status = get_type_partner()->set_tls_master_secret( + &m_eap_master_session_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return; + } + + if (m_eap_type == eap_type_ttls + || m_eap_type == eap_type_peap +#if defined(USE_FAST_EAP_TYPE) + || m_eap_type == eap_type_fast +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + + tls_identity_privacy_handshake_state_e tmp_identity_privacy_handshake_state = +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + m_tls_identity_privacy_handshake_state; +#else + tls_identity_privacy_handshake_state_none; +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + EAP_UNREFERENCED_PARAMETER(tmp_identity_privacy_handshake_state); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: state_notification(): TLS/PEAP authentication ") + EAPL("SUCCESS: %s, %s, tunnel %d, tunneling type %s, tunneling version %s, cipher_suite %s, %s\n"), + (m_is_client == true ? "client": "server"), + (m_tls_peap_server_authenticates_client_action == true + ? "mutual": "anonymous client"), + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + get_is_tunneled_tls(), + eap_header_string_c::get_eap_type_string(m_eap_type), + eap_tls_trace_string_c::get_peap_version_string(m_peap_version), + eap_tls_trace_string_c::get_cipher_suite_string(m_selected_cipher_suite), + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(tmp_identity_privacy_handshake_state))); + + eap_status_e save_status = m_am_tls_services->save_tls_session( + &m_session_id, + &m_master_secret, + m_selected_cipher_suite +#if defined(USE_EAP_TLS_SESSION_TICKET) + , tls_extension_c::get_tls_extension( + tls_extension_type_session_ticket, + &m_received_tls_extensions, + m_am_tools) +#endif //#if defined(USE_EAP_TLS_SESSION_TICKET) + ); + if (save_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + (void) EAP_STATUS_RETURN(m_am_tools, save_status); + } + } + + } + + m_tunneled_eap_type_authentication_state + = static_cast(state->get_current_state()); + set_state(tls_peap_state_tls_success); + } +#if defined(USE_FAST_EAP_TYPE) + else if (m_eap_type == eap_type_fast + && state->get_current_state() == eap_state_inner_eap_method_skipped) + { + m_tunneled_eap_type_authentication_state + = static_cast(state->get_current_state()); + } + else if (m_is_client == false + && m_eap_type == eap_type_fast + && state->get_current_state() == eap_state_authentication_wait_eap_fast_empty_acknowledge) + { + set_state(tls_peap_state_wait_tunneled_authentication_start); + } +#endif //#if defined(USE_FAST_EAP_TYPE) + } + else if (state->get_protocol_layer() == eap_protocol_layer_internal_type) + { + +#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK) + if (state->get_current_state() == tls_peap_state_server_waits_ttls_plain_ms_chap_v2_empty_ack) + { + EAP_TRACE_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: tls_record_c::state_notification(): ") + EAPL("waits TTLS/plain MsChapv2 empty Ack: EAP-type 0x%08x\n"), + (m_is_client == true ? "client": "server"), + convert_eap_type_to_u32_t(m_eap_type))); + } +#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK) + + } + + get_type_partner()->state_notification( + state); +} + +//-------------------------------------------------- + +// This is commented in abs_tls_base_application_c. +EAP_FUNC_EXPORT eap_status_e tls_record_c::set_timer( + abs_eap_base_timer_c * const initializer, + const u32_t id, + void * const data, + const u32_t p_time_ms) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (get_type_partner() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return get_type_partner()->set_timer( + initializer, + id, + data, + p_time_ms); +} + +//-------------------------------------------------- + +// This is commented in abs_tls_base_application_c. +EAP_FUNC_EXPORT eap_status_e tls_record_c::cancel_timer( + abs_eap_base_timer_c * const initializer, + const u32_t id) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (get_type_partner() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return get_type_partner()->cancel_timer( + initializer, + id); +} + +//-------------------------------------------------- + +// This is commented in abs_tls_base_application_c. +EAP_FUNC_EXPORT eap_status_e tls_record_c::cancel_all_timers() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (get_type_partner() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return get_type_partner()->cancel_all_timers(); +} + +//-------------------------------------------------- + +// This is commented in abs_tls_base_application_c. +EAP_FUNC_EXPORT eap_status_e tls_record_c::load_module( + const eap_type_value_e type, + const eap_type_value_e tunneling_type, + abs_eap_base_type_c * const partner, + eap_base_type_c ** const eap_type, + const bool is_client_when_true, + const eap_am_network_id_c * const receive_network_id) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = get_type_partner()->load_module( + type, + tunneling_type, + partner, + eap_type, + is_client_when_true, + receive_network_id); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +// This is commented in abs_tls_base_application_c. +EAP_FUNC_EXPORT eap_status_e tls_record_c::unload_module(const eap_type_value_e type) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = get_type_partner()->unload_module(type); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +// This is commented in abs_tls_base_application_c. +EAP_FUNC_EXPORT eap_status_e tls_record_c::restart_authentication( + const eap_am_network_id_c * const receive_network_id, + const bool is_client_when_true, + const bool force_clean_restart, + const bool from_timer) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = get_type_partner()->restart_authentication( + receive_network_id, + is_client_when_true, + force_clean_restart, + from_timer); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +// This is commented in abs_tls_base_application_c. +EAP_FUNC_EXPORT eap_status_e tls_record_c::packet_data_crypto_keys( + const eap_am_network_id_c * const /* send_network_id */, + const eap_master_session_key_c * const master_session_key) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: starts: tls_record_c::packet_data_crypto_keys()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::packet_data_crypto_keys()"); + + if ((m_eap_type == eap_type_peap + && (m_peap_version == peap_version_0_xp + || m_peap_version == peap_version_1)) + || m_eap_type == eap_type_ttls) + { + // We do not forward keys to lower layer. + } +#if defined(USE_FAST_EAP_TYPE) + else if (m_eap_type == eap_type_fast) + { + eap_status_e status = m_eap_master_session_key.set_copy_of_buffer( + master_session_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // NOTE: state_notification() will deliver master_session_key to lower layers. + } +#endif //#if defined(USE_FAST_EAP_TYPE) + else if (m_eap_type == eap_type_peap + && m_peap_version == peap_version_2) + { + eap_status_e status = m_eap_master_session_key.set_copy_of_buffer( + master_session_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = get_type_partner()->set_tls_master_secret(&m_eap_master_session_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +// This is commented in abs_tls_base_application_c. +EAP_FUNC_EXPORT eap_status_e tls_record_c::check_is_valid_eap_type( + const eap_type_value_e eap_type) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = get_type_partner()->check_is_valid_eap_type(eap_type); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +// This is commented in abs_tls_base_application_c. +EAP_FUNC_EXPORT eap_status_e tls_record_c::get_eap_type_list( + eap_array_c * const eap_type_list) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = get_type_partner()->get_eap_type_list(eap_type_list); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::start_tls_peap_authentication( + const eap_variable_data_c * const received_authority_identity_payload + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::start_tls_peap_authentication()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::start_tls_peap_authentication()"); + + eap_status_e status = completion_action_add(tls_completion_action_query_cipher_suites_and_previous_session); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + set_state(tls_peap_state_wait_handshake_type_server_hello); + + status = completion_action_add(tls_completion_action_create_handshake_type_client_hello); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast) + { + if (m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true) + { + set_tls_session_type(tls_session_type_eap_fast_server_unauthenticated_provisioning_mode_ADHP); + } + else if (received_authority_identity_payload != 0 + && received_authority_identity_payload->get_is_valid_data() == true) + { + eap_fast_variable_data_c in_A_ID_TLV(m_am_tools); + + status = in_A_ID_TLV.set_copy_of_buffer( + received_authority_identity_payload->get_data(), + received_authority_identity_payload->get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_application->query_tunnel_PAC( + &in_A_ID_TLV); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by + // complete_query_tunnel_PAC() call. + m_pending_query_tunnel_PAC = true; + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_query_PACs() call. + + status = check_sent_tls_message(); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call is always completed on success. + status = eap_status_process_general_error; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else // All other status values means error, because this call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + } +#else + EAP_UNREFERENCED_PARAMETER(received_authority_identity_payload); +#endif //#if defined(USE_FAST_EAP_TYPE) + + + status = check_sent_tls_message(); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::start_peap_tunneled_authentication( + const eap_am_network_id_c * const receive_network_id, + const u8_t received_eap_identifier, + const tls_session_type_e tls_session_type) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::start_peap_tunneled_authentication()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::start_peap_tunneled_authentication()"); + + if (m_is_client == true + && verify_state(tls_peap_state_peap_tunnel_ready) == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: function: verify_state(): current state %s != %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string(tls_peap_state_peap_tunnel_ready))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + else if (m_is_client == false + && verify_state(tls_peap_state_wait_tunneled_authentication_start) == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: function: verify_state(): current state %s != %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string(tls_peap_state_wait_tunneled_authentication_start))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + + + set_state(tls_peap_state_wait_application_data); + + eap_status_e status = eap_status_process_general_error; + + { + // This must be inside a block. Automatic variable must be restored after + // the start_peap_tunneled_authentication() function call. + eap_automatic_simple_value_c restore_allow_message_send( + m_am_tools, + &m_allow_message_send, + m_allow_message_send); + + // Packet send is delayed until after the + // m_application->start_peap_tunneled_authentication() function returns. + m_allow_message_send = false; + + status = m_application->start_peap_tunneled_authentication( + receive_network_id, + m_is_client, + received_eap_identifier, + tls_session_type, + m_tls_peap_server_authenticates_client_action); + } + + + { + // Note this call will return eap_status_pending_request + // if any asyncronous call is pending. + eap_status_e send_status = check_sent_tls_message(); + if (send_status != eap_status_ok) + { + status = send_status; + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::allocate_handshake_message_copy( + tls_handshake_message_c ** const tls_handshake_message, + eap_automatic_variable_c * const automatic_tls_handshake_message, + tls_handshake_header_c * const tls_handshake_header) +{ + *tls_handshake_message + = new tls_handshake_message_c(m_am_tools, this, m_is_client); + + automatic_tls_handshake_message->set_variable(*tls_handshake_message); + + if (*tls_handshake_message == 0 + || (*tls_handshake_message)->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_status_e status = (*tls_handshake_message)->set_handshake_header_copy( + tls_handshake_header); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +#if defined(USE_EAP_TLS_SESSION_TICKET) + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_tls_extension_list( + const u32_t handshake_data_length, + u32_t * const data_offset, + const tls_handshake_header_c * const tls_handshake_header, + tls_handshake_message_c * const tls_handshake_message +) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: starts: tls_record_c::parse_tls_extension_list()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_tls_extension_list()"); + + eap_status_e status(eap_status_ok); + + // This is optional field. + if ((*data_offset)+TLS_EXTENSIONS_LENGTH_FIELD_SIZE <= handshake_data_length) + { + // Extension list is formatted as: + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | extension list length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | extension 1 type | extension 1 data length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | extension 1 data ... + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | extension 2 type | extension 2 data length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | extension 2 data ... + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + u8_t *p_extension_list = tls_handshake_header->get_data_offset( + (*data_offset), + TLS_EXTENSIONS_LENGTH_FIELD_SIZE); + if (p_extension_list == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + (*data_offset) += TLS_EXTENSIONS_LENGTH_FIELD_SIZE; + + u32_t extension_list_length( + eap_read_u16_t_network_order( + p_extension_list, + TLS_EXTENSIONS_LENGTH_FIELD_SIZE)); + + if ((*data_offset)+extension_list_length > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + const u32_t offset_end((*data_offset)+extension_list_length); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS-handshake extension payload"), + p_extension_list, + TLS_EXTENSIONS_LENGTH_FIELD_SIZE+extension_list_length)); + + if (extension_list_length > 0ul) + { + eap_array_c extensions_array(m_am_tools); + + while((*data_offset) < offset_end) + { + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if ((*data_offset)+TLS_EXTENSION_TYPE_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_extension_type = tls_handshake_header->get_data_offset( + (*data_offset), + TLS_EXTENSION_TYPE_FIELD_SIZE); + if (p_extension_type == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + (*data_offset) += TLS_EXTENSION_TYPE_FIELD_SIZE; + + u16_t extension_type_host( + eap_read_u16_t_network_order( + p_extension_type, + TLS_EXTENSIONS_LENGTH_FIELD_SIZE)); + + tls_extension_type_e extension_type(static_cast(extension_type_host)); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if ((*data_offset)+TLS_EXTENSION_DATA_LENGTH_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_extension_data_length = tls_handshake_header->get_data_offset( + (*data_offset), + TLS_EXTENSION_DATA_LENGTH_FIELD_SIZE); + if (p_extension_data_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + (*data_offset) += TLS_EXTENSION_DATA_LENGTH_FIELD_SIZE; + + u16_t extension_data_length_host( + eap_read_u16_t_network_order( + p_extension_data_length, + TLS_EXTENSION_DATA_LENGTH_FIELD_SIZE)); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + tls_extension_c * const tls_extension = new tls_extension_c(m_am_tools); + + eap_automatic_variable_c + automatic_tls_extension(m_am_tools, tls_extension); + + if (tls_extension == 0 + || tls_extension->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + tls_extension->set_type(extension_type); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (extension_data_length_host > 0ul) + { + if ((*data_offset)+extension_data_length_host > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + const u8_t * const p_extension_data = tls_handshake_header->get_data_offset( + (*data_offset), + extension_data_length_host); + if (p_extension_data == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + status = tls_extension->set_copy_of_buffer(p_extension_data, extension_data_length_host); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + (*data_offset) += extension_data_length_host; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + automatic_tls_extension.do_not_free_variable(); + + // add_object() will delete extension if operation fails. + status = extensions_array.add_object(tls_extension, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + } // while() + + status = tls_handshake_message->set_tls_extensions(&extensions_array); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_handshake_type_hello_request( + tls_record_message_c * const received_tls_record_message, + tls_handshake_header_c * const tls_handshake_header, + const u32_t handshake_data_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_handshake_type_hello_request()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_handshake_type_hello_request()"); + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message_copy( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_header); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (handshake_data_length != 0ul) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_long_message); + } + + if (status == eap_status_ok) + { + // Note the add_handshake_message() frees message in any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = received_tls_record_message->add_handshake_message(tls_handshake_message, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_handshake_type_client_hello( + tls_record_message_c * const received_tls_record_message, + tls_handshake_header_c * const tls_handshake_header, + const u32_t handshake_data_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_handshake_type_client_hello()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_handshake_type_client_hello()"); + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message_copy( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_header); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + u32_t data_offset = 0ul; + u8_t * const handshake_data = tls_handshake_header->get_data_offset( + data_offset, + tls_handshake_header->get_data_length()); + if (handshake_data == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + //---------------------------------------------------------- + + { + if (data_offset+TLS_VERSION_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_version = handshake_data; + u16_t version = eap_read_u16_t_network_order(p_version, TLS_VERSION_FIELD_SIZE); + + if (version != tls_version_3_1) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + data_offset += TLS_VERSION_FIELD_SIZE; + } + + //---------------------------------------------------------- + + { + if (data_offset+TLS_HANDSHAKE_RANDOM_VALUE_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_random_value = tls_handshake_header->get_data_offset( + data_offset, + TLS_HANDSHAKE_RANDOM_VALUE_SIZE); + if (p_random_value == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + eap_variable_data_c client_random_value(m_am_tools); + status = client_random_value.set_buffer( + p_random_value, + TLS_HANDSHAKE_RANDOM_VALUE_SIZE, + false, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_handshake_message->set_random_value(&client_random_value); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += TLS_HANDSHAKE_RANDOM_VALUE_SIZE; + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: parse_handshake_type_client_hello(): m_client_random_value"), + client_random_value.get_data(client_random_value.get_data_length()), + client_random_value.get_data_length())); + } + + //---------------------------------------------------------- + + { + if (data_offset+TLS_SESSION_ID_LENGTH_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_session_id_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_SESSION_ID_LENGTH_FIELD_SIZE); + if (p_session_id_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + data_offset += TLS_SESSION_ID_LENGTH_FIELD_SIZE; + + if (data_offset+*p_session_id_length > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + if (*p_session_id_length > 0ul) + { + u8_t *p_session_id = tls_handshake_header->get_data_offset( + data_offset, + *p_session_id_length); + if (p_session_id == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + eap_variable_data_c session_id(m_am_tools); + status = session_id.set_buffer(p_session_id, *p_session_id_length, false, false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_handshake_message->set_session_id(&session_id); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + data_offset += *p_session_id_length; + } + + //---------------------------------------------------------- + + { + if (data_offset+TLS_CIPHER_SUITE_LENGTH_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_cipher_suite_length_network_order = tls_handshake_header->get_data_offset( + data_offset, + TLS_CIPHER_SUITE_LENGTH_FIELD_SIZE); + if (p_cipher_suite_length_network_order == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + u16_t cipher_suite_length = eap_read_u16_t_network_order( + p_cipher_suite_length_network_order, + TLS_CIPHER_SUITE_LENGTH_FIELD_SIZE); + data_offset += TLS_CIPHER_SUITE_LENGTH_FIELD_SIZE; + + if (data_offset+cipher_suite_length > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + if ((cipher_suite_length % 2) != 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + if (cipher_suite_length > 0ul) + { + u8_t *p_cipher_suite = tls_handshake_header->get_data_offset( + data_offset, + cipher_suite_length); + if (p_cipher_suite == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + eap_array_c cipher_suites_array(m_am_tools); + + for (u32_t ind = 0ul; ind < cipher_suite_length; ind += 2ul) + { + u16_t * const cipher_suite = new u16_t; + if (cipher_suite == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + u16_t cipher_suite_host_order = eap_read_u16_t_network_order( + p_cipher_suite, + TLS_CIPHER_SUITE_FIELD_SIZE); + *cipher_suite = cipher_suite_host_order; + + // add_object() will delete cipher_suite if operation fails. + status = cipher_suites_array.add_object(cipher_suite, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + p_cipher_suite += TLS_CIPHER_SUITE_FIELD_SIZE; + } // for() + + status = tls_handshake_message->set_cipher_suites(&cipher_suites_array); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + data_offset += cipher_suite_length; + } + + //---------------------------------------------------------- + + { + if (data_offset+TLS_COMPRESSION_LENGTH_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_compression_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_COMPRESSION_LENGTH_FIELD_SIZE); + if (p_compression_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + data_offset += TLS_COMPRESSION_LENGTH_FIELD_SIZE; + + if (data_offset+*p_compression_length > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + if (*p_compression_length > 0ul) + { + u8_t *p_compression = tls_handshake_header->get_data_offset( + data_offset, + *p_compression_length); + if (p_compression == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + eap_array_c compression_array(m_am_tools); + + for (u32_t ind = 0ul; ind < *p_compression_length; ind++) + { + u8_t * const compression_value = new u8_t; + if (compression_value == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + *compression_value = *p_compression; + + // add_object() will delete compression_value if operation fails. + status = compression_array.add_object(compression_value, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + p_compression += TLS_COMPRESSION_FIELD_SIZE; + } // for() + + status = tls_handshake_message->set_compression_methods(&compression_array); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + data_offset += *p_compression_length; + } + + //---------------------------------------------------------- + +#if defined(USE_EAP_TLS_SESSION_TICKET) + + status = parse_tls_extension_list( + handshake_data_length, + &data_offset, + tls_handshake_header, + tls_handshake_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + + //---------------------------------------------------------- + + if (status == eap_status_ok) + { + // Note the add_handshake_message() frees message in any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = received_tls_record_message->add_handshake_message(tls_handshake_message, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = message_hash_init(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_handshake_type_certificate( + tls_record_message_c * const received_tls_record_message, + tls_handshake_header_c * const tls_handshake_header, + const u32_t handshake_data_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_handshake_type_certificate()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_handshake_type_certificate()"); + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message_copy( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_header); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + u32_t data_offset = 0ul; + + //---------------------------------------------------------- + + { + if (data_offset+(TLS_CERTIFICATE_LENGTH_FIELD_SIZE) > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_certificate_chain_length = tls_handshake_header->get_data_offset( + data_offset, + (TLS_CERTIFICATE_LENGTH_FIELD_SIZE)); + if (p_certificate_chain_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u32_t certificate_chain_length = + eap_read_u24_t_network_order( + p_certificate_chain_length, + TLS_CERTIFICATE_LENGTH_FIELD_SIZE); + + data_offset += (TLS_CERTIFICATE_LENGTH_FIELD_SIZE); + + if (certificate_chain_length > 0ul) + { + eap_array_c certificate_chain(m_am_tools); + u32_t max_data_offset = data_offset + certificate_chain_length; + + for (;data_offset < max_data_offset;) + { + u8_t *p_certificate_length = tls_handshake_header->get_data_offset( + data_offset, + (TLS_CERTIFICATE_LENGTH_FIELD_SIZE)); + if (p_certificate_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u32_t certificate_length = + eap_read_u24_t_network_order( + p_certificate_length, + TLS_CERTIFICATE_LENGTH_FIELD_SIZE); + + data_offset += (TLS_CERTIFICATE_LENGTH_FIELD_SIZE); + + + eap_variable_data_c * const certificate = new eap_variable_data_c(m_am_tools); + + eap_automatic_variable_c + automatic_certificate(m_am_tools, certificate); + + if (certificate == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + + u8_t *p_certificate = tls_handshake_header->get_data_offset( + data_offset, + certificate_length); + if (p_certificate == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + status = certificate->set_copy_of_buffer(p_certificate, certificate_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + automatic_certificate.do_not_free_variable(); + + // add_object() will delete certificate if operation fails. + status = certificate_chain.add_object(certificate, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += certificate_length; + } // for() + + status = tls_handshake_message->set_certificate_chain(&certificate_chain); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + data_offset += certificate_chain_length; + } + + //---------------------------------------------------------- + + if (status == eap_status_ok) + { + // Note the add_handshake_message() frees message in any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = received_tls_record_message->add_handshake_message(tls_handshake_message, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_handshake_type_certificate_request( + tls_record_message_c * const received_tls_record_message, + tls_handshake_header_c * const tls_handshake_header, + const u32_t handshake_data_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_handshake_type_certificate_request()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_handshake_type_certificate_request()"); + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message_copy( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_header); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + u32_t data_offset = 0ul; + + //---------------------------------------------------------- + + { + if (data_offset+TLS_CERTIFICATE_TYPE_LENGTH_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_certificate_type_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_CERTIFICATE_TYPE_LENGTH_FIELD_SIZE); + if (p_certificate_type_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + data_offset += TLS_CERTIFICATE_TYPE_LENGTH_FIELD_SIZE; + + if (data_offset+*p_certificate_type_length > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + if (*p_certificate_type_length > 0ul) + { + u8_t *p_certificate_type = tls_handshake_header->get_data_offset( + data_offset, + *p_certificate_type_length); + if (p_certificate_type == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + eap_array_c certificate_type_array(m_am_tools); + + for (u32_t ind = 0ul; ind < *p_certificate_type_length; ind++) + { + u8_t * const certificate_type_value = new u8_t; + if (certificate_type_value == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + *certificate_type_value = *p_certificate_type; + + // add_object() will delete certificate_type_value if operation fails. + status = certificate_type_array.add_object(certificate_type_value, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + p_certificate_type += TLS_CERTIFICATE_TYPE_FIELD_SIZE; + } // for() + + status = tls_handshake_message->set_certificate_types(&certificate_type_array); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + data_offset += *p_certificate_type_length; + } + + //---------------------------------------------------------- + + { + if (data_offset+TLS_CERTIFICATE_AUTHORITIES_LENGTH_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_certificate_authorities_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_CERTIFICATE_AUTHORITIES_LENGTH_FIELD_SIZE); + if (p_certificate_authorities_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u32_t certificate_authorities_length = + eap_read_u16_t_network_order( + p_certificate_authorities_length, + TLS_CERTIFICATE_AUTHORITIES_LENGTH_FIELD_SIZE); + + data_offset += TLS_CERTIFICATE_AUTHORITIES_LENGTH_FIELD_SIZE; + + if (certificate_authorities_length > 0ul) + { + eap_array_c certificate_authorities(m_am_tools); + u32_t max_data_offset = data_offset + certificate_authorities_length; + + for (;data_offset < max_data_offset;) + { + u8_t *p_certificate_authority_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_CERTIFICATE_AUTHORITIES_LENGTH_FIELD_SIZE); + if (p_certificate_authority_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u32_t certificate_authority_length = + eap_read_u16_t_network_order( + p_certificate_authority_length, + TLS_CERTIFICATE_AUTHORITIES_LENGTH_FIELD_SIZE); + + data_offset += TLS_CERTIFICATE_AUTHORITIES_LENGTH_FIELD_SIZE; + + { + eap_variable_data_c * const certificate_authority + = new eap_variable_data_c(m_am_tools); + + eap_automatic_variable_c + automatic_certificate_authority(m_am_tools, certificate_authority); + + if (certificate_authority == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + + u8_t *p_certificate_authority = tls_handshake_header->get_data_offset( + data_offset, + certificate_authority_length); + if (p_certificate_authority == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + status = certificate_authority->set_copy_of_buffer( + p_certificate_authority, + certificate_authority_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + automatic_certificate_authority.do_not_free_variable(); + + // add_object() will delete certificate_authority if operation fails. + status = certificate_authorities.add_object(certificate_authority, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + data_offset += certificate_authority_length; + } // for() + + status = tls_handshake_message->set_certificate_authorities(&certificate_authorities); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + data_offset += certificate_authorities_length; + } + + //---------------------------------------------------------- + + if (status == eap_status_ok) + { + // Note the add_handshake_message() frees message in any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = received_tls_record_message->add_handshake_message(tls_handshake_message, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_handshake_type_server_hello_done( + tls_record_message_c * const received_tls_record_message, + tls_handshake_header_c * const tls_handshake_header, + const u32_t /* handshake_data_length */) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_handshake_type_server_hello_done()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_handshake_type_server_hello_done()"); + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message_copy( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_header); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (tls_handshake_header->get_data_length() > 0ul) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_long_message); + } + + //---------------------------------------------------------- + + if (status == eap_status_ok) + { + // Note the add_handshake_message() frees message in any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = received_tls_record_message->add_handshake_message(tls_handshake_message, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_handshake_type_server_hello( + tls_record_message_c * const received_tls_record_message, + tls_handshake_header_c * const tls_handshake_header, + const u32_t handshake_data_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_handshake_type_server_hello()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_handshake_type_server_hello()"); + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message_copy( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_header); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + u32_t data_offset = 0ul; + + u8_t * handshake_data = tls_handshake_header->get_data_offset( + data_offset, + tls_handshake_header->get_data_length()); + if (handshake_data == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + //---------------------------------------------------------- + + { + if (data_offset+TLS_VERSION_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_version = handshake_data; + u16_t version = eap_read_u16_t_network_order(p_version, TLS_VERSION_FIELD_SIZE); + + if (version != tls_version_3_1) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + data_offset += TLS_VERSION_FIELD_SIZE; + } + + //---------------------------------------------------------- + + { + if (data_offset+TLS_HANDSHAKE_RANDOM_VALUE_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_random_value = tls_handshake_header->get_data_offset( + data_offset, + TLS_HANDSHAKE_RANDOM_VALUE_SIZE); + if (p_random_value == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + eap_variable_data_c server_random_value(m_am_tools); + status = server_random_value.set_buffer( + p_random_value, + TLS_HANDSHAKE_RANDOM_VALUE_SIZE, + false, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_handshake_message->set_random_value(&server_random_value); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += TLS_HANDSHAKE_RANDOM_VALUE_SIZE; + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: parse_handshake_type_server_hello(): m_server_random_value"), + server_random_value.get_data(server_random_value.get_data_length()), + server_random_value.get_data_length())); + } + + //---------------------------------------------------------- + + { + if (data_offset+TLS_SESSION_ID_LENGTH_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_session_id_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_SESSION_ID_LENGTH_FIELD_SIZE); + if (p_session_id_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + data_offset += TLS_SESSION_ID_LENGTH_FIELD_SIZE; + + if (data_offset+*p_session_id_length > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + if (*p_session_id_length > 0ul) + { + u8_t *p_session_id = tls_handshake_header->get_data_offset( + data_offset, + *p_session_id_length); + if (p_session_id == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + eap_variable_data_c session_id(m_am_tools); + status = session_id.set_buffer(p_session_id, *p_session_id_length, false, false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_handshake_message->set_session_id(&session_id); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: parse_handshake_type_server_hello(): session_id"), + session_id.get_data(session_id.get_data_length()), + session_id.get_data_length())); + } + + data_offset += *p_session_id_length; + } + + //---------------------------------------------------------- + + { + if (data_offset+TLS_CIPHER_SUITE_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_cipher_suite_network_order = tls_handshake_header->get_data_offset( + data_offset, + TLS_CIPHER_SUITE_FIELD_SIZE); + if (p_cipher_suite_network_order == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + u16_t cipher_suite + = eap_read_u16_t_network_order( + p_cipher_suite_network_order, + TLS_CIPHER_SUITE_FIELD_SIZE); + + status = tls_handshake_message->set_selected_cipher_suite( + static_cast(cipher_suite)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: parse_handshake_type_server_hello(): cipher_suite"), + &cipher_suite, + sizeof(cipher_suite))); + + data_offset += TLS_CIPHER_SUITE_FIELD_SIZE; + } + + //---------------------------------------------------------- + + { + if (data_offset+TLS_COMPRESSION_METHOD_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_compression = tls_handshake_header->get_data_offset( + data_offset, + TLS_COMPRESSION_METHOD_FIELD_SIZE); + if (p_compression == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + status = tls_handshake_message->set_selected_compression_method( + static_cast(*p_compression)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: parse_handshake_type_server_hello(): p_compression"), + p_compression, + sizeof(*p_compression))); + + data_offset += TLS_COMPRESSION_METHOD_FIELD_SIZE; + } + + //---------------------------------------------------------- + +#if defined(USE_EAP_TLS_SESSION_TICKET) + + status = parse_tls_extension_list( + handshake_data_length, + &data_offset, + tls_handshake_header, + tls_handshake_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + + //---------------------------------------------------------- + + if (status == eap_status_ok) + { + // Note the add_handshake_message() frees message in any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = received_tls_record_message->add_handshake_message(tls_handshake_message, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_handshake_type_server_key_exchange( + tls_record_message_c * const received_tls_record_message, + tls_handshake_header_c * const tls_handshake_header, + const u32_t handshake_data_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_handshake_type_server_key_exchange()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_handshake_type_server_key_exchange()"); + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message_copy( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_header); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + u32_t handshake_length = tls_handshake_header->get_data_length(); + u32_t data_offset = 0ul; + + //---------------------------------------------------------- + + { + if (data_offset+TLS_DHE_PRIME_LENGTH_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_dhe_prime_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_DHE_PRIME_LENGTH_FIELD_SIZE); + if (p_dhe_prime_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + data_offset += TLS_DHE_PRIME_LENGTH_FIELD_SIZE; + + u16_t dhe_prime_length + = eap_read_u16_t_network_order(p_dhe_prime_length, TLS_DHE_PRIME_LENGTH_FIELD_SIZE); + + u8_t *p_dhe_prime_value = tls_handshake_header->get_data_offset( + data_offset, + dhe_prime_length); + if (p_dhe_prime_value == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + eap_variable_data_c dhe_prime(m_am_tools); + status = dhe_prime.set_buffer(p_dhe_prime_value, dhe_prime_length, false, false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_handshake_message->set_dhe_prime(&dhe_prime); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += dhe_prime_length; + } + + //---------------------------------------------------------- + + { + if (data_offset+TLS_DHE_GROUP_GENERATOR_LENGTH_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_dhe_group_generator_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_DHE_GROUP_GENERATOR_LENGTH_FIELD_SIZE); + if (p_dhe_group_generator_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + data_offset += TLS_DHE_GROUP_GENERATOR_LENGTH_FIELD_SIZE; + + u16_t dhe_group_generator_length = + eap_read_u16_t_network_order( + p_dhe_group_generator_length, + TLS_DHE_GROUP_GENERATOR_LENGTH_FIELD_SIZE); + + u8_t *p_dhe_group_generator_value = tls_handshake_header->get_data_offset( + data_offset, + dhe_group_generator_length); + if (p_dhe_group_generator_value == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + eap_variable_data_c dhe_group_generator(m_am_tools); + status = dhe_group_generator.set_buffer( + p_dhe_group_generator_value, + dhe_group_generator_length, + false, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_handshake_message->set_dhe_group_generator(&dhe_group_generator); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += dhe_group_generator_length; + } + + //---------------------------------------------------------- + + { + if (data_offset+TLS_PUBLIC_DHE_KEY_LENGTH_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_public_dhe_key_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_PUBLIC_DHE_KEY_LENGTH_FIELD_SIZE); + if (p_public_dhe_key_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + data_offset += TLS_PUBLIC_DHE_KEY_LENGTH_FIELD_SIZE; + + u16_t public_dhe_key_length = + eap_read_u16_t_network_order( + p_public_dhe_key_length, + TLS_PUBLIC_DHE_KEY_LENGTH_FIELD_SIZE); + + u8_t *p_public_dhe_key_value = tls_handshake_header->get_data_offset( + data_offset, + public_dhe_key_length); + if (p_public_dhe_key_value == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + eap_variable_data_c public_dhe_key(m_am_tools); + status = public_dhe_key.set_buffer( + p_public_dhe_key_value, + public_dhe_key_length, + false, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_handshake_message->set_public_dhe_key(&public_dhe_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += public_dhe_key_length; + } + + //---------------------------------------------------------- + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && data_offset == handshake_data_length) + { + // Here are no signed hash. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_handshake_type_server_key_exchange(): EAP-FAST server unauthenticated provisioning mode, no signed hash\n"), + (m_is_client == true ? "client": "server"))); + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + { + if (data_offset >= handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u16_t expected_dss_sha1_signature_length + = static_cast(handshake_length - data_offset); + + u8_t *p_dss_sha1_signature_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_DSS_SHA1_SIGNATURE_LENGTH_FIELD_SIZE); + if (p_dss_sha1_signature_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u16_t dss_sha1_signature_length = + eap_read_u16_t_network_order( + p_dss_sha1_signature_length, + TLS_DSS_SHA1_SIGNATURE_LENGTH_FIELD_SIZE); + + if (expected_dss_sha1_signature_length == dss_sha1_signature_length+2ul) + { + // WARNING: Here we have additional length field. OpenSSL does this. + /* + // TLS 1.0 RFC 2246 says the length of sha_hash is explicitly 20 bytes + // (Chapter 7.4.3. Server key exchange message). + // The length of the vector is not included in the encoded stream + // (Chapter 4.3. Vectors). + select (SignatureAlgorithm) + { case anonymous: struct { }; + case rsa: + digitally-signed struct { + opaque md5_hash[16]; + opaque sha_hash[20]; + }; + case dsa: + digitally-signed struct { + opaque sha_hash[20]; + }; + } Signature; + */ + data_offset += TLS_DSS_SHA1_SIGNATURE_LENGTH_FIELD_SIZE; + } + else + { + dss_sha1_signature_length = expected_dss_sha1_signature_length; + } + + u8_t *p_dss_sha1_signature = tls_handshake_header->get_data_offset( + data_offset, + dss_sha1_signature_length); + if (p_dss_sha1_signature == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + eap_variable_data_c dss_sha1_signature(m_am_tools); + status = dss_sha1_signature.set_buffer( + p_dss_sha1_signature, + dss_sha1_signature_length, + false, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_handshake_message->set_signed_message_hash(&dss_sha1_signature); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += dss_sha1_signature_length; + } + + //---------------------------------------------------------- + + if (status == eap_status_ok) + { + // Note the add_handshake_message() frees message in any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = received_tls_record_message->add_handshake_message(tls_handshake_message, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_handshake_type_client_key_exchange( + tls_record_message_c * const received_tls_record_message, + tls_handshake_header_c * const tls_handshake_header, + const u32_t handshake_data_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_handshake_type_client_key_exchange()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_handshake_type_client_key_exchange()"); + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message_copy( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_header); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + u32_t data_offset = 0ul; + + //---------------------------------------------------------- + + if (cipher_suite_is_TLS_RSA() == true) + { + u32_t encrypted_premaster_secret_length = tls_handshake_header->get_data_length(); + + if (data_offset+encrypted_premaster_secret_length > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_encrypted_premaster_secret_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_ENCRYPTED_PREMASTER_SECRET_LENGTH_FIELD_SIZE); + if (p_encrypted_premaster_secret_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + data_offset += TLS_ENCRYPTED_PREMASTER_SECRET_LENGTH_FIELD_SIZE; + + u16_t data_encrypted_premaster_secret_length + = eap_read_u16_t_network_order( + p_encrypted_premaster_secret_length, + TLS_ENCRYPTED_PREMASTER_SECRET_LENGTH_FIELD_SIZE); + + if ((data_encrypted_premaster_secret_length + 2ul) != encrypted_premaster_secret_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + u8_t *p_encrypted_premaster_secret_value = tls_handshake_header->get_data_offset( + data_offset, + encrypted_premaster_secret_length-2ul); + if (p_encrypted_premaster_secret_value == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + eap_variable_data_c encrypted_premaster_secret(m_am_tools); + status = encrypted_premaster_secret.set_buffer( + p_encrypted_premaster_secret_value, + encrypted_premaster_secret_length-2ul, + false, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: parse_handshake_type_client_key_exchange(): encrypted premaster_secret"), + encrypted_premaster_secret.get_data(), + encrypted_premaster_secret.get_data_length())); + + status = tls_handshake_message->set_encrypted_premaster_secret(&encrypted_premaster_secret); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += encrypted_premaster_secret_length; + } + else if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true +#if defined(USE_FAST_EAP_TYPE) + || (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + if (data_offset+TLS_PUBLIC_DHE_KEY_LENGTH_LENGTH_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_public_dhe_key_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_PUBLIC_DHE_KEY_LENGTH_LENGTH_FIELD_SIZE); + if (p_public_dhe_key_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + data_offset += TLS_PUBLIC_DHE_KEY_LENGTH_LENGTH_FIELD_SIZE; + + u16_t public_dhe_key_length + = eap_read_u16_t_network_order( + p_public_dhe_key_length, + TLS_PUBLIC_DHE_KEY_LENGTH_LENGTH_FIELD_SIZE); + + u8_t *p_public_dhe_key_value = tls_handshake_header->get_data_offset( + data_offset, + public_dhe_key_length); + if (p_public_dhe_key_value == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + eap_variable_data_c public_dhe_key(m_am_tools); + status = public_dhe_key.set_buffer( + p_public_dhe_key_value, + public_dhe_key_length, + false, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_handshake_message->set_public_dhe_key(&public_dhe_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += public_dhe_key_length; + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_cipher_suite); + } + + //---------------------------------------------------------- + + if (status == eap_status_ok) + { + // Note the add_handshake_message() frees message in any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = received_tls_record_message->add_handshake_message(tls_handshake_message, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_handshake_type_certificate_verify( + tls_record_message_c * const received_tls_record_message, + tls_handshake_header_c * const tls_handshake_header, + const u32_t handshake_data_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_handshake_type_certificate_verify()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_handshake_type_certificate_verify()"); + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message_copy( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_header); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + u32_t data_offset = 0ul; + + //---------------------------------------------------------- + + + // Save the message hash. + message_hash_save_certificate_verify(); + + if (cipher_suite_is_TLS_RSA() == true + || cipher_suite_is_TLS_DHE_RSA() == true) + { + eap_variable_data_c signed_hash(m_am_tools); + + if (data_offset >= handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u32_t handshake_length = tls_handshake_header->get_data_length(); + u32_t rsa_md5_sha1_signature_length = handshake_length - data_offset; + + u8_t *p_signature_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_SIGNATURE_LENGTH_FIELD_SIZE); + if (p_signature_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + data_offset += TLS_SIGNATURE_LENGTH_FIELD_SIZE; + + u16_t data_signature_length + = eap_read_u16_t_network_order(p_signature_length, TLS_SIGNATURE_LENGTH_FIELD_SIZE); + + if ((data_signature_length + 2ul) != rsa_md5_sha1_signature_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + u8_t *p_rsa_md5_sha1_signature = tls_handshake_header->get_data_offset( + data_offset, + rsa_md5_sha1_signature_length-2ul); + if (p_rsa_md5_sha1_signature == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + status = signed_hash.set_copy_of_buffer( + p_rsa_md5_sha1_signature, + rsa_md5_sha1_signature_length-2ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = tls_handshake_message->set_signed_message_hash( + &signed_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += rsa_md5_sha1_signature_length; + } + else if (cipher_suite_is_TLS_DHE_DSS() == true) + { + eap_variable_data_c signed_hash(m_am_tools); + + if (data_offset >= handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u32_t handshake_length = tls_handshake_header->get_data_length(); + u32_t dss_sha1_signature_length = handshake_length - data_offset; + + u8_t *p_signature_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_SIGNATURE_LENGTH_FIELD_SIZE); + if (p_signature_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + data_offset += TLS_SIGNATURE_LENGTH_FIELD_SIZE; + + u16_t data_signature_length + = eap_read_u16_t_network_order(p_signature_length, TLS_SIGNATURE_LENGTH_FIELD_SIZE); + + if ((data_signature_length + 2ul) != dss_sha1_signature_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + u8_t *p_dss_sha1_signature = tls_handshake_header->get_data_offset( + data_offset, + dss_sha1_signature_length-2ul); + if (p_dss_sha1_signature == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + status = signed_hash.set_copy_of_buffer( + p_dss_sha1_signature, + dss_sha1_signature_length-2ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = tls_handshake_message->set_signed_message_hash( + &signed_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += dss_sha1_signature_length; + } + + //---------------------------------------------------------- + + if (status == eap_status_ok) + { + // Note the add_handshake_message() frees message in any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = received_tls_record_message->add_handshake_message(tls_handshake_message, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_handshake_type_finished( + tls_record_message_c * const received_tls_record_message, + tls_handshake_header_c * const tls_handshake_header, + const u32_t /* handshake_data_length */) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_handshake_type_finished()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_handshake_type_finished()"); + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message_copy( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_header); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + u32_t data_offset = 0ul; + + //---------------------------------------------------------- + + bool client_originated = true; + if (m_is_client == true) + { + client_originated = false; + } + // Save the message hash. + message_hash_save_finished(client_originated); + + { + eap_variable_data_c finished_data(m_am_tools); + + u8_t *p_finished_data = tls_handshake_header->get_data_offset( + data_offset, + TLS_FINISHED_DATA_SIZE); + if (p_finished_data == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + status = finished_data.set_copy_of_buffer(p_finished_data, TLS_FINISHED_DATA_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = tls_handshake_message->set_finished_data( + &finished_data); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += TLS_FINISHED_DATA_SIZE; + } + + //---------------------------------------------------------- + + if (status == eap_status_ok) + { + // Note the add_handshake_message() frees message in any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = received_tls_record_message->add_handshake_message(tls_handshake_message, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +#if defined(USE_EAP_TLS_SESSION_TICKET) + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_handshake_type_new_session_ticket( + tls_record_message_c * const received_tls_record_message, + tls_handshake_header_c * const tls_handshake_header, + const u32_t handshake_data_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_handshake_type_new_session_ticket()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_handshake_type_new_session_ticket()"); + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message_copy( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_header); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + u32_t data_offset = 0ul; + + u8_t * handshake_data = tls_handshake_header->get_data_offset( + data_offset, + tls_handshake_header->get_data_length()); + if (handshake_data == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + //---------------------------------------------------------- + + u32_t session_ticket_lifetime_hint(0ul); + + { + if (data_offset+TLS_SESSION_TICKET_LIFETIME_HINT_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_session_ticket_lifetime_hint = handshake_data; + + session_ticket_lifetime_hint = eap_read_u32_t_network_order( + p_session_ticket_lifetime_hint, + TLS_SESSION_TICKET_LIFETIME_HINT_FIELD_SIZE); + + data_offset += TLS_SESSION_TICKET_LIFETIME_HINT_FIELD_SIZE; + } + + //---------------------------------------------------------- + + { + if (data_offset+TLS_EXTENSION_DATA_LENGTH_FIELD_SIZE > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_opaque_session_ticket_length = tls_handshake_header->get_data_offset( + data_offset, + TLS_EXTENSION_DATA_LENGTH_FIELD_SIZE); + if (p_opaque_session_ticket_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u16_t opaque_session_ticket_length = eap_read_u16_t_network_order( + p_opaque_session_ticket_length, + TLS_EXTENSION_DATA_LENGTH_FIELD_SIZE); + + data_offset += TLS_EXTENSION_DATA_LENGTH_FIELD_SIZE; + + if (data_offset+opaque_session_ticket_length > handshake_data_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + tls_extension_c opaque_session_ticket(m_am_tools); + + if (opaque_session_ticket.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + u8_t *p_opaque_session_ticket = tls_handshake_header->get_data_offset( + data_offset, + opaque_session_ticket_length); + if (p_opaque_session_ticket_length == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + status = opaque_session_ticket.set_buffer( + p_opaque_session_ticket, + opaque_session_ticket_length, + false, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + opaque_session_ticket.set_type(tls_extension_type_session_ticket); + + opaque_session_ticket.set_lifetime_hint(session_ticket_lifetime_hint); + + eap_array_c tls_extensions(m_am_tools); + + status = tls_extensions.add_object(&opaque_session_ticket, false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // Save the new session ticket to be included in next NewSessionTicket message. + status = tls_handshake_message->set_tls_extensions( + &tls_extensions); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: parse_handshake_type_new_session_ticket(): opaque_session_ticket"), + opaque_session_ticket.get_data(opaque_session_ticket.get_data_length()), + opaque_session_ticket.get_data_length())); + + data_offset += opaque_session_ticket_length; + } + + //---------------------------------------------------------- + + if (status == eap_status_ok) + { + // Note the add_handshake_message() frees message in any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = received_tls_record_message->add_handshake_message(tls_handshake_message, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_tls_protocol_change_cipher_spec( + tls_record_message_c * const tls_record_message, + eap_variable_data_c * const tls_protocol_messages_buffer) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_tls_protocol_change_cipher_spec()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_tls_protocol_change_cipher_spec()"); + + tls_record_message->set_parsed_record(); + + if (verify_state(tls_peap_state_wait_change_cipher_spec) == false +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + && (m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_none + && verify_state(tls_peap_state_wait_handshake_type_certificate_verify) == false) +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + ) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: function: verify_state(): current state %s != %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string(tls_peap_state_wait_change_cipher_spec))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + + eap_status_e status = eap_status_not_supported; + + const u32_t tls_protocols_length = tls_protocol_messages_buffer->get_data_length(); + + tls_change_cipher_spec_message_c * const tls_change_cipher_spec_message + = new tls_change_cipher_spec_message_c(m_am_tools, this, m_is_client); + + eap_automatic_variable_c + automatic_tls_change_cipher_spec_message(m_am_tools, tls_change_cipher_spec_message); + + if (tls_change_cipher_spec_message == 0 + || tls_change_cipher_spec_message->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + u32_t data_offset = 0ul; + + //---------------------------------------------------------- + + { + if (data_offset+TLS_CHANGE_CIPHER_SPEC_FIELD_SIZE > tls_protocols_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_change_cipher_spec_type = tls_protocol_messages_buffer->get_data_offset( + data_offset, + TLS_CHANGE_CIPHER_SPEC_FIELD_SIZE); + if (p_change_cipher_spec_type == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + status = tls_change_cipher_spec_message->set_change_cipher_spec_type( + static_cast(*p_change_cipher_spec_type)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += TLS_CHANGE_CIPHER_SPEC_FIELD_SIZE; + } + + //---------------------------------------------------------- + + if (tls_protocols_length != data_offset) + { + // Parsed record length does not match with received record length. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + if (status == eap_status_ok) + { + // Note add_change_cipher_spec_message() frees message on any case. + automatic_tls_change_cipher_spec_message.do_not_free_variable(); + + status = tls_record_message->add_change_cipher_spec_message( + tls_change_cipher_spec_message, + true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_tls_protocol_alert( + tls_record_message_c * const tls_record_message, + eap_variable_data_c * const tls_protocol_messages_buffer) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_tls_protocol_alert()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_tls_protocol_alert()"); + + tls_record_message->set_parsed_record(); + + eap_status_e status = eap_status_not_supported; + + // Because we received alert message, we do not send alert messages anymore. + m_could_send_fatal_alert_message = false; + m_could_send_warning_alert_message = false; + + const u32_t tls_protocol_messages_length = tls_protocol_messages_buffer->get_data_length(); + u32_t data_start_offset = 0ul; + + while (data_start_offset < tls_protocol_messages_length) + { + tls_alert_message_c * const tls_alert_message + = new tls_alert_message_c(m_am_tools, m_is_client); + + eap_automatic_variable_c + automatic_tls_alert_message(m_am_tools, tls_alert_message); + + if (tls_alert_message == 0 + || tls_alert_message->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + u32_t data_offset = 0ul; + + //---------------------------------------------------------- + + { + if (data_start_offset+data_offset+TLS_ALERT_LEVEL_FIELD_SIZE + > tls_protocol_messages_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_alert_level = tls_protocol_messages_buffer->get_data_offset( + data_start_offset+data_offset, + TLS_ALERT_LEVEL_FIELD_SIZE); + if (p_alert_level == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + status = tls_alert_message->set_alert_level( + static_cast(*p_alert_level)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += TLS_ALERT_LEVEL_FIELD_SIZE; + } + + //---------------------------------------------------------- + + { + if (data_start_offset+data_offset+TLS_ALERT_DESCRIPTION_FIELD_SIZE + > tls_protocol_messages_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u8_t *p_alert_description = tls_protocol_messages_buffer->get_data_offset( + data_start_offset+data_offset, + TLS_ALERT_DESCRIPTION_FIELD_SIZE); + if (p_alert_description == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + status = tls_alert_message->set_alert_description( + static_cast(*p_alert_description)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += TLS_ALERT_DESCRIPTION_FIELD_SIZE; + } + + if (status == eap_status_ok) + { + // Note add_alert_message() frees message on any case. + automatic_tls_alert_message.do_not_free_variable(); + + status = tls_record_message->add_alert_message(tls_alert_message, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + data_start_offset += data_offset; + } // while() + + //---------------------------------------------------------- + + if (tls_protocol_messages_length != data_start_offset) + { + // Parsed record length does not match with received record length. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_tls_protocol_handshake( + tls_record_message_c * const tls_record_message, + eap_variable_data_c * const tls_protocol_messages_buffer) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_tls_protocol_handshake()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_tls_protocol_handshake()"); + + tls_record_message->set_parsed_record(); + + const u32_t tls_protocol_messages_length = tls_protocol_messages_buffer->get_data_length(); + + u32_t data_start_offset = 0ul; + + tls_handshake_header_c tls_handshake_header( + m_am_tools, + tls_protocol_messages_buffer->get_data_offset( + data_start_offset, + tls_protocol_messages_buffer->get_data_length()-data_start_offset), + tls_protocol_messages_buffer->get_data_length()-data_start_offset); + if (tls_handshake_header.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + if (tls_handshake_header.get_header_length()+tls_handshake_header.get_data_length() > tls_handshake_header.get_header_buffer_length() + || tls_handshake_header.get_header_buffer( + tls_handshake_header.get_header_length()+tls_handshake_header.get_data_length()) == 0) + { + // Not enough data. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("TLS-handshake tls_handshake_header"), + tls_handshake_header.get_header_buffer( + tls_handshake_header.get_header_length()+tls_handshake_header.get_data_length()), + (tls_handshake_header.get_header_length()+tls_handshake_header.get_data_length()))); + + eap_status_e status = eap_status_ok; + + u32_t counter = 0ul; + + + while (tls_handshake_header.get_is_valid() == true + && data_start_offset < tls_protocol_messages_length) + { + const u32_t handshake_data_length = tls_handshake_header.get_data_length(); + if (handshake_data_length+data_start_offset > tls_protocol_messages_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: parse_tls_protocol_handshake(): ") + EAPL("counter[%u] type = 0x%08x=%s.\n"), + (m_is_client == true ? "client": "server"), + counter, + tls_handshake_header.get_handshake_type(), + tls_handshake_header.get_tls_handshake_string())); + + status = tls_handshake_header.check_header( + tls_handshake_header.get_handshake_type(), + m_is_client); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (tls_handshake_header.get_header_length()+tls_handshake_header.get_data_length() + > tls_handshake_header.get_header_buffer_length() + || tls_handshake_header.get_header_buffer( + tls_handshake_header.get_header_length()+tls_handshake_header.get_data_length()) == 0) + { + // Not enough data. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + bool add_to_message_hash = false; + + switch (tls_handshake_header.get_handshake_type()) + { + case tls_handshake_type_hello_request: + status = parse_handshake_type_hello_request( + tls_record_message, + &tls_handshake_header, + handshake_data_length); + add_to_message_hash = false; + break; + case tls_handshake_type_client_hello: + status = parse_handshake_type_client_hello( + tls_record_message, + &tls_handshake_header, + handshake_data_length); + add_to_message_hash = true; + break; + case tls_handshake_type_server_hello: + status = parse_handshake_type_server_hello( + tls_record_message, + &tls_handshake_header, + handshake_data_length); + add_to_message_hash = true; + break; + case tls_handshake_type_certificate: + status = parse_handshake_type_certificate( + tls_record_message, + &tls_handshake_header, + handshake_data_length); + add_to_message_hash = true; + break; + case tls_handshake_type_server_key_exchange: + status = parse_handshake_type_server_key_exchange( + tls_record_message, + &tls_handshake_header, + handshake_data_length); + add_to_message_hash = true; + break; + case tls_handshake_type_certificate_request: + status = parse_handshake_type_certificate_request( + tls_record_message, + &tls_handshake_header, + handshake_data_length); + add_to_message_hash = true; + break; + case tls_handshake_type_server_hello_done: + status = parse_handshake_type_server_hello_done( + tls_record_message, + &tls_handshake_header, + handshake_data_length); + add_to_message_hash = true; + break; + case tls_handshake_type_certificate_verify: + status = parse_handshake_type_certificate_verify( + tls_record_message, + &tls_handshake_header, + handshake_data_length); + add_to_message_hash = true; + break; + case tls_handshake_type_client_key_exchange: + status = parse_handshake_type_client_key_exchange( + tls_record_message, + &tls_handshake_header, + handshake_data_length); + add_to_message_hash = true; + break; + case tls_handshake_type_finished: + status = parse_handshake_type_finished( + tls_record_message, + &tls_handshake_header, + handshake_data_length); + add_to_message_hash = true; + break; +#if defined(USE_EAP_TLS_SESSION_TICKET) + case tls_handshake_type_new_session_ticket: + status = parse_handshake_type_new_session_ticket( + tls_record_message, + &tls_handshake_header, + handshake_data_length); + add_to_message_hash = true; + break; +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + default: + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } // switch() + + + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + + if (add_to_message_hash == true) + { + status = message_hash_update( + true, + tls_handshake_header.get_handshake_type(), + tls_handshake_header.get_header_buffer( + tls_handshake_header.get_header_length() + +tls_handshake_header.get_data_length()), + tls_handshake_header.get_header_length() + +tls_handshake_header.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + data_start_offset += (tls_handshake_header.get_header_length() + +tls_handshake_header.get_data_length()); + + if (data_start_offset > tls_protocol_messages_buffer->get_data_length()) + { + // Parsed record length does not match with received record length. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + tls_handshake_header.set_header_buffer( + tls_protocol_messages_buffer->get_data_offset( + data_start_offset, + tls_protocol_messages_buffer->get_data_length()-data_start_offset), + tls_protocol_messages_buffer->get_data_length()-data_start_offset); + // NOTE tls_handshake_header is checked in the begin of the loop. + + ++counter; + + } // while() + + if (tls_protocol_messages_length != data_start_offset) + { + // Parsed record length does not match with received record length. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::parse_tls_protocol_application_data( + tls_record_message_c * const tls_record_message, + eap_variable_data_c * const tls_protocol_messages_buffer) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::parse_tls_protocol_application_data()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::parse_tls_protocol_application_data()"); + + tls_record_message->set_parsed_record(); + + eap_status_e status = eap_status_not_supported; + + const u32_t tls_protocol_messages_length = tls_protocol_messages_buffer->get_data_length(); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("TLS-application data"), + tls_protocol_messages_buffer->get_data(tls_protocol_messages_length), + tls_protocol_messages_length)); + + tls_application_data_message_c * const tls_application_data_message + = new tls_application_data_message_c(m_am_tools, m_is_client); + + eap_automatic_variable_c + automatic_tls_application_data_message(m_am_tools, tls_application_data_message); + + if (tls_application_data_message == 0 + || tls_application_data_message->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + u32_t data_offset = 0ul; + + //---------------------------------------------------------- + + { + u8_t *p_application_data = tls_protocol_messages_buffer->get_data( + tls_protocol_messages_length); + if (p_application_data == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + status = tls_application_data_message->set_application_data( + p_application_data, + tls_protocol_messages_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + data_offset += tls_protocol_messages_length; + } + + //---------------------------------------------------------- + + if (tls_protocol_messages_length != data_offset) + { + // Parsed record length does not match with received record length. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + if (status == eap_status_ok) + { + // Note add_application_data_message() frees message on any case. + automatic_tls_application_data_message.do_not_free_variable(); + + status = tls_record_message->add_application_data_message( + tls_application_data_message, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::reassemble_tls_records( + tls_record_message_c * const tls_record_message, + tls_record_header_c * const next_tls_record_header) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: starts: tls_record_c::reassemble_tls_records()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::reassemble_tls_records()"); + + eap_status_e status = tls_record_message->get_record_message_data()->add_data( + next_tls_record_header->get_data(next_tls_record_header->get_data_length()), + next_tls_record_header->get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_record_message->add_data_length(next_tls_record_header->get_data_length()); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: tls_record_c::reassemble_tls_records(): fragment %d bytes, ") + EAPL("message %d bytes.\n"), + this, + (m_is_client == true ? "client": "server"), + next_tls_record_header->get_data_length(), + tls_record_message->get_data_length())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::process_tls_records() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::process_tls_records(): index = %d, record count = %d\n"), + (m_is_client == true ? "client": "server"), + m_received_tls_message.get_analyse_index(), + m_received_tls_message.get_record_message_count())); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::process_tls_records()"); + + if (m_already_in_process_tls_records == true) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + // This is recursive call of process_tls_records(). + // This MUST return eap_status_ok. Other return values will skip + // further prosessing of TLS message. + EAP_TRACE_DEBUG( + m_am_tools, TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: send_function: process_tls_records(): skip recursion\n"), + (m_is_client == true ? "client": "server"))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_end_recursion); + } + m_already_in_process_tls_records = true; + + eap_automatic_simple_value_c restore_already_in_process_tls_records( + m_am_tools, + &m_already_in_process_tls_records, + false); + + // One TLS-message could include many records. Each of records could + // include many protocol messages. + // +=================================================+ + // +=================================================+ + // | 1. tls_record_header_c | + // | protocol tls_record_protocol_handshake | + // +-------------------------------------------------+ + // | 1a. tls_handshake_header_c | + // +- - - - - - - - - - - - - - - - - - - - - - - - -+ + // | 1a. data of handshake | + // +-------------------------------------------------+ + // | 1b. tls_handshake_header_c | + // +- - - - - - - - - - - - - - - - - - - - - - - - -+ + // | 1b. data of handshake | + // +=================================================+ + // +=================================================+ + // | 2. tls_record_header_c | + // | protocol tls_record_protocol_change_cipher_spec | + // +-------------------------------------------------+ + // | 2a. data of change_cipher_spec | + // +=================================================+ + // +=================================================+ + // | 3. tls_record_header_c | + // | protocol tls_record_protocol_handshake | + // +-------------------------------------------------+ + // | 3a. tls_handshake_header_c | + // +- - - - - - - - - - - - - - - - - - - - - - - - -+ + // | 3a. data of handshake | + // +=================================================+ + // +=================================================+ + + // One protocol message could be fragmented to many records. + // +=================================================+ + // +=================================================+ + // | 1. tls_record_header_c | + // | protocol tls_record_protocol_handshake | + // +-------------------------------------------------+ + // | 1a. tls_handshake_header_c | + // +- - - - - - - - - - - - - - - - - - - - - - - - -+ + // | 1a. data of handshake (1/2) | + // +=================================================+ + // +=================================================+ + // | 2. tls_record_header_c | + // | protocol tls_record_protocol_change_cipher_spec | + // +-------------------------------------------------+ + // | 2a. data of handshake (2/2) | + // +=================================================+ + // +=================================================+ + + eap_status_e status = eap_status_ok; + u32_t index = 0ul; + bool analyse_messages = true; + + for (index = m_received_tls_message.get_analyse_index() + ; analyse_messages == true + && index < m_received_tls_message.get_record_message_count() + ; index++) + { + // This is used in EAP-FAST to see the next TLS message type. + m_received_tls_message.save_analyse_index(index); + + tls_record_message_c * const tls_record_message + = m_received_tls_message.get_record_message(index); + if (tls_record_message == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_too_short_message); + } + + u32_t tls_record_length = tls_record_message->get_record_message_data()->get_data_length(); + + tls_record_header_c tls_record_header( + m_am_tools, + tls_record_message->get_record_message_data()->get_data( + tls_record_header_c::get_header_length()), + tls_record_length); + + if (tls_record_header.get_is_valid() == false + || tls_record_length < tls_record_header.get_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_too_short_message); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("process TLS-record message"), + tls_record_header.get_header_buffer(tls_record_header.get_header_length() + + tls_record_header.get_data_length()), + tls_record_header.get_header_length() + + tls_record_header.get_data_length())); + + if ((tls_record_length) + < (tls_record_header.get_header_length() + tls_record_header.get_data_length())) + { + // Record header indicates more data than the received buffer includes. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_process_illegal_packet_error); + } + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: process_tls_records(): ") + EAPL("index[%u] protocol = 0x%08x=%s.\n"), + (m_is_client == true ? "client": "server"), + index, + tls_record_header.get_protocol(), + tls_record_header.get_tls_protocol_string())); + + + if (tls_record_message->get_cipher_suite_applied() == false) + { + status = apply_receive_cipher_suite(tls_record_message->get_record_message_data()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + tls_record_message->set_cipher_suite_applied(); + + tls_record_length = tls_record_message->get_record_message_data()->get_data_length(); + + // We must query tls_record_header again, + // memory buffer may be changed during apply_receive_cipher_suite() call. + tls_record_header.set_header_buffer( + tls_record_message->get_record_message_data()->get_data( + tls_record_header_c::get_header_length()), + tls_record_length); + + if (tls_record_header.get_is_valid() == false + || tls_record_length < tls_record_header.get_data_length() + || tls_record_length + < tls_record_header.get_header_length() + + tls_record_header.get_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_too_short_message); + } + } + + + while (index+1ul < m_received_tls_message.get_record_message_count()) + { + tls_record_message_c * const next_tls_record_message + = m_received_tls_message.get_record_message(index+1ul); + if (next_tls_record_message != 0) + { + u32_t next_tls_record_length + = next_tls_record_message->get_record_message_data()->get_data_length(); + + tls_record_header_c next_tls_record_header( + m_am_tools, + next_tls_record_message->get_record_message_data()->get_data( + tls_record_header_c::get_header_length()), + next_tls_record_length); + + if (next_tls_record_header.get_is_valid() == false + || next_tls_record_length < next_tls_record_header.get_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_too_short_message); + } + + if (tls_record_header.get_protocol() == next_tls_record_header.get_protocol()) + { + // Reassembly checks this and the next TLS-records whether they are fragments + // and it reassembles fragments to one TLS-record. + // The easiest check does need only the TLS-protocol fields. + // If TLS-protocol fields are the same those records could be reassembled. + + if (next_tls_record_message->get_cipher_suite_applied() == false) + { + status = apply_receive_cipher_suite( + next_tls_record_message->get_record_message_data()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + status); + } + + next_tls_record_message->set_cipher_suite_applied(); + } + + next_tls_record_length + = next_tls_record_message->get_record_message_data()->get_data_length(); + + next_tls_record_header.set_header_buffer( + next_tls_record_message->get_record_message_data()->get_data( + tls_record_header_c::get_header_length()), + next_tls_record_length); + + if (next_tls_record_header.get_is_valid() == false + || next_tls_record_length < next_tls_record_header.get_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_too_short_message); + } + + status = reassemble_tls_records(tls_record_message, &next_tls_record_header); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + // If TLS-record is complete then it could be parsed and analysed. + // TLS-record is complete when the next TLS-record is other type of protocol. + // If TLS-record is NOT complete the next TLS-record must processed. + // In a case the TLS-record cannot be reassemled the whole + // TLS-message must be dropped. + + // Remove the next_tls_record_message. + status = m_received_tls_message.remove_record_message(index+1ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else + { + break; + } + } + else + { + break; + } + } // while() + + // NOTE at this point the length may be longer than 2^14 bytes. + tls_record_length = tls_record_message->get_record_message_data()->get_data_length(); + + // We must query tls_record_header again, + // memory buffer may be changed during reassembly. + tls_record_header.set_header_buffer( + tls_record_message->get_record_message_data()->get_data( + tls_record_length), + tls_record_length); + + if (tls_record_header.get_is_valid() == false + || tls_record_length < tls_record_header.get_data_length() + || tls_record_length + < tls_record_header.get_header_length() + + tls_record_header.get_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_too_short_message); + } + + + + // Here we extract the protocol messages from the buffer. + // Note the tls_record_header includes only the first protocol message, + // that causes the use of tls_record_message->get_record_message_data(). + u32_t protocol_messages_length = tls_record_length - tls_record_header.get_header_length(); + eap_variable_data_c protocol_messages(m_am_tools); + + status = protocol_messages.set_buffer( + tls_record_message->get_record_message_data()->get_data_offset( + tls_record_header.get_header_length(), + protocol_messages_length), + protocol_messages_length, + false, + true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("reassembled TLS-protocol messages"), + protocol_messages.get_data( + protocol_messages.get_data_length()), + protocol_messages.get_data_length())); + + switch(tls_record_header.get_protocol()) + { + case tls_record_protocol_change_cipher_spec: + { + if (tls_record_message->get_parsed_record() == false) + { + status = parse_tls_protocol_change_cipher_spec( + tls_record_message, + &protocol_messages); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + + status = analyse_tls_protocol_change_cipher_spec( + tls_record_message); + break; + } + case tls_record_protocol_alert: + { + if (tls_record_message->get_parsed_record() == false) + { + status = parse_tls_protocol_alert( + tls_record_message, + &protocol_messages); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + + status = analyse_tls_protocol_alert( + tls_record_message); + break; + } + case tls_record_protocol_handshake: + { + if (tls_record_message->get_parsed_record() == false) + { + status = parse_tls_protocol_handshake( + tls_record_message, + &protocol_messages); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + + status = analyse_tls_protocol_handshake( + tls_record_message, + m_received_tls_message.get_received_eap_identifier()); + break; + } + case tls_record_protocol_application_data: + { + if (tls_record_message->get_parsed_record() == false) + { + status = parse_tls_protocol_application_data( + tls_record_message, + &protocol_messages); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + + status = analyse_tls_protocol_application_data( + tls_record_message, + m_received_tls_message.get_received_eap_identifier()); + break; + } + default: + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_wrong_protocol); + } // switch() + + + // Save the analysed state. We will continue from the following record + // after the pending request is completed. + m_received_tls_message.save_analyse_index(index+1ul); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: process_tls_records(): saves index+1 = %u.\n"), + (m_is_client == true ? "client": "server"), + index+1ul)); + + + if (status == eap_status_pending_request) + { + // Save analyse state. We will continue from the current record + // after the pending request is completed. + m_received_tls_message.save_analyse_index(index); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: process_tls_records(): pending request, saves index = %u.\n"), + (m_is_client == true ? "client": "server"), + index)); + + analyse_messages = false; + + eap_status_e compl_status = completion_action_add( + tls_completion_action_process_tls_records); + if (compl_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else if (status != eap_status_ok) + { + analyse_messages = false; + } + + if ((get_is_tunneled_tls() == false + && m_tls_peap_state == tls_peap_state_tls_success) + || (get_is_tunneled_tls() == true + && m_tls_peap_state == tls_peap_state_peap_tunnel_ready)) + { + // Authentication OK. + + if (m_eap_type == eap_type_peap + && m_peap_version == peap_version_2 + && m_tls_peap_state == tls_peap_state_peap_tunnel_ready) + { + // PEAPv2 sends EAP-Request/Identity message + // within the application data within the same message + // with TLS hello finished. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: PEAPv2 tunnel ready, application data may follow.\n"))); + } + else + { + analyse_messages = false; + if ((index+1ul) != m_received_tls_message.get_record_message_count()) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: parse_function: starts: tls_record_c::process_tls_records(): (index+1 = %d) != (record count = %d)\n"), + (m_is_client == true ? "client": "server"), + index+1, + m_received_tls_message.get_record_message_count())); + // Authentication was successfull, but there are unused TLS-records to process. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: tls_record_c::process_tls_records(): m_received_tls_message.reset().\n"))); + m_received_tls_message.reset(); + } + } + } // for() + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::process_tls_message() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: starts: tls_record_c::process_tls_message()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::process_tls_message()"); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("TLS-message"), + m_received_tls_message.get_tls_message_data()->get_data( + m_received_tls_message.get_tls_message_data()->get_data_length()), + m_received_tls_message.get_tls_message_data()->get_data_length())); + + u32_t next_start_offset = 0ul; + u32_t tls_packet_length = m_received_tls_message.get_tls_message_data()->get_data_length(); + + if (tls_packet_length < tls_record_header_c::get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_too_short_message); + } + + tls_record_header_c tls_record_header( + m_am_tools, + m_received_tls_message.get_tls_message_data()->get_data_offset( + next_start_offset, + tls_record_header_c::get_header_length()), + tls_packet_length); + + if (tls_record_header.get_is_valid() == false + || tls_packet_length < tls_record_header.get_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_too_short_message); + } + + eap_status_e status = eap_status_ok; + u32_t counter = 0ul; + + // One TLS-message could include many records. Each of records + // could include many protocol messages. + // +=================================================+ + // +=================================================+ + // | 1. tls_record_header_c | + // | protocol tls_record_protocol_handshake | + // +-------------------------------------------------+ + // | 1a. tls_handshake_header_c | + // +- - - - - - - - - - - - - - - - - - - - - - - - -+ + // | 1a. data of handshake | + // +-------------------------------------------------+ + // | 1b. tls_handshake_header_c | + // +- - - - - - - - - - - - - - - - - - - - - - - - -+ + // | 1b. data of handshake | + // +=================================================+ + // +=================================================+ + // | 2. tls_record_header_c | + // | protocol tls_record_protocol_change_cipher_spec | + // +-------------------------------------------------+ + // | 2a. data of change_cipher_spec | + // +=================================================+ + // +=================================================+ + // | 3. tls_record_header_c | + // | protocol tls_record_protocol_handshake | + // +-------------------------------------------------+ + // | 3a. tls_handshake_header_c | + // +- - - - - - - - - - - - - - - - - - - - - - - - -+ + // | 3a. data of handshake | + // +=================================================+ + // +=================================================+ + + // One protocol message could be fragmented to many records. + // +=================================================+ + // +=================================================+ + // | 1. tls_record_header_c | + // | protocol tls_record_protocol_handshake | + // +-------------------------------------------------+ + // | 1a. tls_handshake_header_c | + // +- - - - - - - - - - - - - - - - - - - - - - - - -+ + // | 1a. data of handshake (1/2) | + // +=================================================+ + // +=================================================+ + // | 2. tls_record_header_c | + // | protocol tls_record_protocol_change_cipher_spec | + // +-------------------------------------------------+ + // | 2a. data of handshake (2/2) | + // +=================================================+ + // +=================================================+ + + while(status == eap_status_ok + && next_start_offset < tls_packet_length + && tls_record_header.get_is_valid() == true) + { + if ((tls_packet_length-next_start_offset) + < (tls_record_header.get_header_length() + tls_record_header.get_data_length())) + { + // Record header indicates more data than the received buffer includes. + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: Record header indicates more data %u ") + EAPL("than the received buffer includes %u.\n"), + (tls_record_header.get_header_length() + tls_record_header.get_data_length()), + (tls_packet_length-next_start_offset))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_process_illegal_packet_error); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("process TLS-record"), + tls_record_header.get_header_buffer( + tls_record_header.get_header_length() + + tls_record_header.get_data_length()), + tls_record_header.get_header_length() + + tls_record_header.get_data_length())); + + u32_t tls_record_length = tls_record_header.get_header_length() + + tls_record_header.get_data_length(); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: parse_function: process_tls_message(): ") + EAPL("counter[%u] protocol = 0x%08x=%s.\n"), + (m_is_client == true ? "client": "server"), + counter, + tls_record_header.get_protocol(), + tls_record_header.get_tls_protocol_string())); + + tls_record_message_c * const tls_record_message + = new tls_record_message_c(m_am_tools, this, m_is_client); + + eap_automatic_variable_c + automatic_tls_record_message(m_am_tools, tls_record_message); + + if (tls_record_message == 0 + || tls_record_message->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_allocation_error); + } + + tls_record_message->set_tls_record_header_is_included(true); + + status = tls_record_message->set_record_header_copy(&tls_record_header); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + tls_record_message->set_record_message_data( + tls_record_header.get_header_buffer(tls_record_header.get_header_length() + + tls_record_header.get_data_length()), + tls_record_header.get_header_length() + + tls_record_header.get_data_length()); + + // Note m_received_tls_message frees message on any case. + automatic_tls_record_message.do_not_free_variable(); + + status = m_received_tls_message.add_record_message( + tls_record_message, + true, + false // Here the TLS-Hello messages are not marked. + ); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + + next_start_offset += tls_record_length; + + if (next_start_offset < tls_packet_length) + { + u32_t remain_data_length = tls_packet_length - next_start_offset; + if (remain_data_length < tls_record_header_c::get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_too_short_message); + } + + tls_record_header.set_header_buffer( + m_received_tls_message.get_tls_message_data()->get_data_offset( + next_start_offset, + tls_record_header_c::get_header_length()), + remain_data_length); + + if (tls_record_header.get_is_valid() == false + || remain_data_length < tls_record_header.get_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_too_short_message); + } + } + + ++counter; + + } // while() + + if (next_start_offset != tls_packet_length) + { + // Parsed packet length does not match with received packet length. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT( + m_am_tools, + eap_status_process_illegal_packet_error); + } + + status = process_tls_records(); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::check_selected_cipher_suite( + const tls_cipher_suites_e selected_cipher_suite) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: suite_function: starts: tls_record_c::check_selected_cipher_suite(): selected_cipher_suite=%d=%s\n"), + (m_is_client == true ? "client": "server"), + selected_cipher_suite, + eap_tls_trace_string_c::get_cipher_suite_string(selected_cipher_suite))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::check_selected_cipher_suite()"); + + u16_t tmp_selected_cipher_suite = static_cast(selected_cipher_suite); + + i32_t index = find_simple( + &m_proposed_cipher_suites, + &tmp_selected_cipher_suite, + m_am_tools); + if (index == -1) + { + for (u32_t ind = 0ul; ind < m_proposed_cipher_suites.get_object_count(); ++ind) + { + u16_t * proposed_cipher_suite = m_proposed_cipher_suites.get_object(ind); + if (proposed_cipher_suite != 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: suite_function: check_selected_cipher_suite(): proposed cipher suite=%d=%s\n"), + (m_is_client == true ? "client": "server"), + *proposed_cipher_suite, + eap_tls_trace_string_c::get_cipher_suite_string(static_cast(*proposed_cipher_suite)))); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_cipher_suite); + } + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::check_selected_compression_method( + const tls_compression_method_e selected_compression_method) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: suite_function: starts: tls_record_c::check_selected_compression_method(): %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_compression_method_string(selected_compression_method))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::check_selected_compression_method()"); + + if (selected_compression_method == tls_compression_method_null) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); + } + + u8_t tmp_selected_compression_method = static_cast(selected_compression_method); + + i32_t index = find_simple( + &m_proposed_compression_methods, + &tmp_selected_compression_method, m_am_tools); + if (index == -1) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_cipher_suite); + } + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::u16_t_to_host_order( + u16_t * const value, + abs_eap_am_tools_c * const m_am_tools) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_UNREFERENCED_PARAMETER(m_am_tools); + + *value = eap_ntohs(*value); + + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::u16_t_to_network_order( + u16_t * const value, + abs_eap_am_tools_c * const m_am_tools) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_UNREFERENCED_PARAMETER(m_am_tools); + + *value = eap_htons(*value); + + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_handshake_type_hello_request( + EAP_TEMPLATE_CONST tls_handshake_message_c * const /* handshake_message */) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_handshake_type_hello_request()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_handshake_type_hello_request()"); + + EAP_ASSERT(m_is_client == true); + +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + set_tls_identity_privacy_handshake_state(tls_identity_privacy_handshake_state_runs); +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + + set_state(tls_peap_state_wait_handshake_type_server_hello); + + eap_status_e status = completion_action_add(tls_completion_action_create_handshake_type_client_hello); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_handshake_type_client_hello( + EAP_TEMPLATE_CONST tls_handshake_message_c * const handshake_message) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_handshake_type_client_hello(): privacy_handshake_state=%d=%s, session_type=%s\n"), + (m_is_client == true ? "client": "server"), + m_tls_identity_privacy_handshake_state, + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(m_tls_identity_privacy_handshake_state), + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type) + )); +#else + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_handshake_type_client_hello(): privacy_handshake_state=%d=%s\n"), + (m_is_client == true ? "client": "server"), + 0, + "" + )); +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_handshake_type_client_hello()"); + + EAP_ASSERT(m_is_client == false); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Version: 3 | Version: 1 | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | | + // + + + // | ClientRandomValue | + // + (32 bytes) +-+-+-+-+-+-+-+-+ + // | | ID length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | Session ID | + // + (maximum 32 bytes) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | CipherSuite length | CipherSuite 1 | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | CipherSuite 2 | CipherSuite 3 | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | CipherSuite 4 | Cmp length | Cmp 1 | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Cmp 2 | Cmp 3 | extensions ... | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + eap_status_e status = eap_status_not_supported; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (handshake_message->get_random_value() == 0 + || handshake_message->get_random_value()->get_data_length() + != TLS_HANDSHAKE_RANDOM_VALUE_SIZE) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + + status = m_client_handshake_random_value.set_copy_of_buffer( + handshake_message->get_random_value()); + if (status != eap_status_ok + || m_client_handshake_random_value.get_data_length() != TLS_HANDSHAKE_RANDOM_VALUE_SIZE) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (handshake_message->get_session_id() == 0 + || (handshake_message->get_session_id()->get_is_valid_data() == true + && handshake_message->get_session_id()->get_data_length() > TLS_SESSION_ID_SIZE)) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + if (handshake_message->get_session_id()->get_is_valid_data() == true + && handshake_message->get_session_id()->get_data_length() > 0ul) + { + status = m_session_id.set_copy_of_buffer(handshake_message->get_session_id()); + if (status != eap_status_ok + || m_session_id.get_data_length() > TLS_SESSION_ID_SIZE) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + { + EAP_TEMPLATE_CONST eap_array_c * const cipher_suites + = handshake_message->get_cipher_suites(); + + if (cipher_suites->get_object_count() == 0ul) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + m_proposed_cipher_suites.reset(); + + status = copy_simple( + cipher_suites, + &m_proposed_cipher_suites, + m_am_tools, + false); + if (status != eap_status_ok + || m_proposed_cipher_suites.get_object_count() == 0ul) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + { + EAP_TEMPLATE_CONST eap_array_c * const compression_methods + = handshake_message->get_compression_methods(); + + status = copy_simple( + compression_methods, + &m_proposed_compression_methods, + m_am_tools, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +#if defined(USE_EAP_TLS_SESSION_TICKET) + + { + EAP_TEMPLATE_CONST eap_array_c * const tls_extensions + = handshake_message->get_tls_extensions(); + + status = copy( + tls_extensions, + &m_received_tls_extensions, + m_am_tools, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + } + +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + if (m_tls_session_type == tls_session_type_full_authentication + && m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_negotiates) + { + set_tls_identity_privacy_handshake_state(tls_identity_privacy_handshake_state_runs); + } +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + + status = completion_action_add(tls_completion_action_create_handshake_type_server_hello); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + if (m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_none) +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + { + status = m_am_tls_services->select_cipher_suite_and_check_session_id( + &m_proposed_cipher_suites, + &m_session_id + #if defined(USE_EAP_TLS_SESSION_TICKET) + , tls_extension_c::get_tls_extension( + tls_extension_type_session_ticket, + &m_received_tls_extensions, + m_am_tools) + #endif //#if defined(USE_EAP_TLS_SESSION_TICKET) + ); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by + // complete_select_cipher_suite_and_check_session_id() call. + m_pending_select_cipher_suite_and_check_session_id = true; + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_select_cipher_suite_and_check_session_id() call. + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call is always completed on success. + status = eap_status_process_general_error; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else // All other status values means error, because this call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + else if (m_tls_session_type == tls_session_type_full_authentication + && m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_runs) + { + if (m_tls_peap_server_authenticates_client_config_server == true) + { + set_state(tls_peap_state_wait_handshake_type_certificate); + } + else + { + set_state(tls_peap_state_wait_handshake_type_client_key_exchange); + } + + status = completion_action_add(tls_completion_action_create_handshake_type_certificate); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true) + { + // Ephemeral DH key exchange causes creation of server_key_exchange message. + // Server sends DH public key and related parameters to client. + + status = completion_action_add(tls_completion_action_query_dh_parameters); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = completion_action_add( + tls_completion_action_create_handshake_type_server_key_exchange); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // This will complete creation of handshake_type_server_key_exchange message. + status = completion_action_add( + tls_completion_action_complete_create_handshake_type_server_key_exchange); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // Also the other pending messages will be processed after this action is completed. + eap_status_e compl_status = completion_action_add( + tls_completion_action_process_tls_records); + if (compl_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + if (m_tls_peap_server_authenticates_client_config_server == true) + { + // Server initiates client authentication. + status = completion_action_add( + tls_completion_action_create_handshake_type_certificate_request); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + status = completion_action_add( + tls_completion_action_create_handshake_type_server_hello_done); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (/* status == eap_status_pending_request + || */ status == eap_status_completed_request) + { + status = eap_status_ok; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_handshake_type_server_hello( + EAP_TEMPLATE_CONST tls_handshake_message_c * const handshake_message) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_handshake_type_server_hello()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_handshake_type_server_hello()"); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Version: 3 | Version: 1 | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | | + // + + + // | ServerRandomValue | + // + (32 bytes) +-+-+-+-+-+-+-+-+ + // | | ID length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | Session ID | + // + (maximum 32 bytes) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | CipherSuite | Cmp | extensions ...| + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + eap_status_e status = eap_status_not_supported; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (handshake_message->get_random_value() == 0 + || handshake_message->get_random_value()->get_data_length() + != TLS_HANDSHAKE_RANDOM_VALUE_SIZE) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + status = m_server_handshake_random_value.set_copy_of_buffer( + handshake_message->get_random_value()); + if (status != eap_status_ok + || m_server_handshake_random_value.get_data_length() != TLS_HANDSHAKE_RANDOM_VALUE_SIZE) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + set_selected_cipher_suite(handshake_message->get_selected_cipher_suite()); + + status = check_selected_cipher_suite(m_selected_cipher_suite); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: TLS/PEAP selected cipher_suite %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_cipher_suite_string(m_selected_cipher_suite))); + } + + + m_selected_compression_method = handshake_message->get_selected_compression_method(); + + status = check_selected_compression_method(m_selected_compression_method); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (handshake_message->get_session_id() == 0 + || (handshake_message->get_session_id()->get_is_valid_data() == true + && handshake_message->get_session_id()->get_data_length() > TLS_SESSION_ID_SIZE)) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + +#if defined(USE_EAP_TLS_SESSION_TICKET) + m_will_receive_new_session_ticket = false; +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast + && m_tls_session_type == tls_session_type_eap_fast_server_unauthenticated_provisioning_mode_ADHP + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: analyse_handshake_type_server_hello(): ") + EAPL("EAP-FAST server unauthenticated provisioning mode\n"), + (m_is_client == true ? "client": "server"))); + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + if (handshake_message->get_session_id()->get_is_valid_data() == true + && handshake_message->get_session_id()->get_data_length() > 0ul +#if defined(USE_FAST_EAP_TYPE) + // EAP-FAST specification says to watch the next message to see whether the session is resumed or not. + // Original TLS is specified to correctly so the client know what happens when it receives ServerHello message. + && (m_eap_type != eap_type_fast + || (m_tls_session_type == tls_session_type_original_session_resumption + || m_tls_session_type == tls_session_type_full_authentication)) +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + +#if defined(USE_EAP_TLS_SESSION_TICKET) + + if (m_tls_session_type == tls_session_type_stateless_session_resumption) + { + m_received_tls_extensions.reset(); + + const tls_extension_c * const supported_session_ticket_extension = tls_extension_c::get_tls_extension( + tls_extension_type_session_ticket, + &m_supported_tls_extensions, + m_am_tools); + + if (supported_session_ticket_extension != 0) + { + EAP_TEMPLATE_CONST eap_array_c * const tls_extensions + = handshake_message->get_tls_extensions(); + + const tls_extension_c * const received_session_ticket_extension = tls_extension_c::get_tls_extension( + tls_extension_type_session_ticket, + tls_extensions, + m_am_tools); + + if (received_session_ticket_extension != 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: analyse_handshake_type_server_hello(): ") + EAPL("SST: receives stateless session ticket: length = %d\n"), + (m_is_client == true ? "client": "server"), + received_session_ticket_extension->get_data_length())); + + eap_array_c tmp_extensions(m_am_tools); + + tls_extension_c * const received_session_ticket_extension_copy = received_session_ticket_extension->copy(); + + if (received_session_ticket_extension_copy != 0) + { + status = tmp_extensions.add_object(received_session_ticket_extension_copy, true); + + status = copy( + &tmp_extensions, + &m_received_tls_extensions, + m_am_tools, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + m_will_receive_new_session_ticket = true; + } + } + } + } + +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + + +#if defined(USE_EAP_TLS_SESSION_TICKET) + if (m_tls_session_type == tls_session_type_stateless_session_resumption) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: analyse_handshake_type_server_hello(): ") + EAPL("restores stateless session\n"), + (m_is_client == true ? "client": "server"))); + + status = m_session_id.set_copy_of_buffer(handshake_message->get_session_id()); + if (status != eap_status_ok + || m_session_id.get_data_length() > TLS_SESSION_ID_SIZE) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + status = indicate_state_to_lower_layer( + tls_peap_state_stateless_session_resumption); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + /** @{ PEAPv2 does not support session resumption yet. } */ + if (((m_eap_type == eap_type_peap + && m_peap_version != peap_version_2) + || m_eap_type == eap_type_tls + || m_eap_type == eap_type_ttls +#if defined(USE_FAST_EAP_TYPE) + || m_eap_type == eap_type_fast +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + && m_tls_session_type == tls_session_type_original_session_resumption + && m_resumed_cipher_suite == m_selected_cipher_suite + && handshake_message->get_session_id()->compare(&m_session_id) == 0) + { + // OK, previous session will be restored. + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: analyse_handshake_type_server_hello(): ") + EAPL("restores session\n"), + (m_is_client == true ? "client": "server"))); + + + eap_status_e notification_status = indicate_state_to_lower_layer( + tls_peap_state_original_session_resumption); + if (notification_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, notification_status); + } + } + else + { + +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + if (m_is_client == true + && m_tls_use_identity_privacy == true + && m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_none) + { + set_tls_identity_privacy_handshake_state(tls_identity_privacy_handshake_state_negotiates); + } +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + + set_tls_session_type(tls_session_type_full_authentication); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: analyse_handshake_type_server_hello(): ") + EAPL("creates new session\n"), + (m_is_client == true ? "client": "server"))); + + status = m_session_id.set_copy_of_buffer(handshake_message->get_session_id()); + if (status != eap_status_ok + || m_session_id.get_data_length() > TLS_SESSION_ID_SIZE) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + status = indicate_state_to_lower_layer( + tls_peap_state_full_authentication); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + } + else + { + // No session identifier. +#if defined(USE_FAST_EAP_TYPE) + if (m_tls_session_type == tls_session_type_eap_fast_pac_session_resumption + && get_next_tls_handshake_message_type() == tls_handshake_type_none + && get_next_tls_record_message_protocol() == tls_record_protocol_change_cipher_spec) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: analyse_handshake_type_server_hello(): ") + EAPL("EAP-FAST PAC session resumtion.\n"), + (m_is_client == true ? "client": "server"))); + + // Generates master secret from PAC-Key. + status = generate_eap_fast_master_secret_from_pac_key( + &m_eap_fast_pac_key); + + m_eap_fast_pac_key.reset(); + + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: analyse_handshake_type_server_hello(): ") + EAPL("creates new session, no session identifier\n"), + (m_is_client == true ? "client": "server"))); + +#if defined(USE_FAST_EAP_TYPE) + if (m_tls_session_type == tls_session_type_eap_fast_pac_session_resumption) + { + // Server does not accept the Tunnel PAC. + // We will remove the Tunnel PAC if server authenticates OK. + m_remove_tunnel_pac = true; + } +#endif //#if defined(USE_FAST_EAP_TYPE) + + set_tls_session_type(tls_session_type_full_authentication); + } + + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (m_tls_session_type == tls_session_type_original_session_resumption +#if defined(USE_EAP_TLS_SESSION_TICKET) + || m_tls_session_type == tls_session_type_stateless_session_resumption +#if defined(USE_FAST_EAP_TYPE) + || m_tls_session_type == tls_session_type_eap_fast_pac_session_resumption +#endif //#if defined(USE_FAST_EAP_TYPE) +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + ) + { + if (m_tls_session_type == tls_session_type_original_session_resumption +#if defined(USE_FAST_EAP_TYPE) + || m_tls_session_type == tls_session_type_eap_fast_pac_session_resumption +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + // We must generate the key material. + status = generate_key_material(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + set_state(tls_peap_state_wait_change_cipher_spec); + } +#if defined(USE_FAST_EAP_TYPE) + else if (m_eap_type == eap_type_fast + && m_tls_session_type == tls_session_type_eap_fast_server_unauthenticated_provisioning_mode_ADHP + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true) + { + set_state(tls_peap_state_wait_handshake_type_server_key_exchange); + } +#endif //#if defined(USE_FAST_EAP_TYPE) + else + { + set_state(tls_peap_state_wait_handshake_type_certificate); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_handshake_type_certificate( + EAP_TEMPLATE_CONST tls_handshake_message_c * const handshake_message) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_handshake_type_certificate()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_handshake_type_certificate()"); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Certificate Chain Length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Certificate 1 Length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | Certificate 1 | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // . ... . + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Certificate n Length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | Certificate n | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + eap_status_e status = eap_status_not_supported; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TEMPLATE_CONST eap_array_c * const certificate_chain + = handshake_message->get_certificate_chain(); + + if (m_is_client == false + && certificate_chain->get_object_count() == 0ul + && m_tls_peap_server_authenticates_client_policy_flag == false) + { + // Server allows server only authentication, client is anonymous. + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: analyse_handshake_type_certificate(): ") + EAPL("Server allows anonymous client.\n"), + (m_is_client == true ? "client": "server"))); + + m_tls_peap_server_authenticates_client_action = false; + } +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + else if (m_is_client == false + && m_tls_use_identity_privacy == true + && m_tls_session_type == tls_session_type_full_authentication + && m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_none + && certificate_chain->get_object_count() == 0ul) + { + // Server allows TLS identity privacy, at this point client is anonymous. + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: analyse_handshake_type_certificate(): ") + EAPL("Server allows TLS identity privacy.\n"), + (m_is_client == true ? "client": "server"))); + + set_tls_identity_privacy_handshake_state(tls_identity_privacy_handshake_state_negotiates); + } +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + else if (certificate_chain->get_object_count() == 0ul) + { +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) +#if defined(USE_FAST_EAP_TYPE) + if (m_is_client == false + && m_tls_use_identity_privacy == false + && m_eap_type == eap_type_fast + && m_tls_session_type == tls_session_type_full_authentication) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: analyse_handshake_type_certificate(): ") + EAPL("EAP-FAST %s allows anonymous client.\n"), + (m_is_client == true ? "client": "server"), + (m_is_client == true ? "client": "server"))); + + m_tls_peap_server_authenticates_client_action = false; + m_tls_identity_privacy_handshake_state = tls_identity_privacy_handshake_state_none; + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: analyse_handshake_type_certificate(): ") + EAPL("TLS %s does NOT allow anonymous %s.\n"), + (m_is_client == true ? "client": "server"), + (m_is_client == true ? "client": "server"), + (m_is_client == false ? "client": "server"))); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_insufficient_security); + } + } + else + { + status = copy( + certificate_chain, + &m_peer_certificate_chain, + m_am_tools, + false); + if (status != eap_status_ok + || m_peer_certificate_chain.get_object_count() == 0ul) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (m_is_client == true) + { + status = completion_action_add(tls_completion_action_verify_certificate_chain); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: query_certificate_chain()\n"), + (m_is_client == true ? "client": "server"))); + + status = m_am_tls_services->query_certificate_chain( + &m_peer_certificate_authorities, + &m_peer_certificate_types, + m_selected_cipher_suite); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by + // complete_query_certificate_chain() call. + m_pending_query_certificate_chain = true; + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_query_certificate_chain() call. + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call is always completed on success. + status = eap_status_process_general_error; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else // All other status values means error, because this + // call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else if (m_is_client == false + && m_tls_peap_server_authenticates_client_action == true) + { + // This is server. + +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + if (m_tls_session_type == tls_session_type_full_authentication + && m_tls_use_identity_privacy == true + && certificate_chain->get_object_count() == 0ul) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: TLS identity privacy does not verify client certificate yet.\n"), + (m_is_client == true ? "client": "server"))); + status = eap_status_ok; + } + else +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: verify_certificate_chain()\n"), + (m_is_client == true ? "client": "server"))); + + status = m_am_tls_services->verify_certificate_chain( + &m_peer_certificate_chain, + m_selected_cipher_suite); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by + // complete_verify_certificate_chain() call. + m_pending_verify_certificate_chain = true; + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_verify_certificate_chain() call. + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call is always completed on success. + status = eap_status_process_general_error; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else // All other status values means error, because this + // call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + } + else if (m_is_client == false + && m_tls_peap_server_authenticates_client_action == false) + { + // This is server. Server allows anonymous client. + status = eap_status_ok; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (status == eap_status_completed_request) + { + status = eap_status_ok; + } + + if (m_is_client == true) + { + if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true) + { + set_state(tls_peap_state_wait_handshake_type_server_key_exchange); + } + else if (cipher_suite_is_TLS_RSA() == true) + { + set_state(tls_peap_state_wait_handshake_type_certificate_request_or_server_hello_done); + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); + } + } + else + { + // Server. + set_state(tls_peap_state_wait_handshake_type_client_key_exchange); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_handshake_type_certificate_request( + EAP_TEMPLATE_CONST tls_handshake_message_c * const handshake_message) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_handshake_type_certificate_request()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_handshake_type_certificate_request()"); + + EAP_ASSERT_ALWAYS(m_is_client == true); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | CT length | CT 1 | CT 2 | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | CT 3 | CT 4 | CAs length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | CA 1 length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | Distinguished name of Certificate Authority 1 | + // + + + // | | + // + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | CA 2 length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | Distinguished name of Certificate Authority 2 | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + eap_status_e status = eap_status_not_supported; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + { + EAP_TEMPLATE_CONST eap_array_c * const certificate_types + = handshake_message->get_certificate_types(); + + if (certificate_types->get_object_count() == 0ul) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + status = copy_simple( + certificate_types, + &m_peer_certificate_types, + m_am_tools, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + { + EAP_TEMPLATE_CONST eap_array_c * const certificate_authorities + = handshake_message->get_certificate_authorities(); + + if (certificate_authorities->get_object_count() == 0ul + && m_client_allows_empty_certificate_authorities_list == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + status = copy( + certificate_authorities, + &m_peer_certificate_authorities, + m_am_tools, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + } + + m_tls_peap_server_requested_client_certificate = true; + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + set_state(tls_peap_state_wait_handshake_type_server_hello_done); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_handshake_type_server_hello_done( + EAP_TEMPLATE_CONST tls_handshake_message_c * const /*handshake_message*/) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_handshake_type_server_hello_done()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_handshake_type_server_hello_done()"); + + EAP_ASSERT(m_is_client == true); + + eap_status_e status = eap_status_process_general_error; + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // + // ServerHelloDone message does not include payload. + + if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_RSA() == true + || cipher_suite_is_TLS_DHE_RSA() == true +#if defined(USE_FAST_EAP_TYPE) + || (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + if (m_tls_peap_server_requested_client_certificate == true) + { + status = completion_action_add(tls_completion_action_create_handshake_type_certificate); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + status = completion_action_add( + tls_completion_action_create_handshake_type_client_key_exchange); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = completion_action_add( + tls_completion_action_complete_create_handshake_type_client_key_exchange); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (m_tls_peap_server_authenticates_client_action == true +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + && ( + m_tls_use_identity_privacy == false + || (m_tls_session_type == tls_session_type_full_authentication + && m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_runs)) +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + ) + { + status = completion_action_add( + tls_completion_action_create_handshake_type_certificate_verify); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // This will complete creation of handshake_type_certificate_verify message. + status = completion_action_add( + tls_completion_action_complete_create_handshake_type_certificate_verify); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // Also the other pending messages will be processed after this action is completed. + eap_status_e compl_status = completion_action_add( + tls_completion_action_process_tls_records); + if (compl_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + status = completion_action_add( + tls_completion_action_create_change_cipher_spec_type_change_cipher_spec); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = completion_action_add(tls_completion_action_create_handshake_type_finished); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_cipher_suite); + } + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + set_state(tls_peap_state_wait_change_cipher_spec); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_handshake_type_server_key_exchange( + EAP_TEMPLATE_CONST tls_handshake_message_c * const handshake_message) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_handshake_type_server_key_exchange()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_handshake_type_server_key_exchange()"); + + eap_status_e status = eap_status_not_supported; + +#if EAP_TLS_UNSUPPORTED_CIPHER_SUITE + #error This one needs more code. RSA key exchange with different parameters is NOT supported. + if (cipher_suite_is_TLS_RSA() == true) + { + // RSA modulus and exponent are included when selected cipher suite + // is using RSA key exchange + // and parameters are different than included in the certificate. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | rsa_modulus length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | rsa_modulus | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | rsa_exponent length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + rsa_exponent + + // | | + // + + + // | | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | digitally-signed MD5 hash 16 bytes | + // + (ClientHello.random + ServerHello.random + ServerParams) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | digitally-signed SHA-1 hash 20 bytes | + // + (ClientHello.random + ServerHello.random + ServerParams) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); + } + else +#endif + if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true) + { + // Diffie-Hellman prime modulus, generator and server's + // Diffie-Hellman public value (g^X mod p) + // are included when selected cipher suite is ephemeral Diffie-Hellman key exchange. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH p length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH p value (prime modulus) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH g length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH g value (generator) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH Ys length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH Ys value | + // + (server's Diffie-Hellman public value) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | digitally-signed SHA-1 hash 47 bytes | + // + (ClientHello.random + ServerHello.random + ServerParams) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (handshake_message->get_dhe_prime() == 0 + || handshake_message->get_dhe_prime()->get_is_valid_data() == false + || handshake_message->get_dhe_prime()->get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + if (handshake_message->get_dhe_group_generator() == 0 + || handshake_message->get_dhe_group_generator()->get_is_valid_data() == false + || handshake_message->get_dhe_group_generator()->get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + if (handshake_message->get_public_dhe_key() == 0 + || handshake_message->get_public_dhe_key()->get_is_valid_data() == false + || handshake_message->get_public_dhe_key()->get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + if (handshake_message->get_signed_message_hash() == 0 + || handshake_message->get_signed_message_hash()->get_is_valid_data() == false + || handshake_message->get_signed_message_hash()->get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + status = m_dhe_prime.set_copy_of_buffer(handshake_message->get_dhe_prime()); + if (status != eap_status_ok + || m_dhe_prime.get_is_valid_data() == false + || m_dhe_prime.get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + status = m_dhe_group_generator.set_copy_of_buffer( + handshake_message->get_dhe_group_generator()); + if (status != eap_status_ok + || m_dhe_group_generator.get_is_valid_data() == false + || m_dhe_group_generator.get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + status = m_peer_public_dhe_key.set_copy_of_buffer(handshake_message->get_public_dhe_key()); + if (status != eap_status_ok + || m_peer_public_dhe_key.get_is_valid_data() == false + || m_peer_public_dhe_key.get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true) + { + // We must verify the signature of ServerKeyExchange. + status = verify_signature_of_server_key_exchange( + handshake_message->get_signed_message_hash()); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by + // complete_query_certificate_chain() call. + m_pending_verify_with_public_key = true; + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_query_certificate_chain() call. + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call is always completed on success. + status = eap_status_process_general_error; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else // All other status values means error, because this call + // is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); + } + } +#if defined(USE_FAST_EAP_TYPE) + else if (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) + { + // Diffie-Hellman prime modulus, generator and server's + // Diffie-Hellman public value (g^X mod p) + // are included when selected cipher suite is ephemeral Diffie-Hellman key exchange. + // NOTE: Here are no signed hash. This is not authenticated at all and vulnerable to + // man-in-the-middle attacks. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH p length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH p value (prime modulus) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH g length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH g value (generator) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH Ys length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH Ys value | + // + (server's Diffie-Hellman public value) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: analyse_handshake_type_server_key_exchange() no m_signed_message_hash\n"))); + + if (handshake_message->get_dhe_prime() == 0 + || handshake_message->get_dhe_prime()->get_is_valid_data() == false + || handshake_message->get_dhe_prime()->get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + if (handshake_message->get_dhe_group_generator() == 0 + || handshake_message->get_dhe_group_generator()->get_is_valid_data() == false + || handshake_message->get_dhe_group_generator()->get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + if (handshake_message->get_public_dhe_key() == 0 + || handshake_message->get_public_dhe_key()->get_is_valid_data() == false + || handshake_message->get_public_dhe_key()->get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + status = m_dhe_prime.set_copy_of_buffer(handshake_message->get_dhe_prime()); + if (status != eap_status_ok + || m_dhe_prime.get_is_valid_data() == false + || m_dhe_prime.get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + status = m_dhe_group_generator.set_copy_of_buffer( + handshake_message->get_dhe_group_generator()); + if (status != eap_status_ok + || m_dhe_group_generator.get_is_valid_data() == false + || m_dhe_group_generator.get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + status = m_peer_public_dhe_key.set_copy_of_buffer(handshake_message->get_public_dhe_key()); + if (status != eap_status_ok + || m_peer_public_dhe_key.get_is_valid_data() == false + || m_peer_public_dhe_key.get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + } +#endif //#if defined(USE_FAST_EAP_TYPE) + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (/* status == eap_status_pending_request + ||*/ status == eap_status_completed_request) + { + status = eap_status_ok; + } + + // Next we wait certificate_request or server_hello_done + // If next message is certificate_request, server requires client authentication. + // If next message is server_hello_done, server does NOT require client authentication. + set_state(tls_peap_state_wait_handshake_type_certificate_request_or_server_hello_done); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_handshake_type_client_key_exchange( + EAP_TEMPLATE_CONST tls_handshake_message_c * const handshake_message) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_handshake_type_client_key_exchange()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_handshake_type_client_key_exchange()"); + + eap_status_e status = eap_status_not_supported; + + + if (cipher_suite_is_TLS_RSA() == true) + { + // Encrypted premaster secret is included when selected cipher suite + // is using RSA key exchange. + // First two bytes are version of TLS. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // +-+-+-+-+-+-+-+-+ + + // | | + // + + + // | Encrypted Premaster Secret (48 bytes) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (handshake_message->get_encrypted_premaster_secret() == 0 + || handshake_message->get_encrypted_premaster_secret()->get_is_valid_data() == false + || handshake_message->get_encrypted_premaster_secret()->get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: rsa_decrypt_with_private_key()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: analyse_handshake_type_client_key_exchange(): encrypted premaster_secret"), + handshake_message->get_encrypted_premaster_secret()->get_data(), + handshake_message->get_encrypted_premaster_secret()->get_data_length())); + + status = m_am_tls_services->rsa_decrypt_with_private_key( + handshake_message->get_encrypted_premaster_secret()); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by + // complete_rsa_decrypt_with_private_key() call. + m_pending_rsa_decrypt_with_private_key = true; + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_rsa_decrypt_with_private_key() call. + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call is always completed on success. + status = eap_status_process_general_error; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else // All other status values means error, because this call + // is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true +#if defined(USE_FAST_EAP_TYPE) + || (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + // Diffie-Hellman prime modulus, generator and server's + // Diffie-Hellman public value (g^X mod p) + // are included when selected cipher suite is ephemeral Diffie-Hellman key exchange. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH p length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH p value (prime modulus) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH g length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH g value (generator) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH Ys length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH Ys value | + // + (server's Diffie-Hellman public value) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (handshake_message->get_public_dhe_key() == 0 + || handshake_message->get_public_dhe_key()->get_is_valid_data() == false + || handshake_message->get_public_dhe_key()->get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + status = m_peer_public_dhe_key.set_copy_of_buffer(handshake_message->get_public_dhe_key()); + if (status != eap_status_ok + || m_peer_public_dhe_key.get_is_valid_data() == false + || m_peer_public_dhe_key.get_data_length() == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + + // We must generate premaster secret. + status = generate_premaster_secret(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // We must generate master secret. + status = generate_master_secret(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // We must generate the key material. + status = generate_key_material(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (/*status == eap_status_pending_request + ||*/ status == eap_status_completed_request) + { + status = eap_status_ok; + } + + if (m_tls_peap_server_authenticates_client_action == true) + { + set_state(tls_peap_state_wait_handshake_type_certificate_verify); + } + else + { + set_state(tls_peap_state_wait_change_cipher_spec); + } + + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_handshake_type_certificate_verify( + EAP_TEMPLATE_CONST tls_handshake_message_c * const handshake_message) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_handshake_type_certificate_verify()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_handshake_type_certificate_verify()"); + + eap_status_e status = eap_status_not_supported; + + if (cipher_suite_is_TLS_RSA() == true + || cipher_suite_is_TLS_DHE_RSA() == true + || cipher_suite_is_TLS_DHE_DSS() == true) + { + // Signatures when RSA is used: + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // +-+-+-+-+-+-+-+-+ + + // | | + // + Signed MD5 hash + + // | (16 bytes) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + Signed SHA hash + + // | (20 bytes) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // Signature when DSA is used: + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // +-+-+-+-+-+-+-+-+ + + // | | + // + Signed SHA hash + + // | (48 bytes) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + eap_variable_data_c signed_certificate_verify_hash(m_am_tools); + + status = signed_certificate_verify_hash.set_copy_of_buffer( + handshake_message->get_signed_message_hash()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (signed_certificate_verify_hash.get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + eap_variable_data_c message_hash(m_am_tools); + + status = message_hash_create( + true, + tls_handshake_type_certificate_verify, + &message_hash, + true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: analyse_handshake_type_certificate_verify()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: analyse_handshake_type_certificate_verify(): message_hash"), + message_hash.get_data(message_hash.get_data_length()), + message_hash.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: analyse_handshake_type_certificate_verify(): signed_certificate_verify_hash"), + signed_certificate_verify_hash.get_data( + signed_certificate_verify_hash.get_data_length()), + signed_certificate_verify_hash.get_data_length())); + + status = m_am_tls_services->verify_with_public_key( + &message_hash, + &signed_certificate_verify_hash); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by + // complete_query_certificate_chain() call. + m_pending_verify_with_public_key = true; + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_query_certificate_chain() call. + status = eap_status_ok; + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call is always completed on success. + status = eap_status_process_general_error; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else // All other status values means error, because this call + // is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + set_state(tls_peap_state_wait_change_cipher_spec); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_handshake_type_finished( + EAP_TEMPLATE_CONST tls_handshake_message_c * const handshake_message, + const u8_t received_eap_identifier) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_handshake_type_finished()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_handshake_type_finished()"); + + eap_status_e status = eap_status_not_supported; + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (handshake_message->get_finished_data() == 0 + || handshake_message->get_finished_data()->get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + eap_variable_data_c message_hash(m_am_tools); + + bool client_originated_message = true; + if (m_is_client == true) + { + client_originated_message = false; + } + + status = message_hash_create_finished(client_originated_message, &message_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (message_hash.compare(handshake_message->get_finished_data()) != 0) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: analyse_handshake_type_finished(): ") + EAPL("verify check finished data failed, m_tls_session_type=%d=%s.\n"), + (m_is_client == true ? "client": "server"), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type) + )); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_authentication_failure); + } + else + { + EAP_TRACE_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: analyse_handshake_type_finished(): ") + EAPL("verify check finished data OK, m_tls_session_type=%d=%s.\n"), + (m_is_client == true ? "client": "server"), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type))); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if ((m_is_client == false + && m_tls_session_type == tls_session_type_full_authentication) + || (m_is_client == true + && (m_tls_session_type == tls_session_type_original_session_resumption + || m_tls_session_type == tls_session_type_stateless_session_resumption +#if defined(USE_FAST_EAP_TYPE) + || m_tls_session_type == tls_session_type_eap_fast_pac_session_resumption +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + ) + ) + { + // We need to send ChangeCipherSpec and Handshake/Finished. + +#if defined(USE_EAP_TLS_SESSION_TICKET) + if ( + m_is_client == false +#if defined(USE_FAST_EAP_TYPE) + && m_eap_type != eap_type_fast +#endif //#if defined(USE_FAST_EAP_TYPE) +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + && (m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_none + || m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_runs) +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + && m_tls_session_type == tls_session_type_full_authentication + && tls_extension_c::get_tls_extension( + tls_extension_type_session_ticket, + &m_supported_tls_extensions, + m_am_tools) != 0) + { + { + const tls_extension_c * const supported_session_ticket_extension = tls_extension_c::get_tls_extension( + tls_extension_type_session_ticket, + &m_supported_tls_extensions, + m_am_tools); + EAP_UNREFERENCED_PARAMETER(supported_session_ticket_extension); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: analyse_handshake_type_finished(): ") + EAPL("SST: Server will send a new session ticket to client, length = %d.\n"), + (m_is_client == true ? "client": "server"), + supported_session_ticket_extension->get_data_length())); + } + + // Server will send a new session ticket to client. + status = completion_action_add( + tls_completion_action_create_handshake_type_new_session_ticket); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + + status = completion_action_add( + tls_completion_action_create_change_cipher_spec_type_change_cipher_spec); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = completion_action_add(tls_completion_action_create_handshake_type_finished); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + if (m_is_client == false + && m_tls_session_type == tls_session_type_full_authentication + && m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_negotiates) + { + status = completion_action_add(tls_completion_action_create_handshake_type_hello_request); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + + status = completion_action_add(tls_completion_action_check_sent_tls_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } +#if defined(USE_FAST_EAP_TYPE) + else if (m_is_client == false + && m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) + { + status = completion_action_add( + tls_completion_action_create_change_cipher_spec_type_change_cipher_spec); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = completion_action_add(tls_completion_action_create_handshake_type_finished); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = completion_action_add(tls_completion_action_check_sent_tls_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } +#endif //#if defined(USE_FAST_EAP_TYPE) + + +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + if (m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_none + || m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_runs + || m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_negotiates + ) +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + { + // Authentication OK. + status = completion_action_add(tls_completion_action_finish_handshake); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = completion_action_add(tls_completion_action_process_tls_records); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + +#if defined(USE_FAST_EAP_TYPE) + if (m_is_client == false + && m_eap_type == eap_type_fast + && m_tls_session_type == tls_session_type_eap_fast_pac_session_resumption) + { + status = completion_action_add(tls_completion_action_check_tunnel_authentication_runs); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } +#endif //#if defined(USE_FAST_EAP_TYPE) + } + + m_received_eap_identifier = received_eap_identifier; + + + set_state(tls_peap_state_process_pending_tls_completions); + + if (status == eap_status_ok) + { + status = check_sent_tls_message(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +#if defined(USE_EAP_TLS_SESSION_TICKET) + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_handshake_type_new_session_ticket( + EAP_TEMPLATE_CONST tls_handshake_message_c * const handshake_message, + const u8_t /* received_eap_identifier */) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_handshake_type_new_session_ticket()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_handshake_type_new_session_ticket()"); + + eap_status_e status = eap_status_not_supported; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TEMPLATE_CONST eap_array_c * const tls_extensions + = handshake_message->get_tls_extensions(); + + if (tls_extensions == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + const tls_extension_c * const session_ticket = tls_extension_c::get_tls_extension( + tls_extension_type_session_ticket, + tls_extensions, + m_am_tools); + + if (session_ticket == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + m_received_tls_extensions.reset(); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: analyse_handshake_type_new_session_ticket(): ") + EAPL("SST: session ticket received, length = %d.\n"), + (m_is_client == true ? "client": "server"), + session_ticket->get_data_length())); + + tls_extension_c * const copy_of_session_ticket = session_ticket->copy(); + + if (copy_of_session_ticket == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = m_received_tls_extensions.add_object(copy_of_session_ticket, true); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_tls_protocol_change_cipher_spec( + const tls_record_message_c * const record) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_tls_protocol_change_cipher_spec()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_tls_protocol_change_cipher_spec()"); + + eap_status_e status = eap_status_not_supported; + + u32_t ind_change_cipher_spec = 0ul; + + for (ind_change_cipher_spec = 0ul + ; ind_change_cipher_spec < record->get_change_cipher_spec_count() + ; ind_change_cipher_spec++) + { + const tls_change_cipher_spec_message_c * const change_cipher_spec_message + = record->get_change_cipher_spec(ind_change_cipher_spec); + + switch (change_cipher_spec_message->get_change_cipher_spec_type()) + { + case tls_change_cipher_spec_type_change_cipher_spec: + + if (m_tls_session_type == tls_session_type_stateless_session_resumption +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + || (m_tls_session_type == tls_session_type_full_authentication + && m_tls_use_identity_privacy == true + && m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_runs) +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + ) + { + // We must generate the key material. + status = generate_key_material(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + // We change the receive cipher suite. + status = change_cipher_spec(false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else + { + set_state(tls_peap_state_wait_handshake_type_finished); + } + + break; + + default: + + set_state(tls_peap_state_failure); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); + } // switch() + + } // for() + + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_tls_protocol_alert( + const tls_record_message_c * const record) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_tls_protocol_alert()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_tls_protocol_alert()"); + + eap_status_e status = eap_status_authentication_failure; + + u32_t ind_alert = 0ul; + + m_new_tls_message.reset(); + + + for (ind_alert = 0ul + ; ind_alert < record->get_alert_count() + ; ind_alert++) + { + const tls_alert_message_c * const alert_message + = record->get_alert(ind_alert); + + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: %s: EAP_type_TLS_PEAP: Alert message %s:%s\n"), + (m_is_client == true) ? "client": "server", + eap_tls_trace_string_c::get_alert_level_string(alert_message->get_alert_level()), + eap_tls_trace_string_c::get_alert_description_string(alert_message->get_alert_description()))); + + if (m_application != 0) + { + // Indication to TLS-application. + (void) m_application->alert_received( + alert_message->get_alert_level(), + alert_message->get_alert_description()); + } + + // indication to TLS AM. + m_am_tls_services->alert_received( + alert_message->get_alert_level(), + alert_message->get_alert_description()); + + switch (alert_message->get_alert_description()) + { + case tls_alert_description_close_notify: + break; + case tls_alert_description_unexpected_message: + // This message is always fatal. + break; + case tls_alert_description_bad_record_mac: + // This message is always fatal. + break; + case tls_alert_description_decryption_failed: + // This message is always fatal. + break; + case tls_alert_description_record_overflow: + // This message is always fatal. + break; + case tls_alert_description_decompression_failure: + // This message is always fatal. + break; + case tls_alert_description_handshake_failure: + // This message is always fatal. + break; + case tls_alert_description_bad_certificate: + break; + case tls_alert_description_unsupported_certificate: + break; + case tls_alert_description_certificate_revoked: + break; + case tls_alert_description_certificate_expired: + break; + case tls_alert_description_certificate_unknown: + break; + case tls_alert_description_illegal_parameter: + // This message is always fatal. + break; + case tls_alert_description_unknown_ca: + // This message is always fatal. + break; + case tls_alert_description_access_denied: + // This message is always fatal. + break; + case tls_alert_description_decode_error: + // This message is always fatal. + break; + case tls_alert_description_decrypt_error: + break; + case tls_alert_description_export_restriction: + // This message is always fatal. + break; + case tls_alert_description_protocol_version: + // This message is always fatal. + break; + case tls_alert_description_insufficient_security: + // This message is always fatal. + break; + case tls_alert_description_internal_error: + // This message is always fatal. + break; + case tls_alert_description_user_canceled: + break; + case tls_alert_description_no_renegotiation: + // This message is always a warning. + break; + case tls_alert_description_none: + break; + default: + break; + } // switch() + + } // for() + + + set_state(tls_peap_state_failure); + + // This will cause the session terminate immediately. + status = get_type_partner()->set_session_timeout(0ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + + { + eap_state_notification_c notification( + m_am_tools, + &m_send_network_id, + m_is_client, + eap_state_notification_generic, + eap_protocol_layer_internal_type, + 0, + tls_peap_state_none, + eap_state_authentication_terminated_unsuccessfully, + 0, + false); + + notification.set_authentication_error(eap_status_authentication_failure); + + get_type_partner()->state_notification(¬ification); + } + + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT tls_record_protocol_e tls_record_c::get_next_tls_record_message_protocol() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::get_next_tls_record_message_protocol()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::get_next_tls_record_message_protocol()"); + + tls_record_protocol_e record_protocol(tls_record_protocol_none); + + if (m_received_tls_message.get_record_message_count() <= m_received_tls_message.get_analyse_index()+1ul) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return record_protocol; + } + + tls_record_message_c * const tls_record_message + = m_received_tls_message.get_record_message(m_received_tls_message.get_analyse_index()+1ul); + if (tls_record_message == 0 + || tls_record_message->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return record_protocol; + } + + const u32_t tls_record_length = tls_record_message->get_record_message_data()->get_data_length(); + + if (tls_record_message->get_record_message_data()->get_data_length() < tls_record_header_c::get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return record_protocol; + } + + tls_record_header_c tls_record_header( + m_am_tools, + tls_record_message->get_record_message_data()->get_data( + tls_record_header_c::get_header_length()), + tls_record_length); + + if (tls_record_header.get_is_valid() == false + || tls_record_length < tls_record_header.get_data_length() + || tls_record_length + < tls_record_header.get_header_length() + + tls_record_header.get_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return record_protocol; + } + + record_protocol = tls_record_header.get_protocol(); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: ends: tls_record_c::get_next_tls_record_message_protocol(): %d=%s\n"), + (m_is_client == true ? "client": "server"), + record_protocol, + tls_record_header_c::get_tls_protocol_string(record_protocol))); + + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return record_protocol; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT tls_handshake_type_e tls_record_c::get_next_tls_handshake_message_type() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::get_next_tls_handshake_message_type()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::get_next_tls_handshake_message_type()"); + + tls_handshake_type_e handshake_type(tls_handshake_type_none); + + if (m_received_tls_message.get_record_message_count() <= m_received_tls_message.get_analyse_index()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return handshake_type; + } + + tls_record_message_c * const tls_record_message + = m_received_tls_message.get_record_message(m_received_tls_message.get_analyse_index()); + if (tls_record_message == 0 + || tls_record_message->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return handshake_type; + } + + const u32_t tls_record_length = tls_record_message->get_record_message_data()->get_data_length(); + + if (tls_record_message->get_record_message_data()->get_data_length() < tls_record_header_c::get_header_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return handshake_type; + } + + tls_record_header_c tls_record_header( + m_am_tools, + tls_record_message->get_record_message_data()->get_data( + tls_record_header_c::get_header_length()), + tls_record_length); + + if (tls_record_header.get_is_valid() == false + || tls_record_length < tls_record_header.get_data_length() + || tls_record_length + < tls_record_header.get_header_length() + + tls_record_header.get_data_length()) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return handshake_type; + } + + tls_record_protocol_e tls_protocol(tls_record_header.get_protocol()); + + if (tls_protocol == tls_record_protocol_handshake) + { + if (tls_record_message->get_handshake_count() <= tls_record_message->get_analyse_index()+1ul) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return handshake_type; + } + + tls_handshake_message_c * const handshake_message = tls_record_message->get_handshake(tls_record_message->get_analyse_index()+1ul); + + if (handshake_message == 0 + || handshake_message->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return handshake_type; + } + + handshake_type = handshake_message->get_handshake_type(); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: ends: tls_record_c::get_next_tls_handshake_message_type(): %d=%s\n"), + (m_is_client == true ? "client": "server"), + handshake_type, + tls_handshake_header_c::get_tls_handshake_string(handshake_type))); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return handshake_type; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_tls_protocol_handshake( + tls_record_message_c * const record, + const u8_t received_eap_identifier) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_tls_protocol_handshake()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_tls_protocol_handshake()"); + + eap_status_e status = eap_status_ok; + + u32_t ind_handshake = 0ul; + + for (ind_handshake = record->get_analyse_index() + ; ind_handshake < record->get_handshake_count() + ; ind_handshake++) + { + // This is used in EAP-FAST to see the next TLS-handshake message type. + record->save_analyse_index(ind_handshake); + + tls_handshake_message_c * const handshake_message = record->get_handshake(ind_handshake); + + if (handshake_message->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: analyse_tls_protocol_handshake(): ") + EAPL("handshake type %d, analysed %d\n"), + (m_is_client == true ? "client": "server"), + handshake_message->get_handshake_type(), + handshake_message->get_is_analysed())); + + if (handshake_message->get_is_analysed() == false) + { + handshake_message->set_is_analysed(); + + switch (handshake_message->get_handshake_type()) + { + case tls_handshake_type_hello_request: + status = analyse_handshake_type_hello_request( + handshake_message); + break; + case tls_handshake_type_client_hello: + if (m_tls_peap_test_version == true + && verify_state(tls_peap_state_tls_success) == true) + { + // OK, this is test version. + } + else if (verify_state(tls_peap_state_wait_handshake_type_client_hello) == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: function: verify_state(): current state %s != %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string( + tls_peap_state_wait_handshake_type_client_hello))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + + status = analyse_handshake_type_client_hello( + handshake_message); + break; + case tls_handshake_type_server_hello: + if (verify_state(tls_peap_state_wait_handshake_type_server_hello) == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: function: verify_state(): current state %s != %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string( + tls_peap_state_wait_handshake_type_server_hello))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + + status = analyse_handshake_type_server_hello( + handshake_message); + break; + case tls_handshake_type_certificate: + if (m_tls_session_type == tls_session_type_stateless_session_resumption + && verify_state(tls_peap_state_wait_change_cipher_spec) == true) + { + // Server wish to initiate a full handshake. + m_tls_session_type = tls_session_type_full_authentication; + set_state(tls_peap_state_wait_handshake_type_certificate); + } + else if (verify_state(tls_peap_state_wait_handshake_type_certificate) == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: function: verify_state(): current state %s != %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string( + tls_peap_state_wait_handshake_type_certificate))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + + status = analyse_handshake_type_certificate( + handshake_message); + break; + case tls_handshake_type_server_key_exchange: + if (verify_state(tls_peap_state_wait_handshake_type_server_key_exchange) == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: function: verify_state(): current state %s != %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string( + tls_peap_state_wait_handshake_type_server_key_exchange))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + + status = analyse_handshake_type_server_key_exchange( + handshake_message); + break; + case tls_handshake_type_certificate_request: + if (verify_state( + tls_peap_state_wait_handshake_type_certificate_request_or_server_hello_done) + == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: function: verify_state(): current state %s != %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string( + tls_peap_state_wait_handshake_type_certificate_request_or_server_hello_done))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + + status = analyse_handshake_type_certificate_request( + handshake_message); + break; + case tls_handshake_type_server_hello_done: + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: analyse_tls_protocol_handshake(): m_tls_peap_server_authenticates_client_policy_flag=%d\n"), + (m_is_client == true ? "client": "server"), + m_tls_peap_server_authenticates_client_policy_flag)); + + if (verify_state( + tls_peap_state_wait_handshake_type_certificate_request_or_server_hello_done) + == true) + { + if (m_tls_peap_server_authenticates_client_policy_flag == false) + { + // Client accepts server only authentication. + m_tls_peap_server_authenticates_client_action = false; + } + else + { + // ERROR: Client does NOT accept server only authentication. + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: function: current state %s: ") + EAPL("Client does NOT accept server only authentication.\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_insufficient_security); + } + } + else if (verify_state(tls_peap_state_wait_handshake_type_server_hello_done) + == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: function: verify_state(): current state %s != %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string( + tls_peap_state_wait_handshake_type_server_hello_done))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + + status = analyse_handshake_type_server_hello_done( + handshake_message); + break; + case tls_handshake_type_certificate_verify: + if (verify_state(tls_peap_state_wait_handshake_type_certificate_verify) == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: function: verify_state(): current state %s != %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string( + tls_peap_state_wait_handshake_type_certificate_verify))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + + status = analyse_handshake_type_certificate_verify( + handshake_message); + break; + case tls_handshake_type_client_key_exchange: + if (verify_state(tls_peap_state_wait_handshake_type_client_key_exchange) == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: function: verify_state(): current state %s != %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string( + tls_peap_state_wait_handshake_type_client_key_exchange))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + + status = analyse_handshake_type_client_key_exchange( + handshake_message); + break; + case tls_handshake_type_finished: + if (verify_state(tls_peap_state_wait_handshake_type_finished) == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: function: verify_state(): current state %s != %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string( + tls_peap_state_wait_handshake_type_finished))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + + status = analyse_handshake_type_finished( + handshake_message, + received_eap_identifier); + break; +#if defined(USE_EAP_TLS_SESSION_TICKET) + case tls_handshake_type_new_session_ticket: + { + // Note This is optional Handshake message. + + const tls_extension_c * const supported_session_ticket_extension = tls_extension_c::get_tls_extension( + tls_extension_type_session_ticket, + &m_supported_tls_extensions, + m_am_tools); + + if (supported_session_ticket_extension != 0 + && (verify_state(tls_peap_state_wait_change_cipher_spec) == true + || verify_state(tls_peap_state_wait_handshake_type_new_session_ticket) == true)) + { + // OK new Session ticket handshake allowed. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: function: verify_state(): SST: current state %s == %s: Session Ticket Handshake allowed, length = %d.\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string( + tls_peap_state_wait_handshake_type_new_session_ticket), + supported_session_ticket_extension->get_data_length())); + } + else if (verify_state(tls_peap_state_wait_handshake_type_new_session_ticket) == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: function: verify_state(): SST: current state %s != %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_state_string( + tls_peap_state_wait_handshake_type_new_session_ticket))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + + status = analyse_handshake_type_new_session_ticket( + handshake_message, + received_eap_identifier); + break; + } +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + default: + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); + } // switch() + } + + if (status == eap_status_pending_request) + { + // Save pending state. + record->save_analyse_index(ind_handshake); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if ((get_is_tunneled_tls() == false + && m_tls_peap_state == tls_peap_state_tls_success) + || (get_is_tunneled_tls() == true + && m_tls_peap_state == tls_peap_state_peap_tunnel_ready)) + { + // Stop processing TLS-records. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } // for() + + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::analyse_tls_protocol_application_data( + const tls_record_message_c * const record, + const u8_t received_eap_identifier) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_tls_protocol_application_data()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::analyse_tls_protocol_application_data()"); + + eap_status_e status = eap_status_ok; + + u32_t ind; + for (ind = 0ul + ; ind < record->get_application_data_count() + ; ind++) + { + tls_application_data_message_c * const application_data_message + = record->get_application_data(ind); + if (application_data_message == 0 + || application_data_message->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + if (application_data_message->get_is_analysed() == false) + { + application_data_message->set_is_analysed(); + + if (m_application == 0) + { + // ERROR: No application. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: message_function: starts: tls_record_c::analyse_tls_protocol_application_data(): no application.\n"), + (m_is_client == true ? "client": "server"))); + status = eap_status_illegal_data_payload; + } + else + { + status = m_application->packet_process( + application_data_message->get_application_data(), + received_eap_identifier); + } + + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::analyse_tls_protocol_application_data(): already analysed.\n"), + (m_is_client == true ? "client": "server"))); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::are_pending_queries_completed() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_pending_request; + + eap_status_string_c status_string; + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pending_function: starts: tls_record_c::are_pending_queries_completed(): %s\n"), + (m_is_client == true ? "client": "server"), + status_string.get_status_string(status))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::are_pending_queries_completed()"); + + if (m_pending_query_certificate_authorities_and_types == false + && m_pending_query_certificate_chain == false + && m_pending_query_cipher_suites_and_previous_session == false + && m_pending_query_dh_parameters == false + && m_pending_query_realm == false + && m_pending_select_cipher_suite_and_check_session_id == false + && m_pending_verify_certificate_chain == false + && m_pending_rsa_decrypt_with_private_key == false + && m_pending_rsa_encrypt_with_public_key == false + && m_pending_sign_with_private_key == false + && m_pending_verify_with_public_key == false + && m_pending_query_tunnel_PAC == false) + { + status = eap_status_ok; + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pending_function: are_pending_queries_completed(): %s\n"), + (m_is_client == true ? "client": "server"), + status_string.get_status_string(status))); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::indicate_state_to_lower_layer( + const tls_peap_state_e indicated_state) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + // Notify lower layer the state of TLS. + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: state_function: starts: tls_record_c::indicate_state_to_lower_layer(): m_tls_session_type=%d=%s, state=%d=%s\n"), + (m_is_client == true ? "client": "server"), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + indicated_state, + eap_tls_trace_string_c::get_state_string(indicated_state))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::indicate_state_to_lower_layer()"); + + +#if defined(USE_EAP_TRACE_ALWAYS) + + if (m_tls_peap_state == tls_peap_state_tls_success) + { + + tls_identity_privacy_handshake_state_e tmp_identity_privacy_handshake_state = +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + m_tls_identity_privacy_handshake_state; +#else + tls_identity_privacy_handshake_state_none; +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + + EAP_TRACE_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: indicate_state_to_lower_layer(): TLS/PEAP authentication ") + EAPL("SUCCESS: %s, %s, tunnel %d, tunneling type %s, tunneling version %s, cipher_suite %s, %s\n"), + (m_is_client == true ? "client": "server"), + (m_tls_peap_server_authenticates_client_action == true + ? "mutual": "anonymous client"), + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + get_is_tunneled_tls(), + eap_header_string_c::get_eap_type_string(m_eap_type), + eap_tls_trace_string_c::get_peap_version_string(m_peap_version), + eap_tls_trace_string_c::get_cipher_suite_string(m_selected_cipher_suite), + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(tmp_identity_privacy_handshake_state))); + } + else if (m_tls_peap_state == tls_peap_state_peap_tunnel_ready + || m_tls_peap_state == tls_peap_state_wait_application_data) + { + EAP_TRACE_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: indicate_state_to_lower_layer(): TLS/PEAP authentication ") + EAPL("tunnel ready: %s, %s, tunnel %d, tunneling type %s, tunneling version %s, cipher_suite %s\n"), + (m_is_client == true ? "client": "server"), + (m_tls_peap_server_authenticates_client_action == true + ? "mutual": "anonymous client"), + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + get_is_tunneled_tls(), + eap_header_string_c::get_eap_type_string(m_eap_type), + eap_tls_trace_string_c::get_peap_version_string(m_peap_version), + eap_tls_trace_string_c::get_cipher_suite_string(m_selected_cipher_suite))); + + } + else if (m_tls_peap_state == tls_peap_state_failure) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: indicate_state_to_lower_layer(): TLS/PEAP authentication ") + EAPL("FAILED: %s, %s, tunnel %d, tunneling type %s, tunneling version %s, cipher_suite %s\n"), + (m_is_client == true ? "client": "server"), + (m_tls_peap_server_authenticates_client_action == true ? "mutual": "anonymous client"), + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + get_is_tunneled_tls(), + eap_header_string_c::get_eap_type_string(m_eap_type), + eap_tls_trace_string_c::get_peap_version_string(m_peap_version), + eap_tls_trace_string_c::get_cipher_suite_string(m_selected_cipher_suite))); + } + +#endif //#if !defined(USE_EAP_TRACE_ALWAYS) + + + eap_state_notification_c notification( + m_am_tools, + &m_send_network_id, + m_is_client, + eap_state_notification_generic, + eap_protocol_layer_internal_type, + 0, + tls_peap_state_none, + indicated_state, + 0, + false); + get_type_partner()->state_notification(¬ification); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::indicate_messages_processed() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + // Notify lower layer that TLS-messages are processed. + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: state_function: starts: tls_record_c::indicate_messages_processed(): %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::indicate_messages_processed()"); + + eap_state_notification_c notification( + m_am_tools, + &m_send_network_id, + m_is_client, + eap_state_notification_generic, + eap_protocol_layer_internal_type, + 0, + tls_peap_state_none, + tls_peap_state_pending_tls_messages_processed, + 0, + false); + get_type_partner()->state_notification(¬ification); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::send_tls_message() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: send_function: starts: tls_record_c::send_tls_message()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::send_tls_message()"); + + eap_variable_data_c tls_message_buffer(m_am_tools); + + bool includes_tls_handshake_message = false; + + eap_status_e status = m_new_tls_message.add_message_data( + &tls_message_buffer, + &includes_tls_handshake_message); + if (status != eap_status_ok) + { + m_new_tls_message.reset(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + eap_buf_chain_wr_c sent_packet( + eap_write_buffer, + m_am_tools, + tls_message_buffer.get_data(tls_message_buffer.get_data_length()), + tls_message_buffer.get_data_length(), + false, + false, + 0ul); + if (sent_packet.get_is_valid() == false) + { + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("send TLS-message"), + sent_packet.get_data(sent_packet.get_data_length()), + sent_packet.get_data_length())); + + status = get_type_partner()->tls_peap_packet_send( + &sent_packet, + 0ul, + sent_packet.get_data_length(), + sent_packet.get_data_length(), + includes_tls_handshake_message + ); + + m_new_tls_message.reset(); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::check_sent_tls_message() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: send_function: starts: tls_record_c::check_sent_tls_message()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::check_sent_tls_message()"); + + eap_status_e msg_status = eap_status_authentication_failure; + + if (m_already_in_completion_action_check == true) + { + // This is recursive call. Do not process yet. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); + } + + if (m_force_tls_message_send == true) + { + // There may be an alert message pending. + msg_status = send_tls_message(); + } + else + { + msg_status = are_pending_queries_completed(); + if (msg_status == eap_status_ok) + { + eap_status_e compl_status = completion_action_check(); + + if (compl_status == eap_status_pending_request) + { + // Some asyncronous query is still pending. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, compl_status); + } + else if (compl_status != eap_status_ok) + { + // There may be Alert message to be sent. + msg_status = compl_status; + } + + + if (m_allow_message_send == true) + { + if (msg_status == eap_status_ok + && m_new_tls_message.get_record_message_count() > 0ul) + { + // We could send the pending TLS-messages. + msg_status = send_tls_message(); + } + else if (m_force_tls_message_send == true // There may be Alert message to be sent. + && m_new_tls_message.get_record_message_count() > 0ul) + { + // We could send the pending TLS-messages. + send_tls_message(); + } + else + { + // No message to sent. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: send_function: check_sent_tls_message(), ") + EAPL("No message to sent.\n"), + (m_is_client == true ? "client": "server"))); + } + } + + if (msg_status == eap_status_ok + && m_allow_message_send == true) + { + eap_status_e indication_status = indicate_messages_processed(); + if (indication_status != eap_status_ok) + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, indication_status); + } + } + } + } + + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, msg_status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::message_hash_init() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: hash_function: starts: tls_record_c::message_hash_init()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::message_hash_init()"); + + eap_status_e status = eap_status_not_supported; + + status = m_message_hash_md5.hash_init(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_message_hash_sha1.hash_init(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::message_hash_update( + const bool true_when_parse_message, + const tls_handshake_type_e type, + u8_t * const tls_packet, + const u32_t tls_packet_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + +#if !defined(USE_EAP_DEBUG_TRACE) +EAP_UNREFERENCED_PARAMETER(true_when_parse_message); +EAP_UNREFERENCED_PARAMETER(type); +#endif + + eap_status_e status = eap_status_not_supported; + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: hash_function: starts: tls_record_c::message_hash_update(): handshake type %s, %s\n"), + (m_is_client == true ? "client": "server"), + tls_handshake_header_c::get_tls_handshake_string(type), + (true_when_parse_message == true ? "parse": "create"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::message_hash_update()"); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + EAP_TRACE_FLAGS_MESSAGE_DATA, + (EAPL("TLS: message_hash_update()"), + tls_packet, + tls_packet_length)); + + if (tls_packet == 0 + || tls_packet_length == 0ul) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + status = m_message_hash_md5.hash_update(tls_packet, tls_packet_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_message_hash_sha1.hash_update(tls_packet, tls_packet_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::message_hash_create( + const bool true_when_parse_message, + const tls_handshake_type_e type, + eap_variable_data_c * const message_hash, + const bool client_originated) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + +#if !defined(USE_EAP_DEBUG_TRACE) +EAP_UNREFERENCED_PARAMETER(true_when_parse_message); +#endif + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: hash_function: starts: tls_record_c::message_hash_create(): handshake type %s, %s\n"), + (m_is_client == true ? "client": "server"), + tls_handshake_header_c::get_tls_handshake_string(type), + (true_when_parse_message == true ? "parse": "create"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::message_hash_create()"); + + eap_status_e status = eap_status_not_supported; + + eap_variable_data_c * message_hash_md5 = 0; + eap_variable_data_c * message_hash_sha1 = 0; + + if (type == tls_handshake_type_certificate_verify) + { + message_hash_md5 = &m_message_hash_md5_certificate_verify; + message_hash_sha1 = &m_message_hash_sha1_certificate_verify; + } + else if (type == tls_handshake_type_finished) + { + if (client_originated == true) + { + message_hash_md5 = &m_client_message_hash_md5_finished; + message_hash_sha1 = &m_client_message_hash_sha1_finished; + } + else + { + message_hash_md5 = &m_server_message_hash_md5_finished; + message_hash_sha1 = &m_server_message_hash_sha1_finished; + } + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_type); + } + + u32_t md5_digest_length = message_hash_md5->get_data_length(); + + u32_t sha1_digest_length = message_hash_sha1->get_data_length(); + + if (cipher_suite_is_TLS_DHE_DSS() == true) + { + md5_digest_length = 0ul; + } + + status = message_hash->set_buffer_length(md5_digest_length+sha1_digest_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + message_hash->set_data_length(0ul); + + + + if (type == tls_handshake_type_certificate_verify) + { + if (cipher_suite_is_TLS_RSA() == true + || cipher_suite_is_TLS_DHE_RSA() == true) + { + status = message_hash->add_data(message_hash_md5); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + if (cipher_suite_is_TLS_RSA() == true + || cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true) + { + status = message_hash->add_data(message_hash_sha1); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + } + else if (type == tls_handshake_type_finished) + { + status = message_hash->add_data(message_hash_md5); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = message_hash->add_data(message_hash_sha1); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: message_hash_create(): message_hash"), + message_hash->get_data(message_hash->get_data_length()), + message_hash->get_data_length())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::message_hash_final( + eap_variable_data_c * const md5_digest, + eap_variable_data_c * const sha1_digest) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: hash_function: starts: tls_record_c::message_hash_final()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::message_hash_final()"); + + eap_status_e status = eap_status_process_general_error; + + if (md5_digest == 0 + || sha1_digest == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + + { + // The copy of hash context saves original hash context for later use. + // This way we do need store only one SHA1 and MD5 context for all handshake message hashes. + abs_crypto_hash_algorithm_c * const copy_message_hash_md5 = m_message_hash_md5.copy(); + + eap_automatic_variable_c + deletes_copy_message_hash_md5(m_am_tools, copy_message_hash_md5); + + if (copy_message_hash_md5 == 0 + || copy_message_hash_md5->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = md5_digest->set_buffer_length(copy_message_hash_md5->get_digest_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + md5_digest->set_data_length(copy_message_hash_md5->get_digest_length()); + + u32_t digest_length = md5_digest->get_data_length(); + + status = copy_message_hash_md5->hash_final( + md5_digest->get_data(md5_digest->get_data_length()), + &digest_length); + if (digest_length != copy_message_hash_md5->get_digest_length()) + { + status = eap_status_process_general_error; + } + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + + { + // The copy of hash context saves original hash context for later use. + // This way we do need store only one SHA1 and MD5 context for all handshake message hashes. + abs_crypto_hash_algorithm_c * const copy_message_hash_sha1 = m_message_hash_sha1.copy(); + + eap_automatic_variable_c + deletes_copy_message_hash_sha1(m_am_tools, copy_message_hash_sha1); + + if (copy_message_hash_sha1 == 0 + || copy_message_hash_sha1->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = sha1_digest->set_buffer_length(copy_message_hash_sha1->get_digest_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + sha1_digest->set_data_length(copy_message_hash_sha1->get_digest_length()); + + u32_t digest_length = sha1_digest->get_data_length(); + + status = copy_message_hash_sha1->hash_final( + sha1_digest->get_data(sha1_digest->get_data_length()), + &digest_length); + if (digest_length != copy_message_hash_sha1->get_digest_length()) + { + status = eap_status_process_general_error; + } + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::message_hash_save_certificate_verify() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: hash_function: starts: tls_record_c::message_hash_save_certificate_verify()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::message_hash_save_certificate_verify()"); + + eap_status_e status = eap_status_process_general_error; + + status = message_hash_final( + &m_message_hash_md5_certificate_verify, + &m_message_hash_sha1_certificate_verify); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::message_hash_save_finished( + const bool client_originated) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: hash_function: starts: tls_record_c::message_hash_save_finished()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::message_hash_save_finished()"); + + eap_variable_data_c *message_hash_md5_finished = &m_client_message_hash_md5_finished; + eap_variable_data_c *message_hash_sha1_finished = &m_client_message_hash_sha1_finished; + + eap_status_e status = eap_status_process_general_error; + + + if (client_originated == false) + { + message_hash_md5_finished = &m_server_message_hash_md5_finished; + message_hash_sha1_finished = &m_server_message_hash_sha1_finished; + } + + status = message_hash_final( + message_hash_md5_finished, + message_hash_sha1_finished); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::message_hash_create_finished( + const bool client_originated_message, + eap_variable_data_c * const message_hash) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: hash_function: starts: tls_record_c::message_hash_create_finished()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::message_hash_create_finished()"); + + eap_status_e status = eap_status_not_supported; + + eap_variable_data_c label_finished(m_am_tools); + if (label_finished.get_is_valid() == false) + { + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + if (client_originated_message == true) + { + status = label_finished.add_data( + TLS_CLIENT_FINISHED_LABEL, + TLS_CLIENT_FINISHED_LABEL_LENGTH); + } + else + { + status = label_finished.add_data( + TLS_SERVER_FINISHED_LABEL, + TLS_SERVER_FINISHED_LABEL_LENGTH); + } + + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + eap_variable_data_c hash(m_am_tools); + if (hash.get_is_valid() == false) + { + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = message_hash_create( + false, + tls_handshake_type_finished, + &hash, + client_originated_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: message_hash_create_finished(): m_master_secret"), + m_master_secret.get_data(), + m_master_secret.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: message_hash_create_finished(): label_finished"), + label_finished.get_data(), + label_finished.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: message_hash_create_finished(): hash"), + hash.get_data(), + hash.get_data_length())); + + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: prf_function: tls_prf.tls_prf_output()\n"), + (m_is_client == true ? "client": "server"))); + + crypto_tls_prf_c tls_prf(m_am_tools); + + status = tls_prf.tls_prf_init( + &m_master_secret, + &label_finished, + &hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = message_hash->set_buffer_length(TLS_FINISHED_DATA_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + message_hash->set_data_length(TLS_FINISHED_DATA_SIZE); + + status = tls_prf.tls_prf_output( + message_hash->get_data(message_hash->get_data_length()), + message_hash->get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: message_hash_create_finished(): message hash"), + message_hash->get_data(), + message_hash->get_data_length())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::packet_process( + eap_variable_data_c * const tls_packet, + const u8_t received_eap_identifier) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + + tls_identity_privacy_handshake_state_e tmp_identity_privacy_handshake_state = +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + m_tls_identity_privacy_handshake_state; +#else + tls_identity_privacy_handshake_state_none; +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + EAP_UNREFERENCED_PARAMETER(tmp_identity_privacy_handshake_state); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::packet_process(): state %s, privacy_handshake_state=%d=%s, session_type=%s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + tmp_identity_privacy_handshake_state, + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(tmp_identity_privacy_handshake_state), + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::packet_process()"); + + m_received_tls_message.reset(); + + eap_status_e status = m_received_tls_message.set_tls_message_data( + tls_packet, + received_eap_identifier); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + eap_automatic_simple_value_c restore_allow_message_send( + m_am_tools, + &m_allow_message_send, + true); + + // Packet send is delayed until after the process_tls_message() function returns. + m_allow_message_send = false; + + status = process_tls_message(); + + m_allow_message_send = true; + + + if (status != eap_status_pending_request) + { + // Note this call will return eap_status_pending_request if any asyncronous call is pending. + eap_status_e send_status = check_sent_tls_message(); + if (send_status != eap_status_ok) + { + status = send_status; + } + } + + if (status == eap_status_success + && m_tls_peap_state != tls_peap_state_tls_success) + { + status = eap_status_ok; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::plain_eap_success_failure_packet_received( + const eap_am_network_id_c * const receive_network_id, + const eap_code_value_e received_eap_code, + const u8_t received_eap_identifier) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::plain_eap_success_failure_packet_received(): state %s, m_tls_session_type=%s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::plain_eap_success_failure_packet_received()"); + + eap_status_e status(eap_status_ok); + + if (received_eap_code == eap_code_success + && m_eap_type == eap_type_peap + && m_peap_version == peap_version_1 + && m_use_tppd_tls_peap == true) + { + status = m_am_tls_services->save_tls_session( + &m_session_id, + &m_master_secret, + m_selected_cipher_suite +#if defined(USE_EAP_TLS_SESSION_TICKET) + , tls_extension_c::get_tls_extension( + tls_extension_type_session_ticket, + &m_received_tls_extensions, + m_am_tools) +#endif //#if defined(USE_EAP_TLS_SESSION_TICKET) + ); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } +#if defined(USE_FAST_EAP_TYPE) + else if (m_eap_type == eap_type_fast) + { + if (received_eap_code == eap_code_success + && m_tls_peap_state == tls_peap_state_tls_success + && (m_tls_session_type == tls_session_type_original_session_resumption + || m_tls_session_type == tls_session_type_stateless_session_resumption)) + { + eap_state_variable_e current_state(eap_state_authentication_finished_successfully); + + // Here we swap the addresses. + eap_am_network_id_c send_network_id(m_am_tools, + receive_network_id->get_destination_id(), + receive_network_id->get_source_id(), + receive_network_id->get_type()); + + eap_state_notification_c notification( + m_am_tools, + &send_network_id, + m_is_client, + eap_state_notification_eap, + eap_protocol_layer_eap, + m_eap_type, + eap_state_none, + current_state, + m_received_eap_identifier, + false); + + state_notification(¬ification); + } + else + { + status = m_application->plain_eap_success_failure_packet_received( + receive_network_id, + received_eap_code, + received_eap_identifier); + } + } +#endif //#if defined(USE_FAST_EAP_TYPE) + else if (m_eap_type == eap_type_peap + || m_eap_type == eap_type_ttls + ) + { + status = m_application->plain_eap_success_failure_packet_received( + receive_network_id, + received_eap_code, + received_eap_identifier); + } + + if (status != eap_status_pending_request) + { + // Note this call will return eap_status_pending_request if any asyncronous call is pending. + eap_status_e send_status = check_sent_tls_message(); + if (send_status != eap_status_ok) + { + status = send_status; + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::empty_ack_packet_received( + const eap_am_network_id_c * const receive_network_id, + const u8_t received_eap_identifier) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: starts: tls_record_c::empty_ack_packet_received(): state %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_state_string(m_tls_peap_state))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::empty_ack_packet_received()"); + + eap_status_e status(eap_status_not_supported); + + if (m_eap_type == eap_type_ttls) + { + status = m_application->empty_ack_packet_received( + receive_network_id, + received_eap_identifier); + + if (status != eap_status_pending_request) + { + // Note this call will return eap_status_pending_request if any asyncronous call is pending. + eap_status_e send_status = check_sent_tls_message(); + if (send_status != eap_status_ok) + { + status = send_status; + } + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT bool tls_record_c::get_is_valid() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return m_is_valid; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::reset() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: function: starts: tls_record_c::reset()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::reset()"); + + completion_action_clenup(); + + { + m_received_tls_message.reset(); + m_new_tls_message.reset(); + m_message_hash_md5.hash_cleanup(); + m_message_hash_sha1.hash_cleanup(); + m_message_hash_md5_certificate_verify.reset(); + m_message_hash_sha1_certificate_verify.reset(); + m_client_message_hash_md5_finished.reset(); + m_client_message_hash_sha1_finished.reset(); + m_server_message_hash_md5_finished.reset(); + m_server_message_hash_sha1_finished.reset(); + m_client_handshake_random_value.reset(); + m_server_handshake_random_value.reset(); + m_session_id.reset(); + m_master_secret.reset(); + m_eap_master_session_key.reset(); + m_send_mac_key.reset(); + m_receive_mac_key.reset(); + m_send_encryption_key.reset(); + m_receive_encryption_key.reset(); + m_send_iv.reset(); + m_receive_iv.reset(); + m_own_private_dhe_key.reset(); + m_own_public_dhe_key.reset(); + m_peer_public_dhe_key.reset(); + m_shared_dh_key.reset(); + m_dhe_prime.reset(); + m_dhe_group_generator.reset(); + m_signed_message_hash.reset(); + m_premaster_secret.reset(); +#if defined(USE_FAST_EAP_TYPE) + m_eap_fast_pac_key.reset(); +#endif //#if defined(USE_FAST_EAP_TYPE) + m_own_encrypted_premaster_secret.reset(); + m_proposed_cipher_suites.reset(); + m_proposed_compression_methods.reset(); + m_NAI_realm.reset(); + m_own_certificate_chain.reset(); + m_own_certificate_types.reset(); + m_own_certificate_authorities.reset(); + m_peer_certificate_chain.reset(); + m_peer_certificate_chain_result = eap_status_illegal_certificate; + m_verify_signature = eap_status_authentication_failure; + m_peer_certificate_types.reset(); + m_peer_certificate_authorities.reset(); + } + + eap_status_e status = message_hash_init(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + set_selected_cipher_suite(tls_cipher_suites_none); + m_selected_compression_method = tls_compression_method_none; + + status = set_receive_cipher_suite(tls_cipher_suites_TLS_NULL_WITH_NULL_NULL); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + m_receive_compression_method = tls_compression_method_null; + + status = set_send_cipher_suite(tls_cipher_suites_TLS_NULL_WITH_NULL_NULL); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + m_send_compression_method = tls_compression_method_null; + + m_completion_queue.reset(); + + m_send_record_sequence_number = 0ul; + m_receive_record_sequence_number = 0ul; + + m_key_material_generated = false; + + m_force_tls_message_send = false; + + if (m_is_client == false) + { + // Server + // NOTE: set_state() function cannot reset state. + m_tls_peap_state = tls_peap_state_wait_handshake_type_client_hello; + } + else + { + // Client + // NOTE: set_state() function cannot reset state. + m_tls_peap_state = tls_peap_state_wait_tls_start; + } + + m_tunneled_eap_type_authentication_state = eap_state_none; + + m_tls_peap_server_authenticates_client_action = true; + if (m_is_client == false + && m_tls_peap_server_authenticates_client_config_server == false) + { + m_tls_peap_server_authenticates_client_action = false; + } + + m_tls_peap_server_requested_client_certificate = false; + + m_could_send_fatal_alert_message = true; + m_could_send_warning_alert_message = true; + + if (m_application != 0) + { + m_application->reset(); + } + + reset_block_ciphers(true); + reset_block_ciphers(false); + + reset_stream_ciphers(true); + reset_stream_ciphers(false); + + reset_hmac_algorithms(true); + reset_hmac_algorithms(false); + + m_use_tppd_tls_peap = false; + m_use_tppd_peapv1_acknowledge_hack = false; + + m_will_receive_new_session_ticket = false; + +#if defined(USE_FAST_EAP_TYPE) + m_remove_tunnel_pac = false; +#endif //#if defined(USE_FAST_EAP_TYPE) + +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + set_tls_identity_privacy_handshake_state(tls_identity_privacy_handshake_state_none); +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + + +//-------------------------------------------------- + +EAP_FUNC_EXPORT u32_t tls_record_c::get_key_expansion_size( + u32_t * const mac_key_length, + u32_t * const encryption_key_length, + u32_t * const iv_length, + u32_t * const session_key_seed_length, + u32_t * const mschapv2_challenges_length + ) +{ + u32_t length = 0ul; + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: key_function: starts: tls_record_c::get_key_expansion_size()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::get_key_expansion_size()"); + + *mac_key_length = 0ul; + *encryption_key_length = 0ul; + *iv_length = 0ul; + *session_key_seed_length = 0ul; + *mschapv2_challenges_length = 0ul; + + if (cipher_suite_is_3DES_EDE_CBC_SHA(m_selected_cipher_suite) == true) + { + crypto_3des_ede_c ede_3des(m_am_tools); + + crypto_sha1_c sha1(m_am_tools); + crypto_hmac_c hmac_sha1(m_am_tools, &sha1, false); + + if (hmac_sha1.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + + eap_variable_data_c tmp_key(m_am_tools); + if (tmp_key.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_status_e status = tmp_key.add_data("", 0ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return 0; + } + + status = hmac_sha1.hmac_set_key(&tmp_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return 0; + } + + length = 2ul * hmac_sha1.get_digest_length() + + 2ul * ede_3des.get_key_length() + + 2ul * ede_3des.get_block_size(); + + *mac_key_length = hmac_sha1.get_digest_length(); + *encryption_key_length = ede_3des.get_key_length(); + *iv_length = ede_3des.get_block_size(); + } + else if (cipher_suite_is_AES_128_CBC_SHA(m_selected_cipher_suite) == true) + { + crypto_aes_c aes(m_am_tools); + + crypto_sha1_c sha1(m_am_tools); + crypto_hmac_c hmac_sha1(m_am_tools, &sha1, false); + + if (hmac_sha1.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_variable_data_c tmp_key(m_am_tools); + if (tmp_key.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_status_e status = tmp_key.add_data("", 0ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return 0; + } + + status = hmac_sha1.hmac_set_key(&tmp_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return 0; + } + + length = 2ul * hmac_sha1.get_digest_length() + + 2ul * aes.get_key_length() + + 2ul * aes.get_block_size(); + + *mac_key_length = hmac_sha1.get_digest_length(); + *encryption_key_length = aes.get_key_length(); + *iv_length = aes.get_block_size(); + } + else if (cipher_suite_is_RC4_128_MD5(m_selected_cipher_suite) == true) + { + crypto_md5_c md5(m_am_tools); + crypto_hmac_c hmac_md5(m_am_tools, &md5, false); + + if (hmac_md5.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_variable_data_c tmp_key(m_am_tools); + if (tmp_key.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_status_e status = tmp_key.add_data("", 0ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return 0; + } + + status = hmac_md5.hmac_set_key(&tmp_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return 0; + } + + length = 2ul * hmac_md5.get_digest_length() + + 2ul * TLS_RC4_128_KEY_LENGTH + + 2ul * TLS_RC4_128_IV_LENGTH; + + *mac_key_length = hmac_md5.get_digest_length(); + *encryption_key_length = TLS_RC4_128_KEY_LENGTH; + *iv_length = TLS_RC4_128_IV_LENGTH; + } + else if (cipher_suite_is_RC4_128_SHA(m_selected_cipher_suite) == true) + { + crypto_sha1_c sha1(m_am_tools); + crypto_hmac_c hmac_sha1(m_am_tools, &sha1, false); + + if (hmac_sha1.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_variable_data_c tmp_key(m_am_tools); + if (tmp_key.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_status_e status = tmp_key.add_data("", 0ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return 0; + } + + status = hmac_sha1.hmac_set_key(&tmp_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return 0; + } + + length = 2ul * hmac_sha1.get_digest_length() + + 2ul * TLS_RC4_128_KEY_LENGTH + + 2ul * TLS_RC4_128_IV_LENGTH; + + *mac_key_length = hmac_sha1.get_digest_length(); + *encryption_key_length = TLS_RC4_128_KEY_LENGTH; + *iv_length = TLS_RC4_128_IV_LENGTH; + } + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast) + { + *session_key_seed_length = EAP_FAST_SESSION_KEY_SEED_LENGTH; + length += EAP_FAST_SESSION_KEY_SEED_LENGTH; + + if (m_tls_session_type == tls_session_type_eap_fast_server_unauthenticated_provisioning_mode_ADHP + && m_selected_cipher_suite == tls_cipher_suites_TLS_DH_anon_WITH_AES_128_CBC_SHA) + { + *mschapv2_challenges_length = 2ul * EAP_FAST_MSCHAPV2_CHALLENGE_LENGTH; + length += 2ul * EAP_FAST_MSCHAPV2_CHALLENGE_LENGTH; + } + } +#endif //#if defined(USE_FAST_EAP_TYPE) + + return length; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::cipher_suite_initialization_cbc( + abs_crypto_cbc_block_algorithm_c ** const member_cbc_crypto_block_algorithm, + abs_crypto_block_algorithm_c * const crypto_block_algorithm, + const eap_variable_data_c * const member_iv, + const eap_variable_data_c * const member_key, + const bool true_when_encrypt) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: key_function: starts: tls_record_c::cipher_suite_initialization_cbc()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::cipher_suite_initialization_cbc()"); + + eap_automatic_variable_c + block_algorithm_remove(m_am_tools, crypto_block_algorithm); + + if (crypto_block_algorithm == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + if (crypto_block_algorithm->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + if (member_cbc_crypto_block_algorithm == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + *member_cbc_crypto_block_algorithm = new crypto_cbc_c( + m_am_tools, + crypto_block_algorithm, + true); + + if (*member_cbc_crypto_block_algorithm == 0 + || (*member_cbc_crypto_block_algorithm)->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + // After this point *member_cbc_crypto_block_algorithm will delete crypto_block_algorithm. + block_algorithm_remove.do_not_free_variable(); + + if ((*member_cbc_crypto_block_algorithm)->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_status_e status = eap_status_process_general_error; + + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("CBC member_iv"), + member_iv->get_data(member_iv->get_data_length()), + member_iv->get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("CBC member_key"), + member_key->get_data(member_key->get_data_length()), + member_key->get_data_length())); + + + if (true_when_encrypt == true) + { + status = (*member_cbc_crypto_block_algorithm)->set_encryption_key( + member_iv->get_data(member_iv->get_data_length()), + member_iv->get_data_length(), + member_key->get_data(member_key->get_data_length()), + member_key->get_data_length()); + } + else + { + status = (*member_cbc_crypto_block_algorithm)->set_decryption_key( + member_iv->get_data(member_iv->get_data_length()), + member_iv->get_data_length(), + member_key->get_data(member_key->get_data_length()), + member_key->get_data_length()); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::cipher_suite_initialization_hmac( + abs_crypto_hmac_algorithm_c * const member_hmac_algorithm, + const eap_variable_data_c * const member_key) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: key_function: starts: tls_record_c::cipher_suite_initialization_hmac()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::cipher_suite_initialization_hmac()"); + + if (member_hmac_algorithm == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + if (member_hmac_algorithm->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_status_e status = eap_status_process_general_error; + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("HMAC member_key"), + member_key->get_data(member_key->get_data_length()), + member_key->get_data_length())); + + status = member_hmac_algorithm->hmac_set_key( + member_key); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::cipher_suite_initialization_stream( + abs_crypto_stream_algorithm_c * const member_crypto_stream_algorithm, + const eap_variable_data_c * const member_key, + const bool /* true_when_encrypt */) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: key_function: starts: tls_record_c::cipher_suite_initialization_stream()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::cipher_suite_initialization_stream()"); + + if (member_crypto_stream_algorithm == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + if (member_crypto_stream_algorithm->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("STREAM member_key"), + member_key->get_data(member_key->get_data_length()), + member_key->get_data_length())); + + eap_status_e status = member_crypto_stream_algorithm->set_key(member_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::cipher_suite_initialization_hmac_sha1(const bool send_when_true) +{ + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: key_function: starts: tls_record_c::cipher_suite_initialization_hmac_sha1()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::cipher_suite_initialization_hmac_sha1()"); + + reset_hmac_algorithms(send_when_true); + + eap_status_e status = eap_status_ok; + + if (send_when_true == true) + { + crypto_sha1_c * const sha1 = new crypto_sha1_c(m_am_tools); + if (sha1 == 0) + { + delete sha1; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + m_send_hmac_algorithm = new crypto_hmac_c(m_am_tools, sha1, true); + + status = cipher_suite_initialization_hmac( + m_send_hmac_algorithm, + &m_send_mac_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + } + else + { + crypto_sha1_c * const sha1 = new crypto_sha1_c(m_am_tools); + if (sha1 == 0) + { + delete sha1; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + m_receive_hmac_algorithm = new crypto_hmac_c(m_am_tools, sha1, true); + + status = cipher_suite_initialization_hmac( + m_receive_hmac_algorithm, + &m_receive_mac_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::cipher_suite_initialization_hmac_md5(const bool send_when_true) +{ + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: key_function: starts: cipher_suite_initialization_hmac_md5()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::cipher_suite_initialization_hmac_md5()"); + + reset_hmac_algorithms(send_when_true); + + eap_status_e status = eap_status_ok; + + if (send_when_true == true) + { + crypto_md5_c * const md5 = new crypto_md5_c(m_am_tools); + if (md5 == 0) + { + delete md5; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + m_send_hmac_algorithm = new crypto_hmac_c(m_am_tools, md5, true); + + status = cipher_suite_initialization_hmac( + m_send_hmac_algorithm, + &m_send_mac_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + } + else + { + crypto_md5_c * const md5 = new crypto_md5_c(m_am_tools); + if (md5 == 0) + { + delete md5; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + m_receive_hmac_algorithm = new crypto_hmac_c(m_am_tools, md5, true); + + status = cipher_suite_initialization_hmac( + m_receive_hmac_algorithm, + &m_receive_mac_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::cipher_suite_initialization( + const bool send_when_true) +{ + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: key_function: starts: tls_record_c::cipher_suite_initialization(), cipher suite %s: %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_cipher_suite_string(m_selected_cipher_suite), + (send_when_true == true ? "send": "receive"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::cipher_suite_initialization()"); + + reset_block_ciphers(send_when_true); + + reset_stream_ciphers(send_when_true); + + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("m_send_encryption_key"), + m_send_encryption_key.get_data(), + m_send_encryption_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("m_receive_encryption_key"), + m_receive_encryption_key.get_data(), + m_receive_encryption_key.get_data_length())); + + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("m_send_mac_key"), + m_send_mac_key.get_data(), + m_send_mac_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("m_receive_mac_key"), + m_receive_mac_key.get_data(), + m_receive_mac_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("m_send_iv"), + m_send_iv.get_data(), + m_send_iv.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("m_receive_iv"), + m_receive_iv.get_data(), + m_receive_iv.get_data_length())); + + + eap_status_e status = eap_status_ok; + + if (cipher_suite_is_3DES_EDE_CBC_SHA(m_selected_cipher_suite) == true) + { + if (send_when_true == true) + { + crypto_3des_ede_c * des3 = new crypto_3des_ede_c(m_am_tools); + + status = cipher_suite_initialization_cbc( + &m_send_block_cipher, + des3, + &m_send_iv, + &m_send_encryption_key, + true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + } + else + { + crypto_3des_ede_c * des3 = new crypto_3des_ede_c(m_am_tools); + + status = cipher_suite_initialization_cbc( + &m_receive_block_cipher, + des3, + &m_receive_iv, + &m_receive_encryption_key, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + } + + status = cipher_suite_initialization_hmac_sha1(send_when_true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else if (cipher_suite_is_AES_128_CBC_SHA(m_selected_cipher_suite) == true) + { + if (send_when_true == true) + { + crypto_aes_c * aes = new crypto_aes_c(m_am_tools); + + status = cipher_suite_initialization_cbc( + &m_send_block_cipher, + aes, + &m_send_iv, + &m_send_encryption_key, + true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + } + else + { + crypto_aes_c * aes = new crypto_aes_c(m_am_tools); + + status = cipher_suite_initialization_cbc( + &m_receive_block_cipher, + aes, + &m_receive_iv, + &m_receive_encryption_key, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + } + + status = cipher_suite_initialization_hmac_sha1(send_when_true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else if (cipher_suite_is_RC4_128_MD5(m_selected_cipher_suite) == true) + { + if (send_when_true == true) + { + m_send_stream_cipher = new crypto_rc4_c(m_am_tools); + + status = cipher_suite_initialization_stream( + m_send_stream_cipher, + &m_send_encryption_key, + true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + } + else + { + m_receive_stream_cipher = new crypto_rc4_c(m_am_tools); + + status = cipher_suite_initialization_stream( + m_receive_stream_cipher, + &m_receive_encryption_key, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + } + + status = cipher_suite_initialization_hmac_md5(send_when_true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else if (cipher_suite_is_RC4_128_SHA(m_selected_cipher_suite) == true) + { + if (send_when_true == true) + { + m_send_stream_cipher = new crypto_rc4_c(m_am_tools); + + status = cipher_suite_initialization_stream( + m_send_stream_cipher, + &m_send_encryption_key, + true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + } + else + { + m_receive_stream_cipher = new crypto_rc4_c(m_am_tools); + + status = cipher_suite_initialization_stream( + m_receive_stream_cipher, + &m_receive_encryption_key, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + } + + status = cipher_suite_initialization_hmac_sha1(send_when_true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + status = eap_status_illegal_cipher_suite; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::generate_key_material() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: tls_record_c::generate_key_material()\n"), + (m_is_client == true) ? "client": "server")); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::generate_key_material()"); + + eap_status_e status = eap_status_illegal_cipher_suite; + + if (m_key_material_generated == true) + { + // Already generated. + status = eap_status_ok; + } + else + { + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: key_function: starts: tls_record_c::generate_key_material()\n"), + (m_is_client == true) ? "client": "server")); + + if (m_master_secret.get_is_valid_data() == false + || m_client_handshake_random_value.get_is_valid_data() == false + || m_server_handshake_random_value.get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + u32_t mac_key_length = 0ul; + u32_t encryption_key_length = 0ul; + u32_t iv_length = 0ul; + u32_t session_key_seed_length = 0ul; + u32_t mschapv2_challenges_length = 0ul; + + u32_t key_expansion_size = get_key_expansion_size( + &mac_key_length, + &encryption_key_length, + &iv_length, + &session_key_seed_length, + &mschapv2_challenges_length); + + if (key_expansion_size == 0ul) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_key_error); + } + + eap_variable_data_c label(m_am_tools); + if (label.get_is_valid() == false) + { + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = label.add_data( + TLS_PEAP_KEY_EXPANSION_LABEL, + TLS_PEAP_KEY_EXPANSION_LABEL_LENGTH); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + eap_variable_data_c seed(m_am_tools); + if (seed.get_is_valid() == false) + { + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + status = seed.set_copy_of_buffer(&m_server_handshake_random_value); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = seed.add_data(&m_client_handshake_random_value); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: prf_function: tls_prf.tls_prf_output()\n"), + (m_is_client == true ? "client": "server"))); + + crypto_tls_prf_c tls_prf(m_am_tools); + + status = tls_prf.tls_prf_init( + &m_master_secret, + &label, + &seed); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + eap_variable_data_c key_expansion(m_am_tools); + + status = key_expansion.set_buffer_length(key_expansion_size); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + key_expansion.set_data_length(key_expansion_size); + + status = tls_prf.tls_prf_output( + key_expansion.get_data(key_expansion.get_data_length()), + key_expansion.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + u32_t key_offset = 0ul; + + eap_variable_data_c *send_mac_key = &m_new_send_mac_key; + eap_variable_data_c *receive_mac_key = &m_new_receive_mac_key; + eap_variable_data_c *send_encryption_key = &m_new_send_encryption_key; + eap_variable_data_c *receive_encryption_key = &m_new_receive_encryption_key; + eap_variable_data_c *send_iv = &m_new_send_iv; + eap_variable_data_c *receive_iv = &m_new_receive_iv; + + if (m_is_client == false) + { + send_mac_key = &m_new_receive_mac_key; + receive_mac_key = &m_new_send_mac_key; + send_encryption_key = &m_new_receive_encryption_key; + receive_encryption_key = &m_new_send_encryption_key; + send_iv = &m_new_receive_iv; + receive_iv = &m_new_send_iv; + } + + status = send_mac_key->set_copy_of_buffer( + key_expansion.get_data_offset(key_offset, mac_key_length), + mac_key_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + key_offset += mac_key_length; + + status = receive_mac_key->set_copy_of_buffer( + key_expansion.get_data_offset(key_offset, mac_key_length), + mac_key_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + key_offset += mac_key_length; + + status = send_encryption_key->set_copy_of_buffer( + key_expansion.get_data_offset(key_offset, encryption_key_length), + encryption_key_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + key_offset += encryption_key_length; + + status = receive_encryption_key->set_copy_of_buffer( + key_expansion.get_data_offset(key_offset, encryption_key_length), + encryption_key_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + key_offset += encryption_key_length; + + if (iv_length > 0ul) + { + status = send_iv->set_copy_of_buffer( + key_expansion.get_data_offset(key_offset, iv_length), + iv_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + key_offset += iv_length; + } + else + { + status = send_iv->init(0ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + send_iv->set_is_valid(); + } + + if (iv_length > 0ul) + { + status = receive_iv->set_copy_of_buffer( + key_expansion.get_data_offset(key_offset, iv_length), + iv_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + key_offset += iv_length; + } + else + { + status = receive_iv->init(0ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + receive_iv->set_is_valid(); + } + +#if defined(USE_FAST_EAP_TYPE) + if (session_key_seed_length > 0ul) + { + status = m_session_key_seed.set_copy_of_buffer( + key_expansion.get_data_offset(key_offset, session_key_seed_length), + session_key_seed_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + key_offset += session_key_seed_length; + } + + if (mschapv2_challenges_length > 0ul) + { + status = m_mschapv2_challenges.set_copy_of_buffer( + key_expansion.get_data_offset(key_offset, mschapv2_challenges_length), + mschapv2_challenges_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + key_offset += mschapv2_challenges_length; + } +#endif //#if defined(USE_FAST_EAP_TYPE) + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: generate_key_material(): m_master_secret"), + m_master_secret.get_data(), + m_master_secret.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: generate_key_material(): m_client_handshake_random_value"), + m_client_handshake_random_value.get_data(), + m_client_handshake_random_value.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: generate_key_material(): m_server_handshake_random_value"), + m_server_handshake_random_value.get_data(), + m_server_handshake_random_value.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: generate_key_material(): key_expansion"), + key_expansion.get_data(), + key_expansion.get_data_length())); + + + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: generate_key_material(): m_new_send_mac_key"), + m_new_send_mac_key.get_data(), + m_new_send_mac_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: generate_key_material(): m_new_receive_mac_key"), + m_new_receive_mac_key.get_data(), + m_new_receive_mac_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: generate_key_material(): m_new_send_encryption_key"), + m_new_send_encryption_key.get_data(), + m_new_send_encryption_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: generate_key_material(): m_new_receive_encryption_key"), + m_new_receive_encryption_key.get_data(), + m_new_receive_encryption_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: generate_key_material(): m_new_send_iv"), + m_new_send_iv.get_data(), + m_new_send_iv.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: generate_key_material(): m_new_receive_iv"), + m_new_receive_iv.get_data(), + m_new_receive_iv.get_data_length())); + + if (m_session_key_seed.get_is_valid_data() == true) + { + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: generate_key_material(): m_session_key_seed"), + m_session_key_seed.get_data(), + m_session_key_seed.get_data_length())); + } + +#if defined(USE_FAST_EAP_TYPE) + if (m_mschapv2_challenges.get_is_valid_data() == true) + { + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: generate_key_material(): server_mschapv2_challenge"), + m_mschapv2_challenges.get_data(), + EAP_FAST_MSCHAPV2_CHALLENGE_LENGTH)); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: generate_key_material(): client_mschapv2_challenge"), + m_mschapv2_challenges.get_data_offset(EAP_FAST_MSCHAPV2_CHALLENGE_LENGTH, EAP_FAST_MSCHAPV2_CHALLENGE_LENGTH), + EAP_FAST_MSCHAPV2_CHALLENGE_LENGTH)); + } +#endif //#if defined(USE_FAST_EAP_TYPE) + + m_key_material_generated = true; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::set_tls_master_secret( + const eap_variable_data_c * const master_secret, + const eap_variable_data_c * const client_random, + const eap_variable_data_c * const server_random) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: key_function: starts: tls_record_c::set_tls_master_secret()\n"), + this, + (m_is_client == true) ? "client": "server")); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::set_tls_master_secret()"); + + eap_variable_data_c label(m_am_tools); + if (label.get_is_valid() == false) + { + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_status_e status = eap_status_process_general_error; + + if (m_eap_type == eap_type_ttls) + { + status = label.add_data( + EAP_TTLS_KEY_EXPANSION_LABEL, + EAP_TTLS_KEY_EXPANSION_LABEL_LENGTH); + } + else if (m_eap_type == eap_type_peap + && m_peap_version == peap_version_1 + && m_use_tppd_tls_peap == false) + { + status = label.add_data( + EAP_TLS_PEAP_CLIENT_ENCRYPTION_LABEL_V1_DRAFT_5, + EAP_TLS_PEAP_CLIENT_ENCRYPTION_LABEL_V1_DRAFT_5_LENGTH); + } + else + { + status = label.add_data( + EAP_TLS_PEAP_CLIENT_ENCRYPTION_LABEL, + EAP_TLS_PEAP_CLIENT_ENCRYPTION_LABEL_LENGTH); + } + + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + + status = get_tls_prf_data( + master_secret, + client_random, + server_random, + &label, + &m_eap_master_session_key, + EAP_TLS_PEAP_MASTER_SESSION_KEY_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("tls_record_c::set_tls_master_secret(): TLS_MSK"), + m_eap_master_session_key.get_data(EAP_TLS_PEAP_MSK_SIZE), + EAP_TLS_PEAP_MSK_SIZE)); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("tls_record_c::set_tls_master_secret(): TLS_EMSK"), + m_eap_master_session_key.get_data_offset(EAP_TLS_PEAP_MSK_SIZE, EAP_TLS_PEAP_EMSK_SIZE), + EAP_TLS_PEAP_EMSK_SIZE)); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::get_ttls_implicit_challenge( + eap_variable_data_c * const ttls_implicit_challenge, + const u32_t required_ttls_implicit_challenge_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: key_function: starts: tls_record_c::get_ttls_implicit_challenge()\n"), + this, + (m_is_client == true) ? "client": "server")); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::get_ttls_implicit_challenge()"); + + eap_variable_data_c label(m_am_tools); + if (label.get_is_valid() == false) + { + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + + eap_status_e status = eap_status_process_general_error; + + status = label.add_data( + EAP_TTLS_IMPLICIT_CHALLENGE_LABEL, + EAP_TTLS_IMPLICIT_CHALLENGE_LABEL_LENGTH); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = get_tls_prf_data( + &m_master_secret, + &m_client_handshake_random_value, + &m_server_handshake_random_value, + &label, + ttls_implicit_challenge, + required_ttls_implicit_challenge_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("tls_record_c::get_ttls_implicit_challenge(): ttls_implicit_challenge"), + ttls_implicit_challenge->get_data(), + ttls_implicit_challenge->get_data_length())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::get_tls_prf_data( + const eap_variable_data_c * const master_secret, + const eap_variable_data_c * const client_random, + const eap_variable_data_c * const server_random, + const eap_variable_data_c * const label, + eap_variable_data_c * const prf_data, + const u32_t required_prf_data_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: key_function: starts: tls_record_c::get_tls_prf_data()\n"), + this, + (m_is_client == true) ? "client": "server")); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::get_tls_prf_data()"); + + eap_status_e status = eap_status_process_general_error; + + eap_variable_data_c seed(m_am_tools); + if (seed.get_is_valid() == false) + { + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = seed.set_copy_of_buffer(client_random); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = seed.add_data(server_random); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + crypto_tls_prf_c tls_prf(m_am_tools); + + status = tls_prf.tls_prf_init( + master_secret, + label, + &seed); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = prf_data->set_buffer_length( + required_prf_data_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + prf_data->set_data_length(required_prf_data_length); + + status = tls_prf.tls_prf_output( + prf_data->get_data(), + prf_data->get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("tls_record_c::get_tls_prf_data(): prf_data"), + prf_data->get_data(), + prf_data->get_data_length())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::change_cipher_spec( + const bool send_when_true) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: suite_function: starts: tls_record_c::change_cipher_spec(%s)\n"), + this, + (m_is_client == true) ? "client": "server", + (send_when_true == true) ? "send": "receive")); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::change_cipher_spec()"); + + eap_status_e status = eap_status_illegal_cipher_suite; + + if (m_selected_cipher_suite != tls_cipher_suites_none) + { + status = eap_status_ok; + + if (send_when_true == true) + { + status = set_send_cipher_suite(m_selected_cipher_suite); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DEBUG(m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: change_cipher_spec(): send to %s\n"), + eap_tls_trace_string_c::get_cipher_suite_string(m_send_cipher_suite))); + + } + else + { + status = set_receive_cipher_suite(m_selected_cipher_suite); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DEBUG(m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: change_cipher_spec(): receive to %s\n"), + eap_tls_trace_string_c::get_cipher_suite_string(m_receive_cipher_suite))); + } + + // This will initialize encryption, decryption and MAC algorithms. + status = cipher_suite_initialization(send_when_true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + if (status == eap_status_ok) + { + if (send_when_true == true) + { + m_send_compression_method = m_selected_compression_method; + + EAP_TRACE_DEBUG(m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: change_cipher_spec() send to %s\n"), + eap_tls_trace_string_c::get_compression_method_string( + m_send_compression_method))); + } + else + { + m_receive_compression_method = m_selected_compression_method; + + EAP_TRACE_DEBUG(m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: change_cipher_spec() receive to %s\n"), + eap_tls_trace_string_c::get_compression_method_string( + m_receive_compression_method))); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::new_record_message( + tls_record_message_c ** const tls_record_message, + const tls_record_protocol_e protocol) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: starts: tls_record_c::new_record_message()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::new_record_message()"); + + bool add_new_record = false; + + eap_automatic_variable_c automatic_tls_record_message( + m_am_tools, + 0); + + eap_status_e status = eap_status_process_general_error; + + + *tls_record_message = m_new_tls_message.get_last_record_message(); + if (*tls_record_message != 0 + && (*tls_record_message)->get_protocol() != protocol) + { + // We need a new different protocol. + *tls_record_message = 0; + } + + if (m_use_separate_tls_record == true) + { + // Every message is in separate TLS-record. + *tls_record_message = 0; + } + + if (*tls_record_message == 0) + { + *tls_record_message = new tls_record_message_c(m_am_tools, this, m_is_client); + + automatic_tls_record_message.set_variable(*tls_record_message); + + if (*tls_record_message == 0 + || (*tls_record_message)->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = (*tls_record_message)->set_protocol(protocol); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = (*tls_record_message)->set_version(tls_version_3_1); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + add_new_record = true; + } + + if (add_new_record == true) + { + // Note m_new_tls_message free message on any case. + automatic_tls_record_message.do_not_free_variable(); + + bool includes_tls_handshake_message = false; + + if (protocol == tls_record_protocol_handshake) + { + includes_tls_handshake_message = true; + } + + status = m_new_tls_message.add_record_message( + (*tls_record_message), + true, + includes_tls_handshake_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + status = eap_status_ok; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::add_record_message( + tls_handshake_message_c * const tls_handshake_message) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: starts: tls_record_c::add_record_message()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::add_record_message()"); + + tls_record_message_c *tls_record_message = 0; + + eap_status_e status = new_record_message( + &tls_record_message, + tls_record_protocol_handshake); + if (status != eap_status_ok + || tls_record_message == 0) + { + delete tls_handshake_message; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_record_message->add_handshake_message( + tls_handshake_message, + true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_handshake_message->create_message_data(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::add_record_message( + tls_change_cipher_spec_message_c * const change_cipher_spec_message) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: starts: tls_record_c::add_record_message()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::add_record_message()"); + + tls_record_message_c *tls_record_message = 0; + + eap_status_e status = new_record_message( + &tls_record_message, + tls_record_protocol_change_cipher_spec); + if (status != eap_status_ok + || tls_record_message == 0) + { + delete change_cipher_spec_message; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_record_message->add_change_cipher_spec_message( + change_cipher_spec_message, + true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = change_cipher_spec_message->create_message_data(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::add_record_message( + tls_alert_message_c * const alert_message) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: starts: tls_record_c::add_record_message()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::add_record_message()"); + + tls_record_message_c *tls_record_message = 0; + + eap_status_e status = new_record_message( + &tls_record_message, + tls_record_protocol_alert); + if (status != eap_status_ok + || tls_record_message == 0) + { + delete alert_message; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_record_message->add_alert_message( + alert_message, + true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = alert_message->create_message_data(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::add_record_message( + tls_application_data_message_c * const application_data_message) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: starts: tls_record_c::add_record_message()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::add_record_message()"); + + tls_record_message_c *tls_record_message = 0; + + eap_status_e status = new_record_message( + &tls_record_message, + tls_record_protocol_application_data); + if (status != eap_status_ok + || tls_record_message == 0) + { + delete application_data_message; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_record_message->add_application_data_message( + application_data_message, + true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::allocate_handshake_message( + tls_handshake_message_c ** const tls_handshake_message, + eap_automatic_variable_c * const automatic_tls_handshake_message, + const tls_handshake_type_e handshake_type) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: receive_function: starts: tls_record_c::allocate_handshake_message()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::allocate_handshake_message()"); + + *tls_handshake_message + = new tls_handshake_message_c(m_am_tools, this, m_is_client); + + automatic_tls_handshake_message->set_variable(*tls_handshake_message); + + if (*tls_handshake_message == 0 + || (*tls_handshake_message)->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_status_e status = (*tls_handshake_message)->set_handshake_type( + handshake_type); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_handshake_type_hello_request() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_handshake_type_hello_request()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_handshake_type_hello_request()"); + + // This is an empty message. + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_type_hello_request); + + // Note add_record_message() frees message on any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = add_record_message(tls_handshake_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + set_state(tls_peap_state_wait_handshake_type_client_hello); + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_handshake_type_client_hello() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_handshake_type_client_hello(): privacy_handshake_state=%d=%s, session_type=%s\n"), + this, + (m_is_client == true ? "client": "server"), + m_tls_identity_privacy_handshake_state, + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(m_tls_identity_privacy_handshake_state), + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type))); +#else + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_handshake_type_client_hello(): privacy_handshake_state=%d=%s\n"), + this, + (m_is_client == true ? "client": "server"), + 0, + "")); +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_handshake_type_client_hello()"); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Version: 3 | Version: 1 | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | | + // + + + // | ClientRandomValue | + // + (32 bytes) +-+-+-+-+-+-+-+-+ + // | | ID length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | Session ID | + // + (maximum 32 bytes) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | CipherSuite length | CipherSuite 1 | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | CipherSuite 2 | CipherSuite 3 | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | CipherSuite 4 | Cmp length | Cmp 1 | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Cmp 2 | Cmp 3 | extensions ... | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + eap_status_e status(eap_status_ok); + + status = message_hash_init(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + status = allocate_handshake_message( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_type_client_hello); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + u32_t tmp_gmt_unix_time_network_order = eap_htonl(m_am_tools->get_gmt_unix_time()); + eap_variable_data_c tmp_client_random(m_am_tools); + + status = tmp_client_random.set_buffer_length(TLS_HANDSHAKE_RANDOM_VALUE_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + tmp_client_random.set_data_length(TLS_HANDSHAKE_RANDOM_VALUE_SIZE); + + crypto_random_c rand(m_am_tools); + + status = rand.get_rand_bytes( + tmp_client_random.get_data(tmp_client_random.get_data_length()), + tmp_client_random.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // Sets the first bytes to GMT unix time. + u8_t *p_gmt_unix_time = reinterpret_cast(tmp_client_random.get_data(sizeof(u32_t))); + if (p_gmt_unix_time == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + m_am_tools->memmove(p_gmt_unix_time, &tmp_gmt_unix_time_network_order, sizeof(tmp_gmt_unix_time_network_order)); + + + status = m_client_handshake_random_value.set_copy_of_buffer( + &tmp_client_random); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + + status = tls_handshake_message->set_random_value( + &tmp_client_random); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (m_tls_session_type == tls_session_type_original_session_resumption + && m_session_id.get_is_valid_data() == true) + { + status = tls_handshake_message->set_session_id( + &m_session_id); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + // -------------------------------------------------------------------- + + // This copies proposed cipher suites to tls_handshake_message. + status = tls_handshake_message->set_cipher_suites(&m_proposed_cipher_suites); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + status = tls_handshake_message->set_compression_methods(&m_proposed_compression_methods); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + +#if defined(USE_EAP_TLS_SESSION_TICKET) + + { + status = tls_handshake_message->set_tls_extensions(&m_supported_tls_extensions); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + } + +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + + // -------------------------------------------------------------------- + + // Note add_record_message() frees message on any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = add_record_message(tls_handshake_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_handshake_type_server_hello( + const u16_t /*selected_cipher_suite*/, + const u8_t /*selected_compression_method*/) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_handshake_type_server_hello()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_handshake_type_server_hello()"); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Version: 3 | Version: 1 | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | | + // + + + // | ServerRandomValue | + // + (32 bytes) +-+-+-+-+-+-+-+-+ + // | | ID length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | Session ID | + // + (maximum 32 bytes) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | CipherSuite | Cmp | extensions ... + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_type_server_hello); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + u32_t tmp_gmt_unix_time_network_order = eap_htonl(m_am_tools->get_gmt_unix_time()); + eap_variable_data_c tmp_server_random(m_am_tools); + + status = tmp_server_random.set_buffer_length(TLS_HANDSHAKE_RANDOM_VALUE_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + tmp_server_random.set_data_length(TLS_HANDSHAKE_RANDOM_VALUE_SIZE); + + crypto_random_c rand(m_am_tools); + + status = rand.get_rand_bytes( + tmp_server_random.get_data(tmp_server_random.get_data_length()), + tmp_server_random.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // Sets the first bytes to GMT unix time. + u8_t *p_gmt_unix_time = reinterpret_cast(tmp_server_random.get_data(sizeof(u32_t))); + if (p_gmt_unix_time == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + m_am_tools->memmove(p_gmt_unix_time, &tmp_gmt_unix_time_network_order, sizeof(tmp_gmt_unix_time_network_order)); + + status = m_server_handshake_random_value.set_copy_of_buffer( + &tmp_server_random); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + status = tls_handshake_message->set_random_value( + &tmp_server_random); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + if ((m_tls_session_type == tls_session_type_full_authentication +#if defined(USE_FAST_EAP_TYPE) + || m_tls_session_type == tls_session_type_eap_fast_server_unauthenticated_provisioning_mode_ADHP +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + && m_server_offers_new_session_id == true) + { + // We create a new session. + status = m_session_id.set_buffer_length(TLS_SESSION_ID_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + m_session_id.set_data_length(TLS_SESSION_ID_SIZE); + + status = rand.get_rand_bytes( + m_session_id.get_data(m_session_id.get_data_length()), + m_session_id.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + // -------------------------------------------------------------------- + + status = tls_handshake_message->set_session_id( + &m_session_id); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: TLS/PEAP selected cipher_suite %s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_cipher_suite_string(m_selected_cipher_suite))); + } + + status = tls_handshake_message->set_selected_cipher_suite( + m_selected_cipher_suite); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + status = tls_handshake_message->set_selected_compression_method( + m_selected_compression_method); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + +#if defined(USE_EAP_TLS_SESSION_TICKET) + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type != eap_type_fast) // EAP-FAST does not use session ticket in ServerHello message. +#endif //#if defined(USE_FAST_EAP_TYPE) + { + status = tls_handshake_message->set_tls_extensions(&m_supported_tls_extensions); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + + // -------------------------------------------------------------------- + + if (m_tls_session_type == tls_session_type_original_session_resumption +#if defined(USE_EAP_TLS_SESSION_TICKET) + || m_tls_session_type == tls_session_type_stateless_session_resumption +#if defined(USE_FAST_EAP_TYPE) + || m_tls_session_type == tls_session_type_eap_fast_pac_session_resumption +#endif //#if defined(USE_FAST_EAP_TYPE) +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + ) + { + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast + && m_tls_session_type == tls_session_type_eap_fast_pac_session_resumption) + { + // Generates master secret from PAC-Key. + // Parameter resumed_master_secret includes PAC-Key. + status = generate_eap_fast_master_secret_from_pac_key( + &m_eap_fast_pac_key); + + m_eap_fast_pac_key.reset(); + + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } +#endif //#if defined(USE_FAST_EAP_TYPE) + + // We must generate the key material. + status = generate_key_material(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + } + + // -------------------------------------------------------------------- + + // Note add_record_message() frees message on any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = add_record_message(tls_handshake_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_handshake_type_certificate( + EAP_TEMPLATE_CONST eap_array_c * const certificate_chain) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + + tls_identity_privacy_handshake_state_e tmp_identity_privacy_handshake_state = +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + m_tls_identity_privacy_handshake_state; +#else + tls_identity_privacy_handshake_state_none; +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + EAP_UNREFERENCED_PARAMETER(tmp_identity_privacy_handshake_state); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_handshake_type_certificate(): state=%d=%s, privacy_handshake_state=%d=%s, session_type=%s\n"), + this, + (m_is_client == true ? "client": "server"), + m_tls_peap_state, + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + tmp_identity_privacy_handshake_state, + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(tmp_identity_privacy_handshake_state), + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_handshake_type_certificate()"); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Certificate Chain Length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Certificate 1 Length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | Certificate 1 | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // . ... . + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Certificate n Length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | Certificate n | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_type_certificate); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + // Certificate chain is included when TLS identity privacy is not used, + // or send cipher is not NULL + // or sender is server + if (m_tls_session_type == tls_session_type_full_authentication + && (m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_none + || m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_runs + || m_is_client == false)) +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + { + status = tls_handshake_message->set_certificate_chain( + certificate_chain); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + // -------------------------------------------------------------------- + + // Note add_record_message() frees message on any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = add_record_message(tls_handshake_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_handshake_type_certificate_request( + EAP_TEMPLATE_CONST eap_array_c * const certificate_types, + EAP_TEMPLATE_CONST eap_array_c * const certificate_authorities) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_handshake_type_certificate_request()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_handshake_type_certificate_request()"); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | CT length | CT 1 | CT 2 | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | CT 3 | CT 4 | CAs length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | CA 1 length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | Distinguished name of Certificate Authority 1 | + // + + + // | | + // + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | CA 2 length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | Distinguished name of Certificate Authority 2 | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_type_certificate_request); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_handshake_message->set_certificate_types( + certificate_types); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (m_server_sends_empty_certificate_authorities_list == false) + { + status = tls_handshake_message->set_certificate_authorities( + certificate_authorities); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + // -------------------------------------------------------------------- + + // Note add_record_message() frees message on any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = add_record_message(tls_handshake_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_handshake_type_server_hello_done() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_handshake_type_server_hello_done()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_handshake_type_server_hello_done()"); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // + // ServerHelloDone message does not include payload. + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_type_server_hello_done); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + // Note add_record_message() frees message on any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = add_record_message(tls_handshake_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_server_key_exchange_sha1_hash( + const eap_variable_data_c * const dhe_prime, + const eap_variable_data_c * const dhe_group_generator, + const eap_variable_data_c * const public_dhe_key, + eap_variable_data_c * const hash) +{ + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: hash_function: starts: tls_record_c::create_server_key_exchange_sha1_hash()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_server_key_exchange_sha1_hash()"); + + if (m_client_handshake_random_value.get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + if (m_server_handshake_random_value.get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + u16_t dhe_prime_length_network_order + = eap_htons(static_cast(dhe_prime->get_data_length())); + + u16_t dhe_group_generator_length_network_order + = eap_htons(static_cast(dhe_group_generator->get_data_length())); + + u16_t public_dhe_key_length_network_order + = eap_htons(static_cast(public_dhe_key->get_data_length())); + + crypto_sha1_c sha1(m_am_tools); + + eap_status_e status = sha1.hash_init(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_sha1_hash(): client random"), + m_client_handshake_random_value.get_data(m_client_handshake_random_value.get_data_length()), + m_client_handshake_random_value.get_data_length())); + + status = sha1.hash_update( + m_client_handshake_random_value.get_data(m_client_handshake_random_value.get_data_length()), + m_client_handshake_random_value.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_sha1_hash(): server random"), + m_server_handshake_random_value.get_data(m_client_handshake_random_value.get_data_length()), + m_server_handshake_random_value.get_data_length())); + + status = sha1.hash_update( + m_server_handshake_random_value.get_data(m_client_handshake_random_value.get_data_length()), + m_server_handshake_random_value.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_sha1_hash(): dhe_prime_length_network_order"), + &dhe_prime_length_network_order, + sizeof(dhe_prime_length_network_order))); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_sha1_hash(): dhe_prime"), + dhe_prime->get_data(dhe_prime->get_data_length()), + dhe_prime->get_data_length())); + + status = sha1.hash_update( + &dhe_prime_length_network_order, + sizeof(dhe_prime_length_network_order)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = sha1.hash_update( + dhe_prime->get_data( + dhe_prime->get_data_length()), + dhe_prime->get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_sha1_hash(): ") + EAPL("dhe_group_generator_length_network_order"), + &dhe_group_generator_length_network_order, + sizeof(dhe_group_generator_length_network_order))); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_sha1_hash(): dhe_group_generator"), + dhe_group_generator->get_data(dhe_group_generator->get_data_length()), + dhe_group_generator->get_data_length())); + + status = sha1.hash_update( + &dhe_group_generator_length_network_order, + sizeof(dhe_group_generator_length_network_order)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = sha1.hash_update( + dhe_group_generator->get_data( + dhe_group_generator->get_data_length()), + dhe_group_generator->get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_sha1_hash(): public_dhe_key_length_network_order"), + &public_dhe_key_length_network_order, + sizeof(public_dhe_key_length_network_order))); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_sha1_hash(): public_dhe_key"), + public_dhe_key->get_data(public_dhe_key->get_data_length()), + public_dhe_key->get_data_length())); + + status = sha1.hash_update( + &public_dhe_key_length_network_order, + sizeof(public_dhe_key_length_network_order)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = sha1.hash_update( + public_dhe_key->get_data( + public_dhe_key->get_data_length()), + public_dhe_key->get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + status = hash->set_buffer_length(sha1.get_digest_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + hash->set_data_length(sha1.get_digest_length()); + + u32_t digest_length = hash->get_data_length(); + status = sha1.hash_final( + hash->get_data(hash->get_data_length()), + &digest_length); + if (digest_length != sha1.get_digest_length()) + { + status = eap_status_process_general_error; + } + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_sha1_hash(): hash"), + hash->get_data(hash->get_data_length()), + hash->get_data_length())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_server_key_exchange_md5_hash( + const eap_variable_data_c * const dhe_prime, + const eap_variable_data_c * const dhe_group_generator, + const eap_variable_data_c * const public_dhe_key, + eap_variable_data_c * const hash) +{ + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: hash_function: starts: tls_record_c::create_server_key_exchange_md5_hash()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_server_key_exchange_md5_hash()"); + + if (m_client_handshake_random_value.get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + if (m_server_handshake_random_value.get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + u16_t dhe_prime_length_network_order + = eap_htons(static_cast(dhe_prime->get_data_length())); + + u16_t dhe_group_generator_length_network_order + = eap_htons(static_cast(dhe_group_generator->get_data_length())); + + u16_t public_dhe_key_length_network_order + = eap_htons(static_cast(public_dhe_key->get_data_length())); + + crypto_md5_c md5(m_am_tools); + + eap_status_e status = md5.hash_init(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_md5_hash(): client random"), + m_client_handshake_random_value.get_data(m_client_handshake_random_value.get_data_length()), + m_client_handshake_random_value.get_data_length())); + + status = md5.hash_update( + m_client_handshake_random_value.get_data(m_client_handshake_random_value.get_data_length()), + m_client_handshake_random_value.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_md5_hash(): server random"), + m_server_handshake_random_value.get_data(m_client_handshake_random_value.get_data_length()), + m_server_handshake_random_value.get_data_length())); + + status = md5.hash_update( + m_server_handshake_random_value.get_data(m_client_handshake_random_value.get_data_length()), + m_server_handshake_random_value.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_md5_hash(): dhe_prime_length_network_order"), + &dhe_prime_length_network_order, + sizeof(dhe_prime_length_network_order))); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_md5_hash(): dhe_prime"), + dhe_prime->get_data(dhe_prime->get_data_length()), + dhe_prime->get_data_length())); + + status = md5.hash_update( + &dhe_prime_length_network_order, + sizeof(dhe_prime_length_network_order)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = md5.hash_update( + dhe_prime->get_data( + dhe_prime->get_data_length()), + dhe_prime->get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_md5_hash(): ") + EAPL("dhe_group_generator_length_network_order"), + &dhe_group_generator_length_network_order, + sizeof(dhe_group_generator_length_network_order))); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_md5_hash(): dhe_group_generator"), + dhe_group_generator->get_data(dhe_group_generator->get_data_length()), + dhe_group_generator->get_data_length())); + + status = md5.hash_update( + &dhe_group_generator_length_network_order, + sizeof(dhe_group_generator_length_network_order)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = md5.hash_update( + dhe_group_generator->get_data( + dhe_group_generator->get_data_length()), + dhe_group_generator->get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_md5_hash(): public_dhe_key_length_network_order"), + &public_dhe_key_length_network_order, + sizeof(public_dhe_key_length_network_order))); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_md5_hash(): public_dhe_key"), + public_dhe_key->get_data(public_dhe_key->get_data_length()), + public_dhe_key->get_data_length())); + + status = md5.hash_update( + &public_dhe_key_length_network_order, + sizeof(public_dhe_key_length_network_order)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = md5.hash_update( + public_dhe_key->get_data( + public_dhe_key->get_data_length()), + public_dhe_key->get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + status = hash->set_buffer_length(md5.get_digest_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + hash->set_data_length(md5.get_digest_length()); + + u32_t digest_length = hash->get_data_length(); + status = md5.hash_final( + hash->get_data(hash->get_data_length()), + &digest_length); + if (digest_length != md5.get_digest_length()) + { + status = eap_status_process_general_error; + } + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_server_key_exchange_md5_hash(): hash"), + hash->get_data(hash->get_data_length()), + hash->get_data_length())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::verify_signature_of_server_key_exchange( + const eap_variable_data_c * const signed_server_key_exchange_hash) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: hash_function: starts: tls_record_c::verify_signature_of_server_key_exchange()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::verify_signature_of_server_key_exchange()"); + + eap_status_e status = eap_status_not_supported; + + eap_variable_data_c hash(m_am_tools); + + + if (cipher_suite_is_TLS_DHE_DSS() == true) + { + status = create_server_key_exchange_sha1_hash( + &m_dhe_prime, + &m_dhe_group_generator, + &m_peer_public_dhe_key, + &hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else if (cipher_suite_is_TLS_DHE_RSA() == true) + { + eap_variable_data_c md5_hash(m_am_tools); + + status = create_server_key_exchange_md5_hash( + &m_dhe_prime, + &m_dhe_group_generator, + &m_peer_public_dhe_key, + &md5_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + eap_variable_data_c sha1_hash(m_am_tools); + + status = create_server_key_exchange_sha1_hash( + &m_dhe_prime, + &m_dhe_group_generator, + &m_peer_public_dhe_key, + &sha1_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = hash.add_data(&md5_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = hash.add_data(&sha1_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_cipher_suite); + } + + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: verify_signature_of_server_key_exchange(): hash"), + hash.get_data(hash.get_data_length()), + hash.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: verify_signature_of_server_key_exchange(): signed_server_key_exchange_hash"), + signed_server_key_exchange_hash->get_data( + signed_server_key_exchange_hash->get_data_length()), + signed_server_key_exchange_hash->get_data_length())); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: verify_with_public_key()\n"), + (m_is_client == true ? "client": "server"))); + + status = m_am_tls_services->verify_with_public_key( + &hash, + signed_server_key_exchange_hash); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by complete_query_certificate_chain() call. + m_pending_verify_with_public_key = true; + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_query_certificate_chain() call. + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call is always completed on success. + status = eap_status_process_general_error; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else // All other status values means error, because this call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_create_handshake_type_server_key_exchange() +{ + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: parse_function: starts: tls_record_c::complete_create_handshake_type_server_key_exchange()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_create_handshake_type_server_key_exchange()"); + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_type_server_key_exchange); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + +#if EAP_TLS_UNSUPPORTED_CIPHER_SUITE + #error This one needs more code. RSA key exchange with different parameters is NOT supported. + if (cipher_suite_is_TLS_RSA() == true) + { + // RSA modulus and exponent are included when selected cipher suite is + // using RSA key exchange + // and parameters are different than included in the certificate. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | rsa_modulus length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | rsa_modulus | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | rsa_exponent length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + rsa_exponent + + // | | + // + + + // | | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | digitally-signed MD5 hash 16 bytes | + // + (ClientHello.random + ServerHello.random + ServerParams) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | digitally-signed SHA-1 hash 20 bytes | + // + (ClientHello.random + ServerHello.random + ServerParams) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); + } + else +#endif + if (cipher_suite_is_TLS_DHE_DSS() == true) + { + // Diffie-Hellman prime modulus, generator and server's + // Diffie-Hellman public value (g^X mod p) + // are included when selected cipher suite is ephemeral Diffie-Hellman key exchange. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH p length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH p value (prime modulus) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH g length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH g value (generator) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH Ys length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH Ys value | + // + (server's Diffie-Hellman public value) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | digitally-signed SHA-1 hash 47 bytes | + // + (ClientHello.random + ServerHello.random + ServerParams) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_create_handshake_type_server_key_exchange(): m_signed_message_hash"), + m_signed_message_hash.get_data(m_signed_message_hash.get_data_length()), + m_signed_message_hash.get_data_length())); + + status = tls_handshake_message->set_signed_message_hash( + &m_signed_message_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else if (cipher_suite_is_TLS_DHE_RSA() == true) + { + // Diffie-Hellman prime modulus, generator and server's + // Diffie-Hellman public value (g^X mod p) + // are included when selected cipher suite is ephemeral Diffie-Hellman key exchange. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH p length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH p value (prime modulus) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH g length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH g value (generator) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH Ys length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH Ys value | + // + (server's Diffie-Hellman public value) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | digitally-signed MD5 hash 16 bytes | + // + (ClientHello.random + ServerHello.random + ServerParams) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | digitally-signed SHA-1 hash 47 bytes | + // + (ClientHello.random + ServerHello.random + ServerParams) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_create_handshake_type_server_key_exchange(): m_signed_message_hash"), + m_signed_message_hash.get_data(m_signed_message_hash.get_data_length()), + m_signed_message_hash.get_data_length())); + + status = tls_handshake_message->set_signed_message_hash( + &m_signed_message_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } +#if defined(USE_FAST_EAP_TYPE) + else if (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) + { + // Diffie-Hellman prime modulus, generator and server's + // Diffie-Hellman public value (g^X mod p) + // are included when selected cipher suite is ephemeral Diffie-Hellman key exchange. + // NOTE: Here are no signed hash. This is not authenticated at all and vulnerable to + // man-in-the-middle attacks. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH p length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH p value (prime modulus) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH g length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH g value (generator) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH Ys length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH Ys value | + // + (server's Diffie-Hellman public value) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_create_handshake_type_server_key_exchange() no m_signed_message_hash\n"))); + } +#endif //#if defined(USE_FAST_EAP_TYPE) + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_cipher_suite); + } + + // -------------------------------------------------------------------- + + + status = tls_handshake_message->set_dhe_prime( + &m_dhe_prime); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_handshake_message->set_dhe_group_generator( + &m_dhe_group_generator); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_handshake_message->set_public_dhe_key( + &m_own_public_dhe_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + // Note add_record_message() frees message on any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = add_record_message(tls_handshake_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_handshake_type_server_key_exchange() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_handshake_type_server_key_exchange()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_handshake_type_server_key_exchange()"); + + eap_status_e status = eap_status_process_general_error; + eap_variable_data_c hash(m_am_tools); + + +#if EAP_TLS_UNSUPPORTED_CIPHER_SUITE + #error This one needs more code. RSA key exchange with different parameters is NOT supported. + if (cipher_suite_is_TLS_RSA() == true) + { + // RSA modulus and exponent are included when selected + // cipher suite is using RSA key exchange + // and parameters are different than included in the certificate. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | rsa_modulus length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | rsa_modulus | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | rsa_exponent length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + rsa_exponent + + // | | + // + + + // | | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | digitally-signed MD5 hash 16 bytes | + // + (ClientHello.random + ServerHello.random + ServerParams) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | digitally-signed SHA-1 hash 20 bytes | + // + (ClientHello.random + ServerHello.random + ServerParams) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); + } + else +#endif + if (cipher_suite_is_TLS_DHE_DSS() == true) + { + // Diffie-Hellman prime modulus, generator and server's + // Diffie-Hellman public value (g^X mod p) + // are included when selected cipher suite is ephemeral Diffie-Hellman key exchange. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH p length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH p value (prime modulus) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH g length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH g value (generator) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH Ys length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH Ys value | + // + (server's Diffie-Hellman public value) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | digitally-signed SHA-1 hash 47 bytes | + // + (ClientHello.random + ServerHello.random + ServerParams) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + status = create_server_key_exchange_sha1_hash( + &m_dhe_prime, + &m_dhe_group_generator, + &m_own_public_dhe_key, + &hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_handshake_type_server_key_exchange(): hash"), + hash.get_data(hash.get_data_length()), + hash.get_data_length())); + } + else if (cipher_suite_is_TLS_DHE_RSA() == true) + { + // Diffie-Hellman prime modulus, generator and server's + // Diffie-Hellman public value (g^X mod p) + // are included when selected cipher suite is ephemeral Diffie-Hellman key exchange. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH p length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH p value (prime modulus) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH g length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH g value (generator) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH Ys length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH Ys value | + // + (server's Diffie-Hellman public value) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | digitally-signed MD5 hash 16 bytes | + // + (ClientHello.random + ServerHello.random + ServerParams) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + + + // | digitally-signed SHA-1 hash 47 bytes | + // + (ClientHello.random + ServerHello.random + ServerParams) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + eap_variable_data_c md5_hash(m_am_tools); + + status = create_server_key_exchange_md5_hash( + &m_dhe_prime, + &m_dhe_group_generator, + &m_own_public_dhe_key, + &md5_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_handshake_type_server_key_exchange() md5_hash"), + md5_hash.get_data(md5_hash.get_data_length()), + md5_hash.get_data_length())); + + eap_variable_data_c sha1_hash(m_am_tools); + + status = create_server_key_exchange_sha1_hash( + &m_dhe_prime, + &m_dhe_group_generator, + &m_own_public_dhe_key, + &sha1_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_handshake_type_server_key_exchange() sha1_hash"), + sha1_hash.get_data(sha1_hash.get_data_length()), + sha1_hash.get_data_length())); + + status = hash.add_data(&md5_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = hash.add_data(&sha1_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_handshake_type_server_key_exchange(): hash"), + hash.get_data(hash.get_data_length()), + hash.get_data_length())); + } +#if defined(USE_FAST_EAP_TYPE) + else if (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) + { + // Diffie-Hellman prime modulus, generator and server's + // Diffie-Hellman public value (g^X mod p) + // are included when selected cipher suite is ephemeral Diffie-Hellman key exchange. + // NOTE: Here are no signed hash. This is not authenticated at all and vulnerable to + // man-in-the-middle attacks. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH p length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH p value (prime modulus) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH g length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH g value (generator) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH Ys length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH Ys value | + // + (server's Diffie-Hellman public value) + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + // NOTE: Here the return value is eap_status_pending_request to avoid error after return. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_pending_request); + } +#endif //#if defined(USE_FAST_EAP_TYPE) + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_cipher_suite); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: create_handshake_type_server_key_exchange()\n"), + (m_is_client == true ? "client": "server"))); + + m_signed_message_hash.reset(); + + // NOTE this function is asyncronous. This causes complex control flow. + // This function call will be completed always. + status = m_am_tls_services->sign_with_private_key( + &hash); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by complete_sign_with_private_key() call. + m_pending_sign_with_private_key = true; + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_sign_with_private_key() call. + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call is always completed on success. + status = eap_status_process_general_error; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else // All other status values means error, because this call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_create_handshake_type_client_key_exchange() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::complete_create_handshake_type_client_key_exchange(): cipher suite=%d=%s\n"), + this, + (m_is_client == true ? "client": "server"), + m_selected_cipher_suite, + eap_tls_trace_string_c::get_cipher_suite_string(m_selected_cipher_suite))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_create_handshake_type_client_key_exchange()"); + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_type_client_key_exchange); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + if (cipher_suite_is_TLS_RSA() == true) + { + // Encrypted premaster secret is included when selected + // cipher suite is using RSA key exchange. + // First two bytes are version of TLS. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // +-+-+-+-+-+-+-+-+ + + // | | + // + + + // | Encrypted Premaster Secret (48 bytes) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (m_own_encrypted_premaster_secret.get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_create_handshake_type_client_key_exchange(): encrypted premaster_secret"), + m_own_encrypted_premaster_secret.get_data(), + m_own_encrypted_premaster_secret.get_data_length())); + + status = tls_handshake_message->set_encrypted_premaster_secret( + &m_own_encrypted_premaster_secret); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true +#if defined(USE_FAST_EAP_TYPE) + || (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + // Diffie-Hellman Yc is included when selected cipher suite is + // ephemeral Diffie-Hellman key exchange. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH Yc length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH Yc value | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (m_own_public_dhe_key.get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + status = tls_handshake_message->set_public_dhe_key( + &m_own_public_dhe_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_cipher_suite); + } + + // -------------------------------------------------------------------- + + // Note add_record_message() frees message on any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = add_record_message(tls_handshake_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_handshake_type_client_key_exchange() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_handshake_type_client_key_exchange()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_handshake_type_client_key_exchange()"); + + eap_status_e status = eap_status_process_general_error; + + if (cipher_suite_is_TLS_RSA() == true) + { + // Encrypted premaster secret is included when selected + // cipher suite is using RSA key exchange. + // First two bytes are version of TLS. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // +-+-+-+-+-+-+-+-+ + + // | | + // + + + // | Encrypted Premaster Secret (48 bytes) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (m_premaster_secret.get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_key_error); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: rsa_encrypt_with_public_key()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_handshake_type_client_key_exchange(): premaster_secret"), + m_premaster_secret.get_data(), + m_premaster_secret.get_data_length())); + + status = m_am_tls_services->rsa_encrypt_with_public_key( + &m_premaster_secret); + + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by + // complete_rsa_encrypt_with_public_key() call. + m_pending_rsa_encrypt_with_public_key = true; + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_rsa_encrypt_with_public_key() call. + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call is always completed on success. + status = eap_status_process_general_error; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else // All other status values means error, because this + // call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + else if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true +#if defined(USE_FAST_EAP_TYPE) + || (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + // Diffie-Hellman Yc is included when selected cipher suite is + // ephemeral Diffie-Hellman key exchange. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH Yc length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH Yc value | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // These cipher suites does not need asyncronous operations. + // Still these cipher suites are completed in + // complete_create_handshake_type_client_key_exchange(). + status = eap_status_ok; + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_cipher_suite); + } + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_create_handshake_type_certificate_verify() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::complete_create_handshake_type_certificate_verify()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_create_handshake_type_certificate_verify()"); + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_type_certificate_verify); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_create_handshake_type_certificate_verify(): m_signed_message_hash"), + m_signed_message_hash.get_data(m_signed_message_hash.get_data_length()), + m_signed_message_hash.get_data_length())); + + status = tls_handshake_message->set_signed_message_hash( + &m_signed_message_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + // Note add_record_message() frees message on any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = add_record_message(tls_handshake_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_handshake_type_certificate_verify() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_handshake_type_certificate_verify()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_handshake_type_certificate_verify()"); + + // -------------------------------------------------------------------- + + if (cipher_suite_is_TLS_RSA() == true) + { + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // +-+-+-+-+-+-+-+-+ + + // | | + // + Signed MD5 hash + + // | (16 bytes) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + Signed SHA hash + + // | (20 bytes) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // this will be created in tls_handshake_message_c::add_message_data(). + } + else if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true) + { + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // +-+-+-+-+-+-+-+-+ + + // | | + // + Signed SHA hash + + // | (48 bytes) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // this will be created in tls_handshake_message_c::add_message_data(). + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); + } + + eap_status_e status = message_hash_save_certificate_verify(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + eap_variable_data_c message_hash(m_am_tools); + + status = message_hash_create( + false, + tls_handshake_type_certificate_verify, + &message_hash, + m_is_client); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: sign_with_private_key()\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: create_handshake_type_certificate_verify() message_hash"), + message_hash.get_data(message_hash.get_data_length()), + message_hash.get_data_length())); + + // NOTE this function is asyncronous. This causes complex control flow. + status = m_am_tls_services->sign_with_private_key( + &message_hash); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by complete_query_certificate_chain() call. + m_pending_sign_with_private_key = true; + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_query_certificate_chain() call. + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call is always completed on success. + status = eap_status_process_general_error; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else // All other status values means error, because this call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_handshake_type_finished() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_handshake_type_finished()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_handshake_type_finished()"); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // +-+-+-+-+-+-+-+-+ + + // | | + // + + + // | PRF(master_secret, finished_label, | + // + MD5(handshake_messages) + + + // | SHA-1(handshake_messages)) [0..11] | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_type_finished); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + // Note add_record_message() frees message on any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = add_record_message(tls_handshake_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +#if defined(USE_EAP_TLS_SESSION_TICKET) + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_handshake_type_new_session_ticket() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_handshake_type_new_session_ticket()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_handshake_type_new_session_ticket()"); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ticket lifetime hint (4 bytes) ... | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ... | opaque ticket ... n bytes + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + tls_handshake_message_c *tls_handshake_message = 0; + + eap_automatic_variable_c + automatic_tls_handshake_message(m_am_tools); + + eap_status_e status = allocate_handshake_message( + &tls_handshake_message, + &automatic_tls_handshake_message, + tls_handshake_type_new_session_ticket); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + + const tls_extension_c * const p_new_session_ticket = tls_extension_c::get_tls_extension( + tls_extension_type_session_ticket, + &m_supported_tls_extensions, + m_am_tools); + + if (p_new_session_ticket != 0) + { + eap_array_c session_ticket_extension_array(m_am_tools); + + tls_extension_c * const p_new_session_ticket_copy = p_new_session_ticket->copy(); + if (p_new_session_ticket_copy == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = session_ticket_extension_array.add_object(p_new_session_ticket_copy, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_handshake_message->set_tls_extensions(&session_ticket_extension_array); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + // -------------------------------------------------------------------- + + // Note add_record_message() frees message on any case. + automatic_tls_handshake_message.do_not_free_variable(); + + status = add_record_message(tls_handshake_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_change_cipher_spec_type_change_cipher_spec() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_change_cipher_spec_type_change_cipher_spec()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_change_cipher_spec_type_change_cipher_spec()"); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+ + // | CCS: 1 | + // +-+-+-+-+-+-+-+-+ + + tls_change_cipher_spec_message_c * const tls_change_cipher_spec_message + = new tls_change_cipher_spec_message_c(m_am_tools, this, m_is_client); + + eap_automatic_variable_c + automatic_tls_change_cipher_spec_message( + m_am_tools, tls_change_cipher_spec_message); + + if (tls_change_cipher_spec_message == 0 + || tls_change_cipher_spec_message->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + eap_status_e status = tls_change_cipher_spec_message->set_change_cipher_spec_type( + tls_change_cipher_spec_type_change_cipher_spec); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + // Note add_record_message() frees message on any case. + automatic_tls_change_cipher_spec_message.do_not_free_variable(); + + status = add_record_message(tls_change_cipher_spec_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::finish_handshake() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::finish_handshake(): m_tls_session_type=%d=%s, state=%d=%s\n"), + this, + (m_is_client == true ? "client": "server"), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + m_tls_peap_state, + eap_tls_trace_string_c::get_state_string(m_tls_peap_state))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::finish_handshake()"); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: finish_handshake(): m_master_secret"), + m_master_secret.get_data(), + m_master_secret.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: finish_handshake(): m_client_handshake_random_value"), + m_client_handshake_random_value.get_data(), + m_client_handshake_random_value.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: finish_handshake(): m_server_handshake_random_value"), + m_server_handshake_random_value.get_data(), + m_server_handshake_random_value.get_data_length())); + + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + eap_status_e status(eap_status_ok); + + tls_identity_privacy_handshake_state_e tmp_identity_privacy_handshake_state = +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + m_tls_identity_privacy_handshake_state; +#else + tls_identity_privacy_handshake_state_none; +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + + +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + if (m_tls_use_identity_privacy == false + || tmp_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_runs + || m_tls_session_type != tls_session_type_full_authentication) +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + { + status = set_tls_master_secret( + &m_master_secret, + &m_client_handshake_random_value, + &m_server_handshake_random_value); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +#if defined(USE_EAP_DEBUG_TRACE) + // These are for debug break points. + + if (m_is_client == true) + { + if (m_tls_session_type == tls_session_type_full_authentication) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: client, m_tls_session_type=%d=%s, state=%d=%s, privacy_handshake_state=%d=%s\n"), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + m_tls_peap_state, + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + tmp_identity_privacy_handshake_state, + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(tmp_identity_privacy_handshake_state))); + + } + else if (m_tls_session_type == tls_session_type_original_session_resumption) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: client, m_tls_session_type=%d=%s, state=%d=%s, privacy_handshake_state=%d=%s\n"), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + m_tls_peap_state, + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + tmp_identity_privacy_handshake_state, + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(tmp_identity_privacy_handshake_state))); + + } + else if (m_tls_session_type == tls_session_type_stateless_session_resumption) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: client, m_tls_session_type=%d=%s, state=%d=%s, privacy_handshake_state=%d=%s\n"), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + m_tls_peap_state, + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + tmp_identity_privacy_handshake_state, + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(tmp_identity_privacy_handshake_state))); + } +#if defined(USE_FAST_EAP_TYPE) + else if (m_tls_session_type == tls_session_type_eap_fast_pac_session_resumption) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: client, m_tls_session_type=%d=%s, state=%d=%s, privacy_handshake_state=%d=%s\n"), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + m_tls_peap_state, + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + tmp_identity_privacy_handshake_state, + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(tmp_identity_privacy_handshake_state))); + } +#endif //#if defined(USE_FAST_EAP_TYPE) + } + else // if (m_is_client == false) + { + if (m_tls_session_type == tls_session_type_full_authentication) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: server, m_tls_session_type=%d=%s, state=%d=%s, privacy_handshake_state=%d=%s\n"), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + m_tls_peap_state, + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + tmp_identity_privacy_handshake_state, + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(tmp_identity_privacy_handshake_state))); + + } + else if (m_tls_session_type == tls_session_type_original_session_resumption) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: server, m_tls_session_type=%d=%s, state=%d=%s, privacy_handshake_state=%d=%s\n"), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + m_tls_peap_state, + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + tmp_identity_privacy_handshake_state, + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(tmp_identity_privacy_handshake_state))); + + } + else if (m_tls_session_type == tls_session_type_stateless_session_resumption) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: server, m_tls_session_type=%d=%s, state=%d=%s, privacy_handshake_state=%d=%s\n"), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + m_tls_peap_state, + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + tmp_identity_privacy_handshake_state, + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(tmp_identity_privacy_handshake_state))); + } +#if defined(USE_FAST_EAP_TYPE) + else if (m_tls_session_type == tls_session_type_eap_fast_pac_session_resumption) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: server, m_tls_session_type=%d=%s, state=%d=%s, privacy_handshake_state=%d=%s\n"), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + m_tls_peap_state, + eap_tls_trace_string_c::get_state_string(m_tls_peap_state), + tmp_identity_privacy_handshake_state, + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(tmp_identity_privacy_handshake_state))); + } +#endif //#if defined(USE_FAST_EAP_TYPE) + } +#endif //#if defined(USE_EAP_DEBUG_TRACE) + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (m_application != 0) + { + m_application->set_tunneled_state( + m_tls_session_type); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +#if defined(USE_FAST_EAP_TYPE) + if (m_is_client == false + && m_eap_type == eap_type_fast + && m_tls_session_type == tls_session_type_eap_fast_pac_session_resumption) + { + // This is server. + // EAP-FAST is using Tunnel PAC. + // Here we cannot start tunneled authentication immediately + // because client migth have sent a User Authorization PAC. + // We must process the optional TLS Application message(s) + // to see did client send the User Authorization PAC. + set_state(tls_peap_state_wait_tunneled_authentication_start); + + eap_status_e tunnel_ready_status = m_application->peap_tunnel_ready(); + if (tunnel_ready_status != eap_status_ok) + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, tunnel_ready_status); + } + + tunnel_ready_status = get_type_partner()->peap_tunnel_ready(); + if (tunnel_ready_status != eap_status_ok) + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, tunnel_ready_status); + } + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + if (get_is_tunneled_tls() == false + || ((m_tls_session_type == tls_session_type_original_session_resumption + || m_tls_session_type == tls_session_type_stateless_session_resumption) + && ( +#if defined(USE_FAST_EAP_TYPE) + m_eap_type == eap_type_fast + || +#endif //#if defined(USE_FAST_EAP_TYPE) + m_eap_type == eap_type_ttls + || (m_eap_type == eap_type_peap +#if defined(USE_EAP_TLS_PEAP_TPPD_PEAP_V1_NEW_FIXES) + && m_peap_version > peap_version_1 +#else + && m_peap_version > peap_version_0_xp +#endif //#if defined(USE_EAP_TLS_PEAP_TPPD_PEAP_V1_NEW_FIXES) + && m_peap_version < peap_version_2)))) + { + if (m_tls_session_type == tls_session_type_full_authentication + && tmp_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_negotiates) + { + // TLS-privacy negotiation running. + } + else + { + set_state(tls_peap_state_tls_success); + } + + // PEAPv2 does not use m_eap_master_session_key directly. + // PEAPv2 does derive an other master session key. + // EAP-TLS, PEAPv0 and PEAPv1 does use m_eap_master_session_key. + if (m_eap_type == eap_type_tls // Plain EAP-TLS. + || m_eap_type == eap_type_ttls +#if defined(USE_FAST_EAP_TYPE) + || m_eap_type == eap_type_fast +#endif //#if defined(USE_FAST_EAP_TYPE) + || (m_eap_type == eap_type_peap + && (m_peap_version == peap_version_0_xp + || m_peap_version == peap_version_1))) + { + status = get_type_partner()->set_tls_master_secret(&m_eap_master_session_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + if (( +#if defined(USE_FAST_EAP_TYPE) + m_eap_type == eap_type_fast + || +#endif //#if defined(USE_FAST_EAP_TYPE) + m_eap_type == eap_type_ttls) + && (m_tls_session_type == tls_session_type_original_session_resumption + || m_tls_session_type == tls_session_type_stateless_session_resumption)) + { + eap_status_e notification_status = indicate_state_to_lower_layer(m_tls_peap_state); + if (notification_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, notification_status); + } + } + } + else if (tmp_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_none + || tmp_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_runs) + { + if ((m_eap_type == eap_type_peap + && m_peap_version >= peap_version_0_xp + && m_peap_version <= peap_version_2) + || m_eap_type == eap_type_ttls +#if defined(USE_FAST_EAP_TYPE) + || m_eap_type == eap_type_fast +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + if (m_application == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + set_state(tls_peap_state_peap_tunnel_ready); + + eap_status_e tunnel_ready_status = m_application->peap_tunnel_ready(); + if (tunnel_ready_status != eap_status_ok) + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, tunnel_ready_status); + } + + tunnel_ready_status = get_type_partner()->peap_tunnel_ready(); + if (tunnel_ready_status != eap_status_ok) + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, tunnel_ready_status); + } + +#if defined(USE_EAP_TLS_PEAP_TPPD_PEAP_V1_NEW_FIXES) + if ((m_tls_session_type == tls_session_type_original_session_resumption + || m_tls_session_type == tls_session_type_stateless_session_resumption) + && m_use_tppd_tls_peap == true + && m_peap_version == peap_version_1 + && m_use_tppd_peapv1_acknowledge_hack == true) + { + status = get_type_partner()->set_tls_master_secret(&m_eap_master_session_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } +#endif //#if defined(USE_EAP_TLS_PEAP_TPPD_PEAP_V1_NEW_FIXES) + + + if (m_is_client == true + && m_eap_type == eap_type_ttls) + { + // EAP-TTLS client starts the tunneled authentication. + + // Here we swap the addresses. + eap_am_network_id_c receive_network_id(m_am_tools, + m_send_network_id.get_destination_id(), + m_send_network_id.get_source_id(), + m_send_network_id.get_type()); + + status = m_application->start_ttls_tunneled_authentication( + &receive_network_id, + m_received_eap_identifier); + if (status != eap_status_ok + && status != eap_status_pending_request) + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, tunnel_ready_status); + } + } + + +#if defined(USE_EAP_CORE_SERVER) + if (m_is_client == false) + { + // Server + + if ( +#if defined(USE_FAST_EAP_TYPE) + m_eap_type == eap_type_fast + || +#endif //#if defined(USE_FAST_EAP_TYPE) + (m_eap_type == eap_type_peap + && (m_peap_version >= peap_version_2 + || ((m_tls_session_type == tls_session_type_original_session_resumption + || m_tls_session_type == tls_session_type_stateless_session_resumption) + && ( + m_peap_version == peap_version_0_xp +#if defined(USE_EAP_TLS_PEAP_TPPD_PEAP_V1_NEW_FIXES) + || m_peap_version == peap_version_1 +#endif //#if defined(USE_EAP_TLS_PEAP_TPPD_PEAP_V1_NEW_FIXES) + ) + ) + ) + ) + ) + { +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast + && m_send_piggypacked_eap_identity_request == false + && (m_tls_session_type == tls_session_type_eap_fast_server_unauthenticated_provisioning_mode_ADHP + || m_tls_session_type == tls_session_type_full_authentication)) + { + // Server does not start tunneled authentication yet. + // Instead server waits empty EAP-FAST acnowledge message from client. + + eap_state_notification_c notification( + m_am_tools, + &m_send_network_id, + m_is_client, + eap_state_notification_eap, + eap_protocol_layer_eap, + m_eap_type, + eap_state_none, + eap_state_authentication_wait_eap_fast_empty_acknowledge, + m_received_eap_identifier, + false); + get_type_partner()->state_notification(¬ification); + status = eap_status_ok; + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + { + // Here we swap the addresses. + eap_am_network_id_c receive_network_id(m_am_tools, + m_send_network_id.get_destination_id(), + m_send_network_id.get_source_id(), + m_send_network_id.get_type()); + + set_state(tls_peap_state_wait_tunneled_authentication_start); + + // Here we must start the tunneled EAP-type. + status = start_peap_tunneled_authentication( + &receive_network_id, + m_received_eap_identifier, + m_tls_session_type); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + } + } + else +#endif //#if defined(USE_EAP_CORE_SERVER) + { + // Client + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast) + { + // Here we swap the addresses. + eap_am_network_id_c receive_network_id(m_am_tools, + m_send_network_id.get_destination_id(), + m_send_network_id.get_source_id(), + m_send_network_id.get_type()); + + // Here we must start the tunneled EAP-type. + status = start_peap_tunneled_authentication( + &receive_network_id, + m_received_eap_identifier, + m_tls_session_type); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } +#endif //#if defined(USE_FAST_EAP_TYPE) + + } + + +#if defined(USE_EAP_TLS_PEAP_TPPD_PEAP_V1_NEW_FIXES) + if ((m_tls_session_type == tls_session_type_original_session_resumption + || m_tls_session_type == tls_session_type_stateless_session_resumption) + && m_use_tppd_tls_peap == true + && m_peap_version == peap_version_1 + && m_use_tppd_peapv1_acknowledge_hack == true) + { + if (m_is_client == true) + { + eap_state_notification_c notification( + m_am_tools, + &m_send_network_id, + m_is_client, + eap_state_notification_eap, + eap_protocol_layer_internal_type, + m_eap_type, + eap_state_none, + tls_peap_state_tppd_peapv1_waits_eap_success_or_tunneled_packet, + m_received_eap_identifier, + false); + get_type_partner()->state_notification(¬ification); + } + } +#endif //#if defined(USE_EAP_TLS_PEAP_TPPD_PEAP_V1_NEW_FIXES) + + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_no_matching_protocol_version); + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (m_tls_peap_state == tls_peap_state_tls_success) + { + // Notify lower layer that TLS/PEAP ended successfully + + if (get_is_tunneled_tls() == false + || (get_is_tunneled_tls() == true + && m_tunneled_eap_type_authentication_state + == eap_state_authentication_finished_successfully) + || (get_is_tunneled_tls() == true + && m_tls_session_type == tls_session_type_original_session_resumption)) + { + eap_status_e save_status = m_am_tls_services->save_tls_session( + &m_session_id, + &m_master_secret, + m_selected_cipher_suite +#if defined(USE_EAP_TLS_SESSION_TICKET) + , tls_extension_c::get_tls_extension( + tls_extension_type_session_ticket, + &m_received_tls_extensions, + m_am_tools) +#endif //#if defined(USE_EAP_TLS_SESSION_TICKET) + ); + if (save_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, save_status); + } + + eap_status_e notification_status = indicate_state_to_lower_layer(m_tls_peap_state); + if (notification_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, notification_status); + } + } + } + else if (m_tls_peap_state == tls_peap_state_peap_tunnel_ready) + { + // Notify lower layer that TLS tunnel is ready. + + eap_status_e notification_status = indicate_state_to_lower_layer(m_tls_peap_state); + if (notification_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, notification_status); + } + + // Change state that only one indication is sent to lower layer. + if (m_is_client == true) + { + set_state(tls_peap_state_wait_application_data); + } + else + { + set_state(tls_peap_state_wait_tunneled_authentication_start); + } + } + else if (m_tls_peap_state == tls_peap_state_failure) + { + eap_status_e notification_status = indicate_state_to_lower_layer(m_tls_peap_state); + if (notification_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, notification_status); + } + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: tls_record_c::finish_handshake(): No notification, m_tls_session_type=%d=%s, state=%d=%s\n"), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type), + m_tls_peap_state, + eap_tls_trace_string_c::get_state_string(m_tls_peap_state))); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_tls_protocol_alert( + const tls_alert_description_e par_alert_description, + const tls_alert_level_e par_alert_level, + const eap_status_e par_result) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_tls_protocol_alert()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_tls_protocol_alert()"); + + eap_status_e status = eap_status_authentication_failure; + + //-------------------------------------------------------------------- + + tls_alert_level_e alert_level = par_alert_level; + tls_alert_description_e alert_description = par_alert_description; + + if (alert_level == tls_alert_level_none) + { + alert_level = tls_alert_level_fatal; + } + + if (alert_description == tls_alert_description_none) + { + // Examine par_result. + switch(par_result) + { +#if EAP_TLS_UNSUPPORTED_ALERT_DESCRIPTION + #error Alert descriptions need more code. + case : + alert_description = tls_alert_description_close_notify; + break; +#endif //#if EAP_TLS_UNSUPPORTED_ALERT_DESCRIPTION + case eap_status_unexpected_message: + alert_description = tls_alert_description_unexpected_message; + break; + case eap_status_authentication_failure: + alert_description = tls_alert_description_bad_record_mac; + break; + case eap_status_decryption_failure: + case eap_status_illegal_padding: + alert_description = tls_alert_description_decryption_failed; + break; +#if EAP_TLS_UNSUPPORTED_ALERT_DESCRIPTION + case : + alert_description = tls_alert_description_record_overflow; + break; + case : + alert_description = tls_alert_description_decompression_failure; + break; +#endif //#if EAP_TLS_UNSUPPORTED_ALERT_DESCRIPTION + case eap_status_illegal_cipher_suite: + alert_description = tls_alert_description_handshake_failure; + break; + case eap_status_illegal_certificate: + case eap_status_bad_certificate: + alert_description = tls_alert_description_bad_certificate; +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast + && par_result == eap_status_bad_certificate) + { + alert_level = tls_alert_level_fatal; + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + { + alert_level = tls_alert_level_warning; + } + break; + case eap_status_unsupported_certificate: + alert_description = tls_alert_description_unsupported_certificate; + alert_level = tls_alert_level_warning; + break; + case eap_status_certificate_revoked: + alert_description = tls_alert_description_certificate_revoked; + alert_level = tls_alert_level_warning; + break; + case eap_status_certificate_expired: + alert_description = tls_alert_description_certificate_expired; + alert_level = tls_alert_level_warning; + break; + case eap_status_user_certificate_unknown: + case eap_status_ca_certificate_unknown: + alert_description = tls_alert_description_certificate_unknown; + alert_level = tls_alert_level_warning; + break; + case eap_status_illegal_encryption_parameter_size: + case eap_status_illegal_parameter: + alert_description = tls_alert_description_illegal_parameter; + break; + case eap_status_unknown_ca: + alert_description = tls_alert_description_unknown_ca; + break; + case eap_status_access_denied: + alert_description = tls_alert_description_access_denied; + break; + case eap_status_process_illegal_packet_error: + case eap_status_illegal_eap_code: + case eap_status_illegal_eap_type: + case eap_status_illegal_eap_identity: + case eap_status_too_short_message: + case eap_status_too_long_message: + case eap_status_wrong_protocol: + case eap_status_wrong_type: + case eap_status_data_length_not_aligned_to_block_size: + case eap_status_illegal_data_payload: + case eap_status_illegal_payload: + case eap_status_header_corrupted: + case eap_status_illegal_nai: + case eap_status_illegal_nai_payload: + alert_description = tls_alert_description_decode_error; + break; +#if EAP_TLS_UNSUPPORTED_ALERT_DESCRIPTION + case : + alert_description = tls_alert_description_decrypt_error; + break; + case : + alert_description = tls_alert_description_export_restriction; + break; +#endif //#if EAP_TLS_UNSUPPORTED_ALERT_DESCRIPTION + case eap_status_no_matching_protocol_version: + alert_description = tls_alert_description_protocol_version; + break; + case eap_status_insufficient_security: + alert_description = tls_alert_description_insufficient_security; + break; + case eap_status_allocation_error: + case eap_status_not_supported: + case eap_status_process_general_error: + case eap_status_type_does_not_exists_error: + case eap_status_timed_out: + case eap_status_hardware_not_ready: + alert_description = tls_alert_description_internal_error; + break; +#if EAP_TLS_UNSUPPORTED_ALERT_DESCRIPTION + case : + alert_description = tls_alert_description_user_canceled; + break; + case : + alert_description = tls_alert_description_no_renegotiation; + break; +#endif //#if EAP_TLS_UNSUPPORTED_ALERT_DESCRIPTION + default: + alert_description = tls_alert_description_internal_error; + break; + } + } + else + { + alert_description = par_alert_description; + } + + if (alert_level == tls_alert_level_fatal + && m_could_send_fatal_alert_message == false) + { + // If alert message is received or we have sent a fatal alert, we do not send alert anymore. + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: create_tls_protocol_alert(), ") + EAPL("do not send fatal alert message\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, par_result); + } + + if (alert_level == tls_alert_level_warning + && m_could_send_warning_alert_message == false) + { + // If alert message is received or we have sent a warning alert, + // we do not send alert anymore. + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: create_tls_protocol_alert(), ") + EAPL("do not send warning alert message\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, par_result); + } + + //-------------------------------------------------------------------- + + + set_state(tls_peap_state_failure); + + // This will cause the session terminate immediately. + status = get_type_partner()->set_session_timeout(0ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | alert level | alert descrip.| + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + tls_alert_message_c * const tls_alert_message + = new tls_alert_message_c(m_am_tools, m_is_client); + + eap_automatic_variable_c + automatic_tls_alert_message(m_am_tools, tls_alert_message); + + if (tls_alert_message == 0 + || tls_alert_message->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + // -------------------------------------------------------------------- + + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: create_tls_protocol_alert(): Alert message %s:%s\n"), + (m_is_client == true ? "client": "server"), + eap_tls_trace_string_c::get_alert_level_string(alert_level), + eap_tls_trace_string_c::get_alert_description_string(alert_description))); + + + status = tls_alert_message->set_alert_level(alert_level); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_alert_message->set_alert_description(alert_description); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + // Note add_record_message() frees message on any case. + automatic_tls_alert_message.do_not_free_variable(); + + status = add_record_message(tls_alert_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + m_force_tls_message_send = true; + + if (alert_level == tls_alert_level_fatal) + { + m_could_send_fatal_alert_message = false; + } + + if (alert_level == tls_alert_level_warning) + { + m_could_send_warning_alert_message = false; + } + + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::create_tls_application_data( + eap_buf_chain_wr_c * const sent_packet, + const u32_t header_offset) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::create_tls_application_data()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::create_tls_application_data()"); + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Application data n bytes | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + tls_application_data_message_c * const tls_application_data_message + = new tls_application_data_message_c(m_am_tools, m_is_client); + + eap_automatic_variable_c + automatic_tls_application_data_message( + m_am_tools, tls_application_data_message); + + if (tls_application_data_message == 0 + || tls_application_data_message->get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + if (sent_packet->get_data_length() < header_offset) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_short_message); + } + + u32_t packet_length = sent_packet->get_data_length()-header_offset; + + eap_status_e status = tls_application_data_message->set_application_data( + sent_packet->get_data_offset(header_offset, packet_length), + packet_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + // Note add_record_message() frees message on any case. + automatic_tls_application_data_message.do_not_free_variable(); + + status = add_record_message(tls_application_data_message); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // -------------------------------------------------------------------- + + if (status == eap_status_ok) + { + status = check_sent_tls_message(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + // -------------------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + + +//-------------------------------------------------- + +EAP_FUNC_EXPORT bool tls_record_c::cipher_suite_is_3DES_EDE_CBC_SHA( + tls_cipher_suites_e cipher_suite) const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (cipher_suite == tls_cipher_suites_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA + || cipher_suite == tls_cipher_suites_TLS_RSA_WITH_3DES_EDE_CBC_SHA + || cipher_suite == tls_cipher_suites_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) + { + return true; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return false; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT bool tls_record_c::cipher_suite_is_AES_128_CBC_SHA( + tls_cipher_suites_e cipher_suite) const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (cipher_suite == tls_cipher_suites_TLS_DHE_DSS_WITH_AES_128_CBC_SHA + || cipher_suite == tls_cipher_suites_TLS_RSA_WITH_AES_128_CBC_SHA + || cipher_suite == tls_cipher_suites_TLS_DHE_RSA_WITH_AES_128_CBC_SHA +#if defined(USE_FAST_EAP_TYPE) + || cipher_suite == tls_cipher_suites_TLS_DH_anon_WITH_AES_128_CBC_SHA +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + return true; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return false; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT bool tls_record_c::cipher_suite_is_RC4_128_MD5( + tls_cipher_suites_e cipher_suite) const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (cipher_suite == tls_cipher_suites_TLS_RSA_WITH_RC4_128_MD5) + { + return true; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return false; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT bool tls_record_c::cipher_suite_is_RC4_128_SHA( + tls_cipher_suites_e cipher_suite) const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (cipher_suite == tls_cipher_suites_TLS_RSA_WITH_RC4_128_SHA) + { + return true; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return false; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT bool tls_record_c::cipher_suite_is_TLS_RSA() const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (m_selected_cipher_suite == tls_cipher_suites_TLS_RSA_WITH_3DES_EDE_CBC_SHA + || m_selected_cipher_suite == tls_cipher_suites_TLS_RSA_WITH_AES_128_CBC_SHA + || m_selected_cipher_suite == tls_cipher_suites_TLS_RSA_WITH_RC4_128_MD5 + || m_selected_cipher_suite == tls_cipher_suites_TLS_RSA_WITH_RC4_128_SHA) + { + return true; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return false; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT bool tls_record_c::cipher_suite_is_TLS_DHE_RSA() const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (m_selected_cipher_suite == tls_cipher_suites_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + || m_selected_cipher_suite == tls_cipher_suites_TLS_DHE_RSA_WITH_AES_128_CBC_SHA) + { + return true; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return false; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT bool tls_record_c::cipher_suite_is_TLS_DHE_DSS() const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (m_selected_cipher_suite == tls_cipher_suites_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA + || m_selected_cipher_suite == tls_cipher_suites_TLS_DHE_DSS_WITH_AES_128_CBC_SHA) + { + return true; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return false; +} + +//-------------------------------------------------- + +#if defined(USE_FAST_EAP_TYPE) + +EAP_FUNC_EXPORT bool tls_record_c::cipher_suite_is_TLS_DH_anon() const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (m_selected_cipher_suite == tls_cipher_suites_TLS_DH_anon_WITH_AES_128_CBC_SHA) + { + return true; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return false; +} + +#endif //#if defined(USE_FAST_EAP_TYPE) + +//-------------------------------------------------- + +#if EAP_TLS_UNSUPPORTED_CIPHER_SUITE +#error This one needs more code. Diffie-Hellman sertificate key exchange with different parameters is NOT supported. +EAP_FUNC_EXPORT bool tls_record_c::cipher_suite_is_TLS_DH_DSS() const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (m_selected_cipher_suite == tls_cipher_suites_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA) + { + return true; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return false; +} +#endif + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::generate_dhe_keys() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: key_function: starts: tls_record_c::generate_dhe_keys()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::generate_dhe_keys()"); + + eap_status_e status = eap_status_not_supported; + + if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true +#if defined(USE_FAST_EAP_TYPE) + || (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + if (m_dhe_prime.get_is_valid_data() == false + || m_dhe_group_generator.get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + crypto_ephemeral_diffie_hellman_c dhe(m_am_tools); + + if (dhe.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: key_function: dhe.generate_diffie_hellman_keys()\n"), + (m_is_client == true ? "client": "server"))); + + status = dhe.generate_diffie_hellman_keys( + &m_own_private_dhe_key, + &m_own_public_dhe_key, + m_dhe_prime.get_data(m_dhe_prime.get_data_length()), + m_dhe_prime.get_data_length(), + m_dhe_group_generator.get_data(m_dhe_group_generator.get_data_length()), + m_dhe_group_generator.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_cipher_suite); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::generate_premaster_secret() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: key_function: starts: tls_record_c::generate_premaster_secret()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::generate_premaster_secret()"); + + eap_status_e status = eap_status_not_supported; + + m_key_material_generated = false; + + if (cipher_suite_is_TLS_RSA() == true) + { + // Encrypted premaster secret is included when selected + // cipher suite is using RSA key exchange. + // First two bytes are version of TLS. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // +-+-+-+-+-+-+-+-+ + + // | | + // + + + // | Encrypted Premaster Secret (48 bytes) | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + crypto_random_c rand(m_am_tools); + + status = m_premaster_secret.set_buffer_length(TLS_PREMASTER_SECRET_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + m_premaster_secret.set_data_length(TLS_PREMASTER_SECRET_SIZE); + + u16_t version = eap_htons(tls_version_3_1); + status = m_premaster_secret.add_data_to_offset(0ul, &version, sizeof(version)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (m_premaster_secret.get_data_length() < sizeof(version)) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = rand.get_rand_bytes( + m_premaster_secret.get_data_offset( + sizeof(version), + m_premaster_secret.get_data_length()-sizeof(version)), + m_premaster_secret.get_data_length()-sizeof(version)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS: m_premaster_secret"), + m_premaster_secret.get_data(m_premaster_secret.get_data_length()), + m_premaster_secret.get_data_length())); + } + else if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true +#if defined(USE_FAST_EAP_TYPE) + || (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && cipher_suite_is_TLS_DH_anon() == true) +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + { + // Diffie-Hellman Yc is included when selected cipher suite is + // ephemeral Diffie-Hellman key exchange. + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | DH Yc length | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // + + + // | DH Yc value | + // + + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + if (m_dhe_prime.get_is_valid_data() == false + || m_dhe_group_generator.get_is_valid_data() == false + || m_peer_public_dhe_key.get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + crypto_ephemeral_diffie_hellman_c dhe(m_am_tools); + + if (dhe.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: key_function: dhe.generate_g_power_to_xy()\n"), + (m_is_client == true ? "client": "server"))); + + status = dhe.generate_g_power_to_xy( + &m_own_private_dhe_key, + &m_peer_public_dhe_key, + &m_premaster_secret, + m_dhe_prime.get_data(m_dhe_prime.get_data_length()), + m_dhe_prime.get_data_length(), + m_dhe_group_generator.get_data(m_dhe_group_generator.get_data_length()), + m_dhe_group_generator.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS: m_premaster_secret"), + m_premaster_secret.get_data(m_premaster_secret.get_data_length()), + m_premaster_secret.get_data_length())); + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_cipher_suite); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::generate_master_secret() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: key_function: starts: tls_record_c::generate_master_secret()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::generate_master_secret()"); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS: tls_record_c::generate_master_secret(): m_premaster_secret"), + m_premaster_secret.get_data(), + m_premaster_secret.get_data_length())); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS: tls_record_c::generate_master_secret(): m_client_handshake_random_value"), + m_client_handshake_random_value.get_data(), + m_client_handshake_random_value.get_data_length())); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS: tls_record_c::generate_master_secret(): m_server_handshake_random_value"), + m_server_handshake_random_value.get_data(), + m_server_handshake_random_value.get_data_length())); + + if (m_premaster_secret.get_is_valid_data() == false + || m_client_handshake_random_value.get_is_valid_data() == false + || m_server_handshake_random_value.get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + eap_status_e status = eap_status_not_supported; + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: prf_function: tls_prf.tls_prf_output()\n"), + (m_is_client == true ? "client": "server"))); + + crypto_tls_prf_c tls_prf(m_am_tools); + + eap_variable_data_c label(m_am_tools); + if (label.get_is_valid() == false) + { + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = label.add_data( + TLS_MASTER_SECRET_LABEL, + TLS_MASTER_SECRET_LABEL_LENGTH); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + eap_variable_data_c seed(m_am_tools); + if (seed.get_is_valid() == false) + { + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + status = seed.set_copy_of_buffer(&m_client_handshake_random_value); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = seed.add_data(&m_server_handshake_random_value); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_prf.tls_prf_init( + &m_premaster_secret, + &label, + &seed); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_master_secret.set_buffer_length(TLS_MASTER_SECRET_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + m_master_secret.set_data_length(TLS_MASTER_SECRET_SIZE); + + status = tls_prf.tls_prf_output( + m_master_secret.get_data(m_master_secret.get_data_length()), + m_master_secret.get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: tls_record_c::generate_master_secret(): m_master_secret"), + m_master_secret.get_data(), + m_master_secret.get_data_length())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +#if defined(USE_FAST_EAP_TYPE) + +EAP_FUNC_EXPORT eap_status_e tls_record_c::generate_eap_fast_master_secret_from_pac_key( + const eap_variable_data_c * const pac_key) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: key_function: starts: tls_record_c::generate_eap_fast_master_secret_from_pac_key()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::generate_eap_fast_master_secret_from_pac_key()"); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS: tls_record_c::generate_eap_fast_master_secret_from_pac_key(): PAC_Key"), + pac_key->get_data(), + pac_key->get_data_length())); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS: tls_record_c::generate_eap_fast_master_secret_from_pac_key(): m_server_handshake_random_value"), + m_server_handshake_random_value.get_data(), + m_server_handshake_random_value.get_data_length())); + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS: tls_record_c::generate_eap_fast_master_secret_from_pac_key(): m_client_handshake_random_value"), + m_client_handshake_random_value.get_data(), + m_client_handshake_random_value.get_data_length())); + + if (pac_key == 0 + || pac_key->get_is_valid_data() == false + || m_client_handshake_random_value.get_is_valid_data() == false + || m_server_handshake_random_value.get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + + eap_status_e status(eap_status_not_supported); + + + crypto_eap_fast_hmac_sha1_prf_c tls_prf(m_am_tools); + + eap_variable_data_c label(m_am_tools); + if (label.get_is_valid() == false) + { + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = label.add_data( + EAP_FAST_PAC_TO_MASTER_SECRET_LABEL, + EAP_FAST_PAC_TO_MASTER_SECRET_LABEL_LENGTH); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + eap_variable_data_c seed(m_am_tools); + if (seed.get_is_valid() == false) + { + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = seed.set_copy_of_buffer(&m_server_handshake_random_value); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = seed.add_data(&m_client_handshake_random_value); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = tls_prf.t_prf_init( + pac_key, + &label, + &seed); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_master_secret.set_buffer_length(TLS_MASTER_SECRET_SIZE); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + m_master_secret.set_data_length(TLS_MASTER_SECRET_SIZE); + + status = tls_prf.t_prf_output( + m_master_secret.get_data(), + static_cast(m_master_secret.get_data_length())); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("EAP-FAST: m_master_secret"), + m_master_secret.get_data(), + m_master_secret.get_data_length())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +#endif //#if defined(USE_FAST_EAP_TYPE) + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_query_cipher_suites_and_previous_session( + const tls_session_type_e /* tls_session_type */, + EAP_TEMPLATE_CONST eap_array_c * const cipher_suites, + EAP_TEMPLATE_CONST eap_array_c * const compression_methods, +#if defined(USE_EAP_TLS_SESSION_TICKET) + EAP_TEMPLATE_CONST eap_array_c * const tls_extensions, +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + const eap_variable_data_c * const resumed_session_id, + const eap_variable_data_c * const resumed_master_secret, + const tls_cipher_suites_e resumed_cipher_suite, + const eap_status_e completion_status) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::complete_query_cipher_suites_and_previous_session()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_query_cipher_suites_and_previous_session()"); + + m_pending_query_cipher_suites_and_previous_session = false; + + m_proposed_cipher_suites.reset(); + m_proposed_compression_methods.reset(); + + eap_status_e status = eap_status_process_general_error; + + + if (completion_status != eap_status_ok) + { + status = create_tls_protocol_alert( + tls_alert_description_none, + tls_alert_level_none, + completion_status); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + status = copy_simple( + cipher_suites, + &m_proposed_cipher_suites, + m_am_tools, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = for_each(&m_proposed_cipher_suites, u16_t_to_host_order, m_am_tools, false); + if (status != eap_status_ok + || m_proposed_cipher_suites.get_object_count() == 0ul) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == false) + { + // TLS_DH_anon_WITH_AES_128_CBC_SHA is allowed only with EAP-FAST unauthenticated provisioning mode. + u16_t illegal_cipher_suite(static_cast(tls_cipher_suites_TLS_DH_anon_WITH_AES_128_CBC_SHA)); + + i32_t index = find_simple( + &m_proposed_cipher_suites, + &illegal_cipher_suite, + m_am_tools); + if (index >= 0) + { + status = m_proposed_cipher_suites.remove_object(index); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + } +#endif //#if defined(USE_FAST_EAP_TYPE) + + status = copy_simple( + compression_methods, + &m_proposed_compression_methods, + m_am_tools, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast + && m_tls_session_type == tls_session_type_eap_fast_pac_session_resumption) + { + // Let's try tunnel PAC authentication. + + // We will use the first cipher suite as an default one. + u16_t * cipher_suite = m_proposed_cipher_suites.get_object(0ul); + if (cipher_suite != 0) + { + m_resumed_cipher_suite = static_cast(*cipher_suite); + } + else + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter); + } + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + if (resumed_session_id != 0 + && resumed_session_id->get_is_valid_data() == true + && resumed_session_id->get_data_length() > 0ul + && resumed_master_secret != 0 + && resumed_master_secret->get_is_valid_data() == true + && resumed_master_secret->get_data_length() == TLS_MASTER_SECRET_SIZE + && resumed_cipher_suite != tls_cipher_suites_none) + { + // Resume previous session. + + status = m_session_id.set_copy_of_buffer(resumed_session_id); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_master_secret.set_copy_of_buffer(resumed_master_secret); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: complete_query_cipher_suites_and_previous_session(): ") + EAPL("Resume previous session.\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_query_cipher_suites_and_previous_session(): resumed m_master_secret"), + m_master_secret.get_data(m_master_secret.get_data_length()), + m_master_secret.get_data_length())); + + m_resumed_cipher_suite = resumed_cipher_suite; + + set_tls_session_type(tls_session_type_original_session_resumption); + } + else + { + +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + if (m_is_client == true + && m_tls_use_identity_privacy == true + && m_tls_identity_privacy_handshake_state == tls_identity_privacy_handshake_state_none) + { + set_tls_identity_privacy_handshake_state(tls_identity_privacy_handshake_state_negotiates); + } +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + + set_tls_session_type(tls_session_type_full_authentication); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: complete_query_cipher_suites_and_previous_session(): ") + EAPL("full authentication.\n"), + (m_is_client == true ? "client": "server"))); + + eap_status_e notification_status = indicate_state_to_lower_layer( + tls_peap_state_full_authentication); + if (notification_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, notification_status); + } + } + +#if defined(USE_EAP_TLS_SESSION_TICKET) + if (tls_extensions != 0) + { + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast) + { + // Nothing to do. + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + { + status = copy( + tls_extensions, + &m_supported_tls_extensions, + m_am_tools, + false); + } + + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + +#if defined(USE_FAST_EAP_TYPE) + eap_fast_pac_type_e required_pac_type(eap_fast_pac_type_none); + + if (m_eap_type == eap_type_fast) + { + // In EAP-FAST we are interested only Tunnel PAC. + required_pac_type = eap_fast_pac_type_tunnel_pac; + } +#endif //#if defined(USE_FAST_EAP_TYPE) + + const tls_extension_c * const supported_session_ticket_extension = tls_extension_c::get_tls_extension( + tls_extension_type_session_ticket, +#if defined(USE_FAST_EAP_TYPE) + required_pac_type, +#endif //#if defined(USE_FAST_EAP_TYPE) + &m_supported_tls_extensions, + m_am_tools); + + if (supported_session_ticket_extension != 0 + && supported_session_ticket_extension->get_is_valid_data() == true + && supported_session_ticket_extension->get_data_length() > 0ul) + { +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: complete_query_cipher_suites_and_previous_session(): ") + EAPL("SST: EAP-FAST PAC stateless session resumption, length = %d.\n"), + (m_is_client == true ? "client": "server"), + supported_session_ticket_extension->get_data_length())); + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + //if (m_tls_session_type == tls_session_type_original_session_resumption) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: complete_query_cipher_suites_and_previous_session(): ") + EAPL("SST: stateless session resumption, length = %d.\n"), + (m_is_client == true ? "client": "server"), + supported_session_ticket_extension->get_data_length())); + + set_tls_session_type(tls_session_type_stateless_session_resumption); + } + } + } +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast + //&& m_tls_session_type == tls_session_type_full_authentication + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true) + { + // Try dynamic provisioning of PAC. + + set_tls_session_type(tls_session_type_eap_fast_server_unauthenticated_provisioning_mode_ADHP); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: complete_query_cipher_suites_and_previous_session(): ") + EAPL("server unauthenticated provisioning mode ADHP.\n"), + (m_is_client == true ? "client": "server"))); + + m_proposed_cipher_suites.reset(); + + u16_t * const anonymous_cipher_suite = new u16_t; + + if (anonymous_cipher_suite == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + *anonymous_cipher_suite = static_cast(tls_cipher_suites_TLS_DH_anon_WITH_AES_128_CBC_SHA); + + status = m_proposed_cipher_suites.add_object( + anonymous_cipher_suite, + true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload); + } + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: complete_query_cipher_suites_and_previous_session(): ") + EAPL("m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP = %d.\n"), + (m_is_client == true ? "client": "server"), + m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP)); + } +#endif //#if defined(USE_FAST_EAP_TYPE) + + + } + + + if (status == eap_status_ok) + { + status = check_sent_tls_message(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = eap_status_completed_request; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_select_cipher_suite_and_check_session_id( + const tls_session_type_e tls_session_type, + const u16_t selected_cipher_suite, + const eap_variable_data_c * const resumed_session_id, + const eap_variable_data_c * const resumed_master_secret, +#if defined(USE_EAP_TLS_SESSION_TICKET) + const tls_extension_c * const new_session_ticket_or_null, +#endif //#if defined(USE_EAP_TLS_SESSION_TICKET) + const eap_status_e completion_status) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::complete_select_cipher_suite_and_check_session_id()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_select_cipher_suite_and_check_session_id()"); + + EAP_ASSERT_ALWAYS(m_is_client == false); + + eap_status_e status = eap_status_ok; + + m_pending_select_cipher_suite_and_check_session_id = false; + + + if (completion_status != eap_status_ok) + { + status = create_tls_protocol_alert( + tls_alert_description_none, + tls_alert_level_none, + completion_status); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + set_tls_session_type(tls_session_type); + + set_selected_cipher_suite(static_cast(selected_cipher_suite)); + m_selected_compression_method = tls_compression_method_null; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast + && m_tls_session_type == tls_session_type_full_authentication + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == true + && m_selected_cipher_suite == tls_cipher_suites_TLS_DH_anon_WITH_AES_128_CBC_SHA) + { + // Try dynamic provisioning of PAC. + + set_tls_session_type(tls_session_type_eap_fast_server_unauthenticated_provisioning_mode_ADHP); + } +#endif //#if defined(USE_FAST_EAP_TYPE) + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +#if defined(USE_EAP_TLS_SESSION_TICKET) + if (new_session_ticket_or_null != 0) + { + // We are using the session ticket payload. + + tls_extension_c * copy_of_new_session_ticket = new_session_ticket_or_null->copy(); + if (copy_of_new_session_ticket == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + // Save the new session ticket to be included in next NewSessionTicket message. + status = m_supported_tls_extensions.add_object(copy_of_new_session_ticket, true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + if (m_tls_session_type == tls_session_type_stateless_session_resumption) + { + if (resumed_session_id != 0 + && resumed_session_id->get_is_valid_data() == true) + { + // The session ID is needed if client did include it to the ClientHello. + status = m_session_id.set_copy_of_buffer(resumed_session_id); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + if (resumed_master_secret != 0 + && resumed_master_secret->get_is_valid_data() == true + && resumed_master_secret->get_data_length() == TLS_MASTER_SECRET_SIZE) + { + status = m_master_secret.set_copy_of_buffer(resumed_master_secret); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_select_cipher_suite_and_check_session_id(): session ticket resumed m_master_secret"), + m_master_secret.get_data(m_master_secret.get_data_length()), + m_master_secret.get_data_length())); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: ") + EAPL("complete_select_cipher_suite_and_check_session_id(): restores session using session ticket\n"), + (m_is_client == true ? "client": "server"))); + + eap_status_e notification_status = indicate_state_to_lower_layer( + tls_peap_state_original_session_resumption); + if (notification_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, notification_status); + } + } + } + else +#endif //#if defined(USE_EAP_TLS_SESSION_TICKET) + if (m_tls_session_type == tls_session_type_original_session_resumption + && ((m_eap_type == eap_type_peap + /** @{ PEAPv2 does not support session resumption yet. } */ + && m_peap_version != peap_version_2) + || m_eap_type == eap_type_tls + || m_eap_type == eap_type_ttls +#if defined(USE_FAST_EAP_TYPE) + || m_eap_type == eap_type_fast +#endif //#if defined(USE_FAST_EAP_TYPE) + ) + && resumed_session_id != 0 + && resumed_session_id->get_is_valid_data() == true + && resumed_session_id->get_data_length() > 0ul + && resumed_master_secret != 0 + && resumed_master_secret->get_is_valid_data() == true + && resumed_master_secret->get_data_length() == TLS_MASTER_SECRET_SIZE + ) + { + // Restore previous session. + + status = m_session_id.set_copy_of_buffer(resumed_session_id); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_master_secret.set_copy_of_buffer(resumed_master_secret); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_select_cipher_suite_and_check_session_id(): resumed m_master_secret"), + m_master_secret.get_data(m_master_secret.get_data_length()), + m_master_secret.get_data_length())); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: ") + EAPL("complete_select_cipher_suite_and_check_session_id(): restores session\n"), + (m_is_client == true ? "client": "server"))); + + eap_status_e notification_status = indicate_state_to_lower_layer( + tls_peap_state_original_session_resumption); + if (notification_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, notification_status); + } + } +#if defined(USE_FAST_EAP_TYPE) + else if (m_tls_session_type == tls_session_type_eap_fast_pac_session_resumption) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_select_cipher_suite_and_check_session_id(): EAP-FAST server: %s\n"), + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type))); + + // Parameter resumed_master_secret includes PAC-Key. + status = m_eap_fast_pac_key.set_copy_of_buffer(resumed_master_secret); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_select_cipher_suite_and_check_session_id(): resumed m_master_secret"), + m_master_secret.get_data(m_master_secret.get_data_length()), + m_master_secret.get_data_length())); + + eap_status_e notification_status = indicate_state_to_lower_layer( + tls_peap_state_original_session_resumption); + if (notification_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, notification_status); + } + } + else if (m_tls_session_type == tls_session_type_eap_fast_server_unauthenticated_provisioning_mode_ADHP) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_select_cipher_suite_and_check_session_id(): EAP-FAST server unauthenticated provisioning mode\n"))); + + eap_status_e notification_status = indicate_state_to_lower_layer( + tls_peap_state_full_authentication); + if (notification_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, notification_status); + } + } +#endif //#if defined(USE_FAST_EAP_TYPE) + else + { + set_tls_session_type(tls_session_type_full_authentication); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_select_cipher_suite_and_check_session_id(): full authentication\n"))); + + eap_status_e notification_status = indicate_state_to_lower_layer( + tls_peap_state_full_authentication); + if (notification_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, notification_status); + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +#if defined(USE_EAP_TLS_SESSION_TICKET) + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type != eap_type_fast) +#endif //#if defined(USE_FAST_EAP_TYPE) + { + if (m_tls_session_type == tls_session_type_original_session_resumption + || m_tls_session_type == tls_session_type_stateless_session_resumption) + { + const tls_extension_c * const supported_session_ticket_extension = tls_extension_c::get_tls_extension( + tls_extension_type_session_ticket, + &m_supported_tls_extensions, + m_am_tools); + if (supported_session_ticket_extension != 0) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: message_function: complete_select_cipher_suite_and_check_session_id(): ") + EAPL("SST: Server will send a new session ticket to client, length = %d.\n"), + (m_is_client == true ? "client": "server"), + supported_session_ticket_extension->get_data_length())); + + // Server will send a new session ticket to client. + status = completion_action_add( + tls_completion_action_create_handshake_type_new_session_ticket); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + } + } + +#endif //#if defined(USE_EAP_TLS_SESSION_TICKET) + + + // The following sequence depends on whether the previous + // session is restored and on the selected cipher suite. + + if (m_tls_session_type == tls_session_type_original_session_resumption +#if defined(USE_EAP_TLS_SESSION_TICKET) + || m_tls_session_type == tls_session_type_stateless_session_resumption +#if defined(USE_FAST_EAP_TYPE) + || m_tls_session_type == tls_session_type_eap_fast_pac_session_resumption +#endif //#if defined(USE_FAST_EAP_TYPE) +#endif //#if defined(USE_EAP_TLS_SESSION_TICKET) + ) + { +#if defined(USE_EAP_TLS_SESSION_TICKET) + if (m_will_receive_new_session_ticket == true) + { + set_state(tls_peap_state_wait_handshake_type_new_session_ticket); + } + else +#endif // #if defined(USE_EAP_TLS_SESSION_TICKET) + { + set_state(tls_peap_state_wait_change_cipher_spec); + } + + status = completion_action_add( + tls_completion_action_create_change_cipher_spec_type_change_cipher_spec); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = completion_action_add(tls_completion_action_create_handshake_type_finished); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } +#if defined(USE_FAST_EAP_TYPE) + else if (m_tls_session_type == tls_session_type_eap_fast_server_unauthenticated_provisioning_mode_ADHP) + { + // Ephemeral DH key exchange causes creation of server_key_exchange message. + // Server sends DH public key and related parameters to client. + + status = completion_action_add(tls_completion_action_query_dh_parameters); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = completion_action_add( + tls_completion_action_create_handshake_type_server_key_exchange); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // This will complete creation of handshake_type_server_key_exchange message. + status = completion_action_add( + tls_completion_action_complete_create_handshake_type_server_key_exchange); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // Also the other pending messages will be processed after this action is completed. + eap_status_e compl_status = completion_action_add( + tls_completion_action_process_tls_records); + if (compl_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = completion_action_add( + tls_completion_action_create_handshake_type_server_hello_done); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + set_state(tls_peap_state_wait_handshake_type_client_key_exchange); + } +#endif //#if defined(USE_FAST_EAP_TYPE) + else + { + if (m_tls_peap_server_authenticates_client_config_server == true) + { + set_state(tls_peap_state_wait_handshake_type_certificate); + } + else + { + set_state(tls_peap_state_wait_handshake_type_client_key_exchange); + } + + status = completion_action_add(tls_completion_action_create_handshake_type_certificate); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (cipher_suite_is_TLS_DHE_DSS() == true + || cipher_suite_is_TLS_DHE_RSA() == true) + { + // Ephemeral DH key exchange causes creation of server_key_exchange message. + // Server sends DH public key and related parameters to client. + + status = completion_action_add(tls_completion_action_query_dh_parameters); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = completion_action_add( + tls_completion_action_create_handshake_type_server_key_exchange); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // This will complete creation of handshake_type_server_key_exchange message. + status = completion_action_add( + tls_completion_action_complete_create_handshake_type_server_key_exchange); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // Also the other pending messages will be processed after this action is completed. + eap_status_e compl_status = completion_action_add( + tls_completion_action_process_tls_records); + if (compl_status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + if (m_tls_peap_server_authenticates_client_config_server == true) + { + // Server initiates client authentication. + status = completion_action_add( + tls_completion_action_create_handshake_type_certificate_request); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + status = completion_action_add( + tls_completion_action_create_handshake_type_server_hello_done); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: %s: pki_function: query_certificate_chain()\n"), + (m_is_client == true ? "client": "server"))); + + status = m_am_tls_services->query_certificate_chain( + &m_own_certificate_authorities, + &m_own_certificate_types, + m_selected_cipher_suite); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by + // complete_query_certificate_chain() call. + m_pending_query_certificate_chain = true; + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_query_certificate_chain() call. + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call is always completed on success. + status = eap_status_process_general_error; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else // All other status values means error, because this + // call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (m_tls_peap_server_authenticates_client_config_server == true) + { + // Server initiates client authentication. + status = m_am_tls_services->query_certificate_authorities_and_types(); + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by + // complete_query_certificate_authorities_and_types() call. + m_pending_query_certificate_authorities_and_types = true; + } + else if (status == eap_status_completed_request) + { + // This is already completed by + // complete_query_certificate_authorities_and_types() call. + } + else if (status == eap_status_ok) + { + // This is also an error case, because this call is + // always completed on success. + status = eap_status_process_general_error; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else // All other status values means error, because this + // call is always completed on success. + { + // This is an error case. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN_AND_CREATE_TLS_PROTOCOL_ALERT(m_am_tools, status); + } + } + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + if (status == eap_status_ok) + { + status = check_sent_tls_message(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = eap_status_completed_request; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +#if defined(USE_EAP_TLS_SESSION_TICKET) + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_query_new_session_ticket( + const tls_extension_c * const new_session_ticket_or_null) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: pki_function: starts: tls_record_c::complete_query_new_session_ticket()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_query_new_session_ticket()"); + + eap_status_e status(eap_status_ok); + + if (new_session_ticket_or_null != 0) + { + tls_extension_c * const copy_of_session_ticket = new_session_ticket_or_null->copy(); + + if (copy_of_session_ticket == 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + status = m_supported_tls_extensions.add_object(copy_of_session_ticket, true); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +#endif //#if defined(USE_EAP_TLS_SESSION_TICKET) + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_verify_certificate_chain( + const eap_status_e result) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: pki_function: starts: tls_record_c::complete_verify_certificate_chain()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_verify_certificate_chain()"); + + eap_status_e status = result; + + m_pending_verify_certificate_chain = false; + + m_peer_certificate_chain_result = result; + + if (m_peer_certificate_chain_result == eap_status_ok) + { + // Ok certificate. + } + else + { + // Illegal certificate. + + status = create_tls_protocol_alert( + tls_alert_description_none, + tls_alert_level_none, + m_peer_certificate_chain_result); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + if (status == eap_status_ok) + { + status = check_sent_tls_message(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = eap_status_completed_request; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_query_certificate_chain( + EAP_TEMPLATE_CONST eap_array_c * const certificate_chain, + const eap_status_e completion_status) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::complete_query_certificate_chain()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_query_certificate_chain()"); + + eap_status_e status = eap_status_not_supported; + + m_pending_query_certificate_chain = false; + + { + if (completion_status != eap_status_ok + || certificate_chain == 0 + || certificate_chain->get_object_count() == 0) + { + if (completion_status != eap_status_ok) + { + (void)EAP_STATUS_RETURN(m_am_tools, completion_status); + } + + if (m_is_client == false) + { + // Server fails immediately. + + status = create_tls_protocol_alert( + tls_alert_description_none, + tls_alert_level_none, + completion_status); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: pki_function: complete_query_certificate_chain(): ") + EAPL("Server have illegal sertificate for this cipher suite.\n"), + (m_is_client == true ? "client": "server"))); + } + else + { + if (m_tls_peap_server_authenticates_client_policy_flag == true + || (m_tls_peap_server_authenticates_client_policy_flag == false + && completion_status != eap_status_illegal_certificate + && completion_status != eap_status_ca_certificate_unknown)) + { + // Client does fail immediately. + // This session could NOT use server only authentication. + if (completion_status == eap_status_illegal_certificate) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: pki_function: complete_query_certificate_chain(): ") + EAPL("Client have illegal sertificate for this cipher suite.\n"), + (m_is_client == true ? "client": "server"))); + + status = eap_status_illegal_certificate; + (void)EAP_STATUS_RETURN(m_am_tools, status); + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: TLS: %s: pki_function: complete_query_certificate_chain(): ") + EAPL("Client does NOT allow anonymous client.\n"), + (m_is_client == true ? "client": "server"))); + + status = eap_status_insufficient_security; + (void)EAP_STATUS_RETURN(m_am_tools, status); + } + + // This will cause the session terminate immediately. + status = get_type_partner()->set_session_timeout(0ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast) + { + send_error_notification(eap_status_no_pac_nor_certs_to_authenticate_with_provision_disabled); + + status = create_tls_protocol_alert( + tls_alert_description_internal_error, + tls_alert_level_fatal, + status); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + { + status = create_tls_protocol_alert( + tls_alert_description_none, + tls_alert_level_none, + completion_status); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + } + else + { + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast + && m_eap_fast_allow_server_unauthenticated_provisioning_mode_ADHP == false + && m_fast_allow_server_authenticated_provisioning_mode == false) + { + // No PAC, no sertificate, no provision allowed. + // This will cause the session terminate immediately. + status = get_type_partner()->set_session_timeout(0ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + send_error_notification(eap_status_no_pac_nor_certs_to_authenticate_with_provision_disabled); + + status = create_tls_protocol_alert( + tls_alert_description_internal_error, + tls_alert_level_fatal, + status); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else +#endif //#if defined(USE_FAST_EAP_TYPE) + { + // Client does not fail immediately. + // This session could use server only authentication. + // NOTE, in this case client must send empty certificate message to server. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("INFO: TLS: %s: pki_function: complete_query_certificate_chain(): ") + EAPL("Client allows anonymous client.\n"), + (m_is_client == true ? "client": "server"))); + + m_tls_peap_server_authenticates_client_action = false; + status = eap_status_ok; + } + } + } + } + else + { + status = copy( + certificate_chain, + &m_own_certificate_chain, + m_am_tools, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + } + + if (status == eap_status_ok) + { + status = check_sent_tls_message(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = eap_status_completed_request; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_query_certificate_authorities_and_types( + EAP_TEMPLATE_CONST eap_array_c * const certificate_authorities, + EAP_TEMPLATE_CONST eap_array_c * const certificate_types, + const eap_status_e completion_status) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::complete_query_certificate_authorities_and_types()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_query_certificate_authorities_and_types()"); + + m_pending_query_certificate_authorities_and_types = false; + + eap_status_e status = eap_status_not_supported; + + if (completion_status != eap_status_ok) + { + status = create_tls_protocol_alert( + tls_alert_description_none, + tls_alert_level_none, + completion_status); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + status = copy( + certificate_authorities, + &m_own_certificate_authorities, + m_am_tools, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = copy_simple( + certificate_types, + &m_own_certificate_types, + m_am_tools, + false); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + + if (status == eap_status_ok) + { + status = check_sent_tls_message(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = eap_status_completed_request; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_query_dh_parameters( + const eap_variable_data_c * const dhe_prime, + const eap_variable_data_c * const dhe_group_generator, + const eap_status_e completion_status) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: pki_function: starts: tls_record_c::complete_query_dh_parameters()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_query_dh_parameters()"); + + m_pending_query_dh_parameters = false; + + eap_status_e status = eap_status_not_supported; + + if (completion_status != eap_status_ok) + { + status = create_tls_protocol_alert( + tls_alert_description_none, + tls_alert_level_none, + completion_status); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + status = m_dhe_prime.set_copy_of_buffer(dhe_prime); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_dhe_group_generator.set_copy_of_buffer(dhe_group_generator); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + if (status == eap_status_ok) + { + status = check_sent_tls_message(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = eap_status_completed_request; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_query_realm( + const eap_variable_data_c * const realm, + const eap_status_e completion_status) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::complete_query_realm()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_query_realm()"); + + m_pending_query_realm = false; + + eap_status_e status = eap_status_not_supported; + + if (completion_status != eap_status_ok) + { + status = create_tls_protocol_alert( + tls_alert_description_none, + tls_alert_level_none, + completion_status); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + status = m_NAI_realm.set_copy_of_buffer(realm); + } + + if (status == eap_status_ok) + { + status = check_sent_tls_message(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = eap_status_completed_request; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_rsa_decrypt_with_private_key( + const eap_variable_data_c * const premaster_secret, + const eap_status_e completion_status) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: pki_function: starts: tls_record_c::complete_rsa_decrypt_with_private_key()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_rsa_decrypt_with_private_key()"); + + m_pending_rsa_decrypt_with_private_key = false; + + eap_status_e status = eap_status_not_supported; + + if (completion_status != eap_status_ok) + { + status = create_tls_protocol_alert( + tls_alert_description_none, + tls_alert_level_none, + completion_status); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_rsa_decrypt_with_private_key(): premaster_secret"), + premaster_secret->get_data(), + premaster_secret->get_data_length())); + + status = m_premaster_secret.set_copy_of_buffer(premaster_secret); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS: m_premaster_secret"), + m_premaster_secret.get_data(m_premaster_secret.get_data_length()), + m_premaster_secret.get_data_length())); + + m_key_material_generated = false; + + // We must generate master secret. + status = generate_master_secret(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // We must generate the key material. + status = generate_key_material(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + if (status == eap_status_ok) + { + status = check_sent_tls_message(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = eap_status_completed_request; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_rsa_encrypt_with_public_key( + const eap_variable_data_c * const encrypted_premaster_secret, + const eap_status_e completion_status) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: pki_function: starts: tls_record_c::complete_rsa_encrypt_with_public_key()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_rsa_encrypt_with_public_key()"); + + m_pending_rsa_encrypt_with_public_key = false; + + eap_status_e status = eap_status_not_supported; + + if (completion_status != eap_status_ok) + { + status = create_tls_protocol_alert( + tls_alert_description_none, + tls_alert_level_none, + completion_status); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_rsa_encrypt_with_public_key(): encrypted premaster_secret"), + encrypted_premaster_secret->get_data(), + encrypted_premaster_secret->get_data_length())); + + status = m_own_encrypted_premaster_secret.set_copy_of_buffer(encrypted_premaster_secret); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + if (status == eap_status_ok) + { + status = check_sent_tls_message(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = eap_status_completed_request; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_sign_with_private_key( + const eap_variable_data_c * const signed_message_hash, + const eap_status_e completion_status) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: pki_function: starts: tls_record_c::complete_sign_with_private_key()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_sign_with_private_key()"); + + m_pending_sign_with_private_key = false; + + eap_status_e status = eap_status_not_supported; + + if (completion_status != eap_status_ok) + { + status = create_tls_protocol_alert( + tls_alert_description_none, + tls_alert_level_none, + completion_status); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + if (signed_message_hash->get_is_valid_data() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + status = m_signed_message_hash.set_copy_of_buffer(signed_message_hash); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: complete_sign_with_private_key(): m_signed_message_hash"), + m_signed_message_hash.get_data(m_signed_message_hash.get_data_length()), + m_signed_message_hash.get_data_length())); + } + + + if (status == eap_status_ok) + { + status = check_sent_tls_message(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = eap_status_completed_request; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_verify_with_public_key( + const eap_status_e verify_status) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: pki_function: starts: tls_record_c::complete_verify_with_public_key()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_verify_with_public_key()"); + + m_pending_verify_with_public_key = false; + + eap_status_e status = eap_status_ok; + + m_verify_signature = verify_status; + + if (m_verify_signature != eap_status_ok) + { + // Verification failed. + + status = create_tls_protocol_alert( + tls_alert_description_none, + tls_alert_level_none, + m_verify_signature); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + if (status == eap_status_ok) + { + status = check_sent_tls_message(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = eap_status_completed_request; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::get_eap_tls_master_session_key( + eap_variable_data_c * const eap_tls_master_session_key, + eap_variable_data_c * const mschapv2_challenges + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::get_eap_tls_master_session_key()\n"), + this, + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::get_eap_tls_master_session_key()"); + + eap_status_e status(eap_status_process_general_error); + +#if defined(USE_FAST_EAP_TYPE) + if (m_eap_type == eap_type_fast) + { + status = eap_tls_master_session_key->set_copy_of_buffer(&m_session_key_seed); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (mschapv2_challenges != 0 + && mschapv2_challenges->get_is_valid() == true + && m_mschapv2_challenges.get_is_valid_data() == true) + { + status = mschapv2_challenges->set_copy_of_buffer(&m_mschapv2_challenges); + } + } + else +#else + EAP_UNREFERENCED_PARAMETER(mschapv2_challenges); +#endif //#if defined(USE_FAST_EAP_TYPE) + { + status = eap_tls_master_session_key->set_copy_of_buffer(&m_eap_master_session_key); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::add_rogue_ap( + eap_array_c & rogue_ap_list) +{ + return EAP_STATUS_RETURN(m_am_tools, get_type_partner()->add_rogue_ap(rogue_ap_list)); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e tls_record_c::set_session_timeout( + const u32_t session_timeout_ms) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = get_type_partner()->set_session_timeout(session_timeout_ms); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::set_tls_session_type(const tls_session_type_e tls_session_type) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::set_tls_session_type(): m_tls_session_type=%d=%s\n"), + this, + (m_is_client == true ? "client": "server"), + tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(tls_session_type))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::set_tls_session_type()"); + + m_tls_session_type = tls_session_type; + + eap_status_e status = get_type_partner()->set_tls_session_type(tls_session_type); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT tls_session_type_e tls_record_c::get_tls_session_type() +{ + return m_tls_session_type; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT void tls_record_c::set_tls_identity_privacy_handshake_state(const tls_identity_privacy_handshake_state_e state) +{ +#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::set_tls_identity_privacy_handshake_state(): Changes from %d=%s to %d=%s\n"), + this, + (m_is_client == true ? "client": "server"), + m_tls_identity_privacy_handshake_state, + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(m_tls_identity_privacy_handshake_state), + state, + eap_tls_trace_string_c::get_tls_identity_privacy_handshake_state_string(state))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::set_tls_identity_privacy_handshake_state()"); + + m_tls_identity_privacy_handshake_state = state; +#else + EAP_UNREFERENCED_PARAMETER(state); +#endif //#if defined(USE_EAP_TLS_IDENTITY_PRIVACY) +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT void tls_record_c::set_selected_cipher_suite(const tls_cipher_suites_e cipher_suite) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: suite_function: starts: tls_record_c::set_selected_cipher_suite(): Changes from %d=%s to %d=%s\n"), + this, + (m_is_client == true ? "client": "server"), + m_selected_cipher_suite, + eap_tls_trace_string_c::get_cipher_suite_string(m_selected_cipher_suite), + cipher_suite, + eap_tls_trace_string_c::get_cipher_suite_string(cipher_suite))); + + m_selected_cipher_suite = cipher_suite; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::set_receive_cipher_suite(const tls_cipher_suites_e cipher_suite) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: suite_function: starts: tls_record_c::set_receive_cipher_suite(): Changes from %d=%s to %d=%s\n"), + this, + (m_is_client == true ? "client": "server"), + m_receive_cipher_suite, + eap_tls_trace_string_c::get_cipher_suite_string(m_receive_cipher_suite), + cipher_suite, + eap_tls_trace_string_c::get_cipher_suite_string(cipher_suite))); + + m_receive_cipher_suite = cipher_suite; + + m_receive_record_sequence_number = 0ul; + + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("set_receive_cipher_suite(): m_receive_encryption_key"), + m_receive_encryption_key.get_data(), + m_receive_encryption_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("set_receive_cipher_suite(): m_new_receive_encryption_key"), + m_new_receive_encryption_key.get_data(), + m_new_receive_encryption_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("set_receive_cipher_suite(): m_receive_mac_key"), + m_receive_mac_key.get_data(), + m_receive_mac_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("set_receive_cipher_suite(): m_new_receive_mac_key"), + m_new_receive_mac_key.get_data(), + m_new_receive_mac_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("set_receive_cipher_suite(): m_receive_iv"), + m_receive_iv.get_data(), + m_receive_iv.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("set_receive_cipher_suite(): m_new_receive_iv"), + m_new_receive_iv.get_data(), + m_new_receive_iv.get_data_length())); + + + eap_status_e status = m_receive_mac_key.set_copy_of_buffer(&m_new_receive_mac_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_receive_encryption_key.set_copy_of_buffer(&m_new_receive_encryption_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_receive_iv.set_copy_of_buffer(&m_new_receive_iv); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::set_send_cipher_suite(const tls_cipher_suites_e cipher_suite) +{ + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: suite_function: starts: tls_record_c::set_send_cipher_suite(): Changes from %d=%s to %d=%s\n"), + this, + (m_is_client == true ? "client": "server"), + m_send_cipher_suite, + eap_tls_trace_string_c::get_cipher_suite_string(m_send_cipher_suite), + cipher_suite, + eap_tls_trace_string_c::get_cipher_suite_string(cipher_suite))); + + m_send_cipher_suite = cipher_suite; + + m_send_record_sequence_number = 0ul; + + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("set_send_cipher_suite(): m_send_encryption_key"), + m_send_encryption_key.get_data(), + m_send_encryption_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("set_send_cipher_suite(): m_new_send_encryption_key"), + m_new_send_encryption_key.get_data(), + m_new_send_encryption_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("set_send_cipher_suite(): m_send_mac_key"), + m_send_mac_key.get_data(), + m_send_mac_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("set_send_cipher_suite(): m_new_send_mac_key"), + m_new_send_mac_key.get_data(), + m_new_send_mac_key.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("set_send_cipher_suite(): m_send_iv"), + m_send_iv.get_data(), + m_send_iv.get_data_length())); + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("set_send_cipher_suite(): m_new_send_iv"), + m_new_send_iv.get_data(), + m_new_send_iv.get_data_length())); + + + eap_status_e status = m_send_mac_key.set_copy_of_buffer(&m_new_send_mac_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_send_encryption_key.set_copy_of_buffer(&m_new_send_encryption_key); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_send_iv.set_copy_of_buffer(&m_new_send_iv); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e tls_record_c::read_authority_identity(eap_variable_data_c * const authority_identity_payload) +{ + return m_application->read_authority_identity(authority_identity_payload); +} + +//-------------------------------------------------- + +#if defined(USE_FAST_EAP_TYPE) + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_query_tunnel_PAC( + const eap_status_e in_completion_status, + const eap_fast_pac_type_e in_pac_type, + const eap_fast_variable_data_c * const in_tunnel_PAC_key_tlv, + const eap_fast_variable_data_c * const in_tunnel_PAC_opaque_tlv) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("TLS: this = 0x%08x, %s: message_function: starts: tls_record_c::complete_query_tunnel_PAC(): m_tls_session_type=%d=%s\n"), + this, + (m_is_client == true ? "client": "server"), + m_tls_session_type, + eap_tls_trace_string_c::get_tls_session_type_string(m_tls_session_type))); + + EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_record_c::complete_query_tunnel_PAC()"); + + eap_status_e status(eap_status_process_general_error); + + m_pending_query_tunnel_PAC = false; + + if (in_completion_status == eap_status_ok) + { + tls_extension_c extension(m_am_tools); + if (extension.get_is_valid() == false) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + if (in_tunnel_PAC_opaque_tlv != 0 + && in_tunnel_PAC_opaque_tlv->get_is_valid_data() == true) + { + status = extension.set_copy_of_buffer(in_tunnel_PAC_opaque_tlv->get_full_tlv_buffer()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + extension.set_type(tls_extension_type_session_ticket); + extension.set_pac_type(in_pac_type); + + status = m_supported_tls_extensions.add_object(extension.copy(), true); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + if (in_tunnel_PAC_key_tlv != 0 + && in_tunnel_PAC_key_tlv->get_is_valid_data() == true) + { + status = m_eap_fast_pac_key.set_copy_of_buffer( + in_tunnel_PAC_key_tlv->get_data(in_tunnel_PAC_key_tlv->get_data_length()), + in_tunnel_PAC_key_tlv->get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + set_tls_session_type(tls_session_type_eap_fast_pac_session_resumption); + + if (m_application != 0) + { + m_application->set_tunneled_state(get_tls_session_type()); + } + } + + status = check_sent_tls_message(); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_completed_request); +} + +#endif //#if defined(USE_FAST_EAP_TYPE) + +//-------------------------------------------------- + + +EAP_FUNC_EXPORT eap_status_e tls_record_c::query_ttls_pap_username_and_password( + const eap_variable_data_c * const reply_message) +{ + eap_status_e status(eap_status_process_general_error); + + status = m_am_tls_services->query_ttls_pap_username_and_password(reply_message); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + + +//-------------------------------------------------- + + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_query_ttls_pap_username_and_password( + const eap_variable_data_c * const ttls_pap_username, + const eap_variable_data_c * const ttls_pap_password, + const eap_status_e query_result) +{ + eap_status_e status(eap_status_process_general_error); + + status = m_application->complete_query_ttls_pap_username_and_password( + ttls_pap_username, + ttls_pap_password, + query_result); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + + +//-------------------------------------------------- + + +EAP_FUNC_EXPORT eap_status_e tls_record_c::verify_ttls_pap_username_and_password( + const eap_variable_data_c * const user_name, + const eap_variable_data_c * const user_password) +{ + eap_status_e status(eap_status_process_general_error); + + status = m_am_tls_services->verify_ttls_pap_username_and_password( + user_name, + user_password); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + + +//-------------------------------------------------- + + +EAP_FUNC_EXPORT eap_status_e tls_record_c::complete_verify_ttls_pap_username_and_password( + const eap_status_e authentication_result, + const eap_variable_data_c * const ttls_pap_reply_message) +{ + eap_status_e status(eap_status_process_general_error); + + status = m_application->complete_verify_ttls_pap_username_and_password( + authentication_result, + ttls_pap_reply_message); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + + +//-------------------------------------------------- + +// End.