1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
|
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_ASH_COMPONENTS_NETWORK_NETWORK_CERT_LOADER_H_
#define CHROMEOS_ASH_COMPONENTS_NETWORK_NETWORK_CERT_LOADER_H_
#include <string>
#include <vector>
#include "base/compiler_specific.h"
#include "base/component_export.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
#include "chromeos/ash/components/network/policy_certificate_provider.h"
#include "net/cert/scoped_nss_types.h"
namespace net {
class NSSCertDatabase;
class ServerCertificateDatabaseService;
}
namespace ash {
// This class is responsible for loading certificates once the TPM is
// initialized. It is expected to be constructed on the UI thread and public
// methods should all be called from the UI thread.
// When certificates have been loaded (after login completes and tpm token is
// initialized), or the cert database changes, observers are called with
// OnCertificatesLoaded().
// This class supports using one or two cert databases. The expected usage is
// that NetworkCertLoader is used with a NSSCertDatabase backed by the system
// token before user sign-in, and additionally with a user-specific
// NSSCertDatabase after user sign-in. When both NSSCertDatabase are used,
// NetworkCertLoader combines certificates from both into |all_certs()|.
class COMPONENT_EXPORT(CHROMEOS_NETWORK) NetworkCertLoader
: public PolicyCertificateProvider::Observer {
public:
class Observer {
public:
// Called when the certificates have completed loading or have been updated.
virtual void OnCertificatesLoaded() = 0;
protected:
virtual ~Observer() {}
};
// Holds a certificate that can be used in network configs along with
// additional information.
class NetworkCert final {
public:
NetworkCert(net::ScopedCERTCertificate cert,
bool available_for_network_auth,
bool device_wide);
~NetworkCert();
// Not copyable
NetworkCert(const NetworkCert& other) = delete;
NetworkCert& operator=(const NetworkCert& other) = delete;
// Movable
NetworkCert(NetworkCert&& other);
NetworkCert& operator=(NetworkCert&& other);
CERTCertificate* cert() const { return cert_.get(); }
// Returns true if this is a client certificate that is available for
// network authentication. authentication. See also
// NetworkCertLoader::ForceAvailableForNetworkAuthForTesting().
bool is_available_for_network_auth() const {
return available_for_network_auth_;
}
// Returns true if this certificate is available device-wide (so it can be
// used in shared network configs).
bool is_device_wide() const { return device_wide_; }
// Returns true if this certificate is hardware-backed.
bool IsHardwareBacked() const;
NetworkCert Clone() const;
private:
// TODO(https://crbug.com/40554868): There are hidden dependencies on this
// being stored as a NSS certificate object, so that the certificate can be
// found using CERT_FindCertByName/CERT_FindCertIssuer. Fix these locations
// to explicitly access the certificates they care about.
net::ScopedCERTCertificate cert_;
bool available_for_network_auth_;
bool device_wide_;
};
// A list of NetworkCerts.
using NetworkCertList = std::vector<NetworkCert>;
// Sets the global instance. Must be called before any calls to Get().
// Note: For test usage, make sure to call
// SystemTokenCertDbStorage::Initialize() before initializing the
// NetworkCertLoader.
static void Initialize();
// Destroys the global instance.
static void Shutdown();
// Gets the global instance. Initialize() must be called first.
static NetworkCertLoader* Get();
NetworkCertLoader(const NetworkCertLoader&) = delete;
NetworkCertLoader& operator=(const NetworkCertLoader&) = delete;
// Returns true if the global instance has been initialized.
static bool IsInitialized();
// Returns the PKCS#11 attribute CKA_ID for a certificate as an upper-case
// hex string and sets |slot_id| to the id of the containing slot, or returns
// an empty string and doesn't modify |slot_id| if the PKCS#11 id could not be
// determined.
static std::string GetPkcs11IdAndSlotForCert(CERTCertificate* cert,
int* slot_id);
// When this is called, |NetworkCertLoader| stops sending out updates to its
// observers. This is a workaround for https://crbug.com/894867, where a crash
// is suspected to happen due to updates sent out during the shutdown
// procedure. TODO(crbug.com/41420425): Remove this when the root cause
// is found.
void set_is_shutting_down() { is_shutting_down_ = true; }
// Marks that the initialization of the system slot NSSCertDatabase has
// started. The caller should call SetSystemNSSDB when the NSSCertDatabase is
// available.
void MarkSystemNSSDBWillBeInitialized();
// Used by tests to set the NSS cert database which NetworkCertLoader should
// use to access system slot certificates.
void SetSystemNssDbForTesting(net::NSSCertDatabase* system_slot_database);
// Marks that the initialization of the user slot NSSCertDatabase has started.
// The caller should call SetSystemNSSDB when the NSSCertDatabase is
// available.
void MarkUserNSSDBWillBeInitialized();
// Marks that the initialization of the user ServerCertificateDatabaseService
// has started. The caller should call SetUserServerCertDatabaseService when
// the ServerCertificateDatabaseService is available.
void MarkUserServerCertDatabaseWillBeInitialized();
// Sets the NSS cert database which NetworkCertLoader should use to access
// user slot certificates. NetworkCertLoader understands the edge case that
// this database could also give access to system slot certificates (e.g. for
// affiliated users). The NetworkCertLoader will _not_ take the ownership of
// the database, but it expects it to stay alive at least until the shutdown
// starts on the main thread. This assumes that SetUserNSSDB and other methods
// directly using |database_| are not called during shutdown.
// NetworkCertLoader supports working with only one database or with both
// (system and user) databases.
void SetUserNSSDB(net::NSSCertDatabase* user_database);
// Sets the ServerCertificateDatabaseService which NetworkCertLoader should
// use to access user certificates. Should be called again with nullptr
// before the ServerCertificateDatabaseService will be destroyed.
void SetUserServerCertDatabaseService(
net::ServerCertificateDatabaseService* user_cert_db);
// Sets the PolicyCertificateProvider for device policy (its authority
// certificates will be available device-wide). Call with nullptr to remove it
// again.
void SetDevicePolicyCertificateProvider(
PolicyCertificateProvider* device_policy_certificate_provider);
// Sets the PolicyCertificateProvider for user policy (its authority
// certificates will not be available device-wide). Call with nullptr to
// remove it again.
void SetUserPolicyCertificateProvider(
PolicyCertificateProvider* device_user_certificate_provider);
void AddObserver(NetworkCertLoader::Observer* observer);
void RemoveObserver(NetworkCertLoader::Observer* observer);
// Returns true when the certificate list has been requested but not loaded.
// When two databases are in use (SetSystemNSSDB and SetUserNSSDB have both
// been called), this returns true when at least one of them is currently
// loading certificates.
// Note that this method poses an exception in the NetworkCertLoader
// interface: While most of NetworkCertLoader's interface treats the initial
// load of a second database the same way as an update in the first database,
// this method does not. The reason is that it's targeted at displaying a
// message in the GUI, so the user knows that (more) certificates will be
// available soon.
bool initial_load_of_any_database_running() const;
// Returns true if any certificates have been loaded. If NetworkCertLoader
// uses a system and a user NSS database, this returns true after the
// certificates from the first (usually system) database have been loaded.
bool initial_load_finished() const;
// Returns true if certificates from a user NSS database have been loaded.
bool user_cert_database_load_finished() const;
// Returns true if there can be any client certificates in the current device
// state. this means that either a system slot or a primary user's private
// slot are present, or have been marked as being initialized.
bool can_have_client_certificates() const;
// Returns authority certificates usable for network configurations. This will
// be empty until certificates_loaded() is true.
const NetworkCertList& authority_certs() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return all_authority_certs_;
}
// Returns client certificates usable for network configuration. This will be
// empty until certificates_loaded() is true.
const NetworkCertList& client_certs() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return all_client_certs_;
}
// Returns all certificates from |network_cert_list|, ignoring if they're
// device-wide or not.
static net::ScopedCERTCertificateList GetAllCertsFromNetworkCertList(
const NetworkCertList& network_cert_list);
// Clones a vector of |NetworkCert|s.
static NetworkCertList CloneNetworkCertList(
const NetworkCertList& network_cert_list);
// Called in tests if |NetworkCert::is_available_for_network_auth()| should
// always return true.
static void ForceAvailableForNetworkAuthForTesting();
private:
class CertCache;
class ServerCertDbCache;
NetworkCertLoader();
~NetworkCertLoader() override;
// Sets the NSS cert database which NetworkCertLoader should use to access
// system slot certificates. The NetworkCertLoader will _not_ take ownership
// of the database - see comment on SetUserNSSDB. NetworkCertLoader supports
// working with only one database or with both (system and user) databases.
// This method is passed as a callback to SystemTokenCertDbStorage which will
// call it when the system slot database is ready or the database
// initialization has failed.
void OnSystemNssDbReady(net::NSSCertDatabase* system_slot_database);
// Called when |system_cert_cache_| or |user_cert_cache| certificates have
// potentially changed.
void OnCertCacheUpdated();
// Called when policy-provided certificates or cache-based certificates (see
// |all_certs_from_cache_|) have potentially changed.
void UpdateCertificates();
void NotifyCertificatesLoaded();
// PolicyCertificateProvider::Observer
void OnPolicyProvidedCertsChanged() override;
// If this is true, |NetworkCertLoader| does not send out notifications to its
// observers anymore.
bool is_shutting_down_ = false;
base::ObserverList<Observer>::Unchecked observers_;
// Cache for certificates from the system-token NSSCertDatabase.
std::unique_ptr<CertCache> system_slot_cert_cache_;
// Cache for certificates from the user-specific NSSCertDatabase, listing
// certificates from the private slot.
std::unique_ptr<CertCache> user_private_slot_cert_cache_;
// Cache for certificates from the user-specific NSSCertDatabase, listing
// certificates from the public slot.
std::unique_ptr<CertCache> user_public_slot_cert_cache_;
// Cache for certificates from the user-specific
// ServerCertificateDatabaseService.
std::unique_ptr<ServerCertDbCache> user_server_cert_db_cache_;
// Client certificates.
NetworkCertList all_client_certs_;
// Authority certs from |cached_certs_| extended by authority certs provided
// by the policy certificate providers.
NetworkCertList all_authority_certs_;
// True if |StoreCertsFromCache()| was called before.
bool certs_from_cache_loaded_ = false;
raw_ptr<PolicyCertificateProvider> device_policy_certificate_provider_ =
nullptr;
raw_ptr<PolicyCertificateProvider> user_policy_certificate_provider_ =
nullptr;
THREAD_CHECKER(thread_checker_);
base::WeakPtrFactory<NetworkCertLoader> weak_factory_{this};
};
} // namespace ash
#endif // CHROMEOS_ASH_COMPONENTS_NETWORK_NETWORK_CERT_LOADER_H_
|