Support for TLS 1.2 added

This commit is contained in:
Simon Rozman 2016-08-16 00:47:47 +02:00
parent d68fd6ce08
commit 85d7c3d4ec
4 changed files with 234 additions and 105 deletions

View File

@ -297,8 +297,9 @@ namespace eap
///
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_sha1, (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_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.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_seed \p seed size
@ -457,11 +460,60 @@ namespace eap
///
/// \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_bytecount_(size_seed) const void *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
@ -479,9 +531,9 @@ namespace eap
inline sanitizing_blob prf(
_In_ const tls_master_secret &secret,
_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_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_server_hello_done; ///< Is server hello done?

View File

@ -107,7 +107,7 @@ eap::method_tls::method_tls(_In_ module &module, _In_ config_provider_list &cfg,
#endif
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_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_sha256(other.m_hash_handshake_msgs_sha256),
m_certificate_req(other.m_certificate_req),
m_server_hello_done(other.m_server_hello_done),
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_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_sha256(std::move(other.m_hash_handshake_msgs_sha256)),
m_certificate_req(std::move(other.m_certificate_req)),
m_server_hello_done(std::move(other.m_server_hello_done)),
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)) {
assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Copy method with same credentials only!
(method&)*this = 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_client = other.m_key_mppe_client;
m_key_mppe_server = other.m_key_mppe_server;
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_certificate_req = other.m_certificate_req;
m_server_hello_done = other.m_server_hello_done;
m_cipher_spec = other.m_cipher_spec;
m_server_finished = other.m_server_finished;
m_seq_num_client = other.m_seq_num_client;
m_seq_num_server = other.m_seq_num_server;
(method&)*this = 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_client = other.m_key_mppe_client;
m_key_mppe_server = other.m_key_mppe_server;
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_hash_handshake_msgs_sha256 = other.m_hash_handshake_msgs_sha256;
m_certificate_req = other.m_certificate_req;
m_server_hello_done = other.m_server_hello_done;
m_cipher_spec = other.m_cipher_spec;
m_server_finished = other.m_server_finished;
m_seq_num_client = other.m_seq_num_client;
m_seq_num_server = other.m_seq_num_server;
}
return *this;
@ -209,26 +212,27 @@ eap::method_tls& eap::method_tls::operator=(_Inout_ method_tls &&other)
{
if (this != std::addressof(other)) {
assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Move method with same credentials only!
(method&)*this = std::move(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_client = std::move(other.m_key_mppe_client);
m_key_mppe_server = std::move(other.m_key_mppe_server);
m_session_id = std::move(other.m_session_id);
m_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_certificate_req = std::move(other.m_certificate_req);
m_server_hello_done = std::move(other.m_server_hello_done);
m_cipher_spec = std::move(other.m_cipher_spec);
m_server_finished = std::move(other.m_server_finished);
m_seq_num_client = std::move(other.m_seq_num_client);
m_seq_num_server = std::move(other.m_seq_num_server);
(method&)*this = std::move(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_client = std::move(other.m_key_mppe_client);
m_key_mppe_server = std::move(other.m_key_mppe_server);
m_session_id = std::move(other.m_session_id);
m_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_hash_handshake_msgs_sha256 = std::move(other.m_hash_handshake_msgs_sha256);
m_certificate_req = std::move(other.m_certificate_req);
m_server_hello_done = std::move(other.m_server_hello_done);
m_cipher_spec = std::move(other.m_cipher_spec);
m_server_finished = std::move(other.m_server_finished);
m_seq_num_client = std::move(other.m_seq_num_client);
m_seq_num_server = std::move(other.m_seq_num_server);
}
return *this;
@ -244,7 +248,7 @@ void eap::method_tls::begin_session(
method::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
// 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.");
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))
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_server_hello_done = false;
m_cipher_spec = false;
@ -606,7 +613,7 @@ eap::sanitizing_blob eap::method_tls::make_client_hello() const
1 + // Session ID size
m_session_id.size() + // Session ID
2 + // Length of cypher suite list
2 + // Cyper suite list
4 + // Cyper suite list
1 + // Length of 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());
// Cypher suite list
msg.push_back(0x00); // Length of cypher suite is two (in network-byte-order).
msg.push_back(0x02); // --^
msg.push_back(0x00); // Length of cypher suite is four bytes (in network-byte-order).
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(0x0a); // --^
@ -746,14 +755,21 @@ eap::sanitizing_blob eap::method_tls::make_finished() const
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.");
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.");
seed.insert(seed.end(), hash_data.begin(), hash_data.end());
if (m_tls_version < tls_version_1_2) {
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.");
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.");
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));
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)
{
if (encrypt) {
if (encrypt)
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;
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;
}
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;
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)
throw win_runtime_error(ERROR_NOT_SUPPORTED, __FUNCTION__ " Unsupported SSL/TLS version.");
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;
// Server random
@ -1002,7 +1016,16 @@ 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) {
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
m_state.m_alg_encrypt = CALG_3DES;
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;
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.");
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.");
seed.insert(seed.end(), hash_data.begin(), hash_data.end());
if (m_tls_version < tls_version_1_2) {
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.");
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.");
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))
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(
_In_ HCRYPTPROV cp,
_In_ ALG_ID alg,
_In_ const tls_master_secret &secret,
_In_bytecount_(size_seed) const void *seed,
_In_ size_t size_seed,
_In_ size_t size) const
_In_ size_t size)
{
sanitizing_blob data;
data.reserve(size);
if (m_state.m_alg_prf == CALG_TLS1PRF) {
if (alg == CALG_TLS1PRF) {
// Split secret in two halves.
size_t
size_S1 = (sizeof(tls_master_secret) + 1) / 2,
@ -1365,8 +1397,8 @@ eap::sanitizing_blob eap::method_tls::prf(
sanitizing_blob
hmac_padding1(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(m_cp, CALG_SHA1, S2, size_S2, hmac_padding2.data());
hash_hmac::inner_padding(cp, CALG_MD5 , S1, size_S1, hmac_padding1.data());
hash_hmac::inner_padding(cp, CALG_SHA1, S2, size_S2, hmac_padding2.data());
// Prepare A for p_hash.
sanitizing_blob
@ -1380,13 +1412,13 @@ eap::sanitizing_blob eap::method_tls::prf(
for (size_t i = 0, off1 = 0, off2 = 0; i < size; ) {
if (off1 >= hmac1.size()) {
// 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))
throw win_runtime_error(__FUNCTION__ " Error hashing A1.");
hash1.calculate(A1);
// 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) ||
!CryptHashData(hash2, (const BYTE*)seed , (DWORD)size_seed, 0))
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()) {
// 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))
throw win_runtime_error(__FUNCTION__ " Error hashing A2.");
hash1.calculate(A2);
// 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) ||
!CryptHashData(hash2, (const BYTE*)seed , (DWORD)size_seed, 0))
throw win_runtime_error(__FUNCTION__ " Error hashing seed,label or data.");
@ -1418,7 +1450,7 @@ eap::sanitizing_blob eap::method_tls::prf(
} else {
// Precalculate HMAC padding for speed.
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.
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;
for (size_t i = 0; i < size; ) {
// 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))
throw win_runtime_error(__FUNCTION__ " Error hashing A.");
hash1.calculate(A);
// 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) ||
!CryptHashData(hash2, (const BYTE*)seed , (DWORD)size_seed, 0))
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_ 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)
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))
throw winstd::win_runtime_error(__FUNCTION__ " Error importing key.");
return key_out.detach();
#endif
}

View File

@ -155,11 +155,26 @@ void eap::method_ttls::get_result(
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";
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_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();
// MSK: MPPE-Recv-Key

View File

@ -122,7 +122,7 @@ void eap::peer_ttls::get_identity(
if (*pfInvokeUI) {
if ((dwFlags & EAP_FLAG_MACHINE_AUTH) == 0) {
// Per-user authentication
log_event(&EAPMETHOD_TRACE_EVT_CRED_INVOKE_UI2);
log_event(&EAPMETHOD_TRACE_EVT_CRED_INVOKE_UI2, event_data::blank);
return;
} else {
// Per-machine authentication