forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Windows implementation of Chrome Root Store
This wires up the Chrome Root Store on Windows, including limited support for interaction with user-added root certificates. On Windows, the logical "ROOT" store [1] for the local machine will also open up the AuthRoot store, which is Microsoft's builtin root store. The goal here is not to import certificates that Microsoft has trusted, and only import certificates that the user or enterprise has manually trusted. To achieve this, rather than opening up the logical "Root" (e.g. CERT_STORE_PROV_SYSTEM), the individual physical stores are opened (e.g. CERT_STORE_PROV_SYSTEM_REGISTRY) that make up the logical store [2], excluding AuthRoot. This only implements support for positive trust, for the moment, and only for certificates, not for CTLs. It also does not support negative trust, nor does it consider the trust purposes a root is enabled for (e.g. only enabling for S/MIME). [1] https://docs.microsoft.com/en-us/windows/win32/seccrypto/logical-and-physical-stores [2] https://docs.microsoft.com/en-us/windows/win32/seccrypto/system-store-locations Bug: 1233012 Change-Id: I282f453ff57b3f648f31bfb7cac8aa37e2171390 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3052905 Reviewed-by: Ryan Sleevi <rsleevi@chromium.org> Reviewed-by: Mike Pinkerton <pinkerton@chromium.org> Commit-Queue: Hubert Chao <hchao@chromium.org> Cr-Commit-Position: refs/heads/master@{#912276}
- Loading branch information
Hubert Chao
authored and
Chromium LUCI CQ
committed
Aug 16, 2021
1 parent
83a2dae
commit 78114c5
Showing
15 changed files
with
925 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// Copyright (c) 2021 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "net/cert/internal/trust_store_win.h" | ||
|
||
#include "base/hash/sha1.h" | ||
#include "base/logging.h" | ||
#include "base/memory/ptr_util.h" | ||
#include "base/ranges/algorithm.h" | ||
#include "base/strings/string_number_conversions.h" | ||
#include "net/cert/internal/cert_errors.h" | ||
#include "net/cert/internal/parsed_certificate.h" | ||
#include "net/cert/x509_util.h" | ||
#include "net/third_party/mozilla_win/cert/win_util.h" | ||
|
||
namespace net { | ||
|
||
// TODO(https://crbug.com/1239258): import and use distrust settings. | ||
// TODO(https://crbug.com/1239260): limit certs if they have EKU settings. | ||
// TODO(https://crbug.com/1239268): support CTLs. | ||
std::unique_ptr<TrustStoreWin> TrustStoreWin::Create() { | ||
crypto::ScopedHCERTSTORE root_cert_store( | ||
CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, NULL, 0, nullptr)); | ||
crypto::ScopedHCERTSTORE intermediate_cert_store( | ||
CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, NULL, 0, nullptr)); | ||
crypto::ScopedHCERTSTORE all_certs_store( | ||
CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, NULL, 0, nullptr)); | ||
if (!root_cert_store.get() || !intermediate_cert_store.get() || | ||
!all_certs_store.get()) { | ||
return nullptr; | ||
} | ||
|
||
// Grab the user-added roots. | ||
GatherEnterpriseCertsForLocation(root_cert_store.get(), | ||
CERT_SYSTEM_STORE_LOCAL_MACHINE, L"ROOT"); | ||
GatherEnterpriseCertsForLocation(root_cert_store.get(), | ||
CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY, | ||
L"ROOT"); | ||
GatherEnterpriseCertsForLocation(root_cert_store.get(), | ||
CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, | ||
L"ROOT"); | ||
GatherEnterpriseCertsForLocation(root_cert_store.get(), | ||
CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT"); | ||
GatherEnterpriseCertsForLocation(root_cert_store.get(), | ||
CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY, | ||
L"ROOT"); | ||
|
||
// Grab the user-added intermediates. | ||
GatherEnterpriseCertsForLocation(intermediate_cert_store.get(), | ||
CERT_SYSTEM_STORE_LOCAL_MACHINE, L"CA"); | ||
GatherEnterpriseCertsForLocation(intermediate_cert_store.get(), | ||
CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY, | ||
L"CA"); | ||
GatherEnterpriseCertsForLocation(intermediate_cert_store.get(), | ||
CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, | ||
L"CA"); | ||
GatherEnterpriseCertsForLocation(intermediate_cert_store.get(), | ||
CERT_SYSTEM_STORE_CURRENT_USER, L"CA"); | ||
GatherEnterpriseCertsForLocation(intermediate_cert_store.get(), | ||
CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY, | ||
L"CA"); | ||
|
||
CertAddStoreToCollection(all_certs_store.get(), intermediate_cert_store.get(), | ||
/*dwUpdateFlags=*/0, /*dwPriority=*/0); | ||
|
||
CertAddStoreToCollection(all_certs_store.get(), root_cert_store.get(), | ||
/*dwUpdateFlags=*/0, /*dwPriority=*/0); | ||
return base::WrapUnique(new TrustStoreWin(std::move(root_cert_store), | ||
std::move(all_certs_store))); | ||
} | ||
|
||
std::unique_ptr<TrustStoreWin> TrustStoreWin::CreateForTesting( | ||
crypto::ScopedHCERTSTORE root_cert_store, | ||
crypto::ScopedHCERTSTORE all_certs_store) { | ||
return base::WrapUnique(new TrustStoreWin(std::move(root_cert_store), | ||
std::move(all_certs_store))); | ||
} | ||
|
||
TrustStoreWin::TrustStoreWin(crypto::ScopedHCERTSTORE root_cert_store, | ||
crypto::ScopedHCERTSTORE all_certs_store) | ||
: root_cert_store_(std::move(root_cert_store)), | ||
all_certs_store_(std::move(all_certs_store)) {} | ||
|
||
TrustStoreWin::~TrustStoreWin() = default; | ||
|
||
void TrustStoreWin::SyncGetIssuersOf(const ParsedCertificate* cert, | ||
ParsedCertificateList* issuers) { | ||
base::span<const uint8_t> issuer_span = cert->issuer_tlv().AsSpan(); | ||
|
||
CERT_NAME_BLOB cert_issuer_blob; | ||
cert_issuer_blob.cbData = static_cast<DWORD>(issuer_span.size()); | ||
cert_issuer_blob.pbData = const_cast<uint8_t*>(issuer_span.data()); | ||
|
||
PCCERT_CONTEXT cert_from_store = nullptr; | ||
// TODO(https://crbug.com/1239270): figure out if this is thread-safe or if we | ||
// need locking here | ||
while ((cert_from_store = CertFindCertificateInStore( | ||
all_certs_store_.get(), X509_ASN_ENCODING, 0, | ||
CERT_FIND_SUBJECT_NAME, &cert_issuer_blob, cert_from_store))) { | ||
bssl::UniquePtr<CRYPTO_BUFFER> der_crypto = x509_util::CreateCryptoBuffer( | ||
cert_from_store->pbCertEncoded, cert_from_store->cbCertEncoded); | ||
CertErrors errors; | ||
ParsedCertificate::CreateAndAddToVector( | ||
std::move(der_crypto), x509_util::DefaultParseCertificateOptions(), | ||
issuers, &errors); | ||
} | ||
} | ||
|
||
void TrustStoreWin::GetTrust(const scoped_refptr<ParsedCertificate>& cert, | ||
CertificateTrust* trust, | ||
base::SupportsUserData* debug_data) const { | ||
base::span<const uint8_t> cert_span = cert->der_cert().AsSpan(); | ||
base::SHA1Digest cert_hash = base::SHA1HashSpan(cert_span); | ||
CRYPT_HASH_BLOB cert_hash_blob; | ||
cert_hash_blob.cbData = static_cast<DWORD>(cert_hash.size()); | ||
cert_hash_blob.pbData = cert_hash.data(); | ||
|
||
PCCERT_CONTEXT cert_from_store = nullptr; | ||
|
||
// TODO(https://crbug.com/1239270): figure out if this is thread-safe or if we | ||
// need locking here | ||
while ((cert_from_store = CertFindCertificateInStore( | ||
root_cert_store_.get(), X509_ASN_ENCODING, 0, CERT_FIND_SHA1_HASH, | ||
&cert_hash_blob, cert_from_store))) { | ||
base::span<const uint8_t> cert_from_store_span = base::make_span( | ||
cert_from_store->pbCertEncoded, cert_from_store->cbCertEncoded); | ||
|
||
if (base::ranges::equal(cert_span, cert_from_store_span)) { | ||
// Found cert, yay! | ||
*trust = CertificateTrust::ForTrustAnchor(); | ||
// Free before returning | ||
CertFreeCertificateContext(cert_from_store); | ||
return; | ||
} | ||
} | ||
|
||
// Didn't find cert, return Unspecified Trust. | ||
*trust = CertificateTrust::ForUnspecified(); | ||
} | ||
|
||
} // namespace net |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// Copyright 2021 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef NET_CERT_INTERNAL_TRUST_STORE_WIN_H_ | ||
#define NET_CERT_INTERNAL_TRUST_STORE_WIN_H_ | ||
|
||
#include "base/memory/ptr_util.h" | ||
#include "base/memory/ref_counted.h" | ||
#include "base/win/wincrypt_shim.h" | ||
#include "crypto/scoped_capi_types.h" | ||
#include "net/base/net_export.h" | ||
#include "net/cert/internal/trust_store.h" | ||
|
||
namespace net { | ||
|
||
// TrustStoreWin is an implementation of TrustStore which uses the Windows cert | ||
// systems to find user-added trust anchors for path building. It ignores the | ||
// Windows builtin trust anchors. This TrustStore is thread-safe (we think). | ||
// TODO(https://crbug.com/1239270): confirm this is thread safe. | ||
class NET_EXPORT TrustStoreWin : public TrustStore { | ||
public: | ||
~TrustStoreWin() override; | ||
TrustStoreWin(const TrustStoreWin& other) = delete; | ||
TrustStoreWin& operator=(const TrustStoreWin& other) = delete; | ||
|
||
// Creates a TrustStoreWin by reading user settings from Windows system | ||
// CertStores. Returns nullptr on failure. | ||
static std::unique_ptr<TrustStoreWin> Create(); | ||
|
||
// Creates a TrustStoreWin for testing, which will treat `root_cert_store` | ||
// as if it's the source of truth for roots for `GetTrust, | ||
// and `all_certs_store` as the store for locating certificates during | ||
// `SyncGetIssuersOf`. | ||
static std::unique_ptr<TrustStoreWin> CreateForTesting( | ||
crypto::ScopedHCERTSTORE root_cert_store, | ||
crypto::ScopedHCERTSTORE all_certs_store); | ||
|
||
void SyncGetIssuersOf(const ParsedCertificate* cert, | ||
ParsedCertificateList* issuers) override; | ||
|
||
void GetTrust(const scoped_refptr<ParsedCertificate>& cert, | ||
CertificateTrust* trust, | ||
base::SupportsUserData* debug_data) const override; | ||
|
||
private: | ||
TrustStoreWin(crypto::ScopedHCERTSTORE root_cert_store, | ||
crypto::ScopedHCERTSTORE all_certs_store); | ||
|
||
// Cert Collection containing all user-added trust anchors. | ||
crypto::ScopedHCERTSTORE root_cert_store_; | ||
|
||
// Cert Collection for searching via SyncGetIssuersOf() | ||
crypto::ScopedHCERTSTORE all_certs_store_; | ||
}; | ||
|
||
} // namespace net | ||
|
||
#endif // NET_CERT_INTERNAL_TRUST_STORE_WIN_H_ |
Oops, something went wrong.