| // Copyright 2022 The Chromium Authors |
| // 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_android.h" |
| |
| #include "base/logging.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/task/task_traits.h" |
| #include "base/task/thread_pool.h" |
| #include "base/threading/scoped_blocking_call.h" |
| #include "net/android/network_library.h" |
| #include "net/cert/pki/cert_errors.h" |
| #include "net/cert/pki/parse_name.h" |
| #include "net/cert/pki/parsed_certificate.h" |
| #include "net/cert/x509_certificate.h" |
| #include "net/cert/x509_util.h" |
| |
| namespace net { |
| |
| class TrustStoreAndroid::Impl |
| : public base::RefCountedThreadSafe<TrustStoreAndroid::Impl> { |
| public: |
| explicit Impl(int generation) : generation_(generation) { |
| base::ScopedBlockingCall scoped_blocking_call( |
| FROM_HERE, base::BlockingType::MAY_BLOCK); |
| std::vector<std::string> roots = net::android::GetUserAddedRoots(); |
| |
| for (auto& root : roots) { |
| CertErrors errors; |
| auto parsed = net::ParsedCertificate::Create( |
| net::x509_util::CreateCryptoBuffer(root), |
| net::x509_util::DefaultParseCertificateOptions(), &errors); |
| if (!parsed) { |
| LOG(ERROR) << "Error parsing certificate:\n" << errors.ToDebugString(); |
| continue; |
| } |
| trust_store_.AddTrustAnchor(std::move(parsed)); |
| } |
| } |
| |
| // TODO(hchao): see if we can get SyncGetIssueresOf marked const |
| void SyncGetIssuersOf(const ParsedCertificate* cert, |
| ParsedCertificateList* issuers) { |
| trust_store_.SyncGetIssuersOf(cert, issuers); |
| } |
| |
| // TODO(hchao): see if we can get GetTrust marked const again |
| CertificateTrust GetTrust(const ParsedCertificate* cert) { |
| return trust_store_.GetTrust(cert); |
| } |
| |
| int generation() { return generation_; } |
| |
| private: |
| friend class base::RefCountedThreadSafe<TrustStoreAndroid::Impl>; |
| ~Impl() = default; |
| |
| // Generation # that trust_store_ was loaded at. |
| const int generation_; |
| |
| TrustStoreInMemory trust_store_; |
| }; |
| |
| TrustStoreAndroid::TrustStoreAndroid() = default; |
| |
| TrustStoreAndroid::~TrustStoreAndroid() { |
| if (is_observing_certdb_changes_) { |
| CertDatabase::GetInstance()->RemoveObserver(this); |
| } |
| } |
| |
| void TrustStoreAndroid::Initialize() { |
| MaybeInitializeAndGetImpl(); |
| } |
| |
| // This function is not thread safe. CertDatabase observation is added here |
| // rather than in the constructor to avoid having to add a TaskEnvironment to |
| // every unit test that uses TrustStoreAndroid. |
| void TrustStoreAndroid::ObserveCertDBChanges() { |
| if (!is_observing_certdb_changes_) { |
| is_observing_certdb_changes_ = true; |
| CertDatabase::GetInstance()->AddObserver(this); |
| } |
| } |
| |
| void TrustStoreAndroid::OnTrustStoreChanged() { |
| // Increment the generation number. This will regenerate the impl_ next time |
| // it is fetched. It would be neater to regenerate the impl_ here but |
| // complications around blocking of threads prevents this from being easily |
| // accomplished. |
| generation_++; |
| } |
| |
| scoped_refptr<TrustStoreAndroid::Impl> |
| TrustStoreAndroid::MaybeInitializeAndGetImpl() { |
| base::AutoLock lock(init_lock_); |
| |
| // It is possible that generation_ might be incremented in between the various |
| // statements here, but that's okay as the worst case is that we will cause a |
| // bit of extra work in reloading the android trust store if we get many |
| // OnTrustStoreChanged() calls in rapid succession. |
| int current_generation = generation_.load(); |
| if (!impl_ || impl_->generation() != current_generation) { |
| SCOPED_UMA_HISTOGRAM_LONG_TIMER("Net.CertVerifier.AndroidTrustStoreInit"); |
| impl_ = base::MakeRefCounted<TrustStoreAndroid::Impl>(current_generation); |
| } |
| |
| return impl_; |
| } |
| |
| void TrustStoreAndroid::SyncGetIssuersOf(const ParsedCertificate* cert, |
| ParsedCertificateList* issuers) { |
| MaybeInitializeAndGetImpl()->SyncGetIssuersOf(cert, issuers); |
| } |
| |
| CertificateTrust TrustStoreAndroid::GetTrust(const ParsedCertificate* cert) { |
| return MaybeInitializeAndGetImpl()->GetTrust(cert); |
| } |
| |
| } // namespace net |