From c7a41d891a727f96b11df02b54a1c22a388368db Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Fri, 12 Aug 2016 21:09:50 +0200 Subject: [PATCH] TLS work continues... --- MSI/MSIBuild | 2 +- lib/TLS/build/TLS.vcxproj | 2 + lib/TLS/build/TLS.vcxproj.filters | 6 + lib/TLS/include/Config.h | 10 +- lib/TLS/include/Method.h | 369 ++----------------- lib/TLS/include/TLS.h | 524 +++++++++++++++++++++++++++ lib/TLS/src/Config.cpp | 16 +- lib/TLS/src/Method.cpp | 564 ++++++++++++------------------ lib/TLS/src/StdAfx.h | 1 + lib/TLS/src/TLS.cpp | 238 +++++++++++++ lib/WinStd | 2 +- 11 files changed, 1058 insertions(+), 676 deletions(-) create mode 100644 lib/TLS/include/TLS.h create mode 100644 lib/TLS/src/TLS.cpp diff --git a/MSI/MSIBuild b/MSI/MSIBuild index b0c4f3e..7a459c8 160000 --- a/MSI/MSIBuild +++ b/MSI/MSIBuild @@ -1 +1 @@ -Subproject commit b0c4f3edf3b6da1bae21673758ae2a2679e6ea0c +Subproject commit 7a459c8c6c785bffb63a73219998a57f8d610de5 diff --git a/lib/TLS/build/TLS.vcxproj b/lib/TLS/build/TLS.vcxproj index 82266ce..f7060cc 100644 --- a/lib/TLS/build/TLS.vcxproj +++ b/lib/TLS/build/TLS.vcxproj @@ -82,6 +82,7 @@ + @@ -94,6 +95,7 @@ Create + diff --git a/lib/TLS/build/TLS.vcxproj.filters b/lib/TLS/build/TLS.vcxproj.filters index 8c96e75..7982ecc 100644 --- a/lib/TLS/build/TLS.vcxproj.filters +++ b/lib/TLS/build/TLS.vcxproj.filters @@ -23,6 +23,9 @@ Header Files + + Header Files + @@ -37,5 +40,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/lib/TLS/include/Config.h b/lib/TLS/include/Config.h index 27a0359..4798702 100644 --- a/lib/TLS/include/Config.h +++ b/lib/TLS/include/Config.h @@ -18,13 +18,13 @@ along with GÉANTLink. If not, see . */ -#include - #include #include #include // Must include after +#include + namespace eap { /// @@ -41,6 +41,8 @@ namespace eap #pragma once #include "Credentials.h" +#include "Method.h" +#include "TLS.h" #include "../../EAPBase/include/Config.h" @@ -166,5 +168,9 @@ namespace eap public: std::list m_trusted_root_ca; ///< Trusted root CAs std::list m_server_names; ///< Acceptable authenticating server names + + // Following members are used for session resumptions. They are not exported/imported to XML. + sanitizing_blob m_session_id; ///< TLS session ID + tls_master_secret m_master_secret; ///< TLS master secret }; } diff --git a/lib/TLS/include/Method.h b/lib/TLS/include/Method.h index e10c70d..6da0fdd 100644 --- a/lib/TLS/include/Method.h +++ b/lib/TLS/include/Method.h @@ -26,10 +26,12 @@ namespace eap class method_tls; } + #pragma once -#include "../include/Config.h" -#include "../include/Credentials.h" +#include "Config.h" +#include "Credentials.h" +#include "TLS.h" #include "../../EAPBase/include/Method.h" @@ -65,79 +67,6 @@ namespace eap flags_res_more_frag = 0x40, ///< More fragments }; - /// - /// TLS packet type - /// - /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter: A.1. Record Layer](https://tools.ietf.org/html/rfc5246#appendix-A.1) - /// - enum message_type_t { - message_type_change_cipher_spec = 20, - message_type_alert = 21, - message_type_handshake = 22, - message_type_application_data = 23, - }; - - /// - /// TLS handshake type - /// - /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter: A.4. Handshake Protocol](https://tools.ietf.org/html/rfc5246#appendix-A.4) - /// - enum handshake_type_t { - handshake_type_hello_request = 0, - handshake_type_client_hello = 1, - handshake_type_server_hello = 2, - handshake_type_certificate = 11, - handshake_type_server_key_exchange = 12, - handshake_type_certificate_request = 13, - handshake_type_server_hello_done = 14, - handshake_type_certificate_verify = 15, - handshake_type_client_key_exchange = 16, - handshake_type_finished = 20 - }; - - /// - /// TLS alert level - /// - /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter: 7.2. Alert Protocol)](https://tools.ietf.org/html/rfc5246#section-7.2) - /// - enum alert_level_t { - alert_level_warning = 1, - alert_level_fatal = 2, - }; - - /// - /// TLS alert description - /// - /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter: 7.2. Alert Protocol)](https://tools.ietf.org/html/rfc5246#section-7.2) - /// - enum alert_desc_t { - alert_desc_close_notify = 0, - alert_desc_unexpected_message = 10, - alert_desc_bad_record_mac = 20, - alert_desc_decryption_failed = 21, // reserved - alert_desc_record_overflow = 22, - alert_desc_decompression_failure = 30, - alert_desc_handshake_failure = 40, - alert_desc_no_certificate = 41, // reserved - alert_desc_bad_certificate = 42, - alert_desc_unsupported_certificate = 43, - alert_desc_certificate_revoked = 44, - alert_desc_certificate_expired = 45, - alert_desc_certificate_unknown = 46, - alert_desc_illegal_parameter = 47, - alert_desc_unknown_ca = 48, - alert_desc_access_denied = 49, - alert_desc_decode_error = 50, - alert_desc_decrypt_error = 51, - alert_desc_export_restriction = 60, // reserved - alert_desc_protocol_version = 70, - alert_desc_insufficient_security = 71, - alert_desc_internal_error = 80, - alert_desc_user_canceled = 90, - alert_desc_no_renegotiation = 100, - alert_desc_unsupported_extension = 110, - }; - /// /// EAP-TLS packet (data) /// @@ -193,56 +122,6 @@ namespace eap std::vector m_data; ///< Packet data }; -#pragma pack(push) -#pragma pack(1) - /// - /// TLS client/server random - /// - struct random - { - __time32_t time; ///< Unix time-stamp - unsigned char data[28]; ///< Randomness - - /// - /// Constructs a all-zero random - /// - random(); - - /// - /// Copies a random - /// - /// \param[in] other Random to copy from - /// - random(_In_ const random &other); - - /// - /// Destructor - /// - ~random(); - - /// - /// Copies a random - /// - /// \param[in] other Random to copy from - /// - /// \returns Reference to this object - /// - random& operator=(_In_ const random &other); - - /// - /// Empty the random - /// - void clear(); - - /// - /// Generate random - /// - /// \param[in] cp Handle of the cryptographics provider - /// - void reset(_In_ HCRYPTPROV cp); - }; -#pragma pack(pop) - #pragma pack(push) #pragma pack(1) /// @@ -260,208 +139,6 @@ namespace eap }; #pragma pack(pop) -#pragma pack(push) -#pragma pack(1) - /// - /// Master secret - /// - /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (8.1. Computing the Master Secret)](https://tools.ietf.org/html/rfc5246#section-8.1) - /// - struct master_secret - { - unsigned char data[48]; - - /// - /// Constructs a all-zero master secret - /// - master_secret(); - - /// - /// Constructs a pre-master secret - /// - /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 7.4.7.1. RSA-Encrypted Premaster Secret Message)](https://tools.ietf.org/html/rfc5246#section-7.4.7.1) - /// - /// \param[in] cp Handle of the cryptographics provider - /// - master_secret(_In_ HCRYPTPROV cp); - - /// - /// Copies a master secret - /// - /// \param[in] other Random to copy from - /// - master_secret(_In_ const master_secret &other); - - /// - /// Destructor - /// - ~master_secret(); - - /// - /// Copies a master secret - /// - /// \param[in] other Random to copy from - /// - /// \returns Reference to this object - /// - master_secret& operator=(_In_ const master_secret &other); - - /// - /// Empty the master secret - /// - void clear(); - }; -#pragma pack(pop) - - /// - /// Our own implementation of HMAC hashing - /// Microsoft's implementation ([MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/aa382379.aspx)) is flaky. - /// - /// \sa [HMAC: Keyed-Hashing for Message Authentication](https://tools.ietf.org/html/rfc2104) - /// - class hash_hmac - { - public: - typedef unsigned char padding_t[64]; - - public: - /// - /// Construct new HMAC hashing object - /// - /// \param[in] cp Handle of the cryptographics provider - /// \param[in] alg Hashing algorithm - /// \param[in] secret HMAC secret - /// \param[in] size_secret \p secret size - /// - hash_hmac( - _In_ HCRYPTPROV cp, - _In_ ALG_ID alg, - _In_bytecount_(size_secret ) const void *secret, - _In_ size_t size_secret); - - /// - /// Construct new HMAC hashing object using already prepared inner padding - /// - /// \param[in] cp Handle of the cryptographics provider - /// \param[in] alg Hashing algorithm - /// \param[in] padding HMAC secret XOR inner padding - /// - hash_hmac( - _In_ HCRYPTPROV cp, - _In_ ALG_ID alg, - _In_ const padding_t padding); - - /// - /// Provides access to inner hash object to hash data at will. - /// - /// \returns Inner hashing object handle - /// - inline operator HCRYPTHASH() - { - return m_hash_inner; - } - - /// - /// Completes hashing and returns hashed data. - /// - /// \param[out] val Calculated hash value - /// - template - inline void calculate(_Out_ std::vector<_Ty, _Ax> &val) - { - // Calculate inner hash. - if (!CryptGetHashParam(m_hash_inner, HP_HASHVAL, val, 0)) - throw win_runtime_error(__FUNCTION__ " Error calculating inner hash."); - - // Hash inner hash with outer hash. - if (!CryptHashData(m_hash_outer, (const BYTE*)val.data(), (DWORD)(val.size() * sizeof(_Ty)), 0)) - throw win_runtime_error(__FUNCTION__ " Error hashing inner hash."); - - // Calculate outer hash. - if (!CryptGetHashParam(m_hash_outer, HP_HASHVAL, val, 0)) - throw win_runtime_error(__FUNCTION__ " Error calculating outer hash."); - } - - /// - /// Helper method to pre-derive inner padding for frequent reuse - /// - /// \param[in] cp Handle of the cryptographics provider - /// \param[in] alg Hashing algorithm - /// \param[in] secret HMAC secret - /// \param[in] size_secret \p secret size - /// \param[out] padding HMAC secret XOR inner padding - /// - static void inner_padding( - _In_ HCRYPTPROV cp, - _In_ ALG_ID alg, - _In_bytecount_(size_secret ) const void *secret, - _In_ size_t size_secret, - _Out_ padding_t padding); - - protected: - winstd::crypt_hash m_hash_inner; ///< Inner hashing object - winstd::crypt_hash m_hash_outer; ///< Outer hashing object - }; - - - /// - /// TLS client connection state - /// - /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 6.1. Connection States)](https://tools.ietf.org/html/rfc5246#section-6.1) - /// - class conn_state - { - public: - /// - /// Constructs a connection state - /// - conn_state(); - - /// - /// Copies a connection state - /// - /// \param[in] other Connection state to copy from - /// - conn_state(_In_ const conn_state &other); - - /// - /// Moves a connection state - /// - /// \param[in] other Connection state to move from - /// - conn_state(_Inout_ conn_state &&other); - - /// - /// Copies a connection state - /// - /// \param[in] other Connection state to copy from - /// - /// \returns Reference to this object - /// - conn_state& operator=(_In_ const conn_state &other); - - /// - /// Moves a connection state - /// - /// \param[in] other Connection state to move from - /// - /// \returns Reference to this object - /// - conn_state& operator=(_Inout_ conn_state &&other); - - public: - static const ALG_ID m_alg_prf; ///> Pseudo-random function algorithm - static const ALG_ID m_alg_encrypt; ///> Bulk encryption algorithm - static const size_t m_size_enc_key; ///> Encryption key size in bytes (has to comply with `m_alg_encrypt`) - static const size_t m_size_enc_iv; ///> Encryption initialization vector size in bytes (has to comply with `m_alg_encrypt`) - static const ALG_ID m_alg_mac; ///> Message authenticy check algorithm - static const size_t m_size_mac_key; ///> Message authenticy check algorithm key size (has to comply with `m_alg_mac`) - static const size_t m_size_mac_hash; ///> Message authenticy check algorithm result size (has to comply with `m_alg_mac`) - master_secret m_master_secret; ///< TLS master secret - random m_random_client; ///< Client random - random m_random_server; ///< Server random - }; - public: /// /// Constructs an EAP method @@ -486,6 +163,11 @@ namespace eap /// method_tls(_Inout_ method_tls &&other); + /// + /// Destructor + /// + virtual ~method_tls(); + /// /// Copies an EAP method /// @@ -594,7 +276,7 @@ namespace eap /// /// \returns Change cipher spec /// - eap::sanitizing_blob make_finished(); + eap::sanitizing_blob make_finished() const; /// /// Makes a TLS handshake @@ -633,6 +315,11 @@ namespace eap /// void derive_keys(); + /// + /// Generates master session key + /// + void derive_msk(); + /// /// Processes messages in a TLS packet /// @@ -684,7 +371,7 @@ namespace eap /// /// Verifies server's certificate if trusted by configuration /// - void verify_server_trust(); + void verify_server_trust() const; /// /// Encrypt TLS message @@ -698,18 +385,18 @@ namespace eap /// /// \param[inout] msg TLS message to decrypt /// - void decrypt_message(_Inout_ sanitizing_blob &msg); + void decrypt_message(_Inout_ sanitizing_blob &msg) const; /// /// Calculates pseudo-random P_hash data defined in RFC 5246 /// /// \sa [The Transport Layer Security (TLS) Protocol Version 1.1 (Chapter 5: HMAC and the Pseudorandom Function)](https://tools.ietf.org/html/rfc4346#section-5) /// - /// \param[in] secret Hashing secret key - /// \param[in] size_secret \p secret size - /// \param[in] lblseed Concatenated label and seed - /// \param[in] size_lblseed \p lblseed size - /// \param[in] size Number of bytes of pseudo-random data required + /// \param[in] secret Hashing secret key + /// \param[in] size_secret \p secret size + /// \param[in] seed Random seed + /// \param[in] size_seed \p seed size + /// \param[in] size Number of bytes of pseudo-random data required /// /// \returns Generated pseudo-random data (\p size bytes) /// @@ -718,7 +405,7 @@ namespace eap _In_ size_t size_secret, _In_bytecount_(size_seed) const void *seed, _In_ size_t size_seed, - _In_ size_t size); + _In_ size_t size) const; /// /// Creates a key @@ -778,13 +465,16 @@ namespace eap winstd::crypt_prov m_cp; ///< Cryptography provider - conn_state m_state; ///< Connection state + tls_conn_state m_state; ///< TLS connection state for fast reconnect sanitizing_blob m_padding_hmac_client; ///< Padding (key) for client side HMAC calculation //sanitizing_blob m_padding_hmac_server; ///< Padding (key) for server side HMAC calculation winstd::crypt_key m_key_client; ///< Key for encrypting messages winstd::crypt_key m_key_server; ///< Key for decrypting messages + tls_random m_key_mppe_send; ///< MS-MPPE-Send-Key + tls_random m_key_mppe_recv; ///< MS-MPPE-Recv-Key + sanitizing_blob m_session_id; ///< TLS session ID std::list m_server_cert_chain; ///< Server certificate chain @@ -798,5 +488,10 @@ namespace eap bool m_cipher_spec; ///< Did server specify cipher? unsigned __int64 m_seq_num; ///< Sequence number for encryption + + // The following members are required to avoid memory leakage in get_result() + EAP_ATTRIBUTES m_eap_attr_desc; ///< EAP Radius attributes descriptor + std::vector m_eap_attr; ///< EAP Radius attributes + BYTE *m_blob_cfg; ///< Configuration BLOB }; } diff --git a/lib/TLS/include/TLS.h b/lib/TLS/include/TLS.h new file mode 100644 index 0000000..6effc3c --- /dev/null +++ b/lib/TLS/include/TLS.h @@ -0,0 +1,524 @@ +/* + Copyright 2015-2016 Amebis + Copyright 2016 GÉANT + + This file is part of GÉANTLink. + + GÉANTLink is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GÉANTLink is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GÉANTLink. If not, see . +*/ + +#include "../../EAPBase/include/EAP.h" + +namespace eap +{ + /// + /// TLS packet type + /// + /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter: A.1. Record Layer](https://tools.ietf.org/html/rfc5246#appendix-A.1) + /// + enum tls_message_type_t; + + /// + /// TLS handshake type + /// + /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter: A.4. Handshake Protocol](https://tools.ietf.org/html/rfc5246#appendix-A.4) + /// + enum tls_handshake_type_t; + + /// + /// TLS alert level + /// + /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter: 7.2. Alert Protocol)](https://tools.ietf.org/html/rfc5246#section-7.2) + /// + enum tls_alert_level_t; + + /// + /// TLS alert description + /// + /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter: 7.2. Alert Protocol)](https://tools.ietf.org/html/rfc5246#section-7.2) + /// + enum tls_alert_desc_t; + + /// + /// TLS client/server tls_random + /// + struct tls_random; + + /// + /// Master secret + /// + /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (8.1. Computing the Master Secret)](https://tools.ietf.org/html/rfc5246#section-8.1) + /// + struct tls_master_secret; + + /// + /// TLS client connection state + /// + /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 6.1. Connection States)](https://tools.ietf.org/html/rfc5246#section-6.1) + /// + struct tls_conn_state; + + /// + /// Our own implementation of HMAC hashing + /// Microsoft's implementation ([MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/aa382379.aspx)) is flaky. + /// + /// \sa [HMAC: Keyed-Hashing for Message Authentication](https://tools.ietf.org/html/rfc2104) + /// + class hash_hmac; +} + +/// +/// Packs a TLS tls_random +/// +/// \param[inout] cursor Memory cursor +/// \param[in] val Variable with data to pack +/// +inline void operator<<(_Inout_ eap::cursor_out &cursor, _In_ const eap::tls_random &val); + +/// +/// Returns packed size of TLS tls_random +/// +/// \param[in] val Data to pack +/// +/// \returns Size of data when packed (in bytes) +/// +inline size_t pksizeof(_In_ const eap::tls_random &val); + +/// +/// Unpacks a TLS tls_random +/// +/// \param[inout] cursor Memory cursor +/// \param[out] val Variable to receive unpacked value +/// +inline void operator>>(_Inout_ eap::cursor_in &cursor, _Out_ eap::tls_random &val); + +/// +/// Packs a TLS master secret +/// +/// \param[inout] cursor Memory cursor +/// \param[in] val Variable with data to pack +/// +inline void operator<<(_Inout_ eap::cursor_out &cursor, _In_ const eap::tls_master_secret &val); + +/// +/// Returns packed size of TLS master secret +/// +/// \param[in] val Data to pack +/// +/// \returns Size of data when packed (in bytes) +/// +inline size_t pksizeof(_In_ const eap::tls_master_secret &val); + +/// +/// Unpacks a TLS master secret +/// +/// \param[inout] cursor Memory cursor +/// \param[out] val Variable to receive unpacked value +/// +inline void operator>>(_Inout_ eap::cursor_in &cursor, _Out_ eap::tls_master_secret &val); + +/// +/// Packs a TLS connection state +/// +/// \param[inout] cursor Memory cursor +/// \param[in] val Variable with data to pack +/// +inline void operator<<(_Inout_ eap::cursor_out &cursor, _In_ const eap::tls_conn_state &val); + +/// +/// Returns packed size of TLS connection state +/// +/// \param[in] val Data to pack +/// +/// \returns Size of data when packed (in bytes) +/// +inline size_t pksizeof(_In_ const eap::tls_conn_state &val); + +/// +/// Unpacks a TLS connection state +/// +/// \param[inout] cursor Memory cursor +/// \param[out] val Variable to receive unpacked value +/// +inline void operator>>(_Inout_ eap::cursor_in &cursor, _Out_ eap::tls_conn_state &val); + +#pragma once + + +namespace eap +{ + enum tls_message_type_t { + tls_message_type_change_cipher_spec = 20, + tls_message_type_alert = 21, + tls_message_type_handshake = 22, + tls_message_type_application_data = 23, + }; + + + enum tls_handshake_type_t { + tls_handshake_type_hello_request = 0, + tls_handshake_type_client_hello = 1, + tls_handshake_type_server_hello = 2, + tls_handshake_type_certificate = 11, + tls_handshake_type_server_key_exchange = 12, + tls_handshake_type_certificate_request = 13, + tls_handshake_type_server_hello_done = 14, + tls_handshake_type_certificate_verify = 15, + tls_handshake_type_client_key_exchange = 16, + tls_handshake_type_finished = 20 + }; + + + enum tls_alert_level_t { + tls_alert_level_warning = 1, + tls_alert_level_fatal = 2, + }; + + + enum tls_alert_desc_t { + tls_alert_desc_close_notify = 0, + tls_alert_desc_unexpected_message = 10, + tls_alert_desc_bad_record_mac = 20, + tls_alert_desc_decryption_failed = 21, // reserved + tls_alert_desc_record_overflow = 22, + tls_alert_desc_decompression_failure = 30, + tls_alert_desc_handshake_failure = 40, + tls_alert_desc_no_certificate = 41, // reserved + tls_alert_desc_bad_certificate = 42, + tls_alert_desc_unsupported_certificate = 43, + tls_alert_desc_certificate_revoked = 44, + tls_alert_desc_certificate_expired = 45, + tls_alert_desc_certificate_unknown = 46, + tls_alert_desc_illegal_parameter = 47, + tls_alert_desc_unknown_ca = 48, + tls_alert_desc_access_denied = 49, + tls_alert_desc_decode_error = 50, + tls_alert_desc_decrypt_error = 51, + tls_alert_desc_export_restriction = 60, // reserved + tls_alert_desc_protocol_version = 70, + tls_alert_desc_insufficient_security = 71, + tls_alert_desc_internal_error = 80, + tls_alert_desc_user_canceled = 90, + tls_alert_desc_no_renegotiation = 100, + tls_alert_desc_unsupported_extension = 110, + }; + + +#pragma pack(push) +#pragma pack(1) + struct tls_random + { + unsigned char data[32]; ///< Randomness + + /// + /// Constructs a all-zero tls_random + /// + tls_random(); + + /// + /// Copies a tls_random + /// + /// \param[in] other Random to copy from + /// + tls_random(_In_ const tls_random &other); + + /// + /// Destructor + /// + ~tls_random(); + + /// + /// Copies a tls_random + /// + /// \param[in] other Random to copy from + /// + /// \returns Reference to this object + /// + tls_random& operator=(_In_ const tls_random &other); + + /// + /// Empty the tls_random + /// + void clear(); + + /// + /// Generate tls_random + /// + /// \param[in] cp Handle of the cryptographics provider + /// + void reset(_In_ HCRYPTPROV cp); + }; +#pragma pack(pop) + + +#pragma pack(push) +#pragma pack(1) + struct tls_master_secret + { + unsigned char data[48]; + + /// + /// Constructs a all-zero master secret + /// + tls_master_secret(); + + /// + /// Constructs a pre-master secret + /// + /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 7.4.7.1. RSA-Encrypted Premaster Secret Message)](https://tools.ietf.org/html/rfc5246#section-7.4.7.1) + /// + /// \param[in] cp Handle of the cryptographics provider + /// + tls_master_secret(_In_ HCRYPTPROV cp); + + /// + /// Copies a master secret + /// + /// \param[in] other Random to copy from + /// + tls_master_secret(_In_ const tls_master_secret &other); + + /// + /// Destructor + /// + ~tls_master_secret(); + + /// + /// Copies a master secret + /// + /// \param[in] other Random to copy from + /// + /// \returns Reference to this object + /// + tls_master_secret& operator=(_In_ const tls_master_secret &other); + + /// + /// Empty the master secret + /// + void clear(); + }; +#pragma pack(pop) + + + struct tls_conn_state + { + ALG_ID m_alg_prf; ///> Pseudo-tls_random function algorithm + ALG_ID m_alg_encrypt; ///> Bulk encryption algorithm + size_t m_size_enc_key; ///> Encryption key size in bytes (has to comply with `m_alg_encrypt`) + size_t m_size_enc_iv; ///> Encryption initialization vector size in bytes (has to comply with `m_alg_encrypt`) + ALG_ID m_alg_mac; ///> Message authenticy check algorithm + size_t m_size_mac_key; ///> Message authenticy check algorithm key size (has to comply with `m_alg_mac`) + size_t m_size_mac_hash; ///> Message authenticy check algorithm result size (has to comply with `m_alg_mac`) + tls_master_secret m_master_secret; ///< TLS master secret + tls_random m_random_client; ///< Client tls_random + tls_random m_random_server; ///< Server tls_random + + /// + /// Constructs a connection state + /// + tls_conn_state(); + + /// + /// Copies a connection state + /// + /// \param[in] other Connection state to copy from + /// + tls_conn_state(_In_ const tls_conn_state &other); + + /// + /// Moves a connection state + /// + /// \param[in] other Connection state to move from + /// + tls_conn_state(_Inout_ tls_conn_state &&other); + + /// + /// Copies a connection state + /// + /// \param[in] other Connection state to copy from + /// + /// \returns Reference to this object + /// + tls_conn_state& operator=(_In_ const tls_conn_state &other); + + /// + /// Moves a connection state + /// + /// \param[in] other Connection state to move from + /// + /// \returns Reference to this object + /// + tls_conn_state& operator=(_Inout_ tls_conn_state &&other); + }; + + + class hash_hmac + { + public: + typedef unsigned char padding_t[64]; + + public: + /// + /// Construct new HMAC hashing object + /// + /// \param[in] cp Handle of the cryptographics provider + /// \param[in] alg Hashing algorithm + /// \param[in] secret HMAC secret + /// \param[in] size_secret \p secret size + /// + hash_hmac( + _In_ HCRYPTPROV cp, + _In_ ALG_ID alg, + _In_bytecount_(size_secret ) const void *secret, + _In_ size_t size_secret); + + /// + /// Construct new HMAC hashing object using already prepared inner padding + /// + /// \param[in] cp Handle of the cryptographics provider + /// \param[in] alg Hashing algorithm + /// \param[in] padding HMAC secret XOR inner padding + /// + hash_hmac( + _In_ HCRYPTPROV cp, + _In_ ALG_ID alg, + _In_ const padding_t padding); + + /// + /// Provides access to inner hash object to hash data at will. + /// + /// \returns Inner hashing object handle + /// + inline operator HCRYPTHASH() + { + return m_hash_inner; + } + + /// + /// Completes hashing and returns hashed data. + /// + /// \param[out] val Calculated hash value + /// + template + inline void calculate(_Out_ std::vector<_Ty, _Ax> &val) + { + // Calculate inner hash. + if (!CryptGetHashParam(m_hash_inner, HP_HASHVAL, val, 0)) + throw win_runtime_error(__FUNCTION__ " Error calculating inner hash."); + + // Hash inner hash with outer hash. + if (!CryptHashData(m_hash_outer, (const BYTE*)val.data(), (DWORD)(val.size() * sizeof(_Ty)), 0)) + throw win_runtime_error(__FUNCTION__ " Error hashing inner hash."); + + // Calculate outer hash. + if (!CryptGetHashParam(m_hash_outer, HP_HASHVAL, val, 0)) + throw win_runtime_error(__FUNCTION__ " Error calculating outer hash."); + } + + /// + /// Helper method to pre-derive inner padding for frequent reuse + /// + /// \param[in] cp Handle of the cryptographics provider + /// \param[in] alg Hashing algorithm + /// \param[in] secret HMAC secret + /// \param[in] size_secret \p secret size + /// \param[out] padding HMAC secret XOR inner padding + /// + static void inner_padding( + _In_ HCRYPTPROV cp, + _In_ ALG_ID alg, + _In_bytecount_(size_secret ) const void *secret, + _In_ size_t size_secret, + _Out_ padding_t padding); + + protected: + winstd::crypt_hash m_hash_inner; ///< Inner hashing object + winstd::crypt_hash m_hash_outer; ///< Outer hashing object + }; +} + + +inline void operator<<(_Inout_ eap::cursor_out &cursor, _In_ const eap::tls_random &val) +{ + eap::cursor_out::ptr_type ptr_end = cursor.ptr + sizeof(eap::tls_random); + assert(ptr_end <= cursor.ptr_end); + memcpy(cursor.ptr, val.data, sizeof(eap::tls_random)); + cursor.ptr = ptr_end; +} + + +inline size_t pksizeof(_In_ const eap::tls_random &val) +{ + UNREFERENCED_PARAMETER(val); + return sizeof(eap::tls_random); +} + + +inline void operator>>(_Inout_ eap::cursor_in &cursor, _Out_ eap::tls_random &val) +{ + eap::cursor_in::ptr_type ptr_end = cursor.ptr + sizeof(eap::tls_random); + assert(ptr_end <= cursor.ptr_end); + memcpy(val.data, cursor.ptr, sizeof(eap::tls_random)); + cursor.ptr = ptr_end; +} + + +inline void operator<<(_Inout_ eap::cursor_out &cursor, _In_ const eap::tls_master_secret &val) +{ + eap::cursor_out::ptr_type ptr_end = cursor.ptr + sizeof(eap::tls_master_secret); + assert(ptr_end <= cursor.ptr_end); + memcpy(cursor.ptr, val.data, sizeof(eap::tls_master_secret)); + cursor.ptr = ptr_end; +} + + +inline size_t pksizeof(_In_ const eap::tls_master_secret &val) +{ + UNREFERENCED_PARAMETER(val); + return sizeof(eap::tls_master_secret); +} + + +inline void operator>>(_Inout_ eap::cursor_in &cursor, _Out_ eap::tls_master_secret &val) +{ + eap::cursor_in::ptr_type ptr_end = cursor.ptr + sizeof(eap::tls_master_secret); + assert(ptr_end <= cursor.ptr_end); + memcpy(val.data, cursor.ptr, sizeof(eap::tls_master_secret)); + cursor.ptr = ptr_end; +} + + +inline void operator<<(_Inout_ eap::cursor_out &cursor, _In_ const eap::tls_conn_state &val) +{ + cursor << val.m_master_secret; + cursor << val.m_random_client; + cursor << val.m_random_server; +} + + +inline size_t pksizeof(_In_ const eap::tls_conn_state &val) +{ + return + pksizeof(val.m_master_secret) + + pksizeof(val.m_random_client) + + pksizeof(val.m_random_server); +} + + +inline void operator>>(_Inout_ eap::cursor_in &cursor, _Out_ eap::tls_conn_state &val) +{ + cursor >> val.m_master_secret; + cursor >> val.m_random_client; + cursor >> val.m_random_server; +} diff --git a/lib/TLS/src/Config.cpp b/lib/TLS/src/Config.cpp index 2cd150e..cead6b3 100644 --- a/lib/TLS/src/Config.cpp +++ b/lib/TLS/src/Config.cpp @@ -75,6 +75,8 @@ eap::config_method_tls::config_method_tls(_In_ module &mod) : config_method_with eap::config_method_tls::config_method_tls(_In_ const config_method_tls &other) : m_trusted_root_ca(other.m_trusted_root_ca), m_server_names(other.m_server_names), + m_session_id(other.m_session_id), + m_master_secret(other.m_master_secret), config_method_with_cred(other) { } @@ -83,6 +85,8 @@ eap::config_method_tls::config_method_tls(_In_ const config_method_tls &other) : eap::config_method_tls::config_method_tls(_Inout_ config_method_tls &&other) : m_trusted_root_ca(std::move(other.m_trusted_root_ca)), m_server_names(std::move(other.m_server_names)), + m_session_id(std::move(other.m_session_id)), + m_master_secret(std::move(other.m_master_secret)), config_method_with_cred(std::move(other)) { } @@ -94,6 +98,8 @@ eap::config_method_tls& eap::config_method_tls::operator=(_In_ const config_meth (config_method_with_cred&)*this = other; m_trusted_root_ca = other.m_trusted_root_ca; m_server_names = other.m_server_names; + m_session_id = other.m_session_id; + m_master_secret = other.m_master_secret; } return *this; @@ -106,6 +112,8 @@ eap::config_method_tls& eap::config_method_tls::operator=(_Inout_ config_method_ (config_method_with_cred&&)*this = std::move(other); m_trusted_root_ca = std::move(other.m_trusted_root_ca); m_server_names = std::move(other.m_server_names); + m_session_id = std::move(other.m_session_id); + m_master_secret = std::move(other.m_master_secret); } return *this; @@ -242,6 +250,8 @@ void eap::config_method_tls::operator<<(_Inout_ cursor_out &cursor) const config_method_with_cred::operator<<(cursor); cursor << m_trusted_root_ca; cursor << m_server_names ; + cursor << m_session_id ; + cursor << m_master_secret ; } @@ -250,7 +260,9 @@ size_t eap::config_method_tls::get_pk_size() const return config_method_with_cred::get_pk_size() + pksizeof(m_trusted_root_ca) + - pksizeof(m_server_names ); + pksizeof(m_server_names ) + + pksizeof(m_session_id ) + + pksizeof(m_master_secret ); } @@ -259,6 +271,8 @@ void eap::config_method_tls::operator>>(_Inout_ cursor_in &cursor) config_method_with_cred::operator>>(cursor); cursor >> m_trusted_root_ca; cursor >> m_server_names ; + cursor >> m_session_id ; + cursor >> m_master_secret ; } diff --git a/lib/TLS/src/Method.cpp b/lib/TLS/src/Method.cpp index 551a531..5185a5e 100644 --- a/lib/TLS/src/Method.cpp +++ b/lib/TLS/src/Method.cpp @@ -89,233 +89,6 @@ void eap::method_tls::packet::clear() } -////////////////////////////////////////////////////////////////////// -// eap::method_tls::random -////////////////////////////////////////////////////////////////////// - -eap::method_tls::random::random() : - time(0) -{ - memset(data, 0, sizeof(data)); -} - - -eap::method_tls::random::random(_In_ const random &other) : - time(other.time) -{ - memcpy(data, other.data, sizeof(data)); -} - - -eap::method_tls::random::~random() -{ - SecureZeroMemory(data, sizeof(data)); -} - - -eap::method_tls::random& eap::method_tls::random::operator=(_In_ const random &other) -{ - if (this != std::addressof(other)) { - time = other.time; - memcpy(data, other.data, sizeof(data)); - } - - return *this; -} - - -void eap::method_tls::random::clear() -{ - time = 0; - memset(data, 0, sizeof(data)); -} - - -void eap::method_tls::random::reset(_In_ HCRYPTPROV cp) -{ - _time32(&time); - if (!CryptGenRandom(cp, sizeof(data), data)) - throw win_runtime_error(__FUNCTION__ " Error creating randomness."); -} - - -////////////////////////////////////////////////////////////////////// -// eap::method_tls::master_secret -////////////////////////////////////////////////////////////////////// - -eap::method_tls::master_secret::master_secret() -{ - memset(data, 0, sizeof(data)); -} - - -eap::method_tls::master_secret::master_secret(_In_ HCRYPTPROV cp) -{ - data[0] = 3; - data[1] = 1; - - if (!CryptGenRandom(cp, sizeof(data) - 2, data + 2)) - throw win_runtime_error(__FUNCTION__ " Error creating PMS randomness."); -} - - -eap::method_tls::master_secret::master_secret(_In_ const master_secret &other) -{ - memcpy(data, other.data, sizeof(data)); -} - - -eap::method_tls::master_secret::~master_secret() -{ - SecureZeroMemory(data, sizeof(data)); -} - - -eap::method_tls::master_secret& eap::method_tls::master_secret::operator=(_In_ const master_secret &other) -{ - if (this != std::addressof(other)) - memcpy(data, other.data, sizeof(data)); - - return *this; -} - - -void eap::method_tls::master_secret::clear() -{ - memset(data, 0, sizeof(data)); -} - - -////////////////////////////////////////////////////////////////////// -// eap::method_tls::hash_hmac -////////////////////////////////////////////////////////////////////// - -eap::method_tls::hash_hmac::hash_hmac( - _In_ HCRYPTPROV cp, - _In_ ALG_ID alg, - _In_bytecount_(size_secret ) const void *secret, - _In_ size_t size_secret) -{ - // Prepare padding. - sanitizing_blob padding(sizeof(padding_t)); - inner_padding(cp, alg, secret, size_secret, padding.data()); - - // Continue with the other constructor. - this->hash_hmac::hash_hmac(cp, alg, padding.data()); -} - - -eap::method_tls::hash_hmac::hash_hmac( - _In_ HCRYPTPROV cp, - _In_ ALG_ID alg, - _In_ const padding_t padding) -{ - // Create inner hash. - if (!m_hash_inner.create(cp, alg)) - throw win_runtime_error(__FUNCTION__ " Error creating inner hash."); - - // Initialize it with the inner padding. - if (!CryptHashData(m_hash_inner, padding, sizeof(padding_t), 0)) - throw win_runtime_error(__FUNCTION__ " Error hashing secret XOR inner padding."); - - // Convert inner padding to outer padding for final calculation. - padding_t padding_out; - for (size_t i = 0; i < sizeof(padding_t); i++) - padding_out[i] = padding[i] ^ (0x36 ^ 0x5c); - - // Create outer hash. - if (!m_hash_outer.create(cp, alg)) - throw win_runtime_error(__FUNCTION__ " Error creating outer hash."); - - // Initialize it with the outer padding. - if (!CryptHashData(m_hash_outer, padding_out, sizeof(padding_t), 0)) - throw win_runtime_error(__FUNCTION__ " Error hashing secret XOR inner padding."); -} - - -void eap::method_tls::hash_hmac::inner_padding( - _In_ HCRYPTPROV cp, - _In_ ALG_ID alg, - _In_bytecount_(size_secret ) const void *secret, - _In_ size_t size_secret, - _Out_ padding_t padding) -{ - if (size_secret > sizeof(padding_t)) { - // If the secret is longer than padding, use secret's hash instead. - crypt_hash hash; - if (!hash.create(cp, alg)) - throw win_runtime_error(__FUNCTION__ " Error creating hash."); - if (!CryptHashData(hash, (const BYTE*)secret, (DWORD)size_secret, 0)) - throw win_runtime_error(__FUNCTION__ " Error hashing."); - DWORD size_hash = sizeof(padding_t); - if (!CryptGetHashParam(hash, HP_HASHVAL, padding, &size_hash, 0)) - throw win_runtime_error(__FUNCTION__ " Error finishing hash."); - size_secret = size_hash; - } else - memcpy(padding, secret, size_secret); - for (size_t i = 0; i < size_secret; i++) - padding[i] ^= 0x36; - memset(padding + size_secret, 0x36, sizeof(padding_t) - size_secret); -} - - -////////////////////////////////////////////////////////////////////// -// eap::method_tls::conn_state -////////////////////////////////////////////////////////////////////// - -eap::method_tls::conn_state::conn_state() -{ -} - - -eap::method_tls::conn_state::conn_state(_In_ const conn_state &other) : - m_master_secret(other.m_master_secret), - m_random_client(other.m_random_client), - m_random_server(other.m_random_server) -{ -} - - -eap::method_tls::conn_state::conn_state(_Inout_ conn_state &&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)) -{ -} - - -eap::method_tls::conn_state& eap::method_tls::conn_state::operator=(_In_ const conn_state &other) -{ - if (this != std::addressof(other)) { - m_master_secret = other.m_master_secret; - m_random_client = other.m_random_client; - m_random_server = other.m_random_server; - } - - return *this; -} - - -eap::method_tls::conn_state& eap::method_tls::conn_state::operator=(_Inout_ conn_state &&other) -{ - if (this != std::addressof(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); - } - - return *this; -} - - -const ALG_ID eap::method_tls::conn_state::m_alg_prf = CALG_TLS1PRF; -const ALG_ID eap::method_tls::conn_state::m_alg_encrypt = CALG_3DES; -const size_t eap::method_tls::conn_state::m_size_enc_key = 192/8; // 3DES 192bits -const size_t eap::method_tls::conn_state::m_size_enc_iv = 64/8; // 3DES 64bits -const ALG_ID eap::method_tls::conn_state::m_alg_mac = CALG_SHA1; -const size_t eap::method_tls::conn_state::m_size_mac_key = 160/8; // SHA-1 - - ////////////////////////////////////////////////////////////////////// // eap::method_tls ////////////////////////////////////////////////////////////////////// @@ -329,6 +102,7 @@ eap::method_tls::method_tls(_In_ module &module, _In_ config_method_tls &cfg, _I m_server_finished(false), m_cipher_spec(false), m_seq_num(0), + m_blob_cfg(NULL), method(module, cfg, cred) { } @@ -341,6 +115,12 @@ eap::method_tls::method_tls(_In_ const method_tls &other) : m_packet_req(other.m_packet_req), m_packet_res(other.m_packet_res), m_state(other.m_state), + m_padding_hmac_client(other.m_padding_hmac_client), + //m_padding_hmac_server(other.m_padding_hmac_server), + m_key_client(other.m_key_client), + m_key_server(other.m_key_server), + m_key_mppe_send(other.m_key_mppe_send), + m_key_mppe_recv(other.m_key_mppe_recv), m_session_id(other.m_session_id), m_server_cert_chain(other.m_server_cert_chain), m_hash_handshake_msgs_md5(other.m_hash_handshake_msgs_md5), @@ -362,6 +142,12 @@ eap::method_tls::method_tls(_Inout_ method_tls &&other) : m_packet_req(std::move(other.m_packet_req)), m_packet_res(std::move(other.m_packet_res)), m_state(std::move(other.m_state)), + m_padding_hmac_client(std::move(other.m_padding_hmac_client)), + //m_padding_hmac_server(std::move(other.m_padding_hmac_server)), + m_key_client(std::move(other.m_key_client)), + m_key_server(std::move(other.m_key_server)), + m_key_mppe_send(std::move(other.m_key_mppe_send)), + m_key_mppe_recv(std::move(other.m_key_mppe_recv)), m_session_id(std::move(other.m_session_id)), m_server_cert_chain(std::move(other.m_server_cert_chain)), m_hash_handshake_msgs_md5(std::move(other.m_hash_handshake_msgs_md5)), @@ -376,25 +162,38 @@ eap::method_tls::method_tls(_Inout_ method_tls &&other) : } +eap::method_tls::~method_tls() +{ + if (m_blob_cfg) + m_module.free_memory(m_blob_cfg); +} + + eap::method_tls& eap::method_tls::operator=(_In_ const method_tls &other) { if (this != std::addressof(other)) { assert(std::addressof(m_cfg ) == std::addressof(other.m_cfg )); // Copy method with same configuration only! assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Copy method with same credentials only! - (method&)*this = other; - m_phase = other.m_phase; - m_packet_req = other.m_packet_req; - m_packet_res = other.m_packet_res; - m_state = other.m_state; - m_session_id = other.m_session_id; - m_server_cert_chain = other.m_server_cert_chain; - m_hash_handshake_msgs_md5 = other.m_hash_handshake_msgs_md5; - m_hash_handshake_msgs_sha1 = other.m_hash_handshake_msgs_sha1; - m_send_client_cert = other.m_send_client_cert; - m_server_hello_done = other.m_server_hello_done; - m_server_finished = other.m_server_finished; - m_cipher_spec = other.m_cipher_spec; - m_seq_num = other.m_seq_num; + (method&)*this = other; + m_phase = other.m_phase; + m_packet_req = other.m_packet_req; + m_packet_res = other.m_packet_res; + m_state = other.m_state; + m_padding_hmac_client = other.m_padding_hmac_client; + //m_padding_hmac_server = other.m_padding_hmac_server; + m_key_client = other.m_key_client; + m_key_server = other.m_key_server; + m_key_mppe_send = other.m_key_mppe_send; + m_key_mppe_recv = other.m_key_mppe_recv; + m_session_id = other.m_session_id; + m_server_cert_chain = other.m_server_cert_chain; + m_hash_handshake_msgs_md5 = other.m_hash_handshake_msgs_md5; + m_hash_handshake_msgs_sha1 = other.m_hash_handshake_msgs_sha1; + m_send_client_cert = other.m_send_client_cert; + m_server_hello_done = other.m_server_hello_done; + m_server_finished = other.m_server_finished; + m_cipher_spec = other.m_cipher_spec; + m_seq_num = other.m_seq_num; } return *this; @@ -406,20 +205,26 @@ eap::method_tls& eap::method_tls::operator=(_Inout_ method_tls &&other) if (this != std::addressof(other)) { assert(std::addressof(m_cfg ) == std::addressof(other.m_cfg )); // Move method with same configuration only! assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Move method with same credentials only! - (method&)*this = std::move(other); - m_phase = std::move(other.m_phase); - m_packet_req = std::move(other.m_packet_req); - m_packet_res = std::move(other.m_packet_res); - m_state = std::move(other.m_state); - m_session_id = std::move(other.m_session_id); - m_server_cert_chain = std::move(other.m_server_cert_chain); - m_hash_handshake_msgs_md5 = std::move(other.m_hash_handshake_msgs_md5); - m_hash_handshake_msgs_sha1 = std::move(other.m_hash_handshake_msgs_sha1); - m_send_client_cert = std::move(other.m_send_client_cert); - m_server_hello_done = std::move(other.m_server_hello_done); - m_server_finished = std::move(other.m_server_finished); - m_cipher_spec = std::move(other.m_cipher_spec); - m_seq_num = std::move(other.m_seq_num); + (method&)*this = std::move(other); + m_phase = std::move(other.m_phase); + m_packet_req = std::move(other.m_packet_req); + m_packet_res = std::move(other.m_packet_res); + m_state = std::move(other.m_state); + m_padding_hmac_client = std::move(other.m_padding_hmac_client); + //m_padding_hmac_server = std::move(other.m_padding_hmac_server); + m_key_client = std::move(other.m_key_client); + m_key_server = std::move(other.m_key_server); + m_key_mppe_send = std::move(other.m_key_mppe_send); + m_key_mppe_recv = std::move(other.m_key_mppe_recv); + m_session_id = std::move(other.m_session_id); + m_server_cert_chain = std::move(other.m_server_cert_chain); + m_hash_handshake_msgs_md5 = std::move(other.m_hash_handshake_msgs_md5); + m_hash_handshake_msgs_sha1 = std::move(other.m_hash_handshake_msgs_sha1); + m_send_client_cert = std::move(other.m_send_client_cert); + m_server_hello_done = std::move(other.m_server_hello_done); + m_server_finished = std::move(other.m_server_finished); + m_cipher_spec = std::move(other.m_cipher_spec); + m_seq_num = std::move(other.m_seq_num); } return *this; @@ -437,6 +242,9 @@ void eap::method_tls::begin_session( // Create cryptographics provider. if (!m_cp.create(NULL, MS_ENHANCED_PROV, PROV_RSA_FULL)) throw win_runtime_error(__FUNCTION__ " Error creating cryptographics provider."); + + m_session_id = m_cfg.m_session_id; + m_state.m_master_secret = m_cfg.m_master_secret; } @@ -530,15 +338,18 @@ void eap::method_tls::process_request_packet( m_phase = phase_client_hello; m_packet_res.clear(); + + m_state.m_random_client.reset(m_cp); + + // Generate client randomness. m_padding_hmac_client.clear(); //m_padding_hmac_server.clear(); m_key_client.free(); m_key_server.free(); + m_key_mppe_send.clear(); + m_key_mppe_recv.clear(); - // Generate client randomness. - m_state.m_random_client.reset(m_cp); m_server_cert_chain.clear(); - m_session_id.clear(); // Create MD5 hash object. if (!m_hash_handshake_msgs_md5.create(m_cp, CALG_MD5)) @@ -612,7 +423,7 @@ void eap::method_tls::process_request_packet( } // Generate pre-master secret and encrypt it. PMS will get sanitized in its destructor when going out-of-scope. - master_secret pms(m_cp); + tls_master_secret pms(m_cp); sanitizing_blob pms_enc((const unsigned char*)&pms, (const unsigned char*)(&pms + 1)); crypt_key key; if (!key.import_public(m_cp, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &(m_server_cert_chain.front()->pCertInfo->SubjectPublicKeyInfo))) @@ -621,12 +432,12 @@ void eap::method_tls::process_request_packet( throw win_runtime_error(__FUNCTION__ " Error encrypting PMS."); // Derive master secret. - sanitizing_blob lblseed; - const unsigned char s_label[] = "master secret"; - lblseed.assign(s_label, s_label + _countof(s_label) - 1); - lblseed.insert(lblseed.end(), (const unsigned char*)&m_state.m_random_client, (const unsigned char*)(&m_state.m_random_client + 1)); - lblseed.insert(lblseed.end(), (const unsigned char*)&m_state.m_random_server, (const unsigned char*)(&m_state.m_random_server + 1)); - memcpy(&m_state.m_master_secret, prf(&pms, sizeof(pms), lblseed.data(), lblseed.size(), sizeof(master_secret)).data(), sizeof(master_secret)); + sanitizing_blob seed; + static const unsigned char s_label[] = "master secret"; + seed.assign(s_label, s_label + _countof(s_label) - 1); + seed.insert(seed.end(), (const unsigned char*)&m_state.m_random_client, (const unsigned char*)(&m_state.m_random_client + 1)); + seed.insert(seed.end(), (const unsigned char*)&m_state.m_random_server, (const unsigned char*)(&m_state.m_random_server + 1)); + memcpy(&m_state.m_master_secret, prf(&pms, sizeof(pms), seed.data(), seed.size(), sizeof(tls_master_secret)).data(), sizeof(tls_master_secret)); // Create client key exchange message, and append to packet. sanitizing_blob client_key_exchange(make_client_key_exchange(pms_enc)); @@ -751,10 +562,57 @@ void eap::method_tls::get_result( _In_ EapPeerMethodResultReason reason, _Inout_ EapPeerMethodResult *ppResult) { - UNREFERENCED_PARAMETER(reason); - UNREFERENCED_PARAMETER(ppResult); + assert(ppResult); - throw win_runtime_error(ERROR_NOT_SUPPORTED, __FUNCTION__ " Not supported."); + switch (reason) { + case EapPeerMethodResultSuccess: { + if (m_phase < phase_change_chiper_spec) + throw invalid_argument(__FUNCTION__ " Premature success."); + + // Derive MSK. + derive_msk(); + + // Fill array with RADIUS attributes. + eap_attr a; + m_eap_attr.clear(); + a.create_ms_mppe_key(16, (LPCBYTE)&m_key_mppe_send, sizeof(tls_random)); + m_eap_attr.push_back(std::move(a)); + a.create_ms_mppe_key(17, (LPCBYTE)&m_key_mppe_recv, sizeof(tls_random)); + m_eap_attr.push_back(std::move(a)); + m_eap_attr.push_back(eap_attr::blank); + + m_eap_attr_desc.dwNumberOfAttributes = (DWORD)m_eap_attr.size(); + m_eap_attr_desc.pAttribs = m_eap_attr.data(); + ppResult->pAttribArray = &m_eap_attr_desc; + + ppResult->fIsSuccess = TRUE; + + // Update configuration with session resumption data and prepare BLOB. + m_cfg.m_session_id = m_session_id; + m_cfg.m_master_secret = m_state.m_master_secret; + ppResult->fSaveConnectionData = TRUE; + + m_phase = phase_finished; + break; + } + + case EapPeerMethodResultFailure: + // :( + m_cfg.m_session_id.clear(); + m_cfg.m_master_secret.clear(); + ppResult->fSaveConnectionData = TRUE; + break; + + default: + throw win_runtime_error(ERROR_NOT_SUPPORTED, __FUNCTION__ " Not supported."); + } + + if (ppResult->fSaveConnectionData) { + m_module.pack(m_cfg, &ppResult->pConnectionData, &ppResult->dwSizeofConnectionData); + if (m_blob_cfg) + m_module.free_memory(m_blob_cfg); + m_blob_cfg = ppResult->pConnectionData; + } } @@ -763,20 +621,20 @@ eap::sanitizing_blob eap::method_tls::make_client_hello() const size_t size_data; sanitizing_blob msg; msg.reserve( - 4 + // SSL header + 4 + // SSL header (size_data = - 2 + // SSL version - sizeof(random) + // Client random - 1 + // Session ID size - m_session_id.size() + // Session ID - 2 + // Length of cypher suite list - 2 + // Cyper suite list - 1 + // Length of compression suite - 1)); // Compression suite + 2 + // SSL version + sizeof(tls_random) + // Client random + 1 + // Session ID size + m_session_id.size() + // Session ID + 2 + // Length of cypher suite list + 2 + // Cyper suite list + 1 + // Length of compression suite + 1)); // Compression suite // SSL header assert(size_data <= 0xffffff); - unsigned int ssl_header = htonl(((unsigned int)handshake_type_client_hello << 24) | (unsigned int)size_data); + unsigned int ssl_header = htonl(((unsigned int)tls_handshake_type_client_hello << 24) | (unsigned int)size_data); msg.insert(msg.end(), (unsigned char*)&ssl_header, (unsigned char*)(&ssl_header + 1)); // SSL version: TLS 1.0 @@ -829,7 +687,7 @@ eap::sanitizing_blob eap::method_tls::make_client_cert() const // SSL header assert(size_data <= 0xffffff); - unsigned int ssl_header = htonl(((unsigned int)handshake_type_certificate << 24) | (unsigned int)size_data); + unsigned int ssl_header = htonl(((unsigned int)tls_handshake_type_certificate << 24) | (unsigned int)size_data); msg.insert(msg.end(), (unsigned char*)&ssl_header, (unsigned char*)(&ssl_header + 1)); // List size @@ -864,7 +722,7 @@ eap::sanitizing_blob eap::method_tls::make_client_key_exchange(_In_ const saniti // SSL header assert(size_data <= 0xffffff); - unsigned int ssl_header = htonl(((unsigned int)handshake_type_client_key_exchange << 24) | (unsigned int)size_data); + unsigned int ssl_header = htonl(((unsigned int)tls_handshake_type_client_key_exchange << 24) | (unsigned int)size_data); msg.insert(msg.end(), (unsigned char*)&ssl_header, (unsigned char*)(&ssl_header + 1)); // Encrypted pre master secret size @@ -882,18 +740,18 @@ eap::sanitizing_blob eap::method_tls::make_client_key_exchange(_In_ const saniti eap::sanitizing_blob eap::method_tls::make_change_chiper_spec() { static const unsigned char s_msg_css[] = { - (unsigned char)message_type_change_cipher_spec, // SSL record type - 3, // SSL major version - 1, // SSL minor version - 0, // Message size (high-order byte) - 1, // Message size (low-order byte) - 1, // Message: change_cipher_spec is always "1" + (unsigned char)tls_message_type_change_cipher_spec, // SSL record type + 3, // SSL major version + 1, // SSL minor version + 0, // Message size (high-order byte) + 1, // Message size (low-order byte) + 1, // Message: change_cipher_spec is always "1" }; return eap::sanitizing_blob(s_msg_css, s_msg_css + _countof(s_msg_css)); } -eap::sanitizing_blob eap::method_tls::make_finished() +eap::sanitizing_blob eap::method_tls::make_finished() const { sanitizing_blob msg; msg.reserve( @@ -901,20 +759,22 @@ eap::sanitizing_blob eap::method_tls::make_finished() 12); // verify_data is 12B // SSL header - unsigned int ssl_header = htonl(((unsigned int)handshake_type_finished << 24) | 12); + unsigned int ssl_header = htonl(((unsigned int)tls_handshake_type_finished << 24) | 12); msg.insert(msg.end(), (unsigned char*)&ssl_header, (unsigned char*)(&ssl_header + 1)); // Create label + hash MD5 + hash SHA-1 seed. - sanitizing_blob lblseed, hash; - const unsigned char s_label[] = "client finished"; - lblseed.assign(s_label, s_label + _countof(s_label) - 1); - if (!CryptGetHashParam(m_hash_handshake_msgs_md5, HP_HASHVAL, hash, 0)) + crypt_hash hash; + static const unsigned char s_label[] = "client finished"; + sanitizing_blob seed(s_label, s_label + _countof(s_label) - 1), hash_data; + hash = m_hash_handshake_msgs_md5; // duplicate + if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, 0)) throw win_runtime_error(__FUNCTION__ " Error finishing MD5 hash calculation."); - lblseed.insert(lblseed.end(), hash.begin(), hash.end()); - if (!CryptGetHashParam(m_hash_handshake_msgs_sha1, HP_HASHVAL, hash, 0)) + seed.insert(seed.end(), hash_data.begin(), hash_data.end()); + hash = m_hash_handshake_msgs_sha1; // duplicate + if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, 0)) throw win_runtime_error(__FUNCTION__ " Error finishing SHA-1 hash calculation."); - lblseed.insert(lblseed.end(), hash.begin(), hash.end()); - sanitizing_blob verify(prf(&m_state.m_master_secret, sizeof(master_secret), lblseed.data(), lblseed.size(), 12)); + seed.insert(seed.end(), hash_data.begin(), hash_data.end()); + sanitizing_blob verify(prf(&m_state.m_master_secret, sizeof(tls_master_secret), seed.data(), seed.size(), 12)); msg.insert(msg.end(), verify.begin(), verify.end()); return msg; @@ -932,7 +792,7 @@ eap::sanitizing_blob eap::method_tls::make_handshake(_In_ const sanitizing_blob size_msg); // Message // SSL record type - msg_h.push_back((unsigned char)message_type_handshake); + msg_h.push_back((unsigned char)tls_message_type_handshake); // SSL version: TLS 1.0 msg_h.push_back(3); // SSL major version @@ -950,13 +810,13 @@ eap::sanitizing_blob eap::method_tls::make_handshake(_In_ const sanitizing_blob void eap::method_tls::derive_keys() { - sanitizing_blob lblseed; - const unsigned char s_label[] = "key expansion"; - lblseed.assign(s_label, s_label + _countof(s_label) - 1); - lblseed.insert(lblseed.end(), (const unsigned char*)&m_state.m_random_server, (const unsigned char*)(&m_state.m_random_server + 1)); - lblseed.insert(lblseed.end(), (const unsigned char*)&m_state.m_random_client, (const unsigned char*)(&m_state.m_random_client + 1)); + sanitizing_blob seed; + static const unsigned char s_label[] = "key expansion"; + seed.assign(s_label, s_label + _countof(s_label) - 1); + seed.insert(seed.end(), (const unsigned char*)&m_state.m_random_server, (const unsigned char*)(&m_state.m_random_server + 1)); + seed.insert(seed.end(), (const unsigned char*)&m_state.m_random_client, (const unsigned char*)(&m_state.m_random_client + 1)); - sanitizing_blob key_block(prf(&m_state.m_master_secret, sizeof(master_secret), lblseed.data(), lblseed.size(), + sanitizing_blob key_block(prf(&m_state.m_master_secret, sizeof(tls_master_secret), seed.data(), seed.size(), 2*m_state.m_size_mac_key + // client_write_MAC_secret & server_write_MAC_secret (SHA1) 2*m_state.m_size_enc_key + // client_write_key & server_write_key 2*m_state.m_size_enc_iv )); // client_write_IV & server_write_IV @@ -992,6 +852,26 @@ void eap::method_tls::derive_keys() } +void eap::method_tls::derive_msk() +{ + sanitizing_blob seed; + static const unsigned char s_label[] = "ttls keying material"; + seed.assign(s_label, s_label + _countof(s_label) - 1); + seed.insert(seed.end(), (const unsigned char*)&m_state.m_random_client, (const unsigned char*)(&m_state.m_random_client + 1)); + seed.insert(seed.end(), (const unsigned char*)&m_state.m_random_server, (const unsigned char*)(&m_state.m_random_server + 1)); + sanitizing_blob key_block(prf(&m_state.m_master_secret, sizeof(tls_master_secret), seed.data(), seed.size(), 2*sizeof(tls_random))); + const unsigned char *_key_block = key_block.data(); + + // MS-MPPE-Send-Key + memcpy(&m_key_mppe_send, _key_block, sizeof(tls_random)); + _key_block += sizeof(tls_random); + + // MS-MPPE-Recv-Key + memcpy(&m_key_mppe_recv, _key_block, sizeof(tls_random)); + _key_block += sizeof(tls_random); +} + + void eap::method_tls::process_packet(_In_bytecount_(size_pck) const void *_pck, _In_ size_t size_pck) { for (const unsigned char *pck = (const unsigned char*)_pck, *pck_end = pck + size_pck; pck < pck_end; ) { @@ -1007,11 +887,11 @@ void eap::method_tls::process_packet(_In_bytecount_(size_pck) const void *_pck, if (hdr->version.major == 3 && hdr->version.minor == 1) { // Process TLS 1.0 message. switch (hdr->type) { - case message_type_change_cipher_spec: + case tls_message_type_change_cipher_spec: process_change_cipher_spec(msg, msg_end - msg); break; - case message_type_alert: + case tls_message_type_alert: if (m_cipher_spec) { sanitizing_blob msg_dec(msg, msg_end); decrypt_message(msg_dec); @@ -1020,7 +900,7 @@ void eap::method_tls::process_packet(_In_bytecount_(size_pck) const void *_pck, process_alert(msg, msg_end - msg); break; - case message_type_handshake: + case tls_message_type_handshake: if (m_cipher_spec) { sanitizing_blob msg_dec(msg, msg_end); decrypt_message(msg_dec); @@ -1029,7 +909,7 @@ void eap::method_tls::process_packet(_In_bytecount_(size_pck) const void *_pck, process_handshake(msg, msg_end - msg); break; - case message_type_application_data: + case tls_message_type_application_data: if (!m_cipher_spec) throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Application data should be encrypted."); @@ -1096,19 +976,20 @@ void eap::method_tls::process_handshake(_In_bytecount_(msg_size) const void *_ms // Process record. unsigned char type = hdr >> 24; switch (type) { - case handshake_type_server_hello: + case tls_handshake_type_server_hello: // TLS version if (rec + 2 > rec_end) throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Server SSL/TLS version missing or incomplete."); else if (rec[0] != 3 || rec[1] != 1) throw win_runtime_error(ERROR_NOT_SUPPORTED, __FUNCTION__ " Unsupported SSL/TLS version."); + m_state.m_alg_prf = CALG_TLS1PRF; rec += 2; // Server random if (rec + sizeof(m_state.m_random_server) > rec_end) throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Server random missing or incomplete."); - memcpy(&m_state.m_random_server, rec, sizeof(random)); - rec += sizeof(random); + memcpy(&m_state.m_random_server, rec, sizeof(tls_random)); + rec += sizeof(tls_random); // Session ID if (rec + 1 > rec_end || rec + 1 + rec[0] > rec_end) @@ -1120,13 +1001,20 @@ void eap::method_tls::process_handshake(_In_bytecount_(msg_size) const void *_ms // Cipher if (rec + 2 > rec_end) throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Cipher or incomplete."); - if (rec[0] != 0x00 || rec[1] != 0x0a) - throw win_runtime_error(ERROR_NOT_SUPPORTED, string_printf(__FUNCTION__ " Other than requested cipher selected (expected 0x000a, received 0x%02x%02x).", rec[0], rec[1])); + if (rec[0] == 0x00 || rec[1] == 0x0a) { + // TLS_RSA_WITH_3DES_EDE_CBC_SHA + m_state.m_alg_encrypt = CALG_3DES; + m_state.m_size_enc_key = 192/8; // 3DES 192bits + m_state.m_size_enc_iv = 64/8; // 3DES 64bits + m_state.m_alg_mac = CALG_SHA1; + m_state.m_size_mac_key = 160/8; // SHA-1 + } else + throw win_runtime_error(ERROR_NOT_SUPPORTED, string_printf(__FUNCTION__ " Other than requested cipher selected (received 0x%02x%02x).", rec[0], rec[1])); m_module.log_event(&EAPMETHOD_TLS_SERVER_HELLO, event_data((unsigned int)eap_type_tls), event_data((unsigned int)m_session_id.size()), event_data(m_session_id.data(), (ULONG)m_session_id.size()), event_data::blank); break; - case handshake_type_certificate: { + case tls_handshake_type_certificate: { // Certificate list size if (rec + 3 > rec_end) throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Certificate list size missing or incomplete."); @@ -1161,33 +1049,35 @@ void eap::method_tls::process_handshake(_In_bytecount_(msg_size) const void *_ms break; } - case handshake_type_certificate_request: + case tls_handshake_type_certificate_request: m_send_client_cert = true; m_module.log_event(&EAPMETHOD_TLS_CERTIFICATE_REQUEST, event_data((unsigned int)eap_type_tls), event_data::blank); break; - case handshake_type_server_hello_done: + case tls_handshake_type_server_hello_done: m_server_hello_done = true; m_module.log_event(&EAPMETHOD_TLS_SERVER_HELLO_DONE, event_data((unsigned int)eap_type_tls), event_data::blank); break; - case handshake_type_finished: { + case tls_handshake_type_finished: { // According to https://tools.ietf.org/html/rfc5246#section-7.4.9 all verify_data is 12B. if (rec_end - rec != 12) throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, string_printf(__FUNCTION__ " Finished record size incorrect (expected 12B, received %uB).", rec_end - rec)); // Create label + hash MD5 + hash SHA-1 seed. - sanitizing_blob lblseed, hash; - const unsigned char s_label[] = "server finished"; - lblseed.assign(s_label, s_label + _countof(s_label) - 1); - if (!CryptGetHashParam(m_hash_handshake_msgs_md5, HP_HASHVAL, hash, 0)) + crypt_hash hash; + static const unsigned char s_label[] = "server finished"; + sanitizing_blob seed(s_label, s_label + _countof(s_label) - 1), hash_data; + hash = m_hash_handshake_msgs_md5; // duplicate + if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, 0)) throw win_runtime_error(__FUNCTION__ " Error finishing MD5 hash calculation."); - lblseed.insert(lblseed.end(), hash.begin(), hash.end()); - if (!CryptGetHashParam(m_hash_handshake_msgs_sha1, HP_HASHVAL, hash, 0)) + seed.insert(seed.end(), hash_data.begin(), hash_data.end()); + hash = m_hash_handshake_msgs_sha1; // duplicate + if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, 0)) throw win_runtime_error(__FUNCTION__ " Error finishing SHA-1 hash calculation."); - lblseed.insert(lblseed.end(), hash.begin(), hash.end()); + seed.insert(seed.end(), hash_data.begin(), hash_data.end()); - if (memcmp(prf(&m_state.m_master_secret, sizeof(master_secret), lblseed.data(), lblseed.size(), 12).data(), rec, 12)) + if (memcmp(prf(&m_state.m_master_secret, sizeof(tls_master_secret), seed.data(), seed.size(), 12).data(), rec, 12)) throw win_runtime_error(ERROR_ENCRYPTION_FAILED, __FUNCTION__ " Integrity check failed."); m_server_finished = true; @@ -1211,10 +1101,10 @@ void eap::method_tls::process_application_data(_In_bytecount_(msg_size) const vo } -void eap::method_tls::verify_server_trust() +void eap::method_tls::verify_server_trust() const { assert(!m_server_cert_chain.empty()); - cert_context &cert = m_server_cert_chain.front(); + const cert_context &cert = m_server_cert_chain.front(); if (!m_cfg.m_server_names.empty()) { // Check server name. @@ -1357,17 +1247,24 @@ void eap::method_tls::encrypt_message(_Inout_ sanitizing_blob &msg) } -void eap::method_tls::decrypt_message(_Inout_ sanitizing_blob &msg) +void eap::method_tls::decrypt_message(_Inout_ sanitizing_blob &msg) const { // Decrypt. - DWORD size = (DWORD)msg.size(); - if (!CryptDecrypt(m_key_server, NULL, FALSE, 0, msg.data(), &size)) + if (!CryptDecrypt(m_key_server, NULL, FALSE, 0, msg)) throw win_runtime_error(__FUNCTION__ " Error decrypting message."); - // TODO: Check padding! + size_t size = msg.size(); + if (size) { + // Check padding. + unsigned char padding = msg.back(); + size_t size_data = size - 1 - padding; + for (size_t i = size_data, i_end = size - 1; i < i_end; i++) + if (msg[i] != padding) + throw invalid_argument(__FUNCTION__ " Incorrect message padding."); - // Remove padding. - msg.resize(size - msg.back() - 1); + // Remove padding. + msg.resize(size_data); + } } @@ -1376,12 +1273,11 @@ eap::sanitizing_blob eap::method_tls::prf( _In_ size_t size_secret, _In_bytecount_(size_seed) const void *seed, _In_ size_t size_seed, - _In_ size_t size) + _In_ size_t size) const { sanitizing_blob data; data.reserve(size); -#pragma warning(suppress: 4127) // Prepared for future expansion to TLS 1.2, where m_alg_prf will no longer be static const. if (m_state.m_alg_prf == CALG_TLS1PRF) { // Split secret in two halves. size_t diff --git a/lib/TLS/src/StdAfx.h b/lib/TLS/src/StdAfx.h index 97c9438..ba927a1 100644 --- a/lib/TLS/src/StdAfx.h +++ b/lib/TLS/src/StdAfx.h @@ -23,6 +23,7 @@ #include "../include/Config.h" #include "../include/Credentials.h" #include "../include/Method.h" +#include "../include/TLS.h" #include "../../EAPBase/include/EAPXML.h" diff --git a/lib/TLS/src/TLS.cpp b/lib/TLS/src/TLS.cpp new file mode 100644 index 0000000..c5fdbd2 --- /dev/null +++ b/lib/TLS/src/TLS.cpp @@ -0,0 +1,238 @@ +/* + Copyright 2015-2016 Amebis + Copyright 2016 GÉANT + + This file is part of GÉANTLink. + + GÉANTLink is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GÉANTLink is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GÉANTLink. If not, see . +*/ + +#include "StdAfx.h" + +using namespace std; +using namespace winstd; + + +////////////////////////////////////////////////////////////////////// +// eap::tls_random +////////////////////////////////////////////////////////////////////// + +eap::tls_random::tls_random() +{ + memset(data, 0, sizeof(data)); +} + + +eap::tls_random::tls_random(_In_ const tls_random &other) +{ + memcpy(data, other.data, sizeof(data)); +} + + +eap::tls_random::~tls_random() +{ + SecureZeroMemory(data, sizeof(data)); +} + + +eap::tls_random& eap::tls_random::operator=(_In_ const tls_random &other) +{ + if (this != std::addressof(other)) + memcpy(data, other.data, sizeof(data)); + + return *this; +} + + +void eap::tls_random::clear() +{ + memset(data, 0, sizeof(data)); +} + + +void eap::tls_random::reset(_In_ HCRYPTPROV cp) +{ + _time32((__time32_t*)&time); + if (!CryptGenRandom(cp, sizeof(data) - sizeof(__time32_t), data + sizeof(__time32_t))) + throw win_runtime_error(__FUNCTION__ " Error creating randomness."); +} + + +////////////////////////////////////////////////////////////////////// +// eap::tls_master_secret +////////////////////////////////////////////////////////////////////// + +eap::tls_master_secret::tls_master_secret() +{ + memset(data, 0, sizeof(data)); +} + + +eap::tls_master_secret::tls_master_secret(_In_ HCRYPTPROV cp) +{ + data[0] = 3; + data[1] = 1; + + if (!CryptGenRandom(cp, sizeof(data) - 2, data + 2)) + throw win_runtime_error(__FUNCTION__ " Error creating PMS randomness."); +} + + +eap::tls_master_secret::tls_master_secret(_In_ const tls_master_secret &other) +{ + memcpy(data, other.data, sizeof(data)); +} + + +eap::tls_master_secret::~tls_master_secret() +{ + SecureZeroMemory(data, sizeof(data)); +} + + +eap::tls_master_secret& eap::tls_master_secret::operator=(_In_ const tls_master_secret &other) +{ + if (this != std::addressof(other)) + memcpy(data, other.data, sizeof(data)); + + return *this; +} + + +void eap::tls_master_secret::clear() +{ + memset(data, 0, sizeof(data)); +} + + +////////////////////////////////////////////////////////////////////// +// eap::tls_conn_state +////////////////////////////////////////////////////////////////////// + +eap::tls_conn_state::tls_conn_state() +{ +} + + +eap::tls_conn_state::tls_conn_state(_In_ const tls_conn_state &other) : + m_master_secret(other.m_master_secret), + m_random_client(other.m_random_client), + m_random_server(other.m_random_server) +{ +} + + +eap::tls_conn_state::tls_conn_state(_Inout_ tls_conn_state &&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)) +{ +} + + +eap::tls_conn_state& eap::tls_conn_state::operator=(_In_ const tls_conn_state &other) +{ + if (this != std::addressof(other)) { + m_master_secret = other.m_master_secret; + m_random_client = other.m_random_client; + m_random_server = other.m_random_server; + } + + return *this; +} + + +eap::tls_conn_state& eap::tls_conn_state::operator=(_Inout_ tls_conn_state &&other) +{ + if (this != std::addressof(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); + } + + return *this; +} + + +////////////////////////////////////////////////////////////////////// +// eap::hash_hmac +////////////////////////////////////////////////////////////////////// + +eap::hash_hmac::hash_hmac( + _In_ HCRYPTPROV cp, + _In_ ALG_ID alg, + _In_bytecount_(size_secret ) const void *secret, + _In_ size_t size_secret) +{ + // Prepare padding. + sanitizing_blob padding(sizeof(padding_t)); + inner_padding(cp, alg, secret, size_secret, padding.data()); + + // Continue with the other constructor. + this->hash_hmac::hash_hmac(cp, alg, padding.data()); +} + + +eap::hash_hmac::hash_hmac( + _In_ HCRYPTPROV cp, + _In_ ALG_ID alg, + _In_ const padding_t padding) +{ + // Create inner hash. + if (!m_hash_inner.create(cp, alg)) + throw win_runtime_error(__FUNCTION__ " Error creating inner hash."); + + // Initialize it with the inner padding. + if (!CryptHashData(m_hash_inner, padding, sizeof(padding_t), 0)) + throw win_runtime_error(__FUNCTION__ " Error hashing secret XOR inner padding."); + + // Convert inner padding to outer padding for final calculation. + padding_t padding_out; + for (size_t i = 0; i < sizeof(padding_t); i++) + padding_out[i] = padding[i] ^ (0x36 ^ 0x5c); + + // Create outer hash. + if (!m_hash_outer.create(cp, alg)) + throw win_runtime_error(__FUNCTION__ " Error creating outer hash."); + + // Initialize it with the outer padding. + if (!CryptHashData(m_hash_outer, padding_out, sizeof(padding_t), 0)) + throw win_runtime_error(__FUNCTION__ " Error hashing secret XOR inner padding."); +} + + +void eap::hash_hmac::inner_padding( + _In_ HCRYPTPROV cp, + _In_ ALG_ID alg, + _In_bytecount_(size_secret ) const void *secret, + _In_ size_t size_secret, + _Out_ padding_t padding) +{ + if (size_secret > sizeof(padding_t)) { + // If the secret is longer than padding, use secret's hash instead. + crypt_hash hash; + if (!hash.create(cp, alg)) + throw win_runtime_error(__FUNCTION__ " Error creating hash."); + if (!CryptHashData(hash, (const BYTE*)secret, (DWORD)size_secret, 0)) + throw win_runtime_error(__FUNCTION__ " Error hashing."); + DWORD size_hash = sizeof(padding_t); + if (!CryptGetHashParam(hash, HP_HASHVAL, padding, &size_hash, 0)) + throw win_runtime_error(__FUNCTION__ " Error finishing hash."); + size_secret = size_hash; + } else + memcpy(padding, secret, size_secret); + for (size_t i = 0; i < size_secret; i++) + padding[i] ^= 0x36; + memset(padding + size_secret, 0x36, sizeof(padding_t) - size_secret); +} diff --git a/lib/WinStd b/lib/WinStd index dc27115..84e544c 160000 --- a/lib/WinStd +++ b/lib/WinStd @@ -1 +1 @@ -Subproject commit dc2711590306e1c056e49a12f8b8a7c40ee337ea +Subproject commit 84e544c2f6dbf14f76b930b2672c3cc2b77bfc3f