15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/test_root_certs.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <wincrypt.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/win_util.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h" 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_certificate.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Provides a CertDllOpenStoreProv callback provider function, to be called 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// by CertOpenStore when the CERT_STORE_PROV_SYSTEM_W store is opened. See 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://msdn.microsoft.com/en-us/library/aa376043(VS.85).aspx. 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI InterceptedOpenStoreW(LPCSTR store_provider, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD encoding, 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HCRYPTPROV crypt_provider, 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD flags, 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* extra, 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HCERTSTORE memory_store, 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PCERT_STORE_PROV_INFO store_info); 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CryptoAPIInjector is used to inject a store provider function for system 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// certificate stores before the one provided internally by Crypt32.dll. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Once injected, there is no way to remove, so every call to open a system 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// store will be redirected to the injected function. 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct CryptoAPIInjector { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The previous default function for opening system stores. For most 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // configurations, this should point to Crypt32's internal 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // I_CertDllOpenSystemStoreProvW function. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PFN_CERT_DLL_OPEN_STORE_PROV_FUNC original_function; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The handle that CryptoAPI uses to ensure the DLL implementing 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |original_function| remains loaded in memory. 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HCRYPTOIDFUNCADDR original_handle; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend struct base::DefaultLazyInstanceTraits<CryptoAPIInjector>; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CryptoAPIInjector() 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : original_function(NULL), 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) original_handle(NULL) { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HCRYPTOIDFUNCSET registered_functions = 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CryptInitOIDFunctionSet(CRYPT_OID_OPEN_STORE_PROV_FUNC, 0); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Preserve the original handler function in |original_function|. If other 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // functions are overridden, they will also need to be preserved. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL ok = CryptGetOIDFunctionAddress( 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registered_functions, 0, CERT_STORE_PROV_SYSTEM_W, 0, 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void**>(&original_function), &original_handle); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(ok); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For now, intercept only the numeric form of the system store 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // function, CERT_STORE_PROV_SYSTEM_W (0x0A), which is what Crypt32 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // functionality uses exclusively. Depending on the machine that tests 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are being run on, it may prove necessary to also intercept 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sz_CERT_STORE_PROV_SYSTEM_[A/W] and CERT_STORE_PROV_SYSTEM_A, based 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // on whether or not any third-party CryptoAPI modules have been 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // installed. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CRYPT_OID_FUNC_ENTRY kFunctionToIntercept = 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { CERT_STORE_PROV_SYSTEM_W, &InterceptedOpenStoreW }; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Inject kFunctionToIntercept at the front of the linked list that 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // crypt32 uses when CertOpenStore is called, replacing the existing 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // registered function. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok = CryptInstallOIDFunctionAddress(NULL, 0, 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CRYPT_OID_OPEN_STORE_PROV_FUNC, 1, 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &kFunctionToIntercept, 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(ok); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is never called, because this object is intentionally leaked. 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Certificate verification happens on a non-joinable worker thread, which 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // may still be running when ~AtExitManager is called, so the LazyInstance 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // must be leaky. 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~CryptoAPIInjector() { 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) original_function = NULL; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CryptFreeOIDFunctionAddress(original_handle, NULL); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::LazyInstance<CryptoAPIInjector>::Leaky 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_capi_injector = LAZY_INSTANCE_INITIALIZER; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL WINAPI InterceptedOpenStoreW(LPCSTR store_provider, 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD encoding, 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HCRYPTPROV crypt_provider, 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD flags, 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* store_name, 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HCERTSTORE memory_store, 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PCERT_STORE_PROV_INFO store_info) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the high word is all zeroes, then |store_provider| is a numeric ID. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Otherwise, it's a pointer to a null-terminated ASCII string. See the 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // documentation for CryptGetOIDFunctionAddress for more information. 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 store_as_uint = reinterpret_cast<uint32>(store_provider); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (store_as_uint > 0xFFFF || store_provider != CERT_STORE_PROV_SYSTEM_W || 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !g_capi_injector.Get().original_function) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FALSE; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL ok = g_capi_injector.Get().original_function(store_provider, encoding, 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) crypt_provider, flags, 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_name, memory_store, 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) store_info); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only the Root store should have certificates injected. If 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CERT_SYSTEM_STORE_RELOCATE_FLAG is set, then |store_name| points to a 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CERT_SYSTEM_STORE_RELOCATE_PARA structure, rather than a 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NULL-terminated wide string, so check before making a string 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // comparison. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ok || TestRootCerts::GetInstance()->IsEmpty() || 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (flags & CERT_SYSTEM_STORE_RELOCATE_FLAG) || 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lstrcmpiW(reinterpret_cast<LPCWSTR>(store_name), L"root")) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ok; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The result of CertOpenStore with CERT_STORE_PROV_SYSTEM_W is documented 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to be a collection store, and that appears to hold for |memory_store|. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Attempting to add an individual certificate to |memory_store| causes 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the request to be forwarded to the first physical store in the 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // collection that accepts modifications, which will cause a secure 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // confirmation dialog to be displayed, confirming the user wishes to 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // trust the certificate. However, appending a store to the collection 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will merely modify the temporary collection store, and will not persist 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // any changes to the underlying physical store. When the |memory_store| is 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // searched to see if a certificate is in the Root store, all the 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // underlying stores in the collection will be searched, and any certificate 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in temporary_roots() will be found and seen as trusted. 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CertAddStoreToCollection( 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memory_store, TestRootCerts::GetInstance()->temporary_roots(), 0, 0); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TestRootCerts::Add(X509Certificate* certificate) { 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ensure that the default CryptoAPI functionality has been intercepted. 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a test certificate is never added, then no interception should 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // happen. 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_capi_injector.Get(); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL ok = CertAddCertificateContextToStore( 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) temporary_roots_, certificate->os_cert_handle(), 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERT_STORE_ADD_NEW, NULL); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ok) { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the certificate is already added, return successfully. 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetLastError() == CRYPT_E_EXISTS; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) empty_ = false; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestRootCerts::Clear() { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) empty_ = true; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for (PCCERT_CONTEXT prev_cert = 164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch CertEnumCertificatesInStore(temporary_roots_, NULL); 165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch prev_cert; 166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch prev_cert = CertEnumCertificatesInStore(temporary_roots_, NULL)) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CertDeleteCertificateFromStore(prev_cert); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TestRootCerts::IsEmpty() const { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return empty_; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HCERTCHAINENGINE TestRootCerts::GetChainEngine() const { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsEmpty()) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; // Default chain engine will suffice. 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Windows versions before 7 don't accept the struct size for later versions. 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We report the size of the old struct since we don't need the new members. 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const DWORD kSizeofCertChainEngineConfig = 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER( 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERT_CHAIN_ENGINE_CONFIG, CycleDetectionModulus); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Each HCERTCHAINENGINE caches both the configured system stores and 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // information about each chain that has been built. In order to ensure 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that changes to |temporary_roots_| are properly propagated and that the 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // various caches are flushed, when at least one certificate is added, 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // return a new chain engine for every call. Each chain engine creation 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // should re-open the root store, ensuring the most recent changes are 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // visible. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERT_CHAIN_ENGINE_CONFIG engine_config = { 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kSizeofCertChainEngineConfig 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) engine_config.dwFlags = 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE | 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERT_CHAIN_ENABLE_SHARE_STORE; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HCERTCHAINENGINE chain_engine = NULL; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL ok = CertCreateCertificateChainEngine(&engine_config, &chain_engine); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(ok); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return chain_engine; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TestRootCerts::~TestRootCerts() { 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CertCloseStore(temporary_roots_, 0); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestRootCerts::Init() { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) empty_ = true; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) temporary_roots_ = CertOpenStore( 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERT_STORE_PROV_MEMORY, 0, NULL, 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, NULL); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(temporary_roots_); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 216