1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chromeos/tpm_token_loader.h"
10 #include "base/location.h"
11 #include "base/sequenced_task_runner.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/sys_info.h"
14 #include "base/task_runner_util.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "chromeos/dbus/dbus_thread_manager.h"
17 #include "chromeos/tpm_token_info_getter.h"
18 #include "crypto/nss_util.h"
24 void PostResultToTaskRunner(scoped_refptr
<base::SequencedTaskRunner
> runner
,
25 const base::Callback
<void(bool)>& callback
,
27 runner
->PostTask(FROM_HERE
, base::Bind(callback
, success
));
32 static TPMTokenLoader
* g_tpm_token_loader
= NULL
;
35 void TPMTokenLoader::Initialize() {
36 CHECK(!g_tpm_token_loader
);
37 g_tpm_token_loader
= new TPMTokenLoader(false /*for_test*/);
41 void TPMTokenLoader::InitializeForTest() {
42 CHECK(!g_tpm_token_loader
);
43 g_tpm_token_loader
= new TPMTokenLoader(true /*for_test*/);
47 void TPMTokenLoader::Shutdown() {
48 CHECK(g_tpm_token_loader
);
49 delete g_tpm_token_loader
;
50 g_tpm_token_loader
= NULL
;
54 TPMTokenLoader
* TPMTokenLoader::Get() {
55 CHECK(g_tpm_token_loader
)
56 << "TPMTokenLoader::Get() called before Initialize()";
57 return g_tpm_token_loader
;
61 bool TPMTokenLoader::IsInitialized() {
62 return g_tpm_token_loader
;
65 TPMTokenLoader::TPMTokenLoader(bool for_test
)
66 : initialized_for_test_(for_test
),
67 tpm_token_state_(TPM_STATE_UNKNOWN
),
68 tpm_token_info_getter_(
69 TPMTokenInfoGetter::CreateForSystemToken(
70 DBusThreadManager::Get()->GetCryptohomeClient(),
71 base::ThreadTaskRunnerHandle::Get())),
72 tpm_token_slot_id_(-1),
74 if (!initialized_for_test_
&& LoginState::IsInitialized())
75 LoginState::Get()->AddObserver(this);
77 if (initialized_for_test_
) {
78 tpm_token_state_
= TPM_TOKEN_INITIALIZED
;
79 tpm_user_pin_
= "111111";
83 void TPMTokenLoader::SetCryptoTaskRunner(
84 const scoped_refptr
<base::SequencedTaskRunner
>& crypto_task_runner
) {
85 crypto_task_runner_
= crypto_task_runner
;
86 MaybeStartTokenInitialization();
89 TPMTokenLoader::~TPMTokenLoader() {
90 if (!initialized_for_test_
&& LoginState::IsInitialized())
91 LoginState::Get()->RemoveObserver(this);
94 TPMTokenLoader::TPMTokenStatus
TPMTokenLoader::IsTPMTokenEnabled(
95 const TPMReadyCallback
& callback
) {
96 if (tpm_token_state_
== TPM_TOKEN_INITIALIZED
)
97 return TPM_TOKEN_STATUS_ENABLED
;
98 if (!IsTPMLoadingEnabled() || tpm_token_state_
== TPM_DISABLED
)
99 return TPM_TOKEN_STATUS_DISABLED
;
100 // Status is not known yet.
101 if (!callback
.is_null())
102 tpm_ready_callback_list_
.push_back(callback
);
103 return TPM_TOKEN_STATUS_UNDETERMINED
;
106 bool TPMTokenLoader::IsTPMLoadingEnabled() const {
107 // TPM loading is enabled on non-ChromeOS environments, e.g. when running
109 // Treat TPM as disabled for guest users since they do not store certs.
110 return initialized_for_test_
|| (base::SysInfo::IsRunningOnChromeOS() &&
111 !LoginState::Get()->IsGuestSessionUser());
114 void TPMTokenLoader::MaybeStartTokenInitialization() {
115 CHECK(thread_checker_
.CalledOnValidThread());
117 // This is the entry point to the TPM token initialization process,
118 // which we should do at most once.
119 if (tpm_token_state_
!= TPM_STATE_UNKNOWN
|| !crypto_task_runner_
.get())
122 if (!LoginState::IsInitialized())
125 bool start_initialization
= LoginState::Get()->IsUserLoggedIn();
127 VLOG(1) << "StartTokenInitialization: " << start_initialization
;
128 if (!start_initialization
)
131 if (!IsTPMLoadingEnabled())
132 tpm_token_state_
= TPM_DISABLED
;
134 ContinueTokenInitialization();
136 DCHECK_NE(tpm_token_state_
, TPM_STATE_UNKNOWN
);
139 void TPMTokenLoader::ContinueTokenInitialization() {
140 CHECK(thread_checker_
.CalledOnValidThread());
141 VLOG(1) << "ContinueTokenInitialization: " << tpm_token_state_
;
143 switch (tpm_token_state_
) {
144 case TPM_STATE_UNKNOWN
: {
145 crypto_task_runner_
->PostTaskAndReply(
147 base::Bind(&crypto::EnableTPMTokenForNSS
),
148 base::Bind(&TPMTokenLoader::OnTPMTokenEnabledForNSS
,
149 weak_factory_
.GetWeakPtr()));
150 tpm_token_state_
= TPM_INITIALIZATION_STARTED
;
153 case TPM_INITIALIZATION_STARTED
: {
157 case TPM_TOKEN_ENABLED_FOR_NSS
: {
158 tpm_token_info_getter_
->Start(
159 base::Bind(&TPMTokenLoader::OnGotTpmTokenInfo
,
160 weak_factory_
.GetWeakPtr()));
164 // TPM is disabled, so proceed with empty tpm token name.
165 NotifyTPMTokenReady();
168 case TPM_TOKEN_INFO_RECEIVED
: {
169 crypto_task_runner_
->PostTask(
172 &crypto::InitializeTPMTokenAndSystemSlot
,
174 base::Bind(&PostResultToTaskRunner
,
175 base::ThreadTaskRunnerHandle::Get(),
176 base::Bind(&TPMTokenLoader::OnTPMTokenInitialized
,
177 weak_factory_
.GetWeakPtr()))));
180 case TPM_TOKEN_INITIALIZED
: {
181 NotifyTPMTokenReady();
187 void TPMTokenLoader::OnTPMTokenEnabledForNSS() {
188 VLOG(1) << "TPMTokenEnabledForNSS";
189 tpm_token_state_
= TPM_TOKEN_ENABLED_FOR_NSS
;
190 ContinueTokenInitialization();
193 void TPMTokenLoader::OnGotTpmTokenInfo(const TPMTokenInfo
& token_info
) {
194 if (!token_info
.tpm_is_enabled
) {
195 tpm_token_state_
= TPM_DISABLED
;
196 ContinueTokenInitialization();
200 tpm_token_slot_id_
= token_info
.token_slot_id
;
201 tpm_user_pin_
= token_info
.user_pin
;
202 tpm_token_state_
= TPM_TOKEN_INFO_RECEIVED
;
204 ContinueTokenInitialization();
207 void TPMTokenLoader::OnTPMTokenInitialized(bool success
) {
208 VLOG(1) << "OnTPMTokenInitialized: " << success
;
210 tpm_token_state_
= success
? TPM_TOKEN_INITIALIZED
: TPM_DISABLED
;
211 ContinueTokenInitialization();
214 void TPMTokenLoader::NotifyTPMTokenReady() {
215 DCHECK(tpm_token_state_
== TPM_DISABLED
||
216 tpm_token_state_
== TPM_TOKEN_INITIALIZED
);
217 bool tpm_status
= tpm_token_state_
== TPM_TOKEN_INITIALIZED
;
218 for (TPMReadyCallbackList::iterator i
= tpm_ready_callback_list_
.begin();
219 i
!= tpm_ready_callback_list_
.end();
223 tpm_ready_callback_list_
.clear();
226 void TPMTokenLoader::LoggedInStateChanged() {
227 VLOG(1) << "LoggedInStateChanged";
228 MaybeStartTokenInitialization();
231 } // namespace chromeos