mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-01 07:37:02 +00:00
crypt32: Implement retrieving a hashed message's content.
This commit is contained in:
parent
678fb8ac14
commit
8599fd7748
4 changed files with 150 additions and 57 deletions
|
@ -64,10 +64,25 @@ struct AsnConstructedItem
|
|||
BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
|
||||
|
||||
BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
|
||||
BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
|
||||
/* Like CRYPT_AsnEncodeAlgorithmId, but encodes parameters as an asn.1 NULL
|
||||
* if they are empty.
|
||||
*/
|
||||
BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
|
||||
/* Like CRYPT_AsnEncodePKCSContentInfo, but allows the OID to be NULL */
|
||||
BOOL WINAPI CRYPT_AsnEncodePKCSContentInfoInternal(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
|
||||
BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
|
||||
|
||||
/* Helper function to check *pcbEncoded, set it to the required size, and
|
||||
* optionally to allocate memory. Assumes pbEncoded is not NULL.
|
||||
|
|
|
@ -72,18 +72,12 @@ static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
|
|||
static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
|
||||
static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
|
||||
static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
|
||||
static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
|
||||
static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
|
||||
static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
|
||||
|
@ -394,13 +388,9 @@ static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Like CRYPT_AsnEncodeAlgorithmId, but encodes parameters as an asn.1 NULL
|
||||
* if they are empty.
|
||||
*/
|
||||
static BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams(
|
||||
DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
|
||||
DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
|
||||
DWORD *pcbEncoded)
|
||||
BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
const CRYPT_ALGORITHM_IDENTIFIER *algo =
|
||||
(const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
|
||||
|
@ -1449,6 +1439,31 @@ static BOOL WINAPI CRYPT_AsnEncodePKCSAttributes(DWORD dwCertEncodingType,
|
|||
return ret;
|
||||
}
|
||||
|
||||
BOOL WINAPI CRYPT_AsnEncodePKCSContentInfoInternal(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
const CRYPT_CONTENT_INFO *info = (const CRYPT_CONTENT_INFO *)pvStructInfo;
|
||||
struct AsnEncodeSequenceItem items[2] = {
|
||||
{ info->pszObjId, CRYPT_AsnEncodeOid, 0 },
|
||||
{ NULL, NULL, 0 },
|
||||
};
|
||||
struct AsnConstructedItem constructed = { 0 };
|
||||
DWORD cItem = 1;
|
||||
|
||||
if (info->Content.cbData)
|
||||
{
|
||||
constructed.tag = 0;
|
||||
constructed.pvStructInfo = &info->Content;
|
||||
constructed.encodeFunc = CRYPT_CopyEncodedBlob;
|
||||
items[cItem].pvStructInfo = &constructed;
|
||||
items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
|
||||
cItem++;
|
||||
}
|
||||
return CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
|
||||
cItem, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfo(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
|
@ -1463,26 +1478,9 @@ static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfo(DWORD dwCertEncodingType,
|
|||
if (!info->pszObjId)
|
||||
SetLastError(E_INVALIDARG);
|
||||
else
|
||||
{
|
||||
struct AsnEncodeSequenceItem items[2] = {
|
||||
{ info->pszObjId, CRYPT_AsnEncodeOid, 0 },
|
||||
{ NULL, NULL, 0 },
|
||||
};
|
||||
struct AsnConstructedItem constructed = { 0 };
|
||||
DWORD cItem = 1;
|
||||
|
||||
if (info->Content.cbData)
|
||||
{
|
||||
constructed.tag = 0;
|
||||
constructed.pvStructInfo = &info->Content;
|
||||
constructed.encodeFunc = CRYPT_CopyEncodedBlob;
|
||||
items[cItem].pvStructInfo = &constructed;
|
||||
items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
|
||||
cItem++;
|
||||
}
|
||||
ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
|
||||
cItem, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
|
||||
}
|
||||
ret = CRYPT_AsnEncodePKCSContentInfoInternal(dwCertEncodingType,
|
||||
lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
|
||||
pcbEncoded);
|
||||
}
|
||||
__EXCEPT_PAGE_FAULT
|
||||
{
|
||||
|
@ -2258,7 +2256,7 @@ static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
|
||||
BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
|
@ -2413,7 +2411,7 @@ static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
|
||||
BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
|
||||
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
|
||||
{
|
||||
|
|
|
@ -327,6 +327,7 @@ typedef struct _CHashEncodeMsg
|
|||
HCRYPTPROV prov;
|
||||
HCRYPTHASH hash;
|
||||
CRYPT_DATA_BLOB data;
|
||||
BOOL begun;
|
||||
} CHashEncodeMsg;
|
||||
|
||||
static void CHashEncodeMsg_Close(HCRYPTMSG hCryptMsg)
|
||||
|
@ -339,6 +340,70 @@ static void CHashEncodeMsg_Close(HCRYPTMSG hCryptMsg)
|
|||
CryptReleaseContext(msg->prov, 0);
|
||||
}
|
||||
|
||||
static BOOL CRYPT_EncodePKCSDigestedData(CHashEncodeMsg *msg, void *pvData,
|
||||
DWORD *pcbData)
|
||||
{
|
||||
BOOL ret;
|
||||
ALG_ID algID;
|
||||
DWORD size = sizeof(algID);
|
||||
|
||||
ret = CryptGetHashParam(msg->hash, HP_ALGID, (BYTE *)&algID, &size, 0);
|
||||
if (ret)
|
||||
{
|
||||
CRYPT_ALGORITHM_IDENTIFIER algoId = { 0 };
|
||||
DWORD version = 0; /* FIXME */
|
||||
struct AsnEncodeSequenceItem items[7] = { { 0 } };
|
||||
DWORD cItem = 0;
|
||||
CRYPT_DATA_BLOB hash = { 0, NULL };
|
||||
CRYPT_CONTENT_INFO contentInfo = { NULL, { 0, NULL } };
|
||||
char oid_rsa_data[] = szOID_RSA_data;
|
||||
|
||||
items[cItem].pvStructInfo = &version;
|
||||
items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
|
||||
cItem++;
|
||||
algoId.pszObjId = (LPSTR)CertAlgIdToOID(algID);
|
||||
/* FIXME: what about algoId.Parameters? */
|
||||
items[cItem].pvStructInfo = &algoId;
|
||||
items[cItem].encodeFunc = CRYPT_AsnEncodeAlgorithmIdWithNullParams;
|
||||
cItem++;
|
||||
/* Quirk: OID is only encoded messages if an update has happened */
|
||||
if (msg->begun)
|
||||
contentInfo.pszObjId = oid_rsa_data;
|
||||
if (!(msg->base.open_flags & CMSG_DETACHED_FLAG) && msg->data.cbData)
|
||||
{
|
||||
ret = CRYPT_AsnEncodeOctets(0, NULL, &msg->data,
|
||||
CRYPT_ENCODE_ALLOC_FLAG, NULL,
|
||||
(LPBYTE)&contentInfo.Content.pbData,
|
||||
&contentInfo.Content.cbData);
|
||||
}
|
||||
items[cItem].pvStructInfo = &contentInfo;
|
||||
items[cItem].encodeFunc =
|
||||
CRYPT_AsnEncodePKCSContentInfoInternal;
|
||||
cItem++;
|
||||
if (msg->base.finalized)
|
||||
{
|
||||
size = sizeof(DWORD);
|
||||
ret = CryptGetHashParam(msg->hash, HP_HASHSIZE,
|
||||
(LPBYTE)&hash.cbData, &size, 0);
|
||||
if (ret)
|
||||
{
|
||||
hash.pbData = CryptMemAlloc(hash.cbData);
|
||||
ret = CryptGetHashParam(msg->hash, HP_HASHVAL, hash.pbData,
|
||||
&hash.cbData, 0);
|
||||
}
|
||||
}
|
||||
items[cItem].pvStructInfo = &hash;
|
||||
items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
|
||||
cItem++;
|
||||
if (ret)
|
||||
ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem,
|
||||
0, NULL, pvData, pcbData);
|
||||
CryptMemFree(hash.pbData);
|
||||
LocalFree(contentInfo.Content.pbData);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL CHashEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
|
||||
DWORD dwIndex, void *pvData, DWORD *pcbData)
|
||||
{
|
||||
|
@ -350,6 +415,40 @@ static BOOL CHashEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
|
|||
|
||||
switch (dwParamType)
|
||||
{
|
||||
case CMSG_BARE_CONTENT_PARAM:
|
||||
if (msg->base.streamed)
|
||||
SetLastError(E_INVALIDARG);
|
||||
else
|
||||
ret = CRYPT_EncodePKCSDigestedData(msg, pvData, pcbData);
|
||||
break;
|
||||
case CMSG_CONTENT_PARAM:
|
||||
{
|
||||
CRYPT_CONTENT_INFO info;
|
||||
|
||||
ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
|
||||
&info.Content.cbData);
|
||||
if (ret)
|
||||
{
|
||||
info.Content.pbData = CryptMemAlloc(info.Content.cbData);
|
||||
if (info.Content.pbData)
|
||||
{
|
||||
ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
|
||||
info.Content.pbData, &info.Content.cbData);
|
||||
if (ret)
|
||||
{
|
||||
char oid_rsa_hashed[] = szOID_RSA_hashedData;
|
||||
|
||||
info.pszObjId = oid_rsa_hashed;
|
||||
ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
|
||||
PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
|
||||
}
|
||||
CryptMemFree(info.Content.pbData);
|
||||
}
|
||||
else
|
||||
ret = FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMSG_COMPUTED_HASH_PARAM:
|
||||
ret = CryptGetHashParam(msg->hash, HP_HASHVAL, (BYTE *)pvData, pcbData,
|
||||
0);
|
||||
|
@ -367,7 +466,6 @@ static BOOL CHashEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
|
|||
}
|
||||
break;
|
||||
default:
|
||||
FIXME("%d: stub\n", dwParamType);
|
||||
ret = FALSE;
|
||||
}
|
||||
return ret;
|
||||
|
@ -385,6 +483,7 @@ static BOOL CHashEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
|
|||
SetLastError(CRYPT_E_MSG_ERROR);
|
||||
else
|
||||
{
|
||||
msg->begun = TRUE;
|
||||
if (fFinal)
|
||||
msg->base.finalized = TRUE;
|
||||
if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
|
||||
|
@ -453,6 +552,7 @@ static HCRYPTMSG CHashEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
|
|||
msg->prov = prov;
|
||||
msg->data.cbData = 0;
|
||||
msg->data.pbData = NULL;
|
||||
msg->begun = FALSE;
|
||||
if (!CryptCreateHash(prov, algID, 0, 0, &msg->hash))
|
||||
{
|
||||
CryptMsgClose(msg);
|
||||
|
|
|
@ -768,12 +768,10 @@ static void test_hash_msg_get_param(void)
|
|||
/* Content and bare content are always gettable for non-streamed messages */
|
||||
size = 0;
|
||||
ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size);
|
||||
todo_wine {
|
||||
ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
|
||||
size = 0;
|
||||
ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size);
|
||||
ok(ret, "CryptMsgGetParam failed: %08x\n", GetLastError());
|
||||
}
|
||||
/* The hash is also available. */
|
||||
size = 0;
|
||||
ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
|
||||
|
@ -807,14 +805,12 @@ static void test_hash_msg_get_param(void)
|
|||
/* Streamed messages don't allow you to get the content or bare content. */
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &size);
|
||||
todo_wine {
|
||||
ok(!ret && GetLastError() == E_INVALIDARG,
|
||||
"Expected E_INVALIDARG, got %x\n", GetLastError());
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = CryptMsgGetParam(msg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &size);
|
||||
ok(!ret && GetLastError() == E_INVALIDARG,
|
||||
"Expected E_INVALIDARG, got %x\n", GetLastError());
|
||||
}
|
||||
/* The hash is still available. */
|
||||
size = 0;
|
||||
ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &size);
|
||||
|
@ -886,72 +882,56 @@ static void test_hash_msg_encoding(void)
|
|||
hashInfo.HashAlgorithm.pszObjId = oid_rsa_md5;
|
||||
msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, 0, CMSG_HASHED, &hashInfo,
|
||||
NULL, NULL);
|
||||
todo_wine {
|
||||
check_param("hash empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
|
||||
hashEmptyBareContent, sizeof(hashEmptyBareContent));
|
||||
check_param("hash empty content", msg, CMSG_CONTENT_PARAM,
|
||||
hashEmptyContent, sizeof(hashEmptyContent));
|
||||
}
|
||||
ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
|
||||
ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
|
||||
todo_wine {
|
||||
check_param("hash bare content", msg, CMSG_BARE_CONTENT_PARAM,
|
||||
hashBareContent, sizeof(hashBareContent));
|
||||
check_param("hash content", msg, CMSG_CONTENT_PARAM,
|
||||
hashContent, sizeof(hashContent));
|
||||
}
|
||||
CryptMsgClose(msg);
|
||||
/* Same test, but with CMSG_BARE_CONTENT_FLAG set */
|
||||
msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_BARE_CONTENT_FLAG,
|
||||
CMSG_HASHED, &hashInfo, NULL, NULL);
|
||||
todo_wine {
|
||||
check_param("hash empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
|
||||
hashEmptyBareContent, sizeof(hashEmptyBareContent));
|
||||
check_param("hash empty content", msg, CMSG_CONTENT_PARAM,
|
||||
hashEmptyContent, sizeof(hashEmptyContent));
|
||||
}
|
||||
ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
|
||||
ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
|
||||
todo_wine {
|
||||
check_param("hash bare content", msg, CMSG_BARE_CONTENT_PARAM,
|
||||
hashBareContent, sizeof(hashBareContent));
|
||||
check_param("hash content", msg, CMSG_CONTENT_PARAM,
|
||||
hashContent, sizeof(hashContent));
|
||||
}
|
||||
CryptMsgClose(msg);
|
||||
/* Same test, but with CMSG_DETACHED_FLAG set */
|
||||
msg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG,
|
||||
CMSG_HASHED, &hashInfo, NULL, NULL);
|
||||
todo_wine {
|
||||
check_param("detached hash empty bare content", msg,
|
||||
CMSG_BARE_CONTENT_PARAM, hashEmptyBareContent,
|
||||
sizeof(hashEmptyBareContent));
|
||||
check_param("detached hash empty content", msg, CMSG_CONTENT_PARAM,
|
||||
hashEmptyContent, sizeof(hashEmptyContent));
|
||||
}
|
||||
ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), FALSE);
|
||||
ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
|
||||
todo_wine {
|
||||
check_param("detached hash not final bare content", msg,
|
||||
CMSG_BARE_CONTENT_PARAM, detachedHashNonFinalBareContent,
|
||||
sizeof(detachedHashNonFinalBareContent));
|
||||
check_param("detached hash not final content", msg, CMSG_CONTENT_PARAM,
|
||||
detachedHashNonFinalContent, sizeof(detachedHashNonFinalContent));
|
||||
}
|
||||
ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
|
||||
ok(ret, "CryptMsgUpdate failed: %08x\n", GetLastError());
|
||||
todo_wine {
|
||||
check_param("detached hash bare content", msg, CMSG_BARE_CONTENT_PARAM,
|
||||
detachedHashBareContent, sizeof(detachedHashBareContent));
|
||||
check_param("detached hash content", msg, CMSG_CONTENT_PARAM,
|
||||
detachedHashContent, sizeof(detachedHashContent));
|
||||
}
|
||||
todo_wine {
|
||||
check_param("detached hash bare content", msg, CMSG_BARE_CONTENT_PARAM,
|
||||
detachedHashBareContent, sizeof(detachedHashBareContent));
|
||||
check_param("detached hash content", msg, CMSG_CONTENT_PARAM,
|
||||
detachedHashContent, sizeof(detachedHashContent));
|
||||
}
|
||||
CryptMsgClose(msg);
|
||||
/* In what appears to be a bug, streamed updates to hash messages don't
|
||||
* call the output function.
|
||||
|
|
Loading…
Reference in a new issue