• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/374320451): Fix and remove.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "net/cert/internal/trust_store_win.h"
11 
12 #include <string_view>
13 
14 #include "base/containers/span.h"
15 #include "base/containers/to_vector.h"
16 #include "base/hash/sha1.h"
17 #include "base/location.h"
18 #include "base/logging.h"
19 #include "base/memory/ptr_util.h"
20 #include "base/ranges/algorithm.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/threading/scoped_blocking_call.h"
23 #include "net/base/features.h"
24 #include "net/cert/x509_util.h"
25 #include "net/cert/x509_util_win.h"
26 #include "net/third_party/mozilla_win/cert/win_util.h"
27 #include "third_party/boringssl/src/pki/cert_errors.h"
28 #include "third_party/boringssl/src/pki/parsed_certificate.h"
29 
30 namespace net {
31 
32 namespace {
33 
34 // Certificates in the Windows roots store may be used as either trust
35 // anchors or trusted leafs (if self-signed).
36 constexpr bssl::CertificateTrust kRootCertTrust =
37     bssl::CertificateTrust::ForTrustAnchorOrLeaf()
38         .WithEnforceAnchorExpiry()
39         .WithEnforceAnchorConstraints()
40         .WithRequireLeafSelfSigned();
41 
42 // Certificates in the Trusted People store may be trusted leafs (if
43 // self-signed).
44 constexpr bssl::CertificateTrust kTrustedPeopleTrust =
45     bssl::CertificateTrust::ForTrustedLeaf().WithRequireLeafSelfSigned();
46 
47 // Returns true if the cert can be used for server authentication, based on
48 // certificate properties.
49 //
50 // While there are a variety of certificate properties that can affect how
51 // trust is computed, the main property is CERT_ENHKEY_USAGE_PROP_ID, which
52 // is intersected with the certificate's EKU extension (if present).
53 // The intersection is documented in the Remarks section of
54 // CertGetEnhancedKeyUsage, and is as follows:
55 // - No EKU property, and no EKU extension = Trusted for all purpose
56 // - Either an EKU property, or EKU extension, but not both = Trusted only
57 //   for the listed purposes
58 // - Both an EKU property and an EKU extension = Trusted for the set
59 //   intersection of the listed purposes
60 // CertGetEnhancedKeyUsage handles this logic, and if an empty set is
61 // returned, the distinction between the first and third case can be
62 // determined by GetLastError() returning CRYPT_E_NOT_FOUND.
63 //
64 // See:
65 // https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certgetenhancedkeyusage
66 //
67 // If we run into any errors reading the certificate properties, we fail
68 // closed.
IsCertTrustedForServerAuth(PCCERT_CONTEXT cert)69 bool IsCertTrustedForServerAuth(PCCERT_CONTEXT cert) {
70   DWORD usage_size = 0;
71 
72   if (!CertGetEnhancedKeyUsage(cert, 0, nullptr, &usage_size)) {
73     return false;
74   }
75 
76   std::vector<BYTE> usage_bytes(usage_size);
77   CERT_ENHKEY_USAGE* usage =
78       reinterpret_cast<CERT_ENHKEY_USAGE*>(usage_bytes.data());
79   if (!CertGetEnhancedKeyUsage(cert, 0, usage, &usage_size)) {
80     return false;
81   }
82 
83   if (usage->cUsageIdentifier == 0) {
84     // check GetLastError
85     HRESULT error_code = GetLastError();
86 
87     switch (error_code) {
88       case CRYPT_E_NOT_FOUND:
89         return true;
90       case S_OK:
91         return false;
92       default:
93         return false;
94     }
95   }
96 
97   // SAFETY: `usage->rgpszUsageIdentifier` is an array of LPSTR (pointer to null
98   // terminated string) of length `usage->cUsageIdentifier`.
99   base::span<LPSTR> usage_identifiers = UNSAFE_BUFFERS(
100       base::span(usage->rgpszUsageIdentifier, usage->cUsageIdentifier));
101   for (std::string_view eku : usage_identifiers) {
102     if ((eku == szOID_PKIX_KP_SERVER_AUTH) ||
103         (eku == szOID_ANY_ENHANCED_KEY_USAGE)) {
104       return true;
105     }
106   }
107   return false;
108 }
109 
AddCertWithTrust(PCCERT_CONTEXT cert,const bssl::CertificateTrust trust,std::vector<net::PlatformTrustStore::CertWithTrust> * certs)110 void AddCertWithTrust(
111     PCCERT_CONTEXT cert,
112     const bssl::CertificateTrust trust,
113     std::vector<net::PlatformTrustStore::CertWithTrust>* certs) {
114   certs->push_back(net::PlatformTrustStore::CertWithTrust(
115       base::ToVector(x509_util::CertContextAsSpan(cert)), trust));
116 }
117 
118 }  // namespace
119 
120 TrustStoreWin::CertStores::CertStores() = default;
121 TrustStoreWin::CertStores::~CertStores() = default;
122 TrustStoreWin::CertStores::CertStores(CertStores&& other) = default;
123 TrustStoreWin::CertStores& TrustStoreWin::CertStores::operator=(
124     CertStores&& other) = default;
125 
126 // static
127 TrustStoreWin::CertStores
CreateInMemoryStoresForTesting()128 TrustStoreWin::CertStores::CreateInMemoryStoresForTesting() {
129   TrustStoreWin::CertStores stores;
130   stores.roots = crypto::ScopedHCERTSTORE(CertOpenStore(
131       CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, NULL, 0, nullptr));
132   stores.intermediates = crypto::ScopedHCERTSTORE(CertOpenStore(
133       CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, NULL, 0, nullptr));
134   stores.trusted_people = crypto::ScopedHCERTSTORE(CertOpenStore(
135       CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, NULL, 0, nullptr));
136   stores.disallowed = crypto::ScopedHCERTSTORE(CertOpenStore(
137       CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, NULL, 0, nullptr));
138   stores.InitializeAllCertsStore();
139   return stores;
140 }
141 
142 TrustStoreWin::CertStores
CreateNullStoresForTesting()143 TrustStoreWin::CertStores::CreateNullStoresForTesting() {
144   return TrustStoreWin::CertStores();
145 }
146 
147 // static
CreateWithCollections()148 TrustStoreWin::CertStores TrustStoreWin::CertStores::CreateWithCollections() {
149   TrustStoreWin::CertStores stores;
150   stores.roots = crypto::ScopedHCERTSTORE(
151       CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, NULL, 0, nullptr));
152   stores.intermediates = crypto::ScopedHCERTSTORE(
153       CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, NULL, 0, nullptr));
154   stores.trusted_people = crypto::ScopedHCERTSTORE(
155       CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, NULL, 0, nullptr));
156   stores.disallowed = crypto::ScopedHCERTSTORE(
157       CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, NULL, 0, nullptr));
158   stores.InitializeAllCertsStore();
159   return stores;
160 }
161 
InitializeAllCertsStore()162 void TrustStoreWin::CertStores::InitializeAllCertsStore() {
163   all = crypto::ScopedHCERTSTORE(
164       CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, NULL, 0, nullptr));
165   if (is_null()) {
166     return;
167   }
168   // Add intermediate and root cert stores to the all_cert_store collection so
169   // SyncGetIssuersOf will find them. disallowed_cert_store is not added
170   // because the certs are distrusted; making them non-findable in
171   // SyncGetIssuersOf helps us fail path-building faster.
172   // `trusted_people` is not added because it can only contain end-entity
173   // certs, so checking it for issuers during path building is not necessary.
174   if (!CertAddStoreToCollection(all.get(), intermediates.get(),
175                                 /*dwUpdateFlags=*/0, /*dwPriority=*/0)) {
176     return;
177   }
178   if (!CertAddStoreToCollection(all.get(), roots.get(),
179                                 /*dwUpdateFlags=*/0, /*dwPriority=*/0)) {
180     return;
181   }
182 }
183 
184 class TrustStoreWin::Impl {
185  public:
186   // Creates a TrustStoreWin.
Impl()187   Impl() {
188     base::ScopedBlockingCall scoped_blocking_call(
189         FROM_HERE, base::BlockingType::MAY_BLOCK);
190 
191     CertStores stores = CertStores::CreateWithCollections();
192     if (stores.is_null()) {
193       // If there was an error initializing the cert store collections, give
194       // up. The Impl object will still be created but any calls to its public
195       // methods will return no results.
196       return;
197     }
198 
199     // Grab the user-added roots.
200     GatherEnterpriseCertsForLocation(stores.roots.get(),
201                                      CERT_SYSTEM_STORE_LOCAL_MACHINE, L"ROOT");
202     GatherEnterpriseCertsForLocation(
203         stores.roots.get(), CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY,
204         L"ROOT");
205     GatherEnterpriseCertsForLocation(stores.roots.get(),
206                                      CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE,
207                                      L"ROOT");
208     GatherEnterpriseCertsForLocation(stores.roots.get(),
209                                      CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT");
210     GatherEnterpriseCertsForLocation(
211         stores.roots.get(), CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY,
212         L"ROOT");
213 
214     // Grab the user-added intermediates.
215     GatherEnterpriseCertsForLocation(stores.intermediates.get(),
216                                      CERT_SYSTEM_STORE_LOCAL_MACHINE, L"CA");
217     GatherEnterpriseCertsForLocation(
218         stores.intermediates.get(),
219         CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY, L"CA");
220     GatherEnterpriseCertsForLocation(stores.intermediates.get(),
221                                      CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE,
222                                      L"CA");
223     GatherEnterpriseCertsForLocation(stores.intermediates.get(),
224                                      CERT_SYSTEM_STORE_CURRENT_USER, L"CA");
225     GatherEnterpriseCertsForLocation(
226         stores.intermediates.get(), CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY,
227         L"CA");
228 
229     // Grab the user-added trusted server certs. Trusted end-entity certs are
230     // only allowed for server auth in the "local machine" store, but not in the
231     // "current user" store.
232     GatherEnterpriseCertsForLocation(stores.trusted_people.get(),
233                                      CERT_SYSTEM_STORE_LOCAL_MACHINE,
234                                      L"TrustedPeople");
235     GatherEnterpriseCertsForLocation(
236         stores.trusted_people.get(),
237         CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY, L"TrustedPeople");
238     GatherEnterpriseCertsForLocation(stores.trusted_people.get(),
239                                      CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE,
240                                      L"TrustedPeople");
241 
242     // Grab the user-added disallowed certs.
243     GatherEnterpriseCertsForLocation(stores.disallowed.get(),
244                                      CERT_SYSTEM_STORE_LOCAL_MACHINE,
245                                      L"Disallowed");
246     GatherEnterpriseCertsForLocation(
247         stores.disallowed.get(), CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY,
248         L"Disallowed");
249     GatherEnterpriseCertsForLocation(stores.disallowed.get(),
250                                      CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE,
251                                      L"Disallowed");
252     GatherEnterpriseCertsForLocation(
253         stores.disallowed.get(), CERT_SYSTEM_STORE_CURRENT_USER, L"Disallowed");
254     GatherEnterpriseCertsForLocation(
255         stores.disallowed.get(), CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY,
256         L"Disallowed");
257 
258     // Auto-sync all of the cert stores to get updates to the cert store.
259     // Auto-syncing on all_certs_store seems to work to resync the nested
260     // stores, although the docs at
261     // https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certcontrolstore
262     // are somewhat unclear. If and when root store changes are linked to
263     // clearing various caches, this should be replaced with
264     // CERT_STORE_CTRL_NOTIFY_CHANGE and CERT_STORE_CTRL_RESYNC.
265     if (!CertControlStore(stores.all.get(), 0, CERT_STORE_CTRL_AUTO_RESYNC,
266                           0) ||
267         !CertControlStore(stores.trusted_people.get(), 0,
268                           CERT_STORE_CTRL_AUTO_RESYNC, 0) ||
269         !CertControlStore(stores.disallowed.get(), 0,
270                           CERT_STORE_CTRL_AUTO_RESYNC, 0)) {
271       PLOG(ERROR) << "Error enabling CERT_STORE_CTRL_AUTO_RESYNC";
272     }
273 
274     root_cert_store_ = std::move(stores.roots);
275     intermediate_cert_store_ = std::move(stores.intermediates);
276     trusted_people_cert_store_ = std::move(stores.trusted_people);
277     disallowed_cert_store_ = std::move(stores.disallowed);
278     all_certs_store_ = std::move(stores.all);
279   }
280 
Impl(CertStores stores)281   Impl(CertStores stores)
282       : root_cert_store_(std::move(stores.roots)),
283         intermediate_cert_store_(std::move(stores.intermediates)),
284         all_certs_store_(std::move(stores.all)),
285         trusted_people_cert_store_(std::move(stores.trusted_people)),
286         disallowed_cert_store_(std::move(stores.disallowed)) {}
287 
288   ~Impl() = default;
289   Impl(const Impl& other) = delete;
290   Impl& operator=(const Impl& other) = delete;
291 
SyncGetIssuersOf(const bssl::ParsedCertificate * cert,bssl::ParsedCertificateList * issuers)292   void SyncGetIssuersOf(const bssl::ParsedCertificate* cert,
293                         bssl::ParsedCertificateList* issuers) {
294     if (!root_cert_store_.get() || !intermediate_cert_store_.get() ||
295         !trusted_people_cert_store_.get() || !all_certs_store_.get() ||
296         !disallowed_cert_store_.get()) {
297       return;
298     }
299     base::span<const uint8_t> issuer_span = cert->issuer_tlv();
300 
301     CERT_NAME_BLOB cert_issuer_blob;
302     cert_issuer_blob.cbData = static_cast<DWORD>(issuer_span.size());
303     cert_issuer_blob.pbData = const_cast<uint8_t*>(issuer_span.data());
304 
305     PCCERT_CONTEXT cert_from_store = nullptr;
306     while ((cert_from_store = CertFindCertificateInStore(
307                 all_certs_store_.get(), X509_ASN_ENCODING, 0,
308                 CERT_FIND_SUBJECT_NAME, &cert_issuer_blob, cert_from_store))) {
309       bssl::UniquePtr<CRYPTO_BUFFER> der_crypto = x509_util::CreateCryptoBuffer(
310           x509_util::CertContextAsSpan(cert_from_store));
311       bssl::CertErrors errors;
312       bssl::ParsedCertificate::CreateAndAddToVector(
313           std::move(der_crypto), x509_util::DefaultParseCertificateOptions(),
314           issuers, &errors);
315     }
316   }
317 
GetTrust(const bssl::ParsedCertificate * cert)318   bssl::CertificateTrust GetTrust(const bssl::ParsedCertificate* cert) {
319     if (!root_cert_store_.get() || !intermediate_cert_store_.get() ||
320         !trusted_people_cert_store_.get() || !all_certs_store_.get() ||
321         !disallowed_cert_store_.get()) {
322       return bssl::CertificateTrust::ForUnspecified();
323     }
324 
325     base::span<const uint8_t> cert_span = cert->der_cert();
326     base::SHA1Digest cert_hash = base::SHA1Hash(cert_span);
327     CRYPT_HASH_BLOB cert_hash_blob;
328     cert_hash_blob.cbData = static_cast<DWORD>(cert_hash.size());
329     cert_hash_blob.pbData = cert_hash.data();
330 
331     PCCERT_CONTEXT cert_from_store = nullptr;
332 
333     // Check Disallowed store first.
334     while ((cert_from_store = CertFindCertificateInStore(
335                 disallowed_cert_store_.get(), X509_ASN_ENCODING, 0,
336                 CERT_FIND_SHA1_HASH, &cert_hash_blob, cert_from_store))) {
337       base::span<const uint8_t> cert_from_store_span =
338           x509_util::CertContextAsSpan(cert_from_store);
339       // If a cert is in the windows distruted store, it is considered
340       // distrusted for all purporses. EKU isn't checked. See crbug.com/1355961.
341       if (base::ranges::equal(cert_span, cert_from_store_span)) {
342         return bssl::CertificateTrust::ForDistrusted();
343       }
344     }
345 
346     while ((cert_from_store = CertFindCertificateInStore(
347                 root_cert_store_.get(), X509_ASN_ENCODING, 0,
348                 CERT_FIND_SHA1_HASH, &cert_hash_blob, cert_from_store))) {
349       base::span<const uint8_t> cert_from_store_span =
350           x509_util::CertContextAsSpan(cert_from_store);
351       if (base::ranges::equal(cert_span, cert_from_store_span)) {
352         // If we find at least one version of the cert that is trusted for TLS
353         // Server Auth, we will trust the cert.
354         if (IsCertTrustedForServerAuth(cert_from_store)) {
355           return kRootCertTrust;
356         }
357       }
358     }
359 
360     while ((cert_from_store = CertFindCertificateInStore(
361                 trusted_people_cert_store_.get(), X509_ASN_ENCODING, 0,
362                 CERT_FIND_SHA1_HASH, &cert_hash_blob, cert_from_store))) {
363       base::span<const uint8_t> cert_from_store_span =
364           x509_util::CertContextAsSpan(cert_from_store);
365       if (base::ranges::equal(cert_span, cert_from_store_span)) {
366         // If we find at least one version of the cert that is trusted for TLS
367         // Server Auth, we will trust the cert.
368         if (IsCertTrustedForServerAuth(cert_from_store)) {
369           return kTrustedPeopleTrust;
370         }
371       }
372     }
373 
374     // If we fall through here, we've either
375     //
376     // (a) found the cert but it is not usable for server auth. Treat this as
377     //     Unspecified trust. Originally this was treated as Distrusted, but
378     //     this is inconsistent with how the Windows verifier works, which is to
379     //     union all of the EKU usages for all instances of the cert, whereas
380     //     sending back Distrusted would not do that.
381     //
382     // or
383     //
384     // (b) Haven't found the cert. Tell everyone Unspecified.
385     return bssl::CertificateTrust::ForUnspecified();
386   }
387 
GetAllUserAddedCerts()388   std::vector<net::PlatformTrustStore::CertWithTrust> GetAllUserAddedCerts() {
389     std::vector<net::PlatformTrustStore::CertWithTrust> certs;
390     if (!root_cert_store_.get() || !intermediate_cert_store_.get() ||
391         !trusted_people_cert_store_.get() || !all_certs_store_.get() ||
392         !disallowed_cert_store_.get()) {
393       return certs;
394     }
395 
396     PCCERT_CONTEXT cert_from_store = nullptr;
397     while ((cert_from_store = CertEnumCertificatesInStore(
398                 disallowed_cert_store_.get(), cert_from_store))) {
399       AddCertWithTrust(cert_from_store, bssl::CertificateTrust::ForDistrusted(),
400                        &certs);
401     }
402 
403     while ((cert_from_store = CertEnumCertificatesInStore(
404                 trusted_people_cert_store_.get(), cert_from_store))) {
405       if (IsCertTrustedForServerAuth(cert_from_store)) {
406         AddCertWithTrust(cert_from_store, kTrustedPeopleTrust, &certs);
407       }
408     }
409 
410     while ((cert_from_store = CertEnumCertificatesInStore(
411                 root_cert_store_.get(), cert_from_store))) {
412       if (IsCertTrustedForServerAuth(cert_from_store)) {
413         AddCertWithTrust(cert_from_store, kRootCertTrust, &certs);
414       }
415     }
416 
417     while ((cert_from_store = CertEnumCertificatesInStore(
418                 intermediate_cert_store_.get(), cert_from_store))) {
419       AddCertWithTrust(cert_from_store,
420                        bssl::CertificateTrust::ForUnspecified(), &certs);
421     }
422 
423     return certs;
424   }
425 
426  private:
427   // Cert Collection containing all user-added trust anchors.
428   crypto::ScopedHCERTSTORE root_cert_store_;
429 
430   // Cert Collection containing all user-added intermediates.
431   crypto::ScopedHCERTSTORE intermediate_cert_store_;
432 
433   // Cert Collection for searching via SyncGetIssuersOf()
434   crypto::ScopedHCERTSTORE all_certs_store_;
435 
436   // Cert Collection containing all user-added trust leafs.
437   crypto::ScopedHCERTSTORE trusted_people_cert_store_;
438 
439   // Cert Collection for all disallowed certs.
440   crypto::ScopedHCERTSTORE disallowed_cert_store_;
441 };
442 
443 // TODO(crbug.com/40784681): support CTLs.
444 TrustStoreWin::TrustStoreWin() = default;
445 
InitializeStores()446 void TrustStoreWin::InitializeStores() {
447   // Don't need return value
448   MaybeInitializeAndGetImpl();
449 }
450 
MaybeInitializeAndGetImpl()451 TrustStoreWin::Impl* TrustStoreWin::MaybeInitializeAndGetImpl() {
452   base::AutoLock lock(init_lock_);
453   if (!impl_) {
454     impl_ = std::make_unique<TrustStoreWin::Impl>();
455   }
456   return impl_.get();
457 }
458 
CreateForTesting(CertStores stores)459 std::unique_ptr<TrustStoreWin> TrustStoreWin::CreateForTesting(
460     CertStores stores) {
461   return base::WrapUnique(new TrustStoreWin(
462       std::make_unique<TrustStoreWin::Impl>(std::move(stores))));
463 }
464 
TrustStoreWin(std::unique_ptr<Impl> impl)465 TrustStoreWin::TrustStoreWin(std::unique_ptr<Impl> impl)
466     : impl_(std::move(impl)) {}
467 
468 TrustStoreWin::~TrustStoreWin() = default;
469 
SyncGetIssuersOf(const bssl::ParsedCertificate * cert,bssl::ParsedCertificateList * issuers)470 void TrustStoreWin::SyncGetIssuersOf(const bssl::ParsedCertificate* cert,
471                                      bssl::ParsedCertificateList* issuers) {
472   MaybeInitializeAndGetImpl()->SyncGetIssuersOf(cert, issuers);
473 }
474 
475 // As documented in IsCertTrustedForServerAuth(), on Windows, the
476 // set of extended key usages present in a certificate can be further
477 // scoped down by user setting; effectively, disabling a given EKU for
478 // a given intermediate or root.
479 //
480 // Windows uses this during path building when filtering the EKUs; if it
481 // encounters this property, it uses the combined EKUs to determine
482 // whether to continue path building, but doesn't treat the certificate
483 // as affirmatively revoked/distrusted.
484 //
485 // This behaviour is replicated here by returning Unspecified trust if
486 // we find instances of the cert that do not have the correct EKUs set
487 // for TLS Server Auth. This allows path building to continue and allows
488 // us to later trust the cert if it is present in Chrome Root Store.
489 //
490 // Windows does have some idiosyncrasies here, which result in the
491 // following treatment:
492 //
493 //   - If a certificate is in the Disallowed store, it is distrusted for
494 //     all purposes regardless of any EKUs that are set.
495 //   - If a certificate is in the ROOT store, and usable for TLS Server Auth,
496 //     then it's trusted.
497 //   - If a certificate is in the root store, and lacks the EKU, then continue
498 //     path building, but don't treat it as trusted (aka Unspecified).
499 //   - If we can't find the cert anywhere, then continue path
500 //     building, but don't treat it as trusted (aka Unspecified).
501 //
502 // If a certificate is found multiple times in the ROOT store, it is trusted
503 // for TLS server auth if any instance of the certificate found
504 // is usable for TLS server auth.
GetTrust(const bssl::ParsedCertificate * cert)505 bssl::CertificateTrust TrustStoreWin::GetTrust(
506     const bssl::ParsedCertificate* cert) {
507   return MaybeInitializeAndGetImpl()->GetTrust(cert);
508 }
509 
510 std::vector<net::PlatformTrustStore::CertWithTrust>
GetAllUserAddedCerts()511 TrustStoreWin::GetAllUserAddedCerts() {
512   return MaybeInitializeAndGetImpl()->GetAllUserAddedCerts();
513 }
514 
515 }  // namespace net
516