1 // Copyright 2013 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.
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "chrome/browser/chromeos/attestation/attestation_signed_data.pb.h"
11 #include "chrome/browser/chromeos/attestation/fake_certificate.h"
12 #include "chrome/browser/chromeos/attestation/platform_verification_flow.h"
13 #include "chrome/browser/chromeos/login/users/mock_user_manager.h"
14 #include "chrome/browser/chromeos/settings/cros_settings.h"
15 #include "chrome/browser/chromeos/settings/device_settings_service.h"
16 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
17 #include "chrome/browser/profiles/profile_impl.h"
18 #include "chrome/common/pref_names.h"
19 #include "chromeos/attestation/mock_attestation_flow.h"
20 #include "chromeos/cryptohome/mock_async_method_caller.h"
21 #include "chromeos/dbus/fake_cryptohome_client.h"
22 #include "chromeos/settings/cros_settings_names.h"
23 #include "content/public/test/test_browser_thread.h"
24 #include "testing/gtest/include/gtest/gtest.h"
28 using testing::Invoke
;
29 using testing::Return
;
30 using testing::SetArgumentPointee
;
31 using testing::StrictMock
;
32 using testing::WithArgs
;
35 namespace attestation
{
39 const char kTestID
[] = "test_id";
40 const char kTestChallenge
[] = "test_challenge";
41 const char kTestSignedData
[] = "test_challenge_with_salt";
42 const char kTestSignature
[] = "test_signature";
43 const char kTestCertificate
[] = "test_certificate";
44 const char kTestEmail
[] = "test_email@chromium.org";
45 const char kTestURL
[] = "http://mytestdomain/test";
47 class FakeDelegate
: public PlatformVerificationFlow::Delegate
{
51 is_permitted_by_user_(true),
52 is_in_supported_mode_(true) {
53 // Configure a user for the mock user manager.
54 mock_user_manager_
.SetActiveUser(kTestEmail
);
56 ~FakeDelegate() override
{}
58 const GURL
& GetURL(content::WebContents
* web_contents
) override
{
62 user_manager::User
* GetUser(content::WebContents
* web_contents
) override
{
63 return mock_user_manager_
.GetActiveUser();
66 bool IsPermittedByUser(content::WebContents
* web_contents
) override
{
67 return is_permitted_by_user_
;
70 bool IsInSupportedMode(content::WebContents
* web_contents
) override
{
71 return is_in_supported_mode_
;
74 void set_url(const GURL
& url
) {
78 void set_is_permitted_by_user(bool is_permitted_by_user
) {
79 is_permitted_by_user_
= is_permitted_by_user
;
82 void set_is_in_supported_mode(bool is_in_supported_mode
) {
83 is_in_supported_mode_
= is_in_supported_mode
;
87 MockUserManager mock_user_manager_
;
89 bool is_permitted_by_user_
;
90 bool is_in_supported_mode_
;
92 DISALLOW_COPY_AND_ASSIGN(FakeDelegate
);
95 class CustomFakeCryptohomeClient
: public FakeCryptohomeClient
{
97 CustomFakeCryptohomeClient() : call_status_(DBUS_METHOD_CALL_SUCCESS
),
98 attestation_enrolled_(true),
99 attestation_prepared_(true) {}
100 void TpmAttestationIsEnrolled(
101 const BoolDBusMethodCallback
& callback
) override
{
102 base::MessageLoop::current()->PostTask(FROM_HERE
,
105 attestation_enrolled_
));
108 void TpmAttestationIsPrepared(
109 const BoolDBusMethodCallback
& callback
) override
{
110 base::MessageLoop::current()->PostTask(FROM_HERE
,
113 attestation_prepared_
));
116 void set_call_status(DBusMethodCallStatus call_status
) {
117 call_status_
= call_status
;
120 void set_attestation_enrolled(bool attestation_enrolled
) {
121 attestation_enrolled_
= attestation_enrolled
;
124 void set_attestation_prepared(bool attestation_prepared
) {
125 attestation_prepared_
= attestation_prepared
;
129 DBusMethodCallStatus call_status_
;
130 bool attestation_enrolled_
;
131 bool attestation_prepared_
;
136 class PlatformVerificationFlowTest
: public ::testing::Test
{
138 PlatformVerificationFlowTest()
139 : ui_thread_(content::BrowserThread::UI
, &message_loop_
),
140 certificate_success_(true),
141 fake_certificate_index_(0),
142 sign_challenge_success_(true),
143 result_(PlatformVerificationFlow::INTERNAL_ERROR
) {}
146 // Create a verifier for tests to call.
147 verifier_
= new PlatformVerificationFlow(&mock_attestation_flow_
,
149 &fake_cryptohome_client_
,
152 // Create callbacks for tests to use with verifier_.
153 callback_
= base::Bind(&PlatformVerificationFlowTest::FakeChallengeCallback
,
154 base::Unretained(this));
156 // Configure the global cros_settings.
157 CrosSettings
* cros_settings
= CrosSettings::Get();
158 device_settings_provider_
=
159 cros_settings
->GetProvider(kAttestationForContentProtectionEnabled
);
160 cros_settings
->RemoveSettingsProvider(device_settings_provider_
);
161 cros_settings
->AddSettingsProvider(&stub_settings_provider_
);
162 cros_settings
->SetBoolean(kAttestationForContentProtectionEnabled
, true);
166 // Restore the real DeviceSettingsProvider.
167 CrosSettings
* cros_settings
= CrosSettings::Get();
168 cros_settings
->RemoveSettingsProvider(&stub_settings_provider_
);
169 cros_settings
->AddSettingsProvider(device_settings_provider_
);
172 void ExpectAttestationFlow() {
173 // When consent is not given or the feature is disabled, it is important
174 // that there are no calls to the attestation service. Thus, a test must
175 // explicitly expect these calls or the mocks will fail the test.
177 // Configure the mock AttestationFlow to call FakeGetCertificate.
178 EXPECT_CALL(mock_attestation_flow_
,
179 GetCertificate(PROFILE_CONTENT_PROTECTION_CERTIFICATE
,
180 kTestEmail
, kTestID
, _
, _
))
181 .WillRepeatedly(WithArgs
<4>(Invoke(
182 this, &PlatformVerificationFlowTest::FakeGetCertificate
)));
184 // Configure the mock AsyncMethodCaller to call FakeSignChallenge.
185 std::string expected_key_name
= std::string(kContentProtectionKeyPrefix
) +
186 std::string(kTestID
);
187 EXPECT_CALL(mock_async_caller_
,
188 TpmAttestationSignSimpleChallenge(KEY_USER
, kTestEmail
,
191 .WillRepeatedly(WithArgs
<4>(Invoke(
192 this, &PlatformVerificationFlowTest::FakeSignChallenge
)));
195 void FakeGetCertificate(
196 const AttestationFlow::CertificateCallback
& callback
) {
197 std::string certificate
=
198 (fake_certificate_index_
< fake_certificate_list_
.size()) ?
199 fake_certificate_list_
[fake_certificate_index_
] : kTestCertificate
;
200 base::MessageLoop::current()->PostTask(FROM_HERE
,
202 certificate_success_
,
204 ++fake_certificate_index_
;
207 void FakeSignChallenge(
208 const cryptohome::AsyncMethodCaller::DataCallback
& callback
) {
209 base::MessageLoop::current()->PostTask(
212 sign_challenge_success_
,
213 CreateFakeResponseProto()));
216 void FakeChallengeCallback(PlatformVerificationFlow::Result result
,
217 const std::string
& salt
,
218 const std::string
& signature
,
219 const std::string
& certificate
) {
221 challenge_salt_
= salt
;
222 challenge_signature_
= signature
;
223 certificate_
= certificate
;
226 std::string
CreateFakeResponseProto() {
228 pb
.set_data(kTestSignedData
);
229 pb
.set_signature(kTestSignature
);
231 CHECK(pb
.SerializeToString(&serial
));
236 base::MessageLoopForUI message_loop_
;
237 content::TestBrowserThread ui_thread_
;
238 StrictMock
<MockAttestationFlow
> mock_attestation_flow_
;
239 cryptohome::MockAsyncMethodCaller mock_async_caller_
;
240 CustomFakeCryptohomeClient fake_cryptohome_client_
;
241 FakeDelegate fake_delegate_
;
242 CrosSettingsProvider
* device_settings_provider_
;
243 StubCrosSettingsProvider stub_settings_provider_
;
244 ScopedTestDeviceSettingsService test_device_settings_service_
;
245 ScopedTestCrosSettings test_cros_settings_
;
246 scoped_refptr
<PlatformVerificationFlow
> verifier_
;
248 // Controls result of FakeGetCertificate.
249 bool certificate_success_
;
250 std::vector
<std::string
> fake_certificate_list_
;
251 size_t fake_certificate_index_
;
253 // Controls result of FakeSignChallenge.
254 bool sign_challenge_success_
;
256 // Callback functions and data.
257 PlatformVerificationFlow::ChallengeCallback callback_
;
258 PlatformVerificationFlow::Result result_
;
259 std::string challenge_salt_
;
260 std::string challenge_signature_
;
261 std::string certificate_
;
264 TEST_F(PlatformVerificationFlowTest
, Success
) {
265 ExpectAttestationFlow();
266 verifier_
->ChallengePlatformKey(NULL
, kTestID
, kTestChallenge
, callback_
);
267 base::RunLoop().RunUntilIdle();
268 EXPECT_EQ(PlatformVerificationFlow::SUCCESS
, result_
);
269 EXPECT_EQ(kTestSignedData
, challenge_salt_
);
270 EXPECT_EQ(kTestSignature
, challenge_signature_
);
271 EXPECT_EQ(kTestCertificate
, certificate_
);
274 TEST_F(PlatformVerificationFlowTest
, NotPermittedByUser
) {
275 fake_delegate_
.set_is_permitted_by_user(false);
276 verifier_
->ChallengePlatformKey(NULL
, kTestID
, kTestChallenge
, callback_
);
277 base::RunLoop().RunUntilIdle();
278 EXPECT_EQ(PlatformVerificationFlow::USER_REJECTED
, result_
);
281 TEST_F(PlatformVerificationFlowTest
, FeatureDisabledByPolicy
) {
282 CrosSettings::Get()->SetBoolean(kAttestationForContentProtectionEnabled
,
284 verifier_
->ChallengePlatformKey(NULL
, kTestID
, kTestChallenge
, callback_
);
285 base::RunLoop().RunUntilIdle();
286 EXPECT_EQ(PlatformVerificationFlow::POLICY_REJECTED
, result_
);
289 TEST_F(PlatformVerificationFlowTest
, NotVerified
) {
290 certificate_success_
= false;
291 ExpectAttestationFlow();
292 verifier_
->ChallengePlatformKey(NULL
, kTestID
, kTestChallenge
, callback_
);
293 base::RunLoop().RunUntilIdle();
294 EXPECT_EQ(PlatformVerificationFlow::PLATFORM_NOT_VERIFIED
, result_
);
297 TEST_F(PlatformVerificationFlowTest
, ChallengeSigningError
) {
298 sign_challenge_success_
= false;
299 ExpectAttestationFlow();
300 verifier_
->ChallengePlatformKey(NULL
, kTestID
, kTestChallenge
, callback_
);
301 base::RunLoop().RunUntilIdle();
302 EXPECT_EQ(PlatformVerificationFlow::INTERNAL_ERROR
, result_
);
305 TEST_F(PlatformVerificationFlowTest
, DBusFailure
) {
306 fake_cryptohome_client_
.set_call_status(DBUS_METHOD_CALL_FAILURE
);
307 verifier_
->ChallengePlatformKey(NULL
, kTestID
, kTestChallenge
, callback_
);
308 base::RunLoop().RunUntilIdle();
309 EXPECT_EQ(PlatformVerificationFlow::INTERNAL_ERROR
, result_
);
312 TEST_F(PlatformVerificationFlowTest
, Timeout
) {
313 verifier_
->set_timeout_delay(base::TimeDelta::FromSeconds(0));
314 ExpectAttestationFlow();
315 verifier_
->ChallengePlatformKey(NULL
, kTestID
, kTestChallenge
, callback_
);
316 base::RunLoop().RunUntilIdle();
317 EXPECT_EQ(PlatformVerificationFlow::TIMEOUT
, result_
);
320 TEST_F(PlatformVerificationFlowTest
, ExpiredCert
) {
321 ExpectAttestationFlow();
322 fake_certificate_list_
.resize(2);
323 ASSERT_TRUE(GetFakeCertificate(base::TimeDelta::FromDays(-1),
324 &fake_certificate_list_
[0]));
325 ASSERT_TRUE(GetFakeCertificate(base::TimeDelta::FromDays(1),
326 &fake_certificate_list_
[1]));
327 verifier_
->ChallengePlatformKey(NULL
, kTestID
, kTestChallenge
, callback_
);
328 base::RunLoop().RunUntilIdle();
329 EXPECT_EQ(PlatformVerificationFlow::SUCCESS
, result_
);
330 EXPECT_EQ(certificate_
, fake_certificate_list_
[1]);
333 TEST_F(PlatformVerificationFlowTest
, UnsupportedMode
) {
334 fake_delegate_
.set_is_in_supported_mode(false);
335 verifier_
->ChallengePlatformKey(NULL
, kTestID
, kTestChallenge
, callback_
);
336 base::RunLoop().RunUntilIdle();
337 EXPECT_EQ(PlatformVerificationFlow::PLATFORM_NOT_VERIFIED
, result_
);
340 TEST_F(PlatformVerificationFlowTest
, AttestationNotPrepared
) {
341 fake_cryptohome_client_
.set_attestation_enrolled(false);
342 fake_cryptohome_client_
.set_attestation_prepared(false);
343 verifier_
->ChallengePlatformKey(NULL
, kTestID
, kTestChallenge
, callback_
);
344 base::RunLoop().RunUntilIdle();
345 EXPECT_EQ(PlatformVerificationFlow::PLATFORM_NOT_VERIFIED
, result_
);
348 } // namespace attestation
349 } // namespace chromeos