Juan Lang : cryptdlg: Implement CertTrustFinalPolicy.

Alexandre Julliard julliard at winehq.org
Tue Sep 23 09:28:27 CDT 2008


Module: wine
Branch: master
Commit: e893a2c8637d3c3fb522cd01349498ec029fe901
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=e893a2c8637d3c3fb522cd01349498ec029fe901

Author: Juan Lang <juan.lang at gmail.com>
Date:   Mon Sep 22 13:09:56 2008 -0700

cryptdlg: Implement CertTrustFinalPolicy.

---

 dlls/cryptdlg/Makefile.in |    2 +-
 dlls/cryptdlg/main.c      |  259 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 257 insertions(+), 4 deletions(-)

diff --git a/dlls/cryptdlg/Makefile.in b/dlls/cryptdlg/Makefile.in
index a883c27..0271fa3 100644
--- a/dlls/cryptdlg/Makefile.in
+++ b/dlls/cryptdlg/Makefile.in
@@ -3,7 +3,7 @@ TOPOBJDIR = ../..
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = cryptdlg.dll
-IMPORTS   = cryptui crypt32 wintrust kernel32
+IMPORTS   = cryptui crypt32 wintrust advapi32 kernel32
 
 C_SRCS = \
 	main.c
diff --git a/dlls/cryptdlg/main.c b/dlls/cryptdlg/main.c
index ba79d4f..d87d480 100644
--- a/dlls/cryptdlg/main.c
+++ b/dlls/cryptdlg/main.c
@@ -23,6 +23,7 @@
 #include "windef.h"
 #include "winbase.h"
 #include "winnls.h"
+#include "winreg.h"
 #include "wincrypt.h"
 #include "wintrust.h"
 #include "winuser.h"
@@ -105,13 +106,265 @@ HRESULT WINAPI CertTrustCleanup(CRYPT_PROVIDER_DATA *pProvData)
     return E_NOTIMPL;
 }
 
+static BOOL CRYPTDLG_CheckOnlineCRL(void)
+{
+    static const WCHAR policyFlagsKey[] = { 'S','o','f','t','w','a','r','e',
+     '\\','M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g',
+     'r','a','p','h','y','\\','{','7','8','0','1','e','b','d','0','-','c','f',
+     '4','b','-','1','1','d','0','-','8','5','1','f','-','0','0','6','0','9',
+     '7','9','3','8','7','e','a','}',0 };
+    static const WCHAR policyFlags[] = { 'P','o','l','i','c','y','F','l','a',
+     'g','s',0 };
+    HKEY key;
+    BOOL ret = FALSE;
+
+    if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, policyFlagsKey, 0, KEY_READ, &key))
+    {
+        DWORD type, flags, size = sizeof(flags);
+
+        if (!RegQueryValueExW(key, policyFlags, NULL, &type, (BYTE *)&flags,
+         &size) && type == REG_DWORD)
+        {
+            /* The flag values aren't defined in any header I'm aware of, but
+             * this value is well documented on the net.
+             */
+            if (flags & 0x00010000)
+                ret = TRUE;
+        }
+        RegCloseKey(key);
+    }
+    return ret;
+}
+
+/* Returns TRUE if pCert is not in the Disallowed system store, or FALSE if it
+ * is.
+ */
+static BOOL CRYPTDLG_IsCertAllowed(PCCERT_CONTEXT pCert)
+{
+    BOOL ret;
+    BYTE hash[20];
+    DWORD size = sizeof(hash);
+
+    if ((ret = CertGetCertificateContextProperty(pCert,
+     CERT_SIGNATURE_HASH_PROP_ID, hash, &size)))
+    {
+        static const WCHAR disallowedW[] =
+         { 'D','i','s','a','l','l','o','w','e','d',0 };
+        HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
+         X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, disallowedW);
+
+        if (disallowed)
+        {
+            PCCERT_CONTEXT found = CertFindCertificateInStore(disallowed,
+             X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH, hash, NULL);
+
+            if (found)
+            {
+                ret = FALSE;
+                CertFreeCertificateContext(found);
+            }
+            CertCloseStore(disallowed, 0);
+        }
+    }
+    return ret;
+}
+
+static DWORD CRYPTDLG_TrustStatusToConfidence(DWORD errorStatus)
+{
+    DWORD confidence = 0;
+
+    confidence = 0;
+    if (!(errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID))
+        confidence |= CERT_CONFIDENCE_SIG;
+    if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_VALID))
+        confidence |= CERT_CONFIDENCE_TIME;
+    if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED))
+        confidence |= CERT_CONFIDENCE_TIMENEST;
+    return confidence;
+}
+
+static BOOL CRYPTDLG_CopyChain(CRYPT_PROVIDER_DATA *data,
+ PCCERT_CHAIN_CONTEXT chain)
+{
+    BOOL ret;
+    CRYPT_PROVIDER_SGNR signer;
+    PCERT_SIMPLE_CHAIN simpleChain = chain->rgpChain[0];
+    DWORD i;
+
+    memset(&signer, 0, sizeof(signer));
+    signer.cbStruct = sizeof(signer);
+    ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer);
+    if (ret)
+    {
+        CRYPT_PROVIDER_SGNR *sgnr = WTHelperGetProvSignerFromChain(data, 0,
+         FALSE, 0);
+
+        if (sgnr)
+        {
+            sgnr->dwError = simpleChain->TrustStatus.dwErrorStatus;
+            sgnr->pChainContext = CertDuplicateCertificateChain(chain);
+        }
+        else
+            ret = FALSE;
+        for (i = 0; ret && i < simpleChain->cElement; i++)
+        {
+            ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0,
+             simpleChain->rgpElement[i]->pCertContext);
+            if (ret)
+            {
+                CRYPT_PROVIDER_CERT *cert;
+
+                if ((cert = WTHelperGetProvCertFromChain(sgnr, i)))
+                {
+                    CERT_CHAIN_ELEMENT *element = simpleChain->rgpElement[i];
+
+                    cert->dwConfidence = CRYPTDLG_TrustStatusToConfidence(
+                     element->TrustStatus.dwErrorStatus);
+                    cert->dwError = element->TrustStatus.dwErrorStatus;
+                    cert->pChainElement = element;
+                }
+                else
+                    ret = FALSE;
+            }
+        }
+    }
+    return ret;
+}
+
+static CERT_VERIFY_CERTIFICATE_TRUST *CRYPTDLG_GetVerifyData(
+ CRYPT_PROVIDER_DATA *data)
+{
+    CERT_VERIFY_CERTIFICATE_TRUST *pCert = NULL;
+
+    /* This should always be true, but just in case the calling function is
+     * called directly:
+     */
+    if (data->pWintrustData->dwUnionChoice == WTD_CHOICE_BLOB &&
+     data->pWintrustData->pBlob && data->pWintrustData->pBlob->cbMemObject ==
+     sizeof(CERT_VERIFY_CERTIFICATE_TRUST) &&
+     data->pWintrustData->pBlob->pbMemObject)
+         pCert = (CERT_VERIFY_CERTIFICATE_TRUST *)
+          data->pWintrustData->pBlob->pbMemObject;
+    return pCert;
+}
+
+static HCERTCHAINENGINE CRYPTDLG_MakeEngine(CERT_VERIFY_CERTIFICATE_TRUST *cert)
+{
+    HCERTCHAINENGINE engine = NULL;
+    HCERTSTORE root = NULL, trust = NULL;
+    DWORD i;
+
+    if (cert->cRootStores)
+    {
+        root = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
+         CERT_STORE_CREATE_NEW_FLAG, NULL);
+        if (root)
+        {
+            for (i = 0; i < cert->cRootStores; i++)
+                CertAddStoreToCollection(root, cert->rghstoreRoots[i], 0, 0);
+        }
+    }
+    if (cert->cTrustStores)
+    {
+        trust = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
+         CERT_STORE_CREATE_NEW_FLAG, NULL);
+        if (root)
+        {
+            for (i = 0; i < cert->cTrustStores; i++)
+                CertAddStoreToCollection(trust, cert->rghstoreTrust[i], 0, 0);
+        }
+    }
+    if (cert->cRootStores || cert->cStores || cert->cTrustStores)
+    {
+        CERT_CHAIN_ENGINE_CONFIG config;
+
+        memset(&config, 0, sizeof(config));
+        config.cbSize = sizeof(config);
+        config.hRestrictedRoot = root;
+        config.hRestrictedTrust = trust;
+        config.cAdditionalStore = cert->cStores;
+        config.rghAdditionalStore = cert->rghstoreCAs;
+        config.hRestrictedRoot = root;
+        CertCreateCertificateChainEngine(&config, &engine);
+        CertCloseStore(root, 0);
+        CertCloseStore(trust, 0);
+    }
+    return engine;
+}
+
 /***********************************************************************
  *		CertTrustFinalPolicy (CRYPTDLG.@)
  */
-HRESULT WINAPI CertTrustFinalPolicy(CRYPT_PROVIDER_DATA *pProvData)
+HRESULT WINAPI CertTrustFinalPolicy(CRYPT_PROVIDER_DATA *data)
 {
-    FIXME("(%p)\n", pProvData);
-    return E_NOTIMPL;
+    BOOL ret;
+    DWORD err = S_OK;
+    CERT_VERIFY_CERTIFICATE_TRUST *pCert = CRYPTDLG_GetVerifyData(data);
+
+    TRACE("(%p)\n", data);
+
+    if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
+        FIXME("unimplemented for UI choice %d\n",
+         data->pWintrustData->dwUIChoice);
+    if (pCert)
+    {
+        DWORD flags = 0;
+        CERT_CHAIN_PARA chainPara;
+        HCERTCHAINENGINE engine;
+
+        memset(&chainPara, 0, sizeof(chainPara));
+        chainPara.cbSize = sizeof(chainPara);
+        if (CRYPTDLG_CheckOnlineCRL())
+            flags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT;
+        engine = CRYPTDLG_MakeEngine(pCert);
+        GetSystemTimeAsFileTime(&data->sftSystemTime);
+        ret = CRYPTDLG_IsCertAllowed(pCert->pccert);
+        if (ret)
+        {
+            PCCERT_CHAIN_CONTEXT chain;
+
+            ret = CertGetCertificateChain(engine, pCert->pccert,
+             &data->sftSystemTime, NULL, &chainPara, flags, NULL, &chain);
+            if (ret)
+            {
+                if (chain->cChain != 1)
+                {
+                    FIXME("unimplemented for more than 1 simple chain\n");
+                    err = TRUST_E_SUBJECT_FORM_UNKNOWN;
+                    ret = FALSE;
+                }
+                else if ((ret = CRYPTDLG_CopyChain(data, chain)))
+                {
+                    if (CertVerifyTimeValidity(&data->sftSystemTime,
+                     pCert->pccert->pCertInfo))
+                    {
+                        ret = FALSE;
+                        err = CERT_E_EXPIRED;
+                    }
+                }
+                else
+                    err = TRUST_E_SYSTEM_ERROR;
+                CertFreeCertificateChain(chain);
+            }
+            else
+                err = TRUST_E_SUBJECT_NOT_TRUSTED;
+        }
+        CertFreeCertificateChainEngine(engine);
+    }
+    else
+    {
+        ret = FALSE;
+        err = TRUST_E_NOSIGNATURE;
+    }
+    /* Oddly, native doesn't set the error in the trust step error location,
+     * probably because this action is more advisory than anything else.
+     * Instead it stores it as the final error, but the function "succeeds" in
+     * any case.
+     */
+    if (!ret)
+        data->dwFinalError = err;
+    TRACE("returning %d (%08x)\n", S_OK, data->dwFinalError);
+    return S_OK;
 }
 
 /***********************************************************************




More information about the wine-cvs mailing list