Juan Lang : wininet: Honor security flags when verifying certificates.

Alexandre Julliard julliard at winehq.org
Thu Sep 30 11:23:34 CDT 2010


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

Author: Juan Lang <juan.lang at gmail.com>
Date:   Wed Sep 29 07:53:53 2010 -0700

wininet: Honor security flags when verifying certificates.

---

 dlls/wininet/netconnection.c |   52 +++++++++++++++++++++++++++++++----------
 1 files changed, 39 insertions(+), 13 deletions(-)

diff --git a/dlls/wininet/netconnection.c b/dlls/wininet/netconnection.c
index 9d52ae6..7bb00dc 100644
--- a/dlls/wininet/netconnection.c
+++ b/dlls/wininet/netconnection.c
@@ -220,7 +220,7 @@ static PCCERT_CONTEXT X509_to_cert_context(X509 *cert)
 }
 
 static DWORD netconn_verify_cert(PCCERT_CONTEXT cert, HCERTSTORE store,
-    WCHAR *server)
+    WCHAR *server, DWORD security_flags)
 {
     BOOL ret;
     CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } };
@@ -237,30 +237,49 @@ static DWORD netconn_verify_cert(PCCERT_CONTEXT cert, HCERTSTORE store,
     {
         if (chain->TrustStatus.dwErrorStatus)
         {
+            static const DWORD supportedErrors =
+                CERT_TRUST_IS_NOT_TIME_VALID |
+                CERT_TRUST_IS_UNTRUSTED_ROOT |
+                CERT_TRUST_IS_OFFLINE_REVOCATION |
+                CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
+                CERT_TRUST_IS_REVOKED |
+                CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
+
             if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID)
                 err = ERROR_INTERNET_SEC_CERT_DATE_INVALID;
             else if (chain->TrustStatus.dwErrorStatus &
-                     CERT_TRUST_IS_UNTRUSTED_ROOT)
+                     CERT_TRUST_IS_UNTRUSTED_ROOT &&
+                     !(security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA))
                 err = ERROR_INTERNET_INVALID_CA;
-            else if ((chain->TrustStatus.dwErrorStatus &
+            else if (!(security_flags & SECURITY_FLAG_IGNORE_REVOCATION) &&
+                     ((chain->TrustStatus.dwErrorStatus &
                       CERT_TRUST_IS_OFFLINE_REVOCATION) ||
-                     (chain->TrustStatus.dwErrorStatus &
-                      CERT_TRUST_REVOCATION_STATUS_UNKNOWN))
+                      (chain->TrustStatus.dwErrorStatus &
+                       CERT_TRUST_REVOCATION_STATUS_UNKNOWN)))
                 err = ERROR_INTERNET_SEC_CERT_NO_REV;
-            else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED)
+            else if (!(security_flags & SECURITY_FLAG_IGNORE_REVOCATION) &&
+                     (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED))
                 err = ERROR_INTERNET_SEC_CERT_REVOKED;
-            else if (chain->TrustStatus.dwErrorStatus &
-                CERT_TRUST_IS_NOT_VALID_FOR_USAGE)
+            else if (!(security_flags & SECURITY_FLAG_IGNORE_WRONG_USAGE) &&
+                     (chain->TrustStatus.dwErrorStatus &
+                      CERT_TRUST_IS_NOT_VALID_FOR_USAGE))
                 err = ERROR_INTERNET_SEC_INVALID_CERT;
-            else
+            else if (chain->TrustStatus.dwErrorStatus & ~supportedErrors)
                 err = ERROR_INTERNET_SEC_INVALID_CERT;
         }
-        else
+        if (!err)
         {
             CERT_CHAIN_POLICY_PARA policyPara;
             SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara;
             CERT_CHAIN_POLICY_STATUS policyStatus;
+            CERT_CHAIN_CONTEXT chainCopy;
 
+            /* Clear chain->TrustStatus.dwErrorStatus so
+             * CertVerifyCertificateChainPolicy will verify additional checks
+             * rather than stopping with an existing, ignored error.
+             */
+            memcpy(&chainCopy, chain, sizeof(chainCopy));
+            chainCopy.TrustStatus.dwErrorStatus = 0;
             sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara);
             sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER;
             sslExtraPolicyPara.pwszServerName = server;
@@ -268,14 +287,18 @@ static DWORD netconn_verify_cert(PCCERT_CONTEXT cert, HCERTSTORE store,
             policyPara.dwFlags = 0;
             policyPara.pvExtraPolicyPara = &sslExtraPolicyPara;
             ret = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL,
-                chain, &policyPara, &policyStatus);
+                &chainCopy, &policyPara, &policyStatus);
             /* Any error in the policy status indicates that the
              * policy couldn't be verified.
              */
             if (ret && policyStatus.dwError)
             {
                 if (policyStatus.dwError == CERT_E_CN_NO_MATCH)
-                    err = ERROR_INTERNET_SEC_CERT_CN_INVALID;
+                {
+                    if (!(security_flags &
+                          SECURITY_FLAG_IGNORE_CERT_CN_INVALID))
+                        err = ERROR_INTERNET_SEC_CERT_CN_INVALID;
+                }
                 else
                     err = ERROR_INTERNET_SEC_INVALID_CERT;
             }
@@ -293,10 +316,12 @@ static int netconn_secure_verify(int preverify_ok, X509_STORE_CTX *ctx)
     BOOL ret = FALSE;
     HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
         CERT_STORE_CREATE_NEW_FLAG, NULL);
+    WININET_NETCONNECTION *conn;
 
     ssl = pX509_STORE_CTX_get_ex_data(ctx,
         pSSL_get_ex_data_X509_STORE_CTX_idx());
     server = pSSL_get_ex_data(ssl, hostname_idx);
+    conn = pSSL_get_ex_data(ssl, conn_idx);
     if (store)
     {
         X509 *cert;
@@ -323,7 +348,8 @@ static int netconn_secure_verify(int preverify_ok, X509_STORE_CTX *ctx)
         if (!endCert) ret = FALSE;
         if (ret)
         {
-            DWORD_PTR err = netconn_verify_cert(endCert, store, server);
+            DWORD_PTR err = netconn_verify_cert(endCert, store, server,
+                                                conn->security_flags);
 
             if (err)
             {




More information about the wine-cvs mailing list