Commit 8599fd77 authored by Juan Lang's avatar Juan Lang Committed by Alexandre Julliard

crypt32: Implement retrieving a hashed message's content.

parent 678fb8ac
......@@ -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.
......
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