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