xref: /aosp_15_r20/external/cronet/net/cert/nss_cert_database_chromeos.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 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/nss_cert_database_chromeos.h"
6 
7 #include <cert.h>
8 #include <pk11pub.h>
9 
10 #include <algorithm>
11 #include <memory>
12 #include <utility>
13 #include <vector>
14 
15 #include "base/functional/bind.h"
16 #include "base/functional/callback.h"
17 #include "base/location.h"
18 #include "base/task/thread_pool.h"
19 #include "base/threading/scoped_blocking_call.h"
20 #include "net/cert/nss_cert_database.h"
21 
22 namespace net {
23 
NSSCertDatabaseChromeOS(crypto::ScopedPK11Slot public_slot,crypto::ScopedPK11Slot private_slot)24 NSSCertDatabaseChromeOS::NSSCertDatabaseChromeOS(
25     crypto::ScopedPK11Slot public_slot,
26     crypto::ScopedPK11Slot private_slot)
27     : NSSCertDatabase(std::move(public_slot), std::move(private_slot)) {
28   // By default, don't use a system slot. Only if explicitly set by
29   // SetSystemSlot, the system slot will be used.
30   profile_filter_.Init(GetPublicSlot(),
31                        GetPrivateSlot(),
32                        crypto::ScopedPK11Slot() /* no system slot */);
33 }
34 
35 NSSCertDatabaseChromeOS::~NSSCertDatabaseChromeOS() = default;
36 
SetSystemSlot(crypto::ScopedPK11Slot system_slot)37 void NSSCertDatabaseChromeOS::SetSystemSlot(
38     crypto::ScopedPK11Slot system_slot) {
39   system_slot_ = std::move(system_slot);
40   profile_filter_.Init(GetPublicSlot(), GetPrivateSlot(), GetSystemSlot());
41 }
42 
ListCerts(NSSCertDatabase::ListCertsCallback callback)43 void NSSCertDatabaseChromeOS::ListCerts(
44     NSSCertDatabase::ListCertsCallback callback) {
45   base::ThreadPool::PostTaskAndReplyWithResult(
46       FROM_HERE,
47       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
48       base::BindOnce(&NSSCertDatabaseChromeOS::ListCertsImpl, profile_filter_),
49       std::move(callback));
50 }
51 
ListCertsInfo(ListCertsInfoCallback callback,NSSRootsHandling nss_roots_handling)52 void NSSCertDatabaseChromeOS::ListCertsInfo(
53     ListCertsInfoCallback callback,
54     NSSRootsHandling nss_roots_handling) {
55   base::ThreadPool::PostTaskAndReplyWithResult(
56       FROM_HERE,
57       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
58       base::BindOnce(&NSSCertDatabaseChromeOS::ListCertsInfoImpl,
59                      profile_filter_, /*slot=*/GetSystemSlot(),
60                      /*add_certs_info=*/true, nss_roots_handling),
61       std::move(callback));
62 }
63 
GetSystemSlot() const64 crypto::ScopedPK11Slot NSSCertDatabaseChromeOS::GetSystemSlot() const {
65   if (system_slot_)
66     return crypto::ScopedPK11Slot(PK11_ReferenceSlot(system_slot_.get()));
67   return crypto::ScopedPK11Slot();
68 }
69 
ListModules(std::vector<crypto::ScopedPK11Slot> * modules,bool need_rw) const70 void NSSCertDatabaseChromeOS::ListModules(
71     std::vector<crypto::ScopedPK11Slot>* modules,
72     bool need_rw) const {
73   NSSCertDatabase::ListModules(modules, need_rw);
74 
75   const NSSProfileFilterChromeOS& profile_filter = profile_filter_;
76   std::erase_if(*modules, [&profile_filter](crypto::ScopedPK11Slot& module) {
77     return !profile_filter.IsModuleAllowed(module.get());
78   });
79 }
80 
SetCertTrust(CERTCertificate * cert,CertType type,TrustBits trust_bits)81 bool NSSCertDatabaseChromeOS::SetCertTrust(CERTCertificate* cert,
82                                            CertType type,
83                                            TrustBits trust_bits) {
84   crypto::ScopedPK11Slot public_slot = GetPublicSlot();
85 
86   // Ensure that the certificate exists on the public slot so NSS puts the trust
87   // settings there (https://crbug.com/1132030).
88   if (public_slot == GetSystemSlot()) {
89     // Never attempt to store trust setting on the system slot.
90     return false;
91   }
92 
93   if (!IsCertificateOnSlot(cert, public_slot.get())) {
94     // Copy the certificate to the public slot.
95     SECStatus srv =
96         PK11_ImportCert(public_slot.get(), cert, CK_INVALID_HANDLE,
97                         cert->nickname, PR_FALSE /* includeTrust (unused) */);
98     if (srv != SECSuccess) {
99       LOG(ERROR) << "Failed to import certificate onto public slot.";
100       return false;
101     }
102   }
103   return NSSCertDatabase::SetCertTrust(cert, type, trust_bits);
104 }
105 
106 // static
ListCertsImpl(const NSSProfileFilterChromeOS & profile_filter)107 ScopedCERTCertificateList NSSCertDatabaseChromeOS::ListCertsImpl(
108     const NSSProfileFilterChromeOS& profile_filter) {
109   CertInfoList certs_info =
110       ListCertsInfoImpl(profile_filter, crypto::ScopedPK11Slot(),
111                         /*add_certs_info=*/false, NSSRootsHandling::kInclude);
112 
113   return ExtractCertificates(std::move(certs_info));
114 }
115 
116 // static
ListCertsInfoImpl(const NSSProfileFilterChromeOS & profile_filter,crypto::ScopedPK11Slot system_slot,bool add_certs_info,NSSRootsHandling nss_roots_handling)117 NSSCertDatabase::CertInfoList NSSCertDatabaseChromeOS::ListCertsInfoImpl(
118     const NSSProfileFilterChromeOS& profile_filter,
119     crypto::ScopedPK11Slot system_slot,
120     bool add_certs_info,
121     NSSRootsHandling nss_roots_handling) {
122   // This method may acquire the NSS lock or reenter this code via extension
123   // hooks (such as smart card UI). To ensure threads are not starved or
124   // deadlocked, the base::ScopedBlockingCall below increments the thread pool
125   // capacity if this method takes too much time to run.
126   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
127                                                 base::BlockingType::MAY_BLOCK);
128 
129   CertInfoList certs_info(NSSCertDatabase::ListCertsInfoImpl(
130       crypto::ScopedPK11Slot(), add_certs_info, nss_roots_handling));
131 
132   // Filter certificate information according to user profile.
133   std::erase_if(certs_info, [&profile_filter](CertInfo& cert_info) {
134     return !profile_filter.IsCertAllowed(cert_info.cert.get());
135   });
136 
137   if (add_certs_info) {
138     // Add Chrome OS specific information.
139     for (auto& cert_info : certs_info) {
140       cert_info.device_wide =
141           IsCertificateOnSlot(cert_info.cert.get(), system_slot.get());
142       cert_info.hardware_backed = IsHardwareBacked(cert_info.cert.get());
143     }
144   }
145 
146   return certs_info;
147 }
148 
149 }  // namespace net
150