Home | History | Annotate | Download | only in attestation
      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