[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:
akallabeth 2023-01-20 11:03:05 +01:00 committed by akallabeth
parent 2f05166fb1
commit 2c2e9602b3
8 changed files with 700 additions and 488 deletions

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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);

View File

@ -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,