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/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/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),
73 can_start_before_login_(false),
75 if (!initialized_for_test_
&& LoginState::IsInitialized())
76 LoginState::Get()->AddObserver(this);
78 if (initialized_for_test_
) {
79 tpm_token_state_
= TPM_TOKEN_INITIALIZED
;
80 tpm_user_pin_
= "111111";
84 void TPMTokenLoader::SetCryptoTaskRunner(
85 const scoped_refptr
<base::SequencedTaskRunner
>& crypto_task_runner
) {
86 crypto_task_runner_
= crypto_task_runner
;
87 MaybeStartTokenInitialization();
90 void TPMTokenLoader::EnsureStarted() {
91 if (can_start_before_login_
)
93 can_start_before_login_
= true;
94 MaybeStartTokenInitialization();
97 TPMTokenLoader::~TPMTokenLoader() {
98 if (!initialized_for_test_
&& LoginState::IsInitialized())
99 LoginState::Get()->RemoveObserver(this);
102 TPMTokenLoader::TPMTokenStatus
TPMTokenLoader::IsTPMTokenEnabled(
103 const TPMReadyCallback
& callback
) {
104 if (tpm_token_state_
== TPM_TOKEN_INITIALIZED
)
105 return TPM_TOKEN_STATUS_ENABLED
;
106 if (!IsTPMLoadingEnabled() || tpm_token_state_
== TPM_DISABLED
)
107 return TPM_TOKEN_STATUS_DISABLED
;
108 // Status is not known yet.
109 if (!callback
.is_null())
110 tpm_ready_callback_list_
.push_back(callback
);
111 return TPM_TOKEN_STATUS_UNDETERMINED
;
114 bool TPMTokenLoader::IsTPMLoadingEnabled() const {
115 // TPM loading is enabled on non-ChromeOS environments, e.g. when running
117 // Treat TPM as disabled for guest users since they do not store certs.
118 return initialized_for_test_
|| (base::SysInfo::IsRunningOnChromeOS() &&
119 !LoginState::Get()->IsGuestSessionUser());
122 void TPMTokenLoader::MaybeStartTokenInitialization() {
123 CHECK(thread_checker_
.CalledOnValidThread());
125 // This is the entry point to the TPM token initialization process,
126 // which we should do at most once.
127 if (tpm_token_state_
!= TPM_STATE_UNKNOWN
|| !crypto_task_runner_
.get())
130 bool start_initialization
=
131 (LoginState::IsInitialized() && LoginState::Get()->IsUserLoggedIn()) ||
132 can_start_before_login_
;
134 VLOG(1) << "StartTokenInitialization: " << start_initialization
;
135 if (!start_initialization
)
138 if (!IsTPMLoadingEnabled())
139 tpm_token_state_
= TPM_DISABLED
;
141 ContinueTokenInitialization();
143 DCHECK_NE(tpm_token_state_
, TPM_STATE_UNKNOWN
);
146 void TPMTokenLoader::ContinueTokenInitialization() {
147 CHECK(thread_checker_
.CalledOnValidThread());
148 VLOG(1) << "ContinueTokenInitialization: " << tpm_token_state_
;
150 switch (tpm_token_state_
) {
151 case TPM_STATE_UNKNOWN
: {
152 crypto_task_runner_
->PostTaskAndReply(
154 base::Bind(&crypto::EnableTPMTokenForNSS
),
155 base::Bind(&TPMTokenLoader::OnTPMTokenEnabledForNSS
,
156 weak_factory_
.GetWeakPtr()));
157 tpm_token_state_
= TPM_INITIALIZATION_STARTED
;
160 case TPM_INITIALIZATION_STARTED
: {
164 case TPM_TOKEN_ENABLED_FOR_NSS
: {
165 tpm_token_info_getter_
->Start(
166 base::Bind(&TPMTokenLoader::OnGotTpmTokenInfo
,
167 weak_factory_
.GetWeakPtr()));
171 // TPM is disabled, so proceed with empty tpm token name.
172 NotifyTPMTokenReady();
175 case TPM_TOKEN_INFO_RECEIVED
: {
176 crypto_task_runner_
->PostTask(
179 &crypto::InitializeTPMTokenAndSystemSlot
,
181 base::Bind(&PostResultToTaskRunner
,
182 base::ThreadTaskRunnerHandle::Get(),
183 base::Bind(&TPMTokenLoader::OnTPMTokenInitialized
,
184 weak_factory_
.GetWeakPtr()))));
187 case TPM_TOKEN_INITIALIZED
: {
188 NotifyTPMTokenReady();
194 void TPMTokenLoader::OnTPMTokenEnabledForNSS() {
195 VLOG(1) << "TPMTokenEnabledForNSS";
196 tpm_token_state_
= TPM_TOKEN_ENABLED_FOR_NSS
;
197 ContinueTokenInitialization();
200 void TPMTokenLoader::OnGotTpmTokenInfo(const TPMTokenInfo
& token_info
) {
201 if (!token_info
.tpm_is_enabled
) {
202 tpm_token_state_
= TPM_DISABLED
;
203 ContinueTokenInitialization();
207 tpm_token_slot_id_
= token_info
.token_slot_id
;
208 tpm_user_pin_
= token_info
.user_pin
;
209 tpm_token_state_
= TPM_TOKEN_INFO_RECEIVED
;
211 ContinueTokenInitialization();
214 void TPMTokenLoader::OnTPMTokenInitialized(bool success
) {
215 VLOG(1) << "OnTPMTokenInitialized: " << success
;
217 tpm_token_state_
= success
? TPM_TOKEN_INITIALIZED
: TPM_DISABLED
;
218 ContinueTokenInitialization();
221 void TPMTokenLoader::NotifyTPMTokenReady() {
222 DCHECK(tpm_token_state_
== TPM_DISABLED
||
223 tpm_token_state_
== TPM_TOKEN_INITIALIZED
);
224 bool tpm_status
= tpm_token_state_
== TPM_TOKEN_INITIALIZED
;
225 for (TPMReadyCallbackList::iterator i
= tpm_ready_callback_list_
.begin();
226 i
!= tpm_ready_callback_list_
.end();
230 tpm_ready_callback_list_
.clear();
233 void TPMTokenLoader::LoggedInStateChanged() {
234 VLOG(1) << "LoggedInStateChanged";
235 MaybeStartTokenInitialization();
238 } // namespace chromeos