Sync to Wine-0_9_4:
authorGé van Geldorp <ge@gse.nl>
Mon, 26 Dec 2005 23:05:15 +0000 (23:05 +0000)
committerGé van Geldorp <ge@gse.nl>
Mon, 26 Dec 2005 23:05:15 +0000 (23:05 +0000)
Juan Lang <juan_lang@yahoo.com>
- crypt32: Implement more implicit properties, with tests.
- crypt32: Implement CRLDistPoints encoding/decoding.
- rewrite sequence decoding to support context-specific tags, and
  eliminate duplicated code
- implement encoding and decoding of CRLDistPoints
- crypt32: Decode cleanups.
- implement a helper to decode sequences of like types
- use helper functions wherever applicable when decoding
- correct "expected" vs. "got" usage in tests
- fix a few other small bugs
Alexandre Julliard <julliard@winehq.org>
- Take advantage of the __EXCEPT_PAGE_FAULT macro.

svn path=/trunk/; revision=20347

reactos/lib/crypt32/cert.c
reactos/lib/crypt32/encode.c
reactos/w32api/include/wincrypt.h

index 9eaaa19..4f822d1 100644 (file)
@@ -313,14 +313,6 @@ static BOOL WINAPI CRYPT_SetCertificateContextProperty(
 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
  DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
 
-/* filter for page-fault exceptions */
-static WINE_EXCEPTION_FILTER(page_fault)
-{
-    if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
-        return EXCEPTION_EXECUTE_HANDLER;
-    return EXCEPTION_CONTINUE_SEARCH;
-}
-
 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
  DWORD dwFlags, CertStoreType type)
 {
@@ -1885,6 +1877,22 @@ DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
     return ret;
 }
 
+static BOOL CRYPT_GetCertHashProp(PWINE_CERT_CONTEXT context, DWORD dwPropId,
+ ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
+ DWORD *pcbData)
+{
+    BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
+     pcbData);
+    if (ret)
+    {
+        CRYPT_DATA_BLOB blob = { *pcbData, pvData };
+
+        ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
+         0, &blob);
+    }
+    return ret;
+}
+
 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
  PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
 {
@@ -1927,26 +1935,34 @@ static BOOL WINAPI CRYPT_GetCertificateContextProperty(
         switch (dwPropId)
         {
         case CERT_SHA1_HASH_PROP_ID:
-            ret = CryptHashCertificate(0, CALG_SHA1, 0,
+            ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_SHA1,
              context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
              pcbData);
-            if (ret)
-            {
-                CRYPT_DATA_BLOB blob = { *pcbData, pvData };
-
-                ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
-                 0, &blob);
-            }
             break;
-        case CERT_KEY_PROV_INFO_PROP_ID:
         case CERT_MD5_HASH_PROP_ID:
-        case CERT_SIGNATURE_HASH_PROP_ID:
-        case CERT_KEY_IDENTIFIER_PROP_ID:
+            ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
+             context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
+             pcbData);
+            break;
+        case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
+            ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
+             context->cert.pCertInfo->Subject.pbData,
+             context->cert.pCertInfo->Subject.cbData,
+             pvData, pcbData);
+            break;
         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
+            ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
+             context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
+             context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
+             pvData, pcbData);
+            break;
+        case CERT_SIGNATURE_HASH_PROP_ID:
         case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
-        case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
             FIXME("implicit property %ld\n", dwPropId);
+            SetLastError(CRYPT_E_NOT_FOUND);
             break;
+        default:
+            SetLastError(CRYPT_E_NOT_FOUND);
         }
     }
     LeaveCriticalSection(&context->cs);
@@ -2108,6 +2124,7 @@ static BOOL WINAPI CRYPT_SetCertificateContextProperty(
         case CERT_PVK_FILE_PROP_ID:
         case CERT_SIGNATURE_HASH_PROP_ID:
         case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
+        case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
         case CERT_ENROLLMENT_PROP_ID:
         case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
@@ -2787,7 +2804,7 @@ static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         context = NULL;
index bea24dd..25f854e 100644 (file)
@@ -61,8 +61,8 @@
 #define ASN_UTCTIME         (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
 #define ASN_GENERALTIME     (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
 
-#define ASN_FLAGS_MASK 0xf0
-#define ASN_TYPE_MASK  0x0f
+#define ASN_FLAGS_MASK 0xe0
+#define ASN_TYPE_MASK  0x1f
 
 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
 
@@ -134,10 +134,11 @@ static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
  DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
-/* Assumes algo->Parameters.pbData is set ahead of time */
+/* Assumes algo->Parameters.pbData is set ahead of time.  Internal func. */
 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
+/* Internal function */
 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
@@ -171,14 +172,6 @@ static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
  DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
  void *pvStructInfo, DWORD *pcbStructInfo);
 
-/* filter for page-fault exceptions */
-static WINE_EXCEPTION_FILTER(page_fault)
-{
-    if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
-        return EXCEPTION_EXECUTE_HANDLER;
-    return EXCEPTION_CONTINUE_SEARCH;
-}
-
 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
  const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
 {
@@ -311,6 +304,9 @@ static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
         ret = items[i].encodeFunc(dwCertEncodingType, NULL,
          items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
          NULL, &items[i].size);
+        /* Some functions propagate their errors through the size */
+        if (!ret)
+            *pcbEncoded = items[i].size;
         dataLen += items[i].size;
     }
     if (ret)
@@ -336,6 +332,9 @@ static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
                     ret = items[i].encodeFunc(dwCertEncodingType, NULL,
                      items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
                      NULL, pbEncoded, &items[i].size);
+                    /* Some functions propagate their errors through the size */
+                    if (!ret)
+                        *pcbEncoded = items[i].size;
                     pbEncoded += items[i].size;
                 }
             }
@@ -381,8 +380,44 @@ static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
             ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
              item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
              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;
+}
+
+struct AsnEncodeTagSwappedItem
+{
+    BYTE                    tag;
+    const void             *pvStructInfo;
+    CryptEncodeObjectExFunc encodeFunc;
+};
+
+/* Sort of a wacky hack, it encodes something using the struct
+ * AsnEncodeTagSwappedItem's encodeFunc, then replaces the tag byte with the tag
+ * given in the struct AsnEncodeTagSwappedItem.
+ */
+static BOOL WINAPI CRYPT_AsnEncodeSwapTag(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+    BOOL ret;
+    const struct AsnEncodeTagSwappedItem *item =
+     (const struct AsnEncodeTagSwappedItem *)pvStructInfo;
+
+    ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
+     item->pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
+    if (ret && pbEncoded)
+        *pbEncoded = item->tag;
     return ret;
 }
 
@@ -495,7 +530,7 @@ static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
          sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
          pcbEncoded);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -526,7 +561,7 @@ static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
          sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
          pcbEncoded);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -595,7 +630,7 @@ static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -739,7 +774,7 @@ static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -823,7 +858,7 @@ static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -1031,7 +1066,7 @@ static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
                 }
                 else
                 {
-                    *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
+                    *pbEncoded++ = ASN_SEQUENCE;
                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
                      &lenBytes);
                     pbEncoded += lenBytes;
@@ -1140,7 +1175,7 @@ static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
                 CryptMemFree(blobs[i].pbData);
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -1202,7 +1237,7 @@ static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -1339,7 +1374,6 @@ static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
     {
         const CERT_ALT_NAME_INFO *info =
          (const CERT_ALT_NAME_INFO *)pvStructInfo;
-
         DWORD bytesNeeded, dataLen, lenBytes, i;
 
         ret = TRUE;
@@ -1399,7 +1433,7 @@ static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -1436,7 +1470,7 @@ static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -1477,7 +1511,7 @@ static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
              pcbEncoded);
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -1522,7 +1556,7 @@ static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -1593,7 +1627,7 @@ static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -1632,7 +1666,7 @@ static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
              &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
         CryptMemFree(newBlob.pbData);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -1731,7 +1765,7 @@ static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -1802,7 +1836,7 @@ static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -1881,7 +1915,7 @@ static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -1930,7 +1964,7 @@ static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -1960,7 +1994,7 @@ static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
              lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
              pcbEncoded);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -2009,7 +2043,146 @@ static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
+    {
+        SetLastError(STATUS_ACCESS_VIOLATION);
+        ret = FALSE;
+    }
+    __ENDTRY
+    return ret;
+}
+
+static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
+ BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+    BOOL ret = TRUE;
+    struct AsnEncodeSequenceItem items[3] = { { 0 } };
+    struct AsnConstructedItem constructed = { 0 };
+    struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
+    DWORD cItem = 0, cSwapped = 0;
+
+    switch (distPoint->DistPointName.dwDistPointNameChoice)
+    {
+    case CRL_DIST_POINT_NO_NAME:
+        /* do nothing */
+        break;
+    case CRL_DIST_POINT_FULL_NAME:
+        swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
+        swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
+        swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
+        constructed.tag = 0;
+        constructed.pvStructInfo = &swapped[cSwapped];
+        constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
+        items[cItem].pvStructInfo = &constructed;
+        items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
+        cSwapped++;
+        cItem++;
+        break;
+    case CRL_DIST_POINT_ISSUER_RDN_NAME:
+        FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
+        ret = FALSE;
+        break;
+    default:
+        ret = FALSE;
+    }
+    if (ret && distPoint->ReasonFlags.cbData)
+    {
+        swapped[cSwapped].tag = ASN_CONTEXT | 1;
+        swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
+        swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
+        items[cItem].pvStructInfo = &swapped[cSwapped];
+        items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
+        cSwapped++;
+        cItem++;
+    }
+    if (ret && distPoint->CRLIssuer.cAltEntry)
+    {
+        swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
+        swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
+        swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
+        items[cItem].pvStructInfo = &swapped[cSwapped];
+        items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
+        cSwapped++;
+        cItem++;
+    }
+    if (ret)
+        ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
+         pbEncoded, pcbEncoded);
+    return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+    BOOL ret;
+
+    __TRY
+    {
+        const CRL_DIST_POINTS_INFO *info =
+         (const CRL_DIST_POINTS_INFO *)pvStructInfo;
+
+        if (!info->cDistPoint)
+        {
+            SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
+            ret = FALSE;
+        }
+        else
+        {
+            DWORD bytesNeeded, dataLen, lenBytes, i;
+
+            ret = TRUE;
+            for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
+            {
+                DWORD len;
+
+                ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
+                 &len);
+                if (ret)
+                    dataLen += len;
+                else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
+                {
+                    /* Have to propagate index of failing character */
+                    *pcbEncoded = len;
+                }
+            }
+            if (ret)
+            {
+                CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
+                bytesNeeded = 1 + lenBytes + dataLen;
+                if (!pbEncoded)
+                {
+                    *pcbEncoded = bytesNeeded;
+                    ret = TRUE;
+                }
+                else
+                {
+                    if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
+                     pbEncoded, pcbEncoded, bytesNeeded)))
+                    {
+                        if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
+                            pbEncoded = *(BYTE **)pbEncoded;
+                        *pbEncoded++ = ASN_SEQUENCEOF;
+                        CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
+                        pbEncoded += lenBytes;
+                        for (i = 0; ret && i < info->cDistPoint; i++)
+                        {
+                            DWORD len = dataLen;
+
+                            ret = CRYPT_AsnEncodeDistPoint(
+                             &info->rgDistPoint[i], pbEncoded, &len);
+                            if (ret)
+                            {
+                                pbEncoded += len;
+                                dataLen -= len;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -2105,6 +2278,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
         case (WORD)PKCS_UTC_TIME:
             encodeFunc = CRYPT_AsnEncodeUtcTime;
             break;
+        case (WORD)X509_CRL_DIST_POINTS:
+            encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
+            break;
         default:
             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
         }
@@ -2291,7 +2467,9 @@ static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
     return ret;
 }
 
-/* A few of the members need explanation:
+/* tag:
+ *     The expected tag of the item.  If tag is 0, decodeFunc is called
+ *     regardless of the tag value seen.
  * offset:
  *     A sequence is decoded into a struct.  The offset member is the
  *     offset of this item within that struct.
@@ -2301,9 +2479,9 @@ static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
  * minSize:
  *     The minimum amount of space occupied after decoding.  You must set this.
  * optional:
- *     If true, and a decoding function fails with CRYPT_E_ASN1_BADTAG, then
- *     minSize space is filled with 0 for this member.  (Any other failure
- *     results in CRYPT_AsnDecodeSequence failing.)
+ *     If true, and the tag doesn't match the expected tag for this item,
+ *     or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is
+ *     filled with 0 for this member.
  * hasPointer, pointerOffset, minSize:
  *     If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
  *     the offset within the (outer) struct of the data pointer (or to the
@@ -2313,6 +2491,7 @@ static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
  */
 struct AsnDecodeSequenceItem
 {
+    BYTE                    tag;
     DWORD                   offset;
     CryptDecodeObjectExFunc decodeFunc;
     DWORD                   minSize;
@@ -2322,6 +2501,114 @@ struct AsnDecodeSequenceItem
     DWORD                   size;
 };
 
+static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
+ struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData)
+{
+    BOOL ret;
+    DWORD i;
+    const BYTE *ptr;
+
+    ptr = pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]);
+    for (i = 0, ret = TRUE; ret && i < cItem; i++)
+    {
+        if (cbEncoded - (ptr - pbEncoded) != 0)
+        {
+            DWORD nextItemLen;
+
+            if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
+             &nextItemLen)))
+            {
+                BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
+
+                if (ptr[0] == items[i].tag || !items[i].tag)
+                {
+                    if (nextData && pvStructInfo && items[i].hasPointer)
+                    {
+                        TRACE("Setting next pointer to %p\n",
+                         nextData);
+                        *(BYTE **)((BYTE *)pvStructInfo +
+                         items[i].pointerOffset) = nextData;
+                    }
+                    if (items[i].decodeFunc)
+                    {
+                        if (pvStructInfo)
+                            TRACE("decoding item %ld\n", i);
+                        else
+                            TRACE("sizing item %ld\n", i);
+                        ret = items[i].decodeFunc(dwCertEncodingType,
+                         NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
+                         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
+                         pvStructInfo ?  (BYTE *)pvStructInfo + items[i].offset
+                         : NULL, &items[i].size);
+                        if (ret)
+                        {
+                            if (nextData && items[i].hasPointer &&
+                             items[i].size > items[i].minSize)
+                            {
+                                nextData += items[i].size - items[i].minSize;
+                                /* align nextData to DWORD boundaries */
+                                if (items[i].size % sizeof(DWORD))
+                                    nextData += sizeof(DWORD) - items[i].size %
+                                     sizeof(DWORD);
+                            }
+                            /* Account for alignment padding */
+                            if (items[i].size % sizeof(DWORD))
+                                items[i].size += sizeof(DWORD) -
+                                 items[i].size % sizeof(DWORD);
+                            ptr += 1 + nextItemLenBytes + nextItemLen;
+                        }
+                        else if (items[i].optional &&
+                         GetLastError() == CRYPT_E_ASN1_BADTAG)
+                        {
+                            TRACE("skipping optional item %ld\n", i);
+                            items[i].size = items[i].minSize;
+                            SetLastError(NOERROR);
+                            ret = TRUE;
+                        }
+                        else
+                            TRACE("item %ld failed: %08lx\n", i,
+                             GetLastError());
+                    }
+                    else
+                        items[i].size = items[i].minSize;
+                }
+                else if (items[i].optional)
+                {
+                    TRACE("skipping optional item %ld\n", i);
+                    items[i].size = items[i].minSize;
+                }
+                else
+                {
+                    TRACE("tag %02x doesn't match expected %02x\n",
+                     ptr[0], items[i].tag);
+                    SetLastError(CRYPT_E_ASN1_BADTAG);
+                    ret = FALSE;
+                }
+            }
+        }
+        else if (items[i].optional)
+        {
+            TRACE("missing optional item %ld, skipping\n", i);
+            items[i].size = items[i].minSize;
+        }
+        else
+        {
+            TRACE("not enough bytes for item %ld, failing\n", i);
+            SetLastError(CRYPT_E_ASN1_CORRUPT);
+            ret = FALSE;
+        }
+    }
+    if (cbEncoded - (ptr - pbEncoded) != 0)
+    {
+        TRACE("%ld remaining bytes, failing\n", cbEncoded -
+         (ptr - pbEncoded));
+        SetLastError(CRYPT_E_ASN1_CORRUPT);
+        ret = FALSE;
+    }
+    return ret;
+}
+
 /* This decodes an arbitrary sequence into a contiguous block of memory
  * (basically, a struct.)  Each element being decoded is described by a struct
  * AsnDecodeSequenceItem, see above.
@@ -2348,72 +2635,19 @@ static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
 
         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
         {
-            BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
-            DWORD i, bytesNeeded = 0, minSize = 0;
-            const BYTE *ptr;
+            DWORD i;
 
-            ptr = pbEncoded + 1 + lenBytes;
-            for (i = 0; ret && i < cItem; i++)
+            ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, pbEncoded,
+             cbEncoded, dwFlags, NULL, NULL);
+            if (ret)
             {
-                DWORD nextItemLen;
-
-                minSize += items[i].minSize;
-                if (cbEncoded - (ptr - pbEncoded) != 0)
-                {
-                    if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
-                     &nextItemLen)))
-                    {
-                        BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
+                DWORD bytesNeeded = 0, structSize = 0;
 
-                        if (items[i].decodeFunc)
-                        {
-                            TRACE("sizing item %ld\n", i);
-                            ret = items[i].decodeFunc(dwCertEncodingType, NULL,
-                             ptr, 1 + nextItemLenBytes + nextItemLen,
-                             dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
-                             &items[i].size);
-                            if (ret)
-                            {
-                                /* Account for alignment padding */
-                                bytesNeeded += items[i].size;
-                                if (items[i].size % sizeof(DWORD))
-                                    bytesNeeded += sizeof(DWORD) -
-                                     items[i].size % sizeof(DWORD);
-                                ptr += 1 + nextItemLenBytes + nextItemLen;
-                            }
-                            else if (items[i].optional &&
-                             GetLastError() == CRYPT_E_ASN1_BADTAG)
-                            {
-                                TRACE("skipping optional item %ld\n", i);
-                                bytesNeeded += items[i].minSize;
-                                SetLastError(NOERROR);
-                                ret = TRUE;
-                            }
-                            else
-                                TRACE("item %ld failed: %08lx\n", i,
-                                 GetLastError());
-                        }
-                        else
-                            bytesNeeded += items[i].minSize;
-                    }
-                }
-                else if (items[i].optional)
-                    bytesNeeded += items[i].minSize;
-                else
+                for (i = 0; i < cItem; i++)
                 {
-                    SetLastError(CRYPT_E_ASN1_CORRUPT);
-                    ret = FALSE;
+                    bytesNeeded += items[i].size;
+                    structSize += items[i].minSize;
                 }
-            }
-            if (cbEncoded - (ptr - pbEncoded) != 0)
-            {
-                TRACE("%ld remaining bytes, failing\n", cbEncoded -
-                 (ptr - pbEncoded));
-                SetLastError(CRYPT_E_ASN1_CORRUPT);
-                ret = FALSE;
-            }
-            if (ret)
-            {
                 if (!pvStructInfo)
                     *pcbStructInfo = bytesNeeded;
                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
@@ -2426,66 +2660,10 @@ static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
                     if (startingPointer)
                         nextData = (BYTE *)startingPointer;
                     else
-                        nextData = (BYTE *)pvStructInfo + minSize;
-                    memset(pvStructInfo, 0, minSize);
-                    ptr = pbEncoded + 1 + lenBytes;
-                    for (i = 0; ret && i < cItem; i++)
-                    {
-                        if (cbEncoded - (ptr - pbEncoded) != 0)
-                        {
-                            DWORD nextItemLen;
-                            BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
-
-                            CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
-                             &nextItemLen);
-                            if (items[i].hasPointer)
-                            {
-                                *(BYTE **)((BYTE *)pvStructInfo +
-                                 items[i].pointerOffset) = nextData;
-                            }
-                            if (items[i].decodeFunc)
-                            {
-                                TRACE("decoding item %ld\n", i);
-                                ret = items[i].decodeFunc(dwCertEncodingType,
-                                 NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
-                                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
-                                 (BYTE *)pvStructInfo + items[i].offset,
-                                 &items[i].size);
-                                if (!ret)
-                                    TRACE("item %ld failed: %08lx\n", i,
-                                     GetLastError());
-                            }
-                            else
-                                items[i].size = items[i].minSize;
-                            if (ret)
-                            {
-                                if (items[i].hasPointer &&
-                                 items[i].size > items[i].minSize)
-                                {
-                                    nextData += items[i].size -
-                                     items[i].minSize;
-                                    /* align nextData to DWORD boundaries */
-                                    if (items[i].size % sizeof(DWORD))
-                                    {
-                                        nextData += sizeof(DWORD) -
-                                         items[i].size % sizeof(DWORD);
-                                    }
-                                }
-                                ptr += 1 + nextItemLenBytes + nextItemLen;
-                            }
-                            else if (items[i].optional &&
-                             GetLastError() == CRYPT_E_ASN1_BADTAG)
-                            {
-                                SetLastError(NOERROR);
-                                ret = TRUE;
-                            }
-                        }
-                        else if (!items[i].optional)
-                        {
-                            SetLastError(CRYPT_E_ASN1_CORRUPT);
-                            ret = FALSE;
-                        }
-                    }
+                        nextData = (BYTE *)pvStructInfo + structSize;
+                    memset(pvStructInfo, 0, structSize);
+                    ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
+                     pbEncoded, cbEncoded, dwFlags, pvStructInfo, nextData);
                 }
             }
         }
@@ -2499,40 +2677,215 @@ static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
     return ret;
 }
 
-/* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by
- * pvStructInfo.  The BLOB must be non-empty, otherwise the last error is set
- * to CRYPT_E_ASN1_CORRUPT.
- * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData
- * set!
+/* tag:
+ *     The expected tag of the entire encoded array (usually a variant
+ *     of ASN_SETOF or ASN_SEQUENCEOF.)
+ * decodeFunc:
+ *     used to decode each item in the array
+ * itemSize:
+ *      is the minimum size of each decoded item
+ * hasPointer:
+ *      indicates whether each item has a dynamic pointer
+ * pointerOffset:
+ *     indicates the offset within itemSize at which the pointer exists
  */
-static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+struct AsnArrayDescriptor
 {
-    BOOL ret;
-    DWORD dataLen;
+    BYTE                    tag;
+    CryptDecodeObjectExFunc decodeFunc;
+    DWORD                   itemSize;
+    BOOL                    hasPointer;
+    DWORD                   pointerOffset;
+};
 
-    if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+struct AsnArrayItemSize
+{
+    DWORD encodedLen;
+    DWORD size;
+};
+
+struct GenericArray
+{
+    DWORD cItems;
+    BYTE *rgItems;
+};
+
+/* Decodes an array of like types into a struct GenericArray.
+ * The layout and decoding of the array are described by a struct
+ * AsnArrayDescriptor.
+ */
+static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc,
+ const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
+ void *startingPointer)
+{
+    BOOL ret = TRUE;
+
+    TRACE("%p, %p, %ld, %08lx, %p, %p, %ld, %p\n", arrayDesc, pbEncoded,
+     cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
+     startingPointer);
+
+    if (pbEncoded[0] == arrayDesc->tag)
     {
-        BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
-        DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
-       
-        if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
-            bytesNeeded += 1 + lenBytes + dataLen;
+        DWORD dataLen;
 
-        if (!pvStructInfo)
-            *pcbStructInfo = bytesNeeded;
-        else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, 
-         pvStructInfo, pcbStructInfo, bytesNeeded)))
+        if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
         {
-            CRYPT_DER_BLOB *blob = (CRYPT_DER_BLOB *)pvStructInfo;
+            DWORD bytesNeeded, cItems = 0;
+            BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+            /* There can be arbitrarily many items, but there is often only one.
+             */
+            struct AsnArrayItemSize itemSize = { 0 }, *itemSizes = &itemSize;
 
-            blob->cbData = 1 + lenBytes + dataLen;
-            if (blob->cbData)
+            bytesNeeded = sizeof(struct GenericArray);
+            if (dataLen)
             {
-                if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
-                    blob->pbData = (BYTE *)pbEncoded;
-                else
+                const BYTE *ptr;
+
+                for (ptr = pbEncoded + 1 + lenBytes; ret &&
+                 ptr - pbEncoded - 1 - lenBytes < dataLen; )
+                {
+                    DWORD itemLenBytes, itemDataLen, size;
+
+                    itemLenBytes = GET_LEN_BYTES(ptr[1]);
+                    /* Each item decoded may not tolerate extraneous bytes, so
+                     * get the length of the next element and pass it directly.
+                     */
+                    ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
+                     &itemDataLen);
+                    if (ret)
+                        ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr,
+                         1 + itemLenBytes + itemDataLen,
+                         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
+                         &size);
+                    if (ret)
+                    {
+                        DWORD nextLen;
+
+                        cItems++;
+                        if (itemSizes != &itemSize)
+                            itemSizes = CryptMemRealloc(itemSizes,
+                             cItems * sizeof(struct AsnArrayItemSize));
+                        else
+                        {
+                            itemSizes =
+                             CryptMemAlloc(
+                             cItems * sizeof(struct AsnArrayItemSize));
+                            memcpy(itemSizes, &itemSize, sizeof(itemSize));
+                        }
+                        if (itemSizes)
+                        {
+                            itemSizes[cItems - 1].encodedLen = 1 + itemLenBytes
+                             + itemDataLen;
+                            itemSizes[cItems - 1].size = size;
+                            bytesNeeded += size;
+                            ret = CRYPT_GetLen(ptr,
+                             cbEncoded - (ptr - pbEncoded), &nextLen);
+                            if (ret)
+                                ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
+                        }
+                        else
+                            ret = FALSE;
+                    }
+                }
+            }
+            if (ret)
+            {
+                if (!pvStructInfo)
+                    *pcbStructInfo = bytesNeeded;
+                else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
+                 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
+                {
+                    DWORD i;
+                    BYTE *nextData;
+                    const BYTE *ptr;
+                    struct GenericArray *array;
+
+                    if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
+                        pvStructInfo = *(BYTE **)pvStructInfo;
+                    array = (struct GenericArray *)pvStructInfo;
+                    array->cItems = cItems;
+                    if (startingPointer)
+                        array->rgItems = startingPointer;
+                    else
+                        array->rgItems = (BYTE *)array +
+                         sizeof(struct GenericArray);
+                    nextData = (BYTE *)array->rgItems +
+                     array->cItems * arrayDesc->itemSize;
+                    for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
+                     i < cItems && ptr - pbEncoded - 1 - lenBytes <
+                     dataLen; i++)
+                    {
+                        if (arrayDesc->hasPointer)
+                            *(BYTE **)(array->rgItems + i * arrayDesc->itemSize
+                             + arrayDesc->pointerOffset) = nextData;
+                        ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr,
+                         itemSizes[i].encodedLen,
+                         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
+                         array->rgItems + i * arrayDesc->itemSize,
+                         &itemSizes[i].size);
+                        if (ret)
+                        {
+                            DWORD nextLen;
+
+                            nextData += itemSizes[i].size - arrayDesc->itemSize;
+                            ret = CRYPT_GetLen(ptr,
+                             cbEncoded - (ptr - pbEncoded), &nextLen);
+                            if (ret)
+                                ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
+                        }
+                    }
+                }
+            }
+            if (itemSizes != &itemSize)
+                CryptMemFree(itemSizes);
+        }
+    }
+    else
+    {
+        SetLastError(CRYPT_E_ASN1_BADTAG);
+        ret = FALSE;
+    }
+    return ret;
+}
+
+/* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by
+ * pvStructInfo.  The BLOB must be non-empty, otherwise the last error is set
+ * to CRYPT_E_ASN1_CORRUPT.
+ * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData
+ * set!
+ */
+static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+{
+    BOOL ret;
+    DWORD dataLen;
+
+    if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+    {
+        BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+        DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
+       
+        if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
+            bytesNeeded += 1 + lenBytes + dataLen;
+
+        if (!pvStructInfo)
+            *pcbStructInfo = bytesNeeded;
+        else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, 
+         pvStructInfo, pcbStructInfo, bytesNeeded)))
+        {
+            CRYPT_DER_BLOB *blob;
+
+            if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
+                pvStructInfo = *(BYTE **)pvStructInfo;
+            blob = (CRYPT_DER_BLOB *)pvStructInfo;
+            blob->cbData = 1 + lenBytes + dataLen;
+            if (blob->cbData)
+            {
+                if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
+                    blob->pbData = (BYTE *)pbEncoded;
+                else
                 {
                     assert(blob->pbData);
                     memcpy(blob->pbData, pbEncoded, blob->cbData);
@@ -2597,14 +2950,14 @@ static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
     __TRY
     {
         struct AsnDecodeSequenceItem items[] = {
-         { offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned),
+         { 0, offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned),
            CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
            offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 },
-         { offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm),
-           CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
-           FALSE, TRUE, offsetof(CERT_SIGNED_CONTENT_INFO,
-           SignatureAlgorithm.pszObjId), 0 },
-         { offsetof(CERT_SIGNED_CONTENT_INFO, Signature),
+         { ASN_SEQUENCEOF, offsetof(CERT_SIGNED_CONTENT_INFO,
+           SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
+           sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE,
+           offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm.pszObjId), 0 },
+         { ASN_BITSTRING, offsetof(CERT_SIGNED_CONTENT_INFO, Signature),
            CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
            offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 },
         };
@@ -2615,7 +2968,7 @@ static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -2624,29 +2977,21 @@ static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
     return ret;
 }
 
+/* Internal function */
 static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
     BOOL ret;
+    DWORD dataLen;
 
-    if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR))
+    if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
     {
-        DWORD dataLen;
-
-        if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
-        {
-            BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+        BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
 
-            ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
-             pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
-             pvStructInfo, pcbStructInfo);
-        }
-    }
-    else
-    {
-        SetLastError(CRYPT_E_ASN1_BADTAG);
-        ret = FALSE;
+        ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
+         pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
+         pvStructInfo, pcbStructInfo);
     }
     return ret;
 }
@@ -2658,9 +3003,9 @@ static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
     BOOL ret;
 
     struct AsnDecodeSequenceItem items[] = {
-     { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
+     { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
        CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
-     { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
+     { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
        CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
     };
 
@@ -2670,29 +3015,21 @@ static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
     return ret;
 }
 
+/* Internal function */
 static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
     BOOL ret;
+    DWORD dataLen;
 
-    if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR | 3))
+    if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
     {
-        DWORD dataLen;
-
-        if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
-        {
-            BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+        BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
 
-            ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
-             X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
-             pDecodePara, pvStructInfo, pcbStructInfo);
-        }
-    }
-    else
-    {
-        SetLastError(CRYPT_E_ASN1_BADTAG);
-        ret = FALSE;
+        ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
+         X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
+         pDecodePara, pvStructInfo, pcbStructInfo);
     }
     return ret;
 }
@@ -2709,41 +3046,46 @@ static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
     __TRY
     {
         struct AsnDecodeSequenceItem items[] = {
-         { offsetof(CERT_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
-           sizeof(DWORD), TRUE, FALSE, 0, 0 },
-         { offsetof(CERT_INFO, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
-           sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
-           SerialNumber.pbData), 0 },
-         { offsetof(CERT_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
-           sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CERT_INFO,
-           SignatureAlgorithm.pszObjId), 0 },
-         { offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
+         { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(CERT_INFO, dwVersion),
+           CRYPT_AsnDecodeCertVersion, sizeof(DWORD), TRUE, FALSE, 0, 0 },
+         { ASN_INTEGER, offsetof(CERT_INFO, SerialNumber),
+           CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE,
+           TRUE, offsetof(CERT_INFO, SerialNumber.pbData), 0 },
+         { ASN_SEQUENCEOF, offsetof(CERT_INFO, SignatureAlgorithm),
+           CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
+           FALSE, TRUE, offsetof(CERT_INFO, SignatureAlgorithm.pszObjId), 0 },
+         { 0, offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
            sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
            Issuer.pbData) },
-         { offsetof(CERT_INFO, NotBefore), CRYPT_AsnDecodeValidity,
-           sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE, FALSE, 0 },
-         { offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob,
+         { ASN_SEQUENCEOF, offsetof(CERT_INFO, NotBefore),
+           CRYPT_AsnDecodeValidity, sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE,
+           FALSE, 0 },
+         { 0, offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob,
            sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
            Subject.pbData) },
-         { offsetof(CERT_INFO, SubjectPublicKeyInfo), CRYPT_AsnDecodePubKeyInfo,
-           sizeof(CERT_PUBLIC_KEY_INFO), FALSE, TRUE, offsetof(CERT_INFO,
+         /* jil FIXME: shouldn't this have an internal version, which expects
+          * the pbData to be set?
+          */
+         { ASN_SEQUENCEOF, offsetof(CERT_INFO, SubjectPublicKeyInfo),
+           CRYPT_AsnDecodePubKeyInfo, sizeof(CERT_PUBLIC_KEY_INFO), FALSE,
+           TRUE, offsetof(CERT_INFO,
            SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 },
-         { offsetof(CERT_INFO, IssuerUniqueId), CRYPT_AsnDecodeBitsInternal,
-           sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
-           IssuerUniqueId.pbData), 0 },
-         { offsetof(CERT_INFO, SubjectUniqueId), CRYPT_AsnDecodeBitsInternal,
-           sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
-           SubjectUniqueId.pbData), 0 },
-         { offsetof(CERT_INFO, cExtension), CRYPT_AsnDecodeCertExtensions,
-           sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CERT_INFO,
-           rgExtension), 0 },
+         { ASN_BITSTRING, offsetof(CERT_INFO, IssuerUniqueId),
+           CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
+           offsetof(CERT_INFO, IssuerUniqueId.pbData), 0 },
+         { ASN_BITSTRING, offsetof(CERT_INFO, SubjectUniqueId),
+           CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
+           offsetof(CERT_INFO, SubjectUniqueId.pbData), 0 },
+         { ASN_CONTEXT | ASN_CONSTRUCTOR | 3, offsetof(CERT_INFO, cExtension),
+           CRYPT_AsnDecodeCertExtensions, sizeof(CERT_EXTENSIONS), TRUE, TRUE,
+           offsetof(CERT_INFO, rgExtension), 0 },
         };
 
         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -2752,37 +3094,33 @@ static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded,
- DWORD dwFlags, PCRL_ENTRY entry, DWORD *pcbEntry)
+static BOOL WINAPI CRYPT_AsnDecodeCRLEntry(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
     BOOL ret;
     struct AsnDecodeSequenceItem items[] = {
-     { offsetof(CRL_ENTRY, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
-       sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CRL_ENTRY,
-       SerialNumber.pbData), 0 },
-     { offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime,
+     { ASN_INTEGER, offsetof(CRL_ENTRY, SerialNumber),
+       CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE,
+       offsetof(CRL_ENTRY, SerialNumber.pbData), 0 },
+     { 0, offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime,
        sizeof(FILETIME), FALSE, FALSE, 0 },
-     { offsetof(CRL_ENTRY, cExtension), CRYPT_AsnDecodeExtensionsInternal,
-       sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CRL_ENTRY,
-       rgExtension), 0 },
+     { ASN_SEQUENCEOF, offsetof(CRL_ENTRY, cExtension),
+       CRYPT_AsnDecodeExtensionsInternal, sizeof(CERT_EXTENSIONS), TRUE, TRUE,
+       offsetof(CRL_ENTRY, rgExtension), 0 },
     };
+    PCRL_ENTRY entry = (PCRL_ENTRY)pvStructInfo;
 
     TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, entry,
-     *pcbEntry);
+     *pcbStructInfo);
 
     ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
-     NULL, entry, pcbEntry, entry ? entry->SerialNumber.pbData : NULL);
-    TRACE("Returning %d (%08lx)\n", ret, GetLastError());
+     NULL, entry, pcbStructInfo, entry ? entry->SerialNumber.pbData : NULL);
     return ret;
 }
 
-typedef struct _WINE_CRL_ENTRIES {
-    DWORD      cCRLEntry;
-    PCRL_ENTRY rgCRLEntry;
-} WINE_CRL_ENTRIES, *PWINE_CRL_ENTRIES;
-
-/* Warning: assumes pvStructInfo is a WINE_CRL_ENTRIES whose rgCRLEntry has
+/* Warning: assumes pvStructInfo is a struct GenericArray whose rgItems has
  * been set prior to calling.
  */
 static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType,
@@ -2790,98 +3128,17 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
     BOOL ret;
+    struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+     CRYPT_AsnDecodeCRLEntry, sizeof(CRL_ENTRY), TRUE,
+     offsetof(CRL_ENTRY, SerialNumber.pbData) };
+    struct GenericArray *entries = (struct GenericArray *)pvStructInfo;
 
     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
      pDecodePara, pvStructInfo, *pcbStructInfo);
 
-    if (pbEncoded[0] == ASN_SEQUENCEOF)
-    {
-        DWORD dataLen, bytesNeeded;
-
-        if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
-        {
-            DWORD cCRLEntry = 0;
-            BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
-
-            bytesNeeded = sizeof(WINE_CRL_ENTRIES);
-            if (dataLen)
-            {
-                const BYTE *ptr;
-                DWORD size;
-
-                for (ptr = pbEncoded + 1 + lenBytes; ret &&
-                 ptr - pbEncoded - 1 - lenBytes < dataLen; )
-                {
-                    size = 0;
-                    ret = CRYPT_AsnDecodeCRLEntry(ptr,
-                     cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
-                    if (ret)
-                    {
-                        DWORD nextLen;
-
-                        cCRLEntry++;
-                        bytesNeeded += size;
-                        ret = CRYPT_GetLen(ptr,
-                         cbEncoded - (ptr - pbEncoded), &nextLen);
-                        if (ret)
-                            ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
-                    }
-                }
-            }
-            if (ret)
-            {
-                if (!pvStructInfo)
-                    *pcbStructInfo = bytesNeeded;
-                else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
-                 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
-                {
-                    DWORD size, i;
-                    BYTE *nextData;
-                    const BYTE *ptr;
-                    PWINE_CRL_ENTRIES entries;
-
-                    if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
-                        pvStructInfo = *(BYTE **)pvStructInfo;
-                    *pcbStructInfo = bytesNeeded;
-                    entries = (PWINE_CRL_ENTRIES)pvStructInfo;
-                    entries->cCRLEntry = cCRLEntry;
-                    assert(entries->rgCRLEntry);
-                    nextData = (BYTE *)entries->rgCRLEntry +
-                     entries->cCRLEntry * sizeof(CRL_ENTRY);
-                    for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
-                     i < cCRLEntry && ptr - pbEncoded - 1 - lenBytes <
-                     dataLen; i++)
-                    {
-                        entries->rgCRLEntry[i].SerialNumber.pbData = nextData;
-                        size = bytesNeeded;
-                        ret = CRYPT_AsnDecodeCRLEntry(ptr,
-                         cbEncoded - (ptr - pbEncoded), dwFlags,
-                         &entries->rgCRLEntry[i], &size);
-                        if (ret)
-                        {
-                            DWORD nextLen;
-
-                            bytesNeeded -= size;
-                            /* Increment nextData by the difference of the
-                             * minimum size and the actual size.
-                             */
-                            if (size > sizeof(CRL_ENTRY))
-                                nextData += size - sizeof(CRL_ENTRY);
-                            ret = CRYPT_GetLen(ptr,
-                             cbEncoded - (ptr - pbEncoded), &nextLen);
-                            if (ret)
-                                ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
-                        }
-                    }
-                }
-            }
-        }
-    }
-    else
-    {
-        SetLastError(CRYPT_E_ASN1_BADTAG);
-        ret = FALSE;
-    }
+    ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
+     pDecodePara, pvStructInfo, pcbStructInfo,
+     entries ? entries->rgItems : NULL);
     TRACE("Returning %d (%08lx)\n", ret, GetLastError());
     return ret;
 }
@@ -2898,24 +3155,24 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
     __TRY
     {
         struct AsnDecodeSequenceItem items[] = {
-         { offsetof(CRL_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
-           sizeof(DWORD), TRUE, FALSE, 0, 0 },
-         { offsetof(CRL_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
-           sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CRL_INFO,
-           SignatureAlgorithm.pszObjId), 0 },
-         { offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
+         { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(CRL_INFO, dwVersion),
+           CRYPT_AsnDecodeCertVersion, sizeof(DWORD), TRUE, FALSE, 0, 0 },
+         { ASN_SEQUENCEOF, offsetof(CRL_INFO, SignatureAlgorithm),
+           CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
+           FALSE, TRUE, offsetof(CRL_INFO, SignatureAlgorithm.pszObjId), 0 },
+         { 0, offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
            sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO,
            Issuer.pbData) },
-         { offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime,
+         { 0, offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime,
            sizeof(FILETIME), FALSE, FALSE, 0 },
-         { offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime,
+         { 0, offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime,
            sizeof(FILETIME), TRUE, FALSE, 0 },
-         { offsetof(CRL_INFO, cCRLEntry), CRYPT_AsnDecodeCRLEntries,
-           sizeof(WINE_CRL_ENTRIES), TRUE, TRUE, offsetof(CRL_INFO,
-           rgCRLEntry), 0 },
+         { ASN_SEQUENCEOF, offsetof(CRL_INFO, cCRLEntry),
+           CRYPT_AsnDecodeCRLEntries, sizeof(struct GenericArray), TRUE, TRUE,
+           offsetof(CRL_INFO, rgCRLEntry), 0 },
          /* Note that the extensions are ignored by MS, so I'll ignore them too
           */
-         { offsetof(CRL_INFO, cExtension), NULL,
+         { 0, offsetof(CRL_INFO, cExtension), NULL,
            sizeof(CERT_EXTENSIONS), TRUE, FALSE, 0 },
         };
 
@@ -2923,7 +3180,7 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -2958,29 +3215,34 @@ static BOOL WINAPI CRYPT_AsnDecodeOidWrapper(DWORD dwCertEncodingType,
     return ret;
 }
 
-/* Warning:  assumes ext->pszObjId is set ahead of time! */
-static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
- DWORD dwFlags, CERT_EXTENSION *ext, DWORD *pcbExt)
+/* Warning:  assumes pvStructInfo is a CERT_EXTENSION whose pszObjId is set
+ * ahead of time!
+ */
+static BOOL WINAPI CRYPT_AsnDecodeExtension(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
     struct AsnDecodeSequenceItem items[] = {
-     { offsetof(CERT_EXTENSION, pszObjId), CRYPT_AsnDecodeOidWrapper,
-       sizeof(LPSTR), FALSE, TRUE, offsetof(CERT_EXTENSION, pszObjId), 0 },
-     { offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool,
+     { ASN_OBJECTIDENTIFIER, offsetof(CERT_EXTENSION, pszObjId),
+       CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE,
+       offsetof(CERT_EXTENSION, pszObjId), 0 },
+     { ASN_BOOL, offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool,
        sizeof(BOOL), TRUE, FALSE, 0, 0 },
-     { offsetof(CERT_EXTENSION, Value), CRYPT_AsnDecodeOctetsInternal,
-       sizeof(CRYPT_OBJID_BLOB), FALSE, TRUE, offsetof(CERT_EXTENSION,
-       Value.pbData) },
+     { ASN_OCTETSTRING, offsetof(CERT_EXTENSION, Value),
+       CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_OBJID_BLOB), FALSE, TRUE,
+       offsetof(CERT_EXTENSION, Value.pbData) },
     };
     BOOL ret = TRUE;
+    PCERT_EXTENSION ext = (PCERT_EXTENSION)pvStructInfo;
 
     TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, ext,
-     *pcbExt);
+     *pcbStructInfo);
 
     if (ext)
         TRACE("ext->pszObjId is %p\n", ext->pszObjId);
     ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL,
-     ext, pcbExt, ext ? ext->pszObjId : NULL);
+     ext, pcbStructInfo, ext ? ext->pszObjId : NULL);
     if (ext)
         TRACE("ext->pszObjId is %p (%s)\n", ext->pszObjId,
          debugstr_a(ext->pszObjId));
@@ -2993,98 +3255,16 @@ static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
     BOOL ret = TRUE;
+    struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+     CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE,
+     offsetof(CERT_EXTENSION, pszObjId) };
+    PCERT_EXTENSIONS exts = (PCERT_EXTENSIONS)pvStructInfo;
 
     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
      pDecodePara, pvStructInfo, *pcbStructInfo);
 
-    if (pbEncoded[0] == ASN_SEQUENCEOF)
-    {
-        DWORD dataLen, bytesNeeded;
-
-        if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
-        {
-            DWORD cExtension = 0;
-            BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
-
-            bytesNeeded = sizeof(CERT_EXTENSIONS);
-            if (dataLen)
-            {
-                const BYTE *ptr;
-                DWORD size;
-
-                for (ptr = pbEncoded + 1 + lenBytes; ret &&
-                 ptr - pbEncoded - 1 - lenBytes < dataLen; )
-                {
-                    size = 0;
-                    ret = CRYPT_AsnDecodeExtension(ptr,
-                     cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
-                    if (ret)
-                    {
-                        DWORD nextLen;
-
-                        cExtension++;
-                        bytesNeeded += size;
-                        ret = CRYPT_GetLen(ptr,
-                         cbEncoded - (ptr - pbEncoded), &nextLen);
-                        if (ret)
-                            ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
-                    }
-                }
-            }
-            if (ret)
-            {
-                if (!pvStructInfo)
-                    *pcbStructInfo = bytesNeeded;
-                else if (*pcbStructInfo < bytesNeeded)
-                {
-                    SetLastError(ERROR_MORE_DATA);
-                    *pcbStructInfo = bytesNeeded;
-                    ret = FALSE;
-                }
-                else
-                {
-                    DWORD size, i;
-                    BYTE *nextData;
-                    const BYTE *ptr;
-                    CERT_EXTENSIONS *exts;
-
-                    *pcbStructInfo = bytesNeeded;
-                    exts = (CERT_EXTENSIONS *)pvStructInfo;
-                    exts->cExtension = cExtension;
-                    assert(exts->rgExtension);
-                    nextData = (BYTE *)exts->rgExtension +
-                     exts->cExtension * sizeof(CERT_EXTENSION);
-                    for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
-                     i < cExtension && ptr - pbEncoded - 1 - lenBytes <
-                     dataLen; i++)
-                    {
-                        exts->rgExtension[i].pszObjId = (LPSTR)nextData;
-                        size = bytesNeeded;
-                        ret = CRYPT_AsnDecodeExtension(ptr,
-                         cbEncoded - (ptr - pbEncoded), dwFlags,
-                         &exts->rgExtension[i], &size);
-                        if (ret)
-                        {
-                            DWORD nextLen;
-
-                            bytesNeeded -= size;
-                            if (size > sizeof(CERT_EXTENSION))
-                                nextData += size - sizeof(CERT_EXTENSION);
-                            ret = CRYPT_GetLen(ptr,
-                             cbEncoded - (ptr - pbEncoded), &nextLen);
-                            if (ret)
-                                ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
-                        }
-                    }
-                }
-            }
-        }
-    }
-    else
-    {
-        SetLastError(CRYPT_E_ASN1_BADTAG);
-        ret = FALSE;
-    }
+    ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
+     pDecodePara, pvStructInfo, pcbStructInfo, exts ? exts->rgExtension : NULL);
     return ret;
 }
 
@@ -3119,7 +3299,7 @@ static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -3234,7 +3414,7 @@ static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
             ret = FALSE;
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -3247,14 +3427,16 @@ static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
  * order to avoid overwriting memory.  (In some cases, it may change it, if it
  * doesn't copy anything to memory.)  Be sure to set it correctly!
  */
-static BOOL WINAPI CRYPT_AsnDecodeNameValue(const BYTE *pbEncoded,
- DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value, DWORD *pcbValue)
+static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
     BOOL ret = TRUE;
 
     __TRY
     {
         DWORD dataLen;
+        CERT_NAME_VALUE *value = (CERT_NAME_VALUE *)pvStructInfo;
 
         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
         {
@@ -3285,16 +3467,16 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValue(const BYTE *pbEncoded,
                     break;
                 }
                 if (!value)
-                    *pcbValue = bytesNeeded;
-                else if (*pcbValue < bytesNeeded)
+                    *pcbStructInfo = bytesNeeded;
+                else if (*pcbStructInfo < bytesNeeded)
                 {
-                    *pcbValue = bytesNeeded;
+                    *pcbStructInfo = bytesNeeded;
                     SetLastError(ERROR_MORE_DATA);
                     ret = FALSE;
                 }
                 else
                 {
-                    *pcbValue = bytesNeeded;
+                    *pcbStructInfo = bytesNeeded;
                     switch (pbEncoded[0])
                     {
                     case ASN_NUMERICSTRING:
@@ -3329,258 +3511,14 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValue(const BYTE *pbEncoded,
                     }
                     else
                     {
-                        value->Value.cbData = 0;
-                        value->Value.pbData = NULL;
-                    }
-                }
-            }
-        }
-    }
-    __EXCEPT(page_fault)
-    {
-        SetLastError(STATUS_ACCESS_VIOLATION);
-        ret = FALSE;
-    }
-    __ENDTRY
-    return ret;
-}
-
-/* FIXME: this should use CRYPT_AsnDecodeSequence (though that won't accept it
- * at the moment because of the ASN_CONSTRUCTOR tag.)
- */
-static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(const BYTE *pbEncoded,
- DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr, DWORD *pcbAttr)
-{
-    BOOL ret;
-
-    __TRY
-    {
-        if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCE))
-        {
-            DWORD bytesNeeded, dataLen, size;
-            BYTE lenBytes;
-
-            if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
-            {
-                /* The data length must be at least 4, two for the tag and
-                 * length for the OID, and two for the string (assuming both
-                 * have short-form lengths.)
-                 */
-                if (dataLen < 4)
-                {
-                    SetLastError(CRYPT_E_ASN1_EOD);
-                    ret = FALSE;
-                }
-                else
-                {
-                    bytesNeeded = sizeof(CERT_RDN_ATTR);
-                    lenBytes = GET_LEN_BYTES(pbEncoded[1]);
-                    ret = CRYPT_AsnDecodeOid(pbEncoded + 1 + lenBytes,
-                     cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
-                    if (ret)
-                    {
-                        /* ugly: need to know the size of the next element of
-                         * the sequence, so get it directly
-                         */
-                        DWORD objIdOfset = 1 + lenBytes, objIdLen,
-                         nameValueOffset = 0;
-
-                        ret = CRYPT_GetLen(pbEncoded + objIdOfset,
-                         cbEncoded - objIdOfset, &objIdLen);
-                        bytesNeeded += size;
-                        /* hack: like encoding, this takes advantage of the
-                         * fact that the rest of the structure is identical to
-                         * a CERT_NAME_VALUE.
-                         */
-                        if (ret)
-                        {
-                            nameValueOffset = objIdOfset + objIdLen + 1 +
-                             GET_LEN_BYTES(pbEncoded[objIdOfset]);
-                            ret = CRYPT_AsnDecodeNameValue(
-                             pbEncoded + nameValueOffset,
-                             cbEncoded - nameValueOffset, dwFlags, NULL, &size);
-                        }
-                        if (ret)
-                        {
-                            bytesNeeded += size;
-                            if (!attr)
-                                *pcbAttr = bytesNeeded;
-                            else if (*pcbAttr < bytesNeeded)
-                            {
-                                *pcbAttr = bytesNeeded;
-                                SetLastError(ERROR_MORE_DATA);
-                                ret = FALSE;
-                            }
-                            else
-                            {
-                                BYTE *originalData = attr->Value.pbData;
-
-                                *pcbAttr = bytesNeeded;
-                                /* strange: decode the value first, because it
-                                 * has a counted size, and we can store the OID
-                                 * after it.  Keep track of the original data
-                                 * pointer, we'll need to know whether it was
-                                 * changed.
-                                 */
-                                size = bytesNeeded;
-                                ret = CRYPT_AsnDecodeNameValue(
-                                 pbEncoded + nameValueOffset,
-                                 cbEncoded - nameValueOffset, dwFlags,
-                                 (CERT_NAME_VALUE *)&attr->dwValueType, &size);
-                                if (ret)
-                                {
-                                    if (objIdLen)
-                                    {
-                                        /* if the data were copied to the
-                                         * original location, the OID goes
-                                         * after.  Otherwise it goes in the
-                                         * spot originally reserved for the
-                                         * data.
-                                         */
-                                        if (attr->Value.pbData == originalData)
-                                            attr->pszObjId =
-                                             (LPSTR)(attr->Value.pbData +
-                                             attr->Value.cbData);
-                                        else
-                                            attr->pszObjId =
-                                             (LPSTR)originalData;
-                                        size = bytesNeeded - size;
-                                        ret = CRYPT_AsnDecodeOid(
-                                         pbEncoded + objIdOfset,
-                                         cbEncoded - objIdOfset,
-                                         dwFlags, attr->pszObjId, &size);
-                                    }
-                                    else
-                                        attr->pszObjId = NULL;
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        else
-        {
-            SetLastError(CRYPT_E_ASN1_BADTAG);
-            ret = FALSE;
-        }
-    }
-    __EXCEPT(page_fault)
-    {
-        SetLastError(STATUS_ACCESS_VIOLATION);
-        ret = FALSE;
-    }
-    __ENDTRY
-    return ret;
-}
-
-static BOOL WINAPI CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
- DWORD dwFlags, CERT_RDN *rdn, DWORD *pcbRdn)
-{
-    BOOL ret = TRUE;
-
-    __TRY
-    {
-        if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SETOF))
-        {
-            DWORD dataLen;
-
-            if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
-            {
-                DWORD bytesNeeded, cRDNAttr = 0;
-                BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
-
-                bytesNeeded = sizeof(CERT_RDN);
-                if (dataLen)
-                {
-                    const BYTE *ptr;
-                    DWORD size;
-
-                    for (ptr = pbEncoded + 1 + lenBytes; ret &&
-                     ptr - pbEncoded - 1 - lenBytes < dataLen; )
-                    {
-                        ret = CRYPT_AsnDecodeRdnAttr(ptr,
-                         cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
-                        if (ret)
-                        {
-                            DWORD nextLen;
-
-                            cRDNAttr++;
-                            bytesNeeded += size;
-                            ret = CRYPT_GetLen(ptr,
-                             cbEncoded - (ptr - pbEncoded), &nextLen);
-                            if (ret)
-                                ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
-                        }
-                    }
-                }
-                if (ret)
-                {
-                    if (!rdn)
-                        *pcbRdn = bytesNeeded;
-                    else if (*pcbRdn < bytesNeeded)
-                    {
-                        *pcbRdn = bytesNeeded;
-                        SetLastError(ERROR_MORE_DATA);
-                        ret = FALSE;
-                    }
-                    else
-                    {
-                        DWORD size, i;
-                        BYTE *nextData;
-                        const BYTE *ptr;
-
-                        *pcbRdn = bytesNeeded;
-                        rdn->cRDNAttr = cRDNAttr;
-                        rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn +
-                         sizeof(CERT_RDN));
-                        nextData = (BYTE *)rdn->rgRDNAttr +
-                         rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
-                        for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
-                         i < cRDNAttr && ptr - pbEncoded - 1 - lenBytes <
-                         dataLen; i++)
-                        {
-                            rdn->rgRDNAttr[i].Value.pbData = nextData;
-                            size = bytesNeeded;
-                            ret = CRYPT_AsnDecodeRdnAttr(ptr,
-                             cbEncoded - (ptr - pbEncoded), dwFlags,
-                             &rdn->rgRDNAttr[i], &size);
-                            if (ret)
-                            {
-                                DWORD nextLen;
-
-                                bytesNeeded -= size;
-                                /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
-                                 * data may not have been copied.
-                                 */
-                                if (rdn->rgRDNAttr[i].Value.pbData == nextData)
-                                    nextData +=
-                                     rdn->rgRDNAttr[i].Value.cbData;
-                                /* Ugly: the OID, if copied, is stored in
-                                 * memory after the value, so increment by its
-                                 * string length if it's set and points here.
-                                 */
-                                if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId
-                                 == nextData)
-                                    nextData += strlen(
-                                     rdn->rgRDNAttr[i].pszObjId) + 1;
-                                ret = CRYPT_GetLen(ptr,
-                                 cbEncoded - (ptr - pbEncoded), &nextLen);
-                                if (ret)
-                                    ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
-                            }
-                        }
+                        value->Value.cbData = 0;
+                        value->Value.pbData = NULL;
                     }
                 }
             }
         }
-        else
-        {
-            SetLastError(CRYPT_E_ASN1_BADTAG);
-            ret = FALSE;
-        }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -3589,108 +3527,86 @@ static BOOL WINAPI CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
+static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
-    BOOL ret = TRUE;
+    BOOL ret;
+
+    TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo);
 
     __TRY
     {
-        if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
-        {
-            DWORD dataLen;
+        struct AsnDecodeSequenceItem items[] = {
+         { ASN_OBJECTIDENTIFIER, offsetof(CERT_RDN_ATTR, pszObjId),
+           CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE,
+           offsetof(CERT_RDN_ATTR, pszObjId), 0 },
+         { 0, offsetof(CERT_RDN_ATTR, dwValueType), CRYPT_AsnDecodeNameValue,
+           sizeof(CERT_NAME_VALUE), FALSE, TRUE, offsetof(CERT_RDN_ATTR,
+           Value.pbData), 0 },
+        };
+        CERT_RDN_ATTR *attr = (CERT_RDN_ATTR *)pvStructInfo;
 
-            if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
-            {
-                DWORD bytesNeeded, cRDN = 0;
-                BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+        if (attr)
+            TRACE("attr->pszObjId is %p\n", attr->pszObjId);
+        ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
+         sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL,
+         attr, pcbStructInfo, attr ? attr->pszObjId : NULL);
+        if (attr)
+            TRACE("attr->pszObjId is %p (%s)\n", attr->pszObjId,
+             debugstr_a(attr->pszObjId));
+        TRACE("returning %d (%08lx)\n", ret, GetLastError());
+    }
+    __EXCEPT_PAGE_FAULT
+    {
+        SetLastError(STATUS_ACCESS_VIOLATION);
+        ret = FALSE;
+    }
+    __ENDTRY
+    return ret;
+}
 
-                bytesNeeded = sizeof(CERT_NAME_INFO);
-                if (dataLen)
-                {
-                    const BYTE *ptr;
+static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+{
+    BOOL ret = TRUE;
 
-                    for (ptr = pbEncoded + 1 + lenBytes; ret &&
-                     ptr - pbEncoded - 1 - lenBytes < dataLen; )
-                    {
-                        DWORD size;
+    __TRY
+    {
+        struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF,
+         CRYPT_AsnDecodeRdnAttr, sizeof(CERT_RDN_ATTR), TRUE,
+         offsetof(CERT_RDN_ATTR, pszObjId) };
 
-                        ret = CRYPT_AsnDecodeRdn(ptr,
-                         cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
-                        if (ret)
-                        {
-                            DWORD nextLen;
+        ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
+         pDecodePara, pvStructInfo, pcbStructInfo, NULL);
+    }
+    __EXCEPT_PAGE_FAULT
+    {
+        SetLastError(STATUS_ACCESS_VIOLATION);
+        ret = FALSE;
+    }
+    __ENDTRY
+    return ret;
+}
 
-                            cRDN++;
-                            bytesNeeded += size;
-                            ret = CRYPT_GetLen(ptr,
-                             cbEncoded - (ptr - pbEncoded), &nextLen);
-                            if (ret)
-                                ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
-                        }
-                    }
-                }
-                if (ret)
-                {
-                    if (!pvStructInfo)
-                        *pcbStructInfo = bytesNeeded;
-                    else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
-                     pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
-                    {
-                        CERT_NAME_INFO *info;
+static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+{
+    BOOL ret = TRUE;
 
-                        if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
-                            pvStructInfo = *(BYTE **)pvStructInfo;
-                        info = (CERT_NAME_INFO *)pvStructInfo;
-                        info->cRDN = cRDN;
-                        if (info->cRDN == 0)
-                            info->rgRDN = NULL;
-                        else
-                        {
-                            DWORD size, i;
-                            BYTE *nextData;
-                            const BYTE *ptr;
-
-                            info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
-                             sizeof(CERT_NAME_INFO));
-                            nextData = (BYTE *)info->rgRDN +
-                             info->cRDN * sizeof(CERT_RDN);
-                            for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
-                             i < cRDN && ptr - pbEncoded - 1 - lenBytes <
-                             dataLen; i++)
-                            {
-                                info->rgRDN[i].rgRDNAttr =
-                                 (CERT_RDN_ATTR *)nextData;
-                                size = bytesNeeded;
-                                ret = CRYPT_AsnDecodeRdn(ptr,
-                                 cbEncoded - (ptr - pbEncoded), dwFlags,
-                                 &info->rgRDN[i], &size);
-                                if (ret)
-                                {
-                                    DWORD nextLen;
-
-                                    nextData += size;
-                                    bytesNeeded -= size;
-                                    ret = CRYPT_GetLen(ptr,
-                                     cbEncoded - (ptr - pbEncoded), &nextLen);
-                                    if (ret)
-                                        ptr += nextLen + 1 +
-                                         GET_LEN_BYTES(ptr[1]);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        else
-        {
-            SetLastError(CRYPT_E_ASN1_BADTAG);
-            ret = FALSE;
-        }
+    __TRY
+    {
+        struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+         CRYPT_AsnDecodeRdn, sizeof(CERT_RDN), TRUE,
+         offsetof(CERT_RDN, rgRDNAttr) };
+
+        ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
+         pDecodePara, pvStructInfo, pcbStructInfo, NULL);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -3744,10 +3660,10 @@ static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
      (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
     BOOL ret = TRUE;
     struct AsnDecodeSequenceItem items[] = {
-     { offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
+     { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
        CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE, 
        offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
-     { offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
+     { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE, 
        offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
     };
@@ -3775,11 +3691,11 @@ static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
     __TRY
     {
         struct AsnDecodeSequenceItem items[] = {
-         { offsetof(CERT_PUBLIC_KEY_INFO, Algorithm),
+         { ASN_SEQUENCEOF, offsetof(CERT_PUBLIC_KEY_INFO, Algorithm),
            CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
            FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO,
            Algorithm.pszObjId) },
-         { offsetof(CERT_PUBLIC_KEY_INFO, PublicKey),
+         { ASN_BITSTRING, offsetof(CERT_PUBLIC_KEY_INFO, PublicKey),
            CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
            offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) },
         };
@@ -3788,7 +3704,7 @@ static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -3808,11 +3724,6 @@ static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
         SetLastError(CRYPT_E_ASN1_CORRUPT);
         return FALSE;
     }
-    if (pbEncoded[0] != ASN_BOOL)
-    {
-        SetLastError(CRYPT_E_ASN1_BADTAG);
-        return FALSE;
-    }
     if (GET_LEN_BYTES(pbEncoded[1]) > 1)
     {
         SetLastError(CRYPT_E_ASN1_CORRUPT);
@@ -3843,12 +3754,17 @@ static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL CRYPT_AsnDecodeAltNameEntry(const BYTE *pbEncoded, DWORD cbEncoded,
- DWORD dwFlags, CERT_ALT_NAME_ENTRY *entry, DWORD *pcbEntry)
+static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
+    PCERT_ALT_NAME_ENTRY entry = (PCERT_ALT_NAME_ENTRY)pvStructInfo;
     DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY);
     BOOL ret;
 
+    TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
+     pDecodePara, pvStructInfo, *pcbStructInfo);
+
     if (cbEncoded < 2)
     {
         SetLastError(CRYPT_E_ASN1_CORRUPT);
@@ -3897,14 +3813,16 @@ static BOOL CRYPT_AsnDecodeAltNameEntry(const BYTE *pbEncoded, DWORD cbEncoded,
         if (ret)
         {
             if (!entry)
-                *pcbEntry = bytesNeeded;
-            else if (*pcbEntry < bytesNeeded)
+                *pcbStructInfo = bytesNeeded;
+            else if (*pcbStructInfo < bytesNeeded)
             {
+                *pcbStructInfo = bytesNeeded;
                 SetLastError(ERROR_MORE_DATA);
                 ret = FALSE;
             }
             else
             {
+                *pcbStructInfo = bytesNeeded;
                 /* MS used values one greater than the asn1 ones.. sigh */
                 entry->dwAltNameChoice = (pbEncoded[0] & 0x7f) + 1;
                 switch (pbEncoded[0] & ASN_TYPE_MASK)
@@ -3919,6 +3837,8 @@ static BOOL CRYPT_AsnDecodeAltNameEntry(const BYTE *pbEncoded, DWORD cbEncoded,
                         entry->u.pwszURL[i] =
                          (WCHAR)pbEncoded[1 + lenBytes + i];
                     entry->u.pwszURL[i] = 0;
+                    TRACE("URL is %p (%s)\n", entry->u.pwszURL,
+                     debugstr_w(entry->u.pwszURL));
                     break;
                 }
                 case 7: /* iPAddress */
@@ -3937,111 +3857,45 @@ static BOOL CRYPT_AsnDecodeAltNameEntry(const BYTE *pbEncoded, DWORD cbEncoded,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType,
+static BOOL WINAPI CRYPT_AsnDecodeAltNameInternal(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
     BOOL ret = TRUE;
+    struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+     CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE,
+     offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) };
+    PCERT_ALT_NAME_INFO info = (PCERT_ALT_NAME_INFO)pvStructInfo;
 
-    __TRY
-    {
-        if (pbEncoded[0] == ASN_SEQUENCEOF)
-        {
-            DWORD dataLen;
-
-            if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
-            {
-                DWORD bytesNeeded, cEntry = 0;
-                BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+    TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
+     pDecodePara, pvStructInfo, *pcbStructInfo);
 
-                bytesNeeded = sizeof(CERT_ALT_NAME_INFO);
-                if (dataLen)
-                {
-                    const BYTE *ptr;
+    if (info)
+        TRACE("info->rgAltEntry is %p\n", info->rgAltEntry);
+    ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
+     pDecodePara, pvStructInfo, pcbStructInfo, info ? info->rgAltEntry : NULL);
+    return ret;
+}
 
-                    for (ptr = pbEncoded + 1 + lenBytes; ret &&
-                     ptr - pbEncoded - 1 - lenBytes < dataLen; )
-                    {
-                        DWORD size;
+static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+{
+    BOOL ret = TRUE;
 
-                        ret = CRYPT_AsnDecodeAltNameEntry(ptr,
-                         cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
-                        if (ret)
-                        {
-                            DWORD nextLen;
+    TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
+     pDecodePara, pvStructInfo, *pcbStructInfo);
 
-                            cEntry++;
-                            bytesNeeded += size;
-                            ret = CRYPT_GetLen(ptr,
-                             cbEncoded - (ptr - pbEncoded), &nextLen);
-                            if (ret)
-                                ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
-                        }
-                    }
-                }
-                if (ret)
-                {
-                    if (!pvStructInfo)
-                        *pcbStructInfo = bytesNeeded;
-                    else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
-                     pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
-                    {
-                        CERT_ALT_NAME_INFO *info;
+    __TRY
+    {
+        struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+         CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE,
+         offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) };
 
-                        if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
-                            pvStructInfo = *(BYTE **)pvStructInfo;
-                        info = (CERT_ALT_NAME_INFO *)pvStructInfo;
-                        info->cAltEntry = 0;
-                        if (cEntry == 0)
-                            info->rgAltEntry = NULL;
-                        else
-                        {
-                            DWORD size, i;
-                            BYTE *nextData;
-                            const BYTE *ptr;
-
-                            info->rgAltEntry =
-                             (CERT_ALT_NAME_ENTRY *)((BYTE *)pvStructInfo +
-                             sizeof(CERT_ALT_NAME_INFO));
-                            nextData = (BYTE *)info->rgAltEntry +
-                             cEntry * sizeof(CERT_ALT_NAME_ENTRY);
-                            for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
-                             i < cEntry && ptr - pbEncoded - 1 - lenBytes <
-                             dataLen; i++)
-                            {
-                                info->rgAltEntry[i].u.pwszURL =
-                                 (LPWSTR)nextData;
-                                size = bytesNeeded;
-                                ret = CRYPT_AsnDecodeAltNameEntry(ptr,
-                                 cbEncoded - (ptr - pbEncoded), dwFlags,
-                                 &info->rgAltEntry[i], &size);
-                                if (ret)
-                                {
-                                    DWORD nextLen;
-
-                                    info->cAltEntry++;
-                                    nextData += size -
-                                     sizeof(CERT_ALT_NAME_ENTRY);
-                                    bytesNeeded -= size;
-                                    ret = CRYPT_GetLen(ptr,
-                                     cbEncoded - (ptr - pbEncoded), &nextLen);
-                                    if (ret)
-                                        ptr += nextLen + 1 +
-                                         GET_LEN_BYTES(ptr[1]);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        else
-        {
-            SetLastError(CRYPT_E_ASN1_BADTAG);
-            ret = FALSE;
-        }
+        ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
+         pDecodePara, pvStructInfo, pcbStructInfo, NULL);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -4062,6 +3916,9 @@ static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType,
 {
     BOOL ret = TRUE;
 
+    TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo);
+
     if (cbEncoded)
     {
         if (pbEncoded[0] == ASN_INTEGER)
@@ -4110,18 +3967,18 @@ static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
     __TRY
     {
         struct AsnDecodeSequenceItem items[] = {
-         { offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fCA), CRYPT_AsnDecodeBool,
-           sizeof(BOOL), TRUE, FALSE, 0, 0 },
-         { offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fPathLenConstraint),
-           CRYPT_AsnDecodePathLenConstraint, sizeof(struct PATH_LEN_CONSTRAINT),
-           TRUE, FALSE, 0, 0 },
+         { ASN_BOOL, offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fCA),
+           CRYPT_AsnDecodeBool, sizeof(BOOL), TRUE, FALSE, 0, 0 },
+         { ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS2_INFO,
+           fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint,
+           sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 },
         };
 
         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -4147,11 +4004,11 @@ static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
     __TRY
     {
         struct AsnDecodeSequenceItem items[] = {
-         { offsetof(struct DECODED_RSA_PUB_KEY, modulus),
+         { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, modulus),
            CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB),
            FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData),
            0 },
-         { offsetof(struct DECODED_RSA_PUB_KEY, pubexp),
+         { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, pubexp),
            CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
         };
         struct DECODED_RSA_PUB_KEY *decodedKey = NULL;
@@ -4195,7 +4052,7 @@ static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
             LocalFree(decodedKey);
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -4209,52 +4066,43 @@ static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
     BOOL ret;
+    DWORD bytesNeeded, dataLen;
 
     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
      pDecodePara, pvStructInfo, *pcbStructInfo);
 
-    if (pbEncoded[0] == ASN_OCTETSTRING)
+    if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
     {
-        DWORD bytesNeeded, dataLen;
-
-        if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+        if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
+            bytesNeeded = sizeof(CRYPT_DATA_BLOB);
+        else
+            bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
+        if (!pvStructInfo)
+            *pcbStructInfo = bytesNeeded;
+        else if (*pcbStructInfo < bytesNeeded)
+        {
+            SetLastError(ERROR_MORE_DATA);
+            *pcbStructInfo = bytesNeeded;
+            ret = FALSE;
+        }
+        else
         {
+            CRYPT_DATA_BLOB *blob;
+            BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+
+            blob = (CRYPT_DATA_BLOB *)pvStructInfo;
+            blob->cbData = dataLen;
             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
-                bytesNeeded = sizeof(CRYPT_DATA_BLOB);
-            else
-                bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
-            if (!pvStructInfo)
-                *pcbStructInfo = bytesNeeded;
-            else if (*pcbStructInfo < bytesNeeded)
-            {
-                SetLastError(ERROR_MORE_DATA);
-                *pcbStructInfo = bytesNeeded;
-                ret = FALSE;
-            }
+                blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
             else
             {
-                CRYPT_DATA_BLOB *blob;
-                BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
-
-                blob = (CRYPT_DATA_BLOB *)pvStructInfo;
-                blob->cbData = dataLen;
-                if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
-                    blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
-                else
-                {
-                    assert(blob->pbData);
-                    if (blob->cbData)
-                        memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
-                         blob->cbData);
-                }
+                assert(blob->pbData);
+                if (blob->cbData)
+                    memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
+                     blob->cbData);
             }
         }
     }
-    else
-    {
-        SetLastError(CRYPT_E_ASN1_BADTAG);
-        ret = FALSE;
-    }
     return ret;
 }
 
@@ -4271,7 +4119,17 @@ static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
     {
         DWORD bytesNeeded;
 
-        if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
+        if (!cbEncoded)
+        {
+            SetLastError(CRYPT_E_ASN1_CORRUPT);
+            ret = FALSE;
+        }
+        else if (pbEncoded[0] != ASN_OCTETSTRING)
+        {
+            SetLastError(CRYPT_E_ASN1_BADTAG);
+            ret = FALSE;
+        }
+        else if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
          lpszStructType, pbEncoded, cbEncoded,
          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
         {
@@ -4292,13 +4150,8 @@ static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
                  &bytesNeeded);
             }
         }
-        else
-        {
-            SetLastError(CRYPT_E_ASN1_BADTAG);
-            ret = FALSE;
-        }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -4406,7 +4259,7 @@ static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -4463,7 +4316,7 @@ static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
         else if (GetLastError() == ERROR_MORE_DATA)
             SetLastError(CRYPT_E_ASN1_LARGE);
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -4555,7 +4408,7 @@ static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -4654,7 +4507,7 @@ static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -4722,7 +4575,7 @@ static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
             ret = FALSE;
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -4810,7 +4663,7 @@ static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
             }
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -4901,7 +4754,7 @@ static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
             ret = FALSE;
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -4996,7 +4849,7 @@ static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
             ret = FALSE;
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -5027,7 +4880,7 @@ static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
             ret = FALSE;
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -5130,7 +4983,58 @@ static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
             return FALSE;
         }
     }
-    __EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
+    {
+        SetLastError(STATUS_ACCESS_VIOLATION);
+        ret = FALSE;
+    }
+    __ENDTRY
+    return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnDecodeDistPoint(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+{
+    struct AsnDecodeSequenceItem items[] = {
+     { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, offsetof(CRL_DIST_POINT,
+       DistPointName), CRYPT_AsnDecodeAltNameInternal,
+       sizeof(CRL_DIST_POINT_NAME), TRUE, TRUE, offsetof(CRL_DIST_POINT,
+       DistPointName.u.FullName.rgAltEntry), 0 },
+     { ASN_CONTEXT | 1, offsetof(CRL_DIST_POINT, ReasonFlags),
+       CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
+       offsetof(CRL_DIST_POINT, ReasonFlags.pbData), 0 },
+     { ASN_CONTEXT | ASN_CONSTRUCTOR | 2, offsetof(CRL_DIST_POINT, CRLIssuer),
+       CRYPT_AsnDecodeAltNameInternal, sizeof(CERT_ALT_NAME_INFO), TRUE, TRUE,
+       offsetof(CRL_DIST_POINT, CRLIssuer.rgAltEntry), 0 },
+    };
+    BOOL ret;
+
+    ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
+     sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded,
+     dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL);
+    return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnDecodeCRLDistPoints(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+{
+    BOOL ret;
+
+    TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
+     pDecodePara, pvStructInfo, *pcbStructInfo);
+
+    __TRY
+    {
+        struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+         CRYPT_AsnDecodeDistPoint, sizeof(CRL_DIST_POINT), TRUE,
+         offsetof(CRL_DIST_POINT, DistPointName.u.FullName.rgAltEntry) };
+
+        ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
+         pDecodePara, pvStructInfo, pcbStructInfo, NULL);
+    }
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         ret = FALSE;
@@ -5236,6 +5140,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
         case (WORD)PKCS_UTC_TIME:
             decodeFunc = CRYPT_AsnDecodeUtcTime;
             break;
+        case (WORD)X509_CRL_DIST_POINTS:
+            decodeFunc = CRYPT_AsnDecodeCRLDistPoints;
+            break;
         default:
             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
         }
index 782371f..94d90ae 100644 (file)
@@ -1711,7 +1711,46 @@ typedef BOOL (WINAPI *PFN_CRYPT_ENUM_OID_FUNC)(DWORD dwEncodingType,
  LPCWSTR const rgpwszValueName[], const BYTE * const rgpbValueData[],
  const DWORD rgcbValueData[], void *pvArg);
 
-/* subject types for CryptVerifyCertificateSignatureEx */
+typedef struct _CRL_DIST_POINT_NAME {
+    DWORD dwDistPointNameChoice;
+    union {
+        CERT_ALT_NAME_INFO FullName;
+    } DUMMYUNIONNAME;
+} CRL_DIST_POINT_NAME, *PCRL_DIST_POINT_NAME;
+
+#define CRL_DIST_POINT_NO_NAME         0
+#define CRL_DIST_POINT_FULL_NAME       1
+#define CRL_DIST_POINT_ISSUER_RDN_NAME 2
+
+typedef struct _CRL_DIST_POINT {
+    CRL_DIST_POINT_NAME DistPointName;
+    CRYPT_BIT_BLOB      ReasonFlags;
+    CERT_ALT_NAME_INFO  CRLIssuer;
+} CRL_DIST_POINT, *PCRL_DIST_POINT;
+
+#define CRL_REASON_UNUSED_FLAG                 0x80
+#define CRL_REASON_KEY_COMPROMISE_FLAG         0x40
+#define CRL_REASON_CA_COMPROMISE_FLAG          0x20
+#define CRL_REASON_AFFILIATION_CHANGED_FLAG    0x10
+#define CRL_REASON_SUPERSEDED_FLAG             0x08
+#define CRL_REASON_CESSATION_OF_OPERATION_FLAG 0x04
+#define CRL_REASON_CERTIFICATE_HOLD_FLAG       0x02
+
+typedef struct _CRL_DIST_POINTS_INFO {
+    DWORD           cDistPoint;
+    PCRL_DIST_POINT rgDistPoint;
+} CRL_DIST_POINTS_INFO, *PCRL_DIST_POINTS_INFO;
+
+#define CRL_DIST_POINT_ERR_INDEX_MASK  0x7f
+#define CRL_DIST_POINT_ERR_INDEX_SHIFT 24
+#define GET_CRL_DIST_POINT_ERR_INDEX(x) \
+ (((x) >> CRL_DIST_POINT_ERR_INDEX_SHIFT) & CRL_DIST_POINT_ERR_INDEX_MASK)
+
+#define CRL_DIST_POINT_ERR_CRL_ISSUER_BIT 0x80000000L
+#define IS_CRL_DIST_POINT_ERR_CRL_ISSUER(x) \
+ ((x) & CRL_DIST_POINT_ERR_CRL_ISSUER_BIT)
+
+/*  types for CryptVerifyCertificateSignatureEx */
 #define CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB 1
 #define CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT 2
 #define CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL  3