Commit fb85c9e9 authored by Michael Jung's avatar Michael Jung Committed by Alexandre Julliard

Support for TLS1 pseudo random function.

Some helper functions for DATA_BLOB's. Computing TLS1 master secret from the pre-master secret. Deriving the master hash from the master secret. Deriving TLS1 MAC and encryption keys from the master hash. Tests for most of the above.
parent bfef6208
......@@ -4,7 +4,7 @@
*
* Copyright 2002 TransGaming Technologies (David Hammerton)
* Copyright 2004 Mike McCormack for CodeWeavers
* Copyright 2004 Michael Jung
* Copyright 2004, 2005 Michael Jung
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -43,10 +43,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(crypt);
* CRYPTHASH - hash objects
*/
#define RSAENH_MAGIC_HASH 0x85938417u
#define RSAENH_MAX_HASH_SIZE 36
#define RSAENH_MAX_HASH_SIZE 104
#define RSAENH_HASHSTATE_IDLE 0
#define RSAENH_HASHSTATE_HASHING 1
#define RSAENH_HASHSTATE_FINISHED 2
typedef struct _RSAENH_TLS1PRF_PARAMS
{
CRYPT_DATA_BLOB blobLabel;
CRYPT_DATA_BLOB blobSeed;
} RSAENH_TLS1PRF_PARAMS;
typedef struct tagCRYPTHASH
{
OBJECTHDR header;
......@@ -58,6 +64,7 @@ typedef struct tagCRYPTHASH
HASH_CONTEXT context;
BYTE abHashValue[RSAENH_MAX_HASH_SIZE];
PHMAC_INFO pHMACInfo;
RSAENH_TLS1PRF_PARAMS tpPRFParams;
} CRYPTHASH;
/******************************************************************************
......@@ -69,6 +76,15 @@ typedef struct tagCRYPTHASH
#define RSAENH_KEYSTATE_IDLE 0
#define RSAENH_KEYSTATE_ENCRYPTING 1
#define RSAENH_KEYSTATE_DECRYPTING 2
#define RSAENH_KEYSTATE_MASTERKEY 3
typedef struct _RSAENH_SCHANNEL_INFO
{
SCHANNEL_ALG saEncAlg;
SCHANNEL_ALG saMACAlg;
CRYPT_DATA_BLOB blobClientRandom;
CRYPT_DATA_BLOB blobServerRandom;
} RSAENH_SCHANNEL_INFO;
typedef struct tagCRYPTKEY
{
OBJECTHDR header;
......@@ -85,6 +101,7 @@ typedef struct tagCRYPTKEY
BYTE abKeyValue[RSAENH_MAX_KEY_SIZE];
BYTE abInitVector[RSAENH_MAX_BLOCK_SIZE];
BYTE abChainVector[RSAENH_MAX_BLOCK_SIZE];
RSAENH_SCHANNEL_INFO siSChannelInfo;
} CRYPTKEY;
/******************************************************************************
......@@ -135,7 +152,7 @@ typedef struct tagKEYCONTAINER
/******************************************************************************
* aProvEnumAlgsEx - Defines the capabilities of the CSP personalities.
*/
#define RSAENH_MAX_ENUMALGS 19
#define RSAENH_MAX_ENUMALGS 20
#define RSAENH_PCT1_SSL2_SSL3_TLS1 (CRYPT_FLAG_PCT1|CRYPT_FLAG_SSL2|CRYPT_FLAG_SSL3|CRYPT_FLAG_TLS1)
PROV_ENUMALGS_EX aProvEnumAlgsEx[4][RSAENH_MAX_ENUMALGS+1] =
{
......@@ -208,6 +225,7 @@ PROV_ENUMALGS_EX aProvEnumAlgsEx[4][RSAENH_MAX_ENUMALGS+1] =
{CALG_SCHANNEL_MASTER_HASH,0,0,-1,0, 16,"SCH MASTER HASH",21,"SChannel Master Hash"},
{CALG_SCHANNEL_MAC_KEY,0,0,-1,0, 12,"SCH MAC KEY",17,"SChannel MAC Key"},
{CALG_SCHANNEL_ENC_KEY,0,0,-1,0, 12,"SCH ENC KEY",24,"SChannel Encryption Key"},
{CALG_TLS1PRF, 0, 0, -1,0, 9,"TLS1 PRF", 28,"TLS1 Pseudo Random Function"},
{0, 0, 0, 0,0, 1,"", 1,""}
}
};
......@@ -238,6 +256,23 @@ RSAENH_CPEncrypt(
);
BOOL WINAPI
RSAENH_CPCreateHash(
HCRYPTPROV hProv,
ALG_ID Algid,
HCRYPTKEY hKey,
DWORD dwFlags,
HCRYPTHASH *phHash
);
BOOL WINAPI
RSAENH_CPSetHashParam(
HCRYPTPROV hProv,
HCRYPTHASH hHash,
DWORD dwParam,
BYTE *pbData, DWORD dwFlags
);
BOOL WINAPI
RSAENH_CPGetHashParam(
HCRYPTPROV hProv,
HCRYPTHASH hHash,
......@@ -248,6 +283,12 @@ RSAENH_CPGetHashParam(
);
BOOL WINAPI
RSAENH_CPDestroyHash(
HCRYPTPROV hProv,
HCRYPTHASH hHash
);
BOOL WINAPI
RSAENH_CPExportKey(
HCRYPTPROV hProv,
HCRYPTKEY hKey,
......@@ -368,6 +409,84 @@ static inline const PROV_ENUMALGS_EX* get_algid_info(HCRYPTPROV hProv, ALG_ID al
}
/******************************************************************************
* copy_data_blob [Internal]
*
* deeply copies a DATA_BLOB
*
* PARAMS
* dst [O] That's where the blob will be copied to
* src [I] Source blob
*
* RETURNS
* Success: TRUE
* Failure: FALSE (GetLastError() == NTE_NO_MEMORY
*
* NOTES
* Use free_data_blob to release resources occupied by copy_data_blob.
*/
static inline BOOL copy_data_blob(PCRYPT_DATA_BLOB dst, CONST PCRYPT_DATA_BLOB src) {
dst->pbData = (BYTE*)HeapAlloc(GetProcessHeap(), 0, src->cbData);
if (!dst->pbData) {
SetLastError(NTE_NO_MEMORY);
return FALSE;
}
dst->cbData = src->cbData;
memcpy(dst->pbData, src->pbData, src->cbData);
return TRUE;
}
/******************************************************************************
* concat_data_blobs [Internal]
*
* Concatenates two blobs
*
* PARAMS
* dst [O] The new blob will be copied here
* src1 [I] Prefix blob
* src2 [I] Appendix blob
*
* RETURNS
* Success: TRUE
* Failure: FALSE (GetLastError() == NTE_NO_MEMORY)
*
* NOTES
* Release resources occupied by concat_data_blobs with free_data_blobs
*/
static inline BOOL concat_data_blobs(PCRYPT_DATA_BLOB dst, CONST PCRYPT_DATA_BLOB src1,
CONST PCRYPT_DATA_BLOB src2)
{
dst->cbData = src1->cbData + src2->cbData;
dst->pbData = (BYTE*)HeapAlloc(GetProcessHeap(), 0, dst->cbData);
if (!dst->pbData) {
SetLastError(NTE_NO_MEMORY);
return FALSE;
}
memcpy(dst->pbData, src1->pbData, src1->cbData);
memcpy(dst->pbData + src1->cbData, src2->pbData, src2->cbData);
return TRUE;
}
/******************************************************************************
* free_data_blob [Internal]
*
* releases resource occupied by a dynamically allocated CRYPT_DATA_BLOB
*
* PARAMS
* pBlob [I] Heap space occupied by pBlob->pbData is released
*/
static inline void free_data_blob(PCRYPT_DATA_BLOB pBlob) {
HeapFree(GetProcessHeap(), 0, pBlob->pbData);
}
/******************************************************************************
* init_data_blob [Internal]
*/
static inline void init_data_blob(PCRYPT_DATA_BLOB pBlob) {
pBlob->pbData = NULL;
pBlob->cbData = 0;
}
/******************************************************************************
* free_hmac_info [Internal]
*
* Deeply free an HMAC_INFO struct.
......@@ -440,9 +559,13 @@ static BOOL copy_hmac_info(PHMAC_INFO *dst, PHMAC_INFO src) {
* pCryptHash [I] Pointer to the hash object to be destroyed.
* Will be invalid after function returns!
*/
static void destroy_hash(OBJECTHDR *pCryptHash)
static void destroy_hash(OBJECTHDR *pObject)
{
free_hmac_info(((CRYPTHASH*)pCryptHash)->pHMACInfo);
CRYPTHASH *pCryptHash = (CRYPTHASH*)pObject;
free_hmac_info(pCryptHash->pHMACInfo);
free_data_blob(&pCryptHash->tpPRFParams.blobLabel);
free_data_blob(&pCryptHash->tpPRFParams.blobSeed);
HeapFree(GetProcessHeap(), 0, pCryptHash);
}
......@@ -572,9 +695,13 @@ static inline void finalize_hash(CRYPTHASH *pCryptHash) {
* pCryptKey [I] Pointer to the key object to be destroyed.
* Will be invalid after function returns!
*/
static void destroy_key(OBJECTHDR *pCryptKey)
static void destroy_key(OBJECTHDR *pObject)
{
free_key_impl(((CRYPTKEY*)pCryptKey)->aiAlgid, &((CRYPTKEY*)pCryptKey)->context);
CRYPTKEY *pCryptKey = (CRYPTKEY*)pObject;
free_key_impl(pCryptKey->aiAlgid, &pCryptKey->context);
free_data_blob(&pCryptKey->siSChannelInfo.blobClientRandom);
free_data_blob(&pCryptKey->siSChannelInfo.blobServerRandom);
HeapFree(GetProcessHeap(), 0, pCryptKey);
}
......@@ -689,6 +816,8 @@ static HCRYPTKEY new_key(HCRYPTPROV hProv, ALG_ID aiAlgid, DWORD dwFlags, CRYPTK
pCryptKey->dwSaltLen = 0;
memset(pCryptKey->abKeyValue, 0, sizeof(pCryptKey->abKeyValue));
memset(pCryptKey->abInitVector, 0, sizeof(pCryptKey->abInitVector));
init_data_blob(&pCryptKey->siSChannelInfo.blobClientRandom);
init_data_blob(&pCryptKey->siSChannelInfo.blobServerRandom);
switch(aiAlgid)
{
......@@ -1017,6 +1146,135 @@ static BOOL build_hash_signature(BYTE *pbSignature, DWORD dwLen, ALG_ID aiAlgid,
}
/******************************************************************************
* tls1_p [Internal]
*
* This is an implementation of the 'P_hash' helper function for TLS1's PRF.
* It is used exclusively by tls1_prf. For details see RFC 2246, chapter 5.
* The pseudo random stream generated by this function is exclusive or'ed with
* the data in pbBuffer.
*
* PARAMS
* hHMAC [I] HMAC object, which will be used in pseudo random generation
* pblobSeed [I] Seed value
* pbBuffer [I/O] Pseudo random stream will be xor'ed to the provided data
* dwBufferLen [I] Number of pseudo random bytes desired
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*/
static BOOL tls1_p(HCRYPTHASH hHMAC, CONST PCRYPT_DATA_BLOB pblobSeed, PBYTE pbBuffer, DWORD dwBufferLen)
{
CRYPTHASH *pHMAC;
BYTE abAi[RSAENH_MAX_HASH_SIZE];
DWORD i = 0;
if (!lookup_handle(&handle_table, hHMAC, RSAENH_MAGIC_HASH, (OBJECTHDR**)&pHMAC)) {
SetLastError(NTE_BAD_HASH);
return FALSE;
}
/* compute A_1 = HMAC(seed) */
init_hash(pHMAC);
update_hash(pHMAC, pblobSeed->pbData, pblobSeed->cbData);
finalize_hash(pHMAC);
memcpy(abAi, pHMAC->abHashValue, pHMAC->dwHashSize);
do {
/* compute HMAC(A_i + seed) */
init_hash(pHMAC);
update_hash(pHMAC, abAi, pHMAC->dwHashSize);
update_hash(pHMAC, pblobSeed->pbData, pblobSeed->cbData);
finalize_hash(pHMAC);
/* pseudo random stream := CONCAT_{i=1..n} ( HMAC(A_i + seed) ) */
do {
if (i >= dwBufferLen) break;
pbBuffer[i] ^= pHMAC->abHashValue[i % pHMAC->dwHashSize];
i++;
} while (i % pHMAC->dwHashSize);
/* compute A_{i+1} = HMAC(A_i) */
init_hash(pHMAC);
update_hash(pHMAC, abAi, pHMAC->dwHashSize);
finalize_hash(pHMAC);
memcpy(abAi, pHMAC->abHashValue, pHMAC->dwHashSize);
} while (i < dwBufferLen);
return TRUE;
}
/******************************************************************************
* tls1_prf [Internal]
*
* TLS1 pseudo random function as specified in RFC 2246, chapter 5
*
* PARAMS
* hProv [I] Key container used to compute the pseudo random stream
* hSecret [I] Key that holds the (pre-)master secret
* pblobLabel [I] Descriptive label
* pblobSeed [I] Seed value
* pbBuffer [O] Pseudo random numbers will be stored here
* dwBufferLen [I] Number of pseudo random bytes desired
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*/
static BOOL tls1_prf(HCRYPTPROV hProv, HCRYPTPROV hSecret, CONST PCRYPT_DATA_BLOB pblobLabel,
CONST PCRYPT_DATA_BLOB pblobSeed, PBYTE pbBuffer, DWORD dwBufferLen)
{
HMAC_INFO hmacInfo = { 0, NULL, 0, NULL, 0 };
HCRYPTHASH hHMAC = (HCRYPTHASH)INVALID_HANDLE_VALUE;
HCRYPTKEY hHalfSecret = (HCRYPTKEY)INVALID_HANDLE_VALUE;
CRYPTKEY *pHalfSecret, *pSecret;
DWORD dwHalfSecretLen;
BOOL result = FALSE;
CRYPT_DATA_BLOB blobLabelSeed;
TRACE("(hProv=%08lx, hSecret=%08lx, pblobLabel=%p, pblobSeed=%p, pbBuffer=%p, dwBufferLen=%ld)\n",
hProv, hSecret, pblobLabel, pblobSeed, pbBuffer, dwBufferLen);
if (!lookup_handle(&handle_table, hSecret, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pSecret)) {
SetLastError(NTE_FAIL);
return FALSE;
}
dwHalfSecretLen = (pSecret->dwKeyLen+1)/2;
/* concatenation of the label and the seed */
if (!concat_data_blobs(&blobLabelSeed, pblobLabel, pblobSeed)) goto exit;
/* zero out the buffer, since two random streams will be xor'ed into it. */
memset(pbBuffer, 0, dwBufferLen);
/* build a 'fake' key, to hold the secret. CALG_SSL2_MASTER is used since it provides
* the biggest range of valid key lengths. */
hHalfSecret = new_key(hProv, CALG_SSL2_MASTER, MAKELONG(0,dwHalfSecretLen*8), &pHalfSecret);
if (hHalfSecret == (HCRYPTKEY)INVALID_HANDLE_VALUE) goto exit;
/* Derive an HMAC_MD5 hash and call the helper function. */
memcpy(pHalfSecret->abKeyValue, pSecret->abKeyValue, dwHalfSecretLen);
if (!RSAENH_CPCreateHash(hProv, CALG_HMAC, hHalfSecret, 0, &hHMAC)) goto exit;
hmacInfo.HashAlgid = CALG_MD5;
if (!RSAENH_CPSetHashParam(hProv, hHMAC, HP_HMAC_INFO, (BYTE*)&hmacInfo, 0)) goto exit;
if (!tls1_p(hHMAC, &blobLabelSeed, pbBuffer, dwBufferLen)) goto exit;
/* Reconfigure to HMAC_SHA hash and call helper function again. */
memcpy(pHalfSecret->abKeyValue, pSecret->abKeyValue + (pSecret->dwKeyLen/2), dwHalfSecretLen);
hmacInfo.HashAlgid = CALG_SHA;
if (!RSAENH_CPSetHashParam(hProv, hHMAC, HP_HMAC_INFO, (BYTE*)&hmacInfo, 0)) goto exit;
if (!tls1_p(hHMAC, &blobLabelSeed, pbBuffer, dwBufferLen)) goto exit;
result = TRUE;
exit:
release_handle(&handle_table, hHalfSecret, RSAENH_MAGIC_KEY);
if (hHMAC != (HCRYPTHASH)INVALID_HANDLE_VALUE) RSAENH_CPDestroyHash(hProv, hHMAC);
free_data_blob(&blobLabelSeed);
return result;
}
/******************************************************************************
* CPAcquireContext (RSAENH.@)
*
* Acquire a handle to the key container specified by pszContainer
......@@ -1135,6 +1393,7 @@ BOOL WINAPI RSAENH_CPAcquireContext(HCRYPTPROV *phProv, LPSTR pszContainer,
BOOL WINAPI RSAENH_CPCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags,
HCRYPTHASH *phHash)
{
CRYPTKEY *pCryptKey;
CRYPTHASH *pCryptHash;
const PROV_ENUMALGS_EX *peaAlgidInfo;
......@@ -1150,9 +1409,9 @@ BOOL WINAPI RSAENH_CPCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey,
return FALSE;
}
if ((Algid == CALG_MAC || Algid == CALG_HMAC)) {
CRYPTKEY *pCryptKey;
if (Algid == CALG_MAC || Algid == CALG_HMAC || Algid == CALG_SCHANNEL_MASTER_HASH ||
Algid == CALG_TLS1PRF)
{
if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey)) {
SetLastError(NTE_BAD_KEY);
return FALSE;
......@@ -1162,6 +1421,18 @@ BOOL WINAPI RSAENH_CPCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey,
SetLastError(NTE_BAD_KEY);
return FALSE;
}
if ((Algid == CALG_SCHANNEL_MASTER_HASH || Algid == CALG_TLS1PRF) &&
(pCryptKey->aiAlgid != CALG_TLS1_MASTER))
{
SetLastError(NTE_BAD_KEY);
return FALSE;
}
if ((Algid == CALG_TLS1PRF) && (pCryptKey->dwState != RSAENH_KEYSTATE_MASTERKEY)) {
SetLastError(NTE_BAD_KEY_STATE);
return FALSE;
}
}
*phHash = (HCRYPTHASH)new_object(&handle_table, sizeof(CRYPTHASH), RSAENH_MAGIC_HASH,
......@@ -1174,7 +1445,41 @@ BOOL WINAPI RSAENH_CPCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey,
pCryptHash->dwState = RSAENH_HASHSTATE_IDLE;
pCryptHash->pHMACInfo = (PHMAC_INFO)NULL;
pCryptHash->dwHashSize = peaAlgidInfo->dwDefaultLen >> 3;
init_data_blob(&pCryptHash->tpPRFParams.blobLabel);
init_data_blob(&pCryptHash->tpPRFParams.blobSeed);
if (Algid == CALG_SCHANNEL_MASTER_HASH) {
CRYPT_DATA_BLOB blobRandom, blobKeyExpansion = { 13, "key expansion" };
if (pCryptKey->dwState != RSAENH_KEYSTATE_MASTERKEY) {
CRYPT_DATA_BLOB blobLabel = { 13, "master secret" };
BYTE abKeyValue[48];
/* See RFC 2246, chapter 8.1 */
if (!concat_data_blobs(&blobRandom,
&pCryptKey->siSChannelInfo.blobClientRandom,
&pCryptKey->siSChannelInfo.blobServerRandom))
{
return FALSE;
}
tls1_prf(hProv, hKey, &blobLabel, &blobRandom, abKeyValue, 48);
pCryptKey->dwState = RSAENH_KEYSTATE_MASTERKEY;
memcpy(pCryptKey->abKeyValue, abKeyValue, 48);
free_data_blob(&blobRandom);
}
/* See RFC 2246, chapter 6.3 */
if (!concat_data_blobs(&blobRandom,
&pCryptKey->siSChannelInfo.blobServerRandom,
&pCryptKey->siSChannelInfo.blobClientRandom))
{
return FALSE;
}
tls1_prf(hProv, hKey, &blobKeyExpansion, &blobRandom, pCryptHash->abHashValue,
RSAENH_MAX_HASH_SIZE);
free_data_blob(&blobRandom);
}
return init_hash(pCryptHash);
}
......@@ -1293,6 +1598,8 @@ BOOL WINAPI RSAENH_CPDuplicateHash(HCRYPTPROV hUID, HCRYPTHASH hHash, DWORD *pdw
memcpy(pDestHash, pSrcHash, sizeof(CRYPTHASH));
duplicate_hash_impl(pSrcHash->aiAlgid, &pSrcHash->context, &pDestHash->context);
copy_hmac_info(&pDestHash->pHMACInfo, pSrcHash->pHMACInfo);
copy_data_blob(&pDestHash->tpPRFParams.blobLabel, &pSrcHash->tpPRFParams.blobLabel);
copy_data_blob(&pDestHash->tpPRFParams.blobSeed, &pSrcHash->tpPRFParams.blobSeed);
}
return *phHash != (HCRYPTHASH)INVALID_HANDLE_VALUE;
......@@ -1345,6 +1652,10 @@ BOOL WINAPI RSAENH_CPDuplicateKey(HCRYPTPROV hUID, HCRYPTKEY hKey, DWORD *pdwRes
if (*phKey != (HCRYPTKEY)INVALID_HANDLE_VALUE)
{
memcpy(pDestKey, pSrcKey, sizeof(CRYPTKEY));
copy_data_blob(&pDestKey->siSChannelInfo.blobServerRandom,
&pSrcKey->siSChannelInfo.blobServerRandom);
copy_data_blob(&pDestKey->siSChannelInfo.blobClientRandom,
&pSrcKey->siSChannelInfo.blobClientRandom);
duplicate_key_impl(pSrcKey->aiAlgid, &pSrcKey->context, &pDestKey->context);
return TRUE;
}
......@@ -1537,7 +1848,7 @@ BOOL WINAPI RSAENH_CPDecrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash,
if (GET_ALG_CLASS(pCryptKey->aiAlgid) != ALG_CLASS_DATA_ENCRYPT) {
SetLastError(NTE_BAD_TYPE);
return FALSE;
}
}
if (pCryptKey->dwState == RSAENH_KEYSTATE_IDLE)
pCryptKey->dwState = RSAENH_KEYSTATE_DECRYPTING;
......@@ -2082,6 +2393,11 @@ BOOL WINAPI RSAENH_CPGetHashParam(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwPa
sizeof(DWORD));
case HP_HASHVAL:
if (pCryptHash->aiAlgid == CALG_TLS1PRF) {
return tls1_prf(hProv, pCryptHash->hKey, &pCryptHash->tpPRFParams.blobLabel,
&pCryptHash->tpPRFParams.blobSeed, pbData, *pdwDataLen);
}
if (pCryptHash->dwState == RSAENH_HASHSTATE_IDLE) {
SetLastError(NTE_BAD_HASH_STATE);
return FALSE;
......@@ -2168,6 +2484,28 @@ BOOL WINAPI RSAENH_CPSetKeyParam(HCRYPTPROV hProv, HCRYPTKEY hKey, DWORD dwParam
memcpy(pCryptKey->abInitVector, pbData, pCryptKey->dwBlockLen);
return TRUE;
case KP_SCHANNEL_ALG:
switch (((PSCHANNEL_ALG)pbData)->dwUse) {
case SCHANNEL_ENC_KEY:
memcpy(&pCryptKey->siSChannelInfo.saEncAlg, pbData, sizeof(SCHANNEL_ALG));
break;
case SCHANNEL_MAC_KEY:
memcpy(&pCryptKey->siSChannelInfo.saMACAlg, pbData, sizeof(SCHANNEL_ALG));
break;
default:
SetLastError(NTE_FAIL); /* FIXME: error code */
return FALSE;
}
return TRUE;
case KP_CLIENT_RANDOM:
return copy_data_blob(&pCryptKey->siSChannelInfo.blobClientRandom, (PCRYPT_DATA_BLOB)pbData);
case KP_SERVER_RANDOM:
return copy_data_blob(&pCryptKey->siSChannelInfo.blobServerRandom, (PCRYPT_DATA_BLOB)pbData);
default:
SetLastError(NTE_BAD_TYPE);
return FALSE;
......@@ -2258,6 +2596,9 @@ BOOL WINAPI RSAENH_CPGetKeyParam(HCRYPTPROV hProv, HCRYPTKEY hKey, DWORD dwParam
return copy_param(pbData, pdwDataLen, (CONST BYTE*)&pCryptKey->dwPermissions,
sizeof(DWORD));
case KP_ALGID:
return copy_param(pbData, pdwDataLen, (CONST BYTE*)&pCryptKey->aiAlgid, sizeof(DWORD));
default:
SetLastError(NTE_BAD_TYPE);
return FALSE;
......@@ -2414,7 +2755,7 @@ BOOL WINAPI RSAENH_CPGetProvParam(HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData,
BOOL WINAPI RSAENH_CPDeriveKey(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData,
DWORD dwFlags, HCRYPTKEY *phKey)
{
CRYPTKEY *pCryptKey;
CRYPTKEY *pCryptKey, *pMasterKey;
CRYPTHASH *pCryptHash;
BYTE abHashValue[RSAENH_MAX_HASH_SIZE*2];
DWORD dwLen;
......@@ -2441,51 +2782,102 @@ BOOL WINAPI RSAENH_CPDeriveKey(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseD
return FALSE;
}
if (GET_ALG_CLASS(Algid) != ALG_CLASS_DATA_ENCRYPT)
switch (GET_ALG_CLASS(Algid))
{
SetLastError(NTE_BAD_KEY);
return FALSE;
}
*phKey = new_key(hProv, Algid, dwFlags, &pCryptKey);
if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) return FALSE;
case ALG_CLASS_DATA_ENCRYPT:
*phKey = new_key(hProv, Algid, dwFlags, &pCryptKey);
if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) return FALSE;
/*
* We derive the key material from the hash.
* If the hash value is not large enough for the claimed key, we have to construct
* a larger binary value based on the hash. This is documented in MSDN: CryptDeriveKey.
*/
dwLen = RSAENH_MAX_HASH_SIZE;
RSAENH_CPGetHashParam(pCryptHash->hProv, hBaseData, HP_HASHVAL, abHashValue, &dwLen, 0);
/*
* We derive the key material from the hash.
* If the hash value is not large enough for the claimed key, we have to construct
* a larger binary value based on the hash. This is documented in MSDN: CryptDeriveKey.
*/
dwLen = RSAENH_MAX_HASH_SIZE;
RSAENH_CPGetHashParam(pCryptHash->hProv, hBaseData, HP_HASHVAL, abHashValue, &dwLen, 0);
if (dwLen < pCryptKey->dwKeyLen) {
BYTE pad1[RSAENH_HMAC_DEF_PAD_LEN], pad2[RSAENH_HMAC_DEF_PAD_LEN], old_hashval[RSAENH_MAX_HASH_SIZE];
DWORD i;
if (dwLen < pCryptKey->dwKeyLen) {
BYTE pad1[RSAENH_HMAC_DEF_PAD_LEN], pad2[RSAENH_HMAC_DEF_PAD_LEN];
BYTE old_hashval[RSAENH_MAX_HASH_SIZE];
DWORD i;
memcpy(old_hashval, pCryptHash->abHashValue, RSAENH_MAX_HASH_SIZE);
memcpy(old_hashval, pCryptHash->abHashValue, RSAENH_MAX_HASH_SIZE);
for (i=0; i<RSAENH_HMAC_DEF_PAD_LEN; i++) {
pad1[i] = RSAENH_HMAC_DEF_IPAD_CHAR ^ (i<dwLen ? abHashValue[i] : 0);
pad2[i] = RSAENH_HMAC_DEF_OPAD_CHAR ^ (i<dwLen ? abHashValue[i] : 0);
}
for (i=0; i<RSAENH_HMAC_DEF_PAD_LEN; i++) {
pad1[i] = RSAENH_HMAC_DEF_IPAD_CHAR ^ (i<dwLen ? abHashValue[i] : 0);
pad2[i] = RSAENH_HMAC_DEF_OPAD_CHAR ^ (i<dwLen ? abHashValue[i] : 0);
}
init_hash(pCryptHash);
update_hash(pCryptHash, pad1, RSAENH_HMAC_DEF_PAD_LEN);
finalize_hash(pCryptHash);
memcpy(abHashValue, pCryptHash->abHashValue, pCryptHash->dwHashSize);
init_hash(pCryptHash);
update_hash(pCryptHash, pad1, RSAENH_HMAC_DEF_PAD_LEN);
finalize_hash(pCryptHash);
memcpy(abHashValue, pCryptHash->abHashValue, pCryptHash->dwHashSize);
init_hash(pCryptHash);
update_hash(pCryptHash, pad2, RSAENH_HMAC_DEF_PAD_LEN);
finalize_hash(pCryptHash);
memcpy(abHashValue+pCryptHash->dwHashSize, pCryptHash->abHashValue,
pCryptHash->dwHashSize);
init_hash(pCryptHash);
update_hash(pCryptHash, pad2, RSAENH_HMAC_DEF_PAD_LEN);
finalize_hash(pCryptHash);
memcpy(abHashValue+pCryptHash->dwHashSize, pCryptHash->abHashValue,
pCryptHash->dwHashSize);
memcpy(pCryptHash->abHashValue, old_hashval, RSAENH_MAX_HASH_SIZE);
}
memcpy(pCryptHash->abHashValue, old_hashval, RSAENH_MAX_HASH_SIZE);
}
memcpy(pCryptKey->abKeyValue, abHashValue,
RSAENH_MIN(pCryptKey->dwKeyLen, sizeof(pCryptKey->abKeyValue)));
memcpy(pCryptKey->abKeyValue, abHashValue,
RSAENH_MIN(pCryptKey->dwKeyLen, sizeof(pCryptKey->abKeyValue)));
break;
case ALG_CLASS_MSG_ENCRYPT:
if (!lookup_handle(&handle_table, pCryptHash->hKey, RSAENH_MAGIC_KEY,
(OBJECTHDR**)&pMasterKey))
{
SetLastError(NTE_FAIL); /* FIXME error code */
return FALSE;
}
switch (Algid)
{
/* See RFC 2246, chapter 6.3 Key calculation */
case CALG_SCHANNEL_ENC_KEY:
*phKey = new_key(hProv, pMasterKey->siSChannelInfo.saEncAlg.Algid,
MAKELONG(LOWORD(dwFlags),pMasterKey->siSChannelInfo.saEncAlg.cBits),
&pCryptKey);
if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) return FALSE;
memcpy(pCryptKey->abKeyValue,
pCryptHash->abHashValue + (
2 * (pMasterKey->siSChannelInfo.saMACAlg.cBits / 8) +
((dwFlags & CRYPT_SERVER) ?
(pMasterKey->siSChannelInfo.saEncAlg.cBits / 8) : 0)),
pMasterKey->siSChannelInfo.saEncAlg.cBits / 8);
memcpy(pCryptKey->abInitVector,
pCryptHash->abHashValue + (
2 * (pMasterKey->siSChannelInfo.saMACAlg.cBits / 8) +
2 * (pMasterKey->siSChannelInfo.saEncAlg.cBits / 8) +
((dwFlags & CRYPT_SERVER) ? pCryptKey->dwBlockLen : 0)),
pCryptKey->dwBlockLen);
break;
case CALG_SCHANNEL_MAC_KEY:
*phKey = new_key(hProv, Algid,
MAKELONG(LOWORD(dwFlags),pMasterKey->siSChannelInfo.saMACAlg.cBits),
&pCryptKey);
if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) return FALSE;
memcpy(pCryptKey->abKeyValue,
pCryptHash->abHashValue + ((dwFlags & CRYPT_SERVER) ?
pMasterKey->siSChannelInfo.saMACAlg.cBits / 8 : 0),
pMasterKey->siSChannelInfo.saMACAlg.cBits / 8);
break;
default:
SetLastError(NTE_BAD_ALGID);
return FALSE;
}
break;
default:
SetLastError(NTE_BAD_ALGID);
return FALSE;
}
setup_key(pCryptKey);
return TRUE;
}
......@@ -2762,6 +3154,12 @@ BOOL WINAPI RSAENH_CPSetHashParam(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwPa
memcpy(pCryptHash->abHashValue, pbData, pCryptHash->dwHashSize);
pCryptHash->dwState = RSAENH_HASHSTATE_FINISHED;
return TRUE;
case HP_TLS1PRF_SEED:
return copy_data_blob(&pCryptHash->tpPRFParams.blobSeed, (PCRYPT_DATA_BLOB)pbData);
case HP_TLS1PRF_LABEL:
return copy_data_blob(&pCryptHash->tpPRFParams.blobLabel, (PCRYPT_DATA_BLOB)pbData);
default:
SetLastError(NTE_BAD_TYPE);
......
......@@ -1085,6 +1085,223 @@ static void test_verify_signature() {
if (!result) return;
}
void test_schannel_provider()
{
HCRYPTPROV hProv;
HCRYPTKEY hRSAKey, hMasterSecret, hServerWriteKey;
HCRYPTHASH hMasterHash, hTLS1PRF;
BOOL result;
DWORD dwLen;
SCHANNEL_ALG saSChannelAlg;
CRYPT_DATA_BLOB data_blob;
BYTE abPlainPrivateKey[596] = {
0x07, 0x02, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00,
0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00,
0x01, 0x00, 0x01, 0x00, 0x9b, 0x64, 0xef, 0xce,
0x31, 0x7c, 0xad, 0x56, 0xe2, 0x1e, 0x9b, 0x96,
0xb3, 0xf0, 0x29, 0x88, 0x6e, 0xa8, 0xc2, 0x11,
0x33, 0xd6, 0xcc, 0x8c, 0x69, 0xb2, 0x1a, 0xfd,
0xfc, 0x23, 0x21, 0x30, 0x4d, 0x29, 0x45, 0xb6,
0x3a, 0x67, 0x11, 0x80, 0x1a, 0x91, 0xf2, 0x9f,
0x01, 0xac, 0xc0, 0x11, 0x50, 0x5f, 0xcd, 0xb9,
0xad, 0x76, 0x9f, 0x6e, 0x91, 0x55, 0x71, 0xda,
0x97, 0x96, 0x96, 0x22, 0x75, 0xb4, 0x83, 0x44,
0x89, 0x9e, 0xf8, 0x44, 0x40, 0x7c, 0xd6, 0xcd,
0x9d, 0x88, 0xd6, 0x88, 0xbc, 0x56, 0xb7, 0x64,
0xe9, 0x2c, 0x24, 0x2f, 0x0d, 0x78, 0x55, 0x1c,
0xb2, 0x67, 0xb1, 0x5e, 0xbc, 0x0c, 0xcf, 0x1c,
0xe9, 0xd3, 0x9e, 0xa2, 0x15, 0x24, 0x73, 0xd6,
0xdb, 0x6f, 0x83, 0xb2, 0xf8, 0xbc, 0xe7, 0x47,
0x3b, 0x01, 0xef, 0x49, 0x08, 0x98, 0xd6, 0xa3,
0xf9, 0x25, 0x57, 0xe9, 0x39, 0x3c, 0x53, 0x30,
0x1b, 0xf2, 0xc9, 0x62, 0x31, 0x43, 0x5d, 0x84,
0x24, 0x30, 0x21, 0x9a, 0xad, 0xdb, 0x62, 0x91,
0xc8, 0x07, 0xd9, 0x2f, 0xd6, 0xb5, 0x37, 0x6f,
0xfe, 0x7a, 0x12, 0xbc, 0xd9, 0xd2, 0x2b, 0xbf,
0xd7, 0xb1, 0xfa, 0x7d, 0xc0, 0x48, 0xdd, 0x74,
0xdd, 0x55, 0x04, 0xa1, 0x8b, 0xc1, 0x0a, 0xc4,
0xa5, 0x57, 0x62, 0xee, 0x08, 0x8b, 0xf9, 0x19,
0x6c, 0x52, 0x06, 0xf8, 0x73, 0x0f, 0x24, 0xc9,
0x71, 0x9f, 0xc5, 0x45, 0x17, 0x3e, 0xae, 0x06,
0x81, 0xa2, 0x96, 0x40, 0x06, 0xbf, 0xeb, 0x9e,
0x80, 0x2b, 0x27, 0x20, 0x8f, 0x38, 0xcf, 0xeb,
0xff, 0x3b, 0x38, 0x41, 0x35, 0x69, 0x66, 0x13,
0x1d, 0x3c, 0x01, 0x3b, 0xf6, 0x37, 0xca, 0x9c,
0x61, 0x74, 0x98, 0xcf, 0xc9, 0x6e, 0xe8, 0x90,
0xc7, 0xb7, 0x33, 0xc0, 0x07, 0x3c, 0xf8, 0xc8,
0xf6, 0xf2, 0xd7, 0xf0, 0x21, 0x62, 0x58, 0x8a,
0x55, 0xbf, 0xa1, 0x2d, 0x3d, 0xa6, 0x69, 0xc5,
0x02, 0x19, 0x31, 0xf0, 0x94, 0x0f, 0x45, 0x5c,
0x95, 0x1b, 0x53, 0xbc, 0xf5, 0xb0, 0x1a, 0x8f,
0xbf, 0x40, 0xe0, 0xc7, 0x73, 0xe7, 0x72, 0x6e,
0xeb, 0xb1, 0x0f, 0x38, 0xc5, 0xf8, 0xee, 0x04,
0xed, 0x34, 0x1a, 0x10, 0xf9, 0x53, 0x34, 0xf3,
0x3e, 0xe6, 0x5c, 0xd1, 0x47, 0x65, 0xcd, 0xbd,
0xf1, 0x06, 0xcb, 0xb4, 0xb1, 0x26, 0x39, 0x9f,
0x71, 0xfe, 0x3d, 0xf8, 0x62, 0xab, 0x22, 0x8b,
0x0e, 0xdc, 0xb9, 0xe8, 0x74, 0x06, 0xfc, 0x8c,
0x25, 0xa1, 0xa9, 0xcf, 0x07, 0xf9, 0xac, 0x21,
0x01, 0x7b, 0x1c, 0xdc, 0x94, 0xbd, 0x47, 0xe1,
0xa0, 0x86, 0x59, 0x35, 0x6a, 0x6f, 0xb9, 0x70,
0x26, 0x7c, 0x3c, 0xfd, 0xbd, 0x81, 0x39, 0x36,
0x42, 0xc2, 0xbd, 0xbe, 0x84, 0x27, 0x9a, 0x69,
0x81, 0xda, 0x99, 0x27, 0xc2, 0x4f, 0x62, 0x33,
0xf4, 0x79, 0x30, 0xc5, 0x63, 0x54, 0x71, 0xf1,
0x47, 0x22, 0x25, 0x9b, 0x6c, 0x00, 0x2f, 0x1c,
0xf4, 0x1f, 0x85, 0xbc, 0xf6, 0x67, 0x6a, 0xe3,
0xf6, 0x55, 0x8a, 0xef, 0xd0, 0x0b, 0xd3, 0xa2,
0xc5, 0x51, 0x70, 0x15, 0x0a, 0xf0, 0x98, 0x4c,
0xb7, 0x19, 0x62, 0x0e, 0x2d, 0x2a, 0x4a, 0x7d,
0x7a, 0x0a, 0xc4, 0x17, 0xe3, 0x5d, 0x20, 0x52,
0xa9, 0x98, 0xc3, 0xaa, 0x11, 0xf6, 0xbf, 0x4c,
0x94, 0x99, 0x81, 0x89, 0xf0, 0x7f, 0x66, 0xaa,
0xc8, 0x88, 0xd7, 0x31, 0x84, 0x71, 0xb6, 0x64,
0x09, 0x76, 0x0b, 0x7f, 0x1a, 0x1f, 0x2e, 0xfe,
0xcd, 0x59, 0x2a, 0x54, 0x11, 0x84, 0xd4, 0x6a,
0x61, 0xdf, 0xaa, 0x76, 0x66, 0x9d, 0x82, 0x11,
0x56, 0x3d, 0xd2, 0x52, 0xe6, 0x42, 0x5a, 0x77,
0x92, 0x98, 0x34, 0xf3, 0x56, 0x6c, 0x96, 0x10,
0x40, 0x59, 0x16, 0xcb, 0x77, 0x61, 0xe3, 0xbf,
0x4b, 0xd4, 0x39, 0xfb, 0xb1, 0x4e, 0xc1, 0x74,
0xec, 0x7a, 0xea, 0x3d, 0x68, 0xbb, 0x0b, 0xe6,
0xc6, 0x06, 0xbf, 0xdd, 0x7f, 0x94, 0x42, 0xc0,
0x0f, 0xe4, 0x92, 0x33, 0x6c, 0x6e, 0x1b, 0xba,
0x73, 0xf9, 0x79, 0x84, 0xdf, 0x45, 0x00, 0xe4,
0x94, 0x88, 0x9d, 0x08, 0x89, 0xcf, 0xf2, 0xa4,
0xc5, 0x47, 0x45, 0x85, 0x86, 0xa5, 0xcc, 0xa8,
0xf2, 0x5d, 0x58, 0x07
};
BYTE abTLS1Master[140] = {
0x01, 0x02, 0x00, 0x00, 0x06, 0x4c, 0x00, 0x00,
0x00, 0xa4, 0x00, 0x00, 0x5b, 0x13, 0xc7, 0x68,
0xd8, 0x55, 0x23, 0x5d, 0xbc, 0xa6, 0x9d, 0x97,
0x0e, 0xcd, 0x6b, 0xcf, 0xc0, 0xdc, 0xc5, 0x53,
0x28, 0xa0, 0xca, 0xc1, 0x63, 0x4e, 0x3a, 0x24,
0x22, 0xe5, 0x4d, 0x15, 0xbb, 0xa5, 0x06, 0xc3,
0x98, 0x25, 0xdc, 0x35, 0xd3, 0xdb, 0xab, 0xb8,
0x44, 0x1b, 0xfe, 0x63, 0x88, 0x7c, 0x2e, 0x6d,
0x34, 0xd9, 0x0f, 0x7e, 0x2f, 0xc2, 0xb2, 0x6e,
0x56, 0xfa, 0xab, 0xb2, 0x88, 0xf6, 0x15, 0x6e,
0xa8, 0xcd, 0x70, 0x16, 0x94, 0x61, 0x07, 0x40,
0x9e, 0x25, 0x22, 0xf8, 0x64, 0x9f, 0xcc, 0x0b,
0xf1, 0x92, 0x4d, 0xfe, 0xc3, 0x5d, 0x52, 0xdb,
0x0f, 0xff, 0x12, 0x0f, 0x49, 0x43, 0x7d, 0xc6,
0x52, 0x61, 0xb0, 0x06, 0xc8, 0x1b, 0x90, 0xac,
0x09, 0x7e, 0x4b, 0x95, 0x69, 0x3b, 0x0d, 0x41,
0x1b, 0x4c, 0x65, 0x75, 0x4d, 0x85, 0x16, 0xc4,
0xd3, 0x1e, 0x82, 0xb3
};
BYTE abServerSecret[33] = "Super Secret Server Secret 12345";
BYTE abClientSecret[33] = "Super Secret Client Secret 12345";
BYTE abHashedHandshakes[37] = "123456789012345678901234567890123456";
BYTE abClientFinished[16] = "client finished";
BYTE abData[16] = "Wine rocks!";
static const BYTE abEncryptedData[16] = {
0x13, 0xd2, 0xdd, 0xeb, 0x6c, 0x3f, 0xbe, 0xb2,
0x04, 0x86, 0xb5, 0xe5, 0x08, 0xe5, 0xf3, 0x0d
};
static const BYTE abPRF[16] = {
0xa8, 0xb2, 0xa6, 0xef, 0x83, 0x4e, 0x74, 0xb1,
0xf3, 0xb1, 0x51, 0x5a, 0x1a, 0x2b, 0x11, 0x31
};
result = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_SCHANNEL, CRYPT_VERIFYCONTEXT);
ok (result, "%08lx\n", GetLastError());
if (!result) return;
/* To get deterministic results, we import the TLS1 master secret (which
* is typically generated from a random generator). Therefore, we need
* an RSA key. */
dwLen = (DWORD)sizeof(abPlainPrivateKey);
result = CryptImportKey(hProv, abPlainPrivateKey, dwLen, 0, 0, &hRSAKey);
ok (result, "%08lx\n", GetLastError());
if (!result) return;
dwLen = (DWORD)sizeof(abTLS1Master);
result = CryptImportKey(hProv, abTLS1Master, dwLen, hRSAKey, 0, &hMasterSecret);
ok (result, "%08lx\n", GetLastError());
if (!result) return;
/* Setting the TLS1 client and server random parameters, as well as the
* MAC and encryption algorithm parameters. */
data_blob.cbData = 33;
data_blob.pbData = abClientSecret;
result = CryptSetKeyParam(hMasterSecret, KP_CLIENT_RANDOM, (BYTE*)&data_blob, 0);
ok (result, "%08lx\n", GetLastError());
if (!result) return;
data_blob.cbData = 33;
data_blob.pbData = abServerSecret;
result = CryptSetKeyParam(hMasterSecret, KP_SERVER_RANDOM, (BYTE*)&data_blob, 0);
ok (result, "%08lx\n", GetLastError());
if (!result) return;
saSChannelAlg.dwUse = SCHANNEL_ENC_KEY;
saSChannelAlg.Algid = CALG_DES;
saSChannelAlg.cBits = 64;
saSChannelAlg.dwFlags = 0;
saSChannelAlg.dwReserved = 0;
result = CryptSetKeyParam(hMasterSecret, KP_SCHANNEL_ALG, (PBYTE)&saSChannelAlg, 0);
ok (result, "%08lx\n", GetLastError());
if (!result) return;
saSChannelAlg.dwUse = SCHANNEL_MAC_KEY;
saSChannelAlg.Algid = CALG_MD5;
saSChannelAlg.cBits = 128;
saSChannelAlg.dwFlags = 0;
saSChannelAlg.dwReserved = 0;
result = CryptSetKeyParam(hMasterSecret, KP_SCHANNEL_ALG, (PBYTE)&saSChannelAlg, 0);
ok (result, "%08lx\n", GetLastError());
if (!result) return;
/* Deriving a hash from the master secret. This is due to the CryptoAPI architecture.
* (Keys can only be derived from hashes, not from other keys.) */
result = CryptCreateHash(hProv, CALG_SCHANNEL_MASTER_HASH, hMasterSecret, 0, &hMasterHash);
ok (result, "%08lx\n", GetLastError());
if (!result) return;
/* Deriving the server write encryption key from the master hash */
result = CryptDeriveKey(hProv, CALG_SCHANNEL_ENC_KEY, hMasterHash, CRYPT_SERVER, &hServerWriteKey);
ok (result, "%08lx\n", GetLastError());
if (!result) return;
/* Encrypting some data with the server write encryption key and checking the result. */
dwLen = 12;
result = CryptEncrypt(hServerWriteKey, 0, TRUE, 0, abData, &dwLen, 16);
ok (result && (dwLen == 16) && !memcmp(abData, abEncryptedData, 16), "%08lx\n", GetLastError());
/* Second test case: Test the TLS1 pseudo random number function. */
result = CryptCreateHash(hProv, CALG_TLS1PRF, hMasterSecret, 0, &hTLS1PRF);
ok (result, "%08lx\n", GetLastError());
if (!result) return;
/* Set the label and seed parameters for the random number function */
data_blob.cbData = 36;
data_blob.pbData = abHashedHandshakes;
result = CryptSetHashParam(hTLS1PRF, HP_TLS1PRF_SEED, (BYTE*)&data_blob, 0);
ok (result, "%08lx\n", GetLastError());
if (!result) return;
data_blob.cbData = 15;
data_blob.pbData = abClientFinished;
result = CryptSetHashParam(hTLS1PRF, HP_TLS1PRF_LABEL, (BYTE*)&data_blob, 0);
ok (result, "%08lx\n", GetLastError());
if (!result) return;
/* Generate some pseudo random bytes and check if they are correct. */
dwLen = (DWORD)sizeof(abData);
result = CryptGetHashParam(hTLS1PRF, HP_HASHVAL, abData, &dwLen, 0);
ok (result && (dwLen==(DWORD)sizeof(abData)) && !memcmp(abData, abPRF, sizeof(abData)),
"%08lx\n", GetLastError());
CryptDestroyHash(hTLS1PRF);
CryptDestroyHash(hMasterHash);
CryptDestroyKey(hServerWriteKey);
CryptDestroyKey(hRSAKey);
CryptDestroyKey(hMasterSecret);
CryptReleaseContext(hProv, 0);
}
START_TEST(rsaenh)
{
if (!init_environment())
......@@ -1103,4 +1320,5 @@ START_TEST(rsaenh)
test_import_private();
test_verify_signature();
clean_up_environment();
test_schannel_provider();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment