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
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";
51const char kTestURLExtension[] = "chrome-extension://mytestextension";
52
53class 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
138class 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
179class 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
321TEST_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
335TEST_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
348TEST_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
362TEST_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
370TEST_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
379TEST_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
388TEST_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
396TEST_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
404TEST_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
412TEST_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
419TEST_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
426TEST_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
443TEST_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
452TEST_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
460TEST_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
473TEST_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