platform_verification_flow_unittest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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. 4 5#include <string> 6 7#include "base/bind.h" 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/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/content_settings/host_content_settings_map.h" 18#include "chrome/browser/profiles/profile_impl.h" 19#include "chrome/browser/renderer_host/pepper/device_id_fetcher.h" 20#include "chrome/common/content_settings_pattern.h" 21#include "chrome/common/pref_names.h" 22#include "chrome/test/base/testing_pref_service_syncable.h" 23#include "chromeos/attestation/mock_attestation_flow.h" 24#include "chromeos/cryptohome/mock_async_method_caller.h" 25#include "chromeos/dbus/fake_cryptohome_client.h" 26#include "chromeos/settings/cros_settings_names.h" 27#include "content/public/test/test_browser_thread.h" 28#include "testing/gtest/include/gtest/gtest.h" 29 30using testing::_; 31using testing::DoAll; 32using testing::Invoke; 33using testing::Return; 34using testing::SetArgumentPointee; 35using testing::StrictMock; 36using testing::WithArgs; 37 38namespace chromeos { 39namespace attestation { 40 41namespace { 42 43const char kTestID[] = "test_id"; 44const char kTestChallenge[] = "test_challenge"; 45const char kTestSignedData[] = "test_challenge_with_salt"; 46const char kTestSignature[] = "test_signature"; 47const char kTestCertificate[] = "test_certificate"; 48const char kTestEmail[] = "test_email@chromium.org"; 49const char kTestURL[] = "http://mytestdomain/test"; 50const char kTestURLSecure[] = "https://mytestdomain/test"; 51 52class FakeDelegate : public PlatformVerificationFlow::Delegate { 53 public: 54 FakeDelegate() : response_(PlatformVerificationFlow::CONSENT_RESPONSE_ALLOW), 55 num_consent_calls_(0), 56 url_(kTestURL), 57 is_incognito_(false) { 58 // Configure a user for the mock user manager. 59 mock_user_manager_.SetActiveUser(kTestEmail); 60 } 61 virtual ~FakeDelegate() {} 62 63 void SetUp() { 64 ProfileImpl::RegisterProfilePrefs(pref_service_.registry()); 65 chrome::DeviceIDFetcher::RegisterProfilePrefs(pref_service_.registry()); 66 PlatformVerificationFlow::RegisterProfilePrefs(pref_service_.registry()); 67 HostContentSettingsMap::RegisterProfilePrefs(pref_service_.registry()); 68 content_settings_ = new HostContentSettingsMap(&pref_service_, false); 69 } 70 71 void TearDown() { 72 content_settings_->ShutdownOnUIThread(); 73 } 74 75 virtual void ShowConsentPrompt( 76 content::WebContents* web_contents, 77 const PlatformVerificationFlow::Delegate::ConsentCallback& callback) 78 OVERRIDE { 79 num_consent_calls_++; 80 callback.Run(response_); 81 } 82 83 virtual PrefService* GetPrefs(content::WebContents* web_contents) OVERRIDE { 84 return &pref_service_; 85 } 86 87 virtual const GURL& GetURL(content::WebContents* web_contents) OVERRIDE { 88 return url_; 89 } 90 91 virtual User* GetUser(content::WebContents* web_contents) OVERRIDE { 92 return mock_user_manager_.GetActiveUser(); 93 } 94 95 virtual HostContentSettingsMap* GetContentSettings( 96 content::WebContents* web_contents) OVERRIDE { 97 return content_settings_; 98 } 99 100 virtual bool IsGuestOrIncognito(content::WebContents* web_contents) OVERRIDE { 101 return is_incognito_; 102 } 103 104 void set_response(PlatformVerificationFlow::ConsentResponse response) { 105 response_ = response; 106 } 107 108 int num_consent_calls() { 109 return num_consent_calls_; 110 } 111 112 TestingPrefServiceSyncable& pref_service() { 113 return pref_service_; 114 } 115 116 void set_url(const GURL& url) { 117 url_ = url; 118 } 119 120 void set_is_incognito(bool is_incognito) { 121 is_incognito_ = is_incognito; 122 } 123 124 private: 125 PlatformVerificationFlow::ConsentResponse response_; 126 int num_consent_calls_; 127 TestingPrefServiceSyncable pref_service_; 128 MockUserManager mock_user_manager_; 129 GURL url_; 130 scoped_refptr<HostContentSettingsMap> content_settings_; 131 bool is_incognito_; 132 133 DISALLOW_COPY_AND_ASSIGN(FakeDelegate); 134}; 135 136class CustomFakeCryptohomeClient : public FakeCryptohomeClient { 137 public: 138 CustomFakeCryptohomeClient() : call_status_(DBUS_METHOD_CALL_SUCCESS), 139 attestation_enrolled_(true), 140 attestation_prepared_(true) {} 141 virtual void TpmAttestationIsEnrolled( 142 const BoolDBusMethodCallback& callback) OVERRIDE { 143 base::MessageLoop::current()->PostTask(FROM_HERE, 144 base::Bind(callback, 145 call_status_, 146 attestation_enrolled_)); 147 } 148 149 virtual void TpmAttestationIsPrepared( 150 const BoolDBusMethodCallback& callback) OVERRIDE { 151 base::MessageLoop::current()->PostTask(FROM_HERE, 152 base::Bind(callback, 153 call_status_, 154 attestation_prepared_)); 155 } 156 157 void set_call_status(DBusMethodCallStatus call_status) { 158 call_status_ = call_status; 159 } 160 161 void set_attestation_enrolled(bool attestation_enrolled) { 162 attestation_enrolled_ = attestation_enrolled; 163 } 164 165 void set_attestation_prepared(bool attestation_prepared) { 166 attestation_prepared_ = attestation_prepared; 167 } 168 169 private: 170 DBusMethodCallStatus call_status_; 171 bool attestation_enrolled_; 172 bool attestation_prepared_; 173}; 174 175} // namespace 176 177class PlatformVerificationFlowTest : public ::testing::Test { 178 public: 179 PlatformVerificationFlowTest() 180 : ui_thread_(content::BrowserThread::UI, &message_loop_), 181 certificate_success_(true), 182 fake_certificate_index_(0), 183 sign_challenge_success_(true), 184 result_(PlatformVerificationFlow::INTERNAL_ERROR) {} 185 186 void SetUp() { 187 fake_delegate_.SetUp(); 188 189 // Create a verifier for tests to call. 190 verifier_ = new PlatformVerificationFlow(&mock_attestation_flow_, 191 &mock_async_caller_, 192 &fake_cryptohome_client_, 193 &fake_delegate_); 194 195 // Create callbacks for tests to use with verifier_. 196 callback_ = base::Bind(&PlatformVerificationFlowTest::FakeChallengeCallback, 197 base::Unretained(this)); 198 199 // Configure the global cros_settings. 200 CrosSettings* cros_settings = CrosSettings::Get(); 201 device_settings_provider_ = 202 cros_settings->GetProvider(kAttestationForContentProtectionEnabled); 203 cros_settings->RemoveSettingsProvider(device_settings_provider_); 204 cros_settings->AddSettingsProvider(&stub_settings_provider_); 205 cros_settings->SetBoolean(kAttestationForContentProtectionEnabled, true); 206 207 // Start with the first-time setting set since most tests want this. 208 fake_delegate_.pref_service().SetUserPref(prefs::kRAConsentFirstTime, 209 new base::FundamentalValue(true)); 210 211 } 212 213 void TearDown() { 214 // Restore the real DeviceSettingsProvider. 215 CrosSettings* cros_settings = CrosSettings::Get(); 216 cros_settings->RemoveSettingsProvider(&stub_settings_provider_); 217 cros_settings->AddSettingsProvider(device_settings_provider_); 218 fake_delegate_.TearDown(); 219 } 220 221 void ExpectAttestationFlow() { 222 // When consent is not given or the feature is disabled, it is important 223 // that there are no calls to the attestation service. Thus, a test must 224 // explicitly expect these calls or the mocks will fail the test. 225 226 // Configure the mock AttestationFlow to call FakeGetCertificate. 227 EXPECT_CALL(mock_attestation_flow_, 228 GetCertificate(PROFILE_CONTENT_PROTECTION_CERTIFICATE, 229 kTestEmail, kTestID, _, _)) 230 .WillRepeatedly(WithArgs<4>(Invoke( 231 this, &PlatformVerificationFlowTest::FakeGetCertificate))); 232 233 // Configure the mock AsyncMethodCaller to call FakeSignChallenge. 234 std::string expected_key_name = std::string(kContentProtectionKeyPrefix) + 235 std::string(kTestID); 236 EXPECT_CALL(mock_async_caller_, 237 TpmAttestationSignSimpleChallenge(KEY_USER, kTestEmail, 238 expected_key_name, 239 kTestChallenge, _)) 240 .WillRepeatedly(WithArgs<4>(Invoke( 241 this, &PlatformVerificationFlowTest::FakeSignChallenge))); 242 } 243 244 void SetUserConsent(const GURL& url, bool allow) { 245 verifier_->RecordDomainConsent(fake_delegate_.GetContentSettings(NULL), 246 url, 247 allow); 248 } 249 250 void FakeGetCertificate( 251 const AttestationFlow::CertificateCallback& callback) { 252 std::string certificate = 253 (fake_certificate_index_ < fake_certificate_list_.size()) ? 254 fake_certificate_list_[fake_certificate_index_] : kTestCertificate; 255 base::MessageLoop::current()->PostTask(FROM_HERE, 256 base::Bind(callback, 257 certificate_success_, 258 certificate)); 259 ++fake_certificate_index_; 260 } 261 262 void FakeSignChallenge( 263 const cryptohome::AsyncMethodCaller::DataCallback& callback) { 264 base::MessageLoop::current()->PostTask( 265 FROM_HERE, 266 base::Bind(callback, 267 sign_challenge_success_, 268 CreateFakeResponseProto())); 269 } 270 271 void FakeChallengeCallback(PlatformVerificationFlow::Result result, 272 const std::string& salt, 273 const std::string& signature, 274 const std::string& certificate) { 275 result_ = result; 276 challenge_salt_ = salt; 277 challenge_signature_ = signature; 278 certificate_ = certificate; 279 } 280 281 std::string CreateFakeResponseProto() { 282 SignedData pb; 283 pb.set_data(kTestSignedData); 284 pb.set_signature(kTestSignature); 285 std::string serial; 286 CHECK(pb.SerializeToString(&serial)); 287 return serial; 288 } 289 290 protected: 291 base::MessageLoopForUI message_loop_; 292 content::TestBrowserThread ui_thread_; 293 StrictMock<MockAttestationFlow> mock_attestation_flow_; 294 cryptohome::MockAsyncMethodCaller mock_async_caller_; 295 CustomFakeCryptohomeClient fake_cryptohome_client_; 296 FakeDelegate fake_delegate_; 297 CrosSettingsProvider* device_settings_provider_; 298 StubCrosSettingsProvider stub_settings_provider_; 299 ScopedTestDeviceSettingsService test_device_settings_service_; 300 ScopedTestCrosSettings test_cros_settings_; 301 scoped_refptr<PlatformVerificationFlow> verifier_; 302 303 // Controls result of FakeGetCertificate. 304 bool certificate_success_; 305 std::vector<std::string> fake_certificate_list_; 306 size_t fake_certificate_index_; 307 308 // Controls result of FakeSignChallenge. 309 bool sign_challenge_success_; 310 311 // Callback functions and data. 312 PlatformVerificationFlow::ChallengeCallback callback_; 313 PlatformVerificationFlow::Result result_; 314 std::string challenge_salt_; 315 std::string challenge_signature_; 316 std::string certificate_; 317}; 318 319TEST_F(PlatformVerificationFlowTest, SuccessNoConsent) { 320 SetUserConsent(GURL(kTestURL), true); 321 // Make sure the call will fail if consent is requested. 322 fake_delegate_.set_response(PlatformVerificationFlow::CONSENT_RESPONSE_DENY); 323 ExpectAttestationFlow(); 324 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 325 base::RunLoop().RunUntilIdle(); 326 EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_); 327 EXPECT_EQ(kTestSignedData, challenge_salt_); 328 EXPECT_EQ(kTestSignature, challenge_signature_); 329 EXPECT_EQ(kTestCertificate, certificate_); 330 EXPECT_EQ(0, fake_delegate_.num_consent_calls()); 331} 332 333TEST_F(PlatformVerificationFlowTest, SuccessWithAttestationConsent) { 334 SetUserConsent(GURL(kTestURL), true); 335 fake_cryptohome_client_.set_attestation_enrolled(false); 336 ExpectAttestationFlow(); 337 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 338 base::RunLoop().RunUntilIdle(); 339 EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_); 340 EXPECT_EQ(kTestSignedData, challenge_salt_); 341 EXPECT_EQ(kTestSignature, challenge_signature_); 342 EXPECT_EQ(kTestCertificate, certificate_); 343 EXPECT_EQ(1, fake_delegate_.num_consent_calls()); 344} 345 346TEST_F(PlatformVerificationFlowTest, SuccessWithFirstTimeConsent) { 347 SetUserConsent(GURL(kTestURL), true); 348 fake_delegate_.pref_service().SetUserPref(prefs::kRAConsentFirstTime, 349 new base::FundamentalValue(false)); 350 ExpectAttestationFlow(); 351 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 352 base::RunLoop().RunUntilIdle(); 353 EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_); 354 EXPECT_EQ(kTestSignedData, challenge_salt_); 355 EXPECT_EQ(kTestSignature, challenge_signature_); 356 EXPECT_EQ(kTestCertificate, certificate_); 357 EXPECT_EQ(1, fake_delegate_.num_consent_calls()); 358} 359 360TEST_F(PlatformVerificationFlowTest, ConsentRejected) { 361 fake_delegate_.set_response(PlatformVerificationFlow::CONSENT_RESPONSE_DENY); 362 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 363 base::RunLoop().RunUntilIdle(); 364 EXPECT_EQ(PlatformVerificationFlow::USER_REJECTED, result_); 365 EXPECT_EQ(1, fake_delegate_.num_consent_calls()); 366} 367 368TEST_F(PlatformVerificationFlowTest, FeatureDisabled) { 369 CrosSettings::Get()->SetBoolean(kAttestationForContentProtectionEnabled, 370 false); 371 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 372 base::RunLoop().RunUntilIdle(); 373 EXPECT_EQ(PlatformVerificationFlow::POLICY_REJECTED, result_); 374 EXPECT_EQ(0, fake_delegate_.num_consent_calls()); 375} 376 377TEST_F(PlatformVerificationFlowTest, FeatureDisabledByUser) { 378 fake_delegate_.pref_service().SetUserPref(prefs::kEnableDRM, 379 new base::FundamentalValue(false)); 380 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 381 base::RunLoop().RunUntilIdle(); 382 EXPECT_EQ(PlatformVerificationFlow::POLICY_REJECTED, result_); 383 EXPECT_EQ(0, fake_delegate_.num_consent_calls()); 384} 385 386TEST_F(PlatformVerificationFlowTest, FeatureDisabledByUserForDomain) { 387 SetUserConsent(GURL(kTestURL), false); 388 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 389 base::RunLoop().RunUntilIdle(); 390 EXPECT_EQ(PlatformVerificationFlow::POLICY_REJECTED, result_); 391 EXPECT_EQ(0, fake_delegate_.num_consent_calls()); 392} 393 394TEST_F(PlatformVerificationFlowTest, NotVerified) { 395 certificate_success_ = false; 396 ExpectAttestationFlow(); 397 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 398 base::RunLoop().RunUntilIdle(); 399 EXPECT_EQ(PlatformVerificationFlow::PLATFORM_NOT_VERIFIED, result_); 400} 401 402TEST_F(PlatformVerificationFlowTest, ChallengeSigningError) { 403 sign_challenge_success_ = false; 404 ExpectAttestationFlow(); 405 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 406 base::RunLoop().RunUntilIdle(); 407 EXPECT_EQ(PlatformVerificationFlow::INTERNAL_ERROR, result_); 408} 409 410TEST_F(PlatformVerificationFlowTest, DBusFailure) { 411 fake_cryptohome_client_.set_call_status(DBUS_METHOD_CALL_FAILURE); 412 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 413 base::RunLoop().RunUntilIdle(); 414 EXPECT_EQ(PlatformVerificationFlow::INTERNAL_ERROR, result_); 415} 416 417TEST_F(PlatformVerificationFlowTest, ConsentNoResponse) { 418 fake_delegate_.set_response(PlatformVerificationFlow::CONSENT_RESPONSE_NONE); 419 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 420 base::RunLoop().RunUntilIdle(); 421 EXPECT_EQ(PlatformVerificationFlow::USER_REJECTED, result_); 422} 423 424TEST_F(PlatformVerificationFlowTest, ConsentPerScheme) { 425 fake_delegate_.set_response(PlatformVerificationFlow::CONSENT_RESPONSE_DENY); 426 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 427 base::RunLoop().RunUntilIdle(); 428 EXPECT_EQ(PlatformVerificationFlow::USER_REJECTED, result_); 429 // Call again and expect denial based on previous response. 430 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 431 base::RunLoop().RunUntilIdle(); 432 EXPECT_EQ(PlatformVerificationFlow::POLICY_REJECTED, result_); 433 // Call with a different scheme and expect another consent prompt. 434 fake_delegate_.set_url(GURL(kTestURLSecure)); 435 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 436 base::RunLoop().RunUntilIdle(); 437 EXPECT_EQ(PlatformVerificationFlow::USER_REJECTED, result_); 438 EXPECT_EQ(2, fake_delegate_.num_consent_calls()); 439} 440 441TEST_F(PlatformVerificationFlowTest, Timeout) { 442 verifier_->set_timeout_delay(base::TimeDelta::FromSeconds(0)); 443 ExpectAttestationFlow(); 444 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 445 base::RunLoop().RunUntilIdle(); 446 EXPECT_EQ(PlatformVerificationFlow::TIMEOUT, result_); 447} 448 449TEST_F(PlatformVerificationFlowTest, ExpiredCert) { 450 ExpectAttestationFlow(); 451 fake_certificate_list_.resize(2); 452 ASSERT_TRUE(GetFakeCertificate(base::TimeDelta::FromDays(-1), 453 &fake_certificate_list_[0])); 454 ASSERT_TRUE(GetFakeCertificate(base::TimeDelta::FromDays(1), 455 &fake_certificate_list_[1])); 456 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 457 base::RunLoop().RunUntilIdle(); 458 EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_); 459 EXPECT_EQ(certificate_, fake_certificate_list_[1]); 460} 461 462TEST_F(PlatformVerificationFlowTest, IncognitoMode) { 463 fake_delegate_.set_is_incognito(true); 464 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 465 base::RunLoop().RunUntilIdle(); 466 EXPECT_EQ(PlatformVerificationFlow::PLATFORM_NOT_VERIFIED, result_); 467} 468 469} // namespace attestation 470} // namespace chromeos 471