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