ClientCertStoreWin: do client cert and key lookup on SSLPlatformKeyTaskRunner.

When USE_BYTE_CERTS=true and X509Certificate is no longer holding PCCERT_CONTEXT handles, it is safe to move these off the IO thread.

BUG=394131

Review-Url: https://codereview.chromium.org/2927193003
Cr-Commit-Position: refs/heads/master@{#481309}
diff --git a/net/ssl/client_cert_store_win.cc b/net/ssl/client_cert_store_win.cc
index 2383765..e4a59de 100644
--- a/net/ssl/client_cert_store_win.cc
+++ b/net/ssl/client_cert_store_win.cc
@@ -22,6 +22,7 @@
 #include "crypto/wincrypt_shim.h"
 #include "net/cert/x509_util.h"
 #include "net/cert/x509_util_win.h"
+#include "net/ssl/ssl_platform_key_util.h"
 #include "net/ssl/ssl_platform_key_win.h"
 #include "net/ssl/ssl_private_key.h"
 
@@ -105,10 +106,9 @@
   return TRUE;
 }
 
-void GetClientCertsImpl(HCERTSTORE cert_store,
-                        const SSLCertRequestInfo& request,
-                        ClientCertIdentityList* selected_identities) {
-  selected_identities->clear();
+ClientCertIdentityList GetClientCertsImpl(HCERTSTORE cert_store,
+                                          const SSLCertRequestInfo& request) {
+  ClientCertIdentityList selected_identities;
 
   scoped_refptr<base::SingleThreadTaskRunner> current_thread =
       base::ThreadTaskRunnerHandle::Get();
@@ -198,7 +198,7 @@
         x509_util::CreateX509CertificateFromCertContexts(cert_context2,
                                                          intermediates);
     if (cert) {
-      selected_identities->push_back(base::MakeUnique<ClientCertIdentityWin>(
+      selected_identities.push_back(base::MakeUnique<ClientCertIdentityWin>(
           std::move(cert),
           cert_context2,     // Takes ownership of |cert_context2|.
           current_thread));  // The key must be acquired on the same thread, as
@@ -208,8 +208,9 @@
       CertFreeCertificateContext(intermediates[i]);
   }
 
-  std::sort(selected_identities->begin(), selected_identities->end(),
+  std::sort(selected_identities.begin(), selected_identities.end(),
             ClientCertIdentitySorter());
+  return selected_identities;
 }
 
 }  // namespace
@@ -226,16 +227,39 @@
 void ClientCertStoreWin::GetClientCerts(
     const SSLCertRequestInfo& request,
     const ClientCertListCallback& callback) {
-  ClientCertIdentityList selected_identities;
   if (cert_store_) {
     // Use the existing client cert store. Note: Under some situations,
     // it's possible for this to return certificates that aren't usable
     // (see below).
-    GetClientCertsImpl(cert_store_, request, &selected_identities);
-    callback.Run(std::move(selected_identities));
+    // When using caller provided HCERTSTORE, assume that it should be accessed
+    // on the current thread.
+    callback.Run(GetClientCertsImpl(cert_store_, request));
     return;
   }
 
+#if BUILDFLAG(USE_BYTE_CERTS)
+  if (base::PostTaskAndReplyWithResult(
+          GetSSLPlatformKeyTaskRunner().get(), FROM_HERE,
+          // Caller is responsible for keeping the |request| alive
+          // until the callback is run, so ConstRef is safe.
+          base::Bind(&ClientCertStoreWin::GetClientCertsWithMyCertStore,
+                     base::ConstRef(request)),
+          callback)) {
+    return;
+  }
+
+  // If the task could not be posted, behave as if there were no certificates.
+  callback.Run(ClientCertIdentityList());
+#else
+  // When using PCERT_CONTEXT based X509Certificate, must do this on the same
+  // thread.
+  callback.Run(GetClientCertsWithMyCertStore(request));
+#endif
+}
+
+// static
+ClientCertIdentityList ClientCertStoreWin::GetClientCertsWithMyCertStore(
+    const SSLCertRequestInfo& request) {
   // Always open a new instance of the "MY" store, to ensure that there
   // are no previously cached certificates being reused after they're
   // no longer available (some smartcard providers fail to update the "MY"
@@ -243,12 +267,9 @@
   ScopedHCERTSTORE my_cert_store(CertOpenSystemStore(NULL, L"MY"));
   if (!my_cert_store) {
     PLOG(ERROR) << "Could not open the \"MY\" system certificate store: ";
-    callback.Run(ClientCertIdentityList());
-    return;
+    return ClientCertIdentityList();
   }
-
-  GetClientCertsImpl(my_cert_store, request, &selected_identities);
-  callback.Run(std::move(selected_identities));
+  return GetClientCertsImpl(my_cert_store, request);
 }
 
 bool ClientCertStoreWin::SelectClientCertsForTesting(
@@ -287,7 +308,7 @@
     }
   }
 
-  GetClientCertsImpl(test_store.get(), request, selected_identities);
+  *selected_identities = GetClientCertsImpl(test_store.get(), request);
   return true;
 }
 
diff --git a/net/ssl/client_cert_store_win.h b/net/ssl/client_cert_store_win.h
index 0665a9d..4db6d475 100644
--- a/net/ssl/client_cert_store_win.h
+++ b/net/ssl/client_cert_store_win.h
@@ -39,6 +39,10 @@
 
   friend class ClientCertStoreWinTestDelegate;
 
+  // Opens the "MY" cert store and uses it to lookup the client certs.
+  static ClientCertIdentityList GetClientCertsWithMyCertStore(
+      const SSLCertRequestInfo& request);
+
   // A hook for testing. Filters |input_certs| using the logic being used to
   // filter the system store when GetClientCerts() is called.
   // Implemented by creating a temporary in-memory store and filtering it