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