mirror of https://github.com/FreeRDP/FreeRDP
[core] refactor certificate handling
* Remove duplications in rdpRsaKey, reuse rdpCertificate for public components * Move all private key and certificate code to certificate.c, remove the tssk_* variables from gcc * Handle update of client and server random keys in wrapping functions * Simplify gcc_write_server_security_data, use certificate.c functions to write the certificate data * Refactor security_establish_keys, use the random values stored in settings directly
This commit is contained in:
parent
2f05166fb1
commit
2c2e9602b3
|
@ -91,11 +91,6 @@ extern "C"
|
|||
FREERDP_API BOOL crypto_cert_get_public_key(CryptoCert cert, BYTE** PublicKey,
|
||||
DWORD* PublicKeyLength);
|
||||
|
||||
#define TSSK_KEY_LENGTH 64
|
||||
WINPR_API extern const BYTE tssk_modulus[];
|
||||
WINPR_API extern const BYTE tssk_privateExponent[];
|
||||
WINPR_API extern const BYTE tssk_exponent[];
|
||||
|
||||
FREERDP_API SSIZE_T crypto_rsa_public_encrypt(const BYTE* input, size_t length,
|
||||
size_t key_length, const BYTE* modulus,
|
||||
const BYTE* exponent, BYTE* output);
|
||||
|
|
|
@ -359,17 +359,15 @@ typedef struct rdp_CertInfo rdpCertInfo;
|
|||
struct rdp_certificate
|
||||
{
|
||||
rdpCertInfo cert_info;
|
||||
rdpX509CertChain* x509_cert_chain;
|
||||
rdpX509CertChain x509_cert_chain;
|
||||
};
|
||||
typedef struct rdp_certificate rdpCertificate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE* Modulus;
|
||||
DWORD ModulusLength;
|
||||
rdpCertInfo cert;
|
||||
BYTE* PrivateExponent;
|
||||
DWORD PrivateExponentLength;
|
||||
BYTE exponent[4];
|
||||
} rdpRsaKey;
|
||||
|
||||
/* Channels */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -53,6 +53,8 @@ FREERDP_LOCAL SSIZE_T certificate_write_server_certificate(const rdpCertificate*
|
|||
FREERDP_LOCAL rdpCertificate* certificate_clone(const rdpCertificate* certificate);
|
||||
|
||||
FREERDP_LOCAL rdpCertificate* certificate_new(void);
|
||||
FREERDP_LOCAL rdpCertificate* certificate_new_from_file(const char* file);
|
||||
FREERDP_LOCAL rdpCertificate* certificate_new_from_pem(const char* pem);
|
||||
FREERDP_LOCAL void certificate_free(rdpCertificate* certificate);
|
||||
|
||||
FREERDP_LOCAL rdpRsaKey* key_new(const char* keyfile);
|
||||
|
|
|
@ -767,7 +767,7 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp)
|
|||
rdp->do_crypt_license = TRUE;
|
||||
|
||||
/* now calculate encrypt / decrypt and update keys */
|
||||
if (!security_establish_keys(settings->ClientRandom, rdp))
|
||||
if (!security_establish_keys(rdp))
|
||||
goto end;
|
||||
|
||||
rdp->do_crypt = TRUE;
|
||||
|
@ -822,14 +822,42 @@ end:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static BOOL rdp_update_client_random(rdpSettings* settings, const BYTE* crypt_random,
|
||||
size_t crypt_random_len)
|
||||
{
|
||||
const size_t length = 32;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
const rdpRsaKey* rsa = freerdp_settings_get_pointer(settings, FreeRDP_RdpServerRsaKey);
|
||||
WINPR_ASSERT(rsa);
|
||||
|
||||
const rdpCertInfo* cinfo = &rsa->cert;
|
||||
WINPR_ASSERT(cinfo);
|
||||
|
||||
const DWORD key_len = cinfo->ModulusLength;
|
||||
const BYTE* mod = cinfo->Modulus;
|
||||
const BYTE* priv_exp = rsa->PrivateExponent;
|
||||
|
||||
if (crypt_random_len != key_len + 8)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid encrypted client random length");
|
||||
return FALSE;
|
||||
}
|
||||
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ClientRandom, NULL, length))
|
||||
return FALSE;
|
||||
|
||||
BYTE* client_random = freerdp_settings_get_pointer(settings, FreeRDP_ClientRandom);
|
||||
WINPR_ASSERT(client_random);
|
||||
return crypto_rsa_private_decrypt(crypt_random, crypt_random_len - 8, key_len, mod, priv_exp,
|
||||
client_random) > 0;
|
||||
}
|
||||
|
||||
BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
|
||||
{
|
||||
BYTE* client_random = NULL;
|
||||
BYTE* crypt_client_random = NULL;
|
||||
UINT32 rand_len, key_len;
|
||||
UINT16 channel_id, length, sec_flags;
|
||||
BYTE* mod;
|
||||
BYTE* priv_exp;
|
||||
UINT32 rand_len = 0;
|
||||
UINT16 channel_id = 0;
|
||||
UINT16 length = 0;
|
||||
UINT16 sec_flags = 0;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
if (!rdp->settings->UseRdpSecurityLayer)
|
||||
|
@ -864,43 +892,14 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
|
|||
if (!Stream_CheckAndLogRequiredLength(TAG, s, rand_len))
|
||||
return FALSE;
|
||||
|
||||
key_len = rdp->settings->RdpServerRsaKey->ModulusLength;
|
||||
client_random = malloc(key_len);
|
||||
|
||||
if (!client_random)
|
||||
return FALSE;
|
||||
|
||||
if (rand_len != key_len + 8)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid encrypted client random length");
|
||||
free(client_random);
|
||||
const BYTE* crypt_random = Stream_Pointer(s);
|
||||
if (!Stream_SafeSeek(s, rand_len))
|
||||
goto end;
|
||||
}
|
||||
|
||||
crypt_client_random = calloc(1, rand_len);
|
||||
|
||||
if (!crypt_client_random)
|
||||
{
|
||||
free(client_random);
|
||||
if (!rdp_update_client_random(rdp->settings, crypt_random, rand_len))
|
||||
goto end;
|
||||
}
|
||||
|
||||
Stream_Read(s, crypt_client_random, rand_len);
|
||||
mod = rdp->settings->RdpServerRsaKey->Modulus;
|
||||
priv_exp = rdp->settings->RdpServerRsaKey->PrivateExponent;
|
||||
|
||||
if (crypto_rsa_private_decrypt(crypt_client_random, rand_len - 8, key_len, mod, priv_exp,
|
||||
client_random) <= 0)
|
||||
{
|
||||
free(client_random);
|
||||
goto end;
|
||||
}
|
||||
|
||||
rdp->settings->ClientRandom = client_random;
|
||||
rdp->settings->ClientRandomLength = 32;
|
||||
|
||||
/* now calculate encrypt / decrypt and update keys */
|
||||
if (!security_establish_keys(client_random, rdp))
|
||||
if (!security_establish_keys(rdp))
|
||||
goto end;
|
||||
|
||||
rdp->do_crypt = TRUE;
|
||||
|
@ -937,7 +936,6 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s)
|
|||
|
||||
ret = tpkt_ensure_stream_consumed(s, length);
|
||||
end:
|
||||
free(crypt_client_random);
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
|
|
|
@ -1650,44 +1650,24 @@ fail:
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static const BYTE initial_signature[] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01
|
||||
};
|
||||
|
||||
/*
|
||||
* Terminal Services Signing Keys.
|
||||
* Yes, Terminal Services Private Key is publicly available.
|
||||
*/
|
||||
|
||||
const BYTE tssk_modulus[] = { 0x3d, 0x3a, 0x5e, 0xbd, 0x72, 0x43, 0x3e, 0xc9, 0x4d, 0xbb, 0xc1,
|
||||
0x1e, 0x4a, 0xba, 0x5f, 0xcb, 0x3e, 0x88, 0x20, 0x87, 0xef, 0xf5,
|
||||
0xc1, 0xe2, 0xd7, 0xb7, 0x6b, 0x9a, 0xf2, 0x52, 0x45, 0x95, 0xce,
|
||||
0x63, 0x65, 0x6b, 0x58, 0x3a, 0xfe, 0xef, 0x7c, 0xe7, 0xbf, 0xfe,
|
||||
0x3d, 0xf6, 0x5c, 0x7d, 0x6c, 0x5e, 0x06, 0x09, 0x1a, 0xf5, 0x61,
|
||||
0xbb, 0x20, 0x93, 0x09, 0x5f, 0x05, 0x6d, 0xea, 0x87 };
|
||||
|
||||
const BYTE tssk_privateExponent[] = {
|
||||
0x87, 0xa7, 0x19, 0x32, 0xda, 0x11, 0x87, 0x55, 0x58, 0x00, 0x16, 0x16, 0x25, 0x65, 0x68, 0xf8,
|
||||
0x24, 0x3e, 0xe6, 0xfa, 0xe9, 0x67, 0x49, 0x94, 0xcf, 0x92, 0xcc, 0x33, 0x99, 0xe8, 0x08, 0x60,
|
||||
0x17, 0x9a, 0x12, 0x9f, 0x24, 0xdd, 0xb1, 0x24, 0x99, 0xc7, 0x3a, 0xb8, 0x0a, 0x7b, 0x0d, 0xdd,
|
||||
0x35, 0x07, 0x79, 0x17, 0x0b, 0x51, 0x9b, 0xb3, 0xc7, 0x10, 0x01, 0x13, 0xe7, 0x3f, 0xf3, 0x5f
|
||||
};
|
||||
|
||||
const BYTE tssk_exponent[] = { 0x5b, 0x7b, 0x88, 0xc0 };
|
||||
static BOOL gcc_update_server_random(rdpSettings* settings)
|
||||
{
|
||||
const size_t length = 32;
|
||||
WINPR_ASSERT(settings);
|
||||
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ServerRandom, NULL, length))
|
||||
return FALSE;
|
||||
BYTE* data = freerdp_settings_get_pointer(settings, FreeRDP_ServerRandom);
|
||||
if (!data)
|
||||
return FALSE;
|
||||
winpr_RAND(data, length);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* TODO: This function does manipulate data in rdpMcs
|
||||
* TODO: Split this out of this function
|
||||
*/
|
||||
BOOL gcc_write_server_security_data(wStream* s, rdpMcs* mcs)
|
||||
{
|
||||
BYTE* sigData;
|
||||
size_t expLen = 0, keyLen, sigDataLen;
|
||||
BYTE encryptedSignature[TSSK_KEY_LENGTH] = { 0 };
|
||||
BYTE signature[sizeof(initial_signature)] = { 0 };
|
||||
UINT32 headerLen, serverRandomLen, serverCertLen, wPublicKeyBlobLen;
|
||||
rdpSettings* settings = mcs_get_settings(mcs);
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
|
@ -1823,90 +1803,35 @@ BOOL gcc_write_server_security_data(wStream* s, rdpMcs* mcs)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
headerLen = 12;
|
||||
keyLen = 0;
|
||||
wPublicKeyBlobLen = 0;
|
||||
serverRandomLen = 0;
|
||||
serverCertLen = 0;
|
||||
|
||||
if (settings->EncryptionMethods != ENCRYPTION_METHOD_NONE)
|
||||
{
|
||||
serverRandomLen = 32;
|
||||
keyLen = settings->RdpServerRsaKey->ModulusLength;
|
||||
expLen = sizeof(settings->RdpServerRsaKey->exponent);
|
||||
wPublicKeyBlobLen = 4; /* magic (RSA1) */
|
||||
wPublicKeyBlobLen += 4; /* keylen */
|
||||
wPublicKeyBlobLen += 4; /* bitlen */
|
||||
wPublicKeyBlobLen += 4; /* datalen */
|
||||
wPublicKeyBlobLen += expLen;
|
||||
wPublicKeyBlobLen += keyLen;
|
||||
wPublicKeyBlobLen += 8; /* 8 bytes of zero padding */
|
||||
serverCertLen = 4; /* dwVersion */
|
||||
serverCertLen += 4; /* dwSigAlgId */
|
||||
serverCertLen += 4; /* dwKeyAlgId */
|
||||
serverCertLen += 2; /* wPublicKeyBlobType */
|
||||
serverCertLen += 2; /* wPublicKeyBlobLen */
|
||||
serverCertLen += wPublicKeyBlobLen;
|
||||
serverCertLen += 2; /* wSignatureBlobType */
|
||||
serverCertLen += 2; /* wSignatureBlobLen */
|
||||
serverCertLen += sizeof(encryptedSignature); /* SignatureBlob */
|
||||
serverCertLen += 8; /* 8 bytes of zero padding */
|
||||
headerLen += sizeof(serverRandomLen);
|
||||
headerLen += sizeof(serverCertLen);
|
||||
headerLen += serverRandomLen;
|
||||
headerLen += serverCertLen;
|
||||
}
|
||||
|
||||
if (!gcc_write_user_data_header(s, SC_SECURITY, headerLen))
|
||||
const size_t posHeader = Stream_GetPosition(s);
|
||||
if (!gcc_write_user_data_header(s, SC_SECURITY, 12))
|
||||
return FALSE;
|
||||
|
||||
Stream_Write_UINT32(s, settings->EncryptionMethods); /* encryptionMethod */
|
||||
Stream_Write_UINT32(s, settings->EncryptionLevel); /* encryptionLevel */
|
||||
|
||||
if (settings->EncryptionMethods == ENCRYPTION_METHOD_NONE)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(s, serverRandomLen); /* serverRandomLen */
|
||||
Stream_Write_UINT32(s, serverCertLen); /* serverCertLen */
|
||||
settings->ServerRandomLength = serverRandomLen;
|
||||
settings->ServerRandom = (BYTE*)malloc(serverRandomLen);
|
||||
|
||||
if (!settings->ServerRandom)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
winpr_RAND(settings->ServerRandom, serverRandomLen);
|
||||
Stream_Write(s, settings->ServerRandom, serverRandomLen);
|
||||
sigData = Stream_Pointer(s);
|
||||
Stream_Write_UINT32(s, CERT_CHAIN_VERSION_1); /* dwVersion (4 bytes) */
|
||||
Stream_Write_UINT32(s, SIGNATURE_ALG_RSA); /* dwSigAlgId */
|
||||
Stream_Write_UINT32(s, KEY_EXCHANGE_ALG_RSA); /* dwKeyAlgId */
|
||||
Stream_Write_UINT16(s, BB_RSA_KEY_BLOB); /* wPublicKeyBlobType */
|
||||
Stream_Write_UINT16(s, wPublicKeyBlobLen); /* wPublicKeyBlobLen */
|
||||
Stream_Write(s, "RSA1", 4); /* magic */
|
||||
WINPR_ASSERT(keyLen > 0);
|
||||
WINPR_ASSERT(keyLen <= UINT32_MAX / 8);
|
||||
Stream_Write_UINT32(s, (UINT32)keyLen + 8); /* keylen */
|
||||
Stream_Write_UINT32(s, (UINT32)keyLen * 8); /* bitlen */
|
||||
Stream_Write_UINT32(s, (UINT32)keyLen - 1); /* datalen */
|
||||
Stream_Write(s, settings->RdpServerRsaKey->exponent, expLen);
|
||||
Stream_Write(s, settings->RdpServerRsaKey->Modulus, keyLen);
|
||||
Stream_Zero(s, 8);
|
||||
sigDataLen = Stream_Pointer(s) - sigData;
|
||||
Stream_Write_UINT16(s, BB_RSA_SIGNATURE_BLOB); /* wSignatureBlobType */
|
||||
Stream_Write_UINT16(s, sizeof(encryptedSignature) + 8); /* wSignatureBlobLen */
|
||||
memcpy(signature, initial_signature, sizeof(initial_signature));
|
||||
|
||||
if (!winpr_Digest(WINPR_MD_MD5, sigData, sigDataLen, signature, sizeof(signature)))
|
||||
if (!gcc_update_server_random(settings))
|
||||
return FALSE;
|
||||
|
||||
crypto_rsa_private_encrypt(signature, sizeof(signature), TSSK_KEY_LENGTH, tssk_modulus,
|
||||
tssk_privateExponent, encryptedSignature);
|
||||
Stream_Write(s, encryptedSignature, sizeof(encryptedSignature));
|
||||
Stream_Zero(s, 8);
|
||||
Stream_Write_UINT32(s, settings->ServerRandomLength); /* serverRandomLen */
|
||||
const size_t posCertLen = Stream_GetPosition(s);
|
||||
Stream_Seek_UINT32(s); /* serverCertLen */
|
||||
Stream_Write(s, settings->ServerRandom, settings->ServerRandom);
|
||||
|
||||
const SSIZE_T len = certificate_write_server_certificate(
|
||||
settings->RdpServerRsaKey, CERT_TEMPORARILY_ISSUED | CERT_CHAIN_VERSION_1, s);
|
||||
if (len < 0)
|
||||
return FALSE;
|
||||
const size_t end = Stream_GetPosition(s);
|
||||
Stream_SetPosition(s, posHeader);
|
||||
if (!gcc_write_user_data_header(s, SC_SECURITY, end - posHeader))
|
||||
return FALSE;
|
||||
Stream_SetPosition(s, posCertLen);
|
||||
WINPR_ASSERT(len <= UINT32_MAX);
|
||||
Stream_Write_UINT32(s, (UINT32)len);
|
||||
Stream_SetPosition(s, end);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -531,25 +531,31 @@ static void fips_expand_key_bits(BYTE* in, BYTE* out)
|
|||
out[i] = fips_oddparity_table[fips_reverse_table[out[i]]];
|
||||
}
|
||||
|
||||
BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp)
|
||||
BOOL security_establish_keys(rdpRdp* rdp)
|
||||
{
|
||||
BYTE pre_master_secret[48];
|
||||
BYTE master_secret[48];
|
||||
BYTE session_key_blob[48];
|
||||
BYTE* server_random;
|
||||
BYTE pre_master_secret[48] = { 0 };
|
||||
BYTE master_secret[48] = { 0 };
|
||||
BYTE session_key_blob[48] = { 0 };
|
||||
BYTE salt[] = { 0xD1, 0x26, 0x9E }; /* 40 bits: 3 bytes, 56 bits: 1 byte */
|
||||
rdpSettings* settings;
|
||||
BOOL status;
|
||||
settings = rdp->settings;
|
||||
server_random = settings->ServerRandom;
|
||||
BOOL status = FALSE;
|
||||
|
||||
WINPR_ASSERT(rdp);
|
||||
const rdpSettings* settings = rdp->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
const BYTE* server_random = freerdp_settings_get_pointer(settings, FreeRDP_ServerRandom);
|
||||
const BYTE* client_random = freerdp_settings_get_pointer(settings, FreeRDP_ClientRandom);
|
||||
WINPR_ASSERT(client_random);
|
||||
WINPR_ASSERT(server_random);
|
||||
WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_ClientRandomLength) == 32);
|
||||
WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_ServerRandomLength) == 32);
|
||||
|
||||
if (settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
|
||||
{
|
||||
WINPR_DIGEST_CTX* sha1;
|
||||
BYTE client_encrypt_key_t[WINPR_SHA1_DIGEST_LENGTH + 1];
|
||||
BYTE client_decrypt_key_t[WINPR_SHA1_DIGEST_LENGTH + 1];
|
||||
|
||||
if (!(sha1 = winpr_Digest_New()))
|
||||
BYTE client_encrypt_key_t[WINPR_SHA1_DIGEST_LENGTH + 1] = { 0 };
|
||||
BYTE client_decrypt_key_t[WINPR_SHA1_DIGEST_LENGTH + 1] = { 0 };
|
||||
WINPR_DIGEST_CTX* sha1 = winpr_Digest_New();
|
||||
if (!sha1)
|
||||
return FALSE;
|
||||
|
||||
if (!winpr_Digest_Init(sha1, WINPR_MD_SHA1) ||
|
||||
|
@ -585,7 +591,7 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp)
|
|||
|
||||
winpr_Digest_Free(sha1);
|
||||
|
||||
if (rdp->settings->ServerMode)
|
||||
if (settings->ServerMode)
|
||||
{
|
||||
fips_expand_key_bits(client_encrypt_key_t, rdp->fips_decrypt_key);
|
||||
fips_expand_key_bits(client_decrypt_key_t, rdp->fips_encrypt_key);
|
||||
|
@ -608,7 +614,7 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp)
|
|||
|
||||
memcpy(rdp->sign_key, session_key_blob, 16);
|
||||
|
||||
if (rdp->settings->ServerMode)
|
||||
if (settings->ServerMode)
|
||||
{
|
||||
status = security_md5_16_32_32(&session_key_blob[16], client_random, server_random,
|
||||
rdp->encrypt_key);
|
||||
|
|
|
@ -43,7 +43,7 @@ FREERDP_LOCAL BOOL security_mac_signature(rdpRdp* rdp, const BYTE* data, UINT32
|
|||
BYTE* output);
|
||||
FREERDP_LOCAL BOOL security_salted_mac_signature(rdpRdp* rdp, const BYTE* data, UINT32 length,
|
||||
BOOL encryption, BYTE* output);
|
||||
FREERDP_LOCAL BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp);
|
||||
FREERDP_LOCAL BOOL security_establish_keys(rdpRdp* rdp);
|
||||
FREERDP_LOCAL BOOL security_encrypt(BYTE* data, size_t length, rdpRdp* rdp);
|
||||
FREERDP_LOCAL BOOL security_decrypt(BYTE* data, size_t length, rdpRdp* rdp);
|
||||
FREERDP_LOCAL BOOL security_hmac_signature(const BYTE* data, size_t length, BYTE* output,
|
||||
|
|
Loading…
Reference in New Issue