Support for TLS 1.2 added
This commit is contained in:
parent
d68fd6ce08
commit
85d7c3d4ec
@ -297,8 +297,9 @@ namespace eap
|
|||||||
///
|
///
|
||||||
inline void hash_handshake(_In_count_(size) const void *data, _In_ size_t size)
|
inline void hash_handshake(_In_count_(size) const void *data, _In_ size_t size)
|
||||||
{
|
{
|
||||||
CryptHashData(m_hash_handshake_msgs_md5 , (const BYTE*)data, (DWORD)size, 0);
|
CryptHashData(m_hash_handshake_msgs_md5 , (const BYTE*)data, (DWORD)size, 0);
|
||||||
CryptHashData(m_hash_handshake_msgs_sha1, (const BYTE*)data, (DWORD)size, 0);
|
CryptHashData(m_hash_handshake_msgs_sha1 , (const BYTE*)data, (DWORD)size, 0);
|
||||||
|
CryptHashData(m_hash_handshake_msgs_sha256, (const BYTE*)data, (DWORD)size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -450,6 +451,8 @@ namespace eap
|
|||||||
/// \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)
|
/// \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)
|
||||||
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 5. HMAC and the Pseudorandom Function)](https://tools.ietf.org/html/rfc5246#section-5)
|
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 5. HMAC and the Pseudorandom Function)](https://tools.ietf.org/html/rfc5246#section-5)
|
||||||
///
|
///
|
||||||
|
/// \param[in] cp Handle of the cryptographics provider
|
||||||
|
/// \param[in] alg Hashing Algorithm to use (CALG_TLS1PRF = combination of MD5 and SHA-1, CALG_SHA_256...)
|
||||||
/// \param[in] secret Hashing secret key
|
/// \param[in] secret Hashing secret key
|
||||||
/// \param[in] seed Random seed
|
/// \param[in] seed Random seed
|
||||||
/// \param[in] size_seed \p seed size
|
/// \param[in] size_seed \p seed size
|
||||||
@ -457,11 +460,60 @@ namespace eap
|
|||||||
///
|
///
|
||||||
/// \returns Generated pseudo-random data (\p size bytes)
|
/// \returns Generated pseudo-random data (\p size bytes)
|
||||||
///
|
///
|
||||||
sanitizing_blob prf(
|
static sanitizing_blob prf(
|
||||||
|
_In_ HCRYPTPROV cp,
|
||||||
|
_In_ ALG_ID alg,
|
||||||
_In_ const tls_master_secret &secret,
|
_In_ const tls_master_secret &secret,
|
||||||
_In_bytecount_(size_seed) const void *seed,
|
_In_bytecount_(size_seed) const void *seed,
|
||||||
_In_ size_t size_seed,
|
_In_ size_t size_seed,
|
||||||
_In_ size_t size) const;
|
_In_ size_t size);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// 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)
|
||||||
|
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 5. HMAC and the Pseudorandom Function)](https://tools.ietf.org/html/rfc5246#section-5)
|
||||||
|
///
|
||||||
|
/// \param[in] secret Hashing secret key
|
||||||
|
/// \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)
|
||||||
|
///
|
||||||
|
inline sanitizing_blob prf(
|
||||||
|
_In_ const tls_master_secret &secret,
|
||||||
|
_In_bytecount_(size_seed) const void *seed,
|
||||||
|
_In_ size_t size_seed,
|
||||||
|
_In_ size_t size) const
|
||||||
|
{
|
||||||
|
return prf(m_cp, m_state.m_alg_prf, secret, seed, size_seed, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// 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)
|
||||||
|
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 5. HMAC and the Pseudorandom Function)](https://tools.ietf.org/html/rfc5246#section-5)
|
||||||
|
///
|
||||||
|
/// \param[in] cp Handle of the cryptographics provider
|
||||||
|
/// \param[in] alg Hashing Algorithm to use (CALG_TLS1PRF = combination of MD5 and SHA-1, CALG_SHA_256...)
|
||||||
|
/// \param[in] secret Hashing secret key
|
||||||
|
/// \param[in] seed Random seed
|
||||||
|
/// \param[in] size Number of bytes of pseudo-random data required
|
||||||
|
///
|
||||||
|
/// \returns Generated pseudo-random data (\p size bytes)
|
||||||
|
///
|
||||||
|
template<class _Ty, class _Ax>
|
||||||
|
inline static sanitizing_blob prf(
|
||||||
|
_In_ HCRYPTPROV cp,
|
||||||
|
_In_ ALG_ID alg,
|
||||||
|
_In_ const tls_master_secret &secret,
|
||||||
|
_In_ const std::vector<_Ty, _Ax> &seed,
|
||||||
|
_In_ size_t size)
|
||||||
|
{
|
||||||
|
return prf(cp, alg, secret, seed.data(), seed.size() * sizeof(_Ty), size);
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Calculates pseudo-random P_hash data defined in RFC 5246
|
/// Calculates pseudo-random P_hash data defined in RFC 5246
|
||||||
@ -479,9 +531,9 @@ namespace eap
|
|||||||
inline sanitizing_blob prf(
|
inline sanitizing_blob prf(
|
||||||
_In_ const tls_master_secret &secret,
|
_In_ const tls_master_secret &secret,
|
||||||
_In_ const std::vector<_Ty, _Ax> &seed,
|
_In_ const std::vector<_Ty, _Ax> &seed,
|
||||||
_In_ size_t size) const
|
_In_ size_t size) const
|
||||||
{
|
{
|
||||||
return prf(secret, seed.data(), seed.size() * sizeof(_Ty), size);
|
return prf(m_cp, m_state.m_alg_prf, secret, seed.data(), seed.size() * sizeof(_Ty), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
@ -530,6 +582,7 @@ namespace eap
|
|||||||
|
|
||||||
winstd::crypt_hash m_hash_handshake_msgs_md5; ///< Running MD5 hash of handshake messages sent
|
winstd::crypt_hash m_hash_handshake_msgs_md5; ///< Running MD5 hash of handshake messages sent
|
||||||
winstd::crypt_hash m_hash_handshake_msgs_sha1; ///< Running SHA-1 hash of handshake messages sent
|
winstd::crypt_hash m_hash_handshake_msgs_sha1; ///< Running SHA-1 hash of handshake messages sent
|
||||||
|
winstd::crypt_hash m_hash_handshake_msgs_sha256; ///< Running SHA-256 hash of handshake messages sent
|
||||||
|
|
||||||
bool m_certificate_req; ///< Did server request client certificate?
|
bool m_certificate_req; ///< Did server request client certificate?
|
||||||
bool m_server_hello_done; ///< Is server hello done?
|
bool m_server_hello_done; ///< Is server hello done?
|
||||||
|
@ -107,7 +107,7 @@ eap::method_tls::method_tls(_In_ module &module, _In_ config_provider_list &cfg,
|
|||||||
#endif
|
#endif
|
||||||
method(module, cfg, cred)
|
method(module, cfg, cred)
|
||||||
{
|
{
|
||||||
m_tls_version = tls_version_1_1;
|
m_tls_version = tls_version_1_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -126,6 +126,7 @@ eap::method_tls::method_tls(_In_ const method_tls &other) :
|
|||||||
m_server_cert_chain(other.m_server_cert_chain),
|
m_server_cert_chain(other.m_server_cert_chain),
|
||||||
m_hash_handshake_msgs_md5(other.m_hash_handshake_msgs_md5),
|
m_hash_handshake_msgs_md5(other.m_hash_handshake_msgs_md5),
|
||||||
m_hash_handshake_msgs_sha1(other.m_hash_handshake_msgs_sha1),
|
m_hash_handshake_msgs_sha1(other.m_hash_handshake_msgs_sha1),
|
||||||
|
m_hash_handshake_msgs_sha256(other.m_hash_handshake_msgs_sha256),
|
||||||
m_certificate_req(other.m_certificate_req),
|
m_certificate_req(other.m_certificate_req),
|
||||||
m_server_hello_done(other.m_server_hello_done),
|
m_server_hello_done(other.m_server_hello_done),
|
||||||
m_cipher_spec(other.m_cipher_spec),
|
m_cipher_spec(other.m_cipher_spec),
|
||||||
@ -152,6 +153,7 @@ eap::method_tls::method_tls(_Inout_ method_tls &&other) :
|
|||||||
m_server_cert_chain(std::move(other.m_server_cert_chain)),
|
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_md5(std::move(other.m_hash_handshake_msgs_md5)),
|
||||||
m_hash_handshake_msgs_sha1(std::move(other.m_hash_handshake_msgs_sha1)),
|
m_hash_handshake_msgs_sha1(std::move(other.m_hash_handshake_msgs_sha1)),
|
||||||
|
m_hash_handshake_msgs_sha256(std::move(other.m_hash_handshake_msgs_sha256)),
|
||||||
m_certificate_req(std::move(other.m_certificate_req)),
|
m_certificate_req(std::move(other.m_certificate_req)),
|
||||||
m_server_hello_done(std::move(other.m_server_hello_done)),
|
m_server_hello_done(std::move(other.m_server_hello_done)),
|
||||||
m_cipher_spec(std::move(other.m_cipher_spec)),
|
m_cipher_spec(std::move(other.m_cipher_spec)),
|
||||||
@ -179,26 +181,27 @@ eap::method_tls& eap::method_tls::operator=(_In_ const method_tls &other)
|
|||||||
{
|
{
|
||||||
if (this != std::addressof(other)) {
|
if (this != std::addressof(other)) {
|
||||||
assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Copy method with same credentials only!
|
assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Copy method with same credentials only!
|
||||||
(method&)*this = other;
|
(method&)*this = other;
|
||||||
m_packet_req = other.m_packet_req;
|
m_packet_req = other.m_packet_req;
|
||||||
m_packet_res = other.m_packet_res;
|
m_packet_res = other.m_packet_res;
|
||||||
m_state = other.m_state;
|
m_state = other.m_state;
|
||||||
m_padding_hmac_client = other.m_padding_hmac_client;
|
m_padding_hmac_client = other.m_padding_hmac_client;
|
||||||
m_padding_hmac_server = other.m_padding_hmac_server;
|
m_padding_hmac_server = other.m_padding_hmac_server;
|
||||||
m_key_client = other.m_key_client;
|
m_key_client = other.m_key_client;
|
||||||
m_key_server = other.m_key_server;
|
m_key_server = other.m_key_server;
|
||||||
m_key_mppe_client = other.m_key_mppe_client;
|
m_key_mppe_client = other.m_key_mppe_client;
|
||||||
m_key_mppe_server = other.m_key_mppe_server;
|
m_key_mppe_server = other.m_key_mppe_server;
|
||||||
m_session_id = other.m_session_id;
|
m_session_id = other.m_session_id;
|
||||||
m_server_cert_chain = other.m_server_cert_chain;
|
m_server_cert_chain = other.m_server_cert_chain;
|
||||||
m_hash_handshake_msgs_md5 = other.m_hash_handshake_msgs_md5;
|
m_hash_handshake_msgs_md5 = other.m_hash_handshake_msgs_md5;
|
||||||
m_hash_handshake_msgs_sha1 = other.m_hash_handshake_msgs_sha1;
|
m_hash_handshake_msgs_sha1 = other.m_hash_handshake_msgs_sha1;
|
||||||
m_certificate_req = other.m_certificate_req;
|
m_hash_handshake_msgs_sha256 = other.m_hash_handshake_msgs_sha256;
|
||||||
m_server_hello_done = other.m_server_hello_done;
|
m_certificate_req = other.m_certificate_req;
|
||||||
m_cipher_spec = other.m_cipher_spec;
|
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_client = other.m_seq_num_client;
|
m_server_finished = other.m_server_finished;
|
||||||
m_seq_num_server = other.m_seq_num_server;
|
m_seq_num_client = other.m_seq_num_client;
|
||||||
|
m_seq_num_server = other.m_seq_num_server;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
@ -209,26 +212,27 @@ eap::method_tls& eap::method_tls::operator=(_Inout_ method_tls &&other)
|
|||||||
{
|
{
|
||||||
if (this != std::addressof(other)) {
|
if (this != std::addressof(other)) {
|
||||||
assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Move method with same credentials only!
|
assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Move method with same credentials only!
|
||||||
(method&)*this = std::move(other);
|
(method&)*this = std::move(other);
|
||||||
m_packet_req = std::move(other.m_packet_req);
|
m_packet_req = std::move(other.m_packet_req);
|
||||||
m_packet_res = std::move(other.m_packet_res);
|
m_packet_res = std::move(other.m_packet_res);
|
||||||
m_state = std::move(other.m_state);
|
m_state = std::move(other.m_state);
|
||||||
m_padding_hmac_client = std::move(other.m_padding_hmac_client);
|
m_padding_hmac_client = std::move(other.m_padding_hmac_client);
|
||||||
m_padding_hmac_server = std::move(other.m_padding_hmac_server);
|
m_padding_hmac_server = std::move(other.m_padding_hmac_server);
|
||||||
m_key_client = std::move(other.m_key_client);
|
m_key_client = std::move(other.m_key_client);
|
||||||
m_key_server = std::move(other.m_key_server);
|
m_key_server = std::move(other.m_key_server);
|
||||||
m_key_mppe_client = std::move(other.m_key_mppe_client);
|
m_key_mppe_client = std::move(other.m_key_mppe_client);
|
||||||
m_key_mppe_server = std::move(other.m_key_mppe_server);
|
m_key_mppe_server = std::move(other.m_key_mppe_server);
|
||||||
m_session_id = std::move(other.m_session_id);
|
m_session_id = std::move(other.m_session_id);
|
||||||
m_server_cert_chain = std::move(other.m_server_cert_chain);
|
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_md5 = std::move(other.m_hash_handshake_msgs_md5);
|
||||||
m_hash_handshake_msgs_sha1 = std::move(other.m_hash_handshake_msgs_sha1);
|
m_hash_handshake_msgs_sha1 = std::move(other.m_hash_handshake_msgs_sha1);
|
||||||
m_certificate_req = std::move(other.m_certificate_req);
|
m_hash_handshake_msgs_sha256 = std::move(other.m_hash_handshake_msgs_sha256);
|
||||||
m_server_hello_done = std::move(other.m_server_hello_done);
|
m_certificate_req = std::move(other.m_certificate_req);
|
||||||
m_cipher_spec = std::move(other.m_cipher_spec);
|
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_client = std::move(other.m_seq_num_client);
|
m_server_finished = std::move(other.m_server_finished);
|
||||||
m_seq_num_server = std::move(other.m_seq_num_server);
|
m_seq_num_client = std::move(other.m_seq_num_client);
|
||||||
|
m_seq_num_server = std::move(other.m_seq_num_server);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
@ -244,7 +248,7 @@ void eap::method_tls::begin_session(
|
|||||||
method::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
|
method::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
|
||||||
|
|
||||||
// Create cryptographics provider.
|
// Create cryptographics provider.
|
||||||
if (!m_cp.create(NULL, MS_ENHANCED_PROV, PROV_RSA_FULL))
|
if (!m_cp.create(NULL, NULL, PROV_RSA_AES))
|
||||||
throw win_runtime_error(__FUNCTION__ " Error creating cryptographics provider.");
|
throw win_runtime_error(__FUNCTION__ " Error creating cryptographics provider.");
|
||||||
|
|
||||||
if (m_cfg.m_providers.empty() || m_cfg.m_providers.front().m_methods.empty())
|
if (m_cfg.m_providers.empty() || m_cfg.m_providers.front().m_methods.empty())
|
||||||
@ -371,6 +375,9 @@ void eap::method_tls::process_request_packet(
|
|||||||
if (!m_hash_handshake_msgs_sha1.create(m_cp, CALG_SHA1))
|
if (!m_hash_handshake_msgs_sha1.create(m_cp, CALG_SHA1))
|
||||||
throw win_runtime_error(__FUNCTION__ " Error creating SHA-1 hashing object.");
|
throw win_runtime_error(__FUNCTION__ " Error creating SHA-1 hashing object.");
|
||||||
|
|
||||||
|
if (!m_hash_handshake_msgs_sha256.create(m_cp, CALG_SHA_256))
|
||||||
|
throw win_runtime_error(__FUNCTION__ " Error creating SHA-256 hashing object.");
|
||||||
|
|
||||||
m_certificate_req = false;
|
m_certificate_req = false;
|
||||||
m_server_hello_done = false;
|
m_server_hello_done = false;
|
||||||
m_cipher_spec = false;
|
m_cipher_spec = false;
|
||||||
@ -606,7 +613,7 @@ eap::sanitizing_blob eap::method_tls::make_client_hello() const
|
|||||||
1 + // Session ID size
|
1 + // Session ID size
|
||||||
m_session_id.size() + // Session ID
|
m_session_id.size() + // Session ID
|
||||||
2 + // Length of cypher suite list
|
2 + // Length of cypher suite list
|
||||||
2 + // Cyper suite list
|
4 + // Cyper suite list
|
||||||
1 + // Length of compression suite
|
1 + // Length of compression suite
|
||||||
1)); // Compression suite
|
1)); // Compression suite
|
||||||
|
|
||||||
@ -627,8 +634,10 @@ eap::sanitizing_blob eap::method_tls::make_client_hello() const
|
|||||||
msg.insert(msg.end(), m_session_id.begin(), m_session_id.end());
|
msg.insert(msg.end(), m_session_id.begin(), m_session_id.end());
|
||||||
|
|
||||||
// Cypher suite list
|
// Cypher suite list
|
||||||
msg.push_back(0x00); // Length of cypher suite is two (in network-byte-order).
|
msg.push_back(0x00); // Length of cypher suite is four bytes (in network-byte-order).
|
||||||
msg.push_back(0x02); // --^
|
msg.push_back(0x04); // --^
|
||||||
|
msg.push_back(0x00); // TLS_RSA_WITH_AES_128_CBC_SHA (0x00 0x2f)
|
||||||
|
msg.push_back(0x2f); // --^
|
||||||
msg.push_back(0x00); // TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x00 0x0a)
|
msg.push_back(0x00); // TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x00 0x0a)
|
||||||
msg.push_back(0x0a); // --^
|
msg.push_back(0x0a); // --^
|
||||||
|
|
||||||
@ -746,14 +755,21 @@ eap::sanitizing_blob eap::method_tls::make_finished() const
|
|||||||
crypt_hash hash;
|
crypt_hash hash;
|
||||||
static const unsigned char s_label[] = "client finished";
|
static const unsigned char s_label[] = "client finished";
|
||||||
sanitizing_blob seed(s_label, s_label + _countof(s_label) - 1), hash_data;
|
sanitizing_blob seed(s_label, s_label + _countof(s_label) - 1), hash_data;
|
||||||
hash = m_hash_handshake_msgs_md5; // duplicate
|
if (m_tls_version < tls_version_1_2) {
|
||||||
if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, 0))
|
hash = m_hash_handshake_msgs_md5; // duplicate
|
||||||
throw win_runtime_error(__FUNCTION__ " Error finishing MD5 hash calculation.");
|
if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, 0))
|
||||||
seed.insert(seed.end(), hash_data.begin(), hash_data.end());
|
throw win_runtime_error(__FUNCTION__ " Error finishing MD5 hash calculation.");
|
||||||
hash = m_hash_handshake_msgs_sha1; // duplicate
|
seed.insert(seed.end(), hash_data.begin(), hash_data.end());
|
||||||
if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, 0))
|
hash = m_hash_handshake_msgs_sha1; // duplicate
|
||||||
throw win_runtime_error(__FUNCTION__ " Error finishing SHA-1 hash calculation.");
|
if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, 0))
|
||||||
seed.insert(seed.end(), hash_data.begin(), hash_data.end());
|
throw win_runtime_error(__FUNCTION__ " Error finishing SHA-1 hash calculation.");
|
||||||
|
seed.insert(seed.end(), hash_data.begin(), hash_data.end());
|
||||||
|
} else {
|
||||||
|
hash = m_hash_handshake_msgs_sha256; // duplicate
|
||||||
|
if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, 0))
|
||||||
|
throw win_runtime_error(__FUNCTION__ " Error finishing SHA-256 hash calculation.");
|
||||||
|
seed.insert(seed.end(), hash_data.begin(), hash_data.end());
|
||||||
|
}
|
||||||
sanitizing_blob verify(prf(m_state.m_master_secret, seed, 12));
|
sanitizing_blob verify(prf(m_state.m_master_secret, seed, 12));
|
||||||
msg.insert(msg.end(), verify.begin(), verify.end());
|
msg.insert(msg.end(), verify.begin(), verify.end());
|
||||||
|
|
||||||
@ -763,31 +779,29 @@ eap::sanitizing_blob eap::method_tls::make_finished() const
|
|||||||
|
|
||||||
eap::sanitizing_blob eap::method_tls::make_message(_In_ tls_message_type_t type, _Inout_ sanitizing_blob &data, _In_ bool encrypt)
|
eap::sanitizing_blob eap::method_tls::make_message(_In_ tls_message_type_t type, _Inout_ sanitizing_blob &data, _In_ bool encrypt)
|
||||||
{
|
{
|
||||||
if (encrypt) {
|
if (encrypt)
|
||||||
encrypt_message(type, data);
|
encrypt_message(type, data);
|
||||||
return make_message(type, data, false);
|
|
||||||
} else {
|
|
||||||
size_t size_data = data.size();
|
|
||||||
assert(size_data <= 0xffff);
|
|
||||||
message_header hdr = {
|
|
||||||
type, // SSL record type
|
|
||||||
{
|
|
||||||
m_tls_version.major, // SSL major version
|
|
||||||
m_tls_version.minor, // SSL minor version
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// Data length (unencrypted, network byte order)
|
|
||||||
(unsigned char)((size_data >> 8) & 0xff),
|
|
||||||
(unsigned char)((size_data ) & 0xff),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
sanitizing_blob msg;
|
size_t size_data = data.size();
|
||||||
msg.reserve(sizeof(message_header) + size_data);
|
assert(size_data <= 0xffff);
|
||||||
msg.assign((const unsigned char*)&hdr, (const unsigned char*)(&hdr + 1));
|
message_header hdr = {
|
||||||
msg.insert(msg.end(), data.begin(), data.end());
|
type, // SSL record type
|
||||||
return msg;
|
{
|
||||||
}
|
m_tls_version.major, // SSL major version
|
||||||
|
m_tls_version.minor, // SSL minor version
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Data length (unencrypted, network byte order)
|
||||||
|
(unsigned char)((size_data >> 8) & 0xff),
|
||||||
|
(unsigned char)((size_data ) & 0xff),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
sanitizing_blob msg;
|
||||||
|
msg.reserve(sizeof(message_header) + size_data);
|
||||||
|
msg.assign((const unsigned char*)&hdr, (const unsigned char*)(&hdr + 1));
|
||||||
|
msg.insert(msg.end(), data.begin(), data.end());
|
||||||
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -983,7 +997,7 @@ void eap::method_tls::process_handshake(_In_bytecount_(msg_size) const void *_ms
|
|||||||
else if (*(tls_version*)rec < tls_version_1_0 || m_tls_version < *(tls_version*)rec)
|
else if (*(tls_version*)rec < tls_version_1_0 || m_tls_version < *(tls_version*)rec)
|
||||||
throw win_runtime_error(ERROR_NOT_SUPPORTED, __FUNCTION__ " Unsupported SSL/TLS version.");
|
throw win_runtime_error(ERROR_NOT_SUPPORTED, __FUNCTION__ " Unsupported SSL/TLS version.");
|
||||||
m_tls_version = *(tls_version*)rec;
|
m_tls_version = *(tls_version*)rec;
|
||||||
m_state.m_alg_prf = CALG_TLS1PRF;
|
m_state.m_alg_prf = m_tls_version < tls_version_1_2 ? CALG_TLS1PRF : CALG_SHA_256;
|
||||||
rec += 2;
|
rec += 2;
|
||||||
|
|
||||||
// Server random
|
// Server random
|
||||||
@ -1002,7 +1016,16 @@ void eap::method_tls::process_handshake(_In_bytecount_(msg_size) const void *_ms
|
|||||||
// Cipher
|
// Cipher
|
||||||
if (rec + 2 > rec_end)
|
if (rec + 2 > rec_end)
|
||||||
throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Cipher or incomplete.");
|
throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Cipher or incomplete.");
|
||||||
if (rec[0] == 0x00 || rec[1] == 0x0a) {
|
if (rec[0] == 0x00 || rec[1] == 0x2f) {
|
||||||
|
// TLS_RSA_WITH_AES_128_CBC_SHA
|
||||||
|
m_state.m_alg_encrypt = CALG_AES_128;
|
||||||
|
m_state.m_size_enc_key = 128/8; // AES-128
|
||||||
|
m_state.m_size_enc_iv = 128/8; // AES-128
|
||||||
|
m_state.m_size_enc_block = 128/8; // AES-128
|
||||||
|
m_state.m_alg_mac = CALG_SHA1;
|
||||||
|
m_state.m_size_mac_key = 160/8; // SHA-1
|
||||||
|
m_state.m_size_mac_hash = 160/8; // SHA-1
|
||||||
|
} else if (rec[0] == 0x00 || rec[1] == 0x0a) {
|
||||||
// TLS_RSA_WITH_3DES_EDE_CBC_SHA
|
// TLS_RSA_WITH_3DES_EDE_CBC_SHA
|
||||||
m_state.m_alg_encrypt = CALG_3DES;
|
m_state.m_alg_encrypt = CALG_3DES;
|
||||||
m_state.m_size_enc_key = 192/8; // 3DES 192bits
|
m_state.m_size_enc_key = 192/8; // 3DES 192bits
|
||||||
@ -1079,14 +1102,21 @@ void eap::method_tls::process_handshake(_In_bytecount_(msg_size) const void *_ms
|
|||||||
crypt_hash hash;
|
crypt_hash hash;
|
||||||
static const unsigned char s_label[] = "server finished";
|
static const unsigned char s_label[] = "server finished";
|
||||||
sanitizing_blob seed(s_label, s_label + _countof(s_label) - 1), hash_data;
|
sanitizing_blob seed(s_label, s_label + _countof(s_label) - 1), hash_data;
|
||||||
hash = m_hash_handshake_msgs_md5; // duplicate
|
if (m_tls_version < tls_version_1_2) {
|
||||||
if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, 0))
|
hash = m_hash_handshake_msgs_md5; // duplicate
|
||||||
throw win_runtime_error(__FUNCTION__ " Error finishing MD5 hash calculation.");
|
if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, 0))
|
||||||
seed.insert(seed.end(), hash_data.begin(), hash_data.end());
|
throw win_runtime_error(__FUNCTION__ " Error finishing MD5 hash calculation.");
|
||||||
hash = m_hash_handshake_msgs_sha1; // duplicate
|
seed.insert(seed.end(), hash_data.begin(), hash_data.end());
|
||||||
if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, 0))
|
hash = m_hash_handshake_msgs_sha1; // duplicate
|
||||||
throw win_runtime_error(__FUNCTION__ " Error finishing SHA-1 hash calculation.");
|
if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, 0))
|
||||||
seed.insert(seed.end(), hash_data.begin(), hash_data.end());
|
throw win_runtime_error(__FUNCTION__ " Error finishing SHA-1 hash calculation.");
|
||||||
|
seed.insert(seed.end(), hash_data.begin(), hash_data.end());
|
||||||
|
} else {
|
||||||
|
hash = m_hash_handshake_msgs_sha256; // duplicate
|
||||||
|
if (!CryptGetHashParam(hash, HP_HASHVAL, hash_data, 0))
|
||||||
|
throw win_runtime_error(__FUNCTION__ " Error finishing SHA-256 hash calculation.");
|
||||||
|
seed.insert(seed.end(), hash_data.begin(), hash_data.end());
|
||||||
|
}
|
||||||
|
|
||||||
if (memcmp(prf(m_state.m_master_secret, seed, 12).data(), rec, 12))
|
if (memcmp(prf(m_state.m_master_secret, seed, 12).data(), rec, 12))
|
||||||
throw win_runtime_error(ERROR_ENCRYPTION_FAILED, __FUNCTION__ " Integrity check failed.");
|
throw win_runtime_error(ERROR_ENCRYPTION_FAILED, __FUNCTION__ " Integrity check failed.");
|
||||||
@ -1344,15 +1374,17 @@ void eap::method_tls::decrypt_message(_In_ tls_message_type_t type, _Inout_ sani
|
|||||||
|
|
||||||
|
|
||||||
eap::sanitizing_blob eap::method_tls::prf(
|
eap::sanitizing_blob eap::method_tls::prf(
|
||||||
|
_In_ HCRYPTPROV cp,
|
||||||
|
_In_ ALG_ID alg,
|
||||||
_In_ const tls_master_secret &secret,
|
_In_ const tls_master_secret &secret,
|
||||||
_In_bytecount_(size_seed) const void *seed,
|
_In_bytecount_(size_seed) const void *seed,
|
||||||
_In_ size_t size_seed,
|
_In_ size_t size_seed,
|
||||||
_In_ size_t size) const
|
_In_ size_t size)
|
||||||
{
|
{
|
||||||
sanitizing_blob data;
|
sanitizing_blob data;
|
||||||
data.reserve(size);
|
data.reserve(size);
|
||||||
|
|
||||||
if (m_state.m_alg_prf == CALG_TLS1PRF) {
|
if (alg == CALG_TLS1PRF) {
|
||||||
// Split secret in two halves.
|
// Split secret in two halves.
|
||||||
size_t
|
size_t
|
||||||
size_S1 = (sizeof(tls_master_secret) + 1) / 2,
|
size_S1 = (sizeof(tls_master_secret) + 1) / 2,
|
||||||
@ -1365,8 +1397,8 @@ eap::sanitizing_blob eap::method_tls::prf(
|
|||||||
sanitizing_blob
|
sanitizing_blob
|
||||||
hmac_padding1(sizeof(hash_hmac::padding_t)),
|
hmac_padding1(sizeof(hash_hmac::padding_t)),
|
||||||
hmac_padding2(sizeof(hash_hmac::padding_t));
|
hmac_padding2(sizeof(hash_hmac::padding_t));
|
||||||
hash_hmac::inner_padding(m_cp, CALG_MD5 , S1, size_S1, hmac_padding1.data());
|
hash_hmac::inner_padding(cp, CALG_MD5 , S1, size_S1, hmac_padding1.data());
|
||||||
hash_hmac::inner_padding(m_cp, CALG_SHA1, S2, size_S2, hmac_padding2.data());
|
hash_hmac::inner_padding(cp, CALG_SHA1, S2, size_S2, hmac_padding2.data());
|
||||||
|
|
||||||
// Prepare A for p_hash.
|
// Prepare A for p_hash.
|
||||||
sanitizing_blob
|
sanitizing_blob
|
||||||
@ -1380,13 +1412,13 @@ eap::sanitizing_blob eap::method_tls::prf(
|
|||||||
for (size_t i = 0, off1 = 0, off2 = 0; i < size; ) {
|
for (size_t i = 0, off1 = 0, off2 = 0; i < size; ) {
|
||||||
if (off1 >= hmac1.size()) {
|
if (off1 >= hmac1.size()) {
|
||||||
// Rehash A.
|
// Rehash A.
|
||||||
hash_hmac hash1(m_cp, CALG_MD5 , hmac_padding1.data());
|
hash_hmac hash1(cp, CALG_MD5 , hmac_padding1.data());
|
||||||
if (!CryptHashData(hash1, A1.data(), (DWORD)A1.size(), 0))
|
if (!CryptHashData(hash1, A1.data(), (DWORD)A1.size(), 0))
|
||||||
throw win_runtime_error(__FUNCTION__ " Error hashing A1.");
|
throw win_runtime_error(__FUNCTION__ " Error hashing A1.");
|
||||||
hash1.calculate(A1);
|
hash1.calculate(A1);
|
||||||
|
|
||||||
// Hash A and seed.
|
// Hash A and seed.
|
||||||
hash_hmac hash2(m_cp, CALG_MD5 , hmac_padding1.data());
|
hash_hmac hash2(cp, CALG_MD5 , hmac_padding1.data());
|
||||||
if (!CryptHashData(hash2, A1.data(), (DWORD)A1.size(), 0) ||
|
if (!CryptHashData(hash2, A1.data(), (DWORD)A1.size(), 0) ||
|
||||||
!CryptHashData(hash2, (const BYTE*)seed , (DWORD)size_seed, 0))
|
!CryptHashData(hash2, (const BYTE*)seed , (DWORD)size_seed, 0))
|
||||||
throw win_runtime_error(__FUNCTION__ " Error hashing seed,label or data.");
|
throw win_runtime_error(__FUNCTION__ " Error hashing seed,label or data.");
|
||||||
@ -1396,13 +1428,13 @@ eap::sanitizing_blob eap::method_tls::prf(
|
|||||||
|
|
||||||
if (off2 >= hmac2.size()) {
|
if (off2 >= hmac2.size()) {
|
||||||
// Rehash A.
|
// Rehash A.
|
||||||
hash_hmac hash1(m_cp, CALG_SHA1 , hmac_padding2.data());
|
hash_hmac hash1(cp, CALG_SHA1 , hmac_padding2.data());
|
||||||
if (!CryptHashData(hash1, A2.data(), (DWORD)A2.size(), 0))
|
if (!CryptHashData(hash1, A2.data(), (DWORD)A2.size(), 0))
|
||||||
throw win_runtime_error(__FUNCTION__ " Error hashing A2.");
|
throw win_runtime_error(__FUNCTION__ " Error hashing A2.");
|
||||||
hash1.calculate(A2);
|
hash1.calculate(A2);
|
||||||
|
|
||||||
// Hash A and seed.
|
// Hash A and seed.
|
||||||
hash_hmac hash2(m_cp, CALG_SHA1 , hmac_padding2.data());
|
hash_hmac hash2(cp, CALG_SHA1 , hmac_padding2.data());
|
||||||
if (!CryptHashData(hash2, A2.data(), (DWORD)A2.size(), 0) ||
|
if (!CryptHashData(hash2, A2.data(), (DWORD)A2.size(), 0) ||
|
||||||
!CryptHashData(hash2, (const BYTE*)seed , (DWORD)size_seed, 0))
|
!CryptHashData(hash2, (const BYTE*)seed , (DWORD)size_seed, 0))
|
||||||
throw win_runtime_error(__FUNCTION__ " Error hashing seed,label or data.");
|
throw win_runtime_error(__FUNCTION__ " Error hashing seed,label or data.");
|
||||||
@ -1418,7 +1450,7 @@ eap::sanitizing_blob eap::method_tls::prf(
|
|||||||
} else {
|
} else {
|
||||||
// Precalculate HMAC padding for speed.
|
// Precalculate HMAC padding for speed.
|
||||||
sanitizing_blob hmac_padding(sizeof(hash_hmac::padding_t));
|
sanitizing_blob hmac_padding(sizeof(hash_hmac::padding_t));
|
||||||
hash_hmac::inner_padding(m_cp, m_state.m_alg_prf, &secret, sizeof(tls_master_secret), hmac_padding.data());
|
hash_hmac::inner_padding(cp, alg, &secret, sizeof(tls_master_secret), hmac_padding.data());
|
||||||
|
|
||||||
// Prepare A for p_hash.
|
// Prepare A for p_hash.
|
||||||
sanitizing_blob A((unsigned char*)seed, (unsigned char*)seed + size_seed);
|
sanitizing_blob A((unsigned char*)seed, (unsigned char*)seed + size_seed);
|
||||||
@ -1426,13 +1458,13 @@ eap::sanitizing_blob eap::method_tls::prf(
|
|||||||
sanitizing_blob hmac;
|
sanitizing_blob hmac;
|
||||||
for (size_t i = 0; i < size; ) {
|
for (size_t i = 0; i < size; ) {
|
||||||
// Rehash A.
|
// Rehash A.
|
||||||
hash_hmac hash1(m_cp, m_state.m_alg_prf, hmac_padding.data());
|
hash_hmac hash1(cp, alg, hmac_padding.data());
|
||||||
if (!CryptHashData(hash1, A.data(), (DWORD)A.size(), 0))
|
if (!CryptHashData(hash1, A.data(), (DWORD)A.size(), 0))
|
||||||
throw win_runtime_error(__FUNCTION__ " Error hashing A.");
|
throw win_runtime_error(__FUNCTION__ " Error hashing A.");
|
||||||
hash1.calculate(A);
|
hash1.calculate(A);
|
||||||
|
|
||||||
// Hash A and seed.
|
// Hash A and seed.
|
||||||
hash_hmac hash2(m_cp, m_state.m_alg_prf, hmac_padding.data());
|
hash_hmac hash2(cp, alg, hmac_padding.data());
|
||||||
if (!CryptHashData(hash2, A.data(), (DWORD)A.size() , 0) ||
|
if (!CryptHashData(hash2, A.data(), (DWORD)A.size() , 0) ||
|
||||||
!CryptHashData(hash2, (const BYTE*)seed , (DWORD)size_seed, 0))
|
!CryptHashData(hash2, (const BYTE*)seed , (DWORD)size_seed, 0))
|
||||||
throw win_runtime_error(__FUNCTION__ " Error hashing seed,label or data.");
|
throw win_runtime_error(__FUNCTION__ " Error hashing seed,label or data.");
|
||||||
@ -1454,6 +1486,34 @@ HCRYPTKEY eap::method_tls::create_key(
|
|||||||
_In_bytecount_(size_secret) const void *secret,
|
_In_bytecount_(size_secret) const void *secret,
|
||||||
_In_ size_t size_secret)
|
_In_ size_t size_secret)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
|
UNREFERENCED_PARAMETER(key);
|
||||||
|
assert(size_secret <= 0xffffffff);
|
||||||
|
|
||||||
|
// Prepare exported key BLOB.
|
||||||
|
struct key_blob_prefix {
|
||||||
|
PUBLICKEYSTRUC header;
|
||||||
|
DWORD size;
|
||||||
|
} const prefix = {
|
||||||
|
{
|
||||||
|
PLAINTEXTKEYBLOB,
|
||||||
|
CUR_BLOB_VERSION,
|
||||||
|
0,
|
||||||
|
alg,
|
||||||
|
},
|
||||||
|
(DWORD)size_secret,
|
||||||
|
};
|
||||||
|
sanitizing_blob key_blob;
|
||||||
|
key_blob.reserve(sizeof(key_blob_prefix) + size_secret);
|
||||||
|
key_blob.assign((const unsigned char*)&prefix, (const unsigned char*)(&prefix + 1));
|
||||||
|
key_blob.insert(key_blob.end(), (const unsigned char*)secret, (const unsigned char*)secret + size_secret);
|
||||||
|
|
||||||
|
// Import the key.
|
||||||
|
winstd::crypt_key key_out;
|
||||||
|
if (!key_out.import(m_cp, key_blob.data(), (DWORD)key_blob.size(), NULL, 0))
|
||||||
|
throw winstd::win_runtime_error(__FUNCTION__ " Error importing key.");
|
||||||
|
return key_out.detach();
|
||||||
|
#else
|
||||||
if (size_secret > m_state.m_size_enc_key)
|
if (size_secret > m_state.m_size_enc_key)
|
||||||
throw invalid_argument(__FUNCTION__ " Secret too big to fit the key.");
|
throw invalid_argument(__FUNCTION__ " Secret too big to fit the key.");
|
||||||
|
|
||||||
@ -1518,4 +1578,5 @@ HCRYPTKEY eap::method_tls::create_key(
|
|||||||
if (!key_out.import(m_cp, key_blob.data(), (DWORD)key_blob.size(), key, 0))
|
if (!key_out.import(m_cp, key_blob.data(), (DWORD)key_blob.size(), key, 0))
|
||||||
throw winstd::win_runtime_error(__FUNCTION__ " Error importing key.");
|
throw winstd::win_runtime_error(__FUNCTION__ " Error importing key.");
|
||||||
return key_out.detach();
|
return key_out.detach();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -155,11 +155,26 @@ void eap::method_ttls::get_result(
|
|||||||
|
|
||||||
void eap::method_ttls::derive_msk()
|
void eap::method_ttls::derive_msk()
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
// TLS versions 1.0 [RFC2246] and 1.1 [RFC4346] define the same PRF
|
||||||
|
// function, and any EAP-TTLSv0 implementation based on these versions
|
||||||
|
// of TLS must use the PRF defined therein. It is expected that future
|
||||||
|
// versions of or extensions to the TLS protocol will permit alternative
|
||||||
|
// PRF functions to be negotiated. If an alternative PRF function is
|
||||||
|
// specified for the underlying TLS version or has been negotiated
|
||||||
|
// during the TLS handshake negotiation, then that alternative PRF
|
||||||
|
// function must be used in EAP-TTLSv0 computations instead of the TLS
|
||||||
|
// 1.0/1.1 PRF.
|
||||||
|
//
|
||||||
|
// [Extensible Authentication Protocol Tunneled Transport Layer Security Authenticated Protocol Version 0 (EAP-TTLSv0) (Chapter 7.8. Use of TLS PRF)](https://tools.ietf.org/html/rfc5281#section-7.8)
|
||||||
|
//
|
||||||
|
// If we use PRF_SHA256() the key exchange fails. Therefore we use PRF of TLS 1.0/1.1.
|
||||||
|
//
|
||||||
static const unsigned char s_label[] = "ttls keying material";
|
static const unsigned char s_label[] = "ttls keying material";
|
||||||
sanitizing_blob seed(s_label, s_label + _countof(s_label) - 1);
|
sanitizing_blob seed(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_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));
|
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, seed, 2*sizeof(tls_random)));
|
sanitizing_blob key_block(prf(m_cp, CALG_TLS1PRF, m_state.m_master_secret, seed, 2*sizeof(tls_random)));
|
||||||
const unsigned char *_key_block = key_block.data();
|
const unsigned char *_key_block = key_block.data();
|
||||||
|
|
||||||
// MSK: MPPE-Recv-Key
|
// MSK: MPPE-Recv-Key
|
||||||
|
@ -122,7 +122,7 @@ void eap::peer_ttls::get_identity(
|
|||||||
if (*pfInvokeUI) {
|
if (*pfInvokeUI) {
|
||||||
if ((dwFlags & EAP_FLAG_MACHINE_AUTH) == 0) {
|
if ((dwFlags & EAP_FLAG_MACHINE_AUTH) == 0) {
|
||||||
// Per-user authentication
|
// Per-user authentication
|
||||||
log_event(&EAPMETHOD_TRACE_EVT_CRED_INVOKE_UI2);
|
log_event(&EAPMETHOD_TRACE_EVT_CRED_INVOKE_UI2, event_data::blank);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Per-machine authentication
|
// Per-machine authentication
|
||||||
|
Loading…
x
Reference in New Issue
Block a user