tpm_manager: Implemented server/client logic for a few initial commands.
The first commands supported are GetTpmStatus and TakeOwnership. This CL
implements the relevant server and client boilerplate and logic as well
as adds unit tests for this and current untested code.
This CL only includes mock implementations of the LocalDataStore,
TpmStatus, and TpmInitializer interfaces.
BUG=brillo:1040,brillo:1042
TEST=unit
Change-Id: Ie69d343c21ab8abee84eae5c1f3f08f0c37bbeca
Reviewed-on: https://chromium-review.googlesource.com/288367
Reviewed-by: Utkarsh Sanghi <usanghi@chromium.org>
Commit-Queue: Darren Krahn <dkrahn@chromium.org>
Tested-by: Darren Krahn <dkrahn@chromium.org>
diff --git a/client/dbus_proxy.cc b/client/dbus_proxy.cc
index be57336..b5429f2 100644
--- a/client/dbus_proxy.cc
+++ b/client/dbus_proxy.cc
@@ -53,4 +53,21 @@
request);
}
+void DBusProxy::TakeOwnership(const TakeOwnershipRequest& request,
+ const TakeOwnershipCallback& callback) {
+ auto on_error = [callback](chromeos::Error* error) {
+ TakeOwnershipReply reply;
+ reply.set_status(STATUS_NOT_AVAILABLE);
+ callback.Run(reply);
+ };
+ chromeos::dbus_utils::CallMethodWithTimeout(
+ kDBusTimeoutMS,
+ object_proxy_,
+ tpm_manager::kTpmManagerInterface,
+ tpm_manager::kTakeOwnership,
+ callback,
+ base::Bind(on_error),
+ request);
+}
+
} // namespace tpm_manager
diff --git a/client/dbus_proxy.h b/client/dbus_proxy.h
index 8945d07..b99b735 100644
--- a/client/dbus_proxy.h
+++ b/client/dbus_proxy.h
@@ -31,6 +31,8 @@
bool Initialize() override;
void GetTpmStatus(const GetTpmStatusRequest& request,
const GetTpmStatusCallback& callback) override;
+ void TakeOwnership(const TakeOwnershipRequest& request,
+ const TakeOwnershipCallback& callback) override;
void set_object_proxy(dbus::ObjectProxy* object_proxy) {
object_proxy_ = object_proxy;
diff --git a/client/dbus_proxy_test.cc b/client/dbus_proxy_test.cc
new file mode 100644
index 0000000..121896d
--- /dev/null
+++ b/client/dbus_proxy_test.cc
@@ -0,0 +1,108 @@
+// Copyright 2015 The Chromium OS 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 <string>
+
+#include <chromeos/bind_lambda.h>
+#include <dbus/mock_object_proxy.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "tpm_manager/client/dbus_proxy.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::StrictMock;
+using testing::WithArgs;
+
+namespace tpm_manager {
+
+class DBusProxyTest : public testing::Test {
+ public:
+ ~DBusProxyTest() override = default;
+ void SetUp() override {
+ mock_object_proxy_ = new StrictMock<dbus::MockObjectProxy>(
+ nullptr, "", dbus::ObjectPath(""));
+ proxy_.set_object_proxy(mock_object_proxy_.get());
+ }
+ protected:
+ scoped_refptr<StrictMock<dbus::MockObjectProxy>> mock_object_proxy_;
+ DBusProxy proxy_;
+};
+
+TEST_F(DBusProxyTest, GetTpmStatus) {
+ auto fake_dbus_call = [](
+ dbus::MethodCall* method_call,
+ const dbus::MockObjectProxy::ResponseCallback& response_callback) {
+ // Verify request protobuf.
+ dbus::MessageReader reader(method_call);
+ GetTpmStatusRequest request;
+ EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&request));
+ // Create reply protobuf.
+ auto response = dbus::Response::CreateEmpty();
+ dbus::MessageWriter writer(response.get());
+ GetTpmStatusReply reply;
+ reply.set_status(STATUS_NOT_AVAILABLE);
+ reply.set_enabled(true);
+ reply.set_owned(true);
+ reply.mutable_local_data()->set_owned_by_this_install(true);
+ reply.set_dictionary_attack_counter(3);
+ reply.set_dictionary_attack_threshold(4);
+ reply.set_dictionary_attack_lockout_in_effect(true);
+ reply.set_dictionary_attack_lockout_seconds_remaining(5);
+ writer.AppendProtoAsArrayOfBytes(reply);
+ response_callback.Run(response.release());
+ };
+ EXPECT_CALL(*mock_object_proxy_, CallMethodWithErrorCallback(_, _, _, _))
+ .WillOnce(WithArgs<0, 2>(Invoke(fake_dbus_call)));
+
+ // Set expectations on the outputs.
+ int callback_count = 0;
+ auto callback = [&callback_count](const GetTpmStatusReply& reply) {
+ callback_count++;
+ EXPECT_EQ(STATUS_NOT_AVAILABLE, reply.status());
+ EXPECT_TRUE(reply.enabled());
+ EXPECT_TRUE(reply.owned());
+ EXPECT_TRUE(reply.local_data().owned_by_this_install());
+ EXPECT_EQ(3, reply.dictionary_attack_counter());
+ EXPECT_EQ(4, reply.dictionary_attack_threshold());
+ EXPECT_TRUE(reply.dictionary_attack_lockout_in_effect());
+ EXPECT_EQ(5, reply.dictionary_attack_lockout_seconds_remaining());
+ };
+ GetTpmStatusRequest request;
+ proxy_.GetTpmStatus(request, base::Bind(callback));
+ EXPECT_EQ(1, callback_count);
+}
+
+TEST_F(DBusProxyTest, TakeOwnership) {
+ auto fake_dbus_call = [](
+ dbus::MethodCall* method_call,
+ const dbus::MockObjectProxy::ResponseCallback& response_callback) {
+ // Verify request protobuf.
+ dbus::MessageReader reader(method_call);
+ TakeOwnershipRequest request;
+ EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&request));
+ // Create reply protobuf.
+ auto response = dbus::Response::CreateEmpty();
+ dbus::MessageWriter writer(response.get());
+ TakeOwnershipReply reply;
+ reply.set_status(STATUS_NOT_AVAILABLE);
+ writer.AppendProtoAsArrayOfBytes(reply);
+ response_callback.Run(response.release());
+ };
+ EXPECT_CALL(*mock_object_proxy_, CallMethodWithErrorCallback(_, _, _, _))
+ .WillOnce(WithArgs<0, 2>(Invoke(fake_dbus_call)));
+
+ // Set expectations on the outputs.
+ int callback_count = 0;
+ auto callback = [&callback_count](const TakeOwnershipReply& reply) {
+ callback_count++;
+ EXPECT_EQ(STATUS_NOT_AVAILABLE, reply.status());
+ };
+ TakeOwnershipRequest request;
+ proxy_.TakeOwnership(request, base::Bind(callback));
+ EXPECT_EQ(1, callback_count);
+}
+
+} // namespace tpm_manager
diff --git a/common/dbus_interface.h b/common/dbus_interface.h
index 1fce92c..d0f8981 100644
--- a/common/dbus_interface.h
+++ b/common/dbus_interface.h
@@ -13,6 +13,7 @@
// Methods exported by tpm_manager.
constexpr char kGetTpmStatus[] = "GetTpmStatus";
+constexpr char kTakeOwnership[] = "TakeOwnership";
} // namespace tpm_manager
diff --git a/common/dbus_interface.proto b/common/dbus_interface.proto
index 201dfc6..216bda5 100644
--- a/common/dbus_interface.proto
+++ b/common/dbus_interface.proto
@@ -1,50 +1,44 @@
option optimize_for = LITE_RUNTIME;
package tpm_manager;
+import "local_data.proto";
+
// The messages in this file correspond to the TpmManager D-Bus interface.
enum TpmManagerStatus {
STATUS_SUCCESS = 0;
- STATUS_NOT_AVAILABLE = 1;
+ STATUS_UNEXPECTED_DEVICE_ERROR = 1;
+ STATUS_NOT_AVAILABLE = 2;
}
-// Input for the GetTpmStatus method
+// Input for the GetTpmStatus method.
message GetTpmStatusRequest {
}
-// Output from the GetTpmStatus method
+// Output from the GetTpmStatus method.
message GetTpmStatusReply {
optional TpmManagerStatus status = 1;
-
// Whether a TPM is enabled on the system.
optional bool enabled = 2;
// Whether the TPM has been owned.
optional bool owned = 3;
- // Whether the TPM initialization flow has completed. This includes taking
- // ownership, preparing attestation data, and finalizing lockbox NVRAM.
- optional bool initialized = 4;
- // The TPM owner password. This is only available when (owned &&
- // !initialized) and sometimes not even then.
- optional string owner_password = 5;
- // Whether attestation data has been prepared. This includes reading the
- // endorsement certificate out of NVRAM and generating an identity key. This
- // does not include any kind of enrollment with a Privacy CA.
- optional bool attestation_prepared = 6;
- // Whether the device has enrolled with a Privacy CA. This means the identity
- // key has been successfully certified.
- optional bool attestation_enrolled = 7;
+ // Local TPM management data (including the owner password if available).
+ optional LocalData local_data = 4;
// The current dictionary attack counter value.
- optional int32 dictionary_attack_counter = 8;
+ optional int32 dictionary_attack_counter = 5;
// The current dictionary attack counter threshold.
- optional int32 dictionary_attack_threshold = 9;
+ optional int32 dictionary_attack_threshold = 6;
// Whether the TPM is in some form of dictionary attack lockout.
- optional bool dictionary_attack_lockout_in_effect = 10;
+ optional bool dictionary_attack_lockout_in_effect = 7;
// The number of seconds remaining in the lockout.
- optional int32 dictionary_attack_lockout_seconds_remaining = 11;
- // Whether the install lockbox has been finalized.
- optional bool install_lockbox_finalized = 12;
- // Whether the boot lockbox has been finalized.
- optional bool boot_lockbox_finalized = 13;
- // Whether the current PCR values show a verified boot.
- optional bool verified_boot_measured = 14;
+ optional int32 dictionary_attack_lockout_seconds_remaining = 8;
+}
+
+// Input for the TakeOwnership method.
+message TakeOwnershipRequest {
+}
+
+// Output from the TakeOwnership method.
+message TakeOwnershipReply {
+ optional TpmManagerStatus status = 1;
}
diff --git a/common/local_data.proto b/common/local_data.proto
new file mode 100644
index 0000000..efcca47
--- /dev/null
+++ b/common/local_data.proto
@@ -0,0 +1,9 @@
+option optimize_for = LITE_RUNTIME;
+package tpm_manager;
+
+// The format of persistent local TPM management data stored on the device.
+message LocalData {
+ optional bool owned_by_this_install = 1;
+ optional bytes owner_password = 2;
+ repeated string owner_dependency = 3;
+}
diff --git a/common/mock_tpm_manager_interface.cc b/common/mock_tpm_manager_interface.cc
new file mode 100644
index 0000000..f16a1b5
--- /dev/null
+++ b/common/mock_tpm_manager_interface.cc
@@ -0,0 +1,12 @@
+// Copyright 2015 The Chromium OS 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 "tpm_manager/common/mock_tpm_manager_interface.h"
+
+namespace tpm_manager {
+
+MockTpmManagerInterface::MockTpmManagerInterface() {}
+MockTpmManagerInterface::~MockTpmManagerInterface() {}
+
+} // namespace tpm_manager
diff --git a/common/mock_tpm_manager_interface.h b/common/mock_tpm_manager_interface.h
new file mode 100644
index 0000000..664f91c
--- /dev/null
+++ b/common/mock_tpm_manager_interface.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TPM_MANAGER_COMMON_MOCK_TPM_MANAGER_INTERFACE_H_
+#define TPM_MANAGER_COMMON_MOCK_TPM_MANAGER_INTERFACE_H_
+
+#include "tpm_manager/common/tpm_manager_interface.h"
+
+#include <gmock/gmock.h>
+
+namespace tpm_manager {
+
+class MockTpmManagerInterface : public TpmManagerInterface {
+ public:
+ MockTpmManagerInterface();
+ ~MockTpmManagerInterface() override;
+
+ MOCK_METHOD0(Initialize, bool());
+ MOCK_METHOD2(GetTpmStatus,
+ void(const GetTpmStatusRequest& request,
+ const GetTpmStatusCallback& callback));
+ MOCK_METHOD2(TakeOwnership,
+ void(const TakeOwnershipRequest& request,
+ const TakeOwnershipCallback& callback));
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_COMMON_MOCK_TPM_MANAGER_INTERFACE_H_
diff --git a/common/tpm_manager_interface.h b/common/tpm_manager_interface.h
index 0185966..bee631f 100644
--- a/common/tpm_manager_interface.h
+++ b/common/tpm_manager_interface.h
@@ -26,6 +26,11 @@
using GetTpmStatusCallback = base::Callback<void(const GetTpmStatusReply&)>;
virtual void GetTpmStatus(const GetTpmStatusRequest& request,
const GetTpmStatusCallback& callback) = 0;
+
+ // Processes a TakeOwnershipRequest and responds with a TakeOwnershipReply.
+ using TakeOwnershipCallback = base::Callback<void(const TakeOwnershipReply&)>;
+ virtual void TakeOwnership(const TakeOwnershipRequest& request,
+ const TakeOwnershipCallback& callback) = 0;
};
} // namespace tpm_manager
diff --git a/server/dbus_service.cc b/server/dbus_service.cc
index 7708cb1..e326f0c 100644
--- a/server/dbus_service.cc
+++ b/server/dbus_service.cc
@@ -28,6 +28,8 @@
dbus_interface->AddMethodHandler(kGetTpmStatus, base::Unretained(this),
&DBusService::HandleGetTpmStatus);
+ dbus_interface->AddMethodHandler(kTakeOwnership, base::Unretained(this),
+ &DBusService::HandleTakeOwnership);
dbus_object_.RegisterAsync(callback);
}
@@ -38,7 +40,7 @@
// callback.
using SharedResponsePointer = std::shared_ptr<
DBusMethodResponse<const GetTpmStatusReply&>>;
- // A callback that fills the reply protobuf and sends it.
+ // A callback that sends off the reply protobuf.
auto callback = [](const SharedResponsePointer& response,
const GetTpmStatusReply& reply) {
response->Return(reply);
@@ -48,4 +50,21 @@
base::Bind(callback, SharedResponsePointer(std::move(response))));
}
+void DBusService::HandleTakeOwnership(
+ std::unique_ptr<DBusMethodResponse<const TakeOwnershipReply&>> response,
+ const TakeOwnershipRequest& request) {
+ // Convert |response| to a shared_ptr so |service_| can safely copy the
+ // callback.
+ using SharedResponsePointer = std::shared_ptr<
+ DBusMethodResponse<const TakeOwnershipReply&>>;
+ // A callback that sends off the reply protobuf.
+ auto callback = [](const SharedResponsePointer& response,
+ const TakeOwnershipReply& reply) {
+ response->Return(reply);
+ };
+ service_->TakeOwnership(
+ request,
+ base::Bind(callback, SharedResponsePointer(std::move(response))));
+}
+
} // namespace tpm_manager
diff --git a/server/dbus_service.h b/server/dbus_service.h
index 2d52ffd..8286ced 100644
--- a/server/dbus_service.h
+++ b/server/dbus_service.h
@@ -35,12 +35,20 @@
}
private:
+ friend class DBusServiceTest;
+
// Handles the GetTpmStatus D-Bus call.
void HandleGetTpmStatus(
std::unique_ptr<chromeos::dbus_utils::DBusMethodResponse<
const GetTpmStatusReply&>> response,
const GetTpmStatusRequest& request);
+ // Handles the TakeOwnership D-Bus call.
+ void HandleTakeOwnership(
+ std::unique_ptr<chromeos::dbus_utils::DBusMethodResponse<
+ const TakeOwnershipReply&>> response,
+ const TakeOwnershipRequest& request);
+
chromeos::dbus_utils::DBusObject dbus_object_;
TpmManagerInterface* service_;
DISALLOW_COPY_AND_ASSIGN(DBusService);
diff --git a/server/dbus_service_test.cc b/server/dbus_service_test.cc
new file mode 100644
index 0000000..0647951
--- /dev/null
+++ b/server/dbus_service_test.cc
@@ -0,0 +1,136 @@
+// Copyright 2015 The Chromium OS 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 <string>
+
+#include <chromeos/bind_lambda.h>
+#include <chromeos/dbus/dbus_object_test_helpers.h>
+#include <dbus/mock_bus.h>
+#include <dbus/mock_exported_object.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "tpm_manager/common/dbus_interface.h"
+#include "tpm_manager/common/mock_tpm_manager_interface.h"
+#include "tpm_manager/server/dbus_service.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::NiceMock;
+using testing::Return;
+using testing::StrictMock;
+using testing::WithArgs;
+
+namespace tpm_manager {
+
+class DBusServiceTest : public testing::Test {
+ public:
+ ~DBusServiceTest() override = default;
+ void SetUp() override {
+ dbus::Bus::Options options;
+ mock_bus_ = new NiceMock<dbus::MockBus>(options);
+ dbus::ObjectPath path(kTpmManagerServicePath);
+ mock_exported_object_ = new NiceMock<dbus::MockExportedObject>(
+ mock_bus_.get(), path);
+ ON_CALL(*mock_bus_, GetExportedObject(path))
+ .WillByDefault(Return(mock_exported_object_.get()));
+ dbus_service_.reset(new DBusService(mock_bus_, &mock_service_));
+ dbus_service_->Register(chromeos::dbus_utils::AsyncEventSequencer::
+ GetDefaultCompletionAction());
+ }
+
+ std::unique_ptr<dbus::Response> CallMethod(dbus::MethodCall* method_call) {
+ return chromeos::dbus_utils::testing::CallMethod(
+ dbus_service_->dbus_object_, method_call);
+ }
+
+ std::unique_ptr<dbus::MethodCall> CreateMethodCall(
+ const std::string& method_name) {
+ std::unique_ptr<dbus::MethodCall> call(new dbus::MethodCall(
+ kTpmManagerInterface, method_name));
+ call->SetSerial(1);
+ return call;
+ }
+
+ protected:
+ scoped_refptr<dbus::MockBus> mock_bus_;
+ scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
+ StrictMock<MockTpmManagerInterface> mock_service_;
+ std::unique_ptr<DBusService> dbus_service_;
+};
+
+TEST_F(DBusServiceTest, CopyableCallback) {
+ EXPECT_CALL(mock_service_, GetTpmStatus(_, _))
+ .WillOnce(WithArgs<1>(
+ Invoke([](const TpmManagerInterface::GetTpmStatusCallback& callback) {
+ // Copy the callback, then call the original.
+ GetTpmStatusReply reply;
+ base::Closure copy = base::Bind(callback, reply);
+ callback.Run(reply);
+ })));
+ std::unique_ptr<dbus::MethodCall> call = CreateMethodCall(kGetTpmStatus);
+ GetTpmStatusRequest request;
+ dbus::MessageWriter writer(call.get());
+ writer.AppendProtoAsArrayOfBytes(request);
+ auto response = CallMethod(call.get());
+ dbus::MessageReader reader(response.get());
+ GetTpmStatusReply reply;
+ EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply));
+}
+
+TEST_F(DBusServiceTest, GetTpmStatus) {
+ GetTpmStatusRequest request;
+ EXPECT_CALL(mock_service_, GetTpmStatus(_, _))
+ .WillOnce(Invoke([](
+ const GetTpmStatusRequest& request,
+ const TpmManagerInterface::GetTpmStatusCallback& callback) {
+ GetTpmStatusReply reply;
+ reply.set_status(STATUS_NOT_AVAILABLE);
+ reply.set_enabled(true);
+ reply.set_owned(true);
+ reply.mutable_local_data()->set_owned_by_this_install(true);
+ reply.set_dictionary_attack_counter(3);
+ reply.set_dictionary_attack_threshold(4);
+ reply.set_dictionary_attack_lockout_in_effect(true);
+ reply.set_dictionary_attack_lockout_seconds_remaining(5);
+ callback.Run(reply);
+ }));
+ std::unique_ptr<dbus::MethodCall> call = CreateMethodCall(kGetTpmStatus);
+ dbus::MessageWriter writer(call.get());
+ writer.AppendProtoAsArrayOfBytes(request);
+ auto response = CallMethod(call.get());
+ dbus::MessageReader reader(response.get());
+ GetTpmStatusReply reply;
+ EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply));
+ EXPECT_EQ(STATUS_NOT_AVAILABLE, reply.status());
+ EXPECT_TRUE(reply.enabled());
+ EXPECT_TRUE(reply.owned());
+ EXPECT_TRUE(reply.local_data().owned_by_this_install());
+ EXPECT_EQ(3, reply.dictionary_attack_counter());
+ EXPECT_EQ(4, reply.dictionary_attack_threshold());
+ EXPECT_TRUE(reply.dictionary_attack_lockout_in_effect());
+ EXPECT_EQ(5, reply.dictionary_attack_lockout_seconds_remaining());
+}
+
+TEST_F(DBusServiceTest, TakeOwnership) {
+ TakeOwnershipRequest request;
+ EXPECT_CALL(mock_service_, TakeOwnership(_, _))
+ .WillOnce(Invoke([](
+ const TakeOwnershipRequest& request,
+ const TpmManagerInterface::TakeOwnershipCallback& callback) {
+ TakeOwnershipReply reply;
+ reply.set_status(STATUS_NOT_AVAILABLE);
+ callback.Run(reply);
+ }));
+ std::unique_ptr<dbus::MethodCall> call = CreateMethodCall(kTakeOwnership);
+ dbus::MessageWriter writer(call.get());
+ writer.AppendProtoAsArrayOfBytes(request);
+ auto response = CallMethod(call.get());
+ dbus::MessageReader reader(response.get());
+ TakeOwnershipReply reply;
+ EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply));
+ EXPECT_EQ(STATUS_NOT_AVAILABLE, reply.status());
+}
+
+} // namespace tpm_manager
diff --git a/server/local_data_store.h b/server/local_data_store.h
new file mode 100644
index 0000000..0bfecf5
--- /dev/null
+++ b/server/local_data_store.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TPM_MANAGER_SERVER_LOCAL_DATA_STORE_H_
+#define TPM_MANAGER_SERVER_LOCAL_DATA_STORE_H_
+
+#include "tpm_manager/common/local_data.pb.h"
+
+namespace tpm_manager {
+
+// LocalDataStore is an interface class that provides access to read and write
+// local system data.
+class LocalDataStore {
+ public:
+ LocalDataStore() = default;
+ virtual ~LocalDataStore() = default;
+
+ // Reads local |data| from persistent storage. If no local data exists, the
+ // output is an empty protobuf and the method succeeds. Returns true on
+ // success.
+ virtual bool Read(LocalData* data) = 0;
+
+ // Writes local |data| to persistent storage. Returns true on success.
+ virtual bool Write(const LocalData& data) = 0;
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_LOCAL_DATA_STORE_H_
diff --git a/server/main.cc b/server/main.cc
index 6333a26..17f906b 100644
--- a/server/main.cc
+++ b/server/main.cc
@@ -25,6 +25,8 @@
const char kTpmManagerGroup[] = "tpm_manager";
const char kTpmManagerSeccompPath[] =
"/usr/share/policy/tpm_managerd-seccomp.policy";
+const char kWaitForOwnershipTriggerSwitch[] = "wait_for_ownership_trigger";
+
void InitMinijailSandbox() {
uid_t tpm_manager_uid;
@@ -46,13 +48,13 @@
<< "TpmManagerDaemon was not able to drop to tpm_manager group.";
}
-} // namespace
-
class TpmManagerDaemon : public chromeos::DBusServiceDaemon {
public:
TpmManagerDaemon()
: chromeos::DBusServiceDaemon(tpm_manager::kTpmManagerServiceName) {
- tpm_manager_service_.reset(new tpm_manager::TpmManagerService);
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ tpm_manager_service_.reset(new tpm_manager::TpmManagerService(
+ command_line->HasSwitch(kWaitForOwnershipTriggerSwitch)));
}
protected:
@@ -79,11 +81,13 @@
DISALLOW_COPY_AND_ASSIGN(TpmManagerDaemon);
};
+} // namespace
+
int main(int argc, char* argv[]) {
base::CommandLine::Init(argc, argv);
chromeos::InitLog(chromeos::kLogToSyslog | chromeos::kLogToStderr);
+ InitMinijailSandbox();
TpmManagerDaemon daemon;
LOG(INFO) << "TpmManager Daemon Started";
- InitMinijailSandbox();
return daemon.Run();
}
diff --git a/server/mock_local_data_store.cc b/server/mock_local_data_store.cc
new file mode 100644
index 0000000..e4978da
--- /dev/null
+++ b/server/mock_local_data_store.cc
@@ -0,0 +1,23 @@
+// Copyright 2015 The Chromium OS 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 "tpm_manager/server/mock_local_data_store.h"
+
+using testing::_;
+using testing::DoAll;
+using testing::Return;
+using testing::SaveArg;
+using testing::SetArgPointee;
+
+namespace tpm_manager {
+
+MockLocalDataStore::MockLocalDataStore() {
+ ON_CALL(*this, Read(_))
+ .WillByDefault(DoAll(SetArgPointee<0>(fake_), Return(true)));
+ ON_CALL(*this, Write(_))
+ .WillByDefault(DoAll(SaveArg<0>(&fake_), Return(true)));
+}
+MockLocalDataStore::~MockLocalDataStore() {}
+
+} // namespace tpm_manager
diff --git a/server/mock_local_data_store.h b/server/mock_local_data_store.h
new file mode 100644
index 0000000..5c22011
--- /dev/null
+++ b/server/mock_local_data_store.h
@@ -0,0 +1,28 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TPM_MANAGER_SERVER_MOCK_LOCAL_DATA_STORE_H_
+#define TPM_MANAGER_SERVER_MOCK_LOCAL_DATA_STORE_H_
+
+#include "tpm_manager/server/local_data_store.h"
+
+#include <gmock/gmock.h>
+
+namespace tpm_manager {
+
+class MockLocalDataStore : public LocalDataStore {
+ public:
+ MockLocalDataStore();
+ ~MockLocalDataStore() override;
+
+ MOCK_METHOD1(Read, bool(LocalData*));
+ MOCK_METHOD1(Write, bool(const LocalData&));
+
+ private:
+ LocalData fake_;
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_MOCK_LOCAL_DATA_STORE_H_
diff --git a/server/mock_tpm_initializer.cc b/server/mock_tpm_initializer.cc
new file mode 100644
index 0000000..23614be
--- /dev/null
+++ b/server/mock_tpm_initializer.cc
@@ -0,0 +1,16 @@
+// Copyright 2015 The Chromium OS 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 "tpm_manager/server/mock_tpm_initializer.h"
+
+using testing::Return;
+
+namespace tpm_manager {
+
+MockTpmInitializer::MockTpmInitializer() {
+ ON_CALL(*this, InitializeTpm()).WillByDefault(Return(true));
+}
+MockTpmInitializer::~MockTpmInitializer() {}
+
+} // namespace tpm_manager
diff --git a/server/mock_tpm_initializer.h b/server/mock_tpm_initializer.h
new file mode 100644
index 0000000..81297b2
--- /dev/null
+++ b/server/mock_tpm_initializer.h
@@ -0,0 +1,24 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TPM_MANAGER_SERVER_MOCK_TPM_INITIALIZER_H_
+#define TPM_MANAGER_SERVER_MOCK_TPM_INITIALIZER_H_
+
+#include "tpm_manager/server/tpm_initializer.h"
+
+#include <gmock/gmock.h>
+
+namespace tpm_manager {
+
+class MockTpmInitializer : public TpmInitializer {
+ public:
+ MockTpmInitializer();
+ ~MockTpmInitializer() override;
+
+ MOCK_METHOD0(InitializeTpm, bool());
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_MOCK_TPM_INITIALIZER_H_
diff --git a/server/mock_tpm_status.cc b/server/mock_tpm_status.cc
new file mode 100644
index 0000000..345619a
--- /dev/null
+++ b/server/mock_tpm_status.cc
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium OS 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 "tpm_manager/server/mock_tpm_status.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::Return;
+
+namespace tpm_manager {
+
+bool GetDefaultDictionaryAttackInfo(int* counter,
+ int* threshold,
+ bool* lockout,
+ int* seconds_remaining) {
+ *counter = 0;
+ *threshold = 10;
+ *lockout = false;
+ *seconds_remaining = 0;
+ return true;
+}
+
+MockTpmStatus::MockTpmStatus() {
+ ON_CALL(*this, IsTpmEnabled()).WillByDefault(Return(true));
+ ON_CALL(*this, IsTpmOwned()).WillByDefault(Return(true));
+ ON_CALL(*this, GetDictionaryAttackInfo(_, _, _, _))
+ .WillByDefault(Invoke(GetDefaultDictionaryAttackInfo));
+}
+MockTpmStatus::~MockTpmStatus() {}
+
+} // namespace tpm_manager
diff --git a/server/mock_tpm_status.h b/server/mock_tpm_status.h
new file mode 100644
index 0000000..963c47e
--- /dev/null
+++ b/server/mock_tpm_status.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TPM_MANAGER_SERVER_MOCK_TPM_STATUS_H_
+#define TPM_MANAGER_SERVER_MOCK_TPM_STATUS_H_
+
+#include "tpm_manager/server/tpm_status.h"
+
+#include <gmock/gmock.h>
+
+namespace tpm_manager {
+
+class MockTpmStatus : public TpmStatus {
+ public:
+ MockTpmStatus();
+ ~MockTpmStatus() override;
+
+ MOCK_METHOD0(IsTpmEnabled, bool());
+ MOCK_METHOD0(IsTpmOwned, bool());
+ MOCK_METHOD4(GetDictionaryAttackInfo,
+ bool(int* counter,
+ int* threshold,
+ bool* lockout,
+ int* seconds_remaining));
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_MOCK_TPM_STATUS_H_
diff --git a/server/tpm_initializer.h b/server/tpm_initializer.h
new file mode 100644
index 0000000..34aa0d0
--- /dev/null
+++ b/server/tpm_initializer.h
@@ -0,0 +1,25 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TPM_MANAGER_SERVER_TPM_INITIALIZER_H_
+#define TPM_MANAGER_SERVER_TPM_INITIALIZER_H_
+
+namespace tpm_manager {
+
+// TpmInitializer performs initialization tasks on some kind of TPM device.
+class TpmInitializer {
+ public:
+ TpmInitializer() = default;
+ virtual ~TpmInitializer() = default;
+
+ // Initializes a TPM and returns true on success. If the TPM is already
+ // initialized, this method has no effect and succeeds. If the TPM is
+ // partially initialized, e.g. the process was previously interrupted, then
+ // the process picks up where it left off.
+ virtual bool InitializeTpm() = 0;
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_TPM_INITIALIZER_H_
diff --git a/server/tpm_manager_service.cc b/server/tpm_manager_service.cc
index a91b967..dc7e284 100644
--- a/server/tpm_manager_service.cc
+++ b/server/tpm_manager_service.cc
@@ -5,20 +5,41 @@
#include "tpm_manager/server/tpm_manager_service.h"
#include <base/callback.h>
+#include <base/command_line.h>
#include <chromeos/bind_lambda.h>
namespace tpm_manager {
-TpmManagerService::TpmManagerService() : weak_factory_(this) {}
+TpmManagerService::TpmManagerService(bool wait_for_ownership)
+ : wait_for_ownership_(wait_for_ownership),
+ weak_factory_(this) {
+}
bool TpmManagerService::Initialize() {
LOG(INFO) << "TpmManager service started.";
worker_thread_.reset(new base::Thread("TpmManager Service Worker"));
worker_thread_->StartWithOptions(
base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
+ base::Closure task = base::Bind(&TpmManagerService::InitializeTask,
+ base::Unretained(this));
+ worker_thread_->task_runner()->PostNonNestableTask(FROM_HERE, task);
return true;
}
+void TpmManagerService::InitializeTask() {
+ if (!tpm_status_->IsTpmEnabled()) {
+ LOG(WARNING) << __func__ << ": TPM is disabled.";
+ return;
+ }
+ if (!wait_for_ownership_) {
+ VLOG(1) << "Initializing TPM.";
+ if (!tpm_initializer_->InitializeTpm()) {
+ LOG(WARNING) << __func__ << ": TPM initialization failed.";
+ return;
+ }
+ }
+}
+
void TpmManagerService::GetTpmStatus(const GetTpmStatusRequest& request,
const GetTpmStatusCallback& callback) {
auto result = std::make_shared<GetTpmStatusReply>();
@@ -35,8 +56,52 @@
void TpmManagerService::GetTpmStatusTask(
const GetTpmStatusRequest& request,
const std::shared_ptr<GetTpmStatusReply>& result) {
- VLOG(1) << "Performing GetTpmStatusTask.";
- result->set_status(STATUS_NOT_AVAILABLE);
+ VLOG(1) << __func__;
+ result->set_enabled(tpm_status_->IsTpmEnabled());
+ result->set_owned(tpm_status_->IsTpmOwned());
+ LocalData local_data;
+ if (local_data_store_->Read(&local_data)) {
+ *result->mutable_local_data() = local_data;
+ }
+ int counter;
+ int threshold;
+ bool lockout;
+ int lockout_time_remaining;
+ if (tpm_status_->GetDictionaryAttackInfo(&counter, &threshold, &lockout,
+ &lockout_time_remaining)) {
+ result->set_dictionary_attack_counter(counter);
+ result->set_dictionary_attack_threshold(threshold);
+ result->set_dictionary_attack_lockout_in_effect(lockout);
+ result->set_dictionary_attack_lockout_seconds_remaining(
+ lockout_time_remaining);
+ }
+}
+
+void TpmManagerService::TakeOwnership(const TakeOwnershipRequest& request,
+ const TakeOwnershipCallback& callback) {
+ auto result = std::make_shared<TakeOwnershipReply>();
+ base::Closure task = base::Bind(&TpmManagerService::TakeOwnershipTask,
+ base::Unretained(this), request, result);
+ base::Closure reply = base::Bind(
+ &TpmManagerService::TaskRelayCallback<TakeOwnershipReply>,
+ weak_factory_.GetWeakPtr(),
+ callback,
+ result);
+ worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply);
+}
+
+void TpmManagerService::TakeOwnershipTask(
+ const TakeOwnershipRequest& request,
+ const std::shared_ptr<TakeOwnershipReply>& result) {
+ VLOG(1) << __func__;
+ if (!tpm_status_->IsTpmEnabled()) {
+ result->set_status(STATUS_NOT_AVAILABLE);
+ return;
+ }
+ if (!tpm_initializer_->InitializeTpm()) {
+ result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+ return;
+ }
}
} // namespace tpm_manager
diff --git a/server/tpm_manager_service.h b/server/tpm_manager_service.h
index 7f9afd7..56144ee 100644
--- a/server/tpm_manager_service.h
+++ b/server/tpm_manager_service.h
@@ -15,6 +15,10 @@
#include <base/threading/thread.h>
#include <chromeos/bind_lambda.h>
+#include "tpm_manager/server/local_data_store.h"
+#include "tpm_manager/server/tpm_initializer.h"
+#include "tpm_manager/server/tpm_status.h"
+
namespace tpm_manager {
// This class implements the core tpm_manager service. All Tpm access is
@@ -37,13 +41,30 @@
// back to the main thread.
class TpmManagerService : public TpmManagerInterface {
public:
- TpmManagerService();
+ // If |wait_for_ownership| is set, TPM initialization will be postponed until
+ // an explicit TakeOwnership request is received.
+ explicit TpmManagerService(bool wait_for_ownership);
~TpmManagerService() override = default;
// TpmManagerInterface methods.
bool Initialize() override;
void GetTpmStatus(const GetTpmStatusRequest& request,
const GetTpmStatusCallback& callback) override;
+ void TakeOwnership(const TakeOwnershipRequest& request,
+ const TakeOwnershipCallback& callback) override;
+
+ // Mutators useful for injecting dependencies for testing.
+ void set_local_data_store(LocalDataStore* local_data_store) {
+ local_data_store_ = local_data_store;
+ }
+
+ void set_tpm_initializer(TpmInitializer* initializer) {
+ tpm_initializer_ = initializer;
+ }
+
+ void set_tpm_status(TpmStatus* status) {
+ tpm_status_ = status;
+ }
private:
// A relay callback which allows the use of weak pointer semantics for a reply
@@ -60,8 +81,25 @@
void GetTpmStatusTask(const GetTpmStatusRequest& request,
const std::shared_ptr<GetTpmStatusReply>& result);
- // Background thread to allow processing of potentially large TPM
- // requests in the background.
+ // Blocking implementation of TakeOwnership that can be executed on the
+ // background worker thread.
+ void TakeOwnershipTask(const TakeOwnershipRequest& request,
+ const std::shared_ptr<TakeOwnershipReply>& result);
+
+ // Synchronously initializes the TPM according to the current configuration.
+ // If an initialization process was interrupted it will be continued. If the
+ // TPM is already initialized or cannot yet be initialized, this method has no
+ // effect.
+ void InitializeTask();
+
+ LocalDataStore* local_data_store_{nullptr};
+ TpmInitializer* tpm_initializer_{nullptr};
+ TpmStatus* tpm_status_{nullptr};
+ // Whether to wait for an explicit call to 'TakeOwnership' before initializing
+ // the TPM. Normally tracks the --wait_for_ownership command line option.
+ bool wait_for_ownership_;
+ // Background thread to allow processing of potentially lengthy TPM requests
+ // in the background.
std::unique_ptr<base::Thread> worker_thread_;
// Declared last so any weak pointers are destroyed first.
diff --git a/server/tpm_manager_service_test.cc b/server/tpm_manager_service_test.cc
new file mode 100644
index 0000000..337cd72
--- /dev/null
+++ b/server/tpm_manager_service_test.cc
@@ -0,0 +1,223 @@
+// Copyright 2015 The Chromium OS 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/run_loop.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "tpm_manager/server/mock_local_data_store.h"
+#include "tpm_manager/server/mock_tpm_initializer.h"
+#include "tpm_manager/server/mock_tpm_status.h"
+#include "tpm_manager/server/tpm_manager_service.h"
+
+using testing::_;
+using testing::AtLeast;
+using testing::Invoke;
+using testing::NiceMock;
+using testing::Return;
+using testing::SetArgPointee;
+
+namespace tpm_manager {
+
+// A test fixture that takes care of message loop management and configuring a
+// TpmManagerService instance with mock dependencies.
+class TpmManagerServiceTest : public testing::Test {
+ public:
+ ~TpmManagerServiceTest() override = default;
+ void SetUp() override {
+ service_.reset(new TpmManagerService(true /*wait_for_ownership*/));
+ SetupService();
+ }
+
+ protected:
+ void Run() {
+ run_loop_.Run();
+ }
+
+ void RunServiceWorkerAndQuit() {
+ // Run out the service worker loop by posting a new command and waiting for
+ // the response.
+ auto callback = [this](const GetTpmStatusReply& reply) {
+ Quit();
+ };
+ GetTpmStatusRequest request;
+ service_->GetTpmStatus(request, base::Bind(callback));
+ Run();
+ }
+
+ void Quit() {
+ run_loop_.Quit();
+ }
+
+ void SetupService() {
+ service_->set_local_data_store(&mock_local_data_store_);
+ service_->set_tpm_initializer(&mock_tpm_initializer_);
+ service_->set_tpm_status(&mock_tpm_status_);
+ CHECK(service_->Initialize());
+ }
+
+ NiceMock<MockLocalDataStore> mock_local_data_store_;
+ NiceMock<MockTpmInitializer> mock_tpm_initializer_;
+ NiceMock<MockTpmStatus> mock_tpm_status_;
+ std::unique_ptr<TpmManagerService> service_;
+
+ private:
+ base::MessageLoop message_loop_;
+ base::RunLoop run_loop_;
+};
+
+// Tests must call SetupService().
+class TpmManagerServiceTest_NoWaitForOwnership : public TpmManagerServiceTest {
+ public:
+ ~TpmManagerServiceTest_NoWaitForOwnership() override = default;
+ void SetUp() override {
+ service_.reset(new TpmManagerService(false /*wait_for_ownership*/));
+ }
+};
+
+TEST_F(TpmManagerServiceTest_NoWaitForOwnership, AutoInitialize) {
+ // Make sure InitializeTpm doesn't get multiple calls.
+ EXPECT_CALL(mock_tpm_initializer_, InitializeTpm()).Times(1);
+ SetupService();
+ RunServiceWorkerAndQuit();
+}
+
+TEST_F(TpmManagerServiceTest_NoWaitForOwnership, AutoInitializeNoTpm) {
+ EXPECT_CALL(mock_tpm_status_, IsTpmEnabled()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mock_tpm_initializer_, InitializeTpm()).Times(0);
+ SetupService();
+ RunServiceWorkerAndQuit();
+}
+
+TEST_F(TpmManagerServiceTest_NoWaitForOwnership, AutoInitializeFailure) {
+ EXPECT_CALL(mock_tpm_initializer_, InitializeTpm())
+ .WillRepeatedly(Return(false));
+ SetupService();
+ RunServiceWorkerAndQuit();
+}
+
+TEST_F(TpmManagerServiceTest, NoAutoInitialize) {
+ EXPECT_CALL(mock_tpm_initializer_, InitializeTpm()).Times(0);
+ RunServiceWorkerAndQuit();
+}
+
+TEST_F(TpmManagerServiceTest, GetTpmStatusSuccess) {
+ EXPECT_CALL(mock_tpm_status_, GetDictionaryAttackInfo(_, _, _, _))
+ .WillRepeatedly(Invoke([](int* counter, int* threshold, bool* lockout,
+ int* seconds_remaining) {
+ *counter = 5;
+ *threshold = 6;
+ *lockout = true;
+ *seconds_remaining = 7;
+ return true;
+ }));
+ LocalData local_data;
+ local_data.set_owner_password("test");
+ EXPECT_CALL(mock_local_data_store_, Read(_))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(local_data), Return(true)));
+
+ auto callback = [this](const GetTpmStatusReply& reply) {
+ EXPECT_EQ(STATUS_SUCCESS, reply.status());
+ EXPECT_TRUE(reply.enabled());
+ EXPECT_TRUE(reply.owned());
+ EXPECT_EQ("test", reply.local_data().owner_password());
+ EXPECT_EQ(5, reply.dictionary_attack_counter());
+ EXPECT_EQ(6, reply.dictionary_attack_threshold());
+ EXPECT_TRUE(reply.dictionary_attack_lockout_in_effect());
+ EXPECT_EQ(7, reply.dictionary_attack_lockout_seconds_remaining());
+ Quit();
+ };
+ GetTpmStatusRequest request;
+ service_->GetTpmStatus(request, base::Bind(callback));
+ Run();
+}
+
+TEST_F(TpmManagerServiceTest, GetTpmStatusLocalDataFailure) {
+ EXPECT_CALL(mock_local_data_store_, Read(_))
+ .WillRepeatedly(Return(false));
+ auto callback = [this](const GetTpmStatusReply& reply) {
+ EXPECT_EQ(STATUS_SUCCESS, reply.status());
+ EXPECT_TRUE(reply.enabled());
+ EXPECT_TRUE(reply.owned());
+ EXPECT_FALSE(reply.has_local_data());
+ EXPECT_TRUE(reply.has_dictionary_attack_counter());
+ EXPECT_TRUE(reply.has_dictionary_attack_threshold());
+ EXPECT_TRUE(reply.has_dictionary_attack_lockout_in_effect());
+ EXPECT_TRUE(reply.has_dictionary_attack_lockout_seconds_remaining());
+ Quit();
+ };
+ GetTpmStatusRequest request;
+ service_->GetTpmStatus(request, base::Bind(callback));
+ Run();
+}
+
+TEST_F(TpmManagerServiceTest, GetTpmStatusNoTpm) {
+ EXPECT_CALL(mock_tpm_status_, IsTpmEnabled()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mock_tpm_status_, GetDictionaryAttackInfo(_, _, _, _))
+ .WillRepeatedly(Return(false));
+ auto callback = [this](const GetTpmStatusReply& reply) {
+ EXPECT_EQ(STATUS_SUCCESS, reply.status());
+ EXPECT_FALSE(reply.enabled());
+ EXPECT_TRUE(reply.owned());
+ EXPECT_TRUE(reply.has_local_data());
+ EXPECT_FALSE(reply.has_dictionary_attack_counter());
+ EXPECT_FALSE(reply.has_dictionary_attack_threshold());
+ EXPECT_FALSE(reply.has_dictionary_attack_lockout_in_effect());
+ EXPECT_FALSE(reply.has_dictionary_attack_lockout_seconds_remaining());
+ Quit();
+ };
+ GetTpmStatusRequest request;
+ service_->GetTpmStatus(request, base::Bind(callback));
+ Run();
+}
+
+TEST_F(TpmManagerServiceTest, TakeOwnershipSuccess) {
+ // Make sure InitializeTpm doesn't get multiple calls.
+ EXPECT_CALL(mock_tpm_initializer_, InitializeTpm()).Times(1);
+ auto callback = [this](const TakeOwnershipReply& reply) {
+ EXPECT_EQ(STATUS_SUCCESS, reply.status());
+ Quit();
+ };
+ TakeOwnershipRequest request;
+ service_->TakeOwnership(request, base::Bind(callback));
+ Run();
+}
+
+TEST_F(TpmManagerServiceTest, TakeOwnershipFailure) {
+ EXPECT_CALL(mock_tpm_initializer_, InitializeTpm())
+ .WillRepeatedly(Return(false));
+ auto callback = [this](const TakeOwnershipReply& reply) {
+ EXPECT_EQ(STATUS_UNEXPECTED_DEVICE_ERROR, reply.status());
+ Quit();
+ };
+ TakeOwnershipRequest request;
+ service_->TakeOwnership(request, base::Bind(callback));
+ Run();
+}
+
+TEST_F(TpmManagerServiceTest, TakeOwnershipNoTpm) {
+ EXPECT_CALL(mock_tpm_status_, IsTpmEnabled()).WillRepeatedly(Return(false));
+ auto callback = [this](const TakeOwnershipReply& reply) {
+ EXPECT_EQ(STATUS_NOT_AVAILABLE, reply.status());
+ Quit();
+ };
+ TakeOwnershipRequest request;
+ service_->TakeOwnership(request, base::Bind(callback));
+ Run();
+}
+
+TEST_F(TpmManagerServiceTest_NoWaitForOwnership,
+ TakeOwnershipAfterAutoInitialize) {
+ EXPECT_CALL(mock_tpm_initializer_, InitializeTpm()).Times(AtLeast(2));
+ SetupService();
+ auto callback = [this](const TakeOwnershipReply& reply) {
+ EXPECT_EQ(STATUS_SUCCESS, reply.status());
+ Quit();
+ };
+ TakeOwnershipRequest request;
+ service_->TakeOwnership(request, base::Bind(callback));
+ Run();
+}
+
+} // namespace tpm_manager
diff --git a/server/tpm_status.h b/server/tpm_status.h
new file mode 100644
index 0000000..a373f01
--- /dev/null
+++ b/server/tpm_status.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TPM_MANAGER_SERVER_TPM_STATUS_H_
+#define TPM_MANAGER_SERVER_TPM_STATUS_H_
+
+namespace tpm_manager {
+
+// TpmStatus is an interface class that reports status information for some kind
+// of TPM device.
+class TpmStatus {
+ public:
+ TpmStatus() = default;
+ virtual ~TpmStatus() = default;
+
+ // Returns true iff the TPM is enabled.
+ virtual bool IsTpmEnabled() = 0;
+ // Returns true iff the TPM has been owned.
+ virtual bool IsTpmOwned() = 0;
+ // Reports the current state of the TPM dictionary attack logic.
+ virtual bool GetDictionaryAttackInfo(int* counter,
+ int* threshold,
+ bool* lockout,
+ int* seconds_remaining) = 0;
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_TPM_STATUS_H_
diff --git a/tpm_manager.gyp b/tpm_manager.gyp
index 40aed81..53d51df 100644
--- a/tpm_manager.gyp
+++ b/tpm_manager.gyp
@@ -24,6 +24,7 @@
},
'sources': [
'<(proto_in_dir)/dbus_interface.proto',
+ '<(proto_in_dir)/local_data.proto',
],
'includes': ['../common-mk/protoc.gypi'],
},
@@ -92,10 +93,17 @@
],
},
'sources': [
+ 'client/dbus_proxy_test.cc',
+ 'common/mock_tpm_manager_interface.cc',
+ 'server/dbus_service_test.cc',
+ 'server/mock_local_data_store.cc',
+ 'server/mock_tpm_initializer.cc',
+ 'server/mock_tpm_status.cc',
+ 'server/tpm_manager_service_test.cc',
'tpm_manager_testrunner.cc',
],
'dependencies': [
- 'client_library',
+ 'libtpm_manager',
'proto_library',
'server_library',
],