121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// Copyright (c) 2010 The Chromium Authors. All rights reserved.
221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// Use of this source code is governed by a BSD-style license that can be
321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// found in the LICENSE file.
421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "net/base/test_root_certs.h"
621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <windows.h>
821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <wincrypt.h>
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/basictypes.h"
1121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/lazy_instance.h"
1221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/logging.h"
1321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "net/base/x509_certificate.h"
1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsennamespace net {
1621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsennamespace {
1821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// Provides a CertDllOpenStoreProv callback provider function, to be called
2021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// by CertOpenStore when the CERT_STORE_PROV_SYSTEM_W store is opened. See
2121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// http://msdn.microsoft.com/en-us/library/aa376043(VS.85).aspx.
2221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenBOOL WINAPI InterceptedOpenStoreW(LPCSTR store_provider,
2321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                  DWORD encoding,
2421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                  HCRYPTPROV crypt_provider,
2521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                  DWORD flags,
2621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                  const void* extra,
2721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                  HCERTSTORE memory_store,
2821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                  PCERT_STORE_PROV_INFO store_info);
2921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
3021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// CryptoAPIInjector is used to inject a store provider function for system
3121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// certificate stores before the one provided internally by Crypt32.dll.
3221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// Once injected, there is no way to remove, so every call to open a system
3321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// store will be redirected to the injected function.
3421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstruct CryptoAPIInjector {
3521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // The previous default function for opening system stores. For most
3621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // configurations, this should point to Crypt32's internal
3721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // I_CertDllOpenSystemStoreProvW function.
3821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  PFN_CERT_DLL_OPEN_STORE_PROV_FUNC original_function;
3921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
4021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // The handle that CryptoAPI uses to ensure the DLL implementing
4121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // |original_function| remains loaded in memory.
4221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  HCRYPTOIDFUNCADDR original_handle;
4321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
4421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen private:
4521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  friend struct base::DefaultLazyInstanceTraits<CryptoAPIInjector>;
4621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
4721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CryptoAPIInjector()
4821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      : original_function(NULL),
4921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        original_handle(NULL) {
5021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    HCRYPTOIDFUNCSET registered_functions =
5121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        CryptInitOIDFunctionSet(CRYPT_OID_OPEN_STORE_PROV_FUNC, 0);
5221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
5321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // Preserve the original handler function in |original_function|. If other
5421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // functions are overridden, they will also need to be preserved.
5521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    BOOL ok = CryptGetOIDFunctionAddress(
5621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        registered_functions, 0, CERT_STORE_PROV_SYSTEM_W, 0,
5721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        reinterpret_cast<void**>(&original_function), &original_handle);
5821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    DCHECK(ok);
5921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
6021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // For now, intercept only the numeric form of the system store
6121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // function, CERT_STORE_PROV_SYSTEM_W (0x0A), which is what Crypt32
6221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // functionality uses exclusively. Depending on the machine that tests
6321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // are being run on, it may prove necessary to also intercept
6421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // sz_CERT_STORE_PROV_SYSTEM_[A/W] and CERT_STORE_PROV_SYSTEM_A, based
6521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // on whether or not any third-party CryptoAPI modules have been
6621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // installed.
6721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    const CRYPT_OID_FUNC_ENTRY kFunctionToIntercept =
6821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        { CERT_STORE_PROV_SYSTEM_W, &InterceptedOpenStoreW };
6921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
7021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // Inject kFunctionToIntercept at the front of the linked list that
7121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // crypt32 uses when CertOpenStore is called, replacing the existing
7221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // registered function.
7321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    ok = CryptInstallOIDFunctionAddress(NULL, 0,
7421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                        CRYPT_OID_OPEN_STORE_PROV_FUNC, 1,
7521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                        &kFunctionToIntercept,
7621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                        CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG);
7721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    DCHECK(ok);
7821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
7921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
8021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // This is never called, because this object is intentionally leaked.
8121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Certificate verification happens on a non-joinable worker thread, which
8221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // may still be running when ~AtExitManager is called, so the LazyInstance
8321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // must be leaky.
8421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ~CryptoAPIInjector() {
8521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    original_function = NULL;
8621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    CryptFreeOIDFunctionAddress(original_handle, NULL);
8721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
8821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen};
8921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
9021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbase::LazyInstance<CryptoAPIInjector,
9121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                   base::LeakyLazyInstanceTraits<CryptoAPIInjector> >
9221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    g_capi_injector(base::LINKER_INITIALIZED);
9321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
9421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenBOOL WINAPI InterceptedOpenStoreW(LPCSTR store_provider,
9521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                  DWORD encoding,
9621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                  HCRYPTPROV crypt_provider,
9721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                  DWORD flags,
9821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                  const void* store_name,
9921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                  HCERTSTORE memory_store,
10021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                  PCERT_STORE_PROV_INFO store_info) {
10121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // If the high word is all zeroes, then |store_provider| is a numeric ID.
10221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Otherwise, it's a pointer to a null-terminated ASCII string. See the
10321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // documentation for CryptGetOIDFunctionAddress for more information.
10421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  uint32 store_as_uint = reinterpret_cast<uint32>(store_provider);
10521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (store_as_uint > 0xFFFF || store_provider != CERT_STORE_PROV_SYSTEM_W ||
10621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      !g_capi_injector.Get().original_function)
10721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return FALSE;
10821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
10921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  BOOL ok = g_capi_injector.Get().original_function(store_provider, encoding,
11021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                                    crypt_provider, flags,
11121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                                    store_name, memory_store,
11221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                                    store_info);
11321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Only the Root store should have certificates injected. If
11421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // CERT_SYSTEM_STORE_RELOCATE_FLAG is set, then |store_name| points to a
11521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // CERT_SYSTEM_STORE_RELOCATE_PARA structure, rather than a
11621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // NULL-terminated wide string, so check before making a string
11721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // comparison.
11821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!ok || TestRootCerts::GetInstance()->IsEmpty() ||
11921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      (flags & CERT_SYSTEM_STORE_RELOCATE_FLAG) ||
12021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      lstrcmpiW(reinterpret_cast<LPCWSTR>(store_name), L"root"))
12121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return ok;
12221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
12321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // The result of CertOpenStore with CERT_STORE_PROV_SYSTEM_W is documented
12421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // to be a collection store, and that appears to hold for |memory_store|.
12521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Attempting to add an individual certificate to |memory_store| causes
12621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // the request to be forwarded to the first physical store in the
12721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // collection that accepts modifications, which will cause a secure
12821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // confirmation dialog to be displayed, confirming the user wishes to
12921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // trust the certificate. However, appending a store to the collection
13021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // will merely modify the temporary collection store, and will not persist
13121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // any changes to the underlying physical store. When the |memory_store| is
13221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // searched to see if a certificate is in the Root store, all the
13321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // underlying stores in the collection will be searched, and any certificate
13421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // in temporary_roots() will be found and seen as trusted.
13521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return CertAddStoreToCollection(
13621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      memory_store, TestRootCerts::GetInstance()->temporary_roots(), 0, 0);
13721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
13821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
13921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}  // namespace
14021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
14121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool TestRootCerts::Add(X509Certificate* certificate) {
14221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Ensure that the default CryptoAPI functionality has been intercepted.
14321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // If a test certificate is never added, then no interception should
14421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // happen.
14521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  g_capi_injector.Get();
14621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
14721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  BOOL ok = CertAddCertificateContextToStore(
14821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      temporary_roots_, certificate->os_cert_handle(),
14921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CERT_STORE_ADD_NEW, NULL);
15021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!ok) {
15121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // If the certificate is already added, return successfully.
15221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return GetLastError() == CRYPT_E_EXISTS;
15321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
15421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
15521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  empty_ = false;
15621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return true;
15721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
15821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
15921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid TestRootCerts::Clear() {
16021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  empty_ = true;
16121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
16221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  PCCERT_CONTEXT prev_cert = NULL;
16321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  while (prev_cert = CertEnumCertificatesInStore(temporary_roots_, NULL))
16421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    CertDeleteCertificateFromStore(prev_cert);
16521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
16621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
16721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool TestRootCerts::IsEmpty() const {
16821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return empty_;
16921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
17021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
17121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenHCERTCHAINENGINE TestRootCerts::GetChainEngine() const {
17221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (IsEmpty())
17321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return NULL;  // Default chain engine will suffice.
17421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
17521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Each HCERTCHAINENGINE caches both the configured system stores and
17621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // information about each chain that has been built. In order to ensure
17721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // that changes to |temporary_roots_| are properly propagated and that the
17821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // various caches are flushed, when at least one certificate is added,
17921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // return a new chain engine for every call. Each chain engine creation
18021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // should re-open the root store, ensuring the most recent changes are
18121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // visible.
18221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERT_CHAIN_ENGINE_CONFIG engine_config = {
18321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    sizeof(engine_config)
18421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  };
18521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  engine_config.dwFlags =
18621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE |
18721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CERT_CHAIN_ENABLE_SHARE_STORE;
18821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  HCERTCHAINENGINE chain_engine = NULL;
18921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  BOOL ok = CertCreateCertificateChainEngine(&engine_config, &chain_engine);
19021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(ok);
19121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return chain_engine;
19221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
19321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
19421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenTestRootCerts::~TestRootCerts() {
19521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CertCloseStore(temporary_roots_, 0);
19621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
19721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
19821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid TestRootCerts::Init() {
19921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  empty_ = true;
20021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  temporary_roots_ = CertOpenStore(
20121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CERT_STORE_PROV_MEMORY, 0, NULL,
20221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, NULL);
20321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(temporary_roots_);
20421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
20521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
20621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}  // namespace net
207