actually validate the chain before adding
authorBrendan Forster <brendan@github.com>
Thu, 27 Apr 2017 04:44:58 +0000 (14:44 +1000)
committerBrendan Forster <brendan@github.com>
Thu, 27 Apr 2017 04:44:58 +0000 (14:44 +1000)
atom/browser/ui/certificate_trust_win.cc

index 49d7436..892441c 100644 (file)
 
 namespace certificate_trust {
 
-void ShowCertificateTrust(atom::NativeWindow* parent_window,
-                          const scoped_refptr<net::X509Certificate>& cert,
-                          const std::string& message,
-                          const ShowTrustCallback& callback) {
-    // opening the Trusted Root Certificate store for the current user
-    auto hCertStore = CertOpenStore(
+BOOL AddCertificateAndRefresh(
+    const HCERTSTORE certStore,
+    const PCCERT_CONTEXT certContext,
+    const scoped_refptr<net::X509Certificate>& cert) {
+    auto result = CertAddCertificateContextToStore(
+        certStore,
+        certContext,
+        CERT_STORE_ADD_REPLACE_EXISTING,
+        NULL);
+
+    if (result) {
+        auto cert_db = net::CertDatabase::GetInstance();
+        // Force Chromium to reload the certificate since it might be trusted
+        // now.
+        cert_db->NotifyObserversCertDBChanged(cert.get());
+    }
+
+    return result;
+}
+
+
+// Add the provided certificate to the Trusted Root
+// Certificate Authorities store for the current user.
+//
+// This requires prompting the user to confirm they
+// trust the certificate.
+BOOL AddToTrustedRootStore(const PCCERT_CONTEXT certContext,
+                           const scoped_refptr<net::X509Certificate>& cert) {
+    auto rootCertStore = CertOpenStore(
         CERT_STORE_PROV_SYSTEM,
         0,
         NULL,
         CERT_SYSTEM_STORE_CURRENT_USER,
-        // installing into Trusted Root Certificate Authorities, not Personal
         L"Root");
 
-    if (hCertStore == NULL) {
-        callback.Run();
-        return;
+    if (rootCertStore == NULL) {
+        // could not resolve the certificate store, giving up
+        return false;
     }
 
-    auto pCertContext = cert->CreateOSCertChainForCert();
+    auto result = AddCertificateAndRefresh(rootCertStore, certContext, cert);
 
-    // This is a blocking call which displays a prompt to the user to confirm
-    // they trust this certificate
-    auto result = CertAddCertificateContextToStore(
-        hCertStore,
-        pCertContext,
-        CERT_STORE_ADD_REPLACE_EXISTING,
-        NULL);
+    CertCloseStore(rootCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
 
-    if (result) {
-        auto cert_db = net::CertDatabase::GetInstance();
-        // Force Chromium to reload the certificate since it might be trusted
-        // now.
-        cert_db->NotifyObserversCertDBChanged(cert.get());
+    return result;
+}
+
+// Add the provided certificate to the Personal
+// certificate store for the current user.
+BOOL AddToPersonalStore(const PCCERT_CONTEXT certContext,
+                        const scoped_refptr<net::X509Certificate>& cert) {
+    auto userCertStore = CertOpenStore(
+        CERT_STORE_PROV_SYSTEM,
+        0,
+        NULL,
+        CERT_SYSTEM_STORE_CURRENT_USER,
+        L"My");
+
+    if (userCertStore == NULL) {
+        // could not resolve the certificate store, giving up
+        return false;
     }
 
-    CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
+    auto result = AddCertificateAndRefresh(userCertStore, certContext, cert);
+
+    CertCloseStore(userCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
+
+    return result;
+}
+
+CERT_CHAIN_PARA GetCertificateChainParameters() {
+    CERT_ENHKEY_USAGE enhkeyUsage;
+    enhkeyUsage.cUsageIdentifier = 0;
+    enhkeyUsage.rgpszUsageIdentifier = NULL;
+
+    CERT_USAGE_MATCH CertUsage;
+    // ensure the rules are applied to the entire chain
+    CertUsage.dwType = USAGE_MATCH_TYPE_AND;
+    CertUsage.Usage = enhkeyUsage;
+
+    CERT_CHAIN_PARA params = { sizeof(CERT_CHAIN_PARA) };
+    params.RequestedUsage = CertUsage;
+
+    return params;
+}
+
+void ShowCertificateTrust(atom::NativeWindow* parent_window,
+                          const scoped_refptr<net::X509Certificate>& cert,
+                          const std::string& message,
+                          const ShowTrustCallback& callback) {
+    PCCERT_CHAIN_CONTEXT chainContext;
+
+    auto pCertContext = cert->CreateOSCertChainForCert();
+
+    auto params = GetCertificateChainParameters();
+
+    if (CertGetCertificateChain(NULL,
+                                pCertContext,
+                                NULL,
+                                NULL,
+                                &params,
+                                NULL,
+                                NULL,
+                                &chainContext)) {
+        switch (chainContext->TrustStatus.dwErrorStatus) {
+            case CERT_TRUST_NO_ERROR:
+                AddToPersonalStore(pCertContext, cert);
+                break;
+
+            case CERT_TRUST_IS_UNTRUSTED_ROOT:
+            case CERT_TRUST_IS_SELF_SIGNED:
+                AddToTrustedRootStore(pCertContext, cert);
+                break;
+
+            default:
+                // we can't handle other scenarios, giving up
+                break;
+        }
+
+        CertFreeCertificateChain(chainContext);
+    }
 
     CertFreeCertificateContext(pCertContext);