platform_verification_flow_unittest.cc revision 3551c9c881056c480085172ff9840cab31610854
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/platform_verification_flow.h" 11#include "chrome/browser/chromeos/login/mock_user_manager.h" 12#include "chromeos/attestation/mock_attestation_flow.h" 13#include "chromeos/cryptohome/mock_async_method_caller.h" 14#include "chromeos/dbus/fake_cryptohome_client.h" 15#include "content/public/test/test_browser_thread.h" 16#include "testing/gtest/include/gtest/gtest.h" 17 18using testing::_; 19using testing::Invoke; 20using testing::StrictMock; 21using testing::WithArgs; 22 23namespace chromeos { 24namespace attestation { 25 26namespace { 27 28const char kTestID[] = "test_id"; 29const char kTestChallenge[] = "test_challenge"; 30const char kTestResponse[] = "test_challenge_response"; 31const char kTestCertificate[] = "test_certificate"; 32const char kTestEmail[] = "test_email@chromium.org"; 33 34class FakeDelegate : public PlatformVerificationFlow::Delegate { 35 public: 36 FakeDelegate() : response_(PlatformVerificationFlow::CONSENT_RESPONSE_ALLOW), 37 num_consent_calls_(0), 38 attestation_disabled_(false), 39 origin_consent_required_(false), 40 always_ask_required_(false), 41 update_settings_result_(true) {} 42 virtual ~FakeDelegate() {} 43 44 virtual void ShowConsentPrompt( 45 PlatformVerificationFlow::ConsentType type, 46 content::WebContents* web_contents, 47 const PlatformVerificationFlow::Delegate::ConsentCallback& callback) 48 OVERRIDE { 49 num_consent_calls_++; 50 callback.Run(response_); 51 } 52 53 virtual bool IsAttestationDisabled() OVERRIDE { 54 return attestation_disabled_; 55 } 56 57 virtual bool IsOriginConsentRequired( 58 content::WebContents* web_contents) OVERRIDE { 59 return origin_consent_required_; 60 } 61 62 virtual bool IsAlwaysAskRequired( 63 content::WebContents* web_contents) OVERRIDE { 64 return always_ask_required_; 65 } 66 67 virtual bool UpdateSettings( 68 content::WebContents* web_contents, 69 PlatformVerificationFlow::ConsentType consent_type, 70 PlatformVerificationFlow::ConsentResponse consent_response) OVERRIDE { 71 return update_settings_result_; 72 } 73 74 void set_response(PlatformVerificationFlow::ConsentResponse response) { 75 response_ = response; 76 } 77 78 int num_consent_calls() { 79 return num_consent_calls_; 80 } 81 82 void set_attestation_disabled(bool attestation_disabled) { 83 attestation_disabled_ = attestation_disabled; 84 } 85 86 void set_origin_consent_required(bool origin_consent_required) { 87 origin_consent_required_ = origin_consent_required; 88 } 89 90 void set_always_ask_required(bool always_ask_required) { 91 always_ask_required_ = always_ask_required; 92 } 93 94 void set_update_settings_result(bool update_settings_result) { 95 update_settings_result_ = update_settings_result; 96 } 97 98 private: 99 PlatformVerificationFlow::ConsentResponse response_; 100 int num_consent_calls_; 101 bool attestation_disabled_; 102 bool origin_consent_required_; 103 bool always_ask_required_; 104 bool update_settings_result_; 105 106 107 DISALLOW_COPY_AND_ASSIGN(FakeDelegate); 108}; 109 110class CustomFakeCryptohomeClient : public FakeCryptohomeClient { 111 public: 112 CustomFakeCryptohomeClient() : call_status_(DBUS_METHOD_CALL_SUCCESS), 113 attestation_enrolled_(true) {} 114 virtual void TpmAttestationIsEnrolled( 115 const BoolDBusMethodCallback& callback) OVERRIDE { 116 base::MessageLoop::current()->PostTask(FROM_HERE, 117 base::Bind(callback, 118 call_status_, 119 attestation_enrolled_)); 120 } 121 122 void set_call_status(DBusMethodCallStatus call_status) { 123 call_status_ = call_status; 124 } 125 126 void set_attestation_enrolled(bool attestation_enrolled) { 127 attestation_enrolled_ = attestation_enrolled; 128 } 129 130 private: 131 DBusMethodCallStatus call_status_; 132 bool attestation_enrolled_; 133}; 134 135} // namespace 136 137class PlatformVerificationFlowTest : public ::testing::Test { 138 public: 139 PlatformVerificationFlowTest() 140 : message_loop_(base::MessageLoop::TYPE_UI), 141 ui_thread_(content::BrowserThread::UI, &message_loop_), 142 certificate_success_(true), 143 sign_challenge_success_(true), 144 result_(PlatformVerificationFlow::INTERNAL_ERROR) {} 145 146 void SetUp() { 147 // Configure a user for the mock user manager. 148 mock_user_manager_.SetActiveUser(kTestEmail); 149 150 // Create a verifier for tests to call. 151 verifier_.reset(new PlatformVerificationFlow(&mock_attestation_flow_, 152 &mock_async_caller_, 153 &fake_cryptohome_client_, 154 &mock_user_manager_, 155 &fake_delegate_)); 156 157 // Create a callback for tests to use with verifier_. 158 callback_ = base::Bind(&PlatformVerificationFlowTest::FakeChallengeCallback, 159 base::Unretained(this)); 160 } 161 162 void TearDown() { 163 verifier_.reset(); 164 } 165 166 void ExpectAttestationFlow() { 167 // When consent is not given or the feature is disabled, it is important 168 // that there are no calls to the attestation service. Thus, a test must 169 // explicitly expect these calls or the mocks will fail the test. 170 171 // Configure the mock AttestationFlow to call FakeGetCertificate. 172 EXPECT_CALL(mock_attestation_flow_, 173 GetCertificate(PROFILE_CONTENT_PROTECTION_CERTIFICATE, 174 kTestEmail, kTestID, _, _)) 175 .WillRepeatedly(WithArgs<4>(Invoke( 176 this, &PlatformVerificationFlowTest::FakeGetCertificate))); 177 178 // Configure the mock AsyncMethodCaller to call FakeSignChallenge. 179 std::string expected_key_name = std::string(kContentProtectionKeyPrefix) + 180 std::string(kTestID); 181 EXPECT_CALL(mock_async_caller_, 182 TpmAttestationSignSimpleChallenge(KEY_USER, expected_key_name, 183 kTestChallenge, _)) 184 .WillRepeatedly(WithArgs<3>(Invoke( 185 this, &PlatformVerificationFlowTest::FakeSignChallenge))); 186 } 187 188 void FakeGetCertificate( 189 const AttestationFlow::CertificateCallback& callback) { 190 base::MessageLoop::current()->PostTask(FROM_HERE, 191 base::Bind(callback, 192 certificate_success_, 193 kTestCertificate)); 194 } 195 196 void FakeSignChallenge( 197 const cryptohome::AsyncMethodCaller::DataCallback& callback) { 198 base::MessageLoop::current()->PostTask(FROM_HERE, 199 base::Bind(callback, 200 sign_challenge_success_, 201 kTestResponse)); 202 } 203 204 void FakeChallengeCallback(PlatformVerificationFlow::Result result, 205 const std::string& response, 206 const std::string& certificate) { 207 result_ = result; 208 challenge_response_ = response; 209 certificate_ = certificate; 210 } 211 212 protected: 213 base::MessageLoop message_loop_; 214 content::TestBrowserThread ui_thread_; 215 StrictMock<MockAttestationFlow> mock_attestation_flow_; 216 cryptohome::MockAsyncMethodCaller mock_async_caller_; 217 CustomFakeCryptohomeClient fake_cryptohome_client_; 218 MockUserManager mock_user_manager_; 219 FakeDelegate fake_delegate_; 220 scoped_ptr<PlatformVerificationFlow> verifier_; 221 222 // Controls result of FakeGetCertificate. 223 bool certificate_success_; 224 225 // Controls result of FakeSignChallenge. 226 bool sign_challenge_success_; 227 228 // Callback function and data. 229 PlatformVerificationFlow::ChallengeCallback callback_; 230 PlatformVerificationFlow::Result result_; 231 std::string challenge_response_; 232 std::string certificate_; 233}; 234 235TEST_F(PlatformVerificationFlowTest, SuccessNoConsent) { 236 // Make sure the call will fail if consent is requested. 237 fake_delegate_.set_response(PlatformVerificationFlow::CONSENT_RESPONSE_DENY); 238 ExpectAttestationFlow(); 239 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 240 base::RunLoop().RunUntilIdle(); 241 EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_); 242 EXPECT_EQ(kTestResponse, challenge_response_); 243 EXPECT_EQ(kTestCertificate, certificate_); 244 EXPECT_EQ(0, fake_delegate_.num_consent_calls()); 245} 246 247TEST_F(PlatformVerificationFlowTest, SuccessWithOriginConsent) { 248 // Enable two conditions and make sure consent is not requested twice. 249 fake_delegate_.set_origin_consent_required(true); 250 fake_delegate_.set_always_ask_required(true); 251 ExpectAttestationFlow(); 252 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 253 base::RunLoop().RunUntilIdle(); 254 EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_); 255 EXPECT_EQ(kTestResponse, challenge_response_); 256 EXPECT_EQ(kTestCertificate, certificate_); 257 EXPECT_EQ(1, fake_delegate_.num_consent_calls()); 258} 259 260TEST_F(PlatformVerificationFlowTest, SuccessWithAlwaysAskConsent) { 261 fake_delegate_.set_always_ask_required(true); 262 ExpectAttestationFlow(); 263 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 264 base::RunLoop().RunUntilIdle(); 265 EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_); 266 EXPECT_EQ(kTestResponse, challenge_response_); 267 EXPECT_EQ(kTestCertificate, certificate_); 268 EXPECT_EQ(1, fake_delegate_.num_consent_calls()); 269} 270 271TEST_F(PlatformVerificationFlowTest, SuccessWithAttestationConsent) { 272 fake_cryptohome_client_.set_attestation_enrolled(false); 273 ExpectAttestationFlow(); 274 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 275 base::RunLoop().RunUntilIdle(); 276 EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_); 277 EXPECT_EQ(kTestResponse, challenge_response_); 278 EXPECT_EQ(kTestCertificate, certificate_); 279 EXPECT_EQ(1, fake_delegate_.num_consent_calls()); 280} 281 282TEST_F(PlatformVerificationFlowTest, ConsentRejected) { 283 fake_delegate_.set_always_ask_required(true); 284 fake_delegate_.set_response(PlatformVerificationFlow::CONSENT_RESPONSE_DENY); 285 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 286 base::RunLoop().RunUntilIdle(); 287 EXPECT_EQ(PlatformVerificationFlow::USER_REJECTED, result_); 288 EXPECT_EQ(1, fake_delegate_.num_consent_calls()); 289} 290 291TEST_F(PlatformVerificationFlowTest, FeatureDisabled) { 292 fake_delegate_.set_attestation_disabled(true); 293 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 294 base::RunLoop().RunUntilIdle(); 295 EXPECT_EQ(PlatformVerificationFlow::POLICY_REJECTED, result_); 296 EXPECT_EQ(0, fake_delegate_.num_consent_calls()); 297} 298 299TEST_F(PlatformVerificationFlowTest, NotVerified) { 300 certificate_success_ = false; 301 ExpectAttestationFlow(); 302 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 303 base::RunLoop().RunUntilIdle(); 304 EXPECT_EQ(PlatformVerificationFlow::PLATFORM_NOT_VERIFIED, result_); 305} 306 307TEST_F(PlatformVerificationFlowTest, ChallengeSigningError) { 308 sign_challenge_success_ = false; 309 ExpectAttestationFlow(); 310 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 311 base::RunLoop().RunUntilIdle(); 312 EXPECT_EQ(PlatformVerificationFlow::INTERNAL_ERROR, result_); 313} 314 315TEST_F(PlatformVerificationFlowTest, DBusFailure) { 316 fake_cryptohome_client_.set_call_status(DBUS_METHOD_CALL_FAILURE); 317 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 318 base::RunLoop().RunUntilIdle(); 319 EXPECT_EQ(PlatformVerificationFlow::INTERNAL_ERROR, result_); 320} 321 322TEST_F(PlatformVerificationFlowTest, UpdateSettingsFailure) { 323 fake_delegate_.set_origin_consent_required(true); 324 fake_delegate_.set_update_settings_result(false); 325 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 326 base::RunLoop().RunUntilIdle(); 327 EXPECT_EQ(PlatformVerificationFlow::INTERNAL_ERROR, result_); 328} 329 330TEST_F(PlatformVerificationFlowTest, ConsentNoResponse) { 331 fake_delegate_.set_response(PlatformVerificationFlow::CONSENT_RESPONSE_NONE); 332 fake_delegate_.set_origin_consent_required(true); 333 verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_); 334 base::RunLoop().RunUntilIdle(); 335 EXPECT_EQ(PlatformVerificationFlow::USER_REJECTED, result_); 336} 337 338} // namespace attestation 339} // namespace chromeos 340