// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "chromeos/attestation/mock_attestation_flow.h"
#include "chromeos/cryptohome/mock_async_method_caller.h"
#include "chromeos/dbus/mock_cryptohome_client.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::Invoke;
using testing::Sequence;
using testing::StrictMock;
using testing::WithArgs;
namespace chromeos {
namespace attestation {
namespace {
void DBusCallbackFalse(const BoolDBusMethodCallback& callback) {
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, false));
}
void DBusCallbackTrue(const BoolDBusMethodCallback& callback) {
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true));
}
void DBusCallbackFail(const BoolDBusMethodCallback& callback) {
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_FAILURE, false));
}
void AsyncCallbackFalse(cryptohome::AsyncMethodCaller::Callback callback) {
callback.Run(false, cryptohome::MOUNT_ERROR_NONE);
}
class FakeDBusData {
public:
explicit FakeDBusData(const std::string& data) : data_(data) {}
void operator() (const CryptohomeClient::DataMethodCallback& callback) {
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, true, data_));
}
private:
std::string data_;
};
} // namespace
class AttestationFlowTest : public testing::Test {
protected:
void Run() {
base::RunLoop run_loop;
run_loop.RunUntilIdle();
}
base::MessageLoop message_loop_;
};
TEST_F(AttestationFlowTest, GetCertificate) {
// Verify the order of calls in a sequence.
Sequence flow_order;
// Use DBusCallbackFalse so the full enrollment flow is triggered.
chromeos::MockCryptohomeClient client;
EXPECT_CALL(client, TpmAttestationIsEnrolled(_))
.InSequence(flow_order)
.WillRepeatedly(Invoke(DBusCallbackFalse));
// Use StrictMock when we want to verify invocation frequency.
StrictMock<cryptohome::MockAsyncMethodCaller> async_caller;
async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE);
EXPECT_CALL(async_caller, AsyncTpmAttestationCreateEnrollRequest(_))
.Times(1)
.InSequence(flow_order);
scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
proxy->DeferToFake(true);
EXPECT_CALL(*proxy, SendEnrollRequest(
cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest,
_)).Times(1)
.InSequence(flow_order);
std::string fake_enroll_response =
cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest;
fake_enroll_response += "_response";
EXPECT_CALL(async_caller, AsyncTpmAttestationEnroll(fake_enroll_response, _))
.Times(1)
.InSequence(flow_order);
EXPECT_CALL(
async_caller,
AsyncTpmAttestationCreateCertRequest(PROFILE_ENTERPRISE_USER_CERTIFICATE,
"fake@test.com", "fake_origin", _))
.Times(1)
.InSequence(flow_order);
EXPECT_CALL(*proxy, SendCertificateRequest(
cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest,
_)).Times(1)
.InSequence(flow_order);
std::string fake_cert_response =
cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest;
fake_cert_response += "_response";
EXPECT_CALL(async_caller,
AsyncTpmAttestationFinishCertRequest(fake_cert_response,
KEY_USER,
"fake@test.com",
kEnterpriseUserKey,
_))
.Times(1)
.InSequence(flow_order);
StrictMock<MockObserver> observer;
EXPECT_CALL(observer, MockCertificateCallback(
true,
cryptohome::MockAsyncMethodCaller::kFakeAttestationCert))
.Times(1)
.InSequence(flow_order);
AttestationFlow::CertificateCallback mock_callback = base::Bind(
&MockObserver::MockCertificateCallback,
base::Unretained(&observer));
scoped_ptr<ServerProxy> proxy_interface(proxy.release());
AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "fake@test.com",
"fake_origin", true, mock_callback);
Run();
}
TEST_F(AttestationFlowTest, GetCertificate_NoEK) {
StrictMock<cryptohome::MockAsyncMethodCaller> async_caller;
async_caller.SetUp(false, cryptohome::MOUNT_ERROR_NONE);
EXPECT_CALL(async_caller, AsyncTpmAttestationCreateEnrollRequest(_))
.Times(1);
chromeos::MockCryptohomeClient client;
EXPECT_CALL(client, TpmAttestationIsEnrolled(_))
.WillRepeatedly(Invoke(DBusCallbackFalse));
// We're not expecting any server calls in this case; StrictMock will verify.
scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
StrictMock<MockObserver> observer;
EXPECT_CALL(observer, MockCertificateCallback(false, ""))
.Times(1);
AttestationFlow::CertificateCallback mock_callback = base::Bind(
&MockObserver::MockCertificateCallback,
base::Unretained(&observer));
scoped_ptr<ServerProxy> proxy_interface(proxy.release());
AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true,
mock_callback);
Run();
}
TEST_F(AttestationFlowTest, GetCertificate_EKRejected) {
StrictMock<cryptohome::MockAsyncMethodCaller> async_caller;
async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE);
EXPECT_CALL(async_caller, AsyncTpmAttestationCreateEnrollRequest(_))
.Times(1);
chromeos::MockCryptohomeClient client;
EXPECT_CALL(client, TpmAttestationIsEnrolled(_))
.WillRepeatedly(Invoke(DBusCallbackFalse));
scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
proxy->DeferToFake(false);
EXPECT_CALL(*proxy, SendEnrollRequest(
cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest,
_)).Times(1);
StrictMock<MockObserver> observer;
EXPECT_CALL(observer, MockCertificateCallback(false, ""))
.Times(1);
AttestationFlow::CertificateCallback mock_callback = base::Bind(
&MockObserver::MockCertificateCallback,
base::Unretained(&observer));
scoped_ptr<ServerProxy> proxy_interface(proxy.release());
AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true,
mock_callback);
Run();
}
TEST_F(AttestationFlowTest, GetCertificate_FailEnroll) {
StrictMock<cryptohome::MockAsyncMethodCaller> async_caller;
async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE);
EXPECT_CALL(async_caller, AsyncTpmAttestationCreateEnrollRequest(_))
.Times(1);
std::string fake_enroll_response =
cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest;
fake_enroll_response += "_response";
EXPECT_CALL(async_caller, AsyncTpmAttestationEnroll(fake_enroll_response, _))
.WillOnce(WithArgs<1>(Invoke(AsyncCallbackFalse)));
chromeos::MockCryptohomeClient client;
EXPECT_CALL(client, TpmAttestationIsEnrolled(_))
.WillRepeatedly(Invoke(DBusCallbackFalse));
scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
proxy->DeferToFake(true);
EXPECT_CALL(*proxy, SendEnrollRequest(
cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest,
_)).Times(1);
StrictMock<MockObserver> observer;
EXPECT_CALL(observer, MockCertificateCallback(false, "")).Times(1);
AttestationFlow::CertificateCallback mock_callback = base::Bind(
&MockObserver::MockCertificateCallback,
base::Unretained(&observer));
scoped_ptr<ServerProxy> proxy_interface(proxy.release());
AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true,
mock_callback);
Run();
}
TEST_F(AttestationFlowTest, GetMachineCertificateAlreadyEnrolled) {
StrictMock<cryptohome::MockAsyncMethodCaller> async_caller;
async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE);
EXPECT_CALL(async_caller,
AsyncTpmAttestationCreateCertRequest(
PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, "", "", _))
.Times(1);
std::string fake_cert_response =
cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest;
fake_cert_response += "_response";
EXPECT_CALL(async_caller,
AsyncTpmAttestationFinishCertRequest(fake_cert_response,
KEY_DEVICE,
"",
kEnterpriseMachineKey,
_))
.Times(1);
chromeos::MockCryptohomeClient client;
EXPECT_CALL(client, TpmAttestationIsEnrolled(_))
.WillRepeatedly(Invoke(DBusCallbackTrue));
scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
proxy->DeferToFake(true);
EXPECT_CALL(*proxy, SendCertificateRequest(
cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest,
_)).Times(1);
StrictMock<MockObserver> observer;
EXPECT_CALL(observer, MockCertificateCallback(
true,
cryptohome::MockAsyncMethodCaller::kFakeAttestationCert)).Times(1);
AttestationFlow::CertificateCallback mock_callback = base::Bind(
&MockObserver::MockCertificateCallback,
base::Unretained(&observer));
scoped_ptr<ServerProxy> proxy_interface(proxy.release());
AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
flow.GetCertificate(PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, "", "", true,
mock_callback);
Run();
}
TEST_F(AttestationFlowTest, GetCertificate_FailCreateCertRequest) {
StrictMock<cryptohome::MockAsyncMethodCaller> async_caller;
async_caller.SetUp(false, cryptohome::MOUNT_ERROR_NONE);
EXPECT_CALL(async_caller,
AsyncTpmAttestationCreateCertRequest(
PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", _))
.Times(1);
chromeos::MockCryptohomeClient client;
EXPECT_CALL(client, TpmAttestationIsEnrolled(_))
.WillRepeatedly(Invoke(DBusCallbackTrue));
// We're not expecting any server calls in this case; StrictMock will verify.
scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
StrictMock<MockObserver> observer;
EXPECT_CALL(observer, MockCertificateCallback(false, "")).Times(1);
AttestationFlow::CertificateCallback mock_callback = base::Bind(
&MockObserver::MockCertificateCallback,
base::Unretained(&observer));
scoped_ptr<ServerProxy> proxy_interface(proxy.release());
AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true,
mock_callback);
Run();
}
TEST_F(AttestationFlowTest, GetCertificate_CertRequestRejected) {
StrictMock<cryptohome::MockAsyncMethodCaller> async_caller;
async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE);
EXPECT_CALL(async_caller,
AsyncTpmAttestationCreateCertRequest(
PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", _))
.Times(1);
chromeos::MockCryptohomeClient client;
EXPECT_CALL(client, TpmAttestationIsEnrolled(_))
.WillRepeatedly(Invoke(DBusCallbackTrue));
scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
proxy->DeferToFake(false);
EXPECT_CALL(*proxy, SendCertificateRequest(
cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest,
_)).Times(1);
StrictMock<MockObserver> observer;
EXPECT_CALL(observer, MockCertificateCallback(false, "")).Times(1);
AttestationFlow::CertificateCallback mock_callback = base::Bind(
&MockObserver::MockCertificateCallback,
base::Unretained(&observer));
scoped_ptr<ServerProxy> proxy_interface(proxy.release());
AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true,
mock_callback);
Run();
}
TEST_F(AttestationFlowTest, GetCertificate_FailIsEnrolled) {
// We're not expecting any async calls in this case; StrictMock will verify.
StrictMock<cryptohome::MockAsyncMethodCaller> async_caller;
chromeos::MockCryptohomeClient client;
EXPECT_CALL(client, TpmAttestationIsEnrolled(_))
.WillRepeatedly(Invoke(DBusCallbackFail));
// We're not expecting any server calls in this case; StrictMock will verify.
scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
StrictMock<MockObserver> observer;
EXPECT_CALL(observer, MockCertificateCallback(false, "")).Times(1);
AttestationFlow::CertificateCallback mock_callback = base::Bind(
&MockObserver::MockCertificateCallback,
base::Unretained(&observer));
scoped_ptr<ServerProxy> proxy_interface(proxy.release());
AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true,
mock_callback);
Run();
}
TEST_F(AttestationFlowTest, GetCertificate_CheckExisting) {
StrictMock<cryptohome::MockAsyncMethodCaller> async_caller;
async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE);
EXPECT_CALL(async_caller,
AsyncTpmAttestationCreateCertRequest(
PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", _))
.Times(1);
std::string fake_cert_response =
cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest;
fake_cert_response += "_response";
EXPECT_CALL(async_caller,
AsyncTpmAttestationFinishCertRequest(fake_cert_response,
KEY_USER,
"",
kEnterpriseUserKey,
_))
.Times(1);
chromeos::MockCryptohomeClient client;
EXPECT_CALL(client, TpmAttestationIsEnrolled(_))
.WillRepeatedly(Invoke(DBusCallbackTrue));
EXPECT_CALL(client,
TpmAttestationDoesKeyExist(KEY_USER, "", kEnterpriseUserKey, _))
.WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackFalse)));
scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
proxy->DeferToFake(true);
EXPECT_CALL(*proxy, SendCertificateRequest(
cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest,
_)).Times(1);
StrictMock<MockObserver> observer;
EXPECT_CALL(observer, MockCertificateCallback(
true,
cryptohome::MockAsyncMethodCaller::kFakeAttestationCert)).Times(1);
AttestationFlow::CertificateCallback mock_callback = base::Bind(
&MockObserver::MockCertificateCallback,
base::Unretained(&observer));
scoped_ptr<ServerProxy> proxy_interface(proxy.release());
AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", false,
mock_callback);
Run();
}
TEST_F(AttestationFlowTest, GetCertificate_AlreadyExists) {
// We're not expecting any async calls in this case; StrictMock will verify.
StrictMock<cryptohome::MockAsyncMethodCaller> async_caller;
chromeos::MockCryptohomeClient client;
EXPECT_CALL(client, TpmAttestationIsEnrolled(_))
.WillRepeatedly(Invoke(DBusCallbackTrue));
EXPECT_CALL(client,
TpmAttestationDoesKeyExist(KEY_USER, "", kEnterpriseUserKey, _))
.WillRepeatedly(WithArgs<3>(Invoke(DBusCallbackTrue)));
EXPECT_CALL(client,
TpmAttestationGetCertificate(KEY_USER, "", kEnterpriseUserKey, _))
.WillRepeatedly(WithArgs<3>(Invoke(FakeDBusData("fake_cert"))));
// We're not expecting any server calls in this case; StrictMock will verify.
scoped_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
StrictMock<MockObserver> observer;
EXPECT_CALL(observer, MockCertificateCallback(true, "fake_cert")).Times(1);
AttestationFlow::CertificateCallback mock_callback = base::Bind(
&MockObserver::MockCertificateCallback,
base::Unretained(&observer));
scoped_ptr<ServerProxy> proxy_interface(proxy.release());
AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", false,
mock_callback);
Run();
}
} // namespace attestation
} // namespace chromeos