1 // Copyright 2022 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_android.h"
6
7 #include "base/logging.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "base/task/task_traits.h"
10 #include "base/task/thread_pool.h"
11 #include "base/threading/scoped_blocking_call.h"
12 #include "net/android/network_library.h"
13 #include "net/cert/x509_certificate.h"
14 #include "net/cert/x509_util.h"
15 #include "third_party/boringssl/src/pki/cert_errors.h"
16 #include "third_party/boringssl/src/pki/parse_name.h"
17 #include "third_party/boringssl/src/pki/parsed_certificate.h"
18
19 namespace net {
20
21 class TrustStoreAndroid::Impl
22 : public base::RefCountedThreadSafe<TrustStoreAndroid::Impl> {
23 public:
Impl(int generation)24 explicit Impl(int generation) : generation_(generation) {
25 base::ScopedBlockingCall scoped_blocking_call(
26 FROM_HERE, base::BlockingType::MAY_BLOCK);
27 std::vector<std::string> roots = net::android::GetUserAddedRoots();
28
29 for (auto& root : roots) {
30 bssl::CertErrors errors;
31 auto parsed = bssl::ParsedCertificate::Create(
32 net::x509_util::CreateCryptoBuffer(root),
33 net::x509_util::DefaultParseCertificateOptions(), &errors);
34 if (!parsed) {
35 LOG(ERROR) << "Error parsing certificate:\n" << errors.ToDebugString();
36 continue;
37 }
38 trust_store_.AddTrustAnchor(std::move(parsed));
39 }
40 }
41
42 // TODO(hchao): see if we can get SyncGetIssueresOf marked const
SyncGetIssuersOf(const bssl::ParsedCertificate * cert,bssl::ParsedCertificateList * issuers)43 void SyncGetIssuersOf(const bssl::ParsedCertificate* cert,
44 bssl::ParsedCertificateList* issuers) {
45 trust_store_.SyncGetIssuersOf(cert, issuers);
46 }
47
48 // TODO(hchao): see if we can get GetTrust marked const again
GetTrust(const bssl::ParsedCertificate * cert)49 bssl::CertificateTrust GetTrust(const bssl::ParsedCertificate* cert) {
50 return trust_store_.GetTrust(cert);
51 }
52
generation()53 int generation() { return generation_; }
54
55 private:
56 friend class base::RefCountedThreadSafe<TrustStoreAndroid::Impl>;
57 ~Impl() = default;
58
59 // Generation # that trust_store_ was loaded at.
60 const int generation_;
61
62 bssl::TrustStoreInMemory trust_store_;
63 };
64
65 TrustStoreAndroid::TrustStoreAndroid() = default;
66
~TrustStoreAndroid()67 TrustStoreAndroid::~TrustStoreAndroid() {
68 if (is_observing_certdb_changes_) {
69 CertDatabase::GetInstance()->RemoveObserver(this);
70 }
71 }
72
Initialize()73 void TrustStoreAndroid::Initialize() {
74 MaybeInitializeAndGetImpl();
75 }
76
77 // This function is not thread safe. CertDatabase observation is added here
78 // rather than in the constructor to avoid having to add a TaskEnvironment to
79 // every unit test that uses TrustStoreAndroid.
ObserveCertDBChanges()80 void TrustStoreAndroid::ObserveCertDBChanges() {
81 if (!is_observing_certdb_changes_) {
82 is_observing_certdb_changes_ = true;
83 CertDatabase::GetInstance()->AddObserver(this);
84 }
85 }
86
OnTrustStoreChanged()87 void TrustStoreAndroid::OnTrustStoreChanged() {
88 // Increment the generation number. This will regenerate the impl_ next time
89 // it is fetched. It would be neater to regenerate the impl_ here but
90 // complications around blocking of threads prevents this from being easily
91 // accomplished.
92 generation_++;
93 }
94
95 scoped_refptr<TrustStoreAndroid::Impl>
MaybeInitializeAndGetImpl()96 TrustStoreAndroid::MaybeInitializeAndGetImpl() {
97 base::AutoLock lock(init_lock_);
98
99 // It is possible that generation_ might be incremented in between the various
100 // statements here, but that's okay as the worst case is that we will cause a
101 // bit of extra work in reloading the android trust store if we get many
102 // OnTrustStoreChanged() calls in rapid succession.
103 int current_generation = generation_.load();
104 if (!impl_ || impl_->generation() != current_generation) {
105 SCOPED_UMA_HISTOGRAM_LONG_TIMER("Net.CertVerifier.AndroidTrustStoreInit");
106 impl_ = base::MakeRefCounted<TrustStoreAndroid::Impl>(current_generation);
107 }
108
109 return impl_;
110 }
111
SyncGetIssuersOf(const bssl::ParsedCertificate * cert,bssl::ParsedCertificateList * issuers)112 void TrustStoreAndroid::SyncGetIssuersOf(const bssl::ParsedCertificate* cert,
113 bssl::ParsedCertificateList* issuers) {
114 MaybeInitializeAndGetImpl()->SyncGetIssuersOf(cert, issuers);
115 }
116
GetTrust(const bssl::ParsedCertificate * cert)117 bssl::CertificateTrust TrustStoreAndroid::GetTrust(
118 const bssl::ParsedCertificate* cert) {
119 return MaybeInitializeAndGetImpl()->GetTrust(cert);
120 }
121
122 } // namespace net
123