crypt32(21/25): Implement retrieving a hashed message's content
(with patch)
Juan Lang
juan.lang at gmail.com
Thu Jul 12 17:31:54 CDT 2007
Again, depends on patch 20/25 in this series.
--Juan
-------------- next part --------------
From 074792d6129f09975fc2e80209851f7e927c6e7f Mon Sep 17 00:00:00 2001
From: Juan Lang <juanlang at juan.corp.google.com>
Date: Thu, 12 Jul 2007 14:59:27 -0700
Subject: [PATCH] Implement retrieving a hashed message's content
---
dlls/crypt32/crypt32_private.h | 17 ++++++-
dlls/crypt32/encode.c | 68 +++++++++++++--------------
dlls/crypt32/msg.c | 102 ++++++++++++++++++++++++++++++++++++++++
dlls/crypt32/tests/msg.c | 20 --------
4 files changed, 150 insertions(+), 57 deletions(-)
diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h
index 17f7172..477d01d 100644
--- a/dlls/crypt32/crypt32_private.h
+++ b/dlls/crypt32/crypt32_private.h
@@ -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.
diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c
index 3821d36..0a1affc 100644
--- a/dlls/crypt32/encode.c
+++ b/dlls/crypt32/encode.c
@@ -72,18 +72,12 @@ static BOOL WINAPI CRYPT_AsnEncodeBool(D
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_AsnEncodeValidi
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_AsnEncodePKCSAt
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_AsnEncodePKCSCo
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_AsnEncodeRsaPub
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_AsnEncodeBitsSw
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)
{
diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c
index 36194a3..4c495de 100644
--- a/dlls/crypt32/msg.c
+++ b/dlls/crypt32/msg.c
@@ -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(HCRYPTM
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(HCRY
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(HCRY
}
break;
default:
- FIXME("%d: stub\n", dwParamType);
ret = FALSE;
}
return ret;
@@ -385,6 +483,7 @@ static BOOL CHashEncodeMsg_Update(HCRYPT
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(DWO
msg->prov = prov;
msg->data.cbData = 0;
msg->data.pbData = NULL;
+ msg->begun = FALSE;
if (!CryptCreateHash(prov, algID, 0, 0, &msg->hash))
{
CryptMsgClose(msg);
diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c
index e1fcd7a..5831d7b 100644
--- a/dlls/crypt32/tests/msg.c
+++ b/dlls/crypt32/tests/msg.c
@@ -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.
--
1.4.1
More information about the wine-patches
mailing list