1 // Copyright (c) 2012 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 "base/bind.h" 6 #include "base/memory/scoped_ptr.h" 7 #include "base/run_loop.h" 8 #include "chromeos/attestation/mock_attestation_flow.h" 9 #include "chromeos/cryptohome/mock_async_method_caller.h" 10 #include "chromeos/dbus/mock_cryptohome_client.h" 11 #include "testing/gmock/include/gmock/gmock.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 14 using testing::_; 15 using testing::AtLeast; 16 using testing::DoDefault; 17 using testing::Invoke; 18 using testing::NiceMock; 19 using testing::Return; 20 using testing::Sequence; 21 using testing::StrictMock; 22 using testing::WithArgs; 23 24 namespace chromeos { 25 namespace attestation { 26 27 namespace { 28 29 void DBusCallbackFalse(const BoolDBusMethodCallback& callback) { 30 base::MessageLoop::current()->PostTask( 31 FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, false)); 32 } 33 34 void DBusCallbackTrue(const BoolDBusMethodCallback& callback) { 35 base::MessageLoop::current()->PostTask( 36 FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true)); 37 } 38 39 void DBusCallbackFail(const BoolDBusMethodCallback& callback) { 40 base::MessageLoop::current()->PostTask( 41 FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_FAILURE, false)); 42 } 43 44 void AsyncCallbackFalse(cryptohome::AsyncMethodCaller::Callback callback) { 45 callback.Run(false, cryptohome::MOUNT_ERROR_NONE); 46 } 47 48 class FakeDBusData { 49 public: 50 explicit FakeDBusData(const std::string& data) : data_(data) {} 51 52 void operator() (const CryptohomeClient::DataMethodCallback& callback) { 53 base::MessageLoop::current()->PostTask( 54 FROM_HERE, 55 base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true, data_)); 56 } 57 58 private: 59 std::string data_; 60 }; 61 62 } // namespace 63 64 class AttestationFlowTest : public testing::Test { 65 protected: 66 void Run() { 67 base::RunLoop run_loop; 68 run_loop.RunUntilIdle(); 69 } 70 base::MessageLoop message_loop_; 71 }; 72 73 TEST_F(AttestationFlowTest, GetCertificate) { 74 // Verify the order of calls in a sequence. 75 Sequence flow_order; 76 77 // Use DBusCallbackFalse so the full enrollment flow is triggered. 78 chromeos::MockCryptohomeClient client; 79 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 80 .InSequence(flow_order) 81 .WillRepeatedly(Invoke(DBusCallbackFalse)); 82 83 // Use StrictMock when we want to verify invocation frequency. 84 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 85 async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE); 86 EXPECT_CALL(async_caller, AsyncTpmAttestationCreateEnrollRequest(_, _)) 87 .Times(1) 88 .InSequence(flow_order); 89 90 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 91 proxy->DeferToFake(true); 92 EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault()); 93 EXPECT_CALL(*proxy, SendEnrollRequest( 94 cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest, 95 _)).Times(1) 96 .InSequence(flow_order); 97 98 std::string fake_enroll_response = 99 cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest; 100 fake_enroll_response += "_response"; 101 EXPECT_CALL(async_caller, 102 AsyncTpmAttestationEnroll(_, fake_enroll_response, _)) 103 .Times(1) 104 .InSequence(flow_order); 105 106 EXPECT_CALL( 107 async_caller, 108 AsyncTpmAttestationCreateCertRequest(_, 109 PROFILE_ENTERPRISE_USER_CERTIFICATE, 110 "fake (at) test.com", "fake_origin", _)) 111 .Times(1) 112 .InSequence(flow_order); 113 114 EXPECT_CALL(*proxy, SendCertificateRequest( 115 cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest, 116 _)).Times(1) 117 .InSequence(flow_order); 118 119 std::string fake_cert_response = 120 cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest; 121 fake_cert_response += "_response"; 122 EXPECT_CALL(async_caller, 123 AsyncTpmAttestationFinishCertRequest(fake_cert_response, 124 KEY_USER, 125 "fake (at) test.com", 126 kEnterpriseUserKey, 127 _)) 128 .Times(1) 129 .InSequence(flow_order); 130 131 StrictMock<MockObserver> observer; 132 EXPECT_CALL(observer, MockCertificateCallback( 133 true, 134 cryptohome::MockAsyncMethodCaller::kFakeAttestationCert)) 135 .Times(1) 136 .InSequence(flow_order); 137 AttestationFlow::CertificateCallback mock_callback = base::Bind( 138 &MockObserver::MockCertificateCallback, 139 base::Unretained(&observer)); 140 141 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 142 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 143 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "fake (at) test.com", 144 "fake_origin", true, mock_callback); 145 Run(); 146 } 147 148 TEST_F(AttestationFlowTest, GetCertificate_NoEK) { 149 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 150 async_caller.SetUp(false, cryptohome::MOUNT_ERROR_NONE); 151 EXPECT_CALL(async_caller, AsyncTpmAttestationCreateEnrollRequest(_, _)) 152 .Times(1); 153 154 chromeos::MockCryptohomeClient client; 155 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 156 .WillRepeatedly(Invoke(DBusCallbackFalse)); 157 158 // We're not expecting any server calls in this case; StrictMock will verify. 159 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 160 EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault()); 161 162 StrictMock<MockObserver> observer; 163 EXPECT_CALL(observer, MockCertificateCallback(false, "")) 164 .Times(1); 165 AttestationFlow::CertificateCallback mock_callback = base::Bind( 166 &MockObserver::MockCertificateCallback, 167 base::Unretained(&observer)); 168 169 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 170 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 171 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true, 172 mock_callback); 173 Run(); 174 } 175 176 TEST_F(AttestationFlowTest, GetCertificate_EKRejected) { 177 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 178 async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE); 179 EXPECT_CALL(async_caller, AsyncTpmAttestationCreateEnrollRequest(_, _)) 180 .Times(1); 181 182 chromeos::MockCryptohomeClient client; 183 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 184 .WillRepeatedly(Invoke(DBusCallbackFalse)); 185 186 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 187 proxy->DeferToFake(false); 188 EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault()); 189 EXPECT_CALL(*proxy, SendEnrollRequest( 190 cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest, 191 _)).Times(1); 192 193 StrictMock<MockObserver> observer; 194 EXPECT_CALL(observer, MockCertificateCallback(false, "")) 195 .Times(1); 196 AttestationFlow::CertificateCallback mock_callback = base::Bind( 197 &MockObserver::MockCertificateCallback, 198 base::Unretained(&observer)); 199 200 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 201 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 202 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true, 203 mock_callback); 204 Run(); 205 } 206 207 TEST_F(AttestationFlowTest, GetCertificate_FailEnroll) { 208 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 209 async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE); 210 EXPECT_CALL(async_caller, AsyncTpmAttestationCreateEnrollRequest(_, _)) 211 .Times(1); 212 std::string fake_enroll_response = 213 cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest; 214 fake_enroll_response += "_response"; 215 EXPECT_CALL(async_caller, 216 AsyncTpmAttestationEnroll(_, fake_enroll_response, _)) 217 .WillOnce(WithArgs<2>(Invoke(AsyncCallbackFalse))); 218 219 chromeos::MockCryptohomeClient client; 220 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 221 .WillRepeatedly(Invoke(DBusCallbackFalse)); 222 223 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 224 proxy->DeferToFake(true); 225 EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault()); 226 EXPECT_CALL(*proxy, SendEnrollRequest( 227 cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest, 228 _)).Times(1); 229 230 StrictMock<MockObserver> observer; 231 EXPECT_CALL(observer, MockCertificateCallback(false, "")).Times(1); 232 AttestationFlow::CertificateCallback mock_callback = base::Bind( 233 &MockObserver::MockCertificateCallback, 234 base::Unretained(&observer)); 235 236 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 237 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 238 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true, 239 mock_callback); 240 Run(); 241 } 242 243 TEST_F(AttestationFlowTest, GetMachineCertificateAlreadyEnrolled) { 244 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 245 async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE); 246 EXPECT_CALL(async_caller, 247 AsyncTpmAttestationCreateCertRequest( 248 _, PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, "", "", _)) 249 .Times(1); 250 std::string fake_cert_response = 251 cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest; 252 fake_cert_response += "_response"; 253 EXPECT_CALL(async_caller, 254 AsyncTpmAttestationFinishCertRequest(fake_cert_response, 255 KEY_DEVICE, 256 "", 257 kEnterpriseMachineKey, 258 _)) 259 .Times(1); 260 261 chromeos::MockCryptohomeClient client; 262 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 263 .WillRepeatedly(Invoke(DBusCallbackTrue)); 264 265 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 266 proxy->DeferToFake(true); 267 EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault()); 268 EXPECT_CALL(*proxy, SendCertificateRequest( 269 cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest, 270 _)).Times(1); 271 272 StrictMock<MockObserver> observer; 273 EXPECT_CALL(observer, MockCertificateCallback( 274 true, 275 cryptohome::MockAsyncMethodCaller::kFakeAttestationCert)).Times(1); 276 AttestationFlow::CertificateCallback mock_callback = base::Bind( 277 &MockObserver::MockCertificateCallback, 278 base::Unretained(&observer)); 279 280 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 281 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 282 flow.GetCertificate(PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, "", "", true, 283 mock_callback); 284 Run(); 285 } 286 287 TEST_F(AttestationFlowTest, GetCertificate_FailCreateCertRequest) { 288 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 289 async_caller.SetUp(false, cryptohome::MOUNT_ERROR_NONE); 290 EXPECT_CALL(async_caller, 291 AsyncTpmAttestationCreateCertRequest( 292 _, PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", _)) 293 .Times(1); 294 295 chromeos::MockCryptohomeClient client; 296 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 297 .WillRepeatedly(Invoke(DBusCallbackTrue)); 298 299 // We're not expecting any server calls in this case; StrictMock will verify. 300 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 301 EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault()); 302 303 StrictMock<MockObserver> observer; 304 EXPECT_CALL(observer, MockCertificateCallback(false, "")).Times(1); 305 AttestationFlow::CertificateCallback mock_callback = base::Bind( 306 &MockObserver::MockCertificateCallback, 307 base::Unretained(&observer)); 308 309 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 310 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 311 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true, 312 mock_callback); 313 Run(); 314 } 315 316 TEST_F(AttestationFlowTest, GetCertificate_CertRequestRejected) { 317 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 318 async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE); 319 EXPECT_CALL(async_caller, 320 AsyncTpmAttestationCreateCertRequest( 321 _, PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", _)) 322 .Times(1); 323 324 chromeos::MockCryptohomeClient client; 325 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 326 .WillRepeatedly(Invoke(DBusCallbackTrue)); 327 328 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 329 proxy->DeferToFake(false); 330 EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault()); 331 EXPECT_CALL(*proxy, SendCertificateRequest( 332 cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest, 333 _)).Times(1); 334 335 StrictMock<MockObserver> observer; 336 EXPECT_CALL(observer, MockCertificateCallback(false, "")).Times(1); 337 AttestationFlow::CertificateCallback mock_callback = base::Bind( 338 &MockObserver::MockCertificateCallback, 339 base::Unretained(&observer)); 340 341 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 342 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 343 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true, 344 mock_callback); 345 Run(); 346 } 347 348 TEST_F(AttestationFlowTest, GetCertificate_FailIsEnrolled) { 349 // We're not expecting any async calls in this case; StrictMock will verify. 350 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 351 352 chromeos::MockCryptohomeClient client; 353 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 354 .WillRepeatedly(Invoke(DBusCallbackFail)); 355 356 // We're not expecting any server calls in this case; StrictMock will verify. 357 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 358 EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault()); 359 360 StrictMock<MockObserver> observer; 361 EXPECT_CALL(observer, MockCertificateCallback(false, "")).Times(1); 362 AttestationFlow::CertificateCallback mock_callback = base::Bind( 363 &MockObserver::MockCertificateCallback, 364 base::Unretained(&observer)); 365 366 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 367 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 368 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true, 369 mock_callback); 370 Run(); 371 } 372 373 TEST_F(AttestationFlowTest, GetCertificate_CheckExisting) { 374 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 375 async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE); 376 EXPECT_CALL(async_caller, 377 AsyncTpmAttestationCreateCertRequest( 378 _, PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", _)) 379 .Times(1); 380 std::string fake_cert_response = 381 cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest; 382 fake_cert_response += "_response"; 383 EXPECT_CALL(async_caller, 384 AsyncTpmAttestationFinishCertRequest(fake_cert_response, 385 KEY_USER, 386 "", 387 kEnterpriseUserKey, 388 _)) 389 .Times(1); 390 391 chromeos::MockCryptohomeClient client; 392 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 393 .WillRepeatedly(Invoke(DBusCallbackTrue)); 394 EXPECT_CALL(client, 395 TpmAttestationDoesKeyExist(KEY_USER, "", kEnterpriseUserKey, _)) 396 .WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackFalse))); 397 398 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 399 proxy->DeferToFake(true); 400 EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault()); 401 EXPECT_CALL(*proxy, SendCertificateRequest( 402 cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest, 403 _)).Times(1); 404 405 StrictMock<MockObserver> observer; 406 EXPECT_CALL(observer, MockCertificateCallback( 407 true, 408 cryptohome::MockAsyncMethodCaller::kFakeAttestationCert)).Times(1); 409 AttestationFlow::CertificateCallback mock_callback = base::Bind( 410 &MockObserver::MockCertificateCallback, 411 base::Unretained(&observer)); 412 413 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 414 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 415 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", false, 416 mock_callback); 417 Run(); 418 } 419 420 TEST_F(AttestationFlowTest, GetCertificate_AlreadyExists) { 421 // We're not expecting any async calls in this case; StrictMock will verify. 422 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 423 424 chromeos::MockCryptohomeClient client; 425 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 426 .WillRepeatedly(Invoke(DBusCallbackTrue)); 427 EXPECT_CALL(client, 428 TpmAttestationDoesKeyExist(KEY_USER, "", kEnterpriseUserKey, _)) 429 .WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackTrue))); 430 EXPECT_CALL(client, 431 TpmAttestationGetCertificate(KEY_USER, "", kEnterpriseUserKey, _)) 432 .WillRepeatedly(WithArgs<3>(Invoke(FakeDBusData("fake_cert")))); 433 434 // We're not expecting any server calls in this case; StrictMock will verify. 435 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 436 EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault()); 437 438 StrictMock<MockObserver> observer; 439 EXPECT_CALL(observer, MockCertificateCallback(true, "fake_cert")).Times(1); 440 AttestationFlow::CertificateCallback mock_callback = base::Bind( 441 &MockObserver::MockCertificateCallback, 442 base::Unretained(&observer)); 443 444 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 445 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 446 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", false, 447 mock_callback); 448 Run(); 449 } 450 451 TEST_F(AttestationFlowTest, AlternatePCA) { 452 // Strategy: Create a ServerProxy mock which reports ALTERNATE_PCA and check 453 // that all calls to the AsyncMethodCaller reflect this PCA type. 454 scoped_ptr<MockServerProxy> proxy(new NiceMock<MockServerProxy>()); 455 proxy->DeferToFake(true); 456 EXPECT_CALL(*proxy, GetType()).WillRepeatedly(Return(ALTERNATE_PCA)); 457 458 chromeos::MockCryptohomeClient client; 459 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 460 .WillRepeatedly(Invoke(DBusCallbackFalse)); 461 462 NiceMock<cryptohome::MockAsyncMethodCaller> async_caller; 463 async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE); 464 EXPECT_CALL(async_caller, 465 AsyncTpmAttestationCreateEnrollRequest(ALTERNATE_PCA, _)) 466 .Times(AtLeast(1)); 467 EXPECT_CALL(async_caller, 468 AsyncTpmAttestationEnroll(ALTERNATE_PCA, _, _)) 469 .Times(AtLeast(1)); 470 EXPECT_CALL(async_caller, 471 AsyncTpmAttestationCreateCertRequest(ALTERNATE_PCA, _, _, _, _)) 472 .Times(AtLeast(1)); 473 474 NiceMock<MockObserver> observer; 475 AttestationFlow::CertificateCallback mock_callback = base::Bind( 476 &MockObserver::MockCertificateCallback, 477 base::Unretained(&observer)); 478 479 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 480 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 481 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true, 482 mock_callback); 483 Run(); 484 } 485 486 } // namespace attestation 487 } // namespace chromeos 488