1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_CERT_TEST_ROOT_CERTS_H_
#define NET_CERT_TEST_ROOT_CERTS_H_
#include <set>
#include "base/containers/span.h"
#include "base/lazy_instance.h"
#include "base/memory/scoped_refptr.h"
#include "base/synchronization/lock.h"
#include "build/build_config.h"
#include "net/base/net_export.h"
#include "third_party/boringssl/src/pki/trust_store.h"
#include "third_party/boringssl/src/pki/trust_store_in_memory.h"
#if BUILDFLAG(IS_IOS)
#include <CoreFoundation/CFArray.h>
#include <Security/SecTrust.h>
#include "base/apple/scoped_cftyperef.h"
#endif
namespace net {
class X509Certificate;
typedef std::vector<scoped_refptr<X509Certificate>> CertificateList;
class ThreadSafeTrustStoreInMemory : public bssl::TrustStore {
public:
// TrustStoreInMemory wrappers:
bool IsEmpty() const;
void Clear();
void AddCertificate(std::shared_ptr<const bssl::ParsedCertificate> cert,
const bssl::CertificateTrust& trust);
// TrustStore implementation:
void SyncGetIssuersOf(const bssl::ParsedCertificate* cert,
bssl::ParsedCertificateList* issuers) override;
bssl::CertificateTrust GetTrust(const bssl::ParsedCertificate* cert) override;
private:
mutable base::Lock lock_;
bssl::TrustStoreInMemory impl_ GUARDED_BY(lock_);
};
// TestRootCerts is a helper class for unit tests that is used to
// artificially mark a certificate as trusted, independent of the local
// machine configuration.
//
// Test roots can be added using the ScopedTestRoot class below. See the
// class documentation for usage and limitations.
class NET_EXPORT TestRootCerts {
public:
// Obtains the Singleton instance to the trusted certificates.
static TestRootCerts* GetInstance();
TestRootCerts(const TestRootCerts&) = delete;
TestRootCerts& operator=(const TestRootCerts&) = delete;
// Returns true if an instance exists, without forcing an initialization.
static bool HasInstance();
// Clears the trusted status of any certificates that were previously
// marked trusted via Add().
void Clear();
// Returns true if there are no certificates that have been marked trusted.
bool IsEmpty() const;
// Returns true if `der_cert` has been marked as a known root for testing.
bool IsKnownRoot(base::span<const uint8_t> der_cert) const;
#if BUILDFLAG(IS_IOS)
// Modifies the root certificates of |trust_ref| to include the
// certificates stored in |temporary_roots_|. If IsEmpty() is true, this
// does not modify |trust_ref|.
OSStatus FixupSecTrustRef(SecTrustRef trust_ref) const;
#endif
bssl::TrustStore* test_trust_store() { return &test_trust_store_; }
private:
friend struct base::LazyInstanceTraitsBase<TestRootCerts>;
friend class ScopedTestRoot;
friend class ScopedTestKnownRoot;
TestRootCerts();
~TestRootCerts();
// Marks |certificate| as trusted in the effective trust store
// used by CertVerifier::Verify(). Returns false if the
// certificate could not be marked trusted.
bool Add(X509Certificate* certificate, bssl::CertificateTrust trust);
// Marks |der_cert| as a known root. Does not change trust.
void AddKnownRoot(base::span<const uint8_t> der_cert);
// Performs platform-dependent operations.
void Init() EXCLUSIVE_LOCKS_REQUIRED(lock_);
bool AddImpl(X509Certificate* certificate) EXCLUSIVE_LOCKS_REQUIRED(lock_);
void ClearImpl() EXCLUSIVE_LOCKS_REQUIRED(lock_);
// `test_trust_store_` uses its own internal lock rather than the
// TestRootCerts::lock_, since a pointer to the trust store is returned by
// `test_trust_store` the methods on the trust store must themselves be
// thread-safe.
ThreadSafeTrustStoreInMemory test_trust_store_;
mutable base::Lock lock_;
#if BUILDFLAG(IS_IOS)
base::apple::ScopedCFTypeRef<CFMutableArrayRef> temporary_roots_
GUARDED_BY(lock_);
#endif
std::set<std::string, std::less<>> test_known_roots_ GUARDED_BY(lock_);
};
// Scoped helper for unittests to handle safely managing trusted roots.
//
// Limitations:
// Multiple instances of ScopedTestRoot may be created at once, which will
// trust the union of the certs provided. However, when one of the
// ScopedTestRoot instances removes its trust, either by going out of scope, or
// by Reset() being called, *all* test root certs will be untrusted. (This
// limitation could be removed if a reason arises.)
class NET_EXPORT ScopedTestRoot {
public:
ScopedTestRoot();
// Creates a ScopedTestRoot that adds |cert| to the TestRootCerts store.
// |trust| may be specified to change the details of how the trust is
// interpreted (applies only to CertVerifyProcBuiltin).
explicit ScopedTestRoot(
scoped_refptr<X509Certificate> cert,
bssl::CertificateTrust trust = bssl::CertificateTrust::ForTrustAnchor());
// Creates a ScopedTestRoot that adds |certs| to the TestRootCerts store.
// |trust| may be specified to change the details of how the trust is
// interpreted (applies only to CertVerifyProcBuiltin).
explicit ScopedTestRoot(
CertificateList certs,
bssl::CertificateTrust trust = bssl::CertificateTrust::ForTrustAnchor());
ScopedTestRoot(const ScopedTestRoot&) = delete;
ScopedTestRoot& operator=(const ScopedTestRoot&) = delete;
ScopedTestRoot(ScopedTestRoot&& other);
ScopedTestRoot& operator=(ScopedTestRoot&& other);
~ScopedTestRoot();
// Assigns |certs| to be the new test root certs. If |certs| is empty, undoes
// any work the ScopedTestRoot may have previously done.
// If |certs_| contains certificates (due to a prior call to Reset or due to
// certs being passed at construction), the existing TestRootCerts store is
// cleared.
void Reset(
CertificateList certs,
bssl::CertificateTrust trust = bssl::CertificateTrust::ForTrustAnchor());
// Returns true if this ScopedTestRoot has no certs assigned.
bool IsEmpty() const { return certs_.empty(); }
private:
CertificateList certs_;
};
// Scoped helper for unittests to handle safely marking additional roots as
// known roots. Note that this does not trust the root. If the root should be
// trusted, a ScopedTestRoot should also be created.
//
// Limitations:
// Same as for ScopedTestRoot, see comment above.
class NET_EXPORT ScopedTestKnownRoot {
public:
ScopedTestKnownRoot();
explicit ScopedTestKnownRoot(X509Certificate* cert);
ScopedTestKnownRoot(const ScopedTestKnownRoot&) = delete;
ScopedTestKnownRoot& operator=(const ScopedTestKnownRoot&) = delete;
ScopedTestKnownRoot(ScopedTestKnownRoot&& other) = delete;
ScopedTestKnownRoot& operator=(ScopedTestKnownRoot&& other) = delete;
~ScopedTestKnownRoot();
private:
CertificateList certs_;
};
} // namespace net
#endif // NET_CERT_TEST_ROOT_CERTS_H_
|