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