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 #include "net/cert/internal/trust_store_chrome.h"
6
7 #include <optional>
8
9 #include "base/containers/span.h"
10 #include "base/logging.h"
11 #include "base/memory/ptr_util.h"
12 #include "net/cert/root_store_proto_lite/root_store.pb.h"
13 #include "net/cert/x509_certificate.h"
14 #include "net/cert/x509_util.h"
15 #include "third_party/boringssl/src/include/openssl/pool.h"
16 #include "third_party/boringssl/src/pki/cert_errors.h"
17 #include "third_party/boringssl/src/pki/parsed_certificate.h"
18
19 namespace net {
20
21 namespace {
22 #include "net/data/ssl/chrome_root_store/chrome-root-store-inc.cc"
23 } // namespace
24
ChromeRootCertConstraints(std::optional<base::Time> sct_not_after,std::optional<base::Time> sct_all_after,std::optional<base::Version> min_version,std::optional<base::Version> max_version_exclusive)25 ChromeRootCertConstraints::ChromeRootCertConstraints(
26 std::optional<base::Time> sct_not_after,
27 std::optional<base::Time> sct_all_after,
28 std::optional<base::Version> min_version,
29 std::optional<base::Version> max_version_exclusive)
30 : sct_not_after(sct_not_after),
31 sct_all_after(sct_all_after),
32 min_version(std::move(min_version)),
33 max_version_exclusive(std::move(max_version_exclusive)) {}
ChromeRootCertConstraints(const StaticChromeRootCertConstraints & constraints)34 ChromeRootCertConstraints::ChromeRootCertConstraints(
35 const StaticChromeRootCertConstraints& constraints)
36 : sct_not_after(constraints.sct_not_after),
37 sct_all_after(constraints.sct_all_after),
38 min_version(constraints.min_version),
39 max_version_exclusive(constraints.max_version_exclusive) {
40 if (min_version) {
41 CHECK(min_version->IsValid());
42 }
43 if (max_version_exclusive) {
44 CHECK(max_version_exclusive->IsValid());
45 }
46 }
47 ChromeRootCertConstraints::~ChromeRootCertConstraints() = default;
48 ChromeRootCertConstraints::ChromeRootCertConstraints(
49 const ChromeRootCertConstraints& other) = default;
50 ChromeRootCertConstraints::ChromeRootCertConstraints(
51 ChromeRootCertConstraints&& other) = default;
52 ChromeRootCertConstraints& ChromeRootCertConstraints::operator=(
53 const ChromeRootCertConstraints& other) = default;
54 ChromeRootCertConstraints& ChromeRootCertConstraints::operator=(
55 ChromeRootCertConstraints&& other) = default;
56
Anchor(std::shared_ptr<const bssl::ParsedCertificate> certificate,std::vector<ChromeRootCertConstraints> constraints)57 ChromeRootStoreData::Anchor::Anchor(
58 std::shared_ptr<const bssl::ParsedCertificate> certificate,
59 std::vector<ChromeRootCertConstraints> constraints)
60 : certificate(std::move(certificate)),
61 constraints(std::move(constraints)) {}
62 ChromeRootStoreData::Anchor::~Anchor() = default;
63
64 ChromeRootStoreData::Anchor::Anchor(const Anchor& other) = default;
65 ChromeRootStoreData::Anchor::Anchor(Anchor&& other) = default;
66 ChromeRootStoreData::Anchor& ChromeRootStoreData::Anchor::operator=(
67 const ChromeRootStoreData::Anchor& other) = default;
68 ChromeRootStoreData::Anchor& ChromeRootStoreData::Anchor::operator=(
69 ChromeRootStoreData::Anchor&& other) = default;
70
71 ChromeRootStoreData::ChromeRootStoreData() = default;
72 ChromeRootStoreData::~ChromeRootStoreData() = default;
73
74 ChromeRootStoreData::ChromeRootStoreData(const ChromeRootStoreData& other) =
75 default;
76 ChromeRootStoreData::ChromeRootStoreData(ChromeRootStoreData&& other) = default;
77 ChromeRootStoreData& ChromeRootStoreData::operator=(
78 const ChromeRootStoreData& other) = default;
79 ChromeRootStoreData& ChromeRootStoreData::operator=(
80 ChromeRootStoreData&& other) = default;
81
82 std::optional<ChromeRootStoreData>
CreateChromeRootStoreData(const chrome_root_store::RootStore & proto)83 ChromeRootStoreData::CreateChromeRootStoreData(
84 const chrome_root_store::RootStore& proto) {
85 ChromeRootStoreData root_store_data;
86
87 for (auto& anchor : proto.trust_anchors()) {
88 if (anchor.der().empty()) {
89 LOG(ERROR) << "Error anchor with empty DER in update";
90 return std::nullopt;
91 }
92
93 auto parsed = bssl::ParsedCertificate::Create(
94 net::x509_util::CreateCryptoBuffer(anchor.der()),
95 net::x509_util::DefaultParseCertificateOptions(), nullptr);
96 if (!parsed) {
97 LOG(ERROR) << "Error parsing cert for update";
98 return std::nullopt;
99 }
100
101 std::vector<ChromeRootCertConstraints> constraints;
102 for (const auto& constraint : anchor.constraints()) {
103 std::optional<base::Version> min_version;
104 if (constraint.has_min_version()) {
105 min_version = base::Version(constraint.min_version());
106 if (!min_version->IsValid()) {
107 LOG(ERROR) << "Error parsing version";
108 return std::nullopt;
109 }
110 }
111
112 std::optional<base::Version> max_version_exclusive;
113 if (constraint.has_max_version_exclusive()) {
114 max_version_exclusive =
115 base::Version(constraint.max_version_exclusive());
116 if (!max_version_exclusive->IsValid()) {
117 LOG(ERROR) << "Error parsing version";
118 return std::nullopt;
119 }
120 }
121
122 constraints.emplace_back(
123 constraint.has_sct_not_after_sec()
124 ? std::optional(base::Time::UnixEpoch() +
125 base::Seconds(constraint.sct_not_after_sec()))
126 : std::nullopt,
127 constraint.has_sct_all_after_sec()
128 ? std::optional(base::Time::UnixEpoch() +
129 base::Seconds(constraint.sct_all_after_sec()))
130 : std::nullopt,
131 min_version, max_version_exclusive);
132 }
133 root_store_data.anchors_.emplace_back(std::move(parsed),
134 std::move(constraints));
135 }
136
137 root_store_data.version_ = proto.version_major();
138
139 return root_store_data;
140 }
141
TrustStoreChrome()142 TrustStoreChrome::TrustStoreChrome()
143 : TrustStoreChrome(kChromeRootCertList,
144 /*certs_are_static=*/true,
145 /*version=*/CompiledChromeRootStoreVersion()) {}
146
TrustStoreChrome(base::span<const ChromeRootCertInfo> certs,bool certs_are_static,int64_t version)147 TrustStoreChrome::TrustStoreChrome(base::span<const ChromeRootCertInfo> certs,
148 bool certs_are_static,
149 int64_t version) {
150 std::vector<
151 std::pair<std::string_view, std::vector<ChromeRootCertConstraints>>>
152 constraints;
153
154 // TODO(hchao, sleevi): Explore keeping a CRYPTO_BUFFER of just the DER
155 // certificate and subject name. This would hopefully save memory compared
156 // to keeping the full parsed representation in memory, especially when
157 // there are multiple instances of TrustStoreChrome.
158 for (const auto& cert_info : certs) {
159 bssl::UniquePtr<CRYPTO_BUFFER> cert;
160 if (certs_are_static) {
161 // TODO(mattm,hchao): Ensure the static data crypto_buffers for the
162 // compiled-in roots are kept alive, so that roots from the component
163 // updater data will de-dupe against them. This currently works if the
164 // new components roots are the same as the compiled in roots, but
165 // fails if a component update drops a root and then the next component
166 // update readds the root without a restart.
167 cert = x509_util::CreateCryptoBufferFromStaticDataUnsafe(
168 cert_info.root_cert_der);
169 } else {
170 cert = x509_util::CreateCryptoBuffer(cert_info.root_cert_der);
171 }
172 bssl::CertErrors errors;
173 auto parsed = bssl::ParsedCertificate::Create(
174 std::move(cert), x509_util::DefaultParseCertificateOptions(), &errors);
175 // There should always be a valid cert, because we should be parsing Chrome
176 // Root Store static data compiled in.
177 CHECK(parsed);
178 if (!cert_info.constraints.empty()) {
179 std::vector<ChromeRootCertConstraints> cert_constraints;
180 for (const auto& constraint : cert_info.constraints) {
181 cert_constraints.emplace_back(constraint);
182 }
183 constraints.emplace_back(parsed->der_cert().AsStringView(),
184 std::move(cert_constraints));
185 }
186 trust_store_.AddTrustAnchor(std::move(parsed));
187 }
188
189 constraints_ = base::flat_map(std::move(constraints));
190 version_ = version;
191 }
192
TrustStoreChrome(const ChromeRootStoreData & root_store_data)193 TrustStoreChrome::TrustStoreChrome(const ChromeRootStoreData& root_store_data) {
194 std::vector<
195 std::pair<std::string_view, std::vector<ChromeRootCertConstraints>>>
196 constraints;
197
198 for (const auto& anchor : root_store_data.anchors()) {
199 if (!anchor.constraints.empty()) {
200 constraints.emplace_back(anchor.certificate->der_cert().AsStringView(),
201 anchor.constraints);
202 }
203 trust_store_.AddTrustAnchor(anchor.certificate);
204 }
205
206 constraints_ = base::flat_map(std::move(constraints));
207 version_ = root_store_data.version();
208 }
209
210 TrustStoreChrome::~TrustStoreChrome() = default;
211
SyncGetIssuersOf(const bssl::ParsedCertificate * cert,bssl::ParsedCertificateList * issuers)212 void TrustStoreChrome::SyncGetIssuersOf(const bssl::ParsedCertificate* cert,
213 bssl::ParsedCertificateList* issuers) {
214 trust_store_.SyncGetIssuersOf(cert, issuers);
215 }
216
GetTrust(const bssl::ParsedCertificate * cert)217 bssl::CertificateTrust TrustStoreChrome::GetTrust(
218 const bssl::ParsedCertificate* cert) {
219 return trust_store_.GetTrust(cert);
220 }
221
Contains(const bssl::ParsedCertificate * cert) const222 bool TrustStoreChrome::Contains(const bssl::ParsedCertificate* cert) const {
223 return trust_store_.Contains(cert);
224 }
225
226 base::span<const ChromeRootCertConstraints>
GetConstraintsForCert(const bssl::ParsedCertificate * cert) const227 TrustStoreChrome::GetConstraintsForCert(
228 const bssl::ParsedCertificate* cert) const {
229 auto it = constraints_.find(cert->der_cert().AsStringView());
230 if (it != constraints_.end()) {
231 return it->second;
232 }
233 return {};
234 }
235
236 // static
CreateTrustStoreForTesting(base::span<const ChromeRootCertInfo> certs,int64_t version)237 std::unique_ptr<TrustStoreChrome> TrustStoreChrome::CreateTrustStoreForTesting(
238 base::span<const ChromeRootCertInfo> certs,
239 int64_t version) {
240 // Note: wrap_unique is used because the constructor is private.
241 return base::WrapUnique(new TrustStoreChrome(
242 certs, /*certs_are_static=*/false, /*version=*/version));
243 }
244
CompiledChromeRootStoreVersion()245 int64_t CompiledChromeRootStoreVersion() {
246 return kRootStoreVersion;
247 }
248
CompiledChromeRootStoreAnchors()249 std::vector<ChromeRootStoreData::Anchor> CompiledChromeRootStoreAnchors() {
250 std::vector<ChromeRootStoreData::Anchor> anchors;
251 for (const auto& cert_info : kChromeRootCertList) {
252 bssl::UniquePtr<CRYPTO_BUFFER> cert =
253 x509_util::CreateCryptoBufferFromStaticDataUnsafe(
254 cert_info.root_cert_der);
255 bssl::CertErrors errors;
256 auto parsed = bssl::ParsedCertificate::Create(
257 std::move(cert), x509_util::DefaultParseCertificateOptions(), &errors);
258 DCHECK(parsed);
259
260 std::vector<ChromeRootCertConstraints> cert_constraints;
261 for (const auto& constraint : cert_info.constraints) {
262 cert_constraints.emplace_back(constraint);
263 }
264 anchors.emplace_back(std::move(parsed), std::move(cert_constraints));
265 }
266
267 return anchors;
268 }
269
270 } // namespace net
271