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