From 621669828b93294c8c875004f686c49c0c666da5 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Fri, 2 Sep 2016 14:03:34 +0200 Subject: [PATCH] Schannel and ownTLS MSK derivation unified --- lib/MSCHAPv2/src/Method.cpp | 6 ++-- lib/PAP/src/Method.cpp | 6 ++-- lib/TLS/include/Method.h | 10 +++++-- lib/TLS/src/Method.cpp | 60 +++++++++++++++++-------------------- lib/TTLS/include/Method.h | 4 --- lib/TTLS/src/Method.cpp | 41 ++++++++++++++----------- 6 files changed, 64 insertions(+), 63 deletions(-) diff --git a/lib/MSCHAPv2/src/Method.cpp b/lib/MSCHAPv2/src/Method.cpp index d6f3044..9b4568b 100644 --- a/lib/MSCHAPv2/src/Method.cpp +++ b/lib/MSCHAPv2/src/Method.cpp @@ -176,7 +176,7 @@ void eap::method_mschapv2::get_result( m_module.log_event(&EAPMETHOD_METHOD_SUCCESS, event_data((unsigned int)eap_type_legacy_mschapv2), event_data::blank); m_cfg.m_auth_failed = false; - ppResult->fIsSuccess = TRUE; + ppResult->fIsSuccess = TRUE; ppResult->dwFailureReasonCode = ERROR_SUCCESS; break; @@ -189,11 +189,11 @@ void eap::method_mschapv2::get_result( // Mark credentials as failed, so GUI can re-prompt user. // But be careful: do so only after credentials were actually tried. - m_cfg.m_auth_failed = m_phase == phase_finished; + m_cfg.m_auth_failed = m_phase_prev < phase_finished && m_phase >= phase_finished; // Do not report failure to EapHost, as it will not save updated configuration then. But we need it to save it, to alert user on next connection attempt. // EapHost is well aware of the failed condition. - //ppResult->fIsSuccess = FALSE; + //ppResult->fIsSuccess = FALSE; //ppResult->dwFailureReasonCode = EAP_E_AUTHENTICATION_FAILED; break; diff --git a/lib/PAP/src/Method.cpp b/lib/PAP/src/Method.cpp index 89f3520..ab59d9b 100644 --- a/lib/PAP/src/Method.cpp +++ b/lib/PAP/src/Method.cpp @@ -176,7 +176,7 @@ void eap::method_pap::get_result( m_module.log_event(&EAPMETHOD_METHOD_SUCCESS, event_data((unsigned int)eap_type_legacy_pap), event_data::blank); m_cfg.m_auth_failed = false; - ppResult->fIsSuccess = TRUE; + ppResult->fIsSuccess = TRUE; ppResult->dwFailureReasonCode = ERROR_SUCCESS; break; @@ -189,11 +189,11 @@ void eap::method_pap::get_result( // Mark credentials as failed, so GUI can re-prompt user. // But be careful: do so only after credentials were actually tried. - m_cfg.m_auth_failed = m_phase == phase_finished; + m_cfg.m_auth_failed = m_phase_prev < phase_finished && m_phase >= phase_finished; // Do not report failure to EapHost, as it will not save updated configuration then. But we need it to save it, to alert user on next connection attempt. // EapHost is well aware of the failed condition. - //ppResult->fIsSuccess = FALSE; + //ppResult->fIsSuccess = FALSE; //ppResult->dwFailureReasonCode = EAP_E_AUTHENTICATION_FAILED; break; diff --git a/lib/TLS/include/Method.h b/lib/TLS/include/Method.h index a884eb1..50f5508 100644 --- a/lib/TLS/include/Method.h +++ b/lib/TLS/include/Method.h @@ -223,6 +223,8 @@ namespace eap /// @} +#endif + /// \name Key derivation /// @{ @@ -235,6 +237,8 @@ namespace eap /// @} +#if EAP_TLS < EAP_TLS_SCHANNEL + /// \name Server message processing /// @{ @@ -420,6 +424,9 @@ namespace eap packet_tls m_packet_req; ///< Request packet packet_tls m_packet_res; ///< Response packet + tls_random m_key_mppe_client; ///< MS-MPPE-Recv-Key + tls_random m_key_mppe_server; ///< MS-MPPE-Send-Key + #if EAP_TLS < EAP_TLS_SCHANNEL winstd::crypt_prov m_cp; ///< Cryptography provider for general services winstd::crypt_prov m_cp_enc_client; ///< Cryptography provider for encryption @@ -438,9 +445,6 @@ namespace eap tls_random m_random_client; ///< Client random tls_random m_random_server; ///< Server random - tls_random m_key_mppe_client; ///< MS-MPPE-Recv-Key - tls_random m_key_mppe_server; ///< MS-MPPE-Send-Key - sanitizing_blob m_session_id; ///< TLS session ID bool m_session_resumed; ///< Did TLS session resume? diff --git a/lib/TLS/src/Method.cpp b/lib/TLS/src/Method.cpp index 7e55620..677bf54 100644 --- a/lib/TLS/src/Method.cpp +++ b/lib/TLS/src/Method.cpp @@ -90,6 +90,8 @@ eap::method_tls::method_tls(_Inout_ method_tls &&other) : m_user_ctx (std::move(other.m_user_ctx )), m_packet_req (std::move(other.m_packet_req )), m_packet_res (std::move(other.m_packet_res )), + m_key_mppe_client (std::move(other.m_key_mppe_client )), + m_key_mppe_server (std::move(other.m_key_mppe_server )), #if EAP_TLS < EAP_TLS_SCHANNEL m_cp (std::move(other.m_cp )), m_cp_enc_client (std::move(other.m_cp_enc_client )), @@ -104,8 +106,6 @@ eap::method_tls::method_tls(_Inout_ method_tls &&other) : m_master_secret (std::move(other.m_master_secret )), m_random_client (std::move(other.m_random_client )), m_random_server (std::move(other.m_random_server )), - m_key_mppe_client (std::move(other.m_key_mppe_client )), - m_key_mppe_server (std::move(other.m_key_mppe_server )), m_session_id (std::move(other.m_session_id )), m_session_resumed (std::move(other.m_session_resumed )), m_server_cert_chain (std::move(other.m_server_cert_chain )), @@ -142,6 +142,8 @@ eap::method_tls& eap::method_tls::operator=(_Inout_ method_tls &&other) m_user_ctx = std::move(other.m_user_ctx ); m_packet_req = std::move(other.m_packet_req ); m_packet_res = std::move(other.m_packet_res ); + m_key_mppe_client = std::move(other.m_key_mppe_client ); + m_key_mppe_server = std::move(other.m_key_mppe_server ); #if EAP_TLS < EAP_TLS_SCHANNEL m_cp = std::move(other.m_cp ); m_cp_enc_client = std::move(other.m_cp_enc_client ); @@ -156,8 +158,6 @@ eap::method_tls& eap::method_tls::operator=(_Inout_ method_tls &&other) m_master_secret = std::move(other.m_master_secret ); m_random_client = std::move(other.m_random_client ); m_random_server = std::move(other.m_random_server ); - m_key_mppe_client = std::move(other.m_key_mppe_client ); - m_key_mppe_server = std::move(other.m_key_mppe_server ); m_session_id = std::move(other.m_session_id ); m_session_resumed = std::move(other.m_session_resumed ); m_server_cert_chain = std::move(other.m_server_cert_chain ); @@ -308,6 +308,9 @@ void eap::method_tls::process_request_packet( // This is the EAP-TLS start message: (re)initialize method. m_module.log_event(&EAPMETHOD_METHOD_HANDSHAKE_START2, event_data((unsigned int)eap_type_tls), event_data::blank); m_phase = phase_client_hello; + + m_key_mppe_client.clear(); + m_key_mppe_server.clear(); } else { // Process the packet. memset(m_handshake, 0, sizeof(m_handshake)); @@ -319,9 +322,6 @@ void eap::method_tls::process_request_packet( case phase_client_hello: { m_tls_version = tls_version_1_2; - m_key_mppe_client.clear(); - m_key_mppe_server.clear(); - m_server_cert_chain.clear(); // Create handshake hashing objects. @@ -464,6 +464,8 @@ void eap::method_tls::process_request_packet( // This is the EAP-TLS start message: (re)initialize method. m_module.log_event(&EAPMETHOD_METHOD_HANDSHAKE_START2, event_data((unsigned int)eap_type_tls), event_data::blank); m_phase = phase_handshake_init; + m_key_mppe_client.clear(); + m_key_mppe_server.clear(); m_sc_queue.assign(m_packet_req.m_data.begin(), m_packet_req.m_data.end()); } else m_sc_queue.insert(m_sc_queue.end(), m_packet_req.m_data.begin(), m_packet_req.m_data.end()); @@ -510,7 +512,6 @@ void eap::method_tls::get_result( case EapPeerMethodResultSuccess: { m_module.log_event(&EAPMETHOD_METHOD_SUCCESS, event_data((unsigned int)eap_type_tls), event_data::blank); -#if EAP_TLS < EAP_TLS_SCHANNEL // Derive MSK/EMSK for line encryption. derive_msk(); @@ -522,34 +523,15 @@ void eap::method_tls::get_result( a.create_ms_mppe_key(17, (LPCBYTE)&m_key_mppe_server, sizeof(tls_random)); m_eap_attr.push_back(std::move(a)); m_eap_attr.push_back(eap_attr::blank); -#else - // Derive MSK/EMSK for line encryption. - SecPkgContext_EapKeyBlock key_block; - SECURITY_STATUS status = QueryContextAttributes(m_sc_ctx, SECPKG_ATTR_EAP_KEY_BLOCK, &key_block); - if (FAILED(status)) - throw sec_runtime_error(status, __FUNCTION__ "Error generating MSK in Schannel."); - const unsigned char *_key_block = key_block.rgbKeys; - - // Fill array with RADIUS attributes. - eap_attr a; - m_eap_attr.reserve(m_eap_attr.size() + 3); - a.create_ms_mppe_key(16, _key_block, sizeof(tls_random)); - m_eap_attr.push_back(std::move(a)); - _key_block += sizeof(tls_random); - a.create_ms_mppe_key(17, _key_block, sizeof(tls_random)); - m_eap_attr.push_back(std::move(a)); - _key_block += sizeof(tls_random); - m_eap_attr.push_back(eap_attr::blank); -#endif // Clear credentials as failed. m_cfg.m_auth_failed = false; - ppResult->fIsSuccess = TRUE; + ppResult->fIsSuccess = TRUE; ppResult->dwFailureReasonCode = ERROR_SUCCESS; #if EAP_TLS < EAP_TLS_SCHANNEL - // Update configuration with session resumption data and prepare BLOB. + // Update configuration with session resumption data. m_cfg.m_session_id = m_session_id; m_cfg.m_master_secret = m_master_secret; #else @@ -561,6 +543,7 @@ void eap::method_tls::get_result( SECBUFFER_TOKEN, &dwType }; SecBufferDesc token_desc = { SECBUFFER_VERSION, 1, &token }; + SECURITY_STATUS status; if (SUCCEEDED(status = ApplyControlToken(m_sc_ctx, &token_desc))) { // Prepare output buffer(s). SecBuffer buf_out[] = { { 0, SECBUFFER_TOKEN, NULL }, }; @@ -591,7 +574,7 @@ void eap::method_tls::get_result( // Mark credentials as failed, so GUI can re-prompt user. // But be careful: do so only if this happened after transition from handshake to application data phase. - m_cfg.m_auth_failed = m_phase >= phase_application_data; + m_cfg.m_auth_failed = m_phase_prev < phase_application_data && m_phase >= phase_application_data; // Clear session resumption data. m_cfg.m_session_id.clear(); @@ -611,7 +594,7 @@ void eap::method_tls::get_result( // Do not report failure to EapHost, as it will not save updated configuration then. But we need it to save it, to alert user on next connection attempt. // EapHost is well aware of the failed condition. - //ppResult->fIsSuccess = FALSE; + //ppResult->fIsSuccess = FALSE; //ppResult->dwFailureReasonCode = EAP_E_AUTHENTICATION_FAILED; break; @@ -817,15 +800,27 @@ eap::sanitizing_blob eap::method_tls::make_message(_In_ tls_message_type_t type, return msg; } +#endif void eap::method_tls::derive_msk() { + const unsigned char *_key_block; + +#if EAP_TLS < EAP_TLS_SCHANNEL static const unsigned char s_label[] = "client EAP encryption"; sanitizing_blob seed(s_label, s_label + _countof(s_label) - 1); seed.insert(seed.end(), (const unsigned char*)&m_random_client, (const unsigned char*)(&m_random_client + 1)); seed.insert(seed.end(), (const unsigned char*)&m_random_server, (const unsigned char*)(&m_random_server + 1)); sanitizing_blob key_block(prf(m_cp, m_alg_prf, m_master_secret, seed, 2*sizeof(tls_random))); - const unsigned char *_key_block = key_block.data(); + _key_block = key_block.data(); +#else + // Derive MSK/EMSK for line encryption. + SecPkgContext_EapKeyBlock key_block; + SECURITY_STATUS status = QueryContextAttributes(m_sc_ctx, SECPKG_ATTR_EAP_KEY_BLOCK, &key_block); + if (FAILED(status)) + throw sec_runtime_error(status, __FUNCTION__ " Error generating MSK in Schannel."); + _key_block = key_block.rgbKeys; +#endif // MS-MPPE-Recv-Key memcpy(&m_key_mppe_client, _key_block, sizeof(tls_random)); @@ -836,6 +831,7 @@ void eap::method_tls::derive_msk() _key_block += sizeof(tls_random); } +#if EAP_TLS < EAP_TLS_SCHANNEL void eap::method_tls::process_packet(_In_bytecount_(size_pck) const void *_pck, _In_ size_t size_pck) { diff --git a/lib/TTLS/include/Method.h b/lib/TTLS/include/Method.h index 6a2c35d..b16f17c 100644 --- a/lib/TTLS/include/Method.h +++ b/lib/TTLS/include/Method.h @@ -118,8 +118,6 @@ namespace eap /// @} protected: -#if EAP_TLS < EAP_TLS_SCHANNEL - /// /// Generates master session key /// @@ -127,8 +125,6 @@ namespace eap /// virtual void derive_msk(); -#endif - /// /// Processes an application message /// diff --git a/lib/TTLS/src/Method.cpp b/lib/TTLS/src/Method.cpp index 72a0acc..9b60adf 100644 --- a/lib/TTLS/src/Method.cpp +++ b/lib/TTLS/src/Method.cpp @@ -120,10 +120,11 @@ void eap::method_ttls::get_result( _In_ EapPeerMethodResultReason reason, _Inout_ EapPeerMethodResult *ppResult) { - if (m_phase != phase_application_data) { - // Do the TLS. - method_tls::get_result(reason, ppResult); - } else { + // Do the TLS. + method_tls::get_result(reason, ppResult); + + if (m_phase == phase_application_data) { + // Get inner method result. EapPeerMethodResult result = {}; m_inner->get_result(reason, &result); @@ -131,16 +132,6 @@ void eap::method_ttls::get_result( if (result.fSaveConnectionData) ppResult->fSaveConnectionData = TRUE; -#if EAP_TLS >= EAP_TLS_SCHANNEL - // EAP-TTLS uses different label in PRF for MSK derivation than EAP-TLS. - static const DWORD s_key_id = 0x01; // EAP-TTLSv0 Keying Material - static const SecPkgContext_EapPrfInfo s_prf_info = { 0, sizeof(s_key_id), (PBYTE)&s_key_id }; - SECURITY_STATUS status = SetContextAttributes(m_sc_ctx, SECPKG_ATTR_EAP_PRF_INFO, (void*)&s_prf_info, sizeof(s_prf_info)); - if (FAILED(status)) - throw sec_runtime_error(status, __FUNCTION__ "Error setting EAP-TTLS PRF in Schannel."); -#endif - method_tls::get_result(EapPeerMethodResultSuccess, ppResult); - if (reason == EapPeerMethodResultFailure) { // Clear session resumption data. #if EAP_TLS < EAP_TLS_SCHANNEL @@ -154,10 +145,11 @@ void eap::method_ttls::get_result( } -#if EAP_TLS < EAP_TLS_SCHANNEL - void eap::method_ttls::derive_msk() { + const unsigned char *_key_block; + +#if EAP_TLS < EAP_TLS_SCHANNEL // // TLS versions 1.0 [RFC2246] and 1.1 [RFC4346] define the same PRF // function, and any EAP-TTLSv0 implementation based on these versions @@ -178,7 +170,21 @@ void eap::method_ttls::derive_msk() seed.insert(seed.end(), (const unsigned char*)&m_random_client, (const unsigned char*)(&m_random_client + 1)); seed.insert(seed.end(), (const unsigned char*)&m_random_server, (const unsigned char*)(&m_random_server + 1)); sanitizing_blob key_block(prf(m_cp, CALG_TLS1PRF, m_master_secret, seed, 2*sizeof(tls_random))); - const unsigned char *_key_block = key_block.data(); + _key_block = key_block.data(); +#else + // EAP-TTLS uses different label in PRF for MSK derivation than EAP-TLS. + static const DWORD s_key_id = 0x01; // EAP-TTLSv0 Keying Material + static const SecPkgContext_EapPrfInfo s_prf_info = { 0, sizeof(s_key_id), (PBYTE)&s_key_id }; + SECURITY_STATUS status = SetContextAttributes(m_sc_ctx, SECPKG_ATTR_EAP_PRF_INFO, (void*)&s_prf_info, sizeof(s_prf_info)); + if (FAILED(status)) + throw sec_runtime_error(status, __FUNCTION__ " Error setting EAP-TTLS PRF in Schannel."); + + SecPkgContext_EapKeyBlock key_block; + status = QueryContextAttributes(m_sc_ctx, SECPKG_ATTR_EAP_KEY_BLOCK, &key_block); + if (FAILED(status)) + throw sec_runtime_error(status, __FUNCTION__ " Error generating MSK in Schannel."); + _key_block = key_block.rgbKeys; +#endif // MSK: MPPE-Recv-Key memcpy(&m_key_mppe_client, _key_block, sizeof(tls_random)); @@ -189,7 +195,6 @@ void eap::method_ttls::derive_msk() _key_block += sizeof(tls_random); } -#endif void eap::method_ttls::process_application_data(_In_bytecount_(size_msg) const void *msg, _In_ size_t size_msg) {