Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / chromeos / attestation / platform_verification_flow_unittest.cc
blob21dd3c50a8851dcbe6d0e982e7463a904b38e585
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.
5 #include <algorithm>
6 #include <string>
8 #include "base/bind.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "chrome/browser/chromeos/attestation/attestation_signed_data.pb.h"
12 #include "chrome/browser/chromeos/attestation/fake_certificate.h"
13 #include "chrome/browser/chromeos/attestation/platform_verification_flow.h"
14 #include "chrome/browser/chromeos/login/users/mock_user_manager.h"
15 #include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h"
16 #include "chrome/browser/profiles/profile_impl.h"
17 #include "chrome/common/pref_names.h"
18 #include "chromeos/attestation/mock_attestation_flow.h"
19 #include "chromeos/cryptohome/mock_async_method_caller.h"
20 #include "chromeos/dbus/fake_cryptohome_client.h"
21 #include "chromeos/settings/cros_settings_names.h"
22 #include "content/public/test/test_browser_thread.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 using testing::_;
26 using testing::DoAll;
27 using testing::Invoke;
28 using testing::Return;
29 using testing::SetArgumentPointee;
30 using testing::StrictMock;
31 using testing::WithArgs;
33 namespace chromeos {
34 namespace attestation {
36 namespace {
38 const char kTestID[] = "test_id";
39 const char kTestChallenge[] = "test_challenge";
40 const char kTestSignedData[] = "test_challenge_with_salt";
41 const char kTestSignature[] = "test_signature";
42 const char kTestCertificate[] = "test_certificate";
43 const char kTestEmail[] = "test_email@chromium.org";
44 const char kTestURL[] = "http://mytestdomain/test";
46 class FakeDelegate : public PlatformVerificationFlow::Delegate {
47 public:
48 FakeDelegate()
49 : url_(kTestURL),
50 is_permitted_by_user_(true),
51 is_in_supported_mode_(true) {
52 // Configure a user for the mock user manager.
53 mock_user_manager_.SetActiveUser(kTestEmail);
55 ~FakeDelegate() override {}
57 const GURL& GetURL(content::WebContents* web_contents) override {
58 return url_;
61 user_manager::User* GetUser(content::WebContents* web_contents) override {
62 return mock_user_manager_.GetActiveUser();
65 bool IsPermittedByUser(content::WebContents* web_contents) override {
66 return is_permitted_by_user_;
69 bool IsInSupportedMode(content::WebContents* web_contents) override {
70 return is_in_supported_mode_;
73 void set_url(const GURL& url) {
74 url_ = url;
77 void set_is_permitted_by_user(bool is_permitted_by_user) {
78 is_permitted_by_user_ = is_permitted_by_user;
81 void set_is_in_supported_mode(bool is_in_supported_mode) {
82 is_in_supported_mode_ = is_in_supported_mode;
85 private:
86 MockUserManager mock_user_manager_;
87 GURL url_;
88 bool is_permitted_by_user_;
89 bool is_in_supported_mode_;
91 DISALLOW_COPY_AND_ASSIGN(FakeDelegate);
94 class CustomFakeCryptohomeClient : public FakeCryptohomeClient {
95 public:
96 CustomFakeCryptohomeClient() : call_status_(DBUS_METHOD_CALL_SUCCESS),
97 attestation_enrolled_(true),
98 attestation_prepared_(true) {}
99 void TpmAttestationIsEnrolled(
100 const BoolDBusMethodCallback& callback) override {
101 base::MessageLoop::current()->PostTask(FROM_HERE,
102 base::Bind(callback,
103 call_status_,
104 attestation_enrolled_));
107 void TpmAttestationIsPrepared(
108 const BoolDBusMethodCallback& callback) override {
109 base::MessageLoop::current()->PostTask(FROM_HERE,
110 base::Bind(callback,
111 call_status_,
112 attestation_prepared_));
115 void set_call_status(DBusMethodCallStatus call_status) {
116 call_status_ = call_status;
119 void set_attestation_enrolled(bool attestation_enrolled) {
120 attestation_enrolled_ = attestation_enrolled;
123 void set_attestation_prepared(bool attestation_prepared) {
124 attestation_prepared_ = attestation_prepared;
127 private:
128 DBusMethodCallStatus call_status_;
129 bool attestation_enrolled_;
130 bool attestation_prepared_;
133 } // namespace
135 class PlatformVerificationFlowTest : public ::testing::Test {
136 public:
137 PlatformVerificationFlowTest()
138 : ui_thread_(content::BrowserThread::UI, &message_loop_),
139 certificate_success_(true),
140 fake_certificate_index_(0),
141 sign_challenge_success_(true),
142 result_(PlatformVerificationFlow::INTERNAL_ERROR) {}
144 void SetUp() {
145 // Create a verifier for tests to call.
146 verifier_ = new PlatformVerificationFlow(&mock_attestation_flow_,
147 &mock_async_caller_,
148 &fake_cryptohome_client_,
149 &fake_delegate_);
151 // Create callbacks for tests to use with verifier_.
152 callback_ = base::Bind(&PlatformVerificationFlowTest::FakeChallengeCallback,
153 base::Unretained(this));
155 settings_helper_.ReplaceProvider(kAttestationForContentProtectionEnabled);
156 settings_helper_.SetBoolean(kAttestationForContentProtectionEnabled, true);
159 void ExpectAttestationFlow() {
160 // When consent is not given or the feature is disabled, it is important
161 // that there are no calls to the attestation service. Thus, a test must
162 // explicitly expect these calls or the mocks will fail the test.
164 // Configure the mock AttestationFlow to call FakeGetCertificate.
165 EXPECT_CALL(mock_attestation_flow_,
166 GetCertificate(PROFILE_CONTENT_PROTECTION_CERTIFICATE,
167 kTestEmail, kTestID, _, _))
168 .WillRepeatedly(WithArgs<4>(Invoke(
169 this, &PlatformVerificationFlowTest::FakeGetCertificate)));
171 // Configure the mock AsyncMethodCaller to call FakeSignChallenge.
172 std::string expected_key_name = std::string(kContentProtectionKeyPrefix) +
173 std::string(kTestID);
174 EXPECT_CALL(mock_async_caller_,
175 TpmAttestationSignSimpleChallenge(KEY_USER, kTestEmail,
176 expected_key_name,
177 kTestChallenge, _))
178 .WillRepeatedly(WithArgs<4>(Invoke(
179 this, &PlatformVerificationFlowTest::FakeSignChallenge)));
182 void FakeGetCertificate(
183 const AttestationFlow::CertificateCallback& callback) {
184 std::string certificate =
185 (fake_certificate_index_ < fake_certificate_list_.size()) ?
186 fake_certificate_list_[fake_certificate_index_] : kTestCertificate;
187 base::MessageLoop::current()->PostTask(FROM_HERE,
188 base::Bind(callback,
189 certificate_success_,
190 certificate));
191 ++fake_certificate_index_;
194 void FakeSignChallenge(
195 const cryptohome::AsyncMethodCaller::DataCallback& callback) {
196 base::MessageLoop::current()->PostTask(
197 FROM_HERE,
198 base::Bind(callback,
199 sign_challenge_success_,
200 CreateFakeResponseProto()));
203 void FakeChallengeCallback(PlatformVerificationFlow::Result result,
204 const std::string& salt,
205 const std::string& signature,
206 const std::string& certificate) {
207 result_ = result;
208 challenge_salt_ = salt;
209 challenge_signature_ = signature;
210 certificate_ = certificate;
213 std::string CreateFakeResponseProto() {
214 SignedData pb;
215 pb.set_data(kTestSignedData);
216 pb.set_signature(kTestSignature);
217 std::string serial;
218 CHECK(pb.SerializeToString(&serial));
219 return serial;
222 protected:
223 base::MessageLoopForUI message_loop_;
224 content::TestBrowserThread ui_thread_;
225 StrictMock<MockAttestationFlow> mock_attestation_flow_;
226 cryptohome::MockAsyncMethodCaller mock_async_caller_;
227 CustomFakeCryptohomeClient fake_cryptohome_client_;
228 FakeDelegate fake_delegate_;
229 ScopedCrosSettingsTestHelper settings_helper_;
230 scoped_refptr<PlatformVerificationFlow> verifier_;
232 // Controls result of FakeGetCertificate.
233 bool certificate_success_;
234 std::vector<std::string> fake_certificate_list_;
235 size_t fake_certificate_index_;
237 // Controls result of FakeSignChallenge.
238 bool sign_challenge_success_;
240 // Callback functions and data.
241 PlatformVerificationFlow::ChallengeCallback callback_;
242 PlatformVerificationFlow::Result result_;
243 std::string challenge_salt_;
244 std::string challenge_signature_;
245 std::string certificate_;
248 TEST_F(PlatformVerificationFlowTest, Success) {
249 ExpectAttestationFlow();
250 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
251 base::RunLoop().RunUntilIdle();
252 EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_);
253 EXPECT_EQ(kTestSignedData, challenge_salt_);
254 EXPECT_EQ(kTestSignature, challenge_signature_);
255 EXPECT_EQ(kTestCertificate, certificate_);
258 TEST_F(PlatformVerificationFlowTest, NotPermittedByUser) {
259 fake_delegate_.set_is_permitted_by_user(false);
260 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
261 base::RunLoop().RunUntilIdle();
262 EXPECT_EQ(PlatformVerificationFlow::USER_REJECTED, result_);
265 TEST_F(PlatformVerificationFlowTest, FeatureDisabledByPolicy) {
266 settings_helper_.SetBoolean(kAttestationForContentProtectionEnabled, false);
267 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
268 base::RunLoop().RunUntilIdle();
269 EXPECT_EQ(PlatformVerificationFlow::POLICY_REJECTED, result_);
272 TEST_F(PlatformVerificationFlowTest, NotVerified) {
273 certificate_success_ = false;
274 ExpectAttestationFlow();
275 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
276 base::RunLoop().RunUntilIdle();
277 EXPECT_EQ(PlatformVerificationFlow::PLATFORM_NOT_VERIFIED, result_);
280 TEST_F(PlatformVerificationFlowTest, ChallengeSigningError) {
281 sign_challenge_success_ = false;
282 ExpectAttestationFlow();
283 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
284 base::RunLoop().RunUntilIdle();
285 EXPECT_EQ(PlatformVerificationFlow::INTERNAL_ERROR, result_);
288 TEST_F(PlatformVerificationFlowTest, DBusFailure) {
289 fake_cryptohome_client_.set_call_status(DBUS_METHOD_CALL_FAILURE);
290 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
291 base::RunLoop().RunUntilIdle();
292 EXPECT_EQ(PlatformVerificationFlow::INTERNAL_ERROR, result_);
295 TEST_F(PlatformVerificationFlowTest, Timeout) {
296 verifier_->set_timeout_delay(base::TimeDelta::FromSeconds(0));
297 ExpectAttestationFlow();
298 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
299 base::RunLoop().RunUntilIdle();
300 EXPECT_EQ(PlatformVerificationFlow::TIMEOUT, result_);
303 TEST_F(PlatformVerificationFlowTest, ExpiredCert) {
304 ExpectAttestationFlow();
305 fake_certificate_list_.resize(3);
306 ASSERT_TRUE(GetFakeCertificatePEM(base::TimeDelta::FromDays(-1),
307 &fake_certificate_list_[0]));
308 ASSERT_TRUE(GetFakeCertificatePEM(base::TimeDelta::FromDays(1),
309 &fake_certificate_list_[1]));
310 // This is the opportunistic renewal certificate. Send it back expired to test
311 // that it does not pass through the certificate expiry check again.
312 ASSERT_TRUE(GetFakeCertificatePEM(base::TimeDelta::FromDays(-1),
313 &fake_certificate_list_[2]));
314 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
315 base::RunLoop().RunUntilIdle();
316 EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_);
317 EXPECT_EQ(fake_certificate_list_[1], certificate_);
318 // Once for the expired certificate, once for the almost expired certificate,
319 // and once for the opportunistic renewal attempt.
320 EXPECT_EQ(3ul, fake_certificate_index_);
323 TEST_F(PlatformVerificationFlowTest, ExpiredIntermediateCert) {
324 ExpectAttestationFlow();
325 fake_certificate_list_.resize(2);
326 std::string leaf_cert;
327 ASSERT_TRUE(GetFakeCertificatePEM(base::TimeDelta::FromDays(60), &leaf_cert));
328 std::string intermediate_cert;
329 ASSERT_TRUE(
330 GetFakeCertificatePEM(base::TimeDelta::FromDays(-1), &intermediate_cert));
331 fake_certificate_list_[0] = leaf_cert + intermediate_cert;
332 ASSERT_TRUE(GetFakeCertificatePEM(base::TimeDelta::FromDays(90),
333 &fake_certificate_list_[1]));
334 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
335 base::RunLoop().RunUntilIdle();
336 EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_);
337 EXPECT_EQ(fake_certificate_list_[1], certificate_);
338 // Once for the expired intermediate, once for the renewal.
339 EXPECT_EQ(2ul, fake_certificate_index_);
342 TEST_F(PlatformVerificationFlowTest, AsyncRenewalMultipleHits) {
343 ExpectAttestationFlow();
344 fake_certificate_list_.resize(4);
345 ASSERT_TRUE(GetFakeCertificatePEM(base::TimeDelta::FromDays(1),
346 &fake_certificate_list_[0]));
347 std::fill(fake_certificate_list_.begin() + 1, fake_certificate_list_.end(),
348 fake_certificate_list_[0]);
349 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
350 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
351 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
352 base::RunLoop().RunUntilIdle();
353 EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_);
354 EXPECT_EQ(fake_certificate_list_[0], certificate_);
355 // Once per challenge and only one renewal.
356 EXPECT_EQ(4ul, fake_certificate_index_);
359 TEST_F(PlatformVerificationFlowTest, CertificateNotPEM) {
360 ExpectAttestationFlow();
361 fake_certificate_list_.push_back("invalid_pem");
362 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
363 base::RunLoop().RunUntilIdle();
364 EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_);
365 EXPECT_EQ(fake_certificate_list_[0], certificate_);
368 TEST_F(PlatformVerificationFlowTest, CertificateNotX509) {
369 ExpectAttestationFlow();
370 std::string not_x509 =
371 "-----BEGIN CERTIFICATE-----\n"
372 "Vm0wd2QyUXlWa1pOVldoVFYwZDRWVll3WkRSV1JteFZVMjA1VjFadGVEQmFWVll3WVd4YWMx"
373 "TnNiRlZXYkhCUVdWZHplRll5VGtWUwpiSEJPVWpKb1RWZFhkR0ZUTWs1eVRsWmtZUXBTYlZK"
374 "d1ZXcEtiMDFzWkZkV2JVWlVZbFpHTTFSc1dsZFZaM0JwVTBWS2RsWkdZM2hpCk1rbDRWMnhX"
375 "VkdGc1NsaFpiRnBIVGtaYVNFNVZkRmRhTTBKd1ZteGFkMVpXWkZobFIzUnBDazFXY0VoV01X"
376 "aHpZV3hLV1ZWc1ZscGkKUm5Cb1dsZDRXbVZWTlZkYVIyaFdWMFZLVlZacVFsZFRNVnBYV2ta"
377 "b2JGSXpVbGREYlVwWFYydG9WMDF1VW5aWmExcExZMnMxVjFScwpjRmdLVTBWS1dWWnRjRWRq"
378 "TWs1elYyNVNVRll5YUZkV01GWkxWbXhhVlZGc1pGUk5Wa3BJVmpKNGIyRnNTbGxWYkVKRVlr"
379 "VndWbFZ0CmVHOVdNVWw2WVVkb1dGWnNjRXhXTUZwWFpGWk9jd3BhUjJkTFdWUkNkMDVzV2to"
380 "TlZGSmFWbTFTUjFSV1ZsZFdNa3BKVVd4a1YwMUcKV2t4V01uaGhWMGRXU0dSRk9WTk5WWEJa"
381 "Vm1wR2IySXhXblJTV0hCV1lrWktSVmxZY0VkbGJGbDVDbU5GVGxkTlZtdzJWbGMxWVZkdApS"
382 "WGhqUlhSaFZucEdTRlZ0TVZOU2QzQmhVbTFPVEZkWGVGWmtNbEY0VjJ0V1UySkhVbFpVVjNS"
383 "M1pXeFdXR1ZHWkZWaVJYQmFWa2QwCk5GSkdjRFlLVFVSc1JGcDZNRGxEWnowOUNnPT0K\n"
384 "-----END CERTIFICATE-----\n";
385 fake_certificate_list_.push_back(not_x509);
386 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
387 base::RunLoop().RunUntilIdle();
388 EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_);
389 EXPECT_EQ(fake_certificate_list_[0], certificate_);
392 TEST_F(PlatformVerificationFlowTest, UnsupportedMode) {
393 fake_delegate_.set_is_in_supported_mode(false);
394 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
395 base::RunLoop().RunUntilIdle();
396 EXPECT_EQ(PlatformVerificationFlow::PLATFORM_NOT_VERIFIED, result_);
399 TEST_F(PlatformVerificationFlowTest, AttestationNotPrepared) {
400 fake_cryptohome_client_.set_attestation_enrolled(false);
401 fake_cryptohome_client_.set_attestation_prepared(false);
402 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
403 base::RunLoop().RunUntilIdle();
404 EXPECT_EQ(PlatformVerificationFlow::PLATFORM_NOT_VERIFIED, result_);
407 } // namespace attestation
408 } // namespace chromeos