wintrust(6/7): Implement encoding SPC links

Juan Lang juan.lang at gmail.com
Fri Aug 10 16:41:49 CDT 2007


--Juan
-------------- next part --------------
From 8ac410ff3f4b23d6521c482c4f9084bd4448008b Mon Sep 17 00:00:00 2001
From: Juan Lang <juan.lang at gmail.com>
Date: Fri, 10 Aug 2007 14:06:39 -0700
Subject: [PATCH] Implement encoding SPC links
---
 dlls/wintrust/asn.c       |  222 +++++++++++++++++++++++++++++++++++++++++++++
 dlls/wintrust/tests/asn.c |    8 --
 2 files changed, 220 insertions(+), 10 deletions(-)

diff --git a/dlls/wintrust/asn.c b/dlls/wintrust/asn.c
index 77c42d1..7ae2544 100644
--- a/dlls/wintrust/asn.c
+++ b/dlls/wintrust/asn.c
@@ -44,14 +44,232 @@ #define n16toh(x) RtlUshortByteSwap(x)
 
 #endif
 
+static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+    DWORD bytesNeeded, significantBytes = 0;
+
+    if (len <= 0x7f)
+        bytesNeeded = 1;
+    else
+    {
+        DWORD temp;
+
+        for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
+         temp <<= 8, significantBytes--)
+            ;
+        bytesNeeded = significantBytes + 1;
+    }
+    if (!pbEncoded)
+    {
+        *pcbEncoded = bytesNeeded;
+        return TRUE;
+    }
+    if (*pcbEncoded < bytesNeeded)
+    {
+        SetLastError(ERROR_MORE_DATA);
+        return FALSE;
+    }
+    if (len <= 0x7f)
+        *pbEncoded = (BYTE)len;
+    else
+    {
+        DWORD i;
+
+        *pbEncoded++ = significantBytes | 0x80;
+        for (i = 0; i < significantBytes; i++)
+        {
+            *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
+            len >>= 8;
+        }
+    }
+    *pcbEncoded = bytesNeeded;
+    return TRUE;
+}
+
+static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
+ DWORD *pcbEncoded)
+{
+    BOOL ret = TRUE;
+    const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
+    DWORD bytesNeeded, lenBytes;
+
+    TRACE("(%d, %p), %p, %d\n", blob->cbData, blob->pbData, pbEncoded,
+     *pcbEncoded);
+
+    CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
+    bytesNeeded = 1 + lenBytes + blob->cbData;
+    if (!pbEncoded)
+        *pcbEncoded = bytesNeeded;
+    else if (*pcbEncoded < bytesNeeded)
+    {
+        *pcbEncoded = bytesNeeded;
+        SetLastError(ERROR_MORE_DATA);
+        ret = FALSE;
+    }
+    else
+    {
+        *pbEncoded++ = ASN_OCTETSTRING;
+        CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
+        pbEncoded += lenBytes;
+        if (blob->cbData)
+            memcpy(pbEncoded, blob->pbData, blob->cbData);
+    }
+    TRACE("returning %d\n", ret);
+    return ret;
+}
+
 BOOL WINAPI WVTAsn1SpcLinkEncode(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const void *pvStructInfo, BYTE *pbEncoded,
  DWORD *pcbEncoded)
 {
-    FIXME("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
+    BOOL ret = FALSE;
+
+    TRACE("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
      debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
      pcbEncoded);
-    return FALSE;
+
+    __TRY
+    {
+        const SPC_LINK *link = (const SPC_LINK *)pvStructInfo;
+        DWORD bytesNeeded, lenBytes;
+
+        switch (link->dwLinkChoice)
+        {
+        case SPC_FILE_LINK_CHOICE:
+        {
+            DWORD fileNameLen, fileNameLenBytes;
+            LPWSTR ptr;
+
+            fileNameLen = lstrlenW(link->u.pwszFile) * sizeof(WCHAR);
+            CRYPT_EncodeLen(fileNameLen, NULL, &fileNameLenBytes);
+            CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, NULL,
+             &lenBytes);
+            bytesNeeded = 2 + lenBytes + fileNameLenBytes + fileNameLen;
+            if (!pbEncoded)
+            {
+                *pcbEncoded = bytesNeeded;
+                ret = TRUE;
+            }
+            else if (*pcbEncoded < bytesNeeded)
+            {
+                SetLastError(ERROR_MORE_DATA);
+                *pcbEncoded = bytesNeeded;
+            }
+            else
+            {
+                *pcbEncoded = bytesNeeded;
+                *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 2;
+                CRYPT_EncodeLen(1 + fileNameLenBytes + fileNameLen, pbEncoded,
+                 &lenBytes);
+                pbEncoded += lenBytes;
+                *pbEncoded++ = ASN_CONTEXT;
+                CRYPT_EncodeLen(fileNameLen, pbEncoded, &fileNameLenBytes);
+                pbEncoded += fileNameLenBytes;
+                for (ptr = link->u.pwszFile; ptr && *ptr; ptr++)
+                {
+                    *(WCHAR *)pbEncoded = hton16(*ptr);
+                    pbEncoded += sizeof(WCHAR);
+                }
+                ret = TRUE;
+            }
+            break;
+        }
+        case SPC_MONIKER_LINK_CHOICE:
+        {
+            DWORD classIdLenBytes, dataLenBytes, dataLen;
+            CRYPT_DATA_BLOB classId = { sizeof(link->u.Moniker.ClassId),
+             (BYTE *)&link->u.Moniker.ClassId };
+
+            CRYPT_EncodeLen(classId.cbData, NULL, &classIdLenBytes);
+            CRYPT_EncodeLen(link->u.Moniker.SerializedData.cbData, NULL,
+             &dataLenBytes);
+            dataLen = 2 + classIdLenBytes + classId.cbData +
+             dataLenBytes + link->u.Moniker.SerializedData.cbData;
+            CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
+            bytesNeeded = 1 + dataLen + lenBytes;
+            if (!pbEncoded)
+            {
+                *pcbEncoded = bytesNeeded;
+                ret = TRUE;
+            }
+            else if (*pcbEncoded < bytesNeeded)
+            {
+                SetLastError(ERROR_MORE_DATA);
+                *pcbEncoded = bytesNeeded;
+            }
+            else
+            {
+                DWORD size;
+
+                *pcbEncoded = bytesNeeded;
+                *pbEncoded++ = ASN_CONSTRUCTOR | ASN_CONTEXT | 1;
+                CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
+                pbEncoded += lenBytes;
+                size = 1 + classIdLenBytes + classId.cbData;
+                CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL, &classId,
+                 pbEncoded, &size);
+                pbEncoded += size;
+                size = 1 + dataLenBytes + link->u.Moniker.SerializedData.cbData;
+                CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, NULL,
+                 &link->u.Moniker.SerializedData, pbEncoded, &size);
+                pbEncoded += size;
+                ret = TRUE;
+            }
+            break;
+        }
+        case SPC_URL_LINK_CHOICE:
+        {
+            LPWSTR ptr;
+            DWORD urlLen;
+
+            /* Check for invalid characters in URL */
+            ret = TRUE;
+            urlLen = 0;
+            for (ptr = link->u.pwszUrl; ptr && *ptr && ret; ptr++)
+                if (*ptr > 0x7f)
+                {
+                    *pcbEncoded = 0;
+                    SetLastError(CRYPT_E_INVALID_IA5_STRING);
+                    ret = FALSE;
+                }
+                else
+                    urlLen++;
+            if (ret)
+            {
+                CRYPT_EncodeLen(urlLen, NULL, &lenBytes);
+                bytesNeeded = 1 + lenBytes + urlLen;
+                if (!pbEncoded)
+                    *pcbEncoded = bytesNeeded;
+                else if (*pcbEncoded < bytesNeeded)
+                {
+                    SetLastError(ERROR_MORE_DATA);
+                    *pcbEncoded = bytesNeeded;
+                    ret = FALSE;
+                }
+                else
+                {
+                    *pcbEncoded = bytesNeeded;
+                    *pbEncoded++ = ASN_CONTEXT;
+                    CRYPT_EncodeLen(urlLen, pbEncoded, &lenBytes);
+                    pbEncoded += lenBytes;
+                    for (ptr = link->u.pwszUrl; ptr && *ptr; ptr++)
+                        *pbEncoded++ = (BYTE)*ptr;
+                }
+            }
+            break;
+        }
+        default:
+            SetLastError(E_INVALIDARG);
+        }
+    }
+    __EXCEPT_PAGE_FAULT
+    {
+        SetLastError(STATUS_ACCESS_VIOLATION);
+    }
+    __ENDTRY
+    TRACE("returning %d\n", ret);
+    return ret;
 }
 
 BOOL WINAPI WVTAsn1SpcPeImageDataEncode(DWORD dwCertEncodingType,
diff --git a/dlls/wintrust/tests/asn.c b/dlls/wintrust/tests/asn.c
index 01e6bd0..e5e7f6e 100644
--- a/dlls/wintrust/tests/asn.c
+++ b/dlls/wintrust/tests/asn.c
@@ -55,13 +55,11 @@ static void test_encodeSPCLink(void)
     SetLastError(0xdeadbeef);
     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link,
      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
-    todo_wine
     ok(!ret && GetLastError() == E_INVALIDARG,
      "Expected E_INVALIDARG, got %08x\n", GetLastError());
     link.dwLinkChoice = SPC_URL_LINK_CHOICE;
     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link,
      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
-    todo_wine
     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
     if (ret)
     {
@@ -75,18 +73,15 @@ static void test_encodeSPCLink(void)
     SetLastError(0xdeadbeef);
     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link,
      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
-    todo_wine
     ok(!ret && GetLastError() == CRYPT_E_INVALID_IA5_STRING,
      "Expected CRYPT_E_INVALID_IA5_STRING, got %08x\n", GetLastError());
     /* Unlike the crypt32 string encoding routines, size is not set to the
      * index of the first invalid character.
      */
-    todo_wine
     ok(size == 0, "Expected size 0, got %d\n", size);
     link.pwszUrl = url;
     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link,
      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
-    todo_wine
     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
     if (ret)
     {
@@ -98,7 +93,6 @@ static void test_encodeSPCLink(void)
     link.pwszFile = (LPWSTR)nihongoURL;
     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link,
      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
-    todo_wine
     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
     if (ret)
     {
@@ -110,7 +104,6 @@ static void test_encodeSPCLink(void)
     memset(&link.Moniker, 0, sizeof(link.Moniker));
     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link,
      CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
-    todo_wine
     ok(ret, "CryptEncodeObjectEx failed: %08x\n", GetLastError());
     if (ret)
     {
@@ -123,7 +116,6 @@ static void test_encodeSPCLink(void)
     link.Moniker.SerializedData.cbData = sizeof(data);
     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, SPC_LINK_STRUCT, &link,
      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