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(CERTIFICATE_INCLUDE_DEVICE_STATE, _)) 103 .Times(1) 104 .InSequence(flow_order); 105 106 EXPECT_CALL(*proxy, SendCertificateRequest( 107 cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest, 108 _)).Times(1) 109 .InSequence(flow_order); 110 111 std::string fake_cert_response = 112 cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest; 113 fake_cert_response += "_response"; 114 EXPECT_CALL(async_caller, 115 AsyncTpmAttestationFinishCertRequest(fake_cert_response, 116 KEY_USER, 117 kEnterpriseUserKey, 118 _)) 119 .Times(1) 120 .InSequence(flow_order); 121 122 StrictMock<MockObserver> observer; 123 EXPECT_CALL(observer, MockCertificateCallback( 124 true, 125 cryptohome::MockAsyncMethodCaller::kFakeAttestationCert)) 126 .Times(1) 127 .InSequence(flow_order); 128 AttestationFlow::CertificateCallback mock_callback = base::Bind( 129 &MockObserver::MockCertificateCallback, 130 base::Unretained(&observer)); 131 132 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 133 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 134 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, true, mock_callback); 135 Run(); 136 } 137 138 TEST_F(AttestationFlowTest, GetCertificate_NoEK) { 139 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 140 async_caller.SetUp(false, cryptohome::MOUNT_ERROR_NONE); 141 EXPECT_CALL(async_caller, AsyncTpmAttestationCreateEnrollRequest(_)) 142 .Times(1); 143 144 chromeos::MockCryptohomeClient client; 145 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 146 .WillRepeatedly(Invoke(DBusCallbackFalse)); 147 148 // We're not expecting any server calls in this case; StrictMock will verify. 149 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 150 151 StrictMock<MockObserver> observer; 152 EXPECT_CALL(observer, MockCertificateCallback(false, "")) 153 .Times(1); 154 AttestationFlow::CertificateCallback mock_callback = base::Bind( 155 &MockObserver::MockCertificateCallback, 156 base::Unretained(&observer)); 157 158 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 159 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 160 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, true, mock_callback); 161 Run(); 162 } 163 164 TEST_F(AttestationFlowTest, GetCertificate_EKRejected) { 165 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 166 async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE); 167 EXPECT_CALL(async_caller, AsyncTpmAttestationCreateEnrollRequest(_)) 168 .Times(1); 169 170 chromeos::MockCryptohomeClient client; 171 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 172 .WillRepeatedly(Invoke(DBusCallbackFalse)); 173 174 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 175 proxy->DeferToFake(false); 176 EXPECT_CALL(*proxy, SendEnrollRequest( 177 cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest, 178 _)).Times(1); 179 180 StrictMock<MockObserver> observer; 181 EXPECT_CALL(observer, MockCertificateCallback(false, "")) 182 .Times(1); 183 AttestationFlow::CertificateCallback mock_callback = base::Bind( 184 &MockObserver::MockCertificateCallback, 185 base::Unretained(&observer)); 186 187 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 188 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 189 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, true, mock_callback); 190 Run(); 191 } 192 193 TEST_F(AttestationFlowTest, GetCertificate_FailEnroll) { 194 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 195 async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE); 196 EXPECT_CALL(async_caller, AsyncTpmAttestationCreateEnrollRequest(_)) 197 .Times(1); 198 std::string fake_enroll_response = 199 cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest; 200 fake_enroll_response += "_response"; 201 EXPECT_CALL(async_caller, AsyncTpmAttestationEnroll(fake_enroll_response, _)) 202 .WillOnce(WithArgs<1>(Invoke(AsyncCallbackFalse))); 203 204 chromeos::MockCryptohomeClient client; 205 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 206 .WillRepeatedly(Invoke(DBusCallbackFalse)); 207 208 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 209 proxy->DeferToFake(true); 210 EXPECT_CALL(*proxy, SendEnrollRequest( 211 cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest, 212 _)).Times(1); 213 214 StrictMock<MockObserver> observer; 215 EXPECT_CALL(observer, MockCertificateCallback(false, "")).Times(1); 216 AttestationFlow::CertificateCallback mock_callback = base::Bind( 217 &MockObserver::MockCertificateCallback, 218 base::Unretained(&observer)); 219 220 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 221 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 222 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, true, mock_callback); 223 Run(); 224 } 225 226 TEST_F(AttestationFlowTest, GetMachineCertificateAlreadyEnrolled) { 227 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 228 async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE); 229 int options = CERTIFICATE_INCLUDE_DEVICE_STATE | 230 CERTIFICATE_INCLUDE_STABLE_ID; 231 EXPECT_CALL(async_caller, AsyncTpmAttestationCreateCertRequest(options, _)) 232 .Times(1); 233 std::string fake_cert_response = 234 cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest; 235 fake_cert_response += "_response"; 236 EXPECT_CALL(async_caller, 237 AsyncTpmAttestationFinishCertRequest(fake_cert_response, 238 KEY_DEVICE, 239 kEnterpriseMachineKey, 240 _)) 241 .Times(1); 242 243 chromeos::MockCryptohomeClient client; 244 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 245 .WillRepeatedly(Invoke(DBusCallbackTrue)); 246 247 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 248 proxy->DeferToFake(true); 249 EXPECT_CALL(*proxy, SendCertificateRequest( 250 cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest, 251 _)).Times(1); 252 253 StrictMock<MockObserver> observer; 254 EXPECT_CALL(observer, MockCertificateCallback( 255 true, 256 cryptohome::MockAsyncMethodCaller::kFakeAttestationCert)).Times(1); 257 AttestationFlow::CertificateCallback mock_callback = base::Bind( 258 &MockObserver::MockCertificateCallback, 259 base::Unretained(&observer)); 260 261 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 262 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 263 flow.GetCertificate(PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, 264 true, mock_callback); 265 Run(); 266 } 267 268 TEST_F(AttestationFlowTest, GetCertificate_FailCreateCertRequest) { 269 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 270 async_caller.SetUp(false, cryptohome::MOUNT_ERROR_NONE); 271 int options = CERTIFICATE_INCLUDE_DEVICE_STATE; 272 EXPECT_CALL(async_caller, 273 AsyncTpmAttestationCreateCertRequest(options, _)) 274 .Times(1); 275 276 chromeos::MockCryptohomeClient client; 277 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 278 .WillRepeatedly(Invoke(DBusCallbackTrue)); 279 280 // We're not expecting any server calls in this case; StrictMock will verify. 281 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 282 283 StrictMock<MockObserver> observer; 284 EXPECT_CALL(observer, MockCertificateCallback(false, "")).Times(1); 285 AttestationFlow::CertificateCallback mock_callback = base::Bind( 286 &MockObserver::MockCertificateCallback, 287 base::Unretained(&observer)); 288 289 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 290 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 291 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, true, mock_callback); 292 Run(); 293 } 294 295 TEST_F(AttestationFlowTest, GetCertificate_CertRequestRejected) { 296 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 297 async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE); 298 int options = CERTIFICATE_INCLUDE_DEVICE_STATE; 299 EXPECT_CALL(async_caller, 300 AsyncTpmAttestationCreateCertRequest(options, _)) 301 .Times(1); 302 303 chromeos::MockCryptohomeClient client; 304 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 305 .WillRepeatedly(Invoke(DBusCallbackTrue)); 306 307 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 308 proxy->DeferToFake(false); 309 EXPECT_CALL(*proxy, SendCertificateRequest( 310 cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest, 311 _)).Times(1); 312 313 StrictMock<MockObserver> observer; 314 EXPECT_CALL(observer, MockCertificateCallback(false, "")).Times(1); 315 AttestationFlow::CertificateCallback mock_callback = base::Bind( 316 &MockObserver::MockCertificateCallback, 317 base::Unretained(&observer)); 318 319 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 320 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 321 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, true, mock_callback); 322 Run(); 323 } 324 325 TEST_F(AttestationFlowTest, GetCertificate_FailIsEnrolled) { 326 // We're not expecting any async calls in this case; StrictMock will verify. 327 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 328 329 chromeos::MockCryptohomeClient client; 330 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 331 .WillRepeatedly(Invoke(DBusCallbackFail)); 332 333 // We're not expecting any server calls in this case; StrictMock will verify. 334 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 335 336 StrictMock<MockObserver> observer; 337 EXPECT_CALL(observer, MockCertificateCallback(false, "")).Times(1); 338 AttestationFlow::CertificateCallback mock_callback = base::Bind( 339 &MockObserver::MockCertificateCallback, 340 base::Unretained(&observer)); 341 342 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 343 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 344 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, true, mock_callback); 345 Run(); 346 } 347 348 TEST_F(AttestationFlowTest, GetCertificate_CheckExisting) { 349 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 350 async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE); 351 int options = CERTIFICATE_INCLUDE_DEVICE_STATE; 352 EXPECT_CALL(async_caller, AsyncTpmAttestationCreateCertRequest(options, _)) 353 .Times(1); 354 std::string fake_cert_response = 355 cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest; 356 fake_cert_response += "_response"; 357 EXPECT_CALL(async_caller, 358 AsyncTpmAttestationFinishCertRequest(fake_cert_response, 359 KEY_USER, 360 kEnterpriseUserKey, 361 _)) 362 .Times(1); 363 364 chromeos::MockCryptohomeClient client; 365 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 366 .WillRepeatedly(Invoke(DBusCallbackTrue)); 367 EXPECT_CALL(client, 368 TpmAttestationDoesKeyExist(KEY_USER, kEnterpriseUserKey, _)) 369 .WillRepeatedly(WithArgs<2>(Invoke(DBusCallbackFalse))); 370 371 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 372 proxy->DeferToFake(true); 373 EXPECT_CALL(*proxy, SendCertificateRequest( 374 cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest, 375 _)).Times(1); 376 377 StrictMock<MockObserver> observer; 378 EXPECT_CALL(observer, MockCertificateCallback( 379 true, 380 cryptohome::MockAsyncMethodCaller::kFakeAttestationCert)).Times(1); 381 AttestationFlow::CertificateCallback mock_callback = base::Bind( 382 &MockObserver::MockCertificateCallback, 383 base::Unretained(&observer)); 384 385 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 386 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 387 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, 388 false, mock_callback); 389 Run(); 390 } 391 392 TEST_F(AttestationFlowTest, GetCertificate_AlreadyExists) { 393 // We're not expecting any async calls in this case; StrictMock will verify. 394 StrictMock<cryptohome::MockAsyncMethodCaller> async_caller; 395 396 chromeos::MockCryptohomeClient client; 397 EXPECT_CALL(client, TpmAttestationIsEnrolled(_)) 398 .WillRepeatedly(Invoke(DBusCallbackTrue)); 399 EXPECT_CALL(client, 400 TpmAttestationDoesKeyExist(KEY_USER, kEnterpriseUserKey, _)) 401 .WillRepeatedly(WithArgs<2>(Invoke(DBusCallbackTrue))); 402 EXPECT_CALL(client, 403 TpmAttestationGetCertificate(KEY_USER, kEnterpriseUserKey, _)) 404 .WillRepeatedly(WithArgs<2>(Invoke(FakeDBusData("fake_cert")))); 405 406 // We're not expecting any server calls in this case; StrictMock will verify. 407 scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>()); 408 409 StrictMock<MockObserver> observer; 410 EXPECT_CALL(observer, MockCertificateCallback(true, "fake_cert")).Times(1); 411 AttestationFlow::CertificateCallback mock_callback = base::Bind( 412 &MockObserver::MockCertificateCallback, 413 base::Unretained(&observer)); 414 415 scoped_ptr<ServerProxy> proxy_interface(proxy.release()); 416 AttestationFlow flow(&async_caller, &client, proxy_interface.Pass()); 417 flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, 418 false, mock_callback); 419 Run(); 420 } 421 422 } // namespace attestation 423 } // namespace chromeos 424