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.
9 #include "base/location.h"
10 #include "base/macros.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/task_runner.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "chromeos/dbus/fake_cryptohome_client.h"
17 #include "chromeos/tpm/tpm_token_info_getter.h"
18 #include "testing/gtest/include/gtest/gtest.h"
22 // The struct holding information returned by TPMTokenInfoGetter::Start
24 struct TestTPMTokenInfo
{
25 TestTPMTokenInfo() : enabled(false), slot_id(-2) {}
27 bool IsReady() const {
37 // Callback for TPMTokenInfoGetter::Start. It records the values returned
38 // by TPMTokenInfoGetter to |info|.
39 void RecordGetterResult(TestTPMTokenInfo
* target
,
40 const chromeos::TPMTokenInfo
& source
) {
41 target
->enabled
= source
.tpm_is_enabled
;
42 target
->name
= source
.token_name
;
43 target
->pin
= source
.user_pin
;
44 target
->slot_id
= source
.token_slot_id
;
47 // Task runner for handling delayed tasks posted by TPMTokenInfoGetter when
48 // retrying failed cryptohome method calls. It just records the requested
49 // delay and immediately runs the task. The task is run asynchronously to be
50 // closer to what's actually happening in production.
51 // The delays used by TPMTokenGetter should be monotonically increasing, so
52 // the fake task runner does not handle task reordering based on the delays.
53 class FakeTaskRunner
: public base::TaskRunner
{
55 // |delays|: Vector to which the dalays seen by the task runner are saved.
56 explicit FakeTaskRunner(std::vector
<int64
>* delays
) : delays_(delays
) {}
58 // base::TaskRunner overrides:
59 bool PostDelayedTask(const tracked_objects::Location
& from_here
,
60 const base::Closure
& task
,
61 base::TimeDelta delay
) override
{
62 delays_
->push_back(delay
.InMilliseconds());
63 base::ThreadTaskRunnerHandle::Get()->PostTask(from_here
, task
);
66 bool RunsTasksOnCurrentThread() const override
{ return true; }
69 ~FakeTaskRunner() override
{}
72 // The vector of delays.
73 std::vector
<int64
>* delays_
;
75 DISALLOW_COPY_AND_ASSIGN(FakeTaskRunner
);
78 // Implementation of CryptohomeClient used in these tests. Note that
79 // TestCryptohomeClient implements FakeCryptohomeClient purely for convenience
80 // of not having to implement whole CryptohomeClient interface.
81 // TestCryptohomeClient overrides all CryptohomeClient methods used in
82 // TPMTokenInfoGetter tests.
83 class TestCryptohomeClient
: public chromeos::FakeCryptohomeClient
{
85 // |user_id|: The user associated with the TPMTokenInfoGetter that will be
86 // using the TestCryptohomeClient. Should be empty for system token.
87 explicit TestCryptohomeClient(const std::string
& user_id
)
89 tpm_is_enabled_(true),
90 tpm_is_enabled_failure_count_(0),
91 tpm_is_enabled_succeeded_(false),
92 get_tpm_token_info_failure_count_(0),
93 get_tpm_token_info_not_set_count_(0),
94 get_tpm_token_info_succeeded_(false) {
97 ~TestCryptohomeClient() override
{}
99 void set_tpm_is_enabled(bool value
) {
100 tpm_is_enabled_
= value
;
103 void set_tpm_is_enabled_failure_count(int value
) {
105 tpm_is_enabled_failure_count_
= value
;
108 void set_get_tpm_token_info_failure_count(int value
) {
110 get_tpm_token_info_failure_count_
= value
;
113 void set_get_tpm_token_info_not_set_count(int value
) {
115 get_tpm_token_info_not_set_count_
= value
;
118 // Sets the tpm tpken info to be reported by the test CryptohomeClient.
119 // If there is |Pkcs11GetTpmTokenInfo| in progress, runs the pending
120 // callback with the set tpm token info.
121 void SetTPMTokenInfo(const std::string
& token_name
,
122 const std::string
& pin
,
124 tpm_token_info_
.name
= token_name
;
125 tpm_token_info_
.pin
= pin
;
126 tpm_token_info_
.slot_id
= slot_id
;
128 ASSERT_TRUE(tpm_token_info_
.IsReady());
130 InvokeGetTpmTokenInfoCallbackIfReady();
134 // FakeCryptohomeClient override.
135 void TpmIsEnabled(const chromeos::BoolDBusMethodCallback
& callback
) override
{
136 ASSERT_FALSE(tpm_is_enabled_succeeded_
);
137 if (tpm_is_enabled_failure_count_
> 0) {
138 --tpm_is_enabled_failure_count_
;
139 base::ThreadTaskRunnerHandle::Get()->PostTask(
141 base::Bind(callback
, chromeos::DBUS_METHOD_CALL_FAILURE
, false));
143 tpm_is_enabled_succeeded_
= true;
144 base::ThreadTaskRunnerHandle::Get()->PostTask(
147 chromeos::DBUS_METHOD_CALL_SUCCESS
, tpm_is_enabled_
));
151 void Pkcs11GetTpmTokenInfo(
152 const Pkcs11GetTpmTokenInfoCallback
& callback
) override
{
153 ASSERT_TRUE(user_id_
.empty());
155 HandleGetTpmTokenInfo(callback
);
158 void Pkcs11GetTpmTokenInfoForUser(
159 const std::string
& user_id
,
160 const Pkcs11GetTpmTokenInfoCallback
& callback
) override
{
161 ASSERT_FALSE(user_id_
.empty());
162 ASSERT_EQ(user_id_
, user_id
);
164 HandleGetTpmTokenInfo(callback
);
167 // Handles Pkcs11GetTpmTokenInfo calls (both for system and user token). The
168 // CryptohomeClient method overrides should make sure that |user_id_| is
169 // properly set before calling this.
170 void HandleGetTpmTokenInfo(const Pkcs11GetTpmTokenInfoCallback
& callback
) {
171 ASSERT_TRUE(tpm_is_enabled_succeeded_
);
172 ASSERT_FALSE(get_tpm_token_info_succeeded_
);
173 ASSERT_TRUE(pending_get_tpm_token_info_callback_
.is_null());
175 if (get_tpm_token_info_failure_count_
> 0) {
176 --get_tpm_token_info_failure_count_
;
177 base::ThreadTaskRunnerHandle::Get()->PostTask(
180 chromeos::DBUS_METHOD_CALL_FAILURE
,
181 std::string() /* token name */,
182 std::string() /* user pin */,
187 if (get_tpm_token_info_not_set_count_
> 0) {
188 --get_tpm_token_info_not_set_count_
;
189 base::ThreadTaskRunnerHandle::Get()->PostTask(
192 chromeos::DBUS_METHOD_CALL_SUCCESS
,
193 std::string() /* token name */,
194 std::string() /* user pin */,
199 pending_get_tpm_token_info_callback_
= callback
;
200 InvokeGetTpmTokenInfoCallbackIfReady();
203 void InvokeGetTpmTokenInfoCallbackIfReady() {
204 if (!tpm_token_info_
.IsReady() ||
205 pending_get_tpm_token_info_callback_
.is_null())
208 get_tpm_token_info_succeeded_
= true;
209 // Called synchronously for convenience (to avoid using extra RunLoop in
210 // tests). Unlike with other Cryptohome callbacks, TPMTokenInfoGetter does
211 // not rely on this callback being called asynchronously.
212 pending_get_tpm_token_info_callback_
.Run(
213 chromeos::DBUS_METHOD_CALL_SUCCESS
,
214 tpm_token_info_
.name
,
216 tpm_token_info_
.slot_id
);
219 std::string user_id_
;
220 bool tpm_is_enabled_
;
221 int tpm_is_enabled_failure_count_
;
222 bool tpm_is_enabled_succeeded_
;
223 int get_tpm_token_info_failure_count_
;
224 int get_tpm_token_info_not_set_count_
;
225 bool get_tpm_token_info_succeeded_
;
226 Pkcs11GetTpmTokenInfoCallback pending_get_tpm_token_info_callback_
;
227 TestTPMTokenInfo tpm_token_info_
;
229 DISALLOW_COPY_AND_ASSIGN(TestCryptohomeClient
);
232 class SystemTPMTokenInfoGetterTest
: public testing::Test
{
234 SystemTPMTokenInfoGetterTest() {}
235 ~SystemTPMTokenInfoGetterTest() override
{}
237 void SetUp() override
{
238 cryptohome_client_
.reset(new TestCryptohomeClient(std::string()));
239 tpm_token_info_getter_
=
240 chromeos::TPMTokenInfoGetter::CreateForSystemToken(
241 cryptohome_client_
.get(),
242 scoped_refptr
<base::TaskRunner
>(new FakeTaskRunner(&delays_
)));
246 scoped_ptr
<TestCryptohomeClient
> cryptohome_client_
;
247 scoped_ptr
<chromeos::TPMTokenInfoGetter
> tpm_token_info_getter_
;
249 std::vector
<int64
> delays_
;
252 base::MessageLoop message_loop_
;
254 DISALLOW_COPY_AND_ASSIGN(SystemTPMTokenInfoGetterTest
);
257 class UserTPMTokenInfoGetterTest
: public testing::Test
{
259 UserTPMTokenInfoGetterTest() : user_id_("user") {}
260 ~UserTPMTokenInfoGetterTest() override
{}
262 void SetUp() override
{
263 cryptohome_client_
.reset(new TestCryptohomeClient(user_id_
));
264 tpm_token_info_getter_
=
265 chromeos::TPMTokenInfoGetter::CreateForUserToken(
267 cryptohome_client_
.get(),
268 scoped_refptr
<base::TaskRunner
>(new FakeTaskRunner(&delays_
)));
272 scoped_ptr
<TestCryptohomeClient
> cryptohome_client_
;
273 scoped_ptr
<chromeos::TPMTokenInfoGetter
> tpm_token_info_getter_
;
275 std::string user_id_
;
276 std::vector
<int64
> delays_
;
279 base::MessageLoop message_loop_
;
281 DISALLOW_COPY_AND_ASSIGN(UserTPMTokenInfoGetterTest
);
284 TEST_F(SystemTPMTokenInfoGetterTest
, BasicFlow
) {
285 TestTPMTokenInfo reported_info
;
286 tpm_token_info_getter_
->Start(
287 base::Bind(&RecordGetterResult
, &reported_info
));
288 base::RunLoop().RunUntilIdle();
290 EXPECT_FALSE(reported_info
.IsReady());
291 cryptohome_client_
->SetTPMTokenInfo("TOKEN_1", "2222", 1);
293 EXPECT_TRUE(reported_info
.IsReady());
294 EXPECT_TRUE(reported_info
.enabled
);
295 EXPECT_EQ("TOKEN_1", reported_info
.name
);
296 EXPECT_EQ("2222", reported_info
.pin
);
297 EXPECT_EQ(1, reported_info
.slot_id
);
299 EXPECT_EQ(std::vector
<int64
>(), delays_
);
302 TEST_F(SystemTPMTokenInfoGetterTest
, TokenSlotIdEqualsZero
) {
303 TestTPMTokenInfo reported_info
;
304 tpm_token_info_getter_
->Start(
305 base::Bind(&RecordGetterResult
, &reported_info
));
306 base::RunLoop().RunUntilIdle();
308 EXPECT_FALSE(reported_info
.IsReady());
309 cryptohome_client_
->SetTPMTokenInfo("TOKEN_0", "2222", 0);
311 EXPECT_TRUE(reported_info
.IsReady());
312 base::RunLoop().RunUntilIdle();
314 EXPECT_TRUE(reported_info
.enabled
);
315 EXPECT_EQ("TOKEN_0", reported_info
.name
);
316 EXPECT_EQ("2222", reported_info
.pin
);
317 EXPECT_EQ(0, reported_info
.slot_id
);
319 EXPECT_EQ(std::vector
<int64
>(), delays_
);
322 TEST_F(SystemTPMTokenInfoGetterTest
, TPMNotEnabled
) {
323 cryptohome_client_
->set_tpm_is_enabled(false);
325 TestTPMTokenInfo reported_info
;
326 tpm_token_info_getter_
->Start(
327 base::Bind(&RecordGetterResult
, &reported_info
));
328 base::RunLoop().RunUntilIdle();
330 EXPECT_FALSE(reported_info
.IsReady());
331 EXPECT_FALSE(reported_info
.enabled
);
333 EXPECT_EQ(std::vector
<int64
>(), delays_
);
336 TEST_F(SystemTPMTokenInfoGetterTest
, TpmEnabledCallFails
) {
337 cryptohome_client_
->set_tpm_is_enabled_failure_count(1);
339 TestTPMTokenInfo reported_info
;
340 tpm_token_info_getter_
->Start(
341 base::Bind(&RecordGetterResult
, &reported_info
));
342 base::RunLoop().RunUntilIdle();
344 EXPECT_FALSE(reported_info
.IsReady());
345 cryptohome_client_
->SetTPMTokenInfo("TOKEN_1", "2222", 1);
347 EXPECT_TRUE(reported_info
.IsReady());
348 EXPECT_TRUE(reported_info
.enabled
);
349 EXPECT_EQ("TOKEN_1", reported_info
.name
);
350 EXPECT_EQ("2222", reported_info
.pin
);
351 EXPECT_EQ(1, reported_info
.slot_id
);
353 const int64 kExpectedDelays
[] = {100};
354 EXPECT_EQ(std::vector
<int64
>(kExpectedDelays
,
355 kExpectedDelays
+ arraysize(kExpectedDelays
)),
359 TEST_F(SystemTPMTokenInfoGetterTest
, GetTpmTokenInfoInitiallyNotReady
) {
360 cryptohome_client_
->set_get_tpm_token_info_not_set_count(1);
362 TestTPMTokenInfo reported_info
;
363 tpm_token_info_getter_
->Start(
364 base::Bind(&RecordGetterResult
, &reported_info
));
365 base::RunLoop().RunUntilIdle();
367 EXPECT_FALSE(reported_info
.IsReady());
368 cryptohome_client_
->SetTPMTokenInfo("TOKEN_1", "2222", 1);
370 EXPECT_TRUE(reported_info
.IsReady());
371 EXPECT_TRUE(reported_info
.enabled
);
372 EXPECT_EQ("TOKEN_1", reported_info
.name
);
373 EXPECT_EQ("2222", reported_info
.pin
);
374 EXPECT_EQ(1, reported_info
.slot_id
);
376 const int64 kExpectedDelays
[] = {100};
377 EXPECT_EQ(std::vector
<int64
>(kExpectedDelays
,
378 kExpectedDelays
+ arraysize(kExpectedDelays
)),
382 TEST_F(SystemTPMTokenInfoGetterTest
, GetTpmTokenInfoInitiallyFails
) {
383 cryptohome_client_
->set_get_tpm_token_info_failure_count(1);
385 TestTPMTokenInfo reported_info
;
386 tpm_token_info_getter_
->Start(
387 base::Bind(&RecordGetterResult
, &reported_info
));
388 base::RunLoop().RunUntilIdle();
390 EXPECT_FALSE(reported_info
.IsReady());
391 cryptohome_client_
->SetTPMTokenInfo("TOKEN_1", "2222", 1);
393 EXPECT_TRUE(reported_info
.IsReady());
394 EXPECT_TRUE(reported_info
.enabled
);
395 EXPECT_EQ("TOKEN_1", reported_info
.name
);
396 EXPECT_EQ("2222", reported_info
.pin
);
397 EXPECT_EQ(1, reported_info
.slot_id
);
399 const int64 kExpectedDelays
[] = {100};
400 EXPECT_EQ(std::vector
<int64
>(kExpectedDelays
,
401 kExpectedDelays
+ arraysize(kExpectedDelays
)),
405 TEST_F(SystemTPMTokenInfoGetterTest
, RetryDelaysIncreaseExponentially
) {
406 cryptohome_client_
->set_tpm_is_enabled_failure_count(2);
407 cryptohome_client_
->set_get_tpm_token_info_failure_count(1);
408 cryptohome_client_
->set_get_tpm_token_info_not_set_count(3);
410 TestTPMTokenInfo reported_info
;
411 tpm_token_info_getter_
->Start(
412 base::Bind(&RecordGetterResult
, &reported_info
));
413 base::RunLoop().RunUntilIdle();
415 EXPECT_FALSE(reported_info
.IsReady());
416 cryptohome_client_
->SetTPMTokenInfo("TOKEN_1", "2222", 2);
418 EXPECT_TRUE(reported_info
.IsReady());
419 EXPECT_TRUE(reported_info
.enabled
);
420 EXPECT_EQ("TOKEN_1", reported_info
.name
);
421 EXPECT_EQ("2222", reported_info
.pin
);
422 EXPECT_EQ(2, reported_info
.slot_id
);
424 int64 kExpectedDelays
[] = { 100, 200, 400, 800, 1600, 3200 };
426 std::vector
<int64
>(kExpectedDelays
,
427 kExpectedDelays
+ arraysize(kExpectedDelays
)),
431 TEST_F(SystemTPMTokenInfoGetterTest
, RetryDelayBounded
) {
432 cryptohome_client_
->set_tpm_is_enabled_failure_count(4);
433 cryptohome_client_
->set_get_tpm_token_info_failure_count(5);
434 cryptohome_client_
->set_get_tpm_token_info_not_set_count(6);
436 TestTPMTokenInfo reported_info
;
437 tpm_token_info_getter_
->Start(
438 base::Bind(&RecordGetterResult
, &reported_info
));
439 base::RunLoop().RunUntilIdle();
441 EXPECT_FALSE(reported_info
.IsReady());
442 cryptohome_client_
->SetTPMTokenInfo("TOKEN_1", "2222", 1);
444 EXPECT_TRUE(reported_info
.IsReady());
445 EXPECT_TRUE(reported_info
.enabled
);
446 EXPECT_EQ("TOKEN_1", reported_info
.name
);
447 EXPECT_EQ("2222", reported_info
.pin
);
448 EXPECT_EQ(1, reported_info
.slot_id
);
450 int64 kExpectedDelays
[] = {
451 100, 200, 400, 800, 1600, 3200, 6400, 12800, 25600, 51200, 102400, 204800,
452 300000, 300000, 300000
455 std::vector
<int64
>(kExpectedDelays
,
456 kExpectedDelays
+ arraysize(kExpectedDelays
)),
460 TEST_F(UserTPMTokenInfoGetterTest
, BasicFlow
) {
461 TestTPMTokenInfo reported_info
;
462 tpm_token_info_getter_
->Start(
463 base::Bind(&RecordGetterResult
, &reported_info
));
464 base::RunLoop().RunUntilIdle();
466 EXPECT_FALSE(reported_info
.IsReady());
467 cryptohome_client_
->SetTPMTokenInfo("TOKEN_1", "2222", 1);
469 EXPECT_TRUE(reported_info
.IsReady());
470 EXPECT_TRUE(reported_info
.enabled
);
471 EXPECT_EQ("TOKEN_1", reported_info
.name
);
472 EXPECT_EQ("2222", reported_info
.pin
);
473 EXPECT_EQ(1, reported_info
.slot_id
);
475 EXPECT_EQ(std::vector
<int64
>(), delays_
);
478 TEST_F(UserTPMTokenInfoGetterTest
, GetTpmTokenInfoInitiallyFails
) {
479 cryptohome_client_
->set_get_tpm_token_info_failure_count(1);
481 TestTPMTokenInfo reported_info
;
482 tpm_token_info_getter_
->Start(
483 base::Bind(&RecordGetterResult
, &reported_info
));
484 base::RunLoop().RunUntilIdle();
486 EXPECT_FALSE(reported_info
.IsReady());
487 cryptohome_client_
->SetTPMTokenInfo("TOKEN_1", "2222", 1);
489 EXPECT_TRUE(reported_info
.IsReady());
490 EXPECT_TRUE(reported_info
.enabled
);
491 EXPECT_EQ("TOKEN_1", reported_info
.name
);
492 EXPECT_EQ("2222", reported_info
.pin
);
493 EXPECT_EQ(1, reported_info
.slot_id
);
495 const int64 kExpectedDelays
[] = {100};
496 EXPECT_EQ(std::vector
<int64
>(kExpectedDelays
,
497 kExpectedDelays
+ arraysize(kExpectedDelays
)),
501 TEST_F(UserTPMTokenInfoGetterTest
, GetTpmTokenInfoInitiallyNotReady
) {
502 cryptohome_client_
->set_get_tpm_token_info_not_set_count(1);
504 TestTPMTokenInfo reported_info
;
505 tpm_token_info_getter_
->Start(
506 base::Bind(&RecordGetterResult
, &reported_info
));
507 base::RunLoop().RunUntilIdle();
509 EXPECT_FALSE(reported_info
.IsReady());
510 cryptohome_client_
->SetTPMTokenInfo("TOKEN_1", "2222", 1);
512 EXPECT_TRUE(reported_info
.IsReady());
513 EXPECT_TRUE(reported_info
.enabled
);
514 EXPECT_EQ("TOKEN_1", reported_info
.name
);
515 EXPECT_EQ("2222", reported_info
.pin
);
516 EXPECT_EQ(1, reported_info
.slot_id
);
518 const int64 kExpectedDelays
[] = {100};
519 EXPECT_EQ(std::vector
<int64
>(kExpectedDelays
,
520 kExpectedDelays
+ arraysize(kExpectedDelays
)),