File: network_cert_loader.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (300 lines) | stat: -rw-r--r-- 12,546 bytes parent folder | download | duplicates (8)
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_