summaryrefslogtreecommitdiffstats
path: root/chromeos/cert_loader.h
blob: bc1123e394654a7581090756f5e0294718fe9b1d (plain)
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
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROMEOS_CERT_LOADER_H_
#define CHROMEOS_CERT_LOADER_H_

#include <string>

#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list_threadsafe.h"
#include "base/threading/thread_checker.h"
#include "chromeos/chromeos_export.h"
#include "chromeos/dbus/dbus_method_call_status.h"
#include "chromeos/login/login_state.h"
#include "net/cert/cert_database.h"
#include "net/cert/x509_certificate.h"

namespace base {
class SequencedTaskRunner;
class TaskRunner;
}

namespace crypto {
class SymmetricKey;
}

namespace chromeos {

// This class is responsible for initializing the TPM token and 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), or the cert
// database changes, observers are called with OnCertificatesLoaded().
class CHROMEOS_EXPORT CertLoader : public net::CertDatabase::Observer,
                                   public LoginState::Observer {
 public:
  class Observer {
   public:
    virtual ~Observer() {}

    // Called when the certificates, passed for convenience as |cert_list|,
    // have completed loading. |initial_load| is true the first time this
    // is called.
    virtual void OnCertificatesLoaded(const net::CertificateList& cert_list,
                                      bool initial_load) = 0;

   protected:
    Observer() {}

   private:
    DISALLOW_COPY_AND_ASSIGN(Observer);
  };

  // Sets the global instance. Must be called before any calls to Get().
  static void Initialize();

  // Destroys the global instance.
  static void Shutdown();

  // Gets the global instance. Initialize() must be called first.
  static CertLoader* Get();

  // Returns true if the global instance has been initialized.
  static bool IsInitialized();

  static std::string GetPkcs11IdForCert(const net::X509Certificate& cert);

  // By default, CertLoader tries to load the TPMToken only if running in a
  // ChromeOS environment. Tests can call this function after Initialize() and
  // before SetCryptoTaskRunner() to enable the TPM initialization.
  void InitializeTPMForTest();

  // |crypto_task_runner| is the task runner that any synchronous crypto calls
  // should be made from, e.g. in Chrome this is the IO thread. Must be called
  // after the thread is started. Starts TPM initialization and Certificate
  // loading.
  void SetCryptoTaskRunner(
      const scoped_refptr<base::SequencedTaskRunner>& crypto_task_runner);

  // Sets the task runner that any slow calls will be made from, e.g. calls
  // to the NSS database. If not set, uses base::WorkerPool.
  void SetSlowTaskRunnerForTest(
      const scoped_refptr<base::TaskRunner>& task_runner);

  void AddObserver(CertLoader::Observer* observer);
  void RemoveObserver(CertLoader::Observer* observer);

  // Returns true when the certificate list has been requested but not loaded.
  bool CertificatesLoading() const;

  // Returns true if the TPM is available for hardware-backed certificates.
  bool IsHardwareBacked() const;

  bool certificates_loaded() const { return certificates_loaded_; }

  // TPM info is only valid once the TPM is available (IsHardwareBacked is
  // true). Otherwise empty strings will be returned.
  const std::string& tpm_token_name() const { return tpm_token_name_; }
  const std::string& tpm_token_slot() const { return tpm_token_slot_; }
  const std::string& tpm_user_pin() const { return tpm_user_pin_; }

  // This will be empty until certificates_loaded() is true.
  const net::CertificateList& cert_list() const { return cert_list_; }

 private:
  CertLoader();
  virtual ~CertLoader();

  void MaybeRequestCertificates();

  // This is the cyclic chain of callbacks to initialize the TPM token and to
  // kick off the update of the certificate list.
  void InitializeTokenAndLoadCertificates();
  void RetryTokenInitializationLater();
  void OnPersistentNSSDBOpened();
  void OnTpmIsEnabled(DBusMethodCallStatus call_status,
                      bool tpm_is_enabled);
  void OnPkcs11IsTpmTokenReady(DBusMethodCallStatus call_status,
                               bool is_tpm_token_ready);
  void OnPkcs11GetTpmTokenInfo(DBusMethodCallStatus call_status,
                               const std::string& token_name,
                               const std::string& user_pin);
  void OnTPMTokenInitialized(bool success);

  // These calls handle the updating of the certificate list after the TPM token
  // was initialized.

  // Start certificate loading. Must be called at most once.
  void StartLoadCertificates();

  // Trigger a certificate load. If a certificate loading task is already in
  // progress, will start a reload once the current task finised.
  void LoadCertificates();

  // Called if a certificate load task is finished.
  void UpdateCertificates(net::CertificateList* cert_list);

  void NotifyCertificatesLoaded(bool initial_load);

  // net::CertDatabase::Observer
  virtual void OnCertTrustChanged(const net::X509Certificate* cert) OVERRIDE;
  virtual void OnCertAdded(const net::X509Certificate* cert) OVERRIDE;
  virtual void OnCertRemoved(const net::X509Certificate* cert) OVERRIDE;

  // LoginState::Observer
  virtual void LoggedInStateChanged(LoginState::LoggedInState state) OVERRIDE;

  bool initialize_tpm_for_test_;

  ObserverList<Observer> observers_;

  bool certificates_requested_;
  bool certificates_loaded_;
  bool certificates_update_required_;
  bool certificates_update_running_;

  // The states are traversed in this order but some might get omitted or never
  // be left.
  enum TPMTokenState {
    TPM_STATE_UNKNOWN,
    TPM_DB_OPENED,
    TPM_DISABLED,
    TPM_ENABLED,
    TPM_TOKEN_READY,
    TPM_TOKEN_INFO_RECEIVED,
    TPM_TOKEN_INITIALIZED,
  };
  TPMTokenState tpm_token_state_;

  // The current request delay before the next attempt to initialize the
  // TPM. Will be adapted after each attempt.
  base::TimeDelta tpm_request_delay_;

  // Cached TPM token info.
  std::string tpm_token_name_;
  std::string tpm_token_slot_;
  std::string tpm_user_pin_;

  // Cached Certificates.
  net::CertificateList cert_list_;

  base::ThreadChecker thread_checker_;

  // TaskRunner for crypto calls.
  scoped_refptr<base::SequencedTaskRunner> crypto_task_runner_;

  // TaskRunner for other slow tasks. May be set in tests.
  scoped_refptr<base::TaskRunner> slow_task_runner_for_test_;

  // This factory should be used only for callbacks during TPMToken
  // initialization.
  base::WeakPtrFactory<CertLoader> initialize_token_factory_;

  // This factory should be used only for callbacks during updating the
  // certificate list.
  base::WeakPtrFactory<CertLoader> update_certificates_factory_;

  DISALLOW_COPY_AND_ASSIGN(CertLoader);
};

}  // namespace chromeos

#endif  // CHROMEOS_CERT_LOADER_H_