Session key importing honours MSDN recommendation about exponent-one key usage
This commit is contained in:
parent
d1925a0704
commit
47653492a2
@ -443,43 +443,20 @@ namespace eap
|
|||||||
///
|
///
|
||||||
/// Creates a key
|
/// Creates a key
|
||||||
///
|
///
|
||||||
|
/// \sa [How to export and import plain text session keys by using CryptoAPI](https://support.microsoft.com/en-us/kb/228786)
|
||||||
|
///
|
||||||
/// \param[in] alg Key algorithm
|
/// \param[in] alg Key algorithm
|
||||||
/// \param[in] secret Raw key data
|
/// \param[in] key Key that decrypts \p secret
|
||||||
|
/// \param[in] secret Key data
|
||||||
/// \param[in] size_secret \p secret size
|
/// \param[in] size_secret \p secret size
|
||||||
///
|
///
|
||||||
/// \returns Key
|
/// \returns Key
|
||||||
///
|
///
|
||||||
inline HCRYPTKEY create_key(
|
HCRYPTKEY create_key(
|
||||||
_In_ ALG_ID alg,
|
_In_ ALG_ID alg,
|
||||||
|
_In_ HCRYPTKEY 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);
|
||||||
{
|
|
||||||
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;
|
|
||||||
if (!key.import(m_cp, key_blob.data(), (DWORD)key_blob.size(), NULL, 0))
|
|
||||||
throw winstd::win_runtime_error(__FUNCTION__ " Error importing key.");
|
|
||||||
return key.detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
config_method_tls &m_cfg; ///< EAP-TLS method configuration
|
config_method_tls &m_cfg; ///< EAP-TLS method configuration
|
||||||
|
@ -811,9 +811,8 @@ eap::sanitizing_blob eap::method_tls::make_message(_In_ tls_message_type_t type,
|
|||||||
|
|
||||||
void eap::method_tls::derive_keys()
|
void eap::method_tls::derive_keys()
|
||||||
{
|
{
|
||||||
sanitizing_blob seed;
|
|
||||||
static const unsigned char s_label[] = "key expansion";
|
static const unsigned char s_label[] = "key expansion";
|
||||||
seed.assign(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_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));
|
||||||
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));
|
||||||
|
|
||||||
@ -833,12 +832,18 @@ void eap::method_tls::derive_keys()
|
|||||||
//hash_hmac::inner_padding(m_cp, m_state.m_alg_mac, _key_block, m_state.m_size_mac_key, m_padding_hmac_server.data());
|
//hash_hmac::inner_padding(m_cp, m_state.m_alg_mac, _key_block, m_state.m_size_mac_key, m_padding_hmac_server.data());
|
||||||
_key_block += m_state.m_size_mac_key;
|
_key_block += m_state.m_size_mac_key;
|
||||||
|
|
||||||
|
// Microsoft CryptoAPI does not support importing clear text session keys.
|
||||||
|
// Therefore, we trick it to say the session key is "encrypted" with an exponent-of-one key.
|
||||||
|
crypt_key key_exp1;
|
||||||
|
if (!key_exp1.create_exp1(m_cp, AT_KEYEXCHANGE))
|
||||||
|
throw win_runtime_error(__FUNCTION__ " Error creating exponent-of-one key.");
|
||||||
|
|
||||||
// client_write_key
|
// client_write_key
|
||||||
m_key_client = create_key(m_state.m_alg_encrypt, _key_block, m_state.m_size_enc_key);
|
m_key_client = create_key(m_state.m_alg_encrypt, key_exp1, _key_block, m_state.m_size_enc_key);
|
||||||
_key_block += m_state.m_size_enc_key;
|
_key_block += m_state.m_size_enc_key;
|
||||||
|
|
||||||
// server_write_key
|
// server_write_key
|
||||||
m_key_server = create_key(m_state.m_alg_encrypt, _key_block, m_state.m_size_enc_key);
|
m_key_server = create_key(m_state.m_alg_encrypt, key_exp1, _key_block, m_state.m_size_enc_key);
|
||||||
_key_block += m_state.m_size_enc_key;
|
_key_block += m_state.m_size_enc_key;
|
||||||
|
|
||||||
// client_write_IV
|
// client_write_IV
|
||||||
@ -855,9 +860,8 @@ void eap::method_tls::derive_keys()
|
|||||||
|
|
||||||
void eap::method_tls::derive_msk()
|
void eap::method_tls::derive_msk()
|
||||||
{
|
{
|
||||||
sanitizing_blob seed;
|
|
||||||
static const unsigned char s_label[] = "client EAP encryption";
|
static const unsigned char s_label[] = "client EAP encryption";
|
||||||
seed.assign(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_state.m_master_secret, seed, 2*sizeof(tls_random)));
|
||||||
@ -1388,3 +1392,71 @@ eap::sanitizing_blob eap::method_tls::prf(
|
|||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HCRYPTKEY eap::method_tls::create_key(
|
||||||
|
_In_ ALG_ID alg,
|
||||||
|
_In_ HCRYPTKEY key,
|
||||||
|
_In_bytecount_(size_secret) const void *secret,
|
||||||
|
_In_ size_t size_secret)
|
||||||
|
{
|
||||||
|
if (size_secret > m_state.m_size_enc_key)
|
||||||
|
throw invalid_argument(__FUNCTION__ " Secret too big to fit the key.");
|
||||||
|
|
||||||
|
// Get private key's algorithm.
|
||||||
|
ALG_ID alg_key;
|
||||||
|
if (!CryptGetKeyParam(key, KP_ALGID, alg_key, 0))
|
||||||
|
throw win_runtime_error(__FUNCTION__ " Error getting key's algorithm.'");
|
||||||
|
|
||||||
|
// Get private key's length in bytes.
|
||||||
|
DWORD size_key = CryptGetKeyParam(key, KP_KEYLEN, size_key, 0) ? size_key/8 : 0;
|
||||||
|
|
||||||
|
// SIMPLEBLOB Format is documented in SDK
|
||||||
|
// Copy header to buffer
|
||||||
|
#pragma pack(push)
|
||||||
|
#pragma pack(1)
|
||||||
|
struct key_blob_prefix {
|
||||||
|
PUBLICKEYSTRUC header;
|
||||||
|
ALG_ID alg;
|
||||||
|
} const prefix = {
|
||||||
|
{
|
||||||
|
SIMPLEBLOB,
|
||||||
|
CUR_BLOB_VERSION,
|
||||||
|
0,
|
||||||
|
alg,
|
||||||
|
},
|
||||||
|
alg_key,
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
sanitizing_blob key_blob;
|
||||||
|
key_blob.reserve(sizeof(key_blob_prefix) + size_key);
|
||||||
|
key_blob.assign((const unsigned char*)&prefix, (const unsigned char*)(&prefix + 1));
|
||||||
|
|
||||||
|
// Key in EME-PKCS1-v1_5 (RFC 3447).
|
||||||
|
key_blob.push_back(0); // Initial zero
|
||||||
|
key_blob.push_back(2); // PKCS #1 block type = 2
|
||||||
|
|
||||||
|
// PS
|
||||||
|
size_t size_ps = size_key - size_secret - 3;
|
||||||
|
assert(size_ps >= 8);
|
||||||
|
key_blob.insert(key_blob.end(), size_ps, 0);
|
||||||
|
unsigned char *ps = &*(key_blob.end() - size_ps);
|
||||||
|
CryptGenRandom(m_cp, (DWORD)size_ps, ps);
|
||||||
|
for (size_t i = 0; i < size_ps; i++)
|
||||||
|
if (ps[i] == 0) ps[i] = 1;
|
||||||
|
|
||||||
|
key_blob.push_back(0); // PS and M zero delimiter
|
||||||
|
|
||||||
|
// M
|
||||||
|
key_blob.insert(key_blob.end(), (const unsigned char*)secret, (const unsigned char*)secret + size_secret);
|
||||||
|
|
||||||
|
#ifdef _HOST_LOW_ENDIAN
|
||||||
|
std::reverse(key_blob.end() - size_key, key_blob.end());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Import the key.
|
||||||
|
winstd::crypt_key key_out;
|
||||||
|
if (!key_out.import(m_cp, key_blob.data(), (DWORD)key_blob.size(), key, CRYPT_NO_SALT))
|
||||||
|
throw winstd::win_runtime_error(__FUNCTION__ " Error importing key.");
|
||||||
|
return key_out.detach();
|
||||||
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 84e544c2f6dbf14f76b930b2672c3cc2b77bfc3f
|
Subproject commit 25c886754dafdf0d7fef2dc9d28f5328d2bf7ddd
|
Loading…
x
Reference in New Issue
Block a user