wintrust(2/4): Implement SPC PE image encoding

Juan Lang juan.lang at gmail.com
Mon Aug 13 19:38:19 CDT 2007


--Juan
-------------- next part --------------
From a99c24d1f045b1f6f12d19cf29da2f43c526373f Mon Sep 17 00:00:00 2001
From: Juan Lang <juan.lang at gmail.com>
Date: Mon, 13 Aug 2007 14:35:13 -0700
Subject: [PATCH] Implement SPC PE image encoding
---
 dlls/wintrust/asn.c       |  230 ++++++++++++++++++++++++++++++++++++++++++++-
 dlls/wintrust/tests/asn.c |    7 -
 2 files changed, 227 insertions(+), 10 deletions(-)

diff --git a/dlls/wintrust/asn.c b/dlls/wintrust/asn.c
index f60fba8..02c0005 100644
--- a/dlls/wintrust/asn.c
+++ b/dlls/wintrust/asn.c
@@ -143,7 +143,8 @@ BOOL WINAPI WVTAsn1SpcLinkEncode(DWORD d
             DWORD fileNameLen, fileNameLenBytes;
             LPWSTR ptr;
 
-            fileNameLen = lstrlenW(link->u.pwszFile) * sizeof(WCHAR);
+            fileNameLen = link->u.pwszFile ?
+             lstrlenW(link->u.pwszFile) * sizeof(WCHAR) : 0;
             CRYPT_EncodeLen(fileNameLen, NULL, &fileNameLenBytes);
             CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, NULL,
              &lenBytes);
@@ -274,14 +275,237 @@ BOOL WINAPI WVTAsn1SpcLinkEncode(DWORD d
     return ret;
 }
 
+typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
+ BYTE *, DWORD *);
+
+struct AsnEncodeSequenceItem
+{
+    const void           *pvStructInfo;
+    CryptEncodeObjectFunc encodeFunc;
+    DWORD                 size; /* used during encoding, not for your use */
+};
+
+static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
+ struct AsnEncodeSequenceItem items[], DWORD cItem, BYTE *pbEncoded,
+ DWORD *pcbEncoded)
+{
+    BOOL ret;
+    DWORD i, dataLen = 0;
+
+    TRACE("%p, %d, %p, %d\n", items, cItem, pbEncoded, *pcbEncoded);
+    for (i = 0, ret = TRUE; ret && i < cItem; i++)
+    {
+        ret = items[i].encodeFunc(dwCertEncodingType, NULL,
+         items[i].pvStructInfo, NULL, &items[i].size);
+        /* Some functions propagate their errors through the size */
+        if (!ret)
+            *pcbEncoded = items[i].size;
+        dataLen += items[i].size;
+    }
+    if (ret)
+    {
+        DWORD lenBytes, bytesNeeded;
+
+        CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
+        bytesNeeded = 1 + lenBytes + dataLen;
+        if (!pbEncoded)
+            *pcbEncoded = bytesNeeded;
+        else if (*pcbEncoded < bytesNeeded)
+        {
+            *pcbEncoded = bytesNeeded;
+            SetLastError(ERROR_MORE_DATA);
+            ret = FALSE;
+        }
+        else
+        {
+            *pcbEncoded = bytesNeeded;
+            *pbEncoded++ = ASN_SEQUENCE;
+            CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
+            pbEncoded += lenBytes;
+            for (i = 0; ret && i < cItem; i++)
+            {
+                ret = items[i].encodeFunc(dwCertEncodingType, NULL,
+                 items[i].pvStructInfo, pbEncoded, &items[i].size);
+                /* Some functions propagate their errors through the size */
+                if (!ret)
+                    *pcbEncoded = items[i].size;
+                pbEncoded += items[i].size;
+            }
+        }
+    }
+    TRACE("returning %d\n", ret);
+    return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
+ DWORD *pcbEncoded)
+{
+    BOOL ret = FALSE;
+
+    __TRY
+    {
+        const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
+        DWORD bytesNeeded, lenBytes, dataBytes;
+        BYTE unusedBits;
+
+        /* yep, MS allows cUnusedBits to be >= 8 */
+        if (!blob->cUnusedBits)
+        {
+            dataBytes = blob->cbData;
+            unusedBits = 0;
+        }
+        else if (blob->cbData * 8 > blob->cUnusedBits)
+        {
+            dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
+            unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
+             blob->cUnusedBits;
+        }
+        else
+        {
+            dataBytes = 0;
+            unusedBits = 0;
+        }
+        CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
+        bytesNeeded = 1 + lenBytes + dataBytes + 1;
+        if (!pbEncoded)
+        {
+            *pcbEncoded = bytesNeeded;
+            ret = TRUE;
+        }
+        else if (*pcbEncoded < bytesNeeded)
+        {
+            *pcbEncoded = bytesNeeded;
+            SetLastError(ERROR_MORE_DATA);
+        }
+        else
+        {
+            ret = TRUE;
+            *pcbEncoded = bytesNeeded;
+            *pbEncoded++ = ASN_BITSTRING;
+            CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
+            pbEncoded += lenBytes;
+            *pbEncoded++ = unusedBits;
+            if (dataBytes)
+            {
+                BYTE mask = 0xff << unusedBits;
+
+                if (dataBytes > 1)
+                {
+                    memcpy(pbEncoded, blob->pbData, dataBytes - 1);
+                    pbEncoded += dataBytes - 1;
+                }
+                *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
+            }
+        }
+    }
+    __EXCEPT_PAGE_FAULT
+    {
+        SetLastError(STATUS_ACCESS_VIOLATION);
+    }
+    __ENDTRY
+    return ret;
+}
+
+struct AsnConstructedItem
+{
+    BYTE                  tag;
+    const void           *pvStructInfo;
+    CryptEncodeObjectFunc encodeFunc;
+};
+
+static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
+ DWORD *pcbEncoded)
+{
+    BOOL ret;
+    const struct AsnConstructedItem *item =
+     (const struct AsnConstructedItem *)pvStructInfo;
+    DWORD len;
+
+    if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
+     item->pvStructInfo, NULL, &len)))
+    {
+        DWORD dataLen, bytesNeeded;
+
+        CRYPT_EncodeLen(len, NULL, &dataLen);
+        bytesNeeded = 1 + dataLen + len;
+        if (!pbEncoded)
+            *pcbEncoded = bytesNeeded;
+        else if (*pcbEncoded < bytesNeeded)
+        {
+            *pcbEncoded = bytesNeeded;
+            SetLastError(ERROR_MORE_DATA);
+            ret = FALSE;
+        }
+        else
+        {
+            *pcbEncoded = bytesNeeded;
+            *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
+            CRYPT_EncodeLen(len, pbEncoded, &dataLen);
+            pbEncoded += dataLen;
+            ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
+             item->pvStructInfo, pbEncoded, &len);
+            if (!ret)
+            {
+                /* Some functions propagate their errors through the size */
+                *pcbEncoded = len;
+            }
+        }
+    }
+    else
+    {
+        /* Some functions propagate their errors through the size */
+        *pcbEncoded = len;
+    }
+    return ret;
+}
+
+
 BOOL WINAPI WVTAsn1SpcPeImageDataEncode(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
  DWORD *pcbEncoded)
 {
-    FIXME("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
+    const SPC_PE_IMAGE_DATA *imageData =
+     (const SPC_PE_IMAGE_DATA *)pvStructInfo;
+    BOOL ret = FALSE;
+
+    TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
      debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
      pcbEncoded);
-    return FALSE;
+
+    __TRY
+    {
+        struct AsnEncodeSequenceItem items[2] = {
+         { 0 }
+        };
+        struct AsnConstructedItem constructed = { 0, imageData->pFile,
+         WVTAsn1SpcLinkEncode };
+        DWORD cItem = 0;
+
+        if (imageData->Flags.cbData)
+        {
+            items[cItem].pvStructInfo = &imageData->Flags;
+            items[cItem].encodeFunc = CRYPT_AsnEncodeBits;
+            cItem++;
+        }
+        if (imageData->pFile)
+        {
+            items[cItem].pvStructInfo = &constructed;
+            items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
+            cItem++;
+        }
+
+        ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
+         pbEncoded, pcbEncoded);
+    }
+    __EXCEPT_PAGE_FAULT
+    {
+        SetLastError(STATUS_ACCESS_VIOLATION);
+    }
+    __ENDTRY
+    TRACE("returning %d\n", ret);
+    return ret;
 }
 
 /* Gets the number of length bytes from the given (leading) length byte */
diff --git a/dlls/wintrust/tests/asn.c b/dlls/wintrust/tests/asn.c
index b47f790..43b1cba 100644
--- a/dlls/wintrust/tests/asn.c
+++ b/dlls/wintrust/tests/asn.c
@@ -240,7 +240,6 @@ static void test_encodeSPCPEImage(void)
 
     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
      &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
-    todo_wine
     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
     if (ret)
     {
@@ -254,7 +253,6 @@ static void test_encodeSPCPEImage(void)
     SetLastError(0xdeadbeef);
     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
      &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
-    todo_wine
     ok(!ret && GetLastError () == E_INVALIDARG,
      "Expected E_INVALIDARG, got %08x\n", GetLastError());
     /* With just unused bits field set: */
@@ -262,7 +260,6 @@ static void test_encodeSPCPEImage(void)
     imageData.Flags.cUnusedBits = 1;
     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
      &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
-    todo_wine
     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
     if (ret)
     {
@@ -277,7 +274,6 @@ static void test_encodeSPCPEImage(void)
     imageData.Flags.cbData = sizeof(flags);
     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
      &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
-    todo_wine
     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
     if (ret)
     {
@@ -292,7 +288,6 @@ static void test_encodeSPCPEImage(void)
     imageData.pFile = &link;
     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
      &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
-    todo_wine
     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
     if (ret)
     {
@@ -306,7 +301,6 @@ static void test_encodeSPCPEImage(void)
     imageData.Flags.cbData = sizeof(flags);
     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
      &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
-    todo_wine
     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
     if (ret)
     {
@@ -320,7 +314,6 @@ static void test_encodeSPCPEImage(void)
     link.pwszFile = (LPWSTR)nihongoURL;
     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, SPC_PE_IMAGE_DATA_STRUCT,
      &imageData, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
-    todo_wine
     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
     if (ret)
     {
-- 
1.4.1


More information about the wine-patches mailing list