xref: /aosp_15_r20/external/cronet/net/cert/internal/trust_store_chrome.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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