Samuel Serapión (samdwise51 AT gmail DOT com):
authorColin Finck <colin@reactos.org>
Sat, 10 May 2008 18:43:43 +0000 (18:43 +0000)
committerColin Finck <colin@reactos.org>
Sat, 10 May 2008 18:43:43 +0000 (18:43 +0000)
- Winesync of crypt32
  The function import_certs_from_dir had to be killed, because it uses UNIX-only functions. (see "crypt32_ros.diff")
- This gets MSN Messenger a bit more to work

svn path=/trunk/; revision=33417

35 files changed:
reactos/dll/win32/crypt32/cert.c
reactos/dll/win32/crypt32/chain.c
reactos/dll/win32/crypt32/collectionstore.c [new file with mode: 0644]
reactos/dll/win32/crypt32/context.c
reactos/dll/win32/crypt32/crl.c
reactos/dll/win32/crypt32/crypt32.rbuild
reactos/dll/win32/crypt32/crypt32.rc
reactos/dll/win32/crypt32/crypt32.spec
reactos/dll/win32/crypt32/crypt32_De.rc
reactos/dll/win32/crypt32/crypt32_En.rc
reactos/dll/win32/crypt32/crypt32_Fr.rc
reactos/dll/win32/crypt32/crypt32_Ko.rc
reactos/dll/win32/crypt32/crypt32_Nl.rc [new file with mode: 0644]
reactos/dll/win32/crypt32/crypt32_No.rc
reactos/dll/win32/crypt32/crypt32_Sv.rc [new file with mode: 0644]
reactos/dll/win32/crypt32/crypt32_private.h
reactos/dll/win32/crypt32/crypt32_ros.diff
reactos/dll/win32/crypt32/cryptres.h
reactos/dll/win32/crypt32/decode.c
reactos/dll/win32/crypt32/encode.c
reactos/dll/win32/crypt32/filestore.c [new file with mode: 0644]
reactos/dll/win32/crypt32/main.c
reactos/dll/win32/crypt32/msg.c [new file with mode: 0644]
reactos/dll/win32/crypt32/object.c [new file with mode: 0644]
reactos/dll/win32/crypt32/oid.c
reactos/dll/win32/crypt32/protectdata.c
reactos/dll/win32/crypt32/provstore.c [new file with mode: 0644]
reactos/dll/win32/crypt32/regstore.c [new file with mode: 0644]
reactos/dll/win32/crypt32/rootstore.c [new file with mode: 0644]
reactos/dll/win32/crypt32/serialize.c
reactos/dll/win32/crypt32/sip.c
reactos/dll/win32/crypt32/store.c
reactos/dll/win32/crypt32/str.c
reactos/include/psdk/i_cryptasn1tls.h [new file with mode: 0644]
reactos/include/psdk/wincrypt.h

index 056096b..41d3998 100644 (file)
@@ -158,7 +158,7 @@ static BOOL CertContext_GetHashProp(void *context, DWORD dwPropId,
 {
     BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
      pcbData);
-    if (ret)
+    if (ret && pvData)
     {
         CRYPT_DATA_BLOB blob = { *pcbData, pvData };
 
@@ -167,6 +167,27 @@ static BOOL CertContext_GetHashProp(void *context, DWORD dwPropId,
     return ret;
 }
 
+static BOOL CertContext_CopyParam(void *pvData, DWORD *pcbData, const void *pb,
+ DWORD cb)
+{
+    BOOL ret = TRUE;
+
+    if (!pvData)
+        *pcbData = cb;
+    else if (*pcbData < cb)
+    {
+        SetLastError(ERROR_MORE_DATA);
+        *pcbData = cb;
+        ret = FALSE;
+    }
+    else
+    {
+        memcpy(pvData, pb, cb);
+        *pcbData = cb;
+    }
+    return ret;
+}
+
 static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId,
  void *pvData, DWORD *pcbData)
 {
@@ -183,24 +204,7 @@ static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId,
     else
         ret = FALSE;
     if (ret)
-    {
-        if (!pvData)
-        {
-            *pcbData = blob.cbData;
-            ret = TRUE;
-        }
-        else if (*pcbData < blob.cbData)
-        {
-            SetLastError(ERROR_MORE_DATA);
-            *pcbData = blob.cbData;
-        }
-        else
-        {
-            memcpy(pvData, blob.pbData, blob.cbData);
-            *pcbData = blob.cbData;
-            ret = TRUE;
-        }
-    }
+        ret = CertContext_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
     else
     {
         /* Implicit properties */
@@ -238,6 +242,32 @@ static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId,
             FIXME("CERT_SIGNATURE_HASH_PROP_ID unimplemented\n");
             SetLastError(CRYPT_E_NOT_FOUND);
             break;
+        case CERT_KEY_IDENTIFIER_PROP_ID:
+        {
+            PCERT_EXTENSION ext = CertFindExtension(
+             szOID_SUBJECT_KEY_IDENTIFIER, pCertContext->pCertInfo->cExtension,
+             pCertContext->pCertInfo->rgExtension);
+
+            if (ext)
+            {
+                CRYPT_DATA_BLOB value;
+                DWORD size = sizeof(value);
+
+                ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
+                 szOID_SUBJECT_KEY_IDENTIFIER, ext->Value.pbData,
+                 ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &value,
+                 &size);
+                if (ret)
+                {
+                    ret = CertContext_CopyParam(pvData, pcbData, value.pbData,
+                     value.cbData);
+                    CertContext_SetProperty(context, dwPropId, 0, &value);
+                }
+            }
+            else
+                SetLastError(ERROR_INVALID_DATA);
+            break;
+        }
         default:
             SetLastError(CRYPT_E_NOT_FOUND);
         }
@@ -286,30 +316,16 @@ BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
         ret = FALSE;
         break;
     case CERT_ACCESS_STATE_PROP_ID:
-        if (!pvData)
-        {
-            *pcbData = sizeof(DWORD);
-            ret = TRUE;
-        }
-        else if (*pcbData < sizeof(DWORD))
-        {
-            SetLastError(ERROR_MORE_DATA);
-            *pcbData = sizeof(DWORD);
-            ret = FALSE;
-        }
+        if (pCertContext->hCertStore)
+            ret = CertGetStoreProperty(pCertContext->hCertStore, dwPropId,
+             pvData, pcbData);
         else
         {
-            *(DWORD *)pvData =
-             CertStore_GetAccessState(pCertContext->hCertStore);
-            ret = TRUE;
+            DWORD state = 0;
+
+            ret = CertContext_CopyParam(pvData, pcbData, &state, sizeof(state));
         }
         break;
-    case CERT_KEY_IDENTIFIER_PROP_ID:
-        ret = CertContext_GetProperty((void *)pCertContext, dwPropId,
-         pvData, pcbData);
-        if (!ret)
-            SetLastError(ERROR_INVALID_DATA);
-        break;
     case CERT_KEY_PROV_HANDLE_PROP_ID:
     {
         CERT_KEY_CONTEXT keyContext;
@@ -318,24 +334,8 @@ BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
         ret = CertContext_GetProperty((void *)pCertContext,
          CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size);
         if (ret)
-        {
-            if (!pvData)
-            {
-                *pcbData = sizeof(HCRYPTPROV);
-                ret = TRUE;
-            }
-            else if (*pcbData < sizeof(HCRYPTPROV))
-            {
-                SetLastError(ERROR_MORE_DATA);
-                *pcbData = sizeof(HCRYPTPROV);
-                ret = FALSE;
-            }
-            else
-            {
-                *(HCRYPTPROV *)pvData = keyContext.hCryptProv;
-                ret = TRUE;
-            }
-        }
+            ret = CertContext_CopyParam(pvData, pcbData, &keyContext.hCryptProv,
+             sizeof(keyContext.hCryptProv));
         break;
     }
     case CERT_KEY_PROV_INFO_PROP_ID:
@@ -496,8 +496,14 @@ static BOOL WINAPI CertContext_SetProperty(void *context, DWORD dwPropId,
             {
                 const CERT_KEY_CONTEXT *keyContext = (const CERT_KEY_CONTEXT *)pvData;
 
-                ret = ContextPropertyList_SetProperty(properties, dwPropId,
-                 (const BYTE *)keyContext, keyContext->cbSize);
+                if (keyContext->cbSize != sizeof(CERT_KEY_CONTEXT))
+                {
+                    SetLastError(E_INVALIDARG);
+                    ret = FALSE;
+                }
+                else
+                    ret = ContextPropertyList_SetProperty(properties, dwPropId,
+                     (const BYTE *)keyContext, keyContext->cbSize);
             }
             else
             {
@@ -623,8 +629,8 @@ static BOOL CRYPT_AcquirePrivateKeyFromProvInfo(PCCERT_CONTEXT pCert,
 }
 
 BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert,
- DWORD dwFlags, void *pvReserved, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec,
- BOOL *pfCallerFreeProv)
+ DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv,
DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
 {
     BOOL ret = FALSE, cache = FALSE;
     PCRYPT_KEY_PROV_INFO info = NULL;
@@ -700,11 +706,15 @@ BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert,
 BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
  PCERT_INFO pCertId1, PCERT_INFO pCertId2)
 {
+    BOOL ret;
+
     TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2);
 
-    return CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
+    ret = CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
      &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber,
      &pCertId2->SerialNumber);
+    TRACE("returning %d\n", ret);
+    return ret;
 }
 
 BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
@@ -724,6 +734,7 @@ BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
     }
     else
         ret = FALSE;
+    TRACE("returning %d\n", ret);
     return ret;
 }
 
@@ -760,12 +771,13 @@ BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
     if (cb1 == cb2)
     {
         if (cb1)
-            ret = !memcmp(pInt1->pbData, pInt1->pbData, cb1);
+            ret = !memcmp(pInt1->pbData, pInt2->pbData, cb1);
         else
             ret = TRUE;
     }
     else
         ret = FALSE;
+    TRACE("returning %d\n", ret);
     return ret;
 }
 
@@ -819,8 +831,7 @@ DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType,
 
         if (ret)
         {
-            RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)((LPBYTE)buf +
-             sizeof(BLOBHEADER));
+            RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
 
             len = rsaPubKey->bitlen;
             LocalFree(buf);
@@ -899,16 +910,185 @@ static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext,
  DWORD dwType, DWORD dwFlags, const void *pvPara)
 {
     CERT_INFO *pCertInfo = (CERT_INFO *)pvPara;
+    BOOL ret;
 
-    return CertCompareCertificateName(pCertContext->dwCertEncodingType,
+    /* Matching serial number and subject match.. */
+    ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
      &pCertInfo->Issuer, &pCertContext->pCertInfo->Subject);
+    if (ret)
+        ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
+         &pCertInfo->SerialNumber);
+    else
+    {
+        /* failing that, if the serial number and issuer match, we match */
+        ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
+         &pCertInfo->SerialNumber);
+        if (ret)
+            ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
+             &pCertInfo->Issuer, &pCertContext->pCertInfo->Issuer);
+    }
+    TRACE("returning %d\n", ret);
+    return ret;
 }
 
-static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext,
- DWORD dwType, DWORD dwFlags, const void *pvPara)
+static BOOL compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext, DWORD dwType,
+ DWORD dwFlags, const void *pvPara)
 {
-    return compare_cert_by_subject_cert(pCertContext, dwType, dwFlags,
-     ((PCCERT_CONTEXT)pvPara)->pCertInfo);
+    CERT_ID *id = (CERT_ID *)pvPara;
+    BOOL ret;
+
+    switch (id->dwIdChoice)
+    {
+    case CERT_ID_ISSUER_SERIAL_NUMBER:
+        ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
+         &pCertContext->pCertInfo->Issuer, &id->u.IssuerSerialNumber.Issuer);
+        if (ret)
+            ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
+             &id->u.IssuerSerialNumber.SerialNumber);
+        break;
+    case CERT_ID_SHA1_HASH:
+        ret = compare_cert_by_sha1_hash(pCertContext, dwType, dwFlags,
+         &id->u.HashId);
+        break;
+    case CERT_ID_KEY_IDENTIFIER:
+    {
+        DWORD size = 0;
+
+        ret = CertGetCertificateContextProperty(pCertContext,
+         CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
+        if (ret && size == id->u.KeyId.cbData)
+        {
+            LPBYTE buf = CryptMemAlloc(size);
+
+            if (buf)
+            {
+                CertGetCertificateContextProperty(pCertContext,
+                 CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
+                ret = !memcmp(buf, id->u.KeyId.pbData, size);
+                CryptMemFree(buf);
+            }
+        }
+        else
+            ret = FALSE;
+        break;
+    }
+    default:
+        ret = FALSE;
+        break;
+    }
+    return ret;
+}
+
+static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext, DWORD dwType,
+ DWORD dwFlags, const void *pvPara)
+{
+    BOOL ret = FALSE;
+    PCCERT_CONTEXT subject = (PCCERT_CONTEXT)pvPara;
+    PCERT_EXTENSION ext;
+    DWORD size;
+
+    if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
+     subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
+    {
+        CERT_AUTHORITY_KEY_ID_INFO *info;
+
+        ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
+         X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
+         CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
+         &info, &size);
+        if (ret)
+        {
+            CERT_ID id;
+
+            if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
+            {
+                id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
+                memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer,
+                 sizeof(CERT_NAME_BLOB));
+                memcpy(&id.u.IssuerSerialNumber.SerialNumber,
+                 &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
+                ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
+                 &id);
+            }
+            else if (info->KeyId.cbData)
+            {
+                id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
+                memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
+                ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
+                 &id);
+            }
+            else
+                ret = FALSE;
+            LocalFree(info);
+        }
+    }
+    else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
+     subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
+    {
+        CERT_AUTHORITY_KEY_ID2_INFO *info;
+
+        ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
+         X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
+         CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
+         &info, &size);
+        if (ret)
+        {
+            CERT_ID id;
+
+            if (info->AuthorityCertIssuer.cAltEntry &&
+             info->AuthorityCertSerialNumber.cbData)
+            {
+                PCERT_ALT_NAME_ENTRY directoryName = NULL;
+                DWORD i;
+
+                for (i = 0; !directoryName &&
+                 i < info->AuthorityCertIssuer.cAltEntry; i++)
+                    if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
+                     == CERT_ALT_NAME_DIRECTORY_NAME)
+                        directoryName =
+                         &info->AuthorityCertIssuer.rgAltEntry[i];
+                if (directoryName)
+                {
+                    id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
+                    memcpy(&id.u.IssuerSerialNumber.Issuer,
+                     &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB));
+                    memcpy(&id.u.IssuerSerialNumber.SerialNumber,
+                     &info->AuthorityCertSerialNumber,
+                     sizeof(CRYPT_INTEGER_BLOB));
+                    ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
+                     &id);
+                }
+                else
+                {
+                    FIXME("no supported name type in authority key id2\n");
+                    ret = FALSE;
+                }
+            }
+            else if (info->KeyId.cbData)
+            {
+                id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
+                memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
+                ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
+                 &id);
+            }
+            else
+                ret = FALSE;
+            LocalFree(info);
+        }
+    }
+    else
+       ret = compare_cert_by_name(pCertContext,
+        CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT, dwFlags,
+        &subject->pCertInfo->Issuer);
+    return ret;
+}
+
+static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType,
+ DWORD dwFlags, const void *pvPara)
+{
+    PCCERT_CONTEXT toCompare = (PCCERT_CONTEXT)pvPara;
+    return CertCompareCertificate(pCertContext->dwCertEncodingType,
+     pCertContext->pCertInfo, toCompare->pCertInfo);
 }
 
 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
@@ -918,7 +1098,7 @@ PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
     PCCERT_CONTEXT ret;
     CertCompareFunc compare;
 
-    TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore, dwCertEncodingType,
+    TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore, dwCertEncodingType,
         dwFlags, dwType, pvPara, pPrevCertContext);
 
     switch (dwType >> CERT_COMPARE_SHIFT)
@@ -938,9 +1118,15 @@ PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
     case CERT_COMPARE_SUBJECT_CERT:
         compare = compare_cert_by_subject_cert;
         break;
+    case CERT_COMPARE_CERT_ID:
+        compare = compare_cert_by_cert_id;
+        break;
     case CERT_COMPARE_ISSUER_OF:
         compare = compare_cert_by_issuer;
         break;
+    case CERT_COMPARE_EXISTING:
+        compare = compare_existing_cert;
+        break;
     default:
         FIXME("find type %08x unimplemented\n", dwType);
         compare = NULL;
@@ -964,6 +1150,7 @@ PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
         SetLastError(CRYPT_E_NOT_FOUND);
         ret = NULL;
     }
+    TRACE("returning %p\n", ret);
     return ret;
 }
 
@@ -1050,7 +1237,89 @@ PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
             ret = NULL;
         }
     }
+    TRACE("returning %p\n", ret);
+    return ret;
+}
+
+typedef struct _OLD_CERT_REVOCATION_STATUS {
+    DWORD cbSize;
+    DWORD dwIndex;
+    DWORD dwError;
+    DWORD dwReason;
+} OLD_CERT_REVOCATION_STATUS, *POLD_CERT_REVOCATION_STATUS;
+
+typedef BOOL (WINAPI *CertVerifyRevocationFunc)(DWORD, DWORD, DWORD,
+ void **, DWORD, PCERT_REVOCATION_PARA, PCERT_REVOCATION_STATUS);
+
+BOOL WINAPI CertVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType,
+ DWORD cContext, PVOID rgpvContext[], DWORD dwFlags,
+ PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus)
+{
+    BOOL ret;
+
+    TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType,
+     cContext, rgpvContext, dwFlags, pRevPara, pRevStatus);
+
+    if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) &&
+     pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS))
+    {
+        SetLastError(E_INVALIDARG);
+        return FALSE;
+    }
+    if (cContext)
+    {
+        static HCRYPTOIDFUNCSET set = NULL;
+        DWORD size;
 
+        if (!set)
+            set = CryptInitOIDFunctionSet(CRYPT_OID_VERIFY_REVOCATION_FUNC, 0);
+        ret = CryptGetDefaultOIDDllList(set, dwEncodingType, NULL, &size);
+        if (ret)
+        {
+            if (size == 1)
+            {
+                /* empty list */
+                SetLastError(CRYPT_E_NO_REVOCATION_DLL);
+                ret = FALSE;
+            }
+            else
+            {
+                LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR)), ptr;
+
+                if (dllList)
+                {
+                    ret = CryptGetDefaultOIDDllList(set, dwEncodingType,
+                     dllList, &size);
+                    if (ret)
+                    {
+                        for (ptr = dllList; ret && *ptr;
+                         ptr += lstrlenW(ptr) + 1)
+                        {
+                            CertVerifyRevocationFunc func;
+                            HCRYPTOIDFUNCADDR hFunc;
+
+                            ret = CryptGetDefaultOIDFunctionAddress(set,
+                             dwEncodingType, ptr, 0, (void **)&func, &hFunc);
+                            if (ret)
+                            {
+                                ret = func(dwEncodingType, dwRevType, cContext,
+                                 rgpvContext, dwFlags, pRevPara, pRevStatus);
+                                CryptFreeOIDFunctionAddress(hFunc, 0);
+                            }
+                        }
+                    }
+                    CryptMemFree(dllList);
+                }
+                else
+                {
+                    SetLastError(ERROR_OUTOFMEMORY);
+                    ret = FALSE;
+                }
+            }
+        }
+    }
+    else
+        ret = TRUE;
     return ret;
 }
 
@@ -1128,10 +1397,7 @@ LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
 
     if (!pTimeToVerify)
     {
-        SYSTEMTIME sysTime;
-
-        GetSystemTime(&sysTime);
-        SystemTimeToFileTime(&sysTime, &fileTime);
+        GetSystemTimeAsFileTime(&fileTime);
         pTimeToVerify = &fileTime;
     }
     if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
@@ -1152,7 +1418,7 @@ BOOL WINAPI CertVerifyValidityNesting(PCERT_INFO pSubjectInfo,
      && CertVerifyTimeValidity(&pSubjectInfo->NotAfter, pIssuerInfo) == 0;
 }
 
-BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
+BOOL WINAPI CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
  DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
  DWORD *pcbComputedHash)
 {
@@ -1181,7 +1447,7 @@ BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
     return ret;
 }
 
-BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV hCryptProv, ALG_ID Algid,
+BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
  DWORD dwFlags, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo,
  BYTE *pbComputedHash, DWORD *pcbComputedHash)
 {
@@ -1219,8 +1485,8 @@ BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV hCryptProv, ALG_ID Algid,
     return ret;
 }
 
-BOOL WINAPI CryptSignCertificate(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
- DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
+BOOL WINAPI CryptSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
+ DWORD dwKeySpec, DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
  DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
  const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
 {
@@ -1278,10 +1544,10 @@ BOOL WINAPI CryptSignCertificate(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
     return ret;
 }
 
-BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV hCryptProv,
+BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
  DWORD dwKeySpec, DWORD dwCertEncodingType, LPCSTR lpszStructType,
  const void *pvStructInfo, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
- const void *pvHashAuxInfo, PBYTE pbEncoded, DWORD *pcbEncoded)
+ const void *pvHashAuxInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
 {
     BOOL ret;
     DWORD encodedSize, hashSize;
@@ -1339,7 +1605,7 @@ BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV hCryptProv,
     return ret;
 }
 
-BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv,
+BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv,
  DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
  PCERT_PUBLIC_KEY_INFO pPublicKey)
 {
@@ -1348,7 +1614,7 @@ BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv,
      CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
 }
 
-static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV hCryptProv,
+static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv,
  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
  const CERT_SIGNED_CONTENT_INFO *signedCert)
 {
@@ -1358,38 +1624,17 @@ static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV hCryptProv,
     ALG_ID pubKeyID, hashID;
 
     info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
-     pubKeyInfo->Algorithm.pszObjId, 0);
-    if (!info || (info->dwGroupId != CRYPT_PUBKEY_ALG_OID_GROUP_ID &&
-     info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID))
+     signedCert->SignatureAlgorithm.pszObjId, 0);
+    if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
     {
         SetLastError(NTE_BAD_ALGID);
         return FALSE;
     }
-    if (info->dwGroupId == CRYPT_PUBKEY_ALG_OID_GROUP_ID)
-    {
-        switch (info->u.Algid)
-        {
-            case CALG_RSA_KEYX:
-                pubKeyID = CALG_RSA_SIGN;
-                hashID = CALG_SHA1;
-                break;
-            case CALG_RSA_SIGN:
-                pubKeyID = CALG_RSA_SIGN;
-                hashID = CALG_SHA1;
-                break;
-            default:
-                FIXME("unimplemented for %s\n", pubKeyInfo->Algorithm.pszObjId);
-                return FALSE;
-        }
-    }
+    hashID = info->u.Algid;
+    if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
+        pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
     else
-    {
-        hashID = info->u.Algid;
-        if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
-            pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
-        else
-            pubKeyID = hashID;
-    }
+        pubKeyID = hashID;
     /* Load the default provider if necessary */
     if (!hCryptProv)
         hCryptProv = CRYPT_GetDefaultProvider();
@@ -1414,7 +1659,7 @@ static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV hCryptProv,
     return ret;
 }
 
-BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv,
+BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
  DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
  DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
 {
@@ -1657,29 +1902,43 @@ BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
             if (ret)
             {
-                PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
-                 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
+                DWORD i;
+                BOOL exists = FALSE;
 
-                if (newUsage)
+                /* Make sure usage doesn't already exist */
+                for (i = 0; !exists && i < usage->cUsageIdentifier; i++)
                 {
-                    LPSTR nextOID;
-                    DWORD i;
+                    if (!strcmp(usage->rgpszUsageIdentifier[i],
+                     pszUsageIdentifier))
+                        exists = TRUE;
+                }
+                if (!exists)
+                {
+                    PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
+                     sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
 
-                    newUsage->rgpszUsageIdentifier =
-                     (LPSTR *)((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
-                    nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier +
-                     (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
-                    for (i = 0; i < usage->cUsageIdentifier; i++)
+                    if (newUsage)
                     {
+                        LPSTR nextOID;
+
+                        newUsage->rgpszUsageIdentifier = (LPSTR *)
+                         ((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
+                        nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier
+                          + (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
+                        for (i = 0; i < usage->cUsageIdentifier; i++)
+                        {
+                            newUsage->rgpszUsageIdentifier[i] = nextOID;
+                            strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
+                            nextOID += strlen(nextOID) + 1;
+                        }
                         newUsage->rgpszUsageIdentifier[i] = nextOID;
-                        strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
-                        nextOID += strlen(nextOID) + 1;
+                        strcpy(nextOID, pszUsageIdentifier);
+                        newUsage->cUsageIdentifier = i + 1;
+                        ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
+                        CryptMemFree(newUsage);
                     }
-                    newUsage->rgpszUsageIdentifier[i] = nextOID;
-                    strcpy(nextOID, pszUsageIdentifier);
-                    newUsage->cUsageIdentifier = i + 1;
-                    ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
-                    CryptMemFree(newUsage);
+                    else
+                        ret = FALSE;
                 }
             }
             CryptMemFree(usage);
@@ -1766,18 +2025,57 @@ BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
     return ret;
 }
 
+struct BitField
+{
+    DWORD  cIndexes;
+    DWORD *indexes;
+};
+
+#define BITS_PER_DWORD (sizeof(DWORD) * 8)
+
+static void CRYPT_SetBitInField(struct BitField *field, DWORD bit)
+{
+    DWORD indexIndex = bit / BITS_PER_DWORD;
+
+    if (indexIndex + 1 > field->cIndexes)
+    {
+        if (field->cIndexes)
+            field->indexes = CryptMemRealloc(field->indexes,
+             (indexIndex + 1) * sizeof(DWORD));
+        else
+            field->indexes = CryptMemAlloc(sizeof(DWORD));
+        if (field->indexes)
+        {
+            field->indexes[indexIndex] = 0;
+            field->cIndexes = indexIndex + 1;
+        }
+    }
+    if (field->indexes)
+        field->indexes[indexIndex] |= 1 << (bit % BITS_PER_DWORD);
+}
+
+static BOOL CRYPT_IsBitInFieldSet(struct BitField *field, DWORD bit)
+{
+    BOOL set = FALSE;
+    DWORD indexIndex = bit / BITS_PER_DWORD;
+
+    assert(field->cIndexes);
+    set = field->indexes[indexIndex] & (1 << (bit % BITS_PER_DWORD));
+    return set;
+}
+
 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
- int *cNumOIDSs, LPSTR *rghOIDs, DWORD *pcbOIDs)
+ int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs)
 {
     BOOL ret = TRUE;
     DWORD i, cbOIDs = 0;
     BOOL allUsagesValid = TRUE;
     CERT_ENHKEY_USAGE validUsages = { 0, NULL };
 
-    TRACE("(%d, %p, %p, %p, %d)\n", cCerts, *rghCerts, cNumOIDSs,
+    TRACE("(%d, %p, %d, %p, %d)\n", cCerts, rghCerts, *cNumOIDs,
      rghOIDs, *pcbOIDs);
 
-    for (i = 0; ret && i < cCerts; i++)
+    for (i = 0; i < cCerts; i++)
     {
         CERT_ENHKEY_USAGE usage;
         DWORD size = sizeof(usage);
@@ -1819,12 +2117,11 @@ BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
                                 nextOID += lstrlenA(nextOID) + 1;
                             }
                         }
-                        else
-                            ret = FALSE;
                     }
                     else
                     {
-                        DWORD j, k, validIndexes = 0, numRemoved = 0;
+                        struct BitField validIndexes = { 0, NULL };
+                        DWORD j, k, numRemoved = 0;
 
                         /* Merge: build a bitmap of all the indexes of
                          * validUsages.rgpszUsageIdentifier that are in pUsage.
@@ -1836,7 +2133,7 @@ BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
                                 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
                                  validUsages.rgpszUsageIdentifier[k]))
                                 {
-                                    validIndexes |= (1 << k);
+                                    CRYPT_SetBitInField(&validIndexes, k);
                                     break;
                                 }
                             }
@@ -1846,11 +2143,11 @@ BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
                          */
                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
                         {
-                            if (!(validIndexes & (1 << j)))
+                            if (!CRYPT_IsBitInFieldSet(&validIndexes, j))
                             {
                                 if (j < validUsages.cUsageIdentifier - 1)
                                 {
-                                    memcpy(&validUsages.rgpszUsageIdentifier[j],
+                                    memmove(&validUsages.rgpszUsageIdentifier[j],
                                      &validUsages.rgpszUsageIdentifier[j +
                                      numRemoved + 1],
                                      (validUsages.cUsageIdentifier - numRemoved
@@ -1858,52 +2155,54 @@ BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
                                     cbOIDs -= lstrlenA(
                                      validUsages.rgpszUsageIdentifier[j]) + 1 +
                                      sizeof(LPSTR);
+                                    validUsages.cUsageIdentifier--;
                                     numRemoved++;
                                 }
                                 else
                                     validUsages.cUsageIdentifier--;
                             }
                         }
+                        CryptMemFree(validIndexes.indexes);
                     }
                 }
                 CryptMemFree(pUsage);
             }
-            else
-                ret = FALSE;
         }
     }
-    if (ret)
+    ret = TRUE;
+    if (allUsagesValid)
     {
-        if (allUsagesValid)
+        *cNumOIDs = -1;
+        *pcbOIDs = 0;
+    }
+    else
+    {
+        *cNumOIDs = validUsages.cUsageIdentifier;
+        if (!rghOIDs)
+            *pcbOIDs = cbOIDs;
+        else if (*pcbOIDs < cbOIDs)
         {
-            *cNumOIDSs = -1;
-            *pcbOIDs = 0;
+            *pcbOIDs = cbOIDs;
+            SetLastError(ERROR_MORE_DATA);
+            ret = FALSE;
         }
         else
         {
-            if (!rghOIDs || *pcbOIDs < cbOIDs)
-            {
-                *pcbOIDs = cbOIDs;
-                SetLastError(ERROR_MORE_DATA);
-                ret = FALSE;
-            }
-            else
-            {
-                LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
-                 validUsages.cUsageIdentifier * sizeof(LPSTR));
+            LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
+             validUsages.cUsageIdentifier * sizeof(LPSTR));
 
-                *pcbOIDs = cbOIDs;
-                *cNumOIDSs = validUsages.cUsageIdentifier;
-                for (i = 0; i < validUsages.cUsageIdentifier; i++)
-                {
-                    rghOIDs[i] = nextOID;
-                    lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
-                    nextOID += lstrlenA(nextOID) + 1;
-                }
+            *pcbOIDs = cbOIDs;
+            for (i = 0; i < validUsages.cUsageIdentifier; i++)
+            {
+                rghOIDs[i] = nextOID;
+                lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
+                nextOID += lstrlenA(nextOID) + 1;
             }
         }
     }
     CryptMemFree(validUsages.rgpszUsageIdentifier);
+    TRACE("cNumOIDs: %d\n", *cNumOIDs);
+    TRACE("returning %d\n", ret);
     return ret;
 }
 
@@ -1970,10 +2269,10 @@ static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
             }
         }
         size = sizeof(info.dwKeySpec);
-        ret = CryptGetProvParam(hProv, PP_KEYSPEC, (LPBYTE)&info.dwKeySpec,
-         &size, 0);
-        if (!ret)
-            info.dwKeySpec = AT_SIGNATURE;
+        /* in case no CRYPT_KEY_PROV_INFO given,
+         *  we always use AT_SIGNATURE key spec
+         */
+        info.dwKeySpec = AT_SIGNATURE;
         size = sizeof(info.dwProvType);
         ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
          &size, 0);
@@ -1996,19 +2295,19 @@ static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
  * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
  */
 static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob,
- HCRYPTPROV hProv, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
+ HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
 {
     PCCERT_CONTEXT context = NULL;
     BOOL ret;
     DWORD sigSize = 0;
 
-    ret = CryptSignCertificate(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
+    ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
      blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
     if (ret)
     {
         LPBYTE sig = CryptMemAlloc(sigSize);
 
-        ret = CryptSignCertificate(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
+        ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
          blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
         if (ret)
         {
@@ -2108,7 +2407,7 @@ static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNu
         info->rgExtension = NULL;
     }
 }
-
 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
@@ -2159,7 +2458,7 @@ static HCRYPTPROV CRYPT_CreateKeyProv(void)
     return hProv;
 }
 
-PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv,
+PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv,
  PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
  PCRYPT_KEY_PROV_INFO pKeyProvInfo,
  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
@@ -2168,24 +2467,80 @@ PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv,
     PCCERT_CONTEXT context = NULL;
     BOOL ret, releaseContext = FALSE;
     PCERT_PUBLIC_KEY_INFO pubKey = NULL;
-    DWORD pubKeySize = 0;
+    DWORD pubKeySize = 0,dwKeySpec = AT_SIGNATURE;
 
     TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv,
      pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
      pExtensions, pExtensions);
 
+    if(!pSubjectIssuerBlob)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return NULL;
+    }
+
     if (!hProv)
     {
-        hProv = CRYPT_CreateKeyProv();
-        releaseContext = TRUE;
+        if (!pKeyProvInfo)
+        {
+            hProv = CRYPT_CreateKeyProv();
+            releaseContext = TRUE;
+        }
+        else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID)
+        {
+            SetLastError(NTE_BAD_FLAGS);
+            return NULL;
+        }
+        else
+        {
+            HCRYPTKEY hKey = 0;
+            /* acquire the context using the given information*/
+            ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
+                    pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
+                    pKeyProvInfo->dwFlags);
+            if (!ret)
+            {
+               if(GetLastError() != NTE_BAD_KEYSET)
+                    return NULL;
+                /* create the key set */
+                ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
+                    pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
+                    pKeyProvInfo->dwFlags|CRYPT_NEWKEYSET);
+                if (!ret)
+                    return NULL;
+           }
+            dwKeySpec = pKeyProvInfo->dwKeySpec;
+            /* check if the key is here */
+            ret = CryptGetUserKey(hProv,dwKeySpec,&hKey);
+            if(!ret)
+            {
+                if (NTE_NO_KEY == GetLastError())
+                { /* generate the key */
+                    ret = CryptGenKey(hProv,dwKeySpec,0,&hKey);
+                }
+                if (!ret)
+                {
+                    CryptReleaseContext(hProv,0);
+                    SetLastError(NTE_BAD_KEYSET);
+                    return NULL;
+                }
+            }
+            CryptDestroyKey(hKey);
+            releaseContext = TRUE;
+        }
+    }
+    else if (pKeyProvInfo)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return NULL;
     }
 
-    CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
+    CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL,
      &pubKeySize);
     pubKey = CryptMemAlloc(pubKeySize);
     if (pubKey)
     {
-        ret = CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
+        ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING,
          pubKey, &pubKeySize);
         if (ret)
         {
@@ -2203,7 +2558,7 @@ PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv,
             if (ret)
             {
                 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
-                    context = CRYPT_CreateSignedCert(&blob, hProv,
+                    context = CRYPT_CreateSignedCert(&blob, hProv,dwKeySpec,
                      &info.SignatureAlgorithm);
                 else
                     context = CertCreateCertificateContext(X509_ASN_ENCODING,
@@ -2219,3 +2574,15 @@ PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv,
         CryptReleaseContext(hProv, 0);
     return context;
 }
+
+BOOL WINAPI CertVerifyCTLUsage(DWORD dwEncodingType, DWORD dwSubjectType,
+                               void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags,
+                               PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
+                               PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus)
+{
+    FIXME("(0x%x, %d, %p, %p, 0x%x, %p, %p): stub\n", dwEncodingType,
+          dwSubjectType, pvSubject, pSubjectUsage, dwFlags, pVerifyUsagePara,
+          pVerifyUsageStatus);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
+}
index 03267db..a13a896 100644 (file)
  *
  */
 #include <stdarg.h>
+#define NONAMELESSUNION
 #include "windef.h"
 #include "winbase.h"
+#define CERT_CHAIN_PARA_HAS_EXTRA_FIELDS
+#define CERT_REVOCATION_PARA_HAS_EXTRA_FIELDS
 #include "wincrypt.h"
 #include "wine/debug.h"
+#include "wine/unicode.h"
 #include "crypt32_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
 
+#define DEFAULT_CYCLE_MODULUS 7
+
+static HCERTCHAINENGINE CRYPT_defaultChainEngine;
+
 /* This represents a subset of a certificate chain engine:  it doesn't include
  * the "hOther" store described by MSDN, because I'm not sure how that's used.
  * It also doesn't include the "hTrust" store, because I don't yet implement
@@ -100,12 +108,48 @@ static BOOL CRYPT_CheckRestrictedRoot(HCERTSTORE store)
     return ret;
 }
 
-BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig,
HCERTCHAINENGINE *phChainEngine)
+HCERTCHAINENGINE CRYPT_CreateChainEngine(HCERTSTORE root,
PCERT_CHAIN_ENGINE_CONFIG pConfig)
 {
     static const WCHAR caW[] = { 'C','A',0 };
     static const WCHAR myW[] = { 'M','y',0 };
     static const WCHAR trustW[] = { 'T','r','u','s','t',0 };
+    PCertificateChainEngine engine =
+     CryptMemAlloc(sizeof(CertificateChainEngine));
+
+    if (engine)
+    {
+        HCERTSTORE worldStores[4];
+
+        engine->ref = 1;
+        engine->hRoot = root;
+        engine->hWorld = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
+         CERT_STORE_CREATE_NEW_FLAG, NULL);
+        worldStores[0] = CertDuplicateStore(engine->hRoot);
+        worldStores[1] = CertOpenSystemStoreW(0, caW);
+        worldStores[2] = CertOpenSystemStoreW(0, myW);
+        worldStores[3] = CertOpenSystemStoreW(0, trustW);
+        CRYPT_AddStoresToCollection(engine->hWorld,
+         sizeof(worldStores) / sizeof(worldStores[0]), worldStores);
+        CRYPT_AddStoresToCollection(engine->hWorld,
+         pConfig->cAdditionalStore, pConfig->rghAdditionalStore);
+        CRYPT_CloseStores(sizeof(worldStores) / sizeof(worldStores[0]),
+         worldStores);
+        engine->dwFlags = pConfig->dwFlags;
+        engine->dwUrlRetrievalTimeout = pConfig->dwUrlRetrievalTimeout;
+        engine->MaximumCachedCertificates =
+         pConfig->MaximumCachedCertificates;
+        if (pConfig->CycleDetectionModulus)
+            engine->CycleDetectionModulus = pConfig->CycleDetectionModulus;
+        else
+            engine->CycleDetectionModulus = DEFAULT_CYCLE_MODULUS;
+    }
+    return (HCERTCHAINENGINE)engine;
+}
+
+BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig,
+ HCERTCHAINENGINE *phChainEngine)
+{
     BOOL ret;
 
     TRACE("(%p, %p)\n", pConfig, phChainEngine);
@@ -119,36 +163,17 @@ BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig,
     ret = CRYPT_CheckRestrictedRoot(pConfig->hRestrictedRoot);
     if (ret)
     {
-        PCertificateChainEngine engine =
-         CryptMemAlloc(sizeof(CertificateChainEngine));
+        HCERTSTORE root;
+        HCERTCHAINENGINE engine;
 
+        if (pConfig->hRestrictedRoot)
+            root = CertDuplicateStore(pConfig->hRestrictedRoot);
+        else
+            root = CertOpenSystemStoreW(0, rootW);
+        engine = CRYPT_CreateChainEngine(root, pConfig);
         if (engine)
         {
-            HCERTSTORE worldStores[4];
-
-            engine->ref = 1;
-            if (pConfig->hRestrictedRoot)
-                engine->hRoot = CertDuplicateStore(pConfig->hRestrictedRoot);
-            else
-                engine->hRoot = CertOpenSystemStoreW(0, rootW);
-            engine->hWorld = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
-             CERT_STORE_CREATE_NEW_FLAG, NULL);
-            worldStores[0] = CertDuplicateStore(engine->hRoot);
-            worldStores[1] = CertOpenSystemStoreW(0, caW);
-            worldStores[2] = CertOpenSystemStoreW(0, myW);
-            worldStores[3] = CertOpenSystemStoreW(0, trustW);
-            CRYPT_AddStoresToCollection(engine->hWorld,
-             sizeof(worldStores) / sizeof(worldStores[0]), worldStores);
-            CRYPT_AddStoresToCollection(engine->hWorld,
-             pConfig->cAdditionalStore, pConfig->rghAdditionalStore);
-            CRYPT_CloseStores(sizeof(worldStores) / sizeof(worldStores[0]),
-             worldStores);
-            engine->dwFlags = pConfig->dwFlags;
-            engine->dwUrlRetrievalTimeout = pConfig->dwUrlRetrievalTimeout;
-            engine->MaximumCachedCertificates =
-             pConfig->MaximumCachedCertificates;
-            engine->CycleDetectionModulus = pConfig->CycleDetectionModulus;
-            *phChainEngine = (HCERTCHAINENGINE)engine;
+            *phChainEngine = engine;
             ret = TRUE;
         }
         else
@@ -157,7 +182,7 @@ BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig,
     return ret;
 }
 
-void WINAPI CertFreeCertificateChainEngine(HCERTCHAINENGINE hChainEngine)
+VOID WINAPI CertFreeCertificateChainEngine(HCERTCHAINENGINE hChainEngine)
 {
     PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine;
 
@@ -170,3 +195,1619 @@ void WINAPI CertFreeCertificateChainEngine(HCERTCHAINENGINE hChainEngine)
         CryptMemFree(engine);
     }
 }
+
+static HCERTCHAINENGINE CRYPT_GetDefaultChainEngine(void)
+{
+    if (!CRYPT_defaultChainEngine)
+    {
+        CERT_CHAIN_ENGINE_CONFIG config = { 0 };
+        HCERTCHAINENGINE engine;
+
+        config.cbSize = sizeof(config);
+        CertCreateCertificateChainEngine(&config, &engine);
+        InterlockedCompareExchangePointer(&CRYPT_defaultChainEngine, engine,
+         NULL);
+        if (CRYPT_defaultChainEngine != engine)
+            CertFreeCertificateChainEngine(engine);
+    }
+    return CRYPT_defaultChainEngine;
+}
+
+void default_chain_engine_free(void)
+{
+    CertFreeCertificateChainEngine(CRYPT_defaultChainEngine);
+}
+
+typedef struct _CertificateChain
+{
+    CERT_CHAIN_CONTEXT context;
+    HCERTSTORE world;
+    LONG ref;
+} CertificateChain, *PCertificateChain;
+
+static inline BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert)
+{
+    return CertCompareCertificateName(cert->dwCertEncodingType,
+     &cert->pCertInfo->Subject, &cert->pCertInfo->Issuer);
+}
+
+static void CRYPT_FreeChainElement(PCERT_CHAIN_ELEMENT element)
+{
+    CertFreeCertificateContext(element->pCertContext);
+    CryptMemFree(element);
+}
+
+static void CRYPT_CheckSimpleChainForCycles(PCERT_SIMPLE_CHAIN chain)
+{
+    DWORD i, j, cyclicCertIndex = 0;
+
+    /* O(n^2) - I don't think there's a faster way */
+    for (i = 0; !cyclicCertIndex && i < chain->cElement; i++)
+        for (j = i + 1; !cyclicCertIndex && j < chain->cElement; j++)
+            if (CertCompareCertificate(X509_ASN_ENCODING,
+             chain->rgpElement[i]->pCertContext->pCertInfo,
+             chain->rgpElement[j]->pCertContext->pCertInfo))
+                cyclicCertIndex = j;
+    if (cyclicCertIndex)
+    {
+        chain->rgpElement[cyclicCertIndex]->TrustStatus.dwErrorStatus
+         |= CERT_TRUST_IS_CYCLIC;
+        /* Release remaining certs */
+        for (i = cyclicCertIndex + 1; i < chain->cElement; i++)
+            CRYPT_FreeChainElement(chain->rgpElement[i]);
+        /* Truncate chain */
+        chain->cElement = cyclicCertIndex + 1;
+    }
+}
+
+/* Checks whether the chain is cyclic by examining the last element's status */
+static inline BOOL CRYPT_IsSimpleChainCyclic(PCERT_SIMPLE_CHAIN chain)
+{
+    if (chain->cElement)
+        return chain->rgpElement[chain->cElement - 1]->TrustStatus.dwErrorStatus
+         & CERT_TRUST_IS_CYCLIC;
+    else
+        return FALSE;
+}
+
+static inline void CRYPT_CombineTrustStatus(CERT_TRUST_STATUS *chainStatus,
+ CERT_TRUST_STATUS *elementStatus)
+{
+    /* Any error that applies to an element also applies to a chain.. */
+    chainStatus->dwErrorStatus |= elementStatus->dwErrorStatus;
+    /* but the bottom nibble of an element's info status doesn't apply to the
+     * chain.
+     */
+    chainStatus->dwInfoStatus |= (elementStatus->dwInfoStatus & 0xfffffff0);
+}
+
+static BOOL CRYPT_AddCertToSimpleChain(PCertificateChainEngine engine,
+ PCERT_SIMPLE_CHAIN chain, PCCERT_CONTEXT cert, DWORD subjectInfoStatus)
+{
+    BOOL ret = FALSE;
+    PCERT_CHAIN_ELEMENT element = CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT));
+
+    if (element)
+    {
+        if (!chain->cElement)
+            chain->rgpElement = CryptMemAlloc(sizeof(PCERT_CHAIN_ELEMENT));
+        else
+            chain->rgpElement = CryptMemRealloc(chain->rgpElement,
+             (chain->cElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
+        if (chain->rgpElement)
+        {
+            chain->rgpElement[chain->cElement++] = element;
+            memset(element, 0, sizeof(CERT_CHAIN_ELEMENT));
+            element->cbSize = sizeof(CERT_CHAIN_ELEMENT);
+            element->pCertContext = CertDuplicateCertificateContext(cert);
+            if (chain->cElement > 1)
+                chain->rgpElement[chain->cElement - 2]->TrustStatus.dwInfoStatus
+                 = subjectInfoStatus;
+            /* FIXME: initialize the rest of element */
+            if (chain->cElement % engine->CycleDetectionModulus)
+                CRYPT_CheckSimpleChainForCycles(chain);
+            CRYPT_CombineTrustStatus(&chain->TrustStatus,
+             &element->TrustStatus);
+            ret = TRUE;
+        }
+        else
+            CryptMemFree(element);
+    }
+    return ret;
+}
+
+static void CRYPT_FreeSimpleChain(PCERT_SIMPLE_CHAIN chain)
+{
+    DWORD i;
+
+    for (i = 0; i < chain->cElement; i++)
+        CRYPT_FreeChainElement(chain->rgpElement[i]);
+    CryptMemFree(chain->rgpElement);
+    CryptMemFree(chain);
+}
+
+static void CRYPT_CheckTrustedStatus(HCERTSTORE hRoot,
+ PCERT_CHAIN_ELEMENT rootElement)
+{
+    BYTE hash[20];
+    DWORD size = sizeof(hash);
+    CRYPT_HASH_BLOB blob = { sizeof(hash), hash };
+    PCCERT_CONTEXT trustedRoot;
+
+    CertGetCertificateContextProperty(rootElement->pCertContext,
+     CERT_HASH_PROP_ID, hash, &size);
+    trustedRoot = CertFindCertificateInStore(hRoot,
+     rootElement->pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH,
+     &blob, NULL);
+    if (!trustedRoot)
+        rootElement->TrustStatus.dwErrorStatus |=
+         CERT_TRUST_IS_UNTRUSTED_ROOT;
+    else
+        CertFreeCertificateContext(trustedRoot);
+}
+
+static void CRYPT_CheckRootCert(HCERTCHAINENGINE hRoot,
+ PCERT_CHAIN_ELEMENT rootElement)
+{
+    PCCERT_CONTEXT root = rootElement->pCertContext;
+
+    if (!CryptVerifyCertificateSignatureEx(0, root->dwCertEncodingType,
+     CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)root,
+     CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)root, 0, NULL))
+    {
+        TRACE("Last certificate's signature is invalid\n");
+        rootElement->TrustStatus.dwErrorStatus |=
+         CERT_TRUST_IS_NOT_SIGNATURE_VALID;
+    }
+    CRYPT_CheckTrustedStatus(hRoot, rootElement);
+}
+
+/* Decodes a cert's basic constraints extension (either szOID_BASIC_CONSTRAINTS
+ * or szOID_BASIC_CONSTRAINTS2, whichever is present) into a
+ * CERT_BASIC_CONSTRAINTS2_INFO.  If it neither extension is present, sets
+ * constraints->fCA to defaultIfNotSpecified.
+ * Returns FALSE if the extension is present but couldn't be decoded.
+ */
+static BOOL CRYPT_DecodeBasicConstraints(PCCERT_CONTEXT cert,
+ CERT_BASIC_CONSTRAINTS2_INFO *constraints, BOOL defaultIfNotSpecified)
+{
+    BOOL ret = TRUE;
+    PCERT_EXTENSION ext = CertFindExtension(szOID_BASIC_CONSTRAINTS,
+     cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
+
+    constraints->fPathLenConstraint = FALSE;
+    if (ext)
+    {
+        CERT_BASIC_CONSTRAINTS_INFO *info;
+        DWORD size = 0;
+
+        ret = CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS,
+         ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_ALLOC_FLAG,
+         NULL, (LPBYTE)&info, &size);
+        if (ret)
+        {
+            if (info->SubjectType.cbData == 1)
+                constraints->fCA =
+                 info->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG;
+            LocalFree(info);
+        }
+    }
+    else
+    {
+        ext = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
+         cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
+        if (ext)
+        {
+            DWORD size = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
+
+            ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
+             szOID_BASIC_CONSTRAINTS2, ext->Value.pbData, ext->Value.cbData,
+             0, NULL, constraints, &size);
+        }
+        else
+            constraints->fCA = defaultIfNotSpecified;
+    }
+    return ret;
+}
+
+/* Checks element's basic constraints to see if it can act as a CA, with
+ * remainingCAs CAs left in this chain.  Updates chainConstraints with the
+ * element's constraints, if:
+ * 1. chainConstraints doesn't have a path length constraint, or
+ * 2. element's path length constraint is smaller than chainConstraints's
+ * Sets *pathLengthConstraintViolated to TRUE if a path length violation
+ * occurs.
+ * Returns TRUE if the element can be a CA, and the length of the remaining
+ * chain is valid.
+ */
+static BOOL CRYPT_CheckBasicConstraintsForCA(PCCERT_CONTEXT cert,
+ CERT_BASIC_CONSTRAINTS2_INFO *chainConstraints, DWORD remainingCAs,
+ BOOL *pathLengthConstraintViolated)
+{
+    BOOL validBasicConstraints;
+    CERT_BASIC_CONSTRAINTS2_INFO constraints;
+
+    if ((validBasicConstraints = CRYPT_DecodeBasicConstraints(cert,
+     &constraints, TRUE)))
+    {
+        if (!constraints.fCA)
+        {
+            TRACE("chain element %d can't be a CA\n", remainingCAs + 1);
+            validBasicConstraints = FALSE;
+        }
+        else if (constraints.fPathLenConstraint)
+        {
+            /* If the element has path length constraints, they apply to the
+             * entire remaining chain.
+             */
+            if (!chainConstraints->fPathLenConstraint ||
+             constraints.dwPathLenConstraint <
+             chainConstraints->dwPathLenConstraint)
+            {
+                TRACE("setting path length constraint to %d\n",
+                 chainConstraints->dwPathLenConstraint);
+                chainConstraints->fPathLenConstraint = TRUE;
+                chainConstraints->dwPathLenConstraint =
+                 constraints.dwPathLenConstraint;
+            }
+        }
+    }
+    if (chainConstraints->fPathLenConstraint &&
+     remainingCAs > chainConstraints->dwPathLenConstraint)
+    {
+        TRACE("remaining CAs %d exceed max path length %d\n", remainingCAs,
+         chainConstraints->dwPathLenConstraint);
+        validBasicConstraints = FALSE;
+        *pathLengthConstraintViolated = TRUE;
+    }
+    return validBasicConstraints;
+}
+
+static BOOL url_matches(LPCWSTR constraint, LPCWSTR name,
+ DWORD *trustErrorStatus)
+{
+    BOOL match = FALSE;
+
+    TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
+
+    if (!constraint)
+        *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
+    else if (!name)
+        ; /* no match */
+    else if (constraint[0] == '.')
+    {
+        if (lstrlenW(name) > lstrlenW(constraint))
+            match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint),
+             constraint);
+    }
+    else
+        match = !lstrcmpiW(constraint, name);
+    return match;
+}
+
+static BOOL rfc822_name_matches(LPCWSTR constraint, LPCWSTR name,
+ DWORD *trustErrorStatus)
+{
+    BOOL match = FALSE;
+    LPCWSTR at;
+
+    TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
+
+    if (!constraint)
+        *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
+    else if (!name)
+        ; /* no match */
+    else if ((at = strchrW(constraint, '@')))
+        match = !lstrcmpiW(constraint, name);
+    else
+    {
+        if ((at = strchrW(name, '@')))
+            match = url_matches(constraint, at + 1, trustErrorStatus);
+        else
+            match = !lstrcmpiW(constraint, name);
+    }
+    return match;
+}
+
+static BOOL dns_name_matches(LPCWSTR constraint, LPCWSTR name,
+ DWORD *trustErrorStatus)
+{
+    BOOL match = FALSE;
+
+    TRACE("%s, %s\n", debugstr_w(constraint), debugstr_w(name));
+
+    if (!constraint)
+        *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
+    else if (!name)
+        ; /* no match */
+    else if (lstrlenW(name) >= lstrlenW(constraint))
+        match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint),
+         constraint);
+    /* else:  name is too short, no match */
+
+    return match;
+}
+
+static BOOL ip_address_matches(const CRYPT_DATA_BLOB *constraint,
+ const CRYPT_DATA_BLOB *name, DWORD *trustErrorStatus)
+{
+    BOOL match = FALSE;
+
+    TRACE("(%d, %p), (%d, %p)\n", constraint->cbData, constraint->pbData,
+     name->cbData, name->pbData);
+
+    if (constraint->cbData != sizeof(DWORD) * 2)
+        *trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
+    else if (name->cbData == sizeof(DWORD))
+    {
+        DWORD subnet, mask, addr;
+
+        memcpy(&subnet, constraint->pbData, sizeof(subnet));
+        memcpy(&mask, constraint->pbData + sizeof(subnet), sizeof(mask));
+        memcpy(&addr, name->pbData, sizeof(addr));
+        /* These are really in big-endian order, but for equality matching we
+         * don't need to swap to host order
+         */
+        match = (subnet & mask) == (addr & mask);
+    }
+    /* else: name is wrong size, no match */
+
+    return match;
+}
+
+static void CRYPT_FindMatchingNameEntry(const CERT_ALT_NAME_ENTRY *constraint,
+ const CERT_ALT_NAME_INFO *subjectName, DWORD *trustErrorStatus,
+ DWORD errorIfFound, DWORD errorIfNotFound)
+{
+    DWORD i;
+    BOOL defined = FALSE, match = FALSE;
+
+    for (i = 0; i < subjectName->cAltEntry; i++)
+    {
+        if (subjectName->rgAltEntry[i].dwAltNameChoice ==
+         constraint->dwAltNameChoice)
+        {
+            defined = TRUE;
+            switch (constraint->dwAltNameChoice)
+            {
+            case CERT_ALT_NAME_RFC822_NAME:
+                match = rfc822_name_matches(constraint->u.pwszURL,
+                 subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus);
+                break;
+            case CERT_ALT_NAME_DNS_NAME:
+                match = dns_name_matches(constraint->u.pwszURL,
+                 subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus);
+                break;
+            case CERT_ALT_NAME_URL:
+                match = url_matches(constraint->u.pwszURL,
+                 subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus);
+                break;
+            case CERT_ALT_NAME_IP_ADDRESS:
+                match = ip_address_matches(&constraint->u.IPAddress,
+                 &subjectName->rgAltEntry[i].u.IPAddress, trustErrorStatus);
+                break;
+            case CERT_ALT_NAME_DIRECTORY_NAME:
+            default:
+                ERR("name choice %d unsupported in this context\n",
+                 constraint->dwAltNameChoice);
+                *trustErrorStatus |=
+                 CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
+            }
+        }
+    }
+    /* Microsoft's implementation of name constraint checking appears at odds
+     * with RFC 3280:
+     * According to MSDN, CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT is set
+     * when a name constraint is present, but that name form is not defined in
+     * the end certificate.  According to RFC 3280, "if no name of the type is
+     * in the certificate, the name is acceptable."
+     * I follow Microsoft here.
+     */
+    if (!defined)
+        *trustErrorStatus |= CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT;
+    *trustErrorStatus |= match ? errorIfFound : errorIfNotFound;
+}
+
+static void CRYPT_CheckNameConstraints(
+ const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, const CERT_INFO *cert,
+ DWORD *trustErrorStatus)
+{
+    /* If there aren't any existing constraints, don't bother checking */
+    if (nameConstraints->cPermittedSubtree || nameConstraints->cExcludedSubtree)
+    {
+        CERT_EXTENSION *ext;
+
+        if ((ext = CertFindExtension(szOID_SUBJECT_ALT_NAME, cert->cExtension,
+         cert->rgExtension)))
+        {
+            CERT_ALT_NAME_INFO *subjectName;
+            DWORD size;
+
+            if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
+             ext->Value.pbData, ext->Value.cbData,
+             CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
+             &subjectName, &size))
+            {
+                DWORD i;
+
+                for (i = 0; i < nameConstraints->cExcludedSubtree; i++)
+                    CRYPT_FindMatchingNameEntry(
+                     &nameConstraints->rgExcludedSubtree[i].Base, subjectName,
+                     trustErrorStatus,
+                     CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT, 0);
+                for (i = 0; i < nameConstraints->cPermittedSubtree; i++)
+                    CRYPT_FindMatchingNameEntry(
+                     &nameConstraints->rgPermittedSubtree[i].Base, subjectName,
+                     trustErrorStatus,
+                     0, CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT);
+                LocalFree(subjectName);
+            }
+        }
+        else
+        {
+            /* See above comment on CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT.
+             * I match Microsoft's implementation here as well.
+             */
+            *trustErrorStatus |= CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT;
+            if (nameConstraints->cPermittedSubtree)
+                *trustErrorStatus |=
+                 CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
+            if (nameConstraints->cExcludedSubtree)
+                *trustErrorStatus |=
+                 CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT;
+        }
+    }
+}
+
+/* Gets cert's name constraints, if any.  Free with LocalFree. */
+static CERT_NAME_CONSTRAINTS_INFO *CRYPT_GetNameConstraints(CERT_INFO *cert)
+{
+    CERT_NAME_CONSTRAINTS_INFO *info = NULL;
+
+    CERT_EXTENSION *ext;
+
+    if ((ext = CertFindExtension(szOID_NAME_CONSTRAINTS, cert->cExtension,
+     cert->rgExtension)))
+    {
+        DWORD size;
+
+        CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME_CONSTRAINTS,
+         ext->Value.pbData, ext->Value.cbData,
+         CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &info,
+         &size);
+    }
+    return info;
+}
+
+static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain)
+{
+    int i, j;
+
+    /* Microsoft's implementation appears to violate RFC 3280:  according to
+     * MSDN, the various CERT_TRUST_*_NAME_CONSTRAINT errors are set if a CA's
+     * name constraint is violated in the end cert.  According to RFC 3280,
+     * the constraints should be checked against every subsequent certificate
+     * in the chain, not just the end cert.
+     * Microsoft's implementation also sets the name constraint errors on the
+     * certs whose constraints were violated, not on the certs that violated
+     * them.
+     * In order to be error-compatible with Microsoft's implementation, while
+     * still adhering to RFC 3280, I use a O(n ^ 2) algorithm to check name
+     * constraints.
+     */
+    for (i = chain->cElement - 1; i > 0; i--)
+    {
+        CERT_NAME_CONSTRAINTS_INFO *nameConstraints;
+
+        if ((nameConstraints = CRYPT_GetNameConstraints(
+         chain->rgpElement[i]->pCertContext->pCertInfo)))
+        {
+            for (j = i - 1; j >= 0; j--)
+            {
+                DWORD errorStatus = 0;
+
+                /* According to RFC 3280, self-signed certs don't have name
+                 * constraints checked unless they're the end cert.
+                 */
+                if (j == 0 || !CRYPT_IsCertificateSelfSigned(
+                 chain->rgpElement[j]->pCertContext))
+                {
+                    CRYPT_CheckNameConstraints(nameConstraints,
+                     chain->rgpElement[i]->pCertContext->pCertInfo,
+                     &errorStatus);
+                    chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
+                     errorStatus;
+                }
+            }
+            LocalFree(nameConstraints);
+        }
+    }
+}
+
+static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
+ PCERT_SIMPLE_CHAIN chain, LPFILETIME time)
+{
+    PCERT_CHAIN_ELEMENT rootElement = chain->rgpElement[chain->cElement - 1];
+    int i;
+    BOOL pathLengthConstraintViolated = FALSE;
+    CERT_BASIC_CONSTRAINTS2_INFO constraints = { TRUE, FALSE, 0 };
+
+    for (i = chain->cElement - 1; i >= 0; i--)
+    {
+        if (CertVerifyTimeValidity(time,
+         chain->rgpElement[i]->pCertContext->pCertInfo) != 0)
+            chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
+             CERT_TRUST_IS_NOT_TIME_VALID;
+        if (i != 0)
+        {
+            /* Check the signature of the cert this issued */
+            if (!CryptVerifyCertificateSignatureEx(0, X509_ASN_ENCODING,
+             CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
+             (void *)chain->rgpElement[i - 1]->pCertContext,
+             CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT,
+             (void *)chain->rgpElement[i]->pCertContext, 0, NULL))
+                chain->rgpElement[i - 1]->TrustStatus.dwErrorStatus |=
+                 CERT_TRUST_IS_NOT_SIGNATURE_VALID;
+            /* Once a path length constraint has been violated, every remaining
+             * CA cert's basic constraints is considered invalid.
+             */
+            if (pathLengthConstraintViolated)
+                chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
+                 CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
+            else if (!CRYPT_CheckBasicConstraintsForCA(
+             chain->rgpElement[i]->pCertContext, &constraints, i - 1,
+             &pathLengthConstraintViolated))
+                chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
+                 CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
+            else if (constraints.fPathLenConstraint &&
+             constraints.dwPathLenConstraint)
+            {
+                /* This one's valid - decrement max length */
+                constraints.dwPathLenConstraint--;
+            }
+        }
+        /* FIXME: check valid usages */
+        CRYPT_CombineTrustStatus(&chain->TrustStatus,
+         &chain->rgpElement[i]->TrustStatus);
+    }
+    CRYPT_CheckChainNameConstraints(chain);
+    if (CRYPT_IsCertificateSelfSigned(rootElement->pCertContext))
+    {
+        rootElement->TrustStatus.dwInfoStatus |=
+         CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER;
+        CRYPT_CheckRootCert(engine->hRoot, rootElement);
+    }
+    CRYPT_CombineTrustStatus(&chain->TrustStatus, &rootElement->TrustStatus);
+}
+
+static PCCERT_CONTEXT CRYPT_GetIssuer(HCERTSTORE store, PCCERT_CONTEXT subject,
+ PCCERT_CONTEXT prevIssuer, DWORD *infoStatus)
+{
+    PCCERT_CONTEXT issuer = NULL;
+    PCERT_EXTENSION ext;
+    DWORD size;
+
+    *infoStatus = 0;
+    if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
+     subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
+    {
+        CERT_AUTHORITY_KEY_ID_INFO *info;
+        BOOL ret;
+
+        ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
+         X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
+         CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
+         &info, &size);
+        if (ret)
+        {
+            CERT_ID id;
+
+            if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
+            {
+                id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
+                memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer,
+                 sizeof(CERT_NAME_BLOB));
+                memcpy(&id.u.IssuerSerialNumber.SerialNumber,
+                 &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
+                issuer = CertFindCertificateInStore(store,
+                 subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
+                 prevIssuer);
+                if (issuer)
+                    *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER;
+            }
+            else if (info->KeyId.cbData)
+            {
+                id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
+                memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
+                issuer = CertFindCertificateInStore(store,
+                 subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
+                 prevIssuer);
+                if (issuer)
+                    *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
+            }
+            LocalFree(info);
+        }
+    }
+    else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
+     subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
+    {
+        CERT_AUTHORITY_KEY_ID2_INFO *info;
+        BOOL ret;
+
+        ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
+         X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
+         CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
+         &info, &size);
+        if (ret)
+        {
+            CERT_ID id;
+
+            if (info->AuthorityCertIssuer.cAltEntry &&
+             info->AuthorityCertSerialNumber.cbData)
+            {
+                PCERT_ALT_NAME_ENTRY directoryName = NULL;
+                DWORD i;
+
+                for (i = 0; !directoryName &&
+                 i < info->AuthorityCertIssuer.cAltEntry; i++)
+                    if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
+                     == CERT_ALT_NAME_DIRECTORY_NAME)
+                        directoryName =
+                         &info->AuthorityCertIssuer.rgAltEntry[i];
+                if (directoryName)
+                {
+                    id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
+                    memcpy(&id.u.IssuerSerialNumber.Issuer,
+                     &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB));
+                    memcpy(&id.u.IssuerSerialNumber.SerialNumber,
+                     &info->AuthorityCertSerialNumber,
+                     sizeof(CRYPT_INTEGER_BLOB));
+                    issuer = CertFindCertificateInStore(store,
+                     subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
+                     prevIssuer);
+                    if (issuer)
+                        *infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER;
+                }
+                else
+                    FIXME("no supported name type in authority key id2\n");
+            }
+            else if (info->KeyId.cbData)
+            {
+                id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
+                memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
+                issuer = CertFindCertificateInStore(store,
+                 subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
+                 prevIssuer);
+                if (issuer)
+                    *infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
+            }
+            LocalFree(info);
+        }
+    }
+    else
+    {
+        issuer = CertFindCertificateInStore(store,
+         subject->dwCertEncodingType, 0, CERT_FIND_SUBJECT_NAME,
+         &subject->pCertInfo->Issuer, prevIssuer);
+        if (issuer)
+            *infoStatus = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
+    }
+    return issuer;
+}
+
+/* Builds a simple chain by finding an issuer for the last cert in the chain,
+ * until reaching a self-signed cert, or until no issuer can be found.
+ */
+static BOOL CRYPT_BuildSimpleChain(PCertificateChainEngine engine,
+ HCERTSTORE world, PCERT_SIMPLE_CHAIN chain)
+{
+    BOOL ret = TRUE;
+    PCCERT_CONTEXT cert = chain->rgpElement[chain->cElement - 1]->pCertContext;
+
+    while (ret && !CRYPT_IsSimpleChainCyclic(chain) &&
+     !CRYPT_IsCertificateSelfSigned(cert))
+    {
+        DWORD infoStatus;
+        PCCERT_CONTEXT issuer = CRYPT_GetIssuer(world, cert, NULL, &infoStatus);
+
+        if (issuer)
+        {
+            ret = CRYPT_AddCertToSimpleChain(engine, chain, issuer, infoStatus);
+            /* CRYPT_AddCertToSimpleChain add-ref's the issuer, so free it to
+             * close the enumeration that found it
+             */
+            CertFreeCertificateContext(issuer);
+            cert = issuer;
+        }
+        else
+        {
+            TRACE("Couldn't find issuer, halting chain creation\n");
+            break;
+        }
+    }
+    return ret;
+}
+
+static BOOL CRYPT_GetSimpleChainForCert(PCertificateChainEngine engine,
+ HCERTSTORE world, PCCERT_CONTEXT cert, LPFILETIME pTime,
+ PCERT_SIMPLE_CHAIN *ppChain)
+{
+    BOOL ret = FALSE;
+    PCERT_SIMPLE_CHAIN chain;
+
+    TRACE("(%p, %p, %p, %p)\n", engine, world, cert, pTime);
+
+    chain = CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN));
+    if (chain)
+    {
+        memset(chain, 0, sizeof(CERT_SIMPLE_CHAIN));
+        chain->cbSize = sizeof(CERT_SIMPLE_CHAIN);
+        ret = CRYPT_AddCertToSimpleChain(engine, chain, cert, 0);
+        if (ret)
+        {
+            ret = CRYPT_BuildSimpleChain(engine, world, chain);
+            if (ret)
+                CRYPT_CheckSimpleChain(engine, chain, pTime);
+        }
+        if (!ret)
+        {
+            CRYPT_FreeSimpleChain(chain);
+            chain = NULL;
+        }
+        *ppChain = chain;
+    }
+    return ret;
+}
+
+static BOOL CRYPT_BuildCandidateChainFromCert(HCERTCHAINENGINE hChainEngine,
+ PCCERT_CONTEXT cert, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
+ PCertificateChain *ppChain)
+{
+    PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine;
+    PCERT_SIMPLE_CHAIN simpleChain = NULL;
+    HCERTSTORE world;
+    BOOL ret;
+
+    world = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
+     CERT_STORE_CREATE_NEW_FLAG, NULL);
+    CertAddStoreToCollection(world, engine->hWorld, 0, 0);
+    if (hAdditionalStore)
+        CertAddStoreToCollection(world, hAdditionalStore, 0, 0);
+    /* FIXME: only simple chains are supported for now, as CTLs aren't
+     * supported yet.
+     */
+    if ((ret = CRYPT_GetSimpleChainForCert(engine, world, cert, pTime,
+     &simpleChain)))
+    {
+        PCertificateChain chain = CryptMemAlloc(sizeof(CertificateChain));
+
+        if (chain)
+        {
+            chain->ref = 1;
+            chain->world = world;
+            chain->context.cbSize = sizeof(CERT_CHAIN_CONTEXT);
+            chain->context.TrustStatus = simpleChain->TrustStatus;
+            chain->context.cChain = 1;
+            chain->context.rgpChain = CryptMemAlloc(sizeof(PCERT_SIMPLE_CHAIN));
+            chain->context.rgpChain[0] = simpleChain;
+            chain->context.cLowerQualityChainContext = 0;
+            chain->context.rgpLowerQualityChainContext = NULL;
+            chain->context.fHasRevocationFreshnessTime = FALSE;
+            chain->context.dwRevocationFreshnessTime = 0;
+        }
+        else
+            ret = FALSE;
+        *ppChain = chain;
+    }
+    return ret;
+}
+
+/* Makes and returns a copy of chain, up to and including element iElement. */
+static PCERT_SIMPLE_CHAIN CRYPT_CopySimpleChainToElement(
+ PCERT_SIMPLE_CHAIN chain, DWORD iElement)
+{
+    PCERT_SIMPLE_CHAIN copy = CryptMemAlloc(sizeof(CERT_SIMPLE_CHAIN));
+
+    if (copy)
+    {
+        memset(copy, 0, sizeof(CERT_SIMPLE_CHAIN));
+        copy->cbSize = sizeof(CERT_SIMPLE_CHAIN);
+        copy->rgpElement =
+         CryptMemAlloc((iElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
+        if (copy->rgpElement)
+        {
+            DWORD i;
+            BOOL ret = TRUE;
+
+            memset(copy->rgpElement, 0,
+             (iElement + 1) * sizeof(PCERT_CHAIN_ELEMENT));
+            for (i = 0; ret && i <= iElement; i++)
+            {
+                PCERT_CHAIN_ELEMENT element =
+                 CryptMemAlloc(sizeof(CERT_CHAIN_ELEMENT));
+
+                if (element)
+                {
+                    *element = *chain->rgpElement[i];
+                    element->pCertContext = CertDuplicateCertificateContext(
+                     chain->rgpElement[i]->pCertContext);
+                    /* Reset the trust status of the copied element, it'll get
+                     * rechecked after the new chain is done.
+                     */
+                    memset(&element->TrustStatus, 0, sizeof(CERT_TRUST_STATUS));
+                    copy->rgpElement[copy->cElement++] = element;
+                }
+                else
+                    ret = FALSE;
+            }
+            if (!ret)
+            {
+                for (i = 0; i <= iElement; i++)
+                    CryptMemFree(copy->rgpElement[i]);
+                CryptMemFree(copy->rgpElement);
+                CryptMemFree(copy);
+                copy = NULL;
+            }
+        }
+        else
+        {
+            CryptMemFree(copy);
+            copy = NULL;
+        }
+    }
+    return copy;
+}
+
+static void CRYPT_FreeLowerQualityChains(PCertificateChain chain)
+{
+    DWORD i;
+
+    for (i = 0; i < chain->context.cLowerQualityChainContext; i++)
+        CertFreeCertificateChain(chain->context.rgpLowerQualityChainContext[i]);
+    CryptMemFree(chain->context.rgpLowerQualityChainContext);
+    chain->context.cLowerQualityChainContext = 0;
+    chain->context.rgpLowerQualityChainContext = NULL;
+}
+
+static void CRYPT_FreeChainContext(PCertificateChain chain)
+{
+    DWORD i;
+
+    CRYPT_FreeLowerQualityChains(chain);
+    for (i = 0; i < chain->context.cChain; i++)
+        CRYPT_FreeSimpleChain(chain->context.rgpChain[i]);
+    CryptMemFree(chain->context.rgpChain);
+    CertCloseStore(chain->world, 0);
+    CryptMemFree(chain);
+}
+
+/* Makes and returns a copy of chain, up to and including element iElement of
+ * simple chain iChain.
+ */
+static PCertificateChain CRYPT_CopyChainToElement(PCertificateChain chain,
+ DWORD iChain, DWORD iElement)
+{
+    PCertificateChain copy = CryptMemAlloc(sizeof(CertificateChain));
+
+    if (copy)
+    {
+        copy->ref = 1;
+        copy->world = CertDuplicateStore(chain->world);
+        copy->context.cbSize = sizeof(CERT_CHAIN_CONTEXT);
+        /* Leave the trust status of the copied chain unset, it'll get
+         * rechecked after the new chain is done.
+         */
+        memset(&copy->context.TrustStatus, 0, sizeof(CERT_TRUST_STATUS));
+        copy->context.cLowerQualityChainContext = 0;
+        copy->context.rgpLowerQualityChainContext = NULL;
+        copy->context.fHasRevocationFreshnessTime = FALSE;
+        copy->context.dwRevocationFreshnessTime = 0;
+        copy->context.rgpChain = CryptMemAlloc(
+         (iChain + 1) * sizeof(PCERT_SIMPLE_CHAIN));
+        if (copy->context.rgpChain)
+        {
+            BOOL ret = TRUE;
+            DWORD i;
+
+            memset(copy->context.rgpChain, 0,
+             (iChain + 1) * sizeof(PCERT_SIMPLE_CHAIN));
+            if (iChain)
+            {
+                for (i = 0; ret && iChain && i < iChain - 1; i++)
+                {
+                    copy->context.rgpChain[i] =
+                     CRYPT_CopySimpleChainToElement(chain->context.rgpChain[i],
+                     chain->context.rgpChain[i]->cElement - 1);
+                    if (!copy->context.rgpChain[i])
+                        ret = FALSE;
+                }
+            }
+            else
+                i = 0;
+            if (ret)
+            {
+                copy->context.rgpChain[i] =
+                 CRYPT_CopySimpleChainToElement(chain->context.rgpChain[i],
+                 iElement);
+                if (!copy->context.rgpChain[i])
+                    ret = FALSE;
+            }
+            if (!ret)
+            {
+                CRYPT_FreeChainContext(copy);
+                copy = NULL;
+            }
+            else
+                copy->context.cChain = iChain + 1;
+        }
+        else
+        {
+            CryptMemFree(copy);
+            copy = NULL;
+        }
+    }
+    return copy;
+}
+
+static PCertificateChain CRYPT_BuildAlternateContextFromChain(
+ HCERTCHAINENGINE hChainEngine, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
+ PCertificateChain chain)
+{
+    PCertificateChainEngine engine = (PCertificateChainEngine)hChainEngine;
+    PCertificateChain alternate;
+
+    TRACE("(%p, %p, %p, %p)\n", hChainEngine, pTime, hAdditionalStore, chain);
+
+    /* Always start with the last "lower quality" chain to ensure a consistent
+     * order of alternate creation:
+     */
+    if (chain->context.cLowerQualityChainContext)
+        chain = (PCertificateChain)chain->context.rgpLowerQualityChainContext[
+         chain->context.cLowerQualityChainContext - 1];
+    /* A chain with only one element can't have any alternates */
+    if (chain->context.cChain <= 1 && chain->context.rgpChain[0]->cElement <= 1)
+        alternate = NULL;
+    else
+    {
+        DWORD i, j, infoStatus;
+        PCCERT_CONTEXT alternateIssuer = NULL;
+
+        alternate = NULL;
+        for (i = 0; !alternateIssuer && i < chain->context.cChain; i++)
+            for (j = 0; !alternateIssuer &&
+             j < chain->context.rgpChain[i]->cElement - 1; j++)
+            {
+                PCCERT_CONTEXT subject =
+                 chain->context.rgpChain[i]->rgpElement[j]->pCertContext;
+                PCCERT_CONTEXT prevIssuer = CertDuplicateCertificateContext(
+                 chain->context.rgpChain[i]->rgpElement[j + 1]->pCertContext);
+
+                alternateIssuer = CRYPT_GetIssuer(prevIssuer->hCertStore,
+                 subject, prevIssuer, &infoStatus);
+            }
+        if (alternateIssuer)
+        {
+            i--;
+            j--;
+            alternate = CRYPT_CopyChainToElement(chain, i, j);
+            if (alternate)
+            {
+                BOOL ret = CRYPT_AddCertToSimpleChain(engine,
+                 alternate->context.rgpChain[i], alternateIssuer, infoStatus);
+
+                /* CRYPT_AddCertToSimpleChain add-ref's the issuer, so free it
+                 * to close the enumeration that found it
+                 */
+                CertFreeCertificateContext(alternateIssuer);
+                if (ret)
+                {
+                    ret = CRYPT_BuildSimpleChain(engine, alternate->world,
+                     alternate->context.rgpChain[i]);
+                    if (ret)
+                        CRYPT_CheckSimpleChain(engine,
+                         alternate->context.rgpChain[i], pTime);
+                    CRYPT_CombineTrustStatus(&alternate->context.TrustStatus,
+                     &alternate->context.rgpChain[i]->TrustStatus);
+                }
+                if (!ret)
+                {
+                    CRYPT_FreeChainContext(alternate);
+                    alternate = NULL;
+                }
+            }
+        }
+    }
+    TRACE("%p\n", alternate);
+    return alternate;
+}
+
+#define CHAIN_QUALITY_SIGNATURE_VALID 8
+#define CHAIN_QUALITY_TIME_VALID      4
+#define CHAIN_QUALITY_COMPLETE_CHAIN  2
+#define CHAIN_QUALITY_TRUSTED_ROOT    1
+
+#define CHAIN_QUALITY_HIGHEST \
+ CHAIN_QUALITY_SIGNATURE_VALID | CHAIN_QUALITY_TIME_VALID | \
+ CHAIN_QUALITY_COMPLETE_CHAIN | CHAIN_QUALITY_TRUSTED_ROOT
+
+#define IS_TRUST_ERROR_SET(TrustStatus, bits) \
+ (TrustStatus)->dwErrorStatus & (bits)
+
+static DWORD CRYPT_ChainQuality(PCertificateChain chain)
+{
+    DWORD quality = CHAIN_QUALITY_HIGHEST;
+
+    if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
+     CERT_TRUST_IS_UNTRUSTED_ROOT))
+        quality &= ~CHAIN_QUALITY_TRUSTED_ROOT;
+    if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
+     CERT_TRUST_IS_PARTIAL_CHAIN))
+    if (chain->context.TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
+        quality &= ~CHAIN_QUALITY_COMPLETE_CHAIN;
+    if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
+     CERT_TRUST_IS_NOT_TIME_VALID | CERT_TRUST_IS_NOT_TIME_NESTED))
+        quality &= ~CHAIN_QUALITY_TIME_VALID;
+    if (IS_TRUST_ERROR_SET(&chain->context.TrustStatus,
+     CERT_TRUST_IS_NOT_SIGNATURE_VALID))
+        quality &= ~CHAIN_QUALITY_SIGNATURE_VALID;
+    return quality;
+}
+
+/* Chooses the highest quality chain among chain and its "lower quality"
+ * alternate chains.  Returns the highest quality chain, with all other
+ * chains as lower quality chains of it.
+ */
+static PCertificateChain CRYPT_ChooseHighestQualityChain(
+ PCertificateChain chain)
+{
+    DWORD i;
+
+    /* There are always only two chains being considered:  chain, and an
+     * alternate at chain->rgpLowerQualityChainContext[i].  If the alternate
+     * has a higher quality than chain, the alternate gets assigned the lower
+     * quality contexts, with chain taking the alternate's place among the
+     * lower quality contexts.
+     */
+    for (i = 0; i < chain->context.cLowerQualityChainContext; i++)
+    {
+        PCertificateChain alternate =
+         (PCertificateChain)chain->context.rgpLowerQualityChainContext[i];
+
+        if (CRYPT_ChainQuality(alternate) > CRYPT_ChainQuality(chain))
+        {
+            alternate->context.cLowerQualityChainContext =
+             chain->context.cLowerQualityChainContext;
+            alternate->context.rgpLowerQualityChainContext =
+             chain->context.rgpLowerQualityChainContext;
+            alternate->context.rgpLowerQualityChainContext[i] =
+             (PCCERT_CHAIN_CONTEXT)chain;
+            chain->context.cLowerQualityChainContext = 0;
+            chain->context.rgpLowerQualityChainContext = NULL;
+            chain = alternate;
+        }
+    }
+    return chain;
+}
+
+static BOOL CRYPT_AddAlternateChainToChain(PCertificateChain chain,
+ PCertificateChain alternate)
+{
+    BOOL ret;
+
+    if (chain->context.cLowerQualityChainContext)
+        chain->context.rgpLowerQualityChainContext =
+         CryptMemRealloc(chain->context.rgpLowerQualityChainContext,
+         (chain->context.cLowerQualityChainContext + 1) *
+         sizeof(PCCERT_CHAIN_CONTEXT));
+    else
+        chain->context.rgpLowerQualityChainContext =
+         CryptMemAlloc(sizeof(PCCERT_CHAIN_CONTEXT));
+    if (chain->context.rgpLowerQualityChainContext)
+    {
+        chain->context.rgpLowerQualityChainContext[
+         chain->context.cLowerQualityChainContext++] =
+         (PCCERT_CHAIN_CONTEXT)alternate;
+        ret = TRUE;
+    }
+    else
+        ret = FALSE;
+    return ret;
+}
+
+static PCERT_CHAIN_ELEMENT CRYPT_FindIthElementInChain(
+ PCERT_CHAIN_CONTEXT chain, DWORD i)
+{
+    DWORD j, iElement;
+    PCERT_CHAIN_ELEMENT element = NULL;
+
+    for (j = 0, iElement = 0; !element && j < chain->cChain; j++)
+    {
+        if (iElement + chain->rgpChain[j]->cElement < i)
+            iElement += chain->rgpChain[j]->cElement;
+        else
+            element = chain->rgpChain[j]->rgpElement[i - iElement];
+    }
+    return element;
+}
+
+typedef struct _CERT_CHAIN_PARA_NO_EXTRA_FIELDS {
+    DWORD            cbSize;
+    CERT_USAGE_MATCH RequestedUsage;
+} CERT_CHAIN_PARA_NO_EXTRA_FIELDS, *PCERT_CHAIN_PARA_NO_EXTRA_FIELDS;
+
+static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain,
+ LPFILETIME pTime, PCERT_CHAIN_PARA pChainPara, DWORD chainFlags)
+{
+    DWORD cContext;
+
+    if (chainFlags & CERT_CHAIN_REVOCATION_CHECK_END_CERT)
+        cContext = 1;
+    else if ((chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN) ||
+     (chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT))
+    {
+        DWORD i;
+
+        for (i = 0, cContext = 0; i < chain->cChain; i++)
+        {
+            if (i < chain->cChain - 1 ||
+             chainFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN)
+                cContext += chain->rgpChain[i]->cElement;
+            else
+                cContext += chain->rgpChain[i]->cElement - 1;
+        }
+    }
+    else
+        cContext = 0;
+    if (cContext)
+    {
+        PCCERT_CONTEXT *contexts =
+         CryptMemAlloc(cContext * sizeof(PCCERT_CONTEXT *));
+
+        if (contexts)
+        {
+            DWORD i, j, iContext, revocationFlags;
+            CERT_REVOCATION_PARA revocationPara = { sizeof(revocationPara), 0 };
+            CERT_REVOCATION_STATUS revocationStatus =
+             { sizeof(revocationStatus), 0 };
+            BOOL ret;
+
+            for (i = 0, iContext = 0; iContext < cContext && i < chain->cChain;
+             i++)
+            {
+                for (j = 0; iContext < cContext &&
+                 j < chain->rgpChain[i]->cElement; j++)
+                    contexts[iContext++] =
+                     chain->rgpChain[i]->rgpElement[j]->pCertContext;
+            }
+            revocationFlags = CERT_VERIFY_REV_CHAIN_FLAG;
+            if (chainFlags & CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY)
+                revocationFlags |= CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION;
+            if (chainFlags & CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT)
+                revocationFlags |= CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG;
+            revocationPara.pftTimeToUse = pTime;
+            if (pChainPara->cbSize == sizeof(CERT_CHAIN_PARA))
+            {
+                revocationPara.dwUrlRetrievalTimeout =
+                 pChainPara->dwUrlRetrievalTimeout;
+                revocationPara.fCheckFreshnessTime =
+                 pChainPara->fCheckRevocationFreshnessTime;
+                revocationPara.dwFreshnessTime =
+                 pChainPara->dwRevocationFreshnessTime;
+            }
+            ret = CertVerifyRevocation(X509_ASN_ENCODING,
+             CERT_CONTEXT_REVOCATION_TYPE, cContext, (void **)contexts,
+             revocationFlags, &revocationPara, &revocationStatus);
+            if (!ret)
+            {
+                PCERT_CHAIN_ELEMENT element =
+                 CRYPT_FindIthElementInChain(chain, revocationStatus.dwIndex);
+                DWORD error;
+
+                switch (revocationStatus.dwError)
+                {
+                case CRYPT_E_NO_REVOCATION_CHECK:
+                case CRYPT_E_NO_REVOCATION_DLL:
+                case CRYPT_E_NOT_IN_REVOCATION_DATABASE:
+                    error = CERT_TRUST_REVOCATION_STATUS_UNKNOWN;
+                    break;
+                case CRYPT_E_REVOCATION_OFFLINE:
+                    error = CERT_TRUST_IS_OFFLINE_REVOCATION;
+                    break;
+                case CRYPT_E_REVOKED:
+                    error = CERT_TRUST_IS_REVOKED;
+                    break;
+                default:
+                    WARN("unmapped error %08x\n", revocationStatus.dwError);
+                    error = 0;
+                }
+                if (element)
+                {
+                    /* FIXME: set element's pRevocationInfo member */
+                    element->TrustStatus.dwErrorStatus |= error;
+                }
+                chain->TrustStatus.dwErrorStatus |= error;
+            }
+            CryptMemFree(contexts);
+        }
+    }
+}
+
+BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine,
+ PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
+ PCERT_CHAIN_PARA pChainPara, DWORD dwFlags, LPVOID pvReserved,
+ PCCERT_CHAIN_CONTEXT* ppChainContext)
+{
+    BOOL ret;
+    PCertificateChain chain = NULL;
+
+    TRACE("(%p, %p, %p, %p, %p, %08x, %p, %p)\n", hChainEngine, pCertContext,
+     pTime, hAdditionalStore, pChainPara, dwFlags, pvReserved, ppChainContext);
+
+    if (ppChainContext)
+        *ppChainContext = NULL;
+    if (!pChainPara)
+    {
+        SetLastError(E_INVALIDARG);
+        return FALSE;
+    }
+    if (!pCertContext->pCertInfo->SignatureAlgorithm.pszObjId)
+    {
+        SetLastError(ERROR_INVALID_DATA);
+        return FALSE;
+    }
+    if (pChainPara->cbSize != sizeof(CERT_CHAIN_PARA_NO_EXTRA_FIELDS) &&
+     pChainPara->cbSize != sizeof(CERT_CHAIN_PARA))
+    {
+        SetLastError(E_INVALIDARG);
+        return FALSE;
+    }
+    if (!hChainEngine)
+        hChainEngine = CRYPT_GetDefaultChainEngine();
+    /* FIXME: what about HCCE_LOCAL_MACHINE? */
+    ret = CRYPT_BuildCandidateChainFromCert(hChainEngine, pCertContext, pTime,
+     hAdditionalStore, &chain);
+    if (ret)
+    {
+        PCertificateChain alternate = NULL;
+        PCERT_CHAIN_CONTEXT pChain;
+
+        do {
+            alternate = CRYPT_BuildAlternateContextFromChain(hChainEngine,
+             pTime, hAdditionalStore, chain);
+
+            /* Alternate contexts are added as "lower quality" contexts of
+             * chain, to avoid loops in alternate chain creation.
+             * The highest-quality chain is chosen at the end.
+             */
+            if (alternate)
+                ret = CRYPT_AddAlternateChainToChain(chain, alternate);
+        } while (ret && alternate);
+        chain = CRYPT_ChooseHighestQualityChain(chain);
+        if (!(dwFlags & CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS))
+            CRYPT_FreeLowerQualityChains(chain);
+        pChain = (PCERT_CHAIN_CONTEXT)chain;
+        CRYPT_VerifyChainRevocation(pChain, pTime, pChainPara, dwFlags);
+        if (ppChainContext)
+            *ppChainContext = pChain;
+        else
+            CertFreeCertificateChain(pChain);
+    }
+    TRACE("returning %d\n", ret);
+    return ret;
+}
+
+PCCERT_CHAIN_CONTEXT WINAPI CertDuplicateCertificateChain(
+ PCCERT_CHAIN_CONTEXT pChainContext)
+{
+    PCertificateChain chain = (PCertificateChain)pChainContext;
+
+    TRACE("(%p)\n", pChainContext);
+
+    if (chain)
+        InterlockedIncrement(&chain->ref);
+    return pChainContext;
+}
+
+VOID WINAPI CertFreeCertificateChain(PCCERT_CHAIN_CONTEXT pChainContext)
+{
+    PCertificateChain chain = (PCertificateChain)pChainContext;
+
+    TRACE("(%p)\n", pChainContext);
+
+    if (chain)
+    {
+        if (InterlockedDecrement(&chain->ref) == 0)
+            CRYPT_FreeChainContext(chain);
+    }
+}
+
+static void find_element_with_error(PCCERT_CHAIN_CONTEXT chain, DWORD error,
+ LONG *iChain, LONG *iElement)
+{
+    DWORD i, j;
+
+    for (i = 0; i < chain->cChain; i++)
+        for (j = 0; j < chain->rgpChain[i]->cElement; j++)
+            if (chain->rgpChain[i]->rgpElement[j]->TrustStatus.dwErrorStatus &
+             error)
+            {
+                *iChain = i;
+                *iElement = j;
+                return;
+            }
+}
+
+static BOOL WINAPI verify_base_policy(LPCSTR szPolicyOID,
+ PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
+ PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
+{
+    pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1;
+    if (pChainContext->TrustStatus.dwErrorStatus &
+     CERT_TRUST_IS_NOT_SIGNATURE_VALID)
+    {
+        pPolicyStatus->dwError = TRUST_E_CERT_SIGNATURE;
+        find_element_with_error(pChainContext,
+         CERT_TRUST_IS_NOT_SIGNATURE_VALID, &pPolicyStatus->lChainIndex,
+         &pPolicyStatus->lElementIndex);
+    }
+    else if (pChainContext->TrustStatus.dwErrorStatus &
+     CERT_TRUST_IS_UNTRUSTED_ROOT)
+    {
+        pPolicyStatus->dwError = CERT_E_UNTRUSTEDROOT;
+        find_element_with_error(pChainContext,
+         CERT_TRUST_IS_UNTRUSTED_ROOT, &pPolicyStatus->lChainIndex,
+         &pPolicyStatus->lElementIndex);
+    }
+    else if (pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_CYCLIC)
+    {
+        pPolicyStatus->dwError = CERT_E_CHAINING;
+        find_element_with_error(pChainContext, CERT_TRUST_IS_CYCLIC,
+         &pPolicyStatus->lChainIndex, &pPolicyStatus->lElementIndex);
+        /* For a cyclic chain, which element is a cycle isn't meaningful */
+        pPolicyStatus->lElementIndex = -1;
+    }
+    else
+        pPolicyStatus->dwError = NO_ERROR;
+    return TRUE;
+}
+
+static BYTE msTestPubKey1[] = {
+0x30,0x47,0x02,0x40,0x81,0x55,0x22,0xb9,0x8a,0xa4,0x6f,0xed,0xd6,0xe7,0xd9,
+0x66,0x0f,0x55,0xbc,0xd7,0xcd,0xd5,0xbc,0x4e,0x40,0x02,0x21,0xa2,0xb1,0xf7,
+0x87,0x30,0x85,0x5e,0xd2,0xf2,0x44,0xb9,0xdc,0x9b,0x75,0xb6,0xfb,0x46,0x5f,
+0x42,0xb6,0x9d,0x23,0x36,0x0b,0xde,0x54,0x0f,0xcd,0xbd,0x1f,0x99,0x2a,0x10,
+0x58,0x11,0xcb,0x40,0xcb,0xb5,0xa7,0x41,0x02,0x03,0x01,0x00,0x01 };
+static BYTE msTestPubKey2[] = {
+0x30,0x48,0x02,0x41,0x00,0x81,0x55,0x22,0xb9,0x8a,0xa4,0x6f,0xed,0xd6,0xe7,
+0xd9,0x66,0x0f,0x55,0xbc,0xd7,0xcd,0xd5,0xbc,0x4e,0x40,0x02,0x21,0xa2,0xb1,
+0xf7,0x87,0x30,0x85,0x5e,0xd2,0xf2,0x44,0xb9,0xdc,0x9b,0x75,0xb6,0xfb,0x46,
+0x5f,0x42,0xb6,0x9d,0x23,0x36,0x0b,0xde,0x54,0x0f,0xcd,0xbd,0x1f,0x99,0x2a,
+0x10,0x58,0x11,0xcb,0x40,0xcb,0xb5,0xa7,0x41,0x02,0x03,0x01,0x00,0x01 };
+static BYTE msTestPubKey3[] = {
+0x30,0x47,0x02,0x40,0x9c,0x50,0x05,0x1d,0xe2,0x0e,0x4c,0x53,0xd8,0xd9,0xb5,
+0xe5,0xfd,0xe9,0xe3,0xad,0x83,0x4b,0x80,0x08,0xd9,0xdc,0xe8,0xe8,0x35,0xf8,
+0x11,0xf1,0xe9,0x9b,0x03,0x7a,0x65,0x64,0x76,0x35,0xce,0x38,0x2c,0xf2,0xb6,
+0x71,0x9e,0x06,0xd9,0xbf,0xbb,0x31,0x69,0xa3,0xf6,0x30,0xa0,0x78,0x7b,0x18,
+0xdd,0x50,0x4d,0x79,0x1e,0xeb,0x61,0xc1,0x02,0x03,0x01,0x00,0x01 };
+
+static BOOL WINAPI verify_authenticode_policy(LPCSTR szPolicyOID,
+ PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
+ PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
+{
+    BOOL ret = verify_base_policy(szPolicyOID, pChainContext, pPolicyPara,
+     pPolicyStatus);
+
+    if (ret && pPolicyStatus->dwError == CERT_E_UNTRUSTEDROOT)
+    {
+        CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } };
+        BOOL isMSTestRoot = FALSE;
+        PCCERT_CONTEXT failingCert =
+         pChainContext->rgpChain[pPolicyStatus->lChainIndex]->
+         rgpElement[pPolicyStatus->lElementIndex]->pCertContext;
+        DWORD i;
+        CRYPT_DATA_BLOB keyBlobs[] = {
+         { sizeof(msTestPubKey1), msTestPubKey1 },
+         { sizeof(msTestPubKey2), msTestPubKey2 },
+         { sizeof(msTestPubKey3), msTestPubKey3 },
+        };
+
+        /* Check whether the root is an MS test root */
+        for (i = 0; !isMSTestRoot && i < sizeof(keyBlobs) / sizeof(keyBlobs[0]);
+         i++)
+        {
+            msPubKey.PublicKey.cbData = keyBlobs[i].cbData;
+            msPubKey.PublicKey.pbData = keyBlobs[i].pbData;
+            if (CertComparePublicKeyInfo(
+             X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+             &failingCert->pCertInfo->SubjectPublicKeyInfo, &msPubKey))
+                isMSTestRoot = TRUE;
+        }
+        if (isMSTestRoot)
+            pPolicyStatus->dwError = CERT_E_UNTRUSTEDTESTROOT;
+    }
+    return ret;
+}
+
+static BOOL WINAPI verify_basic_constraints_policy(LPCSTR szPolicyOID,
+ PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
+ PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
+{
+    pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = -1;
+    if (pChainContext->TrustStatus.dwErrorStatus &
+     CERT_TRUST_INVALID_BASIC_CONSTRAINTS)
+    {
+        pPolicyStatus->dwError = TRUST_E_BASIC_CONSTRAINTS;
+        find_element_with_error(pChainContext,
+         CERT_TRUST_INVALID_BASIC_CONSTRAINTS, &pPolicyStatus->lChainIndex,
+         &pPolicyStatus->lElementIndex);
+    }
+    else
+        pPolicyStatus->dwError = NO_ERROR;
+    return TRUE;
+}
+
+static BYTE msPubKey1[] = {
+0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xdf,0x08,0xba,0xe3,0x3f,0x6e,
+0x64,0x9b,0xf5,0x89,0xaf,0x28,0x96,0x4a,0x07,0x8f,0x1b,0x2e,0x8b,0x3e,0x1d,
+0xfc,0xb8,0x80,0x69,0xa3,0xa1,0xce,0xdb,0xdf,0xb0,0x8e,0x6c,0x89,0x76,0x29,
+0x4f,0xca,0x60,0x35,0x39,0xad,0x72,0x32,0xe0,0x0b,0xae,0x29,0x3d,0x4c,0x16,
+0xd9,0x4b,0x3c,0x9d,0xda,0xc5,0xd3,0xd1,0x09,0xc9,0x2c,0x6f,0xa6,0xc2,0x60,
+0x53,0x45,0xdd,0x4b,0xd1,0x55,0xcd,0x03,0x1c,0xd2,0x59,0x56,0x24,0xf3,0xe5,
+0x78,0xd8,0x07,0xcc,0xd8,0xb3,0x1f,0x90,0x3f,0xc0,0x1a,0x71,0x50,0x1d,0x2d,
+0xa7,0x12,0x08,0x6d,0x7c,0xb0,0x86,0x6c,0xc7,0xba,0x85,0x32,0x07,0xe1,0x61,
+0x6f,0xaf,0x03,0xc5,0x6d,0xe5,0xd6,0xa1,0x8f,0x36,0xf6,0xc1,0x0b,0xd1,0x3e,
+0x69,0x97,0x48,0x72,0xc9,0x7f,0xa4,0xc8,0xc2,0x4a,0x4c,0x7e,0xa1,0xd1,0x94,
+0xa6,0xd7,0xdc,0xeb,0x05,0x46,0x2e,0xb8,0x18,0xb4,0x57,0x1d,0x86,0x49,0xdb,
+0x69,0x4a,0x2c,0x21,0xf5,0x5e,0x0f,0x54,0x2d,0x5a,0x43,0xa9,0x7a,0x7e,0x6a,
+0x8e,0x50,0x4d,0x25,0x57,0xa1,0xbf,0x1b,0x15,0x05,0x43,0x7b,0x2c,0x05,0x8d,
+0xbd,0x3d,0x03,0x8c,0x93,0x22,0x7d,0x63,0xea,0x0a,0x57,0x05,0x06,0x0a,0xdb,
+0x61,0x98,0x65,0x2d,0x47,0x49,0xa8,0xe7,0xe6,0x56,0x75,0x5c,0xb8,0x64,0x08,
+0x63,0xa9,0x30,0x40,0x66,0xb2,0xf9,0xb6,0xe3,0x34,0xe8,0x67,0x30,0xe1,0x43,
+0x0b,0x87,0xff,0xc9,0xbe,0x72,0x10,0x5e,0x23,0xf0,0x9b,0xa7,0x48,0x65,0xbf,
+0x09,0x88,0x7b,0xcd,0x72,0xbc,0x2e,0x79,0x9b,0x7b,0x02,0x03,0x01,0x00,0x01 };
+static BYTE msPubKey2[] = {
+0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xa9,0x02,0xbd,0xc1,0x70,0xe6,
+0x3b,0xf2,0x4e,0x1b,0x28,0x9f,0x97,0x78,0x5e,0x30,0xea,0xa2,0xa9,0x8d,0x25,
+0x5f,0xf8,0xfe,0x95,0x4c,0xa3,0xb7,0xfe,0x9d,0xa2,0x20,0x3e,0x7c,0x51,0xa2,
+0x9b,0xa2,0x8f,0x60,0x32,0x6b,0xd1,0x42,0x64,0x79,0xee,0xac,0x76,0xc9,0x54,
+0xda,0xf2,0xeb,0x9c,0x86,0x1c,0x8f,0x9f,0x84,0x66,0xb3,0xc5,0x6b,0x7a,0x62,
+0x23,0xd6,0x1d,0x3c,0xde,0x0f,0x01,0x92,0xe8,0x96,0xc4,0xbf,0x2d,0x66,0x9a,
+0x9a,0x68,0x26,0x99,0xd0,0x3a,0x2c,0xbf,0x0c,0xb5,0x58,0x26,0xc1,0x46,0xe7,
+0x0a,0x3e,0x38,0x96,0x2c,0xa9,0x28,0x39,0xa8,0xec,0x49,0x83,0x42,0xe3,0x84,
+0x0f,0xbb,0x9a,0x6c,0x55,0x61,0xac,0x82,0x7c,0xa1,0x60,0x2d,0x77,0x4c,0xe9,
+0x99,0xb4,0x64,0x3b,0x9a,0x50,0x1c,0x31,0x08,0x24,0x14,0x9f,0xa9,0xe7,0x91,
+0x2b,0x18,0xe6,0x3d,0x98,0x63,0x14,0x60,0x58,0x05,0x65,0x9f,0x1d,0x37,0x52,
+0x87,0xf7,0xa7,0xef,0x94,0x02,0xc6,0x1b,0xd3,0xbf,0x55,0x45,0xb3,0x89,0x80,
+0xbf,0x3a,0xec,0x54,0x94,0x4e,0xae,0xfd,0xa7,0x7a,0x6d,0x74,0x4e,0xaf,0x18,
+0xcc,0x96,0x09,0x28,0x21,0x00,0x57,0x90,0x60,0x69,0x37,0xbb,0x4b,0x12,0x07,
+0x3c,0x56,0xff,0x5b,0xfb,0xa4,0x66,0x0a,0x08,0xa6,0xd2,0x81,0x56,0x57,0xef,
+0xb6,0x3b,0x5e,0x16,0x81,0x77,0x04,0xda,0xf6,0xbe,0xae,0x80,0x95,0xfe,0xb0,
+0xcd,0x7f,0xd6,0xa7,0x1a,0x72,0x5c,0x3c,0xca,0xbc,0xf0,0x08,0xa3,0x22,0x30,
+0xb3,0x06,0x85,0xc9,0xb3,0x20,0x77,0x13,0x85,0xdf,0x02,0x03,0x01,0x00,0x01 };
+static BYTE msPubKey3[] = {
+0x30,0x82,0x02,0x0a,0x02,0x82,0x02,0x01,0x00,0xf3,0x5d,0xfa,0x80,0x67,0xd4,
+0x5a,0xa7,0xa9,0x0c,0x2c,0x90,0x20,0xd0,0x35,0x08,0x3c,0x75,0x84,0xcd,0xb7,
+0x07,0x89,0x9c,0x89,0xda,0xde,0xce,0xc3,0x60,0xfa,0x91,0x68,0x5a,0x9e,0x94,
+0x71,0x29,0x18,0x76,0x7c,0xc2,0xe0,0xc8,0x25,0x76,0x94,0x0e,0x58,0xfa,0x04,
+0x34,0x36,0xe6,0xdf,0xaf,0xf7,0x80,0xba,0xe9,0x58,0x0b,0x2b,0x93,0xe5,0x9d,
+0x05,0xe3,0x77,0x22,0x91,0xf7,0x34,0x64,0x3c,0x22,0x91,0x1d,0x5e,0xe1,0x09,
+0x90,0xbc,0x14,0xfe,0xfc,0x75,0x58,0x19,0xe1,0x79,0xb7,0x07,0x92,0xa3,0xae,
+0x88,0x59,0x08,0xd8,0x9f,0x07,0xca,0x03,0x58,0xfc,0x68,0x29,0x6d,0x32,0xd7,
+0xd2,0xa8,0xcb,0x4b,0xfc,0xe1,0x0b,0x48,0x32,0x4f,0xe6,0xeb,0xb8,0xad,0x4f,
+0xe4,0x5c,0x6f,0x13,0x94,0x99,0xdb,0x95,0xd5,0x75,0xdb,0xa8,0x1a,0xb7,0x94,
+0x91,0xb4,0x77,0x5b,0xf5,0x48,0x0c,0x8f,0x6a,0x79,0x7d,0x14,0x70,0x04,0x7d,
+0x6d,0xaf,0x90,0xf5,0xda,0x70,0xd8,0x47,0xb7,0xbf,0x9b,0x2f,0x6c,0xe7,0x05,
+0xb7,0xe1,0x11,0x60,0xac,0x79,0x91,0x14,0x7c,0xc5,0xd6,0xa6,0xe4,0xe1,0x7e,
+0xd5,0xc3,0x7e,0xe5,0x92,0xd2,0x3c,0x00,0xb5,0x36,0x82,0xde,0x79,0xe1,0x6d,
+0xf3,0xb5,0x6e,0xf8,0x9f,0x33,0xc9,0xcb,0x52,0x7d,0x73,0x98,0x36,0xdb,0x8b,
+0xa1,0x6b,0xa2,0x95,0x97,0x9b,0xa3,0xde,0xc2,0x4d,0x26,0xff,0x06,0x96,0x67,
+0x25,0x06,0xc8,0xe7,0xac,0xe4,0xee,0x12,0x33,0x95,0x31,0x99,0xc8,0x35,0x08,
+0x4e,0x34,0xca,0x79,0x53,0xd5,0xb5,0xbe,0x63,0x32,0x59,0x40,0x36,0xc0,0xa5,
+0x4e,0x04,0x4d,0x3d,0xdb,0x5b,0x07,0x33,0xe4,0x58,0xbf,0xef,0x3f,0x53,0x64,
+0xd8,0x42,0x59,0x35,0x57,0xfd,0x0f,0x45,0x7c,0x24,0x04,0x4d,0x9e,0xd6,0x38,
+0x74,0x11,0x97,0x22,0x90,0xce,0x68,0x44,0x74,0x92,0x6f,0xd5,0x4b,0x6f,0xb0,
+0x86,0xe3,0xc7,0x36,0x42,0xa0,0xd0,0xfc,0xc1,0xc0,0x5a,0xf9,0xa3,0x61,0xb9,
+0x30,0x47,0x71,0x96,0x0a,0x16,0xb0,0x91,0xc0,0x42,0x95,0xef,0x10,0x7f,0x28,
+0x6a,0xe3,0x2a,0x1f,0xb1,0xe4,0xcd,0x03,0x3f,0x77,0x71,0x04,0xc7,0x20,0xfc,
+0x49,0x0f,0x1d,0x45,0x88,0xa4,0xd7,0xcb,0x7e,0x88,0xad,0x8e,0x2d,0xec,0x45,
+0xdb,0xc4,0x51,0x04,0xc9,0x2a,0xfc,0xec,0x86,0x9e,0x9a,0x11,0x97,0x5b,0xde,
+0xce,0x53,0x88,0xe6,0xe2,0xb7,0xfd,0xac,0x95,0xc2,0x28,0x40,0xdb,0xef,0x04,
+0x90,0xdf,0x81,0x33,0x39,0xd9,0xb2,0x45,0xa5,0x23,0x87,0x06,0xa5,0x55,0x89,
+0x31,0xbb,0x06,0x2d,0x60,0x0e,0x41,0x18,0x7d,0x1f,0x2e,0xb5,0x97,0xcb,0x11,
+0xeb,0x15,0xd5,0x24,0xa5,0x94,0xef,0x15,0x14,0x89,0xfd,0x4b,0x73,0xfa,0x32,
+0x5b,0xfc,0xd1,0x33,0x00,0xf9,0x59,0x62,0x70,0x07,0x32,0xea,0x2e,0xab,0x40,
+0x2d,0x7b,0xca,0xdd,0x21,0x67,0x1b,0x30,0x99,0x8f,0x16,0xaa,0x23,0xa8,0x41,
+0xd1,0xb0,0x6e,0x11,0x9b,0x36,0xc4,0xde,0x40,0x74,0x9c,0xe1,0x58,0x65,0xc1,
+0x60,0x1e,0x7a,0x5b,0x38,0xc8,0x8f,0xbb,0x04,0x26,0x7c,0xd4,0x16,0x40,0xe5,
+0xb6,0x6b,0x6c,0xaa,0x86,0xfd,0x00,0xbf,0xce,0xc1,0x35,0x02,0x03,0x01,0x00,
+0x01 };
+
+static BOOL WINAPI verify_ms_root_policy(LPCSTR szPolicyOID,
+ PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
+ PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
+{
+    BOOL ret = verify_base_policy(szPolicyOID, pChainContext, pPolicyPara,
+     pPolicyStatus);
+
+    if (ret && !pPolicyStatus->dwError)
+    {
+        CERT_PUBLIC_KEY_INFO msPubKey = { { 0 } };
+        BOOL isMSRoot = FALSE;
+        DWORD i;
+        CRYPT_DATA_BLOB keyBlobs[] = {
+         { sizeof(msPubKey1), msPubKey1 },
+         { sizeof(msPubKey2), msPubKey2 },
+         { sizeof(msPubKey3), msPubKey3 },
+        };
+        PCERT_SIMPLE_CHAIN rootChain =
+         pChainContext->rgpChain[pChainContext->cChain -1 ];
+        PCCERT_CONTEXT root =
+         rootChain->rgpElement[rootChain->cElement - 1]->pCertContext;
+
+        for (i = 0; !isMSRoot && i < sizeof(keyBlobs) / sizeof(keyBlobs[0]);
+         i++)
+        {
+            msPubKey.PublicKey.cbData = keyBlobs[i].cbData;
+            msPubKey.PublicKey.pbData = keyBlobs[i].pbData;
+            if (CertComparePublicKeyInfo(
+             X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+             &root->pCertInfo->SubjectPublicKeyInfo, &msPubKey))
+                isMSRoot = TRUE;
+        }
+        if (isMSRoot)
+            pPolicyStatus->lChainIndex = pPolicyStatus->lElementIndex = 0;
+    }
+    return ret;
+}
+
+typedef BOOL (WINAPI *CertVerifyCertificateChainPolicyFunc)(LPCSTR szPolicyOID,
+ PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
+ PCERT_CHAIN_POLICY_STATUS pPolicyStatus);
+
+BOOL WINAPI CertVerifyCertificateChainPolicy(LPCSTR szPolicyOID,
+ PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
+ PCERT_CHAIN_POLICY_STATUS pPolicyStatus)
+{
+    static HCRYPTOIDFUNCSET set = NULL;
+    BOOL ret = FALSE;
+    CertVerifyCertificateChainPolicyFunc verifyPolicy = NULL;
+    HCRYPTOIDFUNCADDR hFunc = NULL;
+
+    TRACE("(%s, %p, %p, %p)\n", debugstr_a(szPolicyOID), pChainContext,
+     pPolicyPara, pPolicyStatus);
+
+    if (!HIWORD(szPolicyOID))
+    {
+        switch (LOWORD(szPolicyOID))
+        {
+        case LOWORD(CERT_CHAIN_POLICY_BASE):
+            verifyPolicy = verify_base_policy;
+            break;
+        case LOWORD(CERT_CHAIN_POLICY_AUTHENTICODE):
+            verifyPolicy = verify_authenticode_policy;
+            break;
+        case LOWORD(CERT_CHAIN_POLICY_BASIC_CONSTRAINTS):
+            verifyPolicy = verify_basic_constraints_policy;
+            break;
+        case LOWORD(CERT_CHAIN_POLICY_MICROSOFT_ROOT):
+            verifyPolicy = verify_ms_root_policy;
+            break;
+        default:
+            FIXME("unimplemented for %d\n", LOWORD(szPolicyOID));
+        }
+    }
+    if (!verifyPolicy)
+    {
+        if (!set)
+            set = CryptInitOIDFunctionSet(
+             CRYPT_OID_VERIFY_CERTIFICATE_CHAIN_POLICY_FUNC, 0);
+        CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, szPolicyOID, 0,
+         (void **)&verifyPolicy, hFunc);
+    }
+    if (verifyPolicy)
+        ret = verifyPolicy(szPolicyOID, pChainContext, pPolicyPara,
+         pPolicyStatus);
+    if (hFunc)
+        CryptFreeOIDFunctionAddress(hFunc, 0);
+    return ret;
+}
diff --git a/reactos/dll/win32/crypt32/collectionstore.c b/reactos/dll/win32/crypt32/collectionstore.c
new file mode 100644 (file)
index 0000000..9bf6d1d
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * Copyright 2004-2007 Juan Lang
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#include <stdarg.h>
+#include "windef.h"
+#include "winbase.h"
+#include "wincrypt.h"
+#include "wine/debug.h"
+#include "wine/list.h"
+#include "crypt32_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(crypt);
+
+typedef struct _WINE_STORE_LIST_ENTRY
+{
+    PWINECRYPT_CERTSTORE store;
+    DWORD                dwUpdateFlags;
+    DWORD                dwPriority;
+    struct list          entry;
+} WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
+
+typedef struct _WINE_COLLECTIONSTORE
+{
+    WINECRYPT_CERTSTORE hdr;
+    CRITICAL_SECTION    cs;
+    struct list         stores;
+} WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
+
+static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
+{
+    PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
+    PWINE_STORE_LIST_ENTRY entry, next;
+
+    TRACE("(%p, %08x)\n", store, dwFlags);
+
+    LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
+     entry)
+    {
+        TRACE("closing %p\n", entry);
+        CertCloseStore((HCERTSTORE)entry->store, dwFlags);
+        CryptMemFree(entry);
+    }
+    cs->cs.DebugInfo->Spare[0] = 0;
+    DeleteCriticalSection(&cs->cs);
+    CRYPT_FreeStore((PWINECRYPT_CERTSTORE)store);
+}
+
+static void *CRYPT_CollectionCreateContextFromChild(PWINE_COLLECTIONSTORE store,
+ PWINE_STORE_LIST_ENTRY storeEntry, void *child, size_t contextSize,
+ BOOL addRef)
+{
+    void *ret = Context_CreateLinkContext(contextSize, child,
+     sizeof(PWINE_STORE_LIST_ENTRY), addRef);
+
+    if (ret)
+        *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(ret, contextSize)
+         = storeEntry;
+
+    return ret;
+}
+
+static BOOL CRYPT_CollectionAddContext(PWINE_COLLECTIONSTORE store,
+ unsigned int contextFuncsOffset, void *context, void *toReplace, unsigned int contextSize,
+ void **pChildContext)
+{
+    BOOL ret;
+    void *childContext = NULL;
+    PWINE_STORE_LIST_ENTRY storeEntry = NULL;
+
+    TRACE("(%p, %d, %p, %p, %d)\n", store, contextFuncsOffset, context,
+     toReplace, contextSize);
+
+    ret = FALSE;
+    if (toReplace)
+    {
+        void *existingLinked = Context_GetLinkedContext(toReplace, contextSize);
+        PCONTEXT_FUNCS contextFuncs;
+
+        storeEntry = *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(toReplace,
+         contextSize);
+        contextFuncs = (PCONTEXT_FUNCS)((LPBYTE)storeEntry->store +
+         contextFuncsOffset);
+        ret = contextFuncs->addContext(storeEntry->store, context,
+         existingLinked, childContext);
+    }
+    else
+    {
+        PWINE_STORE_LIST_ENTRY entry, next;
+
+        EnterCriticalSection(&store->cs);
+        LIST_FOR_EACH_ENTRY_SAFE(entry, next, &store->stores,
+         WINE_STORE_LIST_ENTRY, entry)
+        {
+            if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
+            {
+                PCONTEXT_FUNCS contextFuncs = (PCONTEXT_FUNCS)(
+                 (LPBYTE)entry->store + contextFuncsOffset);
+
+                storeEntry = entry;
+                ret = contextFuncs->addContext(entry->store, context, NULL,
+                 (const void **)&childContext);
+                break;
+            }
+        }
+        LeaveCriticalSection(&store->cs);
+        if (!storeEntry)
+            SetLastError(E_ACCESSDENIED);
+    }
+    *pChildContext = childContext;
+    return ret;
+}
+
+/* Advances a collection enumeration by one context, if possible, where
+ * advancing means:
+ * - calling the current store's enumeration function once, and returning
+ *   the enumerated context if one is returned
+ * - moving to the next store if the current store has no more items, and
+ *   recursively calling itself to get the next item.
+ * Returns NULL if the collection contains no more items or on error.
+ * Assumes the collection store's lock is held.
+ */
+static void *CRYPT_CollectionAdvanceEnum(PWINE_COLLECTIONSTORE store,
+ PWINE_STORE_LIST_ENTRY storeEntry, PCONTEXT_FUNCS contextFuncs,
+ PCWINE_CONTEXT_INTERFACE contextInterface, void *pPrev, size_t contextSize)
+{
+    void *ret, *child;
+    struct list *storeNext = list_next(&store->stores, &storeEntry->entry);
+
+    TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
+
+    if (pPrev)
+    {
+        /* Ref-counting funny business: "duplicate" (addref) the child, because
+         * the free(pPrev) below can cause the ref count to become negative.
+         */
+        child = Context_GetLinkedContext(pPrev, contextSize);
+        contextInterface->duplicate(child);
+        child = contextFuncs->enumContext(storeEntry->store, child);
+        contextInterface->free(pPrev);
+        pPrev = NULL;
+    }
+    else
+        child = contextFuncs->enumContext(storeEntry->store, NULL);
+    if (child)
+        ret = CRYPT_CollectionCreateContextFromChild(store, storeEntry, child,
+         contextSize, FALSE);
+    else
+    {
+        if (storeNext)
+        {
+            /* We always want the same function pointers (from certs, crls)
+             * in the next store, so use the same offset into the next store.
+             */
+            size_t offset = (LPBYTE)contextFuncs - (LPBYTE)storeEntry->store;
+            PWINE_STORE_LIST_ENTRY storeNextEntry =
+             LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY, entry);
+            PCONTEXT_FUNCS storeNextContexts =
+             (PCONTEXT_FUNCS)((LPBYTE)storeNextEntry->store + offset);
+
+            ret = CRYPT_CollectionAdvanceEnum(store, storeNextEntry,
+             storeNextContexts, contextInterface, NULL, contextSize);
+        }
+        else
+        {
+            SetLastError(CRYPT_E_NOT_FOUND);
+            ret = NULL;
+        }
+    }
+    TRACE("returning %p\n", ret);
+    return ret;
+}
+
+static BOOL CRYPT_CollectionAddCert(PWINECRYPT_CERTSTORE store, void *cert,
+ void *toReplace, const void **ppStoreContext)
+{
+    BOOL ret;
+    void *childContext = NULL;
+    PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
+
+    ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, certs),
+     cert, toReplace, sizeof(CERT_CONTEXT), &childContext);
+    if (ppStoreContext && childContext)
+    {
+        PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *)
+         Context_GetExtra(childContext, sizeof(CERT_CONTEXT));
+        PCERT_CONTEXT context =
+         CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
+         sizeof(CERT_CONTEXT), TRUE);
+
+        if (context)
+            context->hCertStore = store;
+        *ppStoreContext = context;
+    }
+    CertFreeCertificateContext((PCCERT_CONTEXT)childContext);
+    return ret;
+}
+
+static void *CRYPT_CollectionEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
+{
+    PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
+    void *ret;
+
+    TRACE("(%p, %p)\n", store, pPrev);
+
+    EnterCriticalSection(&cs->cs);
+    if (pPrev)
+    {
+        PWINE_STORE_LIST_ENTRY storeEntry =
+         *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev,
+         sizeof(CERT_CONTEXT));
+
+        ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
+         &storeEntry->store->certs, pCertInterface, pPrev,
+         sizeof(CERT_CONTEXT));
+    }
+    else
+    {
+        if (!list_empty(&cs->stores))
+        {
+            PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next,
+             WINE_STORE_LIST_ENTRY, entry);
+
+            ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
+             &storeEntry->store->certs, pCertInterface, NULL,
+             sizeof(CERT_CONTEXT));
+        }
+        else
+        {
+            SetLastError(CRYPT_E_NOT_FOUND);
+            ret = NULL;
+        }
+    }
+    LeaveCriticalSection(&cs->cs);
+    if (ret)
+        ((PCERT_CONTEXT)ret)->hCertStore = store;
+    TRACE("returning %p\n", ret);
+    return ret;
+}
+
+static BOOL CRYPT_CollectionDeleteCert(PWINECRYPT_CERTSTORE store,
+ void *pCertContext)
+{
+    BOOL ret;
+
+    TRACE("(%p, %p)\n", store, pCertContext);
+
+    ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)
+     Context_GetLinkedContext(pCertContext, sizeof(CERT_CONTEXT)));
+    return ret;
+}
+
+static BOOL CRYPT_CollectionAddCRL(PWINECRYPT_CERTSTORE store, void *crl,
+ void *toReplace, const void **ppStoreContext)
+{
+    BOOL ret;
+    void *childContext = NULL;
+    PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
+
+    ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, crls),
+     crl, toReplace, sizeof(CRL_CONTEXT), &childContext);
+    if (ppStoreContext && childContext)
+    {
+        PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *)
+         Context_GetExtra(childContext, sizeof(CRL_CONTEXT));
+        PCRL_CONTEXT context =
+         CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
+         sizeof(CRL_CONTEXT), TRUE);
+
+        if (context)
+            context->hCertStore = store;
+        *ppStoreContext = context;
+    }
+    CertFreeCRLContext((PCCRL_CONTEXT)childContext);
+    return ret;
+}
+
+static void *CRYPT_CollectionEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev)
+{
+    PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
+    void *ret;
+
+    TRACE("(%p, %p)\n", store, pPrev);
+
+    EnterCriticalSection(&cs->cs);
+    if (pPrev)
+    {
+        PWINE_STORE_LIST_ENTRY storeEntry =
+         *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev,
+         sizeof(CRL_CONTEXT));
+
+        ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
+         &storeEntry->store->crls, pCRLInterface, pPrev, sizeof(CRL_CONTEXT));
+    }
+    else
+    {
+        if (!list_empty(&cs->stores))
+        {
+            PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next,
+             WINE_STORE_LIST_ENTRY, entry);
+
+            ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
+             &storeEntry->store->crls, pCRLInterface, NULL,
+             sizeof(CRL_CONTEXT));
+        }
+        else
+        {
+            SetLastError(CRYPT_E_NOT_FOUND);
+            ret = NULL;
+        }
+    }
+    LeaveCriticalSection(&cs->cs);
+    if (ret)
+        ((PCRL_CONTEXT)ret)->hCertStore = store;
+    TRACE("returning %p\n", ret);
+    return ret;
+}
+
+static BOOL CRYPT_CollectionDeleteCRL(PWINECRYPT_CERTSTORE store,
+ void *pCrlContext)
+{
+    BOOL ret;
+
+    TRACE("(%p, %p)\n", store, pCrlContext);
+
+    ret = CertDeleteCRLFromStore((PCCRL_CONTEXT)
+     Context_GetLinkedContext(pCrlContext, sizeof(CRL_CONTEXT)));
+    return ret;
+}
+
+PWINECRYPT_CERTSTORE CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
+ DWORD dwFlags, const void *pvPara)
+{
+    PWINE_COLLECTIONSTORE store;
+
+    if (dwFlags & CERT_STORE_DELETE_FLAG)
+    {
+        SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+        store = NULL;
+    }
+    else
+    {
+        store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
+        if (store)
+        {
+            memset(store, 0, sizeof(WINE_COLLECTIONSTORE));
+            CRYPT_InitStore(&store->hdr, dwFlags, StoreTypeCollection);
+            store->hdr.closeStore          = CRYPT_CollectionCloseStore;
+            store->hdr.certs.addContext    = CRYPT_CollectionAddCert;
+            store->hdr.certs.enumContext   = CRYPT_CollectionEnumCert;
+            store->hdr.certs.deleteContext = CRYPT_CollectionDeleteCert;
+            store->hdr.crls.addContext     = CRYPT_CollectionAddCRL;
+            store->hdr.crls.enumContext    = CRYPT_CollectionEnumCRL;
+            store->hdr.crls.deleteContext  = CRYPT_CollectionDeleteCRL;
+            InitializeCriticalSection(&store->cs);
+            store->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PWINE_COLLECTIONSTORE->cs");
+            list_init(&store->stores);
+        }
+    }
+    return (PWINECRYPT_CERTSTORE)store;
+}
+
+BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
+ HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
+{
+    PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
+    WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
+    PWINE_STORE_LIST_ENTRY entry;
+    BOOL ret;
+
+    TRACE("(%p, %p, %08x, %d)\n", hCollectionStore, hSiblingStore,
+     dwUpdateFlags, dwPriority);
+
+    if (!collection || !sibling)
+        return TRUE;
+    if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
+    {
+        SetLastError(E_INVALIDARG);
+        return FALSE;
+    }
+    if (collection->hdr.type != StoreTypeCollection)
+    {
+        SetLastError(E_INVALIDARG);
+        return FALSE;
+    }
+    if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
+    {
+        SetLastError(E_INVALIDARG);
+        return FALSE;
+    }
+
+    entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
+    if (entry)
+    {
+        InterlockedIncrement(&sibling->ref);
+        TRACE("sibling %p's ref count is %d\n", sibling, sibling->ref);
+        entry->store = sibling;
+        entry->dwUpdateFlags = dwUpdateFlags;
+        entry->dwPriority = dwPriority;
+        list_init(&entry->entry);
+        TRACE("%p: adding %p, priority %d\n", collection, entry, dwPriority);
+        EnterCriticalSection(&collection->cs);
+        if (dwPriority)
+        {
+            PWINE_STORE_LIST_ENTRY cursor;
+            BOOL added = FALSE;
+
+            LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
+             WINE_STORE_LIST_ENTRY, entry)
+            {
+                if (cursor->dwPriority < dwPriority)
+                {
+                    list_add_before(&cursor->entry, &entry->entry);
+                    added = TRUE;
+                    break;
+                }
+            }
+            if (!added)
+                list_add_tail(&collection->stores, &entry->entry);
+        }
+        else
+            list_add_tail(&collection->stores, &entry->entry);
+        LeaveCriticalSection(&collection->cs);
+        ret = TRUE;
+    }
+    else
+        ret = FALSE;
+    return ret;
+}
+
+void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
+ HCERTSTORE hSiblingStore)
+{
+    PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
+    WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
+    PWINE_STORE_LIST_ENTRY store, next;
+
+    TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
+
+    if (!collection || !sibling)
+        return;
+    if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
+    {
+        SetLastError(E_INVALIDARG);
+        return;
+    }
+    if (collection->hdr.type != StoreTypeCollection)
+        return;
+    if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
+    {
+        SetLastError(E_INVALIDARG);
+        return;
+    }
+    EnterCriticalSection(&collection->cs);
+    LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
+     WINE_STORE_LIST_ENTRY, entry)
+    {
+        if (store->store == sibling)
+        {
+            list_remove(&store->entry);
+            CertCloseStore(store->store, 0);
+            CryptMemFree(store);
+            break;
+        }
+    }
+    LeaveCriticalSection(&collection->cs);
+}
index ab57c57..a5b749f 100644 (file)
@@ -71,6 +71,7 @@ void *Context_CreateDataContext(size_t contextSize)
             ret = NULL;
         }
     }
+    TRACE("returning %p\n", ret);
     return ret;
 }
 
@@ -96,6 +97,7 @@ void *Context_CreateLinkContext(unsigned int contextSize, void *linked, unsigned
             InterlockedIncrement(&linkedBase->ref);
         TRACE("%p's ref count is %d\n", context, linkContext->ref);
     }
+    TRACE("returning %p\n", context);
     return context;
 }
 
@@ -123,7 +125,7 @@ void *Context_GetLinkedContext(void *context, size_t contextSize)
      contextSize);
 }
 
-PCONTEXT_PROPERTY_LIST Context_GetProperties(void *context, size_t contextSize)
+PCONTEXT_PROPERTY_LIST Context_GetProperties(const void *context, size_t contextSize)
 {
     PBASE_CONTEXT ptr = BASE_CONTEXT_FROM_CONTEXT(context, contextSize);
 
@@ -242,7 +244,7 @@ void *ContextList_Add(struct ContextList *list, void *toLink, void *toReplace)
             list->contextInterface->free(toReplace);
         }
         else
-            list_add_tail(&list->contexts, entry);
+            list_add_head(&list->contexts, entry);
         LeaveCriticalSection(&list->cs);
     }
     return context;
index 32c4f3a..9caf46d 100644 (file)
@@ -266,10 +266,10 @@ DWORD WINAPI CertEnumCRLContextProperties(PCCRL_CONTEXT pCRLContext,
     return ret;
 }
 
-static BOOL WINAPI CRLContext_SetProperty(void *context, DWORD dwPropId,
- DWORD dwFlags, const void *pvData);
+static BOOL CRLContext_SetProperty(PCCRL_CONTEXT context, DWORD dwPropId,
                                  DWORD dwFlags, const void *pvData);
 
-static BOOL CRLContext_GetHashProp(void *context, DWORD dwPropId,
+static BOOL CRLContext_GetHashProp(PCCRL_CONTEXT context, DWORD dwPropId,
  ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
  DWORD *pcbData)
 {
@@ -284,10 +284,9 @@ static BOOL CRLContext_GetHashProp(void *context, DWORD dwPropId,
     return ret;
 }
 
-static BOOL WINAPI CRLContext_GetProperty(void *context, DWORD dwPropId,
- void *pvData, DWORD *pcbData)
+static BOOL CRLContext_GetProperty(PCCRL_CONTEXT context, DWORD dwPropId,
                                  void *pvData, DWORD *pcbData)
 {
-    PCCRL_CONTEXT pCRLContext = (PCCRL_CONTEXT)context;
     PCONTEXT_PROPERTY_LIST properties =
      Context_GetProperties(context, sizeof(CRL_CONTEXT));
     BOOL ret;
@@ -302,20 +301,17 @@ static BOOL WINAPI CRLContext_GetProperty(void *context, DWORD dwPropId,
     if (ret)
     {
         if (!pvData)
-        {
             *pcbData = blob.cbData;
-            ret = TRUE;
-        }
         else if (*pcbData < blob.cbData)
         {
             SetLastError(ERROR_MORE_DATA);
             *pcbData = blob.cbData;
+            ret = FALSE;
         }
         else
         {
             memcpy(pvData, blob.pbData, blob.cbData);
             *pcbData = blob.cbData;
-            ret = TRUE;
         }
     }
     else
@@ -325,12 +321,12 @@ static BOOL WINAPI CRLContext_GetProperty(void *context, DWORD dwPropId,
         {
         case CERT_SHA1_HASH_PROP_ID:
             ret = CRLContext_GetHashProp(context, dwPropId, CALG_SHA1,
-             pCRLContext->pbCrlEncoded, pCRLContext->cbCrlEncoded, pvData,
+                                         context->pbCrlEncoded, context->cbCrlEncoded, pvData,
              pcbData);
             break;
         case CERT_MD5_HASH_PROP_ID:
             ret = CRLContext_GetHashProp(context, dwPropId, CALG_MD5,
-             pCRLContext->pbCrlEncoded, pCRLContext->cbCrlEncoded, pvData,
+                                         context->pbCrlEncoded, context->cbCrlEncoded, pvData,
              pcbData);
             break;
         default:
@@ -371,19 +367,22 @@ BOOL WINAPI CertGetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
         }
         else
         {
-            *(DWORD *)pvData =
-             CertStore_GetAccessState(pCRLContext->hCertStore);
+            if (pCRLContext->hCertStore)
+                ret = CertGetStoreProperty(pCRLContext->hCertStore, dwPropId,
+                 pvData, pcbData);
+            else
+                *(DWORD *)pvData = 0;
             ret = TRUE;
         }
         break;
     default:
-        ret = CRLContext_GetProperty((void *)pCRLContext, dwPropId, pvData,
+        ret = CRLContext_GetProperty(pCRLContext, dwPropId, pvData,
          pcbData);
     }
     return ret;
 }
 
-static BOOL WINAPI CRLContext_SetProperty(void *context, DWORD dwPropId,
+static BOOL CRLContext_SetProperty(PCCRL_CONTEXT context, DWORD dwPropId,
  DWORD dwFlags, const void *pvData)
 {
     PCONTEXT_PROPERTY_LIST properties =
@@ -460,8 +459,7 @@ BOOL WINAPI CertSetCRLContextProperty(PCCRL_CONTEXT pCRLContext,
         SetLastError(E_INVALIDARG);
         return FALSE;
     }
-    ret = CRLContext_SetProperty((void *)pCRLContext, dwPropId, dwFlags,
-     pvData);
+    ret = CRLContext_SetProperty(pCRLContext, dwPropId, dwFlags, pvData);
     TRACE("returning %d\n", ret);
     return ret;
 }
@@ -519,10 +517,7 @@ LONG WINAPI CertVerifyCRLTimeValidity(LPFILETIME pTimeToVerify,
 
     if (!pTimeToVerify)
     {
-        SYSTEMTIME sysTime;
-
-        GetSystemTime(&sysTime);
-        SystemTimeToFileTime(&sysTime, &fileTime);
+        GetSystemTimeAsFileTime(&fileTime);
         pTimeToVerify = &fileTime;
     }
     if ((ret = CompareFileTime(pTimeToVerify, &pCrlInfo->ThisUpdate)) >= 0)
index c641672..75fbcd3 100644 (file)
@@ -5,28 +5,36 @@
        <define name="__WINESRC__" />
        <define name="__USE_W32API" />
        <define name="_WIN32_IE">0x600</define>
-       <define name="_WIN32_WINNT">0x501</define>
+       <define name="_WIN32_WINNT">0x600</define>
        <define name="WINVER">0x501</define>
        <library>wine</library>
        <library>user32</library>
        <library>advapi32</library>
        <library>kernel32</library>
        <library>ntdll</library>
+       <library>imagehlp</library>
        <file>base64.c</file>
        <file>cert.c</file>
        <file>chain.c</file>
-       <file>crl.c</file>
+       <file>collectionstore.c</file>
        <file>context.c</file>
+       <file>crl.c</file>
        <file>decode.c</file>
        <file>encode.c</file>
+       <file>filestore.c</file>
+       <file>main.c</file>
+       <file>msg.c</file>
+       <file>object.c</file>
        <file>oid.c</file>
        <file>proplist.c</file>
        <file>protectdata.c</file>
+       <file>provstore.c</file>
+       <file>regstore.c</file>
+       <file>rootstore.c</file>
        <file>serialize.c</file>
        <file>sip.c</file>
        <file>store.c</file>
        <file>str.c</file>
-       <file>main.c</file>
        <file>crypt32.rc</file>
        <file>crypt32.spec</file>
 </module>
index 6754693..af0d77c 100644 (file)
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
-
-#define REACTOS_VERSION_DLL
-#define REACTOS_STR_FILE_DESCRIPTION   "CryptoAPI Library\0"
-#define REACTOS_STR_INTERNAL_NAME      "crypt32\0"
-#define REACTOS_STR_ORIGINAL_FILENAME  "crypt32.dll\0"
-
 #include "windef.h"
 #include "winbase.h"
 #include "winuser.h"
 #include "cryptres.h"
 
-#include <reactos/version.rc>
+#include "version.rc"
 
 #include "crypt32_De.rc"
 #include "crypt32_En.rc"
 #include "crypt32_Fr.rc"
 #include "crypt32_Ko.rc"
+#include "crypt32_Nl.rc"
 #include "crypt32_No.rc"
+#include "crypt32_Sv.rc"
index 7ee23f4..b7f45d0 100644 (file)
@@ -26,6 +26,7 @@
 @ stdcall CertDeleteCertificateFromStore(ptr)
 @ stdcall CertDuplicateCRLContext(ptr)
 @ stdcall CertDuplicateCTLContext(ptr)
+@ stdcall CertDuplicateCertificateChain(ptr)
 @ stdcall CertDuplicateCertificateContext(ptr)
 @ stdcall CertDuplicateStore(ptr)
 @ stdcall CertEnumCRLContextProperties(ptr long)
@@ -34,6 +35,7 @@
 @ stdcall CertEnumCTLsInStore(ptr ptr)
 @ stdcall CertEnumCertificateContextProperties(ptr long)
 @ stdcall CertEnumCertificatesInStore(long ptr)
+@ stdcall CertEnumSystemStore(long ptr ptr ptr)
 @ stdcall CertFindAttribute(str long ptr)
 @ stdcall CertFindCRLInStore(long long long long ptr ptr)
 @ stub CertFindCTLInStore
 @ stub CertFindSubjectInCTL
 @ stdcall CertFreeCRLContext(ptr)
 @ stdcall CertFreeCTLContext(ptr)
-@ stub CertFreeCertificateChain
+@ stdcall CertFreeCertificateChain(ptr)
 @ stdcall CertFreeCertificateChainEngine(ptr)
 @ stdcall CertFreeCertificateContext(ptr)
 @ stdcall CertGetCRLContextProperty(ptr long ptr ptr)
 @ stdcall CertGetCRLFromStore(ptr ptr ptr ptr)
 @ stdcall CertGetCTLContextProperty(ptr long ptr ptr)
-@ stub CertGetCertificateChain
+@ stdcall CertGetCertificateChain(ptr ptr ptr ptr ptr long ptr ptr)
 @ stdcall CertGetCertificateContextProperty(ptr long ptr ptr)
 @ stdcall CertGetEnhancedKeyUsage(ptr long ptr ptr)
 @ stub CertGetIntendedKeyUsage
@@ -58,6 +60,7 @@
 @ stdcall CertGetNameStringA(ptr long long ptr ptr long)
 @ stdcall CertGetNameStringW(ptr long long ptr ptr long)
 @ stdcall CertGetPublicKeyLength(long ptr)
+@ stdcall CertGetStoreProperty(long long ptr ptr)
 @ stdcall CertGetSubjectCertificateFromStore(ptr long ptr)
 @ stdcall CertGetValidUsages(long ptr ptr ptr ptr)
 @ stub CertIsRDNAttrsInCertificateName
 @ stdcall CertSetCTLContextProperty(ptr long long ptr)
 @ stdcall CertSetCertificateContextProperty(ptr long long ptr)
 @ stdcall CertSetEnhancedKeyUsage(ptr ptr)
+@ stdcall CertSetStoreProperty(ptr long long ptr)
 @ stdcall CertStrToNameA(long str long ptr ptr ptr ptr)
 @ stdcall CertStrToNameW(long wstr long ptr ptr ptr ptr)
+@ stdcall CertVerifyCertificateChainPolicy(str ptr ptr ptr)
 @ stdcall CertVerifyCRLRevocation(long ptr long ptr)
 @ stdcall CertVerifyCRLTimeValidity(ptr ptr)
-@ stub CertVerifyCTLUsage
-@ stub CertVerifyRevocation
+@ stdcall CertVerifyCTLUsage(long long ptr ptr long ptr ptr)
+@ stdcall CertVerifyRevocation(long long long ptr long ptr ptr)
 @ stdcall CertVerifySubjectCertificateContext(ptr ptr ptr)
 @ stdcall CertVerifyTimeValidity(ptr ptr)
 @ stdcall CertVerifyValidityNesting(ptr ptr)
 @ stub CryptExportPKCS8
 @ stdcall CryptExportPublicKeyInfo(long long long ptr ptr)
 @ stdcall CryptExportPublicKeyInfoEx(long long long str long ptr ptr ptr)
+@ stdcall CryptFindLocalizedName(wstr)
 @ stdcall CryptFindOIDInfo(long ptr long)
 @ stdcall CryptFormatObject(long long long ptr str ptr long ptr ptr)
 @ stdcall CryptFreeOIDFunctionAddress(long long)
 @ stub CryptGetAsyncParam
 @ stdcall CryptGetDefaultOIDDllList(long long ptr ptr)
 @ stdcall CryptGetDefaultOIDFunctionAddress(long long wstr long ptr ptr)
-@ stub CryptGetMessageCertificates
-@ stub CryptGetMessageSignerCount
+@ stdcall CryptGetMessageCertificates(long ptr long ptr long)
+@ stdcall CryptGetMessageSignerCount(long ptr long)
 @ stdcall CryptGetOIDFunctionAddress(long long str long ptr ptr)
 @ stdcall CryptGetOIDFunctionValue(long str str wstr ptr ptr ptr)
 @ stdcall CryptHashCertificate(long long long ptr long ptr ptr)
 @ stdcall CryptMemFree(ptr)
 @ stdcall CryptMemRealloc(ptr long)
 @ stub CryptMsgCalculateEncodedLength
-@ stub CryptMsgClose
-@ stub CryptMsgControl
+@ stdcall CryptMsgClose(ptr)
+@ stdcall CryptMsgControl(ptr long long ptr)
 @ stub CryptMsgCountersign
 @ stub CryptMsgCountersignEncoded
+@ stdcall CryptMsgDuplicate(ptr)
 @ stub CryptMsgEncodeAndSignCTL
 @ stub CryptMsgGetAndVerifySigner
-@ stub CryptMsgGetParam
-@ stub CryptMsgOpenToDecode
-@ stub CryptMsgOpenToEncode
+@ stdcall CryptMsgGetParam(ptr long long ptr ptr)
+@ stdcall CryptMsgOpenToDecode(long long long long ptr ptr)
+@ stdcall CryptMsgOpenToEncode(long long long ptr str ptr)
 @ stub CryptMsgSignCTL
-@ stub CryptMsgUpdate
+@ stdcall CryptMsgUpdate(ptr ptr long long)
 @ stub CryptMsgVerifyCountersignatureEncoded
 @ stdcall CryptProtectData(ptr wstr ptr ptr ptr long ptr)
 @ stdcall CryptQueryObject(long ptr long long long ptr ptr ptr ptr ptr ptr)
 @ stdcall CryptVerifyMessageSignature(ptr long ptr long ptr ptr ptr)
 @ stub CryptVerifyMessageSignatureWithKey
 @ stub CryptVerifySignatureU
+@ stdcall I_CertUpdateStore(ptr ptr long long)
 @ stdcall I_CryptAllocTls()
 @ stdcall I_CryptCreateLruCache(ptr ptr)
-@ stub I_CryptCreateLruEntry
+@ stdcall I_CryptCreateLruEntry(ptr long long)
 @ stdcall I_CryptDetachTls(long)
+@ stdcall I_CryptFindLruEntry(long long)
 @ stdcall I_CryptFindLruEntryData(long long long)
 @ stdcall I_CryptFlushLruCache(ptr long long)
 @ stdcall I_CryptFreeLruCache(ptr long long)
 @ stdcall I_CryptFreeTls(long long)
+@ stdcall I_CryptGetAsn1Decoder(long)
+@ stdcall I_CryptGetAsn1Encoder(long)
 @ stdcall I_CryptGetDefaultCryptProv(long)
 @ stub I_CryptGetDefaultCryptProvForEncrypt
 @ stdcall I_CryptGetOssGlobal(long)
 @ stdcall I_CryptGetTls(long)
 @ stub I_CryptInsertLruEntry
-@ stdcall I_CryptInstallAsn1Module(long long long)
+@ stdcall I_CryptInstallAsn1Module(ptr long ptr)
 @ stdcall I_CryptInstallOssGlobal(long long long)
 @ stdcall I_CryptReadTrustedPublisherDWORDValueFromRegistry(wstr ptr)
 @ stub I_CryptReleaseLruEntry
 @ stdcall I_CryptSetTls(long ptr)
-@ stdcall I_CryptUninstallAsn1Module(ptr)
+@ stdcall I_CryptUninstallAsn1Module(long)
 @ stub I_CryptUninstallOssGlobal
 @ stub PFXExportCertStore
 @ stub PFXImportCertStore
index 6c109ed..40d0719 100644 (file)
@@ -97,7 +97,7 @@ STRINGTABLE DISCARDABLE
     IDS_CROSS_CERT_DIST_POINTS "Verteilungspunkte für Kreuzzertifikate"
     IDS_APPLICATION_POLICIES "Anwendungsrichtlinien"
     IDS_APPLICATION_POLICY_MAPPINGS "Anwendungsrichtlinienzuordnungen"
-    IDS_APPLICATION_POLICY_CONSTRAINTS "Anweungsungsrichtlinieneinschränkungen"
+    IDS_APPLICATION_POLICY_CONSTRAINTS "Anwendungsungsrichtlinieneinschränkungen"
     IDS_CMC_DATA "CMC Daten"
     IDS_CMC_RESPONSE "CMC Antwort"
     IDS_UNSIGNED_CMC_REQUEST "Unsignierte CMC Antwort"
@@ -164,3 +164,11 @@ STRINGTABLE DISCARDABLE
     IDS_LIFETIME_SIGNING "Lebensdauersignatur"
     IDS_ANY_CERT_POLICY "Alle ausgegebenen Richtlinien"
 }
+
+STRINGTABLE DISCARDABLE
+{
+    IDS_LOCALIZEDNAME_ROOT "Vertrauenswürdige Stammzertifizierungsstellen"
+    IDS_LOCALIZEDNAME_MY "Persönlich"
+    IDS_LOCALIZEDNAME_CA "Zwischenzertifizierungsstellen"
+    IDS_LOCALIZEDNAME_ADDRESSBOOK "Andere Personen"
+}
index 273dcc8..38e3b2e 100644 (file)
@@ -18,7 +18,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
 
 STRINGTABLE DISCARDABLE
 {
@@ -164,3 +164,11 @@ STRINGTABLE DISCARDABLE
     IDS_LIFETIME_SIGNING "Lifetime Signing"
     IDS_ANY_CERT_POLICY "All issuance policies"
 }
+
+STRINGTABLE DISCARDABLE
+{
+    IDS_LOCALIZEDNAME_ROOT "Trusted Root Certification Authorities"
+    IDS_LOCALIZEDNAME_MY "Personal"
+    IDS_LOCALIZEDNAME_CA "Intermediate Certification Authorities"
+    IDS_LOCALIZEDNAME_ADDRESSBOOK "Other People"
+}
index f77a77d..06a11f9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * crypt32 dll French resources
  *
- * Copyright 2006 Jonathan Ernst
+ * Copyright 2006-2008 Jonathan Ernst
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,13 +22,13 @@ LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
 
 STRINGTABLE DISCARDABLE
 {
-    IDS_AUTHORITY_KEY_ID "Authority Key Identifier"
-    IDS_KEY_ATTRIBUTES "Key Attributes"
-    IDS_KEY_USAGE_RESTRICTION "Key Usage Restriction"
+    IDS_AUTHORITY_KEY_ID "Identifiant de l'authorité de la clé"
+    IDS_KEY_ATTRIBUTES "Attributs de la clé"
+    IDS_KEY_USAGE_RESTRICTION "Restrictions de l'utilisation de la clé"
     IDS_SUBJECT_ALT_NAME "Subject Alternative Name"
     IDS_ISSUER_ALT_NAME "Issuer Alternative Name"
     IDS_BASIC_CONSTRAINTS "Basic Constraints"
-    IDS_KEY_USAGE "Key Usage"
+    IDS_KEY_USAGE "Utilisation de la clé"
     IDS_CERT_POLICIES "Certificate Policies"
     IDS_SUBJECT_KEY_IDENTIFIER "Subject Key Identifier"
     IDS_CRL_REASON_CODE "CRL Reason Code"
@@ -49,7 +49,7 @@ STRINGTABLE DISCARDABLE
     IDS_SMIME_CAPABILITIES "SMIME Capabilities"
     IDS_PREFER_SIGNED_DATA "Prefer Signed Data"
     IDS_CPS "CPS"
-    IDS_USER_NOTICE "User Notice"
+    IDS_USER_NOTICE "Notice utilisateur"
     IDS_OCSP "On-line Certificate Status Protocol"
     IDS_CA_ISSUER "Certification Authority Issuer"
     IDS_CERT_TEMPLATE_NAME "Certification Template Name"
@@ -157,10 +157,18 @@ STRINGTABLE DISCARDABLE
     IDS_DOCUMENT_SIGNING "Signature de document"
     IDS_IPSEC_IKE_INTERMEDIATE "IP security IKE intermediate"
     IDS_FILE_RECOVERY "Récupération de fichier"
-    IDS_ROOT_LIST_SIGNER "Root List Signer"
+    IDS_ROOT_LIST_SIGNER "Signataires de la liste racine"
     IDS_ANY_APPLICATION_POLICIES "All application policies"
     IDS_DS_EMAIL_REPLICATION "Directory Service Email Replication"
     IDS_ENROLLMENT_AGENT "Certificate Request Agent"
     IDS_LIFETIME_SIGNING "Lifetime Signing"
     IDS_ANY_CERT_POLICY "All issuance policies"
 }
+
+STRINGTABLE DISCARDABLE
+{
+    IDS_LOCALIZEDNAME_ROOT "Autorités de certification de confiance"
+    IDS_LOCALIZEDNAME_MY "Personnel"
+    IDS_LOCALIZEDNAME_CA "Autorités intermédiaires"
+    IDS_LOCALIZEDNAME_ADDRESSBOOK "Autres personnes"
+}
index 418e045..cdb89fc 100644 (file)
@@ -19,7 +19,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
+LANGUAGE LANG_KOREAN, SUBLANG_NEUTRAL
 
 STRINGTABLE DISCARDABLE
 {
@@ -165,3 +165,11 @@ STRINGTABLE DISCARDABLE
     IDS_LIFETIME_SIGNING "Æò»ý ¼­¸í"
     IDS_ANY_CERT_POLICY "¸ðµç ¹èÆ÷ ¹æħ"
 }
+
+STRINGTABLE DISCARDABLE
+{
+    IDS_LOCALIZEDNAME_ROOT "½Åȸ ÇÒ ¼ö Àִ ·çÆ® °Ë»çÁõ±â°ü"
+    IDS_LOCALIZEDNAME_MY "°³ÀÎÀû"
+    IDS_LOCALIZEDNAME_CA "Áß°£ °ËÁõ ±â°ü¤¤Intermediate Certification Authorities"
+    IDS_LOCALIZEDNAME_ADDRESSBOOK "´Ù¸¥ »ç¶÷"
+}
diff --git a/reactos/dll/win32/crypt32/crypt32_Nl.rc b/reactos/dll/win32/crypt32/crypt32_Nl.rc
new file mode 100644 (file)
index 0000000..b98f213
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Dutch crypt32 dll resources
+ *
+ * Copyright (C) 2008 Frans Kool
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL
+
+STRINGTABLE DISCARDABLE
+{
+    IDS_AUTHORITY_KEY_ID "Autoriteits Sleutel Identificatie nummer"
+    IDS_KEY_ATTRIBUTES "Sleutel Attributen"
+    IDS_KEY_USAGE_RESTRICTION "Sleutel Gebruiksbeperkingen"
+    IDS_SUBJECT_ALT_NAME "Onderwerp's Alternatieve Naam"
+    IDS_ISSUER_ALT_NAME "Verstrekker's Alternatieve Naam"
+    IDS_BASIC_CONSTRAINTS "Basis Beperkingen"
+    IDS_KEY_USAGE "Sleutel Gebruik"
+    IDS_CERT_POLICIES "Certificaat Beleid"
+    IDS_SUBJECT_KEY_IDENTIFIER "Onderwerp's Sleutel Identificatie nummer"
+    IDS_CRL_REASON_CODE "CRL Reden Code"
+    IDS_CRL_DIST_POINTS "CRL Distributie Locaties"
+    IDS_ENHANCED_KEY_USAGE "Uitgebreid Sleutel Gebruik"
+    IDS_AUTHORITY_INFO_ACCESS "Autoriteits Informatie Toegang"
+    IDS_CERT_EXTENSIONS "Certificaat Extensies"
+    IDS_NEXT_UPDATE_LOCATION "Volgende Update Locatie"
+    IDS_YES_OR_NO_TRUST "Wel of Geen Vertrouwen"
+    IDS_EMAIL_ADDRESS "Email Adres"
+    IDS_UNSTRUCTURED_NAME "Ongestructureerde Naam"
+    IDS_CONTENT_TYPE "Inhoud Type"
+    IDS_MESSAGE_DIGEST "Boodschap Samenvatting"
+    IDS_SIGNING_TIME "Tijd van Ondertekening"
+    IDS_COUNTER_SIGN "Counter Sign"
+    IDS_CHALLENGE_PASSWORD "Geheime Vraag Wachtwoord"
+    IDS_UNSTRUCTURED_ADDRESS "Ongestructureerd Adres"
+    IDS_SMIME_CAPABILITIES "SMIME Mogelijkheden"
+    IDS_PREFER_SIGNED_DATA "Prefereer Getekende Data"
+    IDS_CPS "CPS"
+    IDS_USER_NOTICE "Gebruikers Mededeling"
+    IDS_OCSP "On-line Certificaat Status Protocol"
+    IDS_CA_ISSUER "Certificatie Autoriteits Verstrekker"
+    IDS_CERT_TEMPLATE_NAME "Certificatie Template Naam"
+    IDS_CERT_TYPE "Type Certificaat"
+    IDS_CERT_MANIFOLD "Certificaat Verspreider"
+    IDS_NETSCAPE_CERT_TYPE "Netscape Certificaat Type"
+    IDS_NETSCAPE_BASE_URL "Netscape Basis URL"
+    IDS_NETSCAPE_REVOCATION_URL "Netscape Terugroep URL"
+    IDS_NETSCAPE_CA_REVOCATION_URL "Netscape CA Terugroep URL"
+    IDS_NETSCAPE_CERT_RENEWAL_URL "Netscape Cert Verversings URL"
+    IDS_NETSCAPE_CA_POLICY_URL "Netscape CA Beleids URL"
+    IDS_NETSCAPE_SSL_SERVER_NAME "Netscape SSL Server Naam"
+    IDS_NETSCAPE_COMMENT "Netscape Commentaar"
+    IDS_SPC_SP_AGENCY_INFO "SpcSpAgencyInfo"
+    IDS_SPC_FINANCIAL_CRITERIA "SpcFinancialCriteria"
+    IDS_SPC_MINIMAL_CRITERIA "SpcMinimalCriteria"
+    IDS_COUNTRY "Land/Regio"
+    IDS_ORGANIZATION "Organisatie"
+    IDS_ORGANIZATIONAL_UNIT "Organisatie Onderdeel"
+    IDS_COMMON_NAME "Gemeenschappelijke Naam"
+    IDS_LOCALITY "Localiteit"
+    IDS_STATE_OR_PROVINCE "Staat of Provincie"
+    IDS_TITLE "Titel"
+    IDS_GIVEN_NAME "Voornaam"
+    IDS_INITIALS "Initialen"
+    IDS_SUR_NAME "Achternaam"
+    IDS_DOMAIN_COMPONENT "Domein Component"
+    IDS_STREET_ADDRESS "Straat/Adres"
+    IDS_SERIAL_NUMBER "Registratie Nummer"
+    IDS_CA_VERSION "CA Versie"
+    IDS_CROSS_CA_VERSION "Cross CA Versie"
+    IDS_SERIALIZED_SIG_SERIAL_NUMBER "Geautomatiseerde Handtekening Serienummer"
+    IDS_PRINCIPAL_NAME "Hoofd Naam"
+    IDS_WINDOWS_PRODUCT_UPDATE "Windows Produkt Update"
+    IDS_ENROLLMENT_NAME_VALUE_PAIR "Inschrijvingsnaam Waarde Paar"
+    IDS_OS_VERSION "OS Versie"
+    IDS_ENROLLMENT_CSP "Inschrijving CSP"
+    IDS_CRL_NUMBER "CRL Nummer"
+    IDS_DELTA_CRL_INDICATOR "Delta CRL Indicatie"
+    IDS_ISSUING_DIST_POINT "Verstrekkend Distributie Punt"
+    IDS_FRESHEST_CRL "Nieuwste CRL"
+    IDS_NAME_CONSTRAINTS "Beperkingen op Naam"
+    IDS_POLICY_MAPPINGS "Beleids Mappingen"
+    IDS_POLICY_CONSTRAINTS "Beperkingen op Beleid"
+    IDS_CROSS_CERT_DIST_POINTS "Trans-Certificaat Distributie Punten"
+    IDS_APPLICATION_POLICIES "Applicatie Beleid"
+    IDS_APPLICATION_POLICY_MAPPINGS "Applicatie Beleids Mappingen"
+    IDS_APPLICATION_POLICY_CONSTRAINTS "Applicatie Beperkingen op Beleid"
+    IDS_CMC_DATA "CMC Data"
+    IDS_CMC_RESPONSE "CMC Antwoord"
+    IDS_UNSIGNED_CMC_REQUEST "Ongetekend CMC Verzoek"
+    IDS_CMC_STATUS_INFO "CMC Status Informatie"
+    IDS_CMC_EXTENSIONS "CMC Extensies"
+    IDS_CMC_ATTRIBUTES "CMC Attributen"
+    IDS_PKCS_7_DATA "PKCS 7 Data"
+    IDS_PKCS_7_SIGNED "PKCS 7 Ondertekend"
+    IDS_PKCS_7_ENVELOPED "PKCS 7 Omsloten"
+    IDS_PKCS_7_SIGNED_ENVELOPED "PKCS 7 Getekend Omsloten"
+    IDS_PKCS_7_DIGESTED "PKCS 7 Samengevat"
+    IDS_PKCS_7_ENCRYPTED "PKCS 7 Gecodeerd"
+    IDS_PREVIOUS_CA_CERT_HASH "Vorige CA Certificaat Hash"
+    IDS_CRL_VIRTUAL_BASE "Virtueel Basis CRL Nummer"
+    IDS_CRL_NEXT_PUBLISH "Volgende CRL Publicatie"
+    IDS_CA_EXCHANGE "CA Coderings Certificaat"
+    IDS_KEY_RECOVERY_AGENT "Sleutel Herstel Agent"
+    IDS_CERTIFICATE_TEMPLATE "Certificaat Template Information"
+    IDS_ENTERPRISE_ROOT_OID "Ondernemings Basis OID"
+    IDS_RDN_DUMMY_SIGNER "Dummie Tekenaar"
+    IDS_ARCHIVED_KEY_ATTR "Gecodeerde Persoonlijke Sleutel"
+    IDS_CRL_SELF_CDP "Gepubliseerde CRL Locaties"
+    IDS_REQUIRE_CERT_CHAIN_POLICY "Afdwingen Certificaat Keten Beleid"
+    IDS_TRANSACTION_ID "Transactie Nummer"
+    IDS_SENDER_NONCE "Zender Nonce"
+    IDS_RECIPIENT_NONCE "Ontvanger Nonce"
+    IDS_REG_INFO "Registratie Informatie"
+    IDS_GET_CERTIFICATE "Haal Certificaat op"
+    IDS_GET_CRL "Haal CRL op"
+    IDS_REVOKE_REQUEST "Trek Verzoek In"
+    IDS_QUERY_PENDING "Verzoek in behandeling"
+    IDS_SORTED_CTL "Certificaat Vertrouwenslijst"
+    IDS_ARCHIVED_KEY_CERT_HASH "Gearchiveerde Sleutel Certificaat Hash"
+    IDS_PRIVATE_KEY_USAGE_PERIOD "Prive Sleutel Gebruik Periode"
+    IDS_CLIENT_INFORMATION "Cliënt Informatie"
+    IDS_SERVER_AUTHENTICATION "Server Authentificatie"
+    IDS_CLIENT_AUTHENTICATION "Cliënt Authentificatie"
+    IDS_CODE_SIGNING "Code Ondertekenen"
+    IDS_SECURE_EMAIL "Beveiligde Email"
+    IDS_TIME_STAMPING "Tijd Stempel Toekennen"
+    IDS_MICROSOFT_TRUST_LIST_SIGNING "Microsoft Trust Lijst Ondertekenen"
+    IDS_MICROSOFT_TIME_STAMPING "Microsoft Tijd Stempel Toekennen"
+    IDS_IPSEC_END_SYSTEM "IP beveiliging eind systeem"
+    IDS_IPSEC_TUNNEL "IP beveiliging tunnel afsluiting"
+    IDS_IPSEC_USER "IP beveiliging gebruiker"
+    IDS_EFS "Versleutelen Bestand Systeem"
+    IDS_WHQL_CRYPTO "Windows Hardware Driver Verificatie"
+    IDS_NT5_CRYPTO "Windows Systeem Component Verificatie"
+    IDS_OEM_WHQL_CRYPTO "OEM Windows Systeem Component Verificatie"
+    IDS_EMBEDDED_NT_CRYPTO "Ingebed Windows Systeem Componenten Verificatie"
+    IDS_KEY_PACK_LICENSES "Sleutel Verzameling Licenties"
+    IDS_LICENSE_SERVER "Licentie Server Verificatie"
+    IDS_SMART_CARD_LOGON "Smart Card Aanmelden"
+    IDS_DIGITAL_RIGHTS "Digitale Rechten"
+    IDS_QUALIFIED_SUBORDINATION "Gekwalificeerde Ondergeschiktheid"
+    IDS_KEY_RECOVERY "Sleutel Herstellen"
+    IDS_DOCUMENT_SIGNING "Document Ondertekenen"
+    IDS_IPSEC_IKE_INTERMEDIATE "IP beveiliging IKE tussenpersoon"
+    IDS_FILE_RECOVERY "Bestand Herstellen"
+    IDS_ROOT_LIST_SIGNER "Basis Lijst Ondertekenaar"
+    IDS_ANY_APPLICATION_POLICIES "Alle applicaties beleid"
+    IDS_DS_EMAIL_REPLICATION "Directory Service Email Replicatie"
+    IDS_ENROLLMENT_AGENT "Certificaat Verzoek Agent"
+    IDS_LIFETIME_SIGNING "Levensduur Ondertekenen"
+    IDS_ANY_CERT_POLICY "Alle uitgifte beleid"
+}
+
+STRINGTABLE DISCARDABLE
+{
+    IDS_LOCALIZEDNAME_ROOT "Vertrouwde Basis Certificatie Autoriteiten"
+    IDS_LOCALIZEDNAME_MY "Persoonlijk"
+    IDS_LOCALIZEDNAME_CA "Certificatie Tussen-Autoriteiten"
+    IDS_LOCALIZEDNAME_ADDRESSBOOK "Overige Personen"
+}
index 02ce5d7..18de84b 100644 (file)
@@ -18,7 +18,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-LANGUAGE LANG_NORWEGIAN, SUBLANG_NEUTRAL
+LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL
 
 STRINGTABLE DISCARDABLE
 {
@@ -164,3 +164,11 @@ STRINGTABLE DISCARDABLE
     IDS_LIFETIME_SIGNING "Livstidsignering"
     IDS_ANY_CERT_POLICY "Alle framgangsmåter for utsteding"
 }
+
+STRINGTABLE DISCARDABLE
+{
+    IDS_LOCALIZEDNAME_ROOT "Klarerte rotsertifiseringsinstanser"
+    IDS_LOCALIZEDNAME_MY "Personlig"
+    IDS_LOCALIZEDNAME_CA "Mellomliggende sertifiseringsinstanser"
+    IDS_LOCALIZEDNAME_ADDRESSBOOK "Andre personer"
+}
diff --git a/reactos/dll/win32/crypt32/crypt32_Sv.rc b/reactos/dll/win32/crypt32/crypt32_Sv.rc
new file mode 100644 (file)
index 0000000..33167d1
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * crypt32 dll resources
+ *
+ * Copyright (C) 2007 Daniel Nylander
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#pragma code_page(65001)
+
+LANGUAGE LANG_SWEDISH, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+    IDS_AUTHORITY_KEY_ID "Authority Key Identifier"
+    IDS_KEY_ATTRIBUTES "Nyckelattribut"
+    IDS_KEY_USAGE_RESTRICTION "Key Usage Restriction"
+    IDS_SUBJECT_ALT_NAME "Subject Alternative Name"
+    IDS_ISSUER_ALT_NAME "Issuer Alternative Name"
+    IDS_BASIC_CONSTRAINTS "Basic Constraints"
+    IDS_KEY_USAGE "Nyckelanvändning"
+    IDS_CERT_POLICIES "Certificate Policies"
+    IDS_SUBJECT_KEY_IDENTIFIER "Subject Key Identifier"
+    IDS_CRL_REASON_CODE "CRL Reason Code"
+    IDS_CRL_DIST_POINTS "CRL Distribution Points"
+    IDS_ENHANCED_KEY_USAGE "Enhanced Key Usage"
+    IDS_AUTHORITY_INFO_ACCESS "Authority Information Access"
+    IDS_CERT_EXTENSIONS "Certificate Extensions"
+    IDS_NEXT_UPDATE_LOCATION "Next Update Location"
+    IDS_YES_OR_NO_TRUST "Yes or No Trust"
+    IDS_EMAIL_ADDRESS "E-postadress"
+    IDS_UNSTRUCTURED_NAME "Unstructured Name"
+    IDS_CONTENT_TYPE "Innehållstyp"
+    IDS_MESSAGE_DIGEST "Message Digest"
+    IDS_SIGNING_TIME "Signing Time"
+    IDS_COUNTER_SIGN "Counter Sign"
+    IDS_CHALLENGE_PASSWORD "Challenge Password"
+    IDS_UNSTRUCTURED_ADDRESS "Unstructured Address"
+    IDS_SMIME_CAPABILITIES "SMIME Capabilities"
+    IDS_PREFER_SIGNED_DATA "Prefer Signed Data"
+    IDS_CPS "CPS"
+    IDS_USER_NOTICE "User Notice"
+    IDS_OCSP "On-line Certificate Status Protocol"
+    IDS_CA_ISSUER "Certification Authority Issuer"
+    IDS_CERT_TEMPLATE_NAME "Certification Template Name"
+    IDS_CERT_TYPE "Certificate Type"
+    IDS_CERT_MANIFOLD "Certificate Manifold"
+    IDS_NETSCAPE_CERT_TYPE "Netscape Cert Type"
+    IDS_NETSCAPE_BASE_URL "Netscape Base URL"
+    IDS_NETSCAPE_REVOCATION_URL "Netscape Revocation URL"
+    IDS_NETSCAPE_CA_REVOCATION_URL "Netscape CA Revocation URL"
+    IDS_NETSCAPE_CERT_RENEWAL_URL "Netscape Cert Renewal URL"
+    IDS_NETSCAPE_CA_POLICY_URL "Netscape CA Policy URL"
+    IDS_NETSCAPE_SSL_SERVER_NAME "Netscape SSL ServerName"
+    IDS_NETSCAPE_COMMENT "Netscape Comment"
+    IDS_SPC_SP_AGENCY_INFO "SpcSpAgencyInfo"
+    IDS_SPC_FINANCIAL_CRITERIA "SpcFinancialCriteria"
+    IDS_SPC_MINIMAL_CRITERIA "SpcMinimalCriteria"
+    IDS_COUNTRY "Land/Region"
+    IDS_ORGANIZATION "Organisation"
+    IDS_ORGANIZATIONAL_UNIT "Organizational Unit"
+    IDS_COMMON_NAME "Common Name"
+    IDS_LOCALITY "Plats"
+    IDS_STATE_OR_PROVINCE "Län eller region"
+    IDS_TITLE "Titel"
+    IDS_GIVEN_NAME "Förnamn"
+    IDS_INITIALS "Initialer"
+    IDS_SUR_NAME "Efternamn"
+    IDS_DOMAIN_COMPONENT "Domain Component"
+    IDS_STREET_ADDRESS "Postadress"
+    IDS_SERIAL_NUMBER "Serienummer"
+    IDS_CA_VERSION "CA Version"
+    IDS_CROSS_CA_VERSION "Cross CA Version"
+    IDS_SERIALIZED_SIG_SERIAL_NUMBER "Serialized Signature Serial Number"
+    IDS_PRINCIPAL_NAME "Principal Name"
+    IDS_WINDOWS_PRODUCT_UPDATE "Windows Product Update"
+    IDS_ENROLLMENT_NAME_VALUE_PAIR "Enrollment Name Value Pair"
+    IDS_OS_VERSION "OS Version"
+    IDS_ENROLLMENT_CSP "Enrollment CSP"
+    IDS_CRL_NUMBER "CRL Number"
+    IDS_DELTA_CRL_INDICATOR "Delta CRL Indicator"
+    IDS_ISSUING_DIST_POINT "Issuing Distribution Point"
+    IDS_FRESHEST_CRL "Freshest CRL"
+    IDS_NAME_CONSTRAINTS "Name Constraints"
+    IDS_POLICY_MAPPINGS "Policy Mappings"
+    IDS_POLICY_CONSTRAINTS "Policy Constraints"
+    IDS_CROSS_CERT_DIST_POINTS "Cross-Certificate Distribution Points"
+    IDS_APPLICATION_POLICIES "Application Policies"
+    IDS_APPLICATION_POLICY_MAPPINGS "Application Policy Mappings"
+    IDS_APPLICATION_POLICY_CONSTRAINTS "Application Policy Constraints"
+    IDS_CMC_DATA "CMC Data"
+    IDS_CMC_RESPONSE "CMC Response"
+    IDS_UNSIGNED_CMC_REQUEST "Unsigned CMC Request"
+    IDS_CMC_STATUS_INFO "CMC Status Info"
+    IDS_CMC_EXTENSIONS "CMC Extensions"
+    IDS_CMC_ATTRIBUTES "CMC Attributes"
+    IDS_PKCS_7_DATA "PKCS 7 Data"
+    IDS_PKCS_7_SIGNED "PKCS 7 Signed"
+    IDS_PKCS_7_ENVELOPED "PKCS 7 Enveloped"
+    IDS_PKCS_7_SIGNED_ENVELOPED "PKCS 7 Signed Enveloped"
+    IDS_PKCS_7_DIGESTED "PKCS 7 Digested"
+    IDS_PKCS_7_ENCRYPTED "PKCS 7 Encrypted"
+    IDS_PREVIOUS_CA_CERT_HASH "Previous CA Certificate Hash"
+    IDS_CRL_VIRTUAL_BASE "Virtual Base CRL Number"
+    IDS_CRL_NEXT_PUBLISH "Next CRL Publish"
+    IDS_CA_EXCHANGE "CA Encryption Certificate"
+    IDS_KEY_RECOVERY_AGENT "Key Recovery Agent"
+    IDS_CERTIFICATE_TEMPLATE "Certificate Template Information"
+    IDS_ENTERPRISE_ROOT_OID "Enterprise Root OID"
+    IDS_RDN_DUMMY_SIGNER "Dummy Signer"
+    IDS_ARCHIVED_KEY_ATTR "Encrypted Private Key"
+    IDS_CRL_SELF_CDP "Published CRL Locations"
+    IDS_REQUIRE_CERT_CHAIN_POLICY "Enforce Certificate Chain Policy"
+    IDS_TRANSACTION_ID "Transaction Id"
+    IDS_SENDER_NONCE "Sender Nonce"
+    IDS_RECIPIENT_NONCE "Recipient Nonce"
+    IDS_REG_INFO "Reg Info"
+    IDS_GET_CERTIFICATE "Get Certificate"
+    IDS_GET_CRL "Get CRL"
+    IDS_REVOKE_REQUEST "Revoke Request"
+    IDS_QUERY_PENDING "Query Pending"
+    IDS_SORTED_CTL "Certificate Trust List"
+    IDS_ARCHIVED_KEY_CERT_HASH "Archived Key Certificate Hash"
+    IDS_PRIVATE_KEY_USAGE_PERIOD "Private Key Usage Period"
+    IDS_CLIENT_INFORMATION "Client Information"
+    IDS_SERVER_AUTHENTICATION "Server Authentication"
+    IDS_CLIENT_AUTHENTICATION "Client Authentication"
+    IDS_CODE_SIGNING "Code Signing"
+    IDS_SECURE_EMAIL "Säker e-post"
+    IDS_TIME_STAMPING "Time Stamping"
+    IDS_MICROSOFT_TRUST_LIST_SIGNING "Microsoft Trust List Signing"
+    IDS_MICROSOFT_TIME_STAMPING "Microsoft Time Stamping"
+    IDS_IPSEC_END_SYSTEM "IP security end system"
+    IDS_IPSEC_TUNNEL "IP security tunnel termination"
+    IDS_IPSEC_USER "IP security user"
+    IDS_EFS "Encrypting File System"
+    IDS_WHQL_CRYPTO "Windows Hardware Driver Verification"
+    IDS_NT5_CRYPTO "Windows System Component Verification"
+    IDS_OEM_WHQL_CRYPTO "OEM Windows System Component Verification"
+    IDS_EMBEDDED_NT_CRYPTO "Embedded Windows System Component Verification"
+    IDS_KEY_PACK_LICENSES "Key Pack Licenses"
+    IDS_LICENSE_SERVER "License Server Verification"
+    IDS_SMART_CARD_LOGON "Smart Card Logon"
+    IDS_DIGITAL_RIGHTS "Digital Rights"
+    IDS_QUALIFIED_SUBORDINATION "Qualified Subordination"
+    IDS_KEY_RECOVERY "Key Recovery"
+    IDS_DOCUMENT_SIGNING "Document Signing"
+    IDS_IPSEC_IKE_INTERMEDIATE "IP security IKE intermediate"
+    IDS_FILE_RECOVERY "File Recovery"
+    IDS_ROOT_LIST_SIGNER "Root List Signer"
+    IDS_ANY_APPLICATION_POLICIES "All application policies"
+    IDS_DS_EMAIL_REPLICATION "Directory Service Email Replication"
+    IDS_ENROLLMENT_AGENT "Certificate Request Agent"
+    IDS_LIFETIME_SIGNING "Lifetime Signing"
+    IDS_ANY_CERT_POLICY "All issuance policies"
+}
+
+#pragma code_page(default)
index 8aa544b..18384dc 100644 (file)
 #define ASN_UNIVERSALSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x1c)
 #define ASN_BMPSTRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x1e)
 
+BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded);
+
+typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
+ DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
+
+struct AsnEncodeSequenceItem
+{
+    const void             *pvStructInfo;
+    CryptEncodeObjectExFunc encodeFunc;
+    DWORD                   size; /* used during encoding, not for your use */
+};
+
+BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
+ struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
+
+struct AsnConstructedItem
+{
+    BYTE                    tag;
+    const void             *pvStructInfo;
+    CryptEncodeObjectExFunc encodeFunc;
+};
+
+BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
+BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
+BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
+ PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
+
+typedef struct _CRYPT_DIGESTED_DATA
+{
+    DWORD                      version;
+    CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm;
+    CRYPT_CONTENT_INFO         ContentInfo;
+    CRYPT_HASH_BLOB            hash;
+} CRYPT_DIGESTED_DATA;
+
+BOOL CRYPT_AsnEncodePKCSDigestedData(CRYPT_DIGESTED_DATA *digestedData,
+ void *pvData, DWORD *pcbData);
+
+typedef struct _CRYPT_SIGNED_INFO
+{
+    DWORD              version;
+    DWORD              cCertEncoded;
+    PCERT_BLOB         rgCertEncoded;
+    DWORD              cCrlEncoded;
+    PCRL_BLOB          rgCrlEncoded;
+    CRYPT_CONTENT_INFO content;
+    DWORD              cSignerInfo;
+    PCMSG_SIGNER_INFO  rgSignerInfo;
+} CRYPT_SIGNED_INFO;
+
+BOOL CRYPT_AsnEncodePKCSSignedInfo(CRYPT_SIGNED_INFO *, void *pvData,
+ DWORD *pcbData);
+
+BOOL CRYPT_AsnDecodePKCSSignedInfo(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
+ CRYPT_SIGNED_INFO *signedInfo, DWORD *pcbSignedInfo);
+
+/* Helper function to check *pcbEncoded, set it to the required size, and
+ * optionally to allocate memory.  Assumes pbEncoded is not NULL.
+ * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
+ * pointer to the newly allocated memory.
+ */
+BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
+ BYTE *pbEncoded, DWORD *pcbEncoded, DWORD bytesNeeded);
+
+BOOL CRYPT_AsnDecodePKCSDigestedData(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
+ CRYPT_DIGESTED_DATA *digestedData, DWORD *pcbDigestedData);
+
 /* The following aren't defined in wincrypt.h, as they're "reserved" */
 #define CERT_CERT_PROP_ID 32
 #define CERT_CRL_PROP_ID  33
@@ -50,6 +125,9 @@ HCRYPTPROV CRYPT_GetDefaultProvider(void);
 
 void crypt_oid_init(HINSTANCE hinst);
 void crypt_oid_free(void);
+void crypt_sip_free(void);
+void root_store_free(void);
+void default_chain_engine_free(void);
 
 /* Some typedefs that make it easier to abstract which type of context we're
  * working with.
@@ -95,6 +173,94 @@ extern PCWINE_CONTEXT_INTERFACE pCertInterface;
 extern PCWINE_CONTEXT_INTERFACE pCRLInterface;
 extern PCWINE_CONTEXT_INTERFACE pCTLInterface;
 
+/* (Internal) certificate store types and functions */
+struct WINE_CRYPTCERTSTORE;
+
+typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv,
+ DWORD dwFlags, const void *pvPara);
+
+/* Called to enumerate the next context in a store. */
+typedef void * (*EnumFunc)(struct WINE_CRYPTCERTSTORE *store, void *pPrev);
+
+/* Called to add a context to a store.  If toReplace is not NULL,
+ * context replaces toReplace in the store, and access checks should not be
+ * performed.  Otherwise context is a new context, and it should only be
+ * added if the store allows it.  If ppStoreContext is not NULL, the added
+ * context should be returned in *ppStoreContext.
+ */
+typedef BOOL (*AddFunc)(struct WINE_CRYPTCERTSTORE *store, void *context,
+ void *toReplace, const void **ppStoreContext);
+
+typedef BOOL (*DeleteFunc)(struct WINE_CRYPTCERTSTORE *store, void *context);
+
+typedef struct _CONTEXT_FUNCS
+{
+    AddFunc    addContext;
+    EnumFunc   enumContext;
+    DeleteFunc deleteContext;
+} CONTEXT_FUNCS, *PCONTEXT_FUNCS;
+
+typedef enum _CertStoreType {
+    StoreTypeMem,
+    StoreTypeCollection,
+    StoreTypeProvider,
+} CertStoreType;
+
+struct _CONTEXT_PROPERTY_LIST;
+typedef struct _CONTEXT_PROPERTY_LIST *PCONTEXT_PROPERTY_LIST;
+
+#define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
+
+/* A cert store is polymorphic through the use of function pointers.  A type
+ * is still needed to distinguish collection stores from other types.
+ * On the function pointers:
+ * - closeStore is called when the store's ref count becomes 0
+ * - control is optional, but should be implemented by any store that supports
+ *   persistence
+ */
+typedef struct WINE_CRYPTCERTSTORE
+{
+    DWORD                       dwMagic;
+    LONG                        ref;
+    DWORD                       dwOpenFlags;
+    CertStoreType               type;
+    PFN_CERT_STORE_PROV_CLOSE   closeStore;
+    CONTEXT_FUNCS               certs;
+    CONTEXT_FUNCS               crls;
+    PFN_CERT_STORE_PROV_CONTROL control; /* optional */
+    PCONTEXT_PROPERTY_LIST      properties;
+} WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE;
+
+void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, DWORD dwFlags,
+ CertStoreType type);
+void CRYPT_FreeStore(PWINECRYPT_CERTSTORE store);
+BOOL WINAPI I_CertUpdateStore(HCERTSTORE store1, HCERTSTORE store2, DWORD unk0,
+ DWORD unk1);
+
+PWINECRYPT_CERTSTORE CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
+ DWORD dwFlags, const void *pvPara);
+PWINECRYPT_CERTSTORE CRYPT_ProvCreateStore(DWORD dwFlags,
+ PWINECRYPT_CERTSTORE memStore, const CERT_STORE_PROV_INFO *pProvInfo);
+PWINECRYPT_CERTSTORE CRYPT_ProvOpenStore(LPCSTR lpszStoreProvider,
+ DWORD dwEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
+ const void *pvPara);
+PWINECRYPT_CERTSTORE CRYPT_RegOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags,
+ const void *pvPara);
+PWINECRYPT_CERTSTORE CRYPT_FileOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags,
+ const void *pvPara);
+PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv,
+ DWORD dwFlags, const void *pvPara);
+PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv,
+ DWORD dwFlags, const void *pvPara);
+PWINECRYPT_CERTSTORE CRYPT_RootOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags);
+
+/* Allocates and initializes a certificate chain engine, but without creating
+ * the root store.  Instead, it uses root, and assumes the caller has done any
+ * checking necessary.
+ */
+HCERTCHAINENGINE CRYPT_CreateChainEngine(HCERTSTORE root,
+ PCERT_CHAIN_ENGINE_CONFIG pConfig);
+
 /* Helper function for store reading functions and
  * CertAddSerializedElementToStore.  Returns a context of the appropriate type
  * if it can, or NULL otherwise.  Doesn't validate any of the properties in
@@ -104,15 +270,12 @@ extern PCWINE_CONTEXT_INTERFACE pCTLInterface;
 const void *CRYPT_ReadSerializedElement(const BYTE *pbElement,
  DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
 
-/* Writes contexts from the memory store to the file. */
-BOOL CRYPT_WriteSerializedFile(HANDLE file, HCERTSTORE store);
-
 /* Reads contexts serialized in the file into the memory store.  Returns FALSE
  * if the file is not of the expected format.
  */
-BOOL CRYPT_ReadSerializedFile(HANDLE file, HCERTSTORE store);
+BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store);
 
-/* Fixes up the the pointers in info, where info is assumed to be a
+/* Fixes up the pointers in info, where info is assumed to be a
  * CRYPT_KEY_PROV_INFO, followed by its container name, provider name, and any
  * provider parameters, in a contiguous buffer, but where info's pointers are
  * assumed to be invalid.  Upon return, info's pointers point to the
@@ -120,8 +283,6 @@ BOOL CRYPT_ReadSerializedFile(HANDLE file, HCERTSTORE store);
  */
 void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info);
 
-DWORD CertStore_GetAccessState(HCERTSTORE hCertStore);
-
 /**
  *  Context functions
  */
@@ -153,13 +314,10 @@ void *Context_GetLinkedContext(void *context, size_t contextSize);
 void Context_CopyProperties(const void *to, const void *from,
  size_t contextSize);
 
-struct _CONTEXT_PROPERTY_LIST;
-typedef struct _CONTEXT_PROPERTY_LIST *PCONTEXT_PROPERTY_LIST;
-
 /* Returns context's properties, or the linked context's properties if context
  * is a link context.
  */
-PCONTEXT_PROPERTY_LIST Context_GetProperties(void *context, size_t contextSize);
+PCONTEXT_PROPERTY_LIST Context_GetProperties(const void *context, size_t contextSize);
 
 void Context_AddRef(void *context, size_t contextSize);
 
index a392a86..0269692 100644 (file)
@@ -1,24 +1,19 @@
-Index: crypt32.rc\r
-===================================================================\r
---- crypt32.rc (revision 22838)\r
-+++ crypt32.rc (working copy)
-@@ -17,12 +17,18 @@\r
-  * License along with this library; if not, write to the Free Software
-  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
-  */
-+
-+#define REACTOS_VERSION_DLL
-+#define REACTOS_STR_FILE_DESCRIPTION  "CryptoAPI Library\0"
-+#define REACTOS_STR_INTERNAL_NAME     "crypt32\0"
-+#define REACTOS_STR_ORIGINAL_FILENAME "crypt32.dll\0"
-+
- #include "windef.h"
- #include "winbase.h"
- #include "winuser.h"
- #include "cryptres.h"
+--- D:/Wine-CVS/wine/dlls/crypt32/rootstore.c  Sat Feb 16 22:49:56 2008
++++ D:/ReactOS-Trunk/reactos/dll/win32/crypt32/rootstore.c     Sat May 10 20:30:25 2008
+@@ -317,7 +317,7 @@
+     DIR *dir;
  
--#include "version.rc"
-+#include <reactos/version.rc>
+     TRACE("(%s, %p)\n", debugstr_a(path), store);
+-
++    /* UNIX functions = bad for reactos
+     dir = opendir(path);
+     if (dir)
+     {
+@@ -340,6 +340,7 @@
+             CryptMemFree(filebuf);
+         }
+     }
++    */
+     return ret;
+ }
  
- #include "crypt32_De.rc"
- #include "crypt32_En.rc"
index 1f0a95e..32c8169 100644 (file)
 #define IDS_LIFETIME_SIGNING 1139
 #define IDS_ANY_CERT_POLICY 1140
 
+#define IDS_LOCALIZEDNAME_ROOT 1141
+#define IDS_LOCALIZEDNAME_MY 1142
+#define IDS_LOCALIZEDNAME_CA 1143
+#define IDS_LOCALIZEDNAME_ADDRESSBOOK 1144
+
 #endif /* ndef __WINE_CRYPTRES_H__ */
index e6ca94c..47b0ba6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005 Juan Lang
+ * Copyright 2005-2007 Juan Lang
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -17,8 +17,8 @@
  *
  * This file implements ASN.1 DER decoding of a limited set of types.
  * It isn't a full ASN.1 implementation.  Microsoft implements BER
- * encoding of many of the basic types in msasn1.dll, but that interface is
- * undocumented, so I implement them here.
+ * encoding of many of the basic types in msasn1.dll, but that interface isn't
+ * implemented, so I implement them here.
  *
  * References:
  * "A Layman's Guide to a Subset of ASN.1, BER, and DER", by Burton Kaliski
  *
  * RFC3280, http://www.faqs.org/rfcs/rfc3280.html
  *
- * MSDN, especially:
- * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp
+ * MSDN, especially "Constants for CryptEncodeObject and CryptDecodeObject"
  */
 
+#include "config.h"
+#include "wine/port.h"
+
 #include <assert.h>
 #include <stdarg.h>
 #include <stdio.h>
 
 #include "windef.h"
 #include "winbase.h"
-#include "excpt.h"
 #include "wincrypt.h"
 #include "winnls.h"
-#include "winreg.h"
 #include "snmp.h"
 #include "wine/debug.h"
 #include "wine/exception.h"
@@ -55,7 +55,8 @@
 #define ASN_FLAGS_MASK 0xe0
 #define ASN_TYPE_MASK  0x1f
 
-WINE_DEFAULT_DEBUG_CHANNEL(crypt);
+WINE_DEFAULT_DEBUG_CHANNEL(cryptasn);
+WINE_DECLARE_DEBUG_CHANNEL(crypt);
 
 struct GenericArray
 {
@@ -68,111 +69,60 @@ typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
  DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
 
-/* Prototypes for built-in decoders.  They follow the Ex style prototypes.
- * The dwCertEncodingType and lpszStructType are ignored by the built-in
- * functions, but the parameters are retained to simplify CryptDecodeObjectEx,
- * since it must call functions in external DLLs that follow these signatures.
+/* Internal decoders don't do memory allocation or exception handling, and
+ * they report how many bytes they decoded.
  */
-static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
-static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
+typedef BOOL (*InternalDecodeFunc)(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded);
+
+static BOOL CRYPT_AsnDecodeChoiceOfTimeInternal(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded);
+static BOOL CRYPT_AsnDecodePubKeyInfoInternal(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded);
 /* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of
  * time, doesn't do memory allocation, and doesn't do exception handling.
- * (This isn't intended to be the externally-called one.)
  */
-static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
-/* 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);
+static BOOL CRYPT_AsnDecodeExtensionsInternal(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded);
+/* Assumes algo->Parameters.pbData is set ahead of time. */
+static BOOL CRYPT_AsnDecodeAlgorithmId(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded);
+static BOOL CRYPT_AsnDecodeBool(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded);
 /* Assumes the CRYPT_DATA_BLOB's pbData member has been initialized */
-static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
-/* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData
- * member has been initialized, doesn't do exception handling, and doesn't do
- * memory allocation.
- */
-static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
-static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
-static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
+static BOOL CRYPT_AsnDecodeOctetsInternal(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded);
+static BOOL CRYPT_AsnDecodeBitsInternal(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded);
+static BOOL CRYPT_AsnDecodeIntInternal(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded);
 /* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData
  * member has been initialized, doesn't do exception handling, and doesn't do
  * memory allocation.  Also doesn't check tag, assumes the caller has checked
  * it.
  */
-static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
+static BOOL CRYPT_AsnDecodeIntegerInternal(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded);
 /* Like CRYPT_AsnDecodeInteger, but unsigned.  */
-static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
- DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
- DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
- void *pvStructInfo, DWORD *pcbStructInfo);
-
-BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
- const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
- DWORD *pcbStructInfo)
-{
-    static HCRYPTOIDFUNCSET set = NULL;
-    BOOL ret = FALSE;
-    CryptDecodeObjectFunc pCryptDecodeObject;
-    HCRYPTOIDFUNCADDR hFunc;
-
-    TRACE("(0x%08x, %s, %p, %d, 0x%08x, %p, %p)\n", dwCertEncodingType,
-     debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags,
-     pvStructInfo, pcbStructInfo);
-
-    if (!pvStructInfo && !pcbStructInfo)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-
-    /* Try registered DLL first.. */
-    if (!set)
-        set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_FUNC, 0);
-    CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
-     (void **)&pCryptDecodeObject, &hFunc);
-    if (pCryptDecodeObject)
-    {
-        ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
-         pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
-        CryptFreeOIDFunctionAddress(hFunc, 0);
-    }
-    else
-    {
-        /* If not, use CryptDecodeObjectEx */
-        ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
-         cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
-    }
-    return ret;
-}
+static BOOL CRYPT_AsnDecodeUnsignedIntegerInternal(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded);
 
 /* Gets the number of length bytes from the given (leading) length byte */
-#define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
+#define GET_LEN_BYTES(b) ((b) <= 0x80 ? 1 : 1 + ((b) & 0x7f))
 
 /* Helper function to get the encoded length of the data starting at pbEncoded,
  * where pbEncoded[0] is the tag.  If the data are too short to contain a
  * length or if the length is too large for cbEncoded, sets an appropriate
- * error code and returns FALSE.
+ * error code and returns FALSE.  If the encoded length is unknown due to
+ * indefinite length encoding, *len is set to CMSG_INDEFINITE_LENGTH.
  */
-static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
+static BOOL CRYPT_GetLengthIndefinite(const BYTE *pbEncoded, DWORD cbEncoded,
  DWORD *len)
 {
     BOOL ret;
@@ -195,6 +145,11 @@ static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
             ret = TRUE;
         }
     }
+    else if (pbEncoded[1] == 0x80)
+    {
+        *len = CMSG_INDEFINITE_LENGTH;
+        ret = TRUE;
+    }
     else
     {
         BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
@@ -234,6 +189,20 @@ static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
     return ret;
 }
 
+/* Like CRYPT_GetLengthIndefinite, but disallows indefinite-length encoding. */
+static BOOL CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded, DWORD *len)
+{
+    BOOL ret;
+
+    if ((ret = CRYPT_GetLengthIndefinite(pbEncoded, cbEncoded, len)) &&
+     *len == CMSG_INDEFINITE_LENGTH)
+    {
+        SetLastError(CRYPT_E_ASN1_CORRUPT);
+        ret = FALSE;
+    }
+    return ret;
+}
+
 /* Helper function to check *pcbStructInfo, set it to the required size, and
  * optionally to allocate memory.  Assumes pvStructInfo is not NULL.
  * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
@@ -265,6 +234,35 @@ static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
     return ret;
 }
 
+static void CRYPT_FreeSpace(PCRYPT_DECODE_PARA pDecodePara, LPVOID pv)
+{
+    if (pDecodePara && pDecodePara->pfnFree)
+        pDecodePara->pfnFree(pv);
+    else
+        LocalFree(pv);
+}
+
+/* Helper function to check *pcbStructInfo and set it to the required size.
+ * Assumes pvStructInfo is not NULL.
+ */
+static BOOL CRYPT_DecodeCheckSpace(DWORD *pcbStructInfo, DWORD bytesNeeded)
+{
+    BOOL ret;
+
+    if (*pcbStructInfo < bytesNeeded)
+    {
+        *pcbStructInfo = bytesNeeded;
+        SetLastError(ERROR_MORE_DATA);
+        ret = FALSE;
+    }
+    else
+    {
+        *pcbStructInfo = bytesNeeded;
+        ret = TRUE;
+    }
+    return ret;
+}
+
 /* tag:
  *     The expected tag of the item.  If tag is 0, decodeFunc is called
  *     regardless of the tag value seen.
@@ -280,47 +278,62 @@ static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
  *     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:
+ * hasPointer, pointerOffset:
  *     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
+ *     the offset within the struct of the data pointer (or to the
  *     first data pointer, if more than one exist).
  * size:
  *     Used by CRYPT_AsnDecodeSequence, not for your use.
  */
 struct AsnDecodeSequenceItem
 {
-    BYTE                    tag;
-    DWORD                   offset;
-    CryptDecodeObjectExFunc decodeFunc;
-    DWORD                   minSize;
-    BOOL                    optional;
-    BOOL                    hasPointer;
-    DWORD                   pointerOffset;
-    DWORD                   size;
+    BYTE               tag;
+    DWORD              offset;
+    InternalDecodeFunc decodeFunc;
+    DWORD              minSize;
+    BOOL               optional;
+    BOOL               hasPointer;
+    DWORD              pointerOffset;
+    DWORD              size;
 };
 
-static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
- struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
- DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData)
+/* Decodes the items in a sequence, where the items are described in items,
+ * the encoded data are in pbEncoded with length cbEncoded.  Decodes into
+ * pvStructInfo.  nextData is a pointer to the memory location at which the
+ * first decoded item with a dynamic pointer should point.
+ * Upon decoding, *cbDecoded is the total number of bytes decoded.
+ * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set.
+ */
+static BOOL CRYPT_AsnDecodeSequenceItems(struct AsnDecodeSequenceItem items[],
+ DWORD cItem, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ void *pvStructInfo, BYTE *nextData, DWORD *cbDecoded)
 {
     BOOL ret;
-    DWORD i;
-    const BYTE *ptr;
+    DWORD i, decoded = 0;
+    const BYTE *ptr = pbEncoded;
+
+    TRACE("%p, %d, %p, %d, %08x, %p, %p, %p\n", items, cItem, pbEncoded,
+     cbEncoded, dwFlags, pvStructInfo, nextData, cbDecoded);
 
-    ptr = pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]);
     for (i = 0, ret = TRUE; ret && i < cItem; i++)
     {
         if (cbEncoded - (ptr - pbEncoded) != 0)
         {
-            DWORD nextItemLen;
+            DWORD itemLen;
 
-            if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
-             &nextItemLen)))
+            if ((ret = CRYPT_GetLengthIndefinite(ptr,
+             cbEncoded - (ptr - pbEncoded), &itemLen)))
             {
-                BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
+                BYTE itemLenBytes = GET_LEN_BYTES(ptr[1]);
 
                 if (ptr[0] == items[i].tag || !items[i].tag)
                 {
+                    DWORD itemEncodedLen;
+
+                    if (itemLen == CMSG_INDEFINITE_LENGTH)
+                        itemEncodedLen = cbEncoded - (ptr - pbEncoded);
+                    else
+                        itemEncodedLen = 1 + itemLenBytes + itemLen;
                     if (nextData && pvStructInfo && items[i].hasPointer)
                     {
                         TRACE("Setting next pointer to %p\n",
@@ -330,31 +343,56 @@ static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
                     }
                     if (items[i].decodeFunc)
                     {
+                        DWORD itemDecoded;
+
                         if (pvStructInfo)
                             TRACE("decoding item %d\n", i);
                         else
                             TRACE("sizing item %d\n", i);
-                        ret = items[i].decodeFunc(dwCertEncodingType,
-                         NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
-                         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
+                        ret = items[i].decodeFunc(ptr, itemEncodedLen,
+                         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
                          pvStructInfo ?  (BYTE *)pvStructInfo + items[i].offset
-                         : NULL, &items[i].size);
+                         : NULL, &items[i].size, &itemDecoded);
                         if (ret)
                         {
+                            /* Account for alignment padding */
+                            if (items[i].size % sizeof(DWORD_PTR))
+                                items[i].size += sizeof(DWORD_PTR) -
+                                 items[i].size % sizeof(DWORD_PTR);
+                            TRACE("item %d size: %d\n", i, items[i].size);
                             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);
+                            if (itemDecoded > itemEncodedLen)
+                            {
+                                WARN("decoded length %d exceeds encoded %d\n",
+                                 itemDecoded, itemEncodedLen);
+                                SetLastError(CRYPT_E_ASN1_CORRUPT);
+                                ret = FALSE;
+                            }
+                            else
+                            {
+                                if (itemLen == CMSG_INDEFINITE_LENGTH)
+                                {
+                                    if (itemDecoded > itemEncodedLen - 2 ||
+                                     *(ptr + itemDecoded) != 0 ||
+                                     *(ptr + itemDecoded + 1) != 0)
+                                    {
+                                        TRACE("expected 0 TLV\n");
+                                        SetLastError(CRYPT_E_ASN1_CORRUPT);
+                                        ret = FALSE;
+                                    }
+                                    else
+                                        itemDecoded += 2;
+                                }
+                                if (ret)
+                                {
+                                    ptr += itemDecoded;
+                                    decoded += itemDecoded;
+                                    TRACE("item %d: decoded %d bytes\n", i,
+                                     itemDecoded);
+                                }
                             }
-                            /* 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)
@@ -368,8 +406,19 @@ static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
                             TRACE("item %d failed: %08x\n", i,
                              GetLastError());
                     }
+                    else if (itemLen == CMSG_INDEFINITE_LENGTH)
+                    {
+                        ERR("can't use indefinite length encoding without a decoder\n");
+                        SetLastError(CRYPT_E_ASN1_CORRUPT);
+                        ret = FALSE;
+                    }
                     else
+                    {
+                        TRACE("item %d: decoded %d bytes\n", i, itemEncodedLen);
+                        ptr += itemEncodedLen;
+                        decoded += itemEncodedLen;
                         items[i].size = items[i].minSize;
+                    }
                 }
                 else if (items[i].optional)
                 {
@@ -378,8 +427,8 @@ static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
                 }
                 else
                 {
-                    TRACE("tag %02x doesn't match expected %02x\n",
-                     ptr[0], items[i].tag);
+                    TRACE("item %d: tag %02x doesn't match expected %02x\n",
+                     i, ptr[0], items[i].tag);
                     SetLastError(CRYPT_E_ASN1_BADTAG);
                     ret = FALSE;
                 }
@@ -397,13 +446,9 @@ static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
             ret = FALSE;
         }
     }
-    if (cbEncoded - (ptr - pbEncoded) != 0)
-    {
-        TRACE("%d remaining bytes, failing\n", cbEncoded -
-         (ptr - pbEncoded));
-        SetLastError(CRYPT_E_ASN1_CORRUPT);
-        ret = FALSE;
-    }
+    if (cbDecoded)
+        *cbDecoded = decoded;
+    TRACE("returning %d\n", ret);
     return ret;
 }
 
@@ -413,13 +458,11 @@ static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
  * startingPointer is an optional pointer to the first place where dynamic
  * data will be stored.  If you know the starting offset, you may pass it
  * here.  Otherwise, pass NULL, and one will be inferred from the items.
- * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set.
- * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT.
  */
-static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
void *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer)
+static BOOL CRYPT_AsnDecodeSequence(struct AsnDecodeSequenceItem items[],
DWORD cItem, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded, void *startingPointer)
 {
     BOOL ret;
 
@@ -431,21 +474,66 @@ static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
     {
         DWORD dataLen;
 
-        if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+        if ((ret = CRYPT_GetLengthIndefinite(pbEncoded, cbEncoded, &dataLen)))
         {
-            DWORD i;
+            DWORD lenBytes = GET_LEN_BYTES(pbEncoded[1]), cbDecoded;
+            const BYTE *ptr = pbEncoded + 1 + lenBytes;
+            BOOL indefinite = FALSE;
 
-            ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, pbEncoded,
-             cbEncoded, dwFlags, NULL, NULL);
+            cbEncoded -= 1 + lenBytes;
+            if (dataLen == CMSG_INDEFINITE_LENGTH)
+            {
+                dataLen = cbEncoded;
+                indefinite = TRUE;
+            }
+            else if (cbEncoded < dataLen)
+            {
+                TRACE("dataLen %d exceeds cbEncoded %d, failing\n", dataLen,
+                 cbEncoded);
+                SetLastError(CRYPT_E_ASN1_CORRUPT);
+                ret = FALSE;
+            }
+            if (ret)
+            {
+                ret = CRYPT_AsnDecodeSequenceItems(items, cItem,
+                 ptr, dataLen, dwFlags, NULL, NULL, &cbDecoded);
+                if (ret && dataLen == CMSG_INDEFINITE_LENGTH)
+                {
+                    if (cbDecoded > cbEncoded - 2)
+                    {
+                        /* Not enough space for 0 TLV */
+                        SetLastError(CRYPT_E_ASN1_CORRUPT);
+                        ret = FALSE;
+                    }
+                    else if (*(ptr + cbDecoded) != 0 ||
+                     *(ptr + cbDecoded + 1) != 0)
+                    {
+                        TRACE("expected 0 TLV\n");
+                        SetLastError(CRYPT_E_ASN1_CORRUPT);
+                        ret = FALSE;
+                    }
+                    else
+                        cbDecoded += 2;
+                }
+            }
+            if (ret && !indefinite && cbDecoded != dataLen)
+            {
+                TRACE("expected %d decoded, got %d, failing\n", dataLen,
+                 cbDecoded);
+                SetLastError(CRYPT_E_ASN1_CORRUPT);
+                ret = FALSE;
+            }
             if (ret)
             {
-                DWORD bytesNeeded = 0, structSize = 0;
+                DWORD i, bytesNeeded = 0, structSize = 0;
 
                 for (i = 0; i < cItem; i++)
                 {
                     bytesNeeded += items[i].size;
                     structSize += items[i].minSize;
                 }
+                if (pcbDecoded)
+                    *pcbDecoded = 1 + lenBytes + cbDecoded;
                 if (!pvStructInfo)
                     *pcbStructInfo = bytesNeeded;
                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
@@ -460,8 +548,11 @@ static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
                     else
                         nextData = (BYTE *)pvStructInfo + structSize;
                     memset(pvStructInfo, 0, structSize);
-                    ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
-                     pbEncoded, cbEncoded, dwFlags, pvStructInfo, nextData);
+                    ret = CRYPT_AsnDecodeSequenceItems(items, cItem,
+                     ptr, dataLen, dwFlags, pvStructInfo, nextData,
+                     &cbDecoded);
+                    if (!ret && (dwFlags & CRYPT_DECODE_ALLOC_FLAG))
+                        CRYPT_FreeSpace(pDecodePara, pvStructInfo);
                 }
             }
         }
@@ -477,7 +568,8 @@ static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
 
 /* tag:
  *     The expected tag of the entire encoded array (usually a variant
- *     of ASN_SETOF or ASN_SEQUENCEOF.)
+ *     of ASN_SETOF or ASN_SEQUENCEOF.)  If tag is 0, decodeFunc is called
+ *     regardless of the tag seen.
  * decodeFunc:
  *     used to decode each item in the array
  * itemSize:
@@ -489,11 +581,11 @@ static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
  */
 struct AsnArrayDescriptor
 {
-    BYTE                    tag;
-    CryptDecodeObjectExFunc decodeFunc;
-    DWORD                   itemSize;
-    BOOL                    hasPointer;
-    DWORD                   pointerOffset;
+    BYTE               tag;
+    InternalDecodeFunc decodeFunc;
+    DWORD              itemSize;
+    BOOL               hasPointer;
+    DWORD              pointerOffset;
 };
 
 struct AsnArrayItemSize
@@ -509,7 +601,7 @@ struct AsnArrayItemSize
 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)
DWORD *pcbDecoded, void *startingPointer)
 {
     BOOL ret = TRUE;
 
@@ -517,73 +609,96 @@ static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc,
      cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
      startingPointer);
 
-    if (pbEncoded[0] == arrayDesc->tag)
+    if (!arrayDesc->tag || pbEncoded[0] == arrayDesc->tag)
     {
         DWORD dataLen;
 
-        if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+        if ((ret = CRYPT_GetLengthIndefinite(pbEncoded, cbEncoded, &dataLen)))
         {
-            DWORD bytesNeeded, cItems = 0;
+            DWORD bytesNeeded, cItems = 0, decoded;
             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;
 
+            decoded = 1 + lenBytes;
             bytesNeeded = sizeof(struct GenericArray);
             if (dataLen)
             {
                 const BYTE *ptr;
+                BOOL doneDecoding = FALSE;
 
-                for (ptr = pbEncoded + 1 + lenBytes; ret &&
-                 ptr - pbEncoded - 1 - lenBytes < dataLen; )
+                for (ptr = pbEncoded + 1 + lenBytes; ret && !doneDecoding; )
                 {
-                    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)
+                    if (dataLen == CMSG_INDEFINITE_LENGTH)
+                    {
+                        if (ptr[0] == 0)
+                        {
+                            doneDecoding = TRUE;
+                            if (ptr[1] != 0)
+                            {
+                                SetLastError(CRYPT_E_ASN1_CORRUPT);
+                                ret = FALSE;
+                            }
+                            else
+                                decoded += 2;
+                        }
+                    }
+                    else if (ptr - pbEncoded - 1 - lenBytes >= dataLen)
+                        doneDecoding = TRUE;
+                    if (!doneDecoding)
                     {
-                        DWORD nextLen;
+                        DWORD itemEncoded, itemDataLen, itemDecoded, size = 0;
 
-                        cItems++;
-                        if (itemSizes != &itemSize)
-                            itemSizes = CryptMemRealloc(itemSizes,
-                             cItems * sizeof(struct AsnArrayItemSize));
-                        else
+                        /* Each item decoded may not tolerate extraneous bytes,
+                         * so get the length of the next element if known.
+                         */
+                        if ((ret = CRYPT_GetLengthIndefinite(ptr,
+                         cbEncoded - (ptr - pbEncoded), &itemDataLen)))
                         {
-                            itemSizes =
-                             CryptMemAlloc(
-                             cItems * sizeof(struct AsnArrayItemSize));
-                            if (itemSizes)
-                                memcpy(itemSizes, &itemSize, sizeof(itemSize));
+                            if (itemDataLen == CMSG_INDEFINITE_LENGTH)
+                                itemEncoded = cbEncoded - (ptr - pbEncoded);
+                            else
+                                itemEncoded = 1 + GET_LEN_BYTES(ptr[1]) +
+                                 itemDataLen;
                         }
-                        if (itemSizes)
+                        if (ret)
+                            ret = arrayDesc->decodeFunc(ptr, itemEncoded,
+                             dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &size,
+                             &itemDecoded);
+                        if (ret)
                         {
-                            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]);
+                            cItems++;
+                            if (itemSizes != &itemSize)
+                                itemSizes = CryptMemRealloc(itemSizes,
+                                 cItems * sizeof(struct AsnArrayItemSize));
+                            else if (cItems > 1)
+                            {
+                                itemSizes =
+                                 CryptMemAlloc(
+                                 cItems * sizeof(struct AsnArrayItemSize));
+                                if (itemSizes)
+                                    memcpy(itemSizes, &itemSize,
+                                     sizeof(itemSize));
+                            }
+                            if (itemSizes)
+                            {
+                                decoded += itemDecoded;
+                                itemSizes[cItems - 1].encodedLen = itemEncoded;
+                                itemSizes[cItems - 1].size = size;
+                                bytesNeeded += size;
+                                ptr += itemEncoded;
+                            }
+                            else
+                                ret = FALSE;
                         }
-                        else
-                            ret = FALSE;
                     }
                 }
             }
             if (ret)
             {
+                if (pcbDecoded)
+                    *pcbDecoded = decoded;
                 if (!pvStructInfo)
                     *pcbStructInfo = bytesNeeded;
                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
@@ -603,31 +718,30 @@ static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc,
                     else
                         array->rgItems = (BYTE *)array +
                          sizeof(struct GenericArray);
-                    nextData = (BYTE *)array->rgItems +
+                    nextData = array->rgItems +
                      array->cItems * arrayDesc->itemSize;
                     for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
                      i < cItems && ptr - pbEncoded - 1 - lenBytes <
                      dataLen; i++)
                     {
+                        DWORD itemDecoded;
+
                         if (arrayDesc->hasPointer)
                             *(BYTE **)(array->rgItems + i * arrayDesc->itemSize
                              + arrayDesc->pointerOffset) = nextData;
-                        ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr,
+                        ret = arrayDesc->decodeFunc(ptr,
                          itemSizes[i].encodedLen,
-                         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
+                         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
                          array->rgItems + i * arrayDesc->itemSize,
-                         &itemSizes[i].size);
+                         &itemSizes[i].size, &itemDecoded);
                         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]);
+                            ptr += itemDecoded;
                         }
                     }
+                    if (!ret && (dwFlags & CRYPT_DECODE_ALLOC_FLAG))
+                        CRYPT_FreeSpace(pDecodePara, pvStructInfo);
                 }
             }
             if (itemSizes != &itemSize)
@@ -648,9 +762,8 @@ static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc,
  * 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)
+static BOOL CRYPT_AsnDecodeDerBlob(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
 {
     BOOL ret;
     DWORD dataLen;
@@ -659,14 +772,15 @@ static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
     {
         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
         DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
-
+       
         if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
             bytesNeeded += 1 + lenBytes + dataLen;
 
+        if (pcbDecoded)
+            *pcbDecoded = 1 + lenBytes + dataLen;
         if (!pvStructInfo)
             *pcbStructInfo = bytesNeeded;
-        else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
-         pvStructInfo, pcbStructInfo, bytesNeeded)))
+        else if ((ret = CRYPT_DecodeCheckSpace(pcbStructInfo, bytesNeeded)))
         {
             CRYPT_DER_BLOB *blob;
 
@@ -695,21 +809,21 @@ static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
 }
 
 /* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */
-static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeBitsSwapBytes(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
 {
     BOOL ret;
 
-    TRACE("(%p, %d, 0x%08x, %p, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, *pcbStructInfo);
+    TRACE("(%p, %d, 0x%08x, %p, %d, %p)\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
 
     /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in-
      * place.
      */
-    ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType,
-     pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pDecodePara,
-     pvStructInfo, pcbStructInfo);
+    ret = CRYPT_AsnDecodeBitsInternal(pbEncoded, cbEncoded,
+     dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pvStructInfo, pcbStructInfo,
+     pcbDecoded);
     if (ret && pvStructInfo)
     {
         CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
@@ -757,9 +871,9 @@ static BOOL WINAPI CRYPT_AsnDecodeCertSignedContent(DWORD dwCertEncodingType,
 
         if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
             items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal;
-        ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
-         sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
-         pDecodePara, pvStructInfo, pcbStructInfo, NULL);
+        ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+         pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
+         pcbStructInfo, NULL, NULL);
     }
     __EXCEPT_PAGE_FAULT
     {
@@ -772,10 +886,8 @@ static BOOL WINAPI CRYPT_AsnDecodeCertSignedContent(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)
+static BOOL CRYPT_AsnDecodeCertVersion(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
 {
     BOOL ret;
     DWORD dataLen;
@@ -784,36 +896,35 @@ static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType,
     {
         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
 
-        ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
-         pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
-         pvStructInfo, pcbStructInfo);
+        ret = CRYPT_AsnDecodeIntInternal(pbEncoded + 1 + lenBytes, dataLen,
+         dwFlags, pvStructInfo, pcbStructInfo, NULL);
+        if (pcbDecoded)
+            *pcbDecoded = 1 + lenBytes + dataLen;
     }
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeValidity(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
 {
     BOOL ret;
 
     struct AsnDecodeSequenceItem items[] = {
      { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
-       CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
+       CRYPT_AsnDecodeChoiceOfTimeInternal, sizeof(FILETIME), FALSE, FALSE, 0 },
      { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
-       CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
+       CRYPT_AsnDecodeChoiceOfTimeInternal, sizeof(FILETIME), FALSE, FALSE, 0 },
     };
 
-    ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
-     sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, pcbStructInfo, NULL);
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo,
+     pcbDecoded, NULL);
     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)
+static BOOL CRYPT_AsnDecodeCertExtensions(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
 {
     BOOL ret;
     DWORD dataLen;
@@ -822,9 +933,10 @@ static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType,
     {
         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
 
-        ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
-         X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
-         pDecodePara, pvStructInfo, pcbStructInfo);
+        ret = CRYPT_AsnDecodeExtensionsInternal(pbEncoded + 1 + lenBytes,
+         dataLen, dwFlags, pvStructInfo, pcbStructInfo, NULL);
+        if (ret && pcbDecoded)
+            *pcbDecoded = 1 + lenBytes + dataLen;
     }
     return ret;
 }
@@ -870,9 +982,27 @@ static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
     TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
      pDecodePara, pvStructInfo, *pcbStructInfo);
 
-    ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
-     sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, pcbStructInfo, NULL);
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo,
+     NULL, NULL);
+    if (ret && pvStructInfo)
+    {
+        CERT_INFO *info;
+
+        if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
+            info = *(CERT_INFO **)pvStructInfo;
+        else
+            info = (CERT_INFO *)pvStructInfo;
+        if (!info->SerialNumber.cbData || !info->Issuer.cbData ||
+         !info->Subject.cbData)
+        {
+            SetLastError(CRYPT_E_ASN1_CORRUPT);
+            /* Don't need to deallocate, because it should have failed on the
+             * first pass (and no memory was allocated.)
+             */
+            ret = FALSE;
+        }
+    }
 
     TRACE("Returning %d (%08x)\n", ret, GetLastError());
     return ret;
@@ -882,28 +1012,32 @@ static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
-    BOOL ret = TRUE;
+    BOOL ret = FALSE;
 
     TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
      pDecodePara, pvStructInfo, *pcbStructInfo);
 
     __TRY
     {
-        PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
         DWORD size = 0;
 
-        /* First try to decode it as a signed cert. */
-        ret = CRYPT_AsnDecodeCertSignedContent(dwCertEncodingType, X509_CERT,
-         pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
-         (BYTE *)&signedCert, &size);
-        if (ret)
+        /* Unless told not to, first try to decode it as a signed cert. */
+        if (!(dwFlags & CRYPT_DECODE_TO_BE_SIGNED_FLAG))
         {
-            size = 0;
-            ret = CRYPT_AsnDecodeCertInfo(dwCertEncodingType,
-             X509_CERT_TO_BE_SIGNED, signedCert->ToBeSigned.pbData,
-             signedCert->ToBeSigned.cbData, dwFlags, pDecodePara, pvStructInfo,
-             pcbStructInfo);
-            LocalFree(signedCert);
+            PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
+
+            ret = CRYPT_AsnDecodeCertSignedContent(dwCertEncodingType,
+             X509_CERT, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
+             (BYTE *)&signedCert, &size);
+            if (ret)
+            {
+                size = 0;
+                ret = CRYPT_AsnDecodeCertInfo(dwCertEncodingType,
+                 X509_CERT_TO_BE_SIGNED, signedCert->ToBeSigned.pbData,
+                 signedCert->ToBeSigned.cbData, dwFlags, pDecodePara,
+                 pvStructInfo, pcbStructInfo);
+                LocalFree(signedCert);
+            }
         }
         /* Failing that, try it as an unsigned cert */
         if (!ret)
@@ -917,7 +1051,6 @@ static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
     __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
-        ret = FALSE;
     }
     __ENDTRY
 
@@ -925,17 +1058,16 @@ static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeCRLEntry(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
 {
     BOOL ret;
     struct AsnDecodeSequenceItem items[] = {
      { 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 },
+     { 0, offsetof(CRL_ENTRY, RevocationDate),
+       CRYPT_AsnDecodeChoiceOfTimeInternal, sizeof(FILETIME), FALSE, FALSE, 0 },
      { ASN_SEQUENCEOF, offsetof(CRL_ENTRY, cExtension),
        CRYPT_AsnDecodeExtensionsInternal, sizeof(CERT_EXTENSIONS), TRUE, TRUE,
        offsetof(CRL_ENTRY, rgExtension), 0 },
@@ -945,18 +1077,23 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLEntry(DWORD dwCertEncodingType,
     TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags, entry,
      *pcbStructInfo);
 
-    ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
-     sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
-     NULL, entry, pcbStructInfo, entry ? entry->SerialNumber.pbData : NULL);
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, NULL, entry, pcbStructInfo, pcbDecoded,
+     entry ? entry->SerialNumber.pbData : NULL);
+    if (ret && entry && !entry->SerialNumber.cbData)
+    {
+        WARN("empty CRL entry serial number\n");
+        SetLastError(CRYPT_E_ASN1_CORRUPT);
+        ret = FALSE;
+    }
     return ret;
 }
 
 /* Warning: assumes pvStructInfo is a struct GenericArray whose rgItems has
  * been set prior to calling.
  */
-static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeCRLEntries(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
 {
     BOOL ret;
     struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
@@ -964,11 +1101,11 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType,
      offsetof(CRL_ENTRY, SerialNumber.pbData) };
     struct GenericArray *entries = (struct GenericArray *)pvStructInfo;
 
-    TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, *pcbStructInfo);
+    TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
 
     ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, pcbStructInfo,
+     NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
      entries ? entries->rgItems : NULL);
     TRACE("Returning %d (%08x)\n", ret, GetLastError());
     return ret;
@@ -980,16 +1117,16 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
 {
     struct AsnDecodeSequenceItem items[] = {
      { ASN_INTEGER, offsetof(CRL_INFO, dwVersion),
-       CRYPT_AsnDecodeInt, sizeof(DWORD), TRUE, FALSE, 0, 0 },
+       CRYPT_AsnDecodeIntInternal, 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) },
-     { 0, offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime,
+     { 0, offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTimeInternal,
        sizeof(FILETIME), FALSE, FALSE, 0 },
-     { 0, offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime,
+     { 0, offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTimeInternal,
        sizeof(FILETIME), TRUE, FALSE, 0 },
      { ASN_SEQUENCEOF, offsetof(CRL_INFO, cCRLEntry),
        CRYPT_AsnDecodeCRLEntries, sizeof(struct GenericArray), TRUE, TRUE,
@@ -1003,9 +1140,9 @@ static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
     TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
      pDecodePara, pvStructInfo, *pcbStructInfo);
 
-    ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
-     sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, pcbStructInfo, NULL);
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo,
+     NULL, NULL);
 
     TRACE("Returning %d (%08x)\n", ret, GetLastError());
     return ret;
@@ -1015,28 +1152,32 @@ static BOOL WINAPI CRYPT_AsnDecodeCRL(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
-    BOOL ret = TRUE;
+    BOOL ret = FALSE;
 
     TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
      pDecodePara, pvStructInfo, *pcbStructInfo);
 
     __TRY
     {
-        PCERT_SIGNED_CONTENT_INFO signedCrl = NULL;
         DWORD size = 0;
 
-        /* First try to decode it as a signed crl. */
-        ret = CRYPT_AsnDecodeCertSignedContent(dwCertEncodingType, X509_CERT,
-         pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
-         (BYTE *)&signedCrl, &size);
-        if (ret)
+        /* Unless told not to, first try to decode it as a signed crl. */
+        if (!(dwFlags & CRYPT_DECODE_TO_BE_SIGNED_FLAG))
         {
-            size = 0;
-            ret = CRYPT_AsnDecodeCRLInfo(dwCertEncodingType,
-             X509_CERT_CRL_TO_BE_SIGNED, signedCrl->ToBeSigned.pbData,
-             signedCrl->ToBeSigned.cbData, dwFlags, pDecodePara,
-             pvStructInfo, pcbStructInfo);
-            LocalFree(signedCrl);
+            PCERT_SIGNED_CONTENT_INFO signedCrl = NULL;
+
+            ret = CRYPT_AsnDecodeCertSignedContent(dwCertEncodingType,
+             X509_CERT, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
+             (BYTE *)&signedCrl, &size);
+            if (ret)
+            {
+                size = 0;
+                ret = CRYPT_AsnDecodeCRLInfo(dwCertEncodingType,
+                 X509_CERT_CRL_TO_BE_SIGNED, signedCrl->ToBeSigned.pbData,
+                 signedCrl->ToBeSigned.cbData, dwFlags, pDecodePara,
+                 pvStructInfo, pcbStructInfo);
+                LocalFree(signedCrl);
+            }
         }
         /* Failing that, try it as an unsigned crl */
         if (!ret)
@@ -1050,7 +1191,6 @@ static BOOL WINAPI CRYPT_AsnDecodeCRL(DWORD dwCertEncodingType,
     __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
-        ret = FALSE;
     }
     __ENDTRY
 
@@ -1058,42 +1198,87 @@ static BOOL WINAPI CRYPT_AsnDecodeCRL(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeOidInternal(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeOidIgnoreTag(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
 {
     BOOL ret = TRUE;
+    DWORD dataLen;
 
-    TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, *pcbStructInfo);
+    TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo);
 
-    if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
+    if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
     {
-        DWORD dataLen;
+        BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+        DWORD bytesNeeded = sizeof(LPSTR);
 
-        if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
+        if (dataLen)
         {
-            BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
-            DWORD bytesNeeded = sizeof(LPSTR);
+            /* The largest possible string for the first two components
+             * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
+             */
+            char firstTwo[6];
+            const BYTE *ptr;
+
+            snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
+             pbEncoded[1 + lenBytes] / 40,
+             pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
+             * 40);
+            bytesNeeded += strlen(firstTwo) + 1;
+            for (ptr = pbEncoded + 2 + lenBytes; ret &&
+             ptr - pbEncoded - 1 - lenBytes < dataLen; )
+            {
+                /* large enough for ".4000000" */
+                char str[9];
+                int val = 0;
 
+                while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
+                 (*ptr & 0x80))
+                {
+                    val <<= 7;
+                    val |= *ptr & 0x7f;
+                    ptr++;
+                }
+                if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
+                 (*ptr & 0x80))
+                {
+                    SetLastError(CRYPT_E_ASN1_CORRUPT);
+                    ret = FALSE;
+                }
+                else
+                {
+                    val <<= 7;
+                    val |= *ptr++;
+                    snprintf(str, sizeof(str), ".%d", val);
+                    bytesNeeded += strlen(str);
+                }
+            }
+        }
+        if (pcbDecoded)
+            *pcbDecoded = 1 + lenBytes + dataLen;
+        if (!pvStructInfo)
+            *pcbStructInfo = bytesNeeded;
+        else if (*pcbStructInfo < bytesNeeded)
+        {
+            *pcbStructInfo = bytesNeeded;
+            SetLastError(ERROR_MORE_DATA);
+            ret = FALSE;
+        }
+        else
+        {
             if (dataLen)
             {
-                /* The largest possible string for the first two components
-                 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
-                 */
-                char firstTwo[6];
                 const BYTE *ptr;
+                LPSTR pszObjId = *(LPSTR *)pvStructInfo;
 
-                snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
-                 pbEncoded[1 + lenBytes] / 40,
-                 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
-                 * 40);
-                bytesNeeded += strlen(firstTwo) + 1;
+                *pszObjId = 0;
+                sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
+                 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
+                 40) * 40);
+                pszObjId += strlen(pszObjId);
                 for (ptr = pbEncoded + 2 + lenBytes; ret &&
                  ptr - pbEncoded - 1 - lenBytes < dataLen; )
                 {
-                    /* large enough for ".4000000" */
-                    char str[9];
                     int val = 0;
 
                     while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
@@ -1103,64 +1288,35 @@ static BOOL WINAPI CRYPT_AsnDecodeOidInternal(DWORD dwCertEncodingType,
                         val |= *ptr & 0x7f;
                         ptr++;
                     }
-                    if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
-                     (*ptr & 0x80))
-                    {
-                        SetLastError(CRYPT_E_ASN1_CORRUPT);
-                        ret = FALSE;
-                    }
-                    else
-                    {
-                        val <<= 7;
-                        val |= *ptr++;
-                        snprintf(str, sizeof(str), ".%d", val);
-                        bytesNeeded += strlen(str);
-                    }
+                    val <<= 7;
+                    val |= *ptr++;
+                    sprintf(pszObjId, ".%d", val);
+                    pszObjId += strlen(pszObjId);
                 }
             }
-            if (!pvStructInfo)
-                *pcbStructInfo = bytesNeeded;
-            else if (*pcbStructInfo < bytesNeeded)
-            {
-                *pcbStructInfo = bytesNeeded;
-                SetLastError(ERROR_MORE_DATA);
-                ret = FALSE;
-            }
             else
-            {
-                if (dataLen)
-                {
-                    const BYTE *ptr;
-                    LPSTR pszObjId = *(LPSTR *)pvStructInfo;
+                *(LPSTR *)pvStructInfo = NULL;
+            *pcbStructInfo = bytesNeeded;
+        }
+    }
+    return ret;
+}
 
-                    *pszObjId = 0;
-                    sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
-                     pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
-                     40) * 40);
-                    pszObjId += strlen(pszObjId);
-                    for (ptr = pbEncoded + 2 + lenBytes; ret &&
-                     ptr - pbEncoded - 1 - lenBytes < dataLen; )
-                    {
-                        int val = 0;
+static BOOL CRYPT_AsnDecodeOidInternal(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
+{
+    BOOL ret;
 
-                        while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
-                         (*ptr & 0x80))
-                        {
-                            val <<= 7;
-                            val |= *ptr & 0x7f;
-                            ptr++;
-                        }
-                        val <<= 7;
-                        val |= *ptr++;
-                        sprintf(pszObjId, ".%d", val);
-                        pszObjId += strlen(pszObjId);
-                    }
-                }
-                else
-                    *(LPSTR *)pvStructInfo = NULL;
-                *pcbStructInfo = bytesNeeded;
-            }
-        }
+    TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo);
+
+    if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
+        ret = CRYPT_AsnDecodeOidIgnoreTag(pbEncoded, cbEncoded, dwFlags,
+         pvStructInfo, pcbStructInfo, pcbDecoded);
+    else
+    {
+        SetLastError(CRYPT_E_ASN1_BADTAG);
+        ret = FALSE;
     }
     return ret;
 }
@@ -1168,13 +1324,12 @@ static BOOL WINAPI CRYPT_AsnDecodeOidInternal(DWORD dwCertEncodingType,
 /* 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)
+static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
 {
     struct AsnDecodeSequenceItem items[] = {
      { ASN_OBJECTIDENTIFIER, offsetof(CERT_EXTENSION, pszObjId),
-       CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE,
+       CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
        offsetof(CERT_EXTENSION, pszObjId), 0 },
      { ASN_BOOL, offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool,
        sizeof(BOOL), TRUE, FALSE, 0, 0 },
@@ -1190,9 +1345,9 @@ static BOOL WINAPI CRYPT_AsnDecodeExtension(DWORD dwCertEncodingType,
 
     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, pcbStructInfo, ext ? ext->pszObjId : NULL);
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, NULL, ext, pcbStructInfo,
+     pcbDecoded, ext ? ext->pszObjId : NULL);
     if (ext)
         TRACE("ext->pszObjId is %p (%s)\n", ext->pszObjId,
          debugstr_a(ext->pszObjId));
@@ -1200,9 +1355,9 @@ static BOOL WINAPI CRYPT_AsnDecodeExtension(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeExtensionsInternal(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
 {
     BOOL ret = TRUE;
     struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
@@ -1210,11 +1365,12 @@ static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
      offsetof(CERT_EXTENSION, pszObjId) };
     PCERT_EXTENSIONS exts = (PCERT_EXTENSIONS)pvStructInfo;
 
-    TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, *pcbStructInfo);
+    TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
 
     ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, pcbStructInfo, exts ? exts->rgExtension : NULL);
+     NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
+     exts ? exts->rgExtension : NULL);
     return ret;
 }
 
@@ -1226,9 +1382,8 @@ static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
 
     __TRY
     {
-        ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
-         lpszStructType, pbEncoded, cbEncoded,
-         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo);
+        ret = CRYPT_AsnDecodeExtensionsInternal(pbEncoded, cbEncoded,
+         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pcbStructInfo, NULL);
         if (ret && pvStructInfo)
         {
             ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
@@ -1242,10 +1397,9 @@ static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
                 exts = (CERT_EXTENSIONS *)pvStructInfo;
                 exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
                  sizeof(CERT_EXTENSIONS));
-                ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
-                 lpszStructType, pbEncoded, cbEncoded,
-                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
-                 pcbStructInfo);
+                ret = CRYPT_AsnDecodeExtensionsInternal(pbEncoded, cbEncoded,
+                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo,
+                 pcbStructInfo, NULL);
             }
         }
     }
@@ -1262,9 +1416,9 @@ static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
  * 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_AsnDecodeNameValueInternal(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeNameValueInternal(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
 {
     BOOL ret = TRUE;
     DWORD dataLen;
@@ -1340,6 +1494,8 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValueInternal(DWORD dwCertEncodingType,
             return FALSE;
         }
 
+        if (pcbDecoded)
+            *pcbDecoded = 1 + lenBytes + dataLen;
         if (!value)
             *pcbStructInfo = bytesNeeded;
         else if (*pcbStructInfo < bytesNeeded)
@@ -1394,7 +1550,7 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValueInternal(DWORD dwCertEncodingType,
                     LPWSTR str = (LPWSTR)value->Value.pbData;
 
                     value->Value.cbData = MultiByteToWideChar(CP_UTF8, 0,
-                     (LPCSTR)pbEncoded + 1 + lenBytes, dataLen,
+                     (LPCSTR)pbEncoded + 1 + lenBytes, dataLen, 
                      str, bytesNeeded - sizeof(CERT_NAME_VALUE)) * 2;
                     break;
                 }
@@ -1418,9 +1574,8 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
 
     __TRY
     {
-        ret = CRYPT_AsnDecodeNameValueInternal(dwCertEncodingType,
-         lpszStructType, pbEncoded, cbEncoded,
-         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo);
+        ret = CRYPT_AsnDecodeNameValueInternal(pbEncoded, cbEncoded,
+         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pcbStructInfo, NULL);
         if (ret && pvStructInfo)
         {
             ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
@@ -1433,10 +1588,9 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
                     pvStructInfo = *(BYTE **)pvStructInfo;
                 value = (CERT_NAME_VALUE *)pvStructInfo;
                 value->Value.pbData = ((BYTE *)value + sizeof(CERT_NAME_VALUE));
-                ret = CRYPT_AsnDecodeNameValueInternal(dwCertEncodingType,
-                 lpszStructType, pbEncoded, cbEncoded,
-                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
-                 pcbStructInfo);
+                ret = CRYPT_AsnDecodeNameValueInternal( pbEncoded, cbEncoded,
+                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo,
+                 pcbStructInfo, NULL);
             }
         }
     }
@@ -1449,10 +1603,9 @@ static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeUnicodeNameValueInternal(
- DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
- DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
- void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeUnicodeNameValueInternal(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
 {
     BOOL ret = TRUE;
     DWORD dataLen;
@@ -1515,6 +1668,8 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeNameValueInternal(
             return FALSE;
         }
 
+        if (pcbDecoded)
+            *pcbDecoded = 1 + lenBytes + dataLen;
         if (!value)
             *pcbStructInfo = bytesNeeded;
         else if (*pcbStructInfo < bytesNeeded)
@@ -1584,9 +1739,8 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeNameValue(DWORD dwCertEncodingType,
 
     __TRY
     {
-        ret = CRYPT_AsnDecodeUnicodeNameValueInternal(dwCertEncodingType,
-         lpszStructType, pbEncoded, cbEncoded,
-         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo);
+        ret = CRYPT_AsnDecodeUnicodeNameValueInternal(pbEncoded, cbEncoded,
+         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pcbStructInfo, NULL);
         if (ret && pvStructInfo)
         {
             ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
@@ -1599,10 +1753,9 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeNameValue(DWORD dwCertEncodingType,
                     pvStructInfo = *(BYTE **)pvStructInfo;
                 value = (CERT_NAME_VALUE *)pvStructInfo;
                 value->Value.pbData = ((BYTE *)value + sizeof(CERT_NAME_VALUE));
-                ret = CRYPT_AsnDecodeUnicodeNameValueInternal(
-                 dwCertEncodingType, lpszStructType, pbEncoded, cbEncoded,
-                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
-                 pcbStructInfo);
+                ret = CRYPT_AsnDecodeUnicodeNameValueInternal(pbEncoded,
+                 cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo,
+                 pcbStructInfo, NULL);
             }
         }
     }
@@ -1615,14 +1768,13 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeNameValue(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeRdnAttr(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
 {
     BOOL ret;
     struct AsnDecodeSequenceItem items[] = {
      { ASN_OBJECTIDENTIFIER, offsetof(CERT_RDN_ATTR, pszObjId),
-       CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE,
+       CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
        offsetof(CERT_RDN_ATTR, pszObjId), 0 },
      { 0, offsetof(CERT_RDN_ATTR, dwValueType),
        CRYPT_AsnDecodeNameValueInternal, sizeof(CERT_NAME_VALUE),
@@ -1635,9 +1787,9 @@ static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
 
     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);
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, NULL, attr, pcbStructInfo, pcbDecoded,
+     attr ? attr->pszObjId : NULL);
     if (attr)
     {
         TRACE("attr->pszObjId is %p (%s)\n", attr->pszObjId,
@@ -1648,9 +1800,8 @@ static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags,  void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
 {
     BOOL ret = TRUE;
     struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF,
@@ -1659,7 +1810,8 @@ static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
     PCERT_RDN rdn = (PCERT_RDN)pvStructInfo;
 
     ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, pcbStructInfo, rdn ? rdn->rgRDNAttr : NULL);
+     NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
+     rdn ? rdn->rgRDNAttr : NULL);
     return ret;
 }
 
@@ -1676,7 +1828,7 @@ static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
          offsetof(CERT_RDN, rgRDNAttr) };
 
         ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
-         pDecodePara, pvStructInfo, pcbStructInfo, NULL);
+         pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL);
     }
     __EXCEPT_PAGE_FAULT
     {
@@ -1687,14 +1839,14 @@ static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeUnicodeRdnAttr(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeUnicodeRdnAttr(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
 {
     BOOL ret;
     struct AsnDecodeSequenceItem items[] = {
      { ASN_OBJECTIDENTIFIER, offsetof(CERT_RDN_ATTR, pszObjId),
-       CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE,
+       CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
        offsetof(CERT_RDN_ATTR, pszObjId), 0 },
      { 0, offsetof(CERT_RDN_ATTR, dwValueType),
        CRYPT_AsnDecodeUnicodeNameValueInternal, sizeof(CERT_NAME_VALUE),
@@ -1707,9 +1859,9 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeRdnAttr(DWORD dwCertEncodingType,
 
     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);
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, NULL, attr, pcbStructInfo, pcbDecoded,
+     attr ? attr->pszObjId : NULL);
     if (attr)
     {
         TRACE("attr->pszObjId is %p (%s)\n", attr->pszObjId,
@@ -1720,9 +1872,8 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeRdnAttr(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeUnicodeRdn(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeUnicodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
 {
     BOOL ret = TRUE;
     struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF,
@@ -1731,7 +1882,8 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeRdn(DWORD dwCertEncodingType,
     PCERT_RDN rdn = (PCERT_RDN)pvStructInfo;
 
     ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, pcbStructInfo, rdn ? rdn->rgRDNAttr : NULL);
+     NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
+     rdn ? rdn->rgRDNAttr : NULL);
     return ret;
 }
 
@@ -1748,7 +1900,7 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeName(DWORD dwCertEncodingType,
          offsetof(CERT_RDN, rgRDNAttr) };
 
         ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
-         pDecodePara, pvStructInfo, pcbStructInfo, NULL);
+         pDecodePara, pvStructInfo, pcbStructInfo, NULL, NULL);
     }
     __EXCEPT_PAGE_FAULT
     {
@@ -1759,65 +1911,275 @@ static BOOL WINAPI CRYPT_AsnDecodeUnicodeName(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
+static BOOL CRYPT_FindEncodedLen(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD *pcbDecoded)
+{
+    BOOL ret = TRUE, done = FALSE;
+    DWORD indefiniteNestingLevels = 0, decoded = 0;
+
+    TRACE("(%p, %d)\n", pbEncoded, cbEncoded);
+
+    do {
+        DWORD dataLen;
+
+        if (!cbEncoded)
+            done = TRUE;
+        else if ((ret = CRYPT_GetLengthIndefinite(pbEncoded, cbEncoded,
+         &dataLen)))
+        {
+            BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+
+            if (dataLen == CMSG_INDEFINITE_LENGTH)
+            {
+                indefiniteNestingLevels++;
+                pbEncoded += 1 + lenBytes;
+                cbEncoded -= 1 + lenBytes;
+                decoded += 1 + lenBytes;
+                TRACE("indefiniteNestingLevels = %d\n",
+                 indefiniteNestingLevels);
+            }
+            else
+            {
+                if (pbEncoded[0] == 0 && pbEncoded[1] == 0 &&
+                 indefiniteNestingLevels)
+                {
+                    indefiniteNestingLevels--;
+                    TRACE("indefiniteNestingLevels = %d\n",
+                     indefiniteNestingLevels);
+                }
+                pbEncoded += 1 + lenBytes + dataLen;
+                cbEncoded -= 1 + lenBytes + dataLen;
+                decoded += 1 + lenBytes + dataLen;
+                if (!indefiniteNestingLevels)
+                    done = TRUE;
+            }
+        }
+    } while (ret && !done);
+    /* If we haven't found all 0 TLVs, we haven't found the end */
+    if (ret && indefiniteNestingLevels)
+    {
+        SetLastError(CRYPT_E_ASN1_EOD);
+        ret = FALSE;
+    }
+    if (ret)
+        *pcbDecoded = decoded;
+    TRACE("returning %d (%d)\n", ret, ret ? *pcbDecoded : 0);
+    return ret;
+}
+
+static BOOL CRYPT_AsnDecodeCopyBytes(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+    BOOL ret = TRUE;
+    DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB), encodedLen = 0;
+
+    TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo);
+
+    if ((ret = CRYPT_FindEncodedLen(pbEncoded, cbEncoded, &encodedLen)))
+    {
+        if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
+            bytesNeeded += encodedLen;
+        if (!pvStructInfo)
+            *pcbStructInfo = bytesNeeded;
+        else if (*pcbStructInfo < bytesNeeded)
+        {
+            SetLastError(ERROR_MORE_DATA);
+            *pcbStructInfo = bytesNeeded;
+            ret = FALSE;
+        }
+        else
+        {
+            PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
+
+            *pcbStructInfo = bytesNeeded;
+            blob->cbData = encodedLen;
+            if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
+                blob->pbData = (LPBYTE)pbEncoded;
+            else
+            {
+                assert(blob->pbData);
+                memcpy(blob->pbData, pbEncoded, blob->cbData);
+            }
+        }
+        if (pcbDecoded)
+            *pcbDecoded = encodedLen;
+    }
+    return ret;
+}
+
+static BOOL CRYPT_DecodeDERArray(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
+{
+    BOOL ret;
+    struct AsnArrayDescriptor arrayDesc = { 0, CRYPT_AsnDecodeCopyBytes,
+     sizeof(CRYPT_DER_BLOB), TRUE, offsetof(CRYPT_DER_BLOB, pbData) };
+    struct GenericArray *array = (struct GenericArray *)pvStructInfo;
+
+    TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
+
+    ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
+     NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
+     array ? array->rgItems : NULL);
+    return ret;
+}
+
+static BOOL CRYPT_AsnDecodePKCSAttributeInternal(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+    BOOL ret;
+    struct AsnDecodeSequenceItem items[] = {
+     { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ATTRIBUTE, pszObjId),
+       CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
+       offsetof(CRYPT_ATTRIBUTE, pszObjId), 0 },
+     { ASN_CONSTRUCTOR | ASN_SETOF, offsetof(CRYPT_ATTRIBUTE, cValue),
+       CRYPT_DecodeDERArray, sizeof(struct GenericArray), FALSE, TRUE,
+       offsetof(CRYPT_ATTRIBUTE, rgValue), 0 },
+    };
+    PCRYPT_ATTRIBUTE attr = (PCRYPT_ATTRIBUTE)pvStructInfo;
+
+    TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo);
+
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo,
+     pcbDecoded, attr ? attr->pszObjId : NULL);
+    TRACE("returning %d\n", ret);
+    return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnDecodePKCSAttribute(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
-    BOOL ret = TRUE;
-    DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
+    BOOL ret = FALSE;
 
     TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
      pDecodePara, pvStructInfo, *pcbStructInfo);
 
-    if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
-        bytesNeeded += cbEncoded;
-    if (!pvStructInfo)
-        *pcbStructInfo = bytesNeeded;
-    else if (*pcbStructInfo < bytesNeeded)
-    {
-        SetLastError(ERROR_MORE_DATA);
-        *pcbStructInfo = bytesNeeded;
-        ret = FALSE;
-    }
-    else
+    __TRY
     {
-        PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
+        DWORD bytesNeeded;
 
-        *pcbStructInfo = bytesNeeded;
-        blob->cbData = cbEncoded;
-        if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
-            blob->pbData = (LPBYTE)pbEncoded;
-        else
+        ret = CRYPT_AsnDecodePKCSAttributeInternal(pbEncoded, cbEncoded,
+         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL);
+        if (ret)
         {
-            assert(blob->pbData);
-            memcpy(blob->pbData, pbEncoded, blob->cbData);
+            if (!pvStructInfo)
+                *pcbStructInfo = bytesNeeded;
+            else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
+             pvStructInfo, pcbStructInfo, bytesNeeded)))
+            {
+                PCRYPT_ATTRIBUTE attr;
+
+                if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
+                    pvStructInfo = *(BYTE **)pvStructInfo;
+                attr = (PCRYPT_ATTRIBUTE)pvStructInfo;
+                attr->pszObjId = (LPSTR)((BYTE *)pvStructInfo +
+                 sizeof(CRYPT_ATTRIBUTE));
+                ret = CRYPT_AsnDecodePKCSAttributeInternal(pbEncoded, cbEncoded,
+                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo, &bytesNeeded,
+                 NULL);
+            }
         }
     }
+    __EXCEPT_PAGE_FAULT
+    {
+        SetLastError(STATUS_ACCESS_VIOLATION);
+    }
+    __ENDTRY
+    TRACE("returning %d\n", ret);
+    return ret;
+}
+
+static BOOL CRYPT_AsnDecodePKCSAttributesInternal(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+    struct AsnArrayDescriptor arrayDesc = { 0,
+     CRYPT_AsnDecodePKCSAttributeInternal, sizeof(CRYPT_ATTRIBUTE), TRUE,
+     offsetof(CRYPT_ATTRIBUTE, pszObjId) };
+    PCRYPT_ATTRIBUTES attrs = (PCRYPT_ATTRIBUTES)pvStructInfo;
+    BOOL ret;
+
+    ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
+     NULL, pvStructInfo, pcbStructInfo, pcbDecoded, attrs ? attrs->rgAttr :
+     NULL);
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
+static BOOL WINAPI CRYPT_AsnDecodePKCSAttributes(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+{
+    BOOL ret = FALSE;
+
+    TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
+     pDecodePara, pvStructInfo, *pcbStructInfo);
+
+    __TRY
+    {
+        DWORD bytesNeeded;
+
+        if (!cbEncoded)
+            SetLastError(CRYPT_E_ASN1_EOD);
+        else if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SETOF))
+            SetLastError(CRYPT_E_ASN1_CORRUPT);
+        else if ((ret = CRYPT_AsnDecodePKCSAttributesInternal(pbEncoded,
+         cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded,
+         NULL)))
+        {
+            if (!pvStructInfo)
+                *pcbStructInfo = bytesNeeded;
+            else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
+             pvStructInfo, pcbStructInfo, bytesNeeded)))
+            {
+                PCRYPT_ATTRIBUTES attrs;
+
+                if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
+                    pvStructInfo = *(BYTE **)pvStructInfo;
+                attrs = (PCRYPT_ATTRIBUTES)pvStructInfo;
+                attrs->rgAttr = (PCRYPT_ATTRIBUTE)((BYTE *)pvStructInfo +
+                 sizeof(CRYPT_ATTRIBUTES));
+                ret = CRYPT_AsnDecodePKCSAttributesInternal(pbEncoded,
+                 cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo,
+                 &bytesNeeded, NULL);
+            }
+        }
+    }
+    __EXCEPT_PAGE_FAULT
+    {
+        SetLastError(STATUS_ACCESS_VIOLATION);
+    }
+    __ENDTRY
+    TRACE("returning %d\n", ret);
+    return ret;
+}
+
+static BOOL CRYPT_AsnDecodeAlgorithmId(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
 {
     CRYPT_ALGORITHM_IDENTIFIER *algo =
      (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
     BOOL ret = TRUE;
     struct AsnDecodeSequenceItem items[] = {
      { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
-       CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE,
+       CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
        offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
      { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
-       CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
+       CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE, 
        offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
     };
 
-    TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, *pcbStructInfo);
+    TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
 
-    ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
-     sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo,
+     pcbDecoded, algo ? algo->pszObjId : NULL);
     if (ret && pvStructInfo)
     {
         TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
@@ -1826,9 +2188,9 @@ static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodePubKeyInfoInternal(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
 {
     BOOL ret = TRUE;
     struct AsnDecodeSequenceItem items[] = {
@@ -1842,10 +2204,9 @@ static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType,
     };
     PCERT_PUBLIC_KEY_INFO info = (PCERT_PUBLIC_KEY_INFO)pvStructInfo;
 
-    ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
-     sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, pcbStructInfo, info ?
-     info->Algorithm.Parameters.pbData : NULL);
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo,
+     pcbDecoded, info ? info->Algorithm.Parameters.pbData : NULL);
     return ret;
 }
 
@@ -1859,9 +2220,8 @@ static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
     {
         DWORD bytesNeeded;
 
-        if ((ret = CRYPT_AsnDecodePubKeyInfoInternal(dwCertEncodingType,
-         lpszStructType, pbEncoded, cbEncoded,
-         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
+        if ((ret = CRYPT_AsnDecodePubKeyInfoInternal(pbEncoded, cbEncoded,
+         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL)))
         {
             if (!pvStructInfo)
                 *pcbStructInfo = bytesNeeded;
@@ -1875,10 +2235,9 @@ static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
                 info = (PCERT_PUBLIC_KEY_INFO)pvStructInfo;
                 info->Algorithm.Parameters.pbData = (BYTE *)pvStructInfo +
                  sizeof(CERT_PUBLIC_KEY_INFO);
-                ret = CRYPT_AsnDecodePubKeyInfoInternal(dwCertEncodingType,
-                 lpszStructType, pbEncoded, cbEncoded,
-                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
-                 &bytesNeeded);
+                ret = CRYPT_AsnDecodePubKeyInfoInternal(pbEncoded, cbEncoded,
+                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo,
+                 &bytesNeeded, NULL);
             }
         }
     }
@@ -1891,9 +2250,8 @@ static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeBool(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
 {
     BOOL ret;
 
@@ -1912,6 +2270,8 @@ static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
         SetLastError(CRYPT_E_ASN1_CORRUPT);
         return FALSE;
     }
+    if (pcbDecoded)
+        *pcbDecoded = 3;
     if (!pvStructInfo)
     {
         *pcbStructInfo = sizeof(BOOL);
@@ -1932,27 +2292,21 @@ static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeAltNameEntry(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
 {
     PCERT_ALT_NAME_ENTRY entry = (PCERT_ALT_NAME_ENTRY)pvStructInfo;
     DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY);
     BOOL ret;
 
-    TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, *pcbStructInfo);
+    TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo);
 
     if (cbEncoded < 2)
     {
         SetLastError(CRYPT_E_ASN1_CORRUPT);
         return FALSE;
     }
-    if ((pbEncoded[0] & ASN_FLAGS_MASK) != ASN_CONTEXT)
-    {
-        SetLastError(CRYPT_E_ASN1_BADTAG);
-        return FALSE;
-    }
     lenBytes = GET_LEN_BYTES(pbEncoded[1]);
     if (1 + lenBytes > cbEncoded)
     {
@@ -1968,28 +2322,41 @@ static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType,
         case 6: /* uniformResourceIdentifier */
             bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
             break;
+        case 4: /* directoryName */
         case 7: /* iPAddress */
             bytesNeeded += dataLen;
             break;
         case 8: /* registeredID */
-            /* FIXME: decode as OID */
+            ret = CRYPT_AsnDecodeOidIgnoreTag(pbEncoded, cbEncoded, 0, NULL,
+             &dataLen, NULL);
+            if (ret)
+            {
+                /* FIXME: ugly, shouldn't need to know internals of OID decode
+                 * function to use it.
+                 */
+                bytesNeeded += dataLen - sizeof(LPSTR);
+            }
+            break;
         case 0: /* otherName */
-        case 4: /* directoryName */
-            FIXME("stub\n");
+            FIXME("%d: stub\n", pbEncoded[0] & ASN_TYPE_MASK);
             SetLastError(CRYPT_E_ASN1_BADTAG);
             ret = FALSE;
             break;
         case 3: /* x400Address, unimplemented */
         case 5: /* ediPartyName, unimplemented */
+            TRACE("type %d unimplemented\n", pbEncoded[0] & ASN_TYPE_MASK);
             SetLastError(CRYPT_E_ASN1_BADTAG);
             ret = FALSE;
             break;
         default:
+            TRACE("type %d bad\n", pbEncoded[0] & ASN_TYPE_MASK);
             SetLastError(CRYPT_E_ASN1_CORRUPT);
             ret = FALSE;
         }
         if (ret)
         {
+            if (pcbDecoded)
+                *pcbDecoded = 1 + lenBytes + dataLen;
             if (!entry)
                 *pcbStructInfo = bytesNeeded;
             else if (*pcbStructInfo < bytesNeeded)
@@ -2019,6 +2386,11 @@ static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType,
                      debugstr_w(entry->u.pwszURL));
                     break;
                 }
+                case 4: /* directoryName */
+                    entry->dwAltNameChoice = CERT_ALT_NAME_DIRECTORY_NAME;
+                    /* The data are memory-equivalent with the IPAddress case,
+                     * fall-through
+                     */
                 case 7: /* iPAddress */
                     /* The next data pointer is in the pwszURL spot, that is,
                      * the first 4 bytes.  Need to move it to the next spot.
@@ -2028,6 +2400,10 @@ static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType,
                     memcpy(entry->u.IPAddress.pbData, pbEncoded + 1 + lenBytes,
                      dataLen);
                     break;
+                case 8: /* registeredID */
+                    ret = CRYPT_AsnDecodeOidIgnoreTag(pbEncoded, cbEncoded, 0,
+                     &entry->u.pszRegisteredID, &dataLen, NULL);
+                    break;
                 }
             }
         }
@@ -2035,51 +2411,89 @@ static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeAltNameInternal(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeAltNameInternal(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
 {
     BOOL ret = TRUE;
-    struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
+    struct AsnArrayDescriptor arrayDesc = { 0,
      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;
 
-    TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, *pcbStructInfo);
+    TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
 
     if (info)
         TRACE("info->rgAltEntry is %p\n", info->rgAltEntry);
     ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, pcbStructInfo, info ? info->rgAltEntry : NULL);
+     NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
+     info ? info->rgAltEntry : NULL);
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeAuthorityKeyId(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+/* Like CRYPT_AsnDecodeIntegerInternal, but swaps the bytes */
+static BOOL CRYPT_AsnDecodeIntegerSwapBytes(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
 {
     BOOL ret;
 
-    __TRY
+    TRACE("(%p, %d, 0x%08x, %p, %d, %p)\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
+
+    /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in-
+     * place.
+     */
+    ret = CRYPT_AsnDecodeIntegerInternal(pbEncoded, cbEncoded,
+     dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pvStructInfo, pcbStructInfo,
+     pcbDecoded);
+    if (ret && pvStructInfo)
     {
-        struct AsnDecodeSequenceItem items[] = {
-         { ASN_CONTEXT | 0, offsetof(CERT_AUTHORITY_KEY_ID_INFO, KeyId),
-           CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_DATA_BLOB),
-           TRUE, TRUE, offsetof(CERT_AUTHORITY_KEY_ID_INFO, KeyId.pbData), 0 },
-         { ASN_CONTEXT | ASN_CONSTRUCTOR| 1,
-           offsetof(CERT_AUTHORITY_KEY_ID_INFO, CertIssuer),
-           CRYPT_AsnDecodeOctetsInternal, sizeof(CERT_NAME_BLOB), TRUE, TRUE,
-           offsetof(CERT_AUTHORITY_KEY_ID_INFO, CertIssuer.pbData), 0 },
+        CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)pvStructInfo;
+
+        if (blob->cbData)
+        {
+            DWORD i;
+            BYTE temp;
+
+            for (i = 0; i < blob->cbData / 2; i++)
+            {
+                temp = blob->pbData[i];
+                blob->pbData[i] = blob->pbData[blob->cbData - i - 1];
+                blob->pbData[blob->cbData - i - 1] = temp;
+            }
+        }
+    }
+    TRACE("returning %d (%08x)\n", ret, GetLastError());
+    return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnDecodeAuthorityKeyId(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+{
+    BOOL ret;
+
+    __TRY
+    {
+        struct AsnDecodeSequenceItem items[] = {
+         { ASN_CONTEXT | 0, offsetof(CERT_AUTHORITY_KEY_ID_INFO, KeyId),
+           CRYPT_AsnDecodeIntegerSwapBytes, sizeof(CRYPT_DATA_BLOB),
+           TRUE, TRUE, offsetof(CERT_AUTHORITY_KEY_ID_INFO, KeyId.pbData), 0 },
+         { ASN_CONTEXT | ASN_CONSTRUCTOR| 1,
+           offsetof(CERT_AUTHORITY_KEY_ID_INFO, CertIssuer),
+           CRYPT_AsnDecodeOctetsInternal, sizeof(CERT_NAME_BLOB), TRUE, TRUE,
+           offsetof(CERT_AUTHORITY_KEY_ID_INFO, CertIssuer.pbData), 0 },
          { ASN_CONTEXT | 2, offsetof(CERT_AUTHORITY_KEY_ID_INFO,
            CertSerialNumber), CRYPT_AsnDecodeIntegerInternal,
            sizeof(CRYPT_INTEGER_BLOB), TRUE, TRUE,
            offsetof(CERT_AUTHORITY_KEY_ID_INFO, CertSerialNumber.pbData), 0 },
         };
 
-        ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
-         sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
-         pDecodePara, pvStructInfo, pcbStructInfo, NULL);
+        ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+         pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
+         pcbStructInfo, NULL, NULL);
     }
     __EXCEPT_PAGE_FAULT
     {
@@ -2090,90 +2504,278 @@ static BOOL WINAPI CRYPT_AsnDecodeAuthorityKeyId(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType,
+static BOOL WINAPI CRYPT_AsnDecodeAuthorityKeyId2(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
-    BOOL ret = TRUE;
+    BOOL ret;
+
+    __TRY
+    {
+        struct AsnDecodeSequenceItem items[] = {
+         { ASN_CONTEXT | 0, offsetof(CERT_AUTHORITY_KEY_ID2_INFO, KeyId),
+           CRYPT_AsnDecodeIntegerSwapBytes, sizeof(CRYPT_DATA_BLOB),
+           TRUE, TRUE, offsetof(CERT_AUTHORITY_KEY_ID2_INFO, KeyId.pbData), 0 },
+         { ASN_CONTEXT | ASN_CONSTRUCTOR| 1,
+           offsetof(CERT_AUTHORITY_KEY_ID2_INFO, AuthorityCertIssuer),
+           CRYPT_AsnDecodeAltNameInternal, sizeof(CERT_ALT_NAME_INFO), TRUE,
+           TRUE, offsetof(CERT_AUTHORITY_KEY_ID2_INFO,
+           AuthorityCertIssuer.rgAltEntry), 0 },
+         { ASN_CONTEXT | 2, offsetof(CERT_AUTHORITY_KEY_ID2_INFO,
+           AuthorityCertSerialNumber), CRYPT_AsnDecodeIntegerInternal,
+           sizeof(CRYPT_INTEGER_BLOB), TRUE, TRUE,
+           offsetof(CERT_AUTHORITY_KEY_ID2_INFO,
+           AuthorityCertSerialNumber.pbData), 0 },
+        };
+
+        ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+         pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
+         pcbStructInfo, NULL, NULL);
+    }
+    __EXCEPT_PAGE_FAULT
+    {
+        SetLastError(STATUS_ACCESS_VIOLATION);
+        ret = FALSE;
+    }
+    __ENDTRY
+    return ret;
+}
+
+static BOOL CRYPT_AsnDecodePKCSContent(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
+{
+    BOOL ret;
+    DWORD dataLen;
+
+    TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
+
+    /* The caller has already checked the tag, no need to check it again.
+     * Check the outer length is valid:
+     */
+    if ((ret = CRYPT_GetLengthIndefinite(pbEncoded, cbEncoded, &dataLen)))
+    {
+        BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+        DWORD innerLen;
+
+        pbEncoded += 1 + lenBytes;
+        cbEncoded -= 1 + lenBytes;
+        if (dataLen == CMSG_INDEFINITE_LENGTH)
+            cbEncoded -= 2; /* space for 0 TLV */
+        /* Check the inner length is valid: */
+        if ((ret = CRYPT_GetLengthIndefinite(pbEncoded, cbEncoded, &innerLen)))
+        {
+            DWORD decodedLen;
+
+            ret = CRYPT_AsnDecodeCopyBytes(pbEncoded, cbEncoded, dwFlags,
+             pvStructInfo, pcbStructInfo, &decodedLen);
+            if (dataLen == CMSG_INDEFINITE_LENGTH)
+            {
+                if (*(pbEncoded + decodedLen) != 0 ||
+                 *(pbEncoded + decodedLen + 1) != 0)
+                {
+                    TRACE("expected 0 TLV, got {%02x,%02x}\n",
+                     *(pbEncoded + decodedLen),
+                     *(pbEncoded + decodedLen + 1));
+                    SetLastError(CRYPT_E_ASN1_CORRUPT);
+                    ret = FALSE;
+                }
+                else
+                    decodedLen += 2;
+            }
+            if (ret && pcbDecoded)
+            {
+                *pcbDecoded = 1 + lenBytes + decodedLen;
+                TRACE("decoded %d bytes\n", *pcbDecoded);
+            }
+        }
+    }
+    return ret;
+}
+
+static BOOL CRYPT_AsnDecodePKCSContentInfoInternal(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+    CRYPT_CONTENT_INFO *info = (CRYPT_CONTENT_INFO *)pvStructInfo;
+    struct AsnDecodeSequenceItem items[] = {
+     { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_CONTENT_INFO, pszObjId),
+       CRYPT_AsnDecodeOidIgnoreTag, sizeof(LPSTR), FALSE, TRUE,
+       offsetof(CRYPT_CONTENT_INFO, pszObjId), 0 },
+     { ASN_CONTEXT | ASN_CONSTRUCTOR | 0,
+       offsetof(CRYPT_CONTENT_INFO, Content), CRYPT_AsnDecodePKCSContent,
+       sizeof(CRYPT_DER_BLOB), TRUE, TRUE,
+       offsetof(CRYPT_CONTENT_INFO, Content.pbData), 0 },
+    };
+    BOOL ret;
+
+    TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
+
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo,
+     pcbDecoded, info ? info->pszObjId : NULL);
+    return ret;
+}
+
+static BOOL WINAPI CRYPT_AsnDecodePKCSContentInfo(DWORD dwCertEncodingType,
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+{
+    BOOL ret = FALSE;
 
     TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
      pDecodePara, pvStructInfo, *pcbStructInfo);
 
     __TRY
     {
-        struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
-         CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE,
-         offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) };
+        ret = CRYPT_AsnDecodePKCSContentInfoInternal(pbEncoded, cbEncoded,
+         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pcbStructInfo, NULL);
+        if (ret && pvStructInfo)
+        {
+            ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
+             pcbStructInfo, *pcbStructInfo);
+            if (ret)
+            {
+                CRYPT_CONTENT_INFO *info;
 
-        ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
-         pDecodePara, pvStructInfo, pcbStructInfo, NULL);
+                if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
+                    pvStructInfo = *(BYTE **)pvStructInfo;
+                info = (CRYPT_CONTENT_INFO *)pvStructInfo;
+                info->pszObjId = (LPSTR)((BYTE *)info +
+                 sizeof(CRYPT_CONTENT_INFO));
+                ret = CRYPT_AsnDecodePKCSContentInfoInternal(pbEncoded,
+                 cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo,
+                 pcbStructInfo, NULL);
+            }
+        }
     }
     __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
-        ret = FALSE;
     }
     __ENDTRY
     return ret;
 }
 
-struct PATH_LEN_CONSTRAINT
+BOOL CRYPT_AsnDecodePKCSDigestedData(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
+ CRYPT_DIGESTED_DATA *digestedData, DWORD *pcbDigestedData)
 {
-    BOOL  fPathLenConstraint;
-    DWORD dwPathLenConstraint;
-};
+    BOOL ret;
+    struct AsnDecodeSequenceItem items[] = {
+     { ASN_INTEGER, offsetof(CRYPT_DIGESTED_DATA, version),
+       CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE, 0, 0 },
+     { ASN_SEQUENCEOF, offsetof(CRYPT_DIGESTED_DATA, DigestAlgorithm),
+       CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
+       FALSE, TRUE, offsetof(CRYPT_DIGESTED_DATA, DigestAlgorithm.pszObjId),
+       0 },
+     { ASN_SEQUENCEOF, offsetof(CRYPT_DIGESTED_DATA, ContentInfo),
+       CRYPT_AsnDecodePKCSContentInfoInternal,
+       sizeof(CRYPT_CONTENT_INFO), FALSE, TRUE, offsetof(CRYPT_DIGESTED_DATA,
+       ContentInfo.pszObjId), 0 },
+     { ASN_OCTETSTRING, offsetof(CRYPT_DIGESTED_DATA, hash),
+       CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_HASH_BLOB), FALSE, TRUE,
+       offsetof(CRYPT_DIGESTED_DATA, hash.pbData), 0 },
+    };
 
-static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType,
+    ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+     pbEncoded, cbEncoded, dwFlags, pDecodePara, digestedData, pcbDigestedData,
+     NULL, NULL);
+    return ret;
+}
+
+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;
 
-    TRACE("%p, %d, %08x, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
-     pvStructInfo, *pcbStructInfo);
+    TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
+     pDecodePara, pvStructInfo, *pcbStructInfo);
 
-    if (cbEncoded)
+    __TRY
     {
-        if (pbEncoded[0] == ASN_INTEGER)
-        {
-            DWORD bytesNeeded = sizeof(struct PATH_LEN_CONSTRAINT);
+        DWORD bytesNeeded;
 
+        if ((ret = CRYPT_AsnDecodeAltNameInternal(pbEncoded, cbEncoded,
+         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL)))
+        {
             if (!pvStructInfo)
                 *pcbStructInfo = bytesNeeded;
-            else if (*pcbStructInfo < bytesNeeded)
-            {
-                SetLastError(ERROR_MORE_DATA);
-                *pcbStructInfo = bytesNeeded;
-                ret = FALSE;
-            }
-            else
+            else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
+             pvStructInfo, pcbStructInfo, bytesNeeded)))
             {
-                struct PATH_LEN_CONSTRAINT *constraint =
-                 (struct PATH_LEN_CONSTRAINT *)pvStructInfo;
-                DWORD size = sizeof(constraint->dwPathLenConstraint);
+                CERT_ALT_NAME_INFO *name;
 
-                ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
-                 pbEncoded, cbEncoded, 0, NULL,
-                 &constraint->dwPathLenConstraint, &size);
-                if (ret)
-                    constraint->fPathLenConstraint = TRUE;
-                TRACE("got an int, dwPathLenConstraint is %d\n",
-                 constraint->dwPathLenConstraint);
+                if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
+                    pvStructInfo = *(BYTE **)pvStructInfo;
+                name = (CERT_ALT_NAME_INFO *)pvStructInfo;
+                name->rgAltEntry = (PCERT_ALT_NAME_ENTRY)
+                 ((BYTE *)pvStructInfo + sizeof(CERT_ALT_NAME_INFO));
+                ret = CRYPT_AsnDecodeAltNameInternal(pbEncoded, cbEncoded,
+                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo,
+                 &bytesNeeded, NULL);
             }
         }
-        else
-        {
-            SetLastError(CRYPT_E_ASN1_CORRUPT);
-            ret = FALSE;
-        }
+    }
+    __EXCEPT_PAGE_FAULT
+    {
+        SetLastError(STATUS_ACCESS_VIOLATION);
+        ret = FALSE;
+    }
+    __ENDTRY
+    return ret;
+}
+
+struct PATH_LEN_CONSTRAINT
+{
+    BOOL  fPathLenConstraint;
+    DWORD dwPathLenConstraint;
+};
+
+static BOOL CRYPT_AsnDecodePathLenConstraint(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
+{
+    BOOL ret = TRUE;
+    DWORD bytesNeeded = sizeof(struct PATH_LEN_CONSTRAINT), size;
+
+    TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
+
+    if (!pvStructInfo)
+    {
+        ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded, dwFlags, NULL,
+         &size, pcbDecoded);
+        *pcbStructInfo = bytesNeeded;
+    }
+    else if (*pcbStructInfo < bytesNeeded)
+    {
+        SetLastError(ERROR_MORE_DATA);
+        *pcbStructInfo = bytesNeeded;
+        ret = FALSE;
+    }
+    else
+    {
+        struct PATH_LEN_CONSTRAINT *constraint =
+         (struct PATH_LEN_CONSTRAINT *)pvStructInfo;
+
+        size = sizeof(constraint->dwPathLenConstraint);
+        ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded, dwFlags,
+         &constraint->dwPathLenConstraint, &size, pcbDecoded);
+        if (ret)
+            constraint->fPathLenConstraint = TRUE;
+        TRACE("got an int, dwPathLenConstraint is %d\n",
+         constraint->dwPathLenConstraint);
     }
     TRACE("returning %d (%08x)\n", ret, GetLastError());
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeSubtreeConstraints(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeSubtreeConstraints(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
 {
     BOOL ret;
     struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
@@ -2181,11 +2783,11 @@ static BOOL WINAPI CRYPT_AsnDecodeSubtreeConstraints(DWORD dwCertEncodingType,
      offsetof(CERT_NAME_BLOB, pbData) };
     struct GenericArray *entries = (struct GenericArray *)pvStructInfo;
 
-    TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, *pcbStructInfo);
+    TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
 
     ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, pcbStructInfo,
+     NULL, pvStructInfo, pcbStructInfo, pcbDecoded,
      entries ? entries->rgItems : NULL);
     TRACE("Returning %d (%08x)\n", ret, GetLastError());
     return ret;
@@ -2201,7 +2803,7 @@ static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints(DWORD dwCertEncodingType,
     {
         struct AsnDecodeSequenceItem items[] = {
          { ASN_BITSTRING, offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType),
-           CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
+           CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE, 
            offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType.pbData), 0 },
          { ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS_INFO,
            fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint,
@@ -2212,9 +2814,9 @@ static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints(DWORD dwCertEncodingType,
            offsetof(CERT_BASIC_CONSTRAINTS_INFO, rgSubtreesConstraint), 0 },
         };
 
-        ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
-         sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
-         pDecodePara, pvStructInfo, pcbStructInfo, NULL);
+        ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+         pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
+         pcbStructInfo, NULL, NULL);
     }
     __EXCEPT_PAGE_FAULT
     {
@@ -2241,9 +2843,9 @@ static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
            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);
+        ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+         pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
+         pcbStructInfo, NULL, NULL);
     }
     __EXCEPT_PAGE_FAULT
     {
@@ -2276,14 +2878,14 @@ static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
            FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData),
            0 },
          { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, pubexp),
-           CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
+           CRYPT_AsnDecodeIntInternal, sizeof(DWORD), FALSE, FALSE, 0, 0 },
         };
         struct DECODED_RSA_PUB_KEY *decodedKey = NULL;
         DWORD size = 0;
 
-        ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
-         sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded,
-         CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, &size, NULL);
+        ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
+         pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey,
+         &size, NULL, NULL);
         if (ret)
         {
             DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
@@ -2328,22 +2930,26 @@ static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeOctetsInternal(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
 {
     BOOL ret;
     DWORD bytesNeeded, dataLen;
 
-    TRACE("%p, %d, %08x, %p, %p, %d\n", pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, *pcbStructInfo);
+    TRACE("%p, %d, %08x, %p, %d, %p\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
 
     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
     {
+        BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
+
         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
             bytesNeeded = sizeof(CRYPT_DATA_BLOB);
         else
             bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
+        if (pcbDecoded)
+            *pcbDecoded = 1 + lenBytes + dataLen;
         if (!pvStructInfo)
             *pcbStructInfo = bytesNeeded;
         else if (*pcbStructInfo < bytesNeeded)
@@ -2355,7 +2961,6 @@ static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
         else
         {
             CRYPT_DATA_BLOB *blob;
-            BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
 
             blob = (CRYPT_DATA_BLOB *)pvStructInfo;
             blob->cbData = dataLen;
@@ -2396,9 +3001,8 @@ static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
             SetLastError(CRYPT_E_ASN1_BADTAG);
             ret = FALSE;
         }
-        else if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
-         lpszStructType, pbEncoded, cbEncoded,
-         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
+        else if ((ret = CRYPT_AsnDecodeOctetsInternal(pbEncoded, cbEncoded,
+         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL)))
         {
             if (!pvStructInfo)
                 *pcbStructInfo = bytesNeeded;
@@ -2411,10 +3015,9 @@ static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
                     pvStructInfo = *(BYTE **)pvStructInfo;
                 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
                 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_DATA_BLOB);
-                ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
-                 lpszStructType, pbEncoded, cbEncoded,
-                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
-                 &bytesNeeded);
+                ret = CRYPT_AsnDecodeOctetsInternal(pbEncoded, cbEncoded,
+                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo,
+                 &bytesNeeded, NULL);
             }
         }
     }
@@ -2427,18 +3030,18 @@ static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
- PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeBitsInternal(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
 {
     BOOL ret;
 
-    TRACE("(%p, %d, 0x%08x, %p, %p, %d)\n", pbEncoded, cbEncoded, dwFlags,
-     pDecodePara, pvStructInfo, *pcbStructInfo);
+    TRACE("(%p, %d, 0x%08x, %p, %d, %p)\n", pbEncoded, cbEncoded, dwFlags,
+     pvStructInfo, *pcbStructInfo, pcbDecoded);
 
     if (pbEncoded[0] == ASN_BITSTRING)
     {
         DWORD bytesNeeded, dataLen;
+        BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
 
         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
         {
@@ -2446,6 +3049,8 @@ static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
                 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
             else
                 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
+            if (pcbDecoded)
+                *pcbDecoded = 1 + lenBytes + dataLen;
             if (!pvStructInfo)
                 *pcbStructInfo = bytesNeeded;
             else if (*pcbStructInfo < bytesNeeded)
@@ -2460,12 +3065,10 @@ static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
 
                 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
                 blob->cbData = dataLen - 1;
-                blob->cUnusedBits = *(pbEncoded + 1 +
-                 GET_LEN_BYTES(pbEncoded[1]));
+                blob->cUnusedBits = *(pbEncoded + 1 + lenBytes);
                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
                 {
-                    blob->pbData = (BYTE *)pbEncoded + 2 +
-                     GET_LEN_BYTES(pbEncoded[1]);
+                    blob->pbData = (BYTE *)pbEncoded + 2 + lenBytes;
                 }
                 else
                 {
@@ -2474,8 +3077,8 @@ static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
                     {
                         BYTE mask = 0xff << blob->cUnusedBits;
 
-                        memcpy(blob->pbData, pbEncoded + 2 +
-                         GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
+                        memcpy(blob->pbData, pbEncoded + 2 + lenBytes,
+                         blob->cbData);
                         blob->pbData[blob->cbData - 1] &= mask;
                     }
                 }
@@ -2504,9 +3107,8 @@ static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
     {
         DWORD bytesNeeded;
 
-        if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
-         lpszStructType, pbEncoded, cbEncoded,
-         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
+        if ((ret = CRYPT_AsnDecodeBitsInternal(pbEncoded, cbEncoded,
+         dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL)))
         {
             if (!pvStructInfo)
                 *pcbStructInfo = bytesNeeded;
@@ -2519,10 +3121,9 @@ static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
                     pvStructInfo = *(BYTE **)pvStructInfo;
                 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
                 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
-                ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
-                 lpszStructType, pbEncoded, cbEncoded,
-                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
-                 &bytesNeeded);
+                ret = CRYPT_AsnDecodeBitsInternal(pbEncoded, cbEncoded,
+                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo,
+                 &bytesNeeded, NULL);
             }
         }
     }
@@ -2536,59 +3137,83 @@ static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
     return ret;
 }
 
+/* Ignores tag.  Only allows integers 4 bytes or smaller in size. */
+static BOOL CRYPT_AsnDecodeIntInternal(const BYTE *pbEncoded, DWORD cbEncoded,
+ DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo, DWORD *pcbDecoded)
+{
+    BOOL ret;
+    BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
+    CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
+    DWORD size = sizeof(buf);
+
+    blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
+    ret = CRYPT_AsnDecodeIntegerInternal(pbEncoded, cbEncoded, 0, &buf,
+     &size, pcbDecoded);
+    if (ret)
+    {
+        if (!pvStructInfo)
+            *pcbStructInfo = sizeof(int);
+        else if ((ret = CRYPT_DecodeCheckSpace(pcbStructInfo, sizeof(int))))
+        {
+            int val, i;
+
+            if (blob->pbData[blob->cbData - 1] & 0x80)
+            {
+                /* initialize to a negative value to sign-extend */
+                val = -1;
+            }
+            else
+                val = 0;
+            for (i = 0; i < blob->cbData; i++)
+            {
+                val <<= 8;
+                val |= blob->pbData[blob->cbData - i - 1];
+            }
+            memcpy(pvStructInfo, &val, sizeof(int));
+        }
+    }
+    else if (GetLastError() == ERROR_MORE_DATA)
+        SetLastError(CRYPT_E_ASN1_LARGE);
+    return ret;
+}
+
 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
 {
     BOOL ret;
 
-    if (!pvStructInfo)
-    {
-        *pcbStructInfo = sizeof(int);
-        return TRUE;
-    }
     __TRY
     {
-        BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
-        CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
-        DWORD size = sizeof(buf);
+        DWORD bytesNeeded;
 
-        blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
-        if (pbEncoded[0] != ASN_INTEGER)
+        if (!cbEncoded)
+        {
+            SetLastError(CRYPT_E_ASN1_CORRUPT);
+            ret = FALSE;
+        }
+        else if (pbEncoded[0] != ASN_INTEGER)
         {
             SetLastError(CRYPT_E_ASN1_BADTAG);
             ret = FALSE;
         }
         else
-            ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
-             X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf,
-             &size);
+            ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded,
+             dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL);
         if (ret)
         {
-            if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
-             pvStructInfo, pcbStructInfo, sizeof(int))))
+            if (!pvStructInfo)
+                *pcbStructInfo = bytesNeeded;
+            else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
+             pvStructInfo, pcbStructInfo, bytesNeeded)))
             {
-                int val, i;
-
                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
                     pvStructInfo = *(BYTE **)pvStructInfo;
-                if (blob->pbData[blob->cbData - 1] & 0x80)
-                {
-                    /* initialize to a negative value to sign-extend */
-                    val = -1;
-                }
-                else
-                    val = 0;
-                for (i = 0; i < blob->cbData; i++)
-                {
-                    val <<= 8;
-                    val |= blob->pbData[blob->cbData - i - 1];
-                }
-                memcpy(pvStructInfo, &val, sizeof(int));
+                ret = CRYPT_AsnDecodeIntInternal(pbEncoded, cbEncoded,
+                 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, pvStructInfo,
+                 &bytesNeeded, NULL);
             }
         }
-        else if (GetLastError() == ERROR_MORE_DATA)
-            SetLastError(CRYPT_E_ASN1_LARGE);
     }
     __EXCEPT_PAGE_FAULT
     {
@@ -2599,9 +3224,9 @@ static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeIntegerInternal(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
 {
     BOOL ret;
     DWORD bytesNeeded, dataLen;
@@ -2611,6 +3236,8 @@ static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
 
         bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
+        if (pcbDecoded)
+            *pcbDecoded = 1 + lenBytes + dataLen;
         if (!pvStructInfo)
             *pcbStructInfo = bytesNeeded;
         else if (*pcbStructInfo < bytesNeeded)
@@ -2656,9 +3283,8 @@ static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
             ret = FALSE;
         }
         else
-            ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
-             lpszStructType, pbEncoded, cbEncoded,
-             dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded);
+            ret = CRYPT_AsnDecodeIntegerInternal(pbEncoded, cbEncoded,
+             dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL);
         if (ret)
         {
             if (!pvStructInfo)
@@ -2673,10 +3299,9 @@ static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
                 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
                 blob->pbData = (BYTE *)pvStructInfo +
                  sizeof(CRYPT_INTEGER_BLOB);
-                ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
-                 lpszStructType, pbEncoded, cbEncoded,
-                 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
-                 &bytesNeeded);
+                ret = CRYPT_AsnDecodeIntegerInternal(pbEncoded, cbEncoded,
+                 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, pvStructInfo,
+                 &bytesNeeded, NULL);
             }
         }
     }
@@ -2689,10 +3314,9 @@ static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
     return ret;
 }
 
-static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
- DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
- DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
- void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeUnsignedIntegerInternal(const BYTE *pbEncoded,
+ DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
+ DWORD *pcbDecoded)
 {
     BOOL ret;
 
@@ -2704,6 +3328,8 @@ static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
         {
             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
 
+            if (pcbDecoded)
+                *pcbDecoded = 1 + lenBytes + dataLen;
             bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
             if (!pvStructInfo)
                 *pcbStructInfo = bytesNeeded;
@@ -2756,9 +3382,8 @@ static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
     {
         DWORD bytesNeeded;
 
-        if ((ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType,
-         lpszStructType, pbEncoded, cbEncoded,
-         dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
+        if ((ret = CRYPT_AsnDecodeUnsignedIntegerInternal(pbEncoded, cbEncoded,
+         dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, &bytesNeeded, NULL)))
         {
             if (!pvStructInfo)
                 *pcbStructInfo = bytesNeeded;
@@ -2772,10 +3397,9 @@ static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
                 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
                 blob->pbData = (BYTE *)pvStructInfo +
                  sizeof(CRYPT_INTEGER_BLOB);
-                ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType,
-                 lpszStructType, pbEncoded, cbEncoded,
-                 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
-                 &bytesNeeded);
+                ret = CRYPT_AsnDecodeUnsignedIntegerInternal(pbEncoded,
+                 cbEncoded, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, pvStructInfo,
+                 &bytesNeeded, NULL);
             }
         }
     }
@@ -2882,251 +3506,254 @@ static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
  SYSTEMTIME *sysTime)
 {
-    BOOL ret;
+    BOOL ret = TRUE;
 
-    __TRY
+    if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
     {
-        ret = TRUE;
-        if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
-        {
-            WORD hours, minutes = 0;
-            BYTE sign = *pbEncoded++;
+        WORD hours, minutes = 0;
+        BYTE sign = *pbEncoded++;
 
-            len--;
-            CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
-            if (ret && hours >= 24)
+        len--;
+        CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
+        if (ret && hours >= 24)
+        {
+            SetLastError(CRYPT_E_ASN1_CORRUPT);
+            ret = FALSE;
+        }
+        else if (len >= 2)
+        {
+            CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
+            if (ret && minutes >= 60)
             {
                 SetLastError(CRYPT_E_ASN1_CORRUPT);
                 ret = FALSE;
             }
-            else if (len >= 2)
+        }
+        if (ret)
+        {
+            if (sign == '+')
             {
-                CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
-                if (ret && minutes >= 60)
-                {
-                    SetLastError(CRYPT_E_ASN1_CORRUPT);
-                    ret = FALSE;
-                }
+                sysTime->wHour += hours;
+                sysTime->wMinute += minutes;
             }
-            if (ret)
+            else
             {
-                if (sign == '+')
+                if (hours > sysTime->wHour)
                 {
-                    sysTime->wHour += hours;
-                    sysTime->wMinute += minutes;
+                    sysTime->wDay--;
+                    sysTime->wHour = 24 - (hours - sysTime->wHour);
                 }
                 else
+                    sysTime->wHour -= hours;
+                if (minutes > sysTime->wMinute)
                 {
-                    if (hours > sysTime->wHour)
-                    {
-                        sysTime->wDay--;
-                        sysTime->wHour = 24 - (hours - sysTime->wHour);
-                    }
-                    else
-                        sysTime->wHour -= hours;
-                    if (minutes > sysTime->wMinute)
-                    {
-                        sysTime->wHour--;
-                        sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
-                    }
-                    else
-                        sysTime->wMinute -= minutes;
+                    sysTime->wHour--;
+                    sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
                 }
+                else
+                    sysTime->wMinute -= minutes;
             }
         }
     }
-    __EXCEPT_PAGE_FAULT
-    {
-        SetLastError(STATUS_ACCESS_VIOLATION);
-        ret = FALSE;
-    }
-    __ENDTRY
     return ret;
 }
 
 #define MIN_ENCODED_TIME_LENGTH 10
 
-static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
+static BOOL CRYPT_AsnDecodeUtcTimeInternal(const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
DWORD *pcbDecoded)
 {
-    BOOL ret;
+    BOOL ret = FALSE;
 
-    if (!pvStructInfo)
-    {
-        *pcbStructInfo = sizeof(FILETIME);
-        return TRUE;
-    }
-    __TRY
+    if (pbEncoded[0] == ASN_UTCTIME)
     {
-        ret = TRUE;
-        if (pbEncoded[0] == ASN_UTCTIME)
+        if (cbEncoded <= 1)
+            SetLastError(CRYPT_E_ASN1_EOD);
+        else if (pbEncoded[1] > 0x7f)
         {
-            if (cbEncoded <= 1)
-            {
-                SetLastError(CRYPT_E_ASN1_EOD);
-                ret = FALSE;
-            }
-            else if (pbEncoded[1] > 0x7f)
-            {
-                /* long-form date strings really can't be valid */
+            /* long-form date strings really can't be valid */
+            SetLastError(CRYPT_E_ASN1_CORRUPT);
+        }
+        else
+        {
+            SYSTEMTIME sysTime = { 0 };
+            BYTE len = pbEncoded[1];
+
+            if (len < MIN_ENCODED_TIME_LENGTH)
                 SetLastError(CRYPT_E_ASN1_CORRUPT);
-                ret = FALSE;
-            }
             else
             {
-                SYSTEMTIME sysTime = { 0 };
-                BYTE len = pbEncoded[1];
-
-                if (len < MIN_ENCODED_TIME_LENGTH)
+                ret = TRUE;
+                if (pcbDecoded)
+                    *pcbDecoded = 2 + len;
+                pbEncoded += 2;
+                CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
+                if (sysTime.wYear >= 50)
+                    sysTime.wYear += 1900;
+                else
+                    sysTime.wYear += 2000;
+                CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
+                CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
+                CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
+                CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
+                if (ret && len > 0)
                 {
-                    SetLastError(CRYPT_E_ASN1_CORRUPT);
-                    ret = FALSE;
+                    if (len >= 2 && isdigit(*pbEncoded) &&
+                     isdigit(*(pbEncoded + 1)))
+                        CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
+                         sysTime.wSecond);
+                    else if (isdigit(*pbEncoded))
+                        CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
+                         sysTime.wSecond);
+                    if (ret)
+                        ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
+                         &sysTime);
                 }
-                else
+                if (ret)
                 {
-                    pbEncoded += 2;
-                    CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
-                    if (sysTime.wYear >= 50)
-                        sysTime.wYear += 1900;
-                    else
-                        sysTime.wYear += 2000;
-                    CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
-                    CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
-                    CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
-                    CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
-                    if (ret && len > 0)
-                    {
-                        if (len >= 2 && isdigit(*pbEncoded) &&
-                         isdigit(*(pbEncoded + 1)))
-                            CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
-                             sysTime.wSecond);
-                        else if (isdigit(*pbEncoded))
-                            CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
-                             sysTime.wSecond);
-                        if (ret)
-                            ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
-                             &sysTime);
-                    }
-                    if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
-                     pDecodePara, pvStructInfo, pcbStructInfo,
+                    if (!pvStructInfo)
+                        *pcbStructInfo = sizeof(FILETIME);
+                    else if ((ret = CRYPT_DecodeCheckSpace(pcbStructInfo,
                      sizeof(FILETIME))))
-                    {
-                        if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
-                            pvStructInfo = *(BYTE **)pvStructInfo;
                         ret = SystemTimeToFileTime(&sysTime,
                          (FILETIME *)pvStructInfo);
-                    }
                 }
             }
         }
-        else
+    }
+    else