crypt32(12/20): Partially implement encoding signed messages

Juan Lang juan.lang at gmail.com
Mon Jul 23 20:30:40 CDT 2007


--Juan
-------------- next part --------------
From 62421d182d0d2a68c07a3ba585e388149a8e0841 Mon Sep 17 00:00:00 2001
From: Juan Lang <juanlang at juan.corp.google.com>
Date: Mon, 23 Jul 2007 18:11:17 -0700
Subject: [PATCH] Partially implement encoding signed messages
---
 dlls/crypt32/crypt32_private.h |   17 ++++++
 dlls/crypt32/encode.c          |   82 +++++++++++++++++++++++++++++++
 dlls/crypt32/msg.c             |  106 +++++++++++++++++++++++++++++++++++-----
 dlls/crypt32/tests/msg.c       |    4 --
 4 files changed, 193 insertions(+), 16 deletions(-)

diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h
index a26b366..9b1fc27 100644
--- a/dlls/crypt32/crypt32_private.h
+++ b/dlls/crypt32/crypt32_private.h
@@ -82,6 +82,23 @@ typedef struct _CRYPT_DIGESTED_DATA
 BOOL CRYPT_AsnEncodePKCSDigestedData(CRYPT_DIGESTED_DATA *digestedData,
  void *pvData, DWORD *pcbData);
 
+typedef struct _CRYPT_SIGNED_INFO
+{
+    DWORD              version;
+    DWORD              cCertEncoded;
+    PCERT_BLOB         rgCertEncoded;
+    DWORD              cCrlEncoded;
+    PCRL_BLOB          rgCrlEncoded;
+    DWORD              cAttrCertEncoded;
+    PCERT_BLOB         rgAttrCertEncoded;
+    CRYPT_CONTENT_INFO content;
+    DWORD              cSignerInfo;
+    PCMSG_SIGNER_INFO  rgSignerInfo;
+} CRYPT_SIGNED_INFO;
+
+BOOL CRYPT_AsnEncodePKCSSignedInfo(CRYPT_SIGNED_INFO *, void *pvData,
+ DWORD *pcbData);
+
 /* Helper function to check *pcbEncoded, set it to the required size, and
  * optionally to allocate memory.  Assumes pbEncoded is not NULL.
  * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c
index e2fcc99..d63b389 100644
--- a/dlls/crypt32/encode.c
+++ b/dlls/crypt32/encode.c
@@ -1540,6 +1540,88 @@ BOOL CRYPT_AsnEncodePKCSDigestedData(CRY
      sizeof(items) / sizeof(items[0]), 0, NULL, pvData, pcbData);
 }
 
+BOOL CRYPT_AsnEncodePKCSSignedInfo(CRYPT_SIGNED_INFO *signedInfo, void *pvData,
+ DWORD *pcbData)
+{
+    struct AsnEncodeSequenceItem items[7] = {
+     { &signedInfo->version, CRYPT_AsnEncodeInt, 0 },
+    };
+    CRYPT_SET_OF digestAlgorithmsSet = { 0, NULL }, signerSet = { 0, NULL };
+    DWORD i, cItem = 1;
+    BOOL ret = TRUE;
+
+    if (signedInfo->cCertEncoded)
+        FIXME("unimplemented for certs\n");
+    if (signedInfo->cCrlEncoded)
+        FIXME("unimplemented for CRLs\n");
+    if (signedInfo->cAttrCertEncoded)
+        FIXME("unimplemented for attr certs\n");
+    if (signedInfo->cSignerInfo)
+    {
+        digestAlgorithmsSet.cValue = signedInfo->cSignerInfo;
+        digestAlgorithmsSet.rgValue =
+         CryptMemAlloc(digestAlgorithmsSet.cValue * sizeof(CRYPT_DER_BLOB));
+        if (digestAlgorithmsSet.rgValue)
+        {
+            memset(digestAlgorithmsSet.rgValue, 0,
+             digestAlgorithmsSet.cValue * sizeof(CRYPT_DER_BLOB));
+            for (i = 0; ret && i < digestAlgorithmsSet.cValue; i++)
+                ret = CRYPT_AsnEncodeAlgorithmIdWithNullParams(0, NULL,
+                 &signedInfo->rgSignerInfo[i].HashAlgorithm,
+                 CRYPT_ENCODE_ALLOC_FLAG, NULL,
+                 (BYTE *)&digestAlgorithmsSet.rgValue[i].pbData,
+                 &digestAlgorithmsSet.rgValue[i].cbData);
+        }
+        else
+            ret = FALSE;
+        if (ret)
+        {
+            items[cItem].pvStructInfo = &digestAlgorithmsSet;
+            items[cItem].encodeFunc = CRYPT_DEREncodeSet;
+            cItem++;
+        }
+    }
+    items[cItem].pvStructInfo = &signedInfo->content;
+    items[cItem].encodeFunc = CRYPT_AsnEncodePKCSContentInfoInternal;
+    cItem++;
+    if (ret && signedInfo->cSignerInfo)
+    {
+        signerSet.cValue = signedInfo->cSignerInfo;
+        signerSet.rgValue =
+         CryptMemAlloc(signerSet.cValue * sizeof(CRYPT_DER_BLOB));
+        if (signerSet.rgValue)
+        {
+            memset(signerSet.rgValue, 0,
+             signerSet.cValue * sizeof(CRYPT_DER_BLOB));
+            for (i = 0; ret && i < signerSet.cValue; i++)
+                ret = CryptEncodeObjectEx(
+                 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS7_SIGNER_INFO,
+                 &signedInfo->rgSignerInfo[i], CRYPT_ENCODE_ALLOC_FLAG, NULL,
+                 &signerSet.rgValue[i].pbData, &signerSet.rgValue[i].cbData);
+        }
+        else
+            ret = FALSE;
+        if (ret)
+        {
+            items[cItem].pvStructInfo = &signerSet;
+            items[cItem].encodeFunc = CRYPT_DEREncodeSet;
+            cItem++;
+        }
+    }
+    if (ret)
+        ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
+         pvData, pcbData);
+
+    for (i = 0; i < digestAlgorithmsSet.cValue; i++)
+        LocalFree(digestAlgorithmsSet.rgValue[i].pbData);
+    CryptMemFree(digestAlgorithmsSet.rgValue);
+    for (i = 0; i < signerSet.cValue; i++)
+        LocalFree(signerSet.rgValue[i].pbData);
+    CryptMemFree(signerSet.rgValue);
+
+    return ret;
+}
+
 static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfo(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 226c04b..cd1dd39 100644
--- a/dlls/crypt32/msg.c
+++ b/dlls/crypt32/msg.c
@@ -627,25 +627,27 @@ static BOOL CRYPT_CopyBlob(CRYPT_DATA_BL
     return ret;
 }
 
-static BOOL CRYPT_CopyAttribute(CRYPT_ATTRIBUTE *out, const CRYPT_ATTRIBUTE *in)
+typedef struct _BlobArray
+{
+    DWORD            cBlobs;
+    PCRYPT_DATA_BLOB blobs;
+} BlobArray;
+
+static BOOL CRYPT_CopyBlobArray(BlobArray *out, const BlobArray *in)
 {
     BOOL ret = TRUE;
 
-    /* Assumption:  algorithm IDs will point to static strings, not stack-based
-     * ones, so copying the pointer values is safe.
-     */
-    out->pszObjId = in->pszObjId;
-    out->cValue = in->cValue;
-    if (out->cValue)
+    out->cBlobs = in->cBlobs;
+    if (out->cBlobs)
     {
-        out->rgValue = CryptMemAlloc(out->cValue * sizeof(CRYPT_DATA_BLOB));
-        if (out->rgValue)
+        out->blobs = CryptMemAlloc(out->cBlobs * sizeof(CRYPT_DATA_BLOB));
+        if (out->blobs)
         {
             DWORD i;
 
-            memset(out->rgValue, 0, out->cValue * sizeof(CRYPT_DATA_BLOB));
-            for (i = 0; ret && i < out->cValue; i++)
-                ret = CRYPT_CopyBlob(&out->rgValue[i], &in->rgValue[i]);
+            memset(out->blobs, 0, out->cBlobs * sizeof(CRYPT_DATA_BLOB));
+            for (i = 0; ret && i < out->cBlobs; i++)
+                ret = CRYPT_CopyBlob(&out->blobs[i], &in->blobs[i]);
         }
         else
             ret = FALSE;
@@ -653,6 +655,25 @@ static BOOL CRYPT_CopyAttribute(CRYPT_AT
     return ret;
 }
 
+static void CRYPT_FreeBlobArray(BlobArray *array)
+{
+    DWORD i;
+
+    for (i = 0; i < array->cBlobs; i++)
+        CryptMemFree(array->blobs[i].pbData);
+    CryptMemFree(array->blobs);
+}
+
+static BOOL CRYPT_CopyAttribute(CRYPT_ATTRIBUTE *out, const CRYPT_ATTRIBUTE *in)
+{
+    /* Assumption:  algorithm IDs will point to static strings, not stack-based
+     * ones, so copying the pointer values is safe.
+     */
+    out->pszObjId = in->pszObjId;
+    return CRYPT_CopyBlobArray((BlobArray *)&out->cValue,
+     (const BlobArray *)&in->cValue);
+}
+
 static BOOL CRYPT_CopyAttributes(CRYPT_ATTRIBUTES *out,
  const CRYPT_ATTRIBUTES *in)
 {
@@ -749,6 +770,10 @@ typedef struct _CSignedEncodeMsg
     CRYPT_DATA_BLOB data;
     DWORD           cSigners;
     CSignerInfo    *signers;
+    DWORD           cCertEncoded;
+    PCERT_BLOB      rgCertEncoded;
+    DWORD           cCrlEncoded;
+    PCRL_BLOB       rgCrlEncoded;
 } CSignedEncodeMsg;
 
 static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
@@ -757,6 +782,8 @@ static void CSignedEncodeMsg_Close(HCRYP
     DWORD i;
 
     CryptMemFree(msg->data.pbData);
+    CRYPT_FreeBlobArray((BlobArray *)&msg->cCertEncoded);
+    CRYPT_FreeBlobArray((BlobArray *)&msg->cCrlEncoded);
     for (i = 0; i < msg->cSigners; i++)
         CSignerInfo_Free(&msg->signers[i]);
     CryptMemFree(msg->signers);
@@ -770,6 +797,55 @@ static BOOL CSignedEncodeMsg_GetParam(HC
 
     switch (dwParamType)
     {
+    case CMSG_BARE_CONTENT_PARAM:
+    {
+        CRYPT_SIGNED_INFO info;
+        char oid_rsa_data[] = szOID_RSA_data;
+
+        /* Note: needs to change if CMS fields are supported */
+        info.version = CMSG_SIGNED_DATA_V1;
+        info.cCertEncoded = msg->cCertEncoded;
+        info.rgCertEncoded = msg->rgCertEncoded;
+        info.cCrlEncoded = msg->cCrlEncoded;
+        info.rgCrlEncoded = msg->rgCrlEncoded;
+        info.cAttrCertEncoded = 0;
+        info.cSignerInfo = msg->cSigners;
+        /* Quirk:  OID is only encoded messages if an update has happened */
+        if (msg->base.state != MsgStateInit)
+            info.content.pszObjId = oid_rsa_data;
+        else
+            info.content.pszObjId = NULL;
+        if (msg->data.cbData)
+        {
+            CRYPT_DATA_BLOB blob = { msg->data.cbData, msg->data.pbData };
+
+            ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
+             &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL,
+             &info.content.Content.pbData, &info.content.Content.cbData);
+        }
+        else
+        {
+            info.content.Content.cbData = 0;
+            info.content.Content.pbData = NULL;
+            ret = TRUE;
+        }
+        if (ret)
+        {
+            info.rgSignerInfo =
+             CryptMemAlloc(msg->cSigners * sizeof(CMSG_SIGNER_INFO));
+            if (info.rgSignerInfo)
+            {
+                DWORD i;
+
+                for (i = 0; i < info.cSignerInfo; i++)
+                    info.rgSignerInfo[i] = msg->signers[i].info;
+                ret = CRYPT_AsnEncodePKCSSignedInfo(&info, pvData, pcbData);
+                CryptMemFree(info.rgSignerInfo);
+            }
+            LocalFree(info.content.Content.pbData);
+        }
+        break;
+    }
     case CMSG_COMPUTED_HASH_PARAM:
         if (dwIndex >= msg->cSigners)
             SetLastError(CRYPT_E_INVALID_INDEX);
@@ -931,6 +1007,12 @@ static HCRYPTMSG CSignedEncodeMsg_Open(D
             else
                 ret = FALSE;
         }
+        if (ret)
+            ret = CRYPT_CopyBlobArray((BlobArray *)&msg->cCertEncoded,
+             (const BlobArray *)&info->cCertEncoded);
+        if (ret)
+            ret = CRYPT_CopyBlobArray((BlobArray *)&msg->cCrlEncoded,
+             (const BlobArray *)&info->cCrlEncoded);
         if (!ret)
         {
             CSignedEncodeMsg_Close(msg);
diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c
index 18c758b..7a244b5 100644
--- a/dlls/crypt32/tests/msg.c
+++ b/dlls/crypt32/tests/msg.c
@@ -1289,7 +1289,6 @@ static void test_signed_msg_encoding(voi
      CMSG_DETACHED_FLAG, CMSG_SIGNED, &signInfo, NULL, NULL);
     ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
 
-    todo_wine
     check_param("detached signed empty bare content", msg,
      CMSG_BARE_CONTENT_PARAM, signedEmptyBareContent,
      sizeof(signedEmptyBareContent));
@@ -1300,7 +1299,6 @@ static void test_signed_msg_encoding(voi
     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
     check_param("detached signed hash", msg, CMSG_COMPUTED_HASH_PARAM,
      signedHash, sizeof(signedHash));
-    todo_wine
     check_param("detached signed bare content", msg, CMSG_BARE_CONTENT_PARAM,
      detachedSignedBareContent, sizeof(detachedSignedBareContent));
     todo_wine
@@ -1317,7 +1315,6 @@ static void test_signed_msg_encoding(voi
      NULL, NULL);
     ok(msg != NULL, "CryptMsgOpenToEncode failed: %x\n", GetLastError());
 
-    todo_wine
     check_param("signed empty bare content", msg, CMSG_BARE_CONTENT_PARAM,
      signedEmptyBareContent, sizeof(signedEmptyBareContent));
     todo_wine
@@ -1325,7 +1322,6 @@ static void test_signed_msg_encoding(voi
      signedEmptyContent, sizeof(signedEmptyContent));
     ret = CryptMsgUpdate(msg, msgData, sizeof(msgData), TRUE);
     ok(ret, "CryptMsgUpdate failed: %x\n", GetLastError());
-    todo_wine
     check_param("signed bare content", msg, CMSG_BARE_CONTENT_PARAM,
      signedBareContent, sizeof(signedBareContent));
     todo_wine
-- 
1.4.1


More information about the wine-patches mailing list