summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Yi <byi@google.com>2015-09-09 16:59:53 -0700
committerBill Yi <byi@google.com>2015-09-09 16:59:53 -0700
commit22782fa6dfd49381b701ebaaada6612b62719f34 (patch)
tree6b49512635ddd192c10077add62efcf6f5dd9cd7
parentd9d0a2a68a7eb79cb0ab212fd5fe77c193728081 (diff)
parent50e52ff6bcc478118a1cdec27903a5af5061d77b (diff)
downloadtpm_manager-22782fa6dfd49381b701ebaaada6612b62719f34.tar.gz
Merge branch 'rewrite-tpm_manager' into merge-tpm_manager
-rw-r--r--client/dbus_proxy.cc73
-rw-r--r--client/dbus_proxy.h49
-rw-r--r--client/dbus_proxy_test.cc108
-rw-r--r--client/main.cc136
-rw-r--r--common/dbus_interface.h20
-rw-r--r--common/dbus_interface.proto44
-rw-r--r--common/export.h12
-rw-r--r--common/local_data.proto20
-rw-r--r--common/mock_tpm_manager_interface.cc12
-rw-r--r--common/mock_tpm_manager_interface.h30
-rw-r--r--common/print_dbus_interface_proto.cc146
-rw-r--r--common/print_dbus_interface_proto.h34
-rw-r--r--common/print_local_data_proto.cc49
-rw-r--r--common/print_local_data_proto.h22
-rw-r--r--common/tpm_manager_interface.h38
-rw-r--r--server/dbus_service.cc70
-rw-r--r--server/dbus_service.h59
-rw-r--r--server/dbus_service_test.cc136
-rw-r--r--server/local_data_store.h30
-rw-r--r--server/local_data_store_impl.cc86
-rw-r--r--server/local_data_store_impl.h33
-rw-r--r--server/main.cc93
-rw-r--r--server/mock_local_data_store.cc23
-rw-r--r--server/mock_local_data_store.h28
-rw-r--r--server/mock_tpm_initializer.cc16
-rw-r--r--server/mock_tpm_initializer.h24
-rw-r--r--server/mock_tpm_status.cc32
-rw-r--r--server/mock_tpm_status.h30
-rw-r--r--server/openssl_crypto_util.cc26
-rw-r--r--server/openssl_crypto_util.h36
-rw-r--r--server/org.chromium.TpmManager.conf15
-rw-r--r--server/tpm2_initializer_impl.cc121
-rw-r--r--server/tpm2_initializer_impl.h66
-rw-r--r--server/tpm2_initializer_test.cc138
-rw-r--r--server/tpm2_status_impl.cc75
-rw-r--r--server/tpm2_status_impl.h50
-rw-r--r--server/tpm2_status_test.cc147
-rw-r--r--server/tpm_connection.cc96
-rw-r--r--server/tpm_connection.h43
-rw-r--r--server/tpm_initializer.h25
-rw-r--r--server/tpm_initializer_impl.cc246
-rw-r--r--server/tpm_initializer_impl.h80
-rw-r--r--server/tpm_manager-seccomp-amd64.policy63
-rw-r--r--server/tpm_manager-seccomp-arm.policy0
-rw-r--r--server/tpm_manager-seccomp-x86.policy0
-rw-r--r--server/tpm_manager_service.cc114
-rw-r--r--server/tpm_manager_service.h103
-rw-r--r--server/tpm_manager_service_test.cc226
-rw-r--r--server/tpm_managerd.conf16
-rw-r--r--server/tpm_status.h30
-rw-r--r--server/tpm_status_impl.cc104
-rw-r--r--server/tpm_status_impl.h56
-rw-r--r--server/tpm_util.h16
-rw-r--r--tpm_manager.gyp163
-rw-r--r--tpm_manager_testrunner.cc19
55 files changed, 3527 insertions, 0 deletions
diff --git a/client/dbus_proxy.cc b/client/dbus_proxy.cc
new file mode 100644
index 0000000..b5429f2
--- /dev/null
+++ b/client/dbus_proxy.cc
@@ -0,0 +1,73 @@
+// 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/client/dbus_proxy.h"
+
+#include <chromeos/bind_lambda.h>
+#include <chromeos/dbus/dbus_method_invoker.h>
+
+#include "tpm_manager/common/dbus_interface.h"
+
+namespace {
+
+// Use a two minute timeout because TPM operations can take a long time.
+const int kDBusTimeoutMS = 2 * 60 * 1000;
+
+} // namespace
+
+namespace tpm_manager {
+
+DBusProxy::DBusProxy() {}
+
+DBusProxy::~DBusProxy() {
+ if (bus_) {
+ bus_->ShutdownAndBlock();
+ }
+}
+
+bool DBusProxy::Initialize() {
+ dbus::Bus::Options options;
+ options.bus_type = dbus::Bus::SYSTEM;
+ bus_ = new dbus::Bus(options);
+ object_proxy_ = bus_->GetObjectProxy(
+ tpm_manager::kTpmManagerServiceName,
+ dbus::ObjectPath(tpm_manager::kTpmManagerServicePath));
+ return (object_proxy_ != nullptr);
+}
+
+void DBusProxy::GetTpmStatus(const GetTpmStatusRequest& request,
+ const GetTpmStatusCallback& callback) {
+ auto on_error = [callback](chromeos::Error* error) {
+ GetTpmStatusReply reply;
+ reply.set_status(STATUS_NOT_AVAILABLE);
+ callback.Run(reply);
+ };
+ chromeos::dbus_utils::CallMethodWithTimeout(
+ kDBusTimeoutMS,
+ object_proxy_,
+ tpm_manager::kTpmManagerInterface,
+ tpm_manager::kGetTpmStatus,
+ callback,
+ base::Bind(on_error),
+ 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
new file mode 100644
index 0000000..b99b735
--- /dev/null
+++ b/client/dbus_proxy.h
@@ -0,0 +1,49 @@
+// 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_CLIENT_DBUS_PROXY_H_
+#define TPM_MANAGER_CLIENT_DBUS_PROXY_H_
+
+#include "tpm_manager/common/tpm_manager_interface.h"
+
+#include <string>
+
+#include <base/memory/ref_counted.h>
+#include <dbus/bus.h>
+#include <dbus/object_proxy.h>
+
+#include "tpm_manager/common/export.h"
+
+namespace tpm_manager {
+
+// An implementation of TpmManagerInterface that forwards requests to
+// tpm_managerd over D-Bus.
+// Usage:
+// std::unique_ptr<TpmManagerInterface> tpm_manager = new DBusProxy();
+// tpm_manager->GetTpmStatus(...);
+class TPM_MANAGER_EXPORT DBusProxy : public TpmManagerInterface {
+ public:
+ DBusProxy();
+ virtual ~DBusProxy();
+
+ // TpmManagerInterface methods.
+ 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;
+ }
+
+ private:
+ scoped_refptr<dbus::Bus> bus_;
+ dbus::ObjectProxy* object_proxy_;
+ DISALLOW_COPY_AND_ASSIGN(DBusProxy);
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_CLIENT_DBUS_PROXY_H_
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/client/main.cc b/client/main.cc
new file mode 100644
index 0000000..376e0aa
--- /dev/null
+++ b/client/main.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 <stdio.h>
+#include <sysexits.h>
+
+#include <memory>
+#include <string>
+
+#include <base/command_line.h>
+#include <base/logging.h>
+#include <base/message_loop/message_loop.h>
+#include <chromeos/bind_lambda.h>
+#include <chromeos/daemons/daemon.h>
+#include <chromeos/syslog_logging.h>
+
+#include "tpm_manager/client/dbus_proxy.h"
+#include "tpm_manager/common/dbus_interface.pb.h"
+#include "tpm_manager/common/print_dbus_interface_proto.h"
+
+namespace tpm_manager {
+
+const char kGetTpmStatusCommand[] = "status";
+const char kTakeOwnershipCommand[] = "take_ownership";
+const char kUsage[] = R"(
+Usage: tpm_manager_client <command> [<args>]
+Commands:
+ status
+ Prints the current status of the Tpm.
+ take_ownership
+ Takes ownership of the Tpm with a random password.
+)";
+
+using ClientLoopBase = chromeos::Daemon;
+class ClientLoop : public ClientLoopBase {
+ public:
+ ClientLoop() = default;
+ ~ClientLoop() override = default;
+
+ protected:
+ int OnInit() override {
+ int exit_code = ClientLoopBase::OnInit();
+ if (exit_code != EX_OK) {
+ LOG(ERROR) << "Error initializing tpm_manager_client.";
+ return exit_code;
+ }
+ tpm_manager_.reset(new tpm_manager::DBusProxy());
+ if (!tpm_manager_->Initialize()) {
+ LOG(ERROR) << "Error initializing dbus proxy to tpm_managerd.";
+ return EX_UNAVAILABLE;
+ }
+ exit_code = ScheduleCommand();
+ if (exit_code == EX_USAGE) {
+ printf("%s", kUsage);
+ }
+ return exit_code;
+ }
+
+ void OnShutdown(int* exit_code) override {
+ tpm_manager_.reset();
+ ClientLoopBase::OnShutdown(exit_code);
+ }
+
+ private:
+ // Posts tasks on to the message loop based on command line flags.
+ int ScheduleCommand() {
+ base::Closure task;
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch("help") || command_line->HasSwitch("h")) {
+ return EX_USAGE;
+ } else if (command_line->HasSwitch(kGetTpmStatusCommand)) {
+ task = base::Bind(&ClientLoop::HandleGetTpmStatus,
+ weak_factory_.GetWeakPtr());
+ } else if (command_line->HasSwitch(kTakeOwnershipCommand)) {
+ task = base::Bind(&ClientLoop::HandleTakeOwnership,
+ weak_factory_.GetWeakPtr());
+ } else {
+ // Command line arguments did not match any valid commands.
+ LOG(ERROR) << "No Valid Command selected.";
+ return EX_USAGE;
+ }
+ base::MessageLoop::current()->PostTask(FROM_HERE, task);
+ return EX_OK;
+ }
+
+ void PrintGetTpmStatusReply(const GetTpmStatusReply& reply) {
+ if (reply.has_status() && reply.status() == STATUS_NOT_AVAILABLE) {
+ LOG(INFO) << "tpm_managerd is not available.";
+ } else {
+ LOG(INFO) << "TpmStatusReply: " << GetProtoDebugString(reply);
+ }
+ Quit();
+ }
+
+ void HandleGetTpmStatus() {
+ GetTpmStatusRequest request;
+ tpm_manager_->GetTpmStatus(
+ request,
+ base::Bind(&ClientLoop::PrintGetTpmStatusReply,
+ weak_factory_.GetWeakPtr()));
+ }
+
+ void PrintTakeOwnershipReply(const TakeOwnershipReply& reply) {
+ if (reply.has_status() && reply.status() == STATUS_NOT_AVAILABLE) {
+ LOG(INFO) << "tpm_managerd is not available.";
+ } else {
+ LOG(INFO) << "TakeOwnershipReply: " << GetProtoDebugString(reply);
+ }
+ Quit();
+ }
+
+ void HandleTakeOwnership() {
+ TakeOwnershipRequest request;
+ tpm_manager_->TakeOwnership(request,
+ base::Bind(&ClientLoop::PrintTakeOwnershipReply,
+ weak_factory_.GetWeakPtr()));
+ }
+
+ // Pointer to a DBus proxy to tpm_managerd.
+ std::unique_ptr<tpm_manager::TpmManagerInterface> tpm_manager_;
+
+ // Declared last so that weak pointers will be destroyed first.
+ base::WeakPtrFactory<ClientLoop> weak_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(ClientLoop);
+};
+
+} // namespace tpm_manager
+
+int main(int argc, char* argv[]) {
+ base::CommandLine::Init(argc, argv);
+ chromeos::InitLog(chromeos::kLogToSyslog | chromeos::kLogToStderr);
+ tpm_manager::ClientLoop loop;
+ return loop.Run();
+}
diff --git a/common/dbus_interface.h b/common/dbus_interface.h
new file mode 100644
index 0000000..d0f8981
--- /dev/null
+++ b/common/dbus_interface.h
@@ -0,0 +1,20 @@
+// 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_DBUS_INTERFACE_H_
+#define TPM_MANAGER_COMMON_DBUS_INTERFACE_H_
+
+namespace tpm_manager {
+
+constexpr char kTpmManagerInterface[] = "org.chromium.TpmManager";
+constexpr char kTpmManagerServicePath[] = "/org/chromium/TpmManager";
+constexpr char kTpmManagerServiceName[] = "org.chromium.TpmManager";
+
+// Methods exported by tpm_manager.
+constexpr char kGetTpmStatus[] = "GetTpmStatus";
+constexpr char kTakeOwnership[] = "TakeOwnership";
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_COMMON_DBUS_INTERFACE_H_
diff --git a/common/dbus_interface.proto b/common/dbus_interface.proto
new file mode 100644
index 0000000..216bda5
--- /dev/null
+++ b/common/dbus_interface.proto
@@ -0,0 +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_UNEXPECTED_DEVICE_ERROR = 1;
+ STATUS_NOT_AVAILABLE = 2;
+}
+
+// Input for the GetTpmStatus method.
+message GetTpmStatusRequest {
+}
+
+// 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;
+ // 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 = 5;
+ // The current dictionary attack counter threshold.
+ optional int32 dictionary_attack_threshold = 6;
+ // Whether the TPM is in some form of dictionary attack lockout.
+ optional bool dictionary_attack_lockout_in_effect = 7;
+ // The number of seconds remaining in the lockout.
+ 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/export.h b/common/export.h
new file mode 100644
index 0000000..6973236
--- /dev/null
+++ b/common/export.h
@@ -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.
+
+#ifndef TPM_MANAGER_COMMON_EXPORT_H_
+#define TPM_MANAGER_COMMON_EXPORT_H_
+
+// Use this for any class or function that needs to be exported from
+// libtpm_manager. E.g. TPM_MANAGER_EXPORT void foo();
+#define TPM_MANAGER_EXPORT __attribute__((__visibility__("default")))
+
+#endif // TPM_MANAGER_COMMON_EXPORT_H_
diff --git a/common/local_data.proto b/common/local_data.proto
new file mode 100644
index 0000000..509f027
--- /dev/null
+++ b/common/local_data.proto
@@ -0,0 +1,20 @@
+// 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.
+
+option optimize_for = LITE_RUNTIME;
+package tpm_manager;
+
+// The format of persistent local TPM management data stored on the device.
+// When Tpm ownership is taken, this protobuf is populated with the passwords
+// used to take ownership, and with a list of clients who have a dependency on
+// the owner password (like Attestation, InstallAttributes and BootLockbox).
+// when all the clients have the owner password injected, this protobuf is
+// cleared of all passwords.
+message LocalData {
+ optional bool owned_by_this_install = 1;
+ optional bytes owner_password = 2;
+ repeated string owner_dependency = 3;
+ optional bytes endorsement_password = 4;
+ optional bytes lockout_password = 5;
+}
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/print_dbus_interface_proto.cc b/common/print_dbus_interface_proto.cc
new file mode 100644
index 0000000..0fb1fd1
--- /dev/null
+++ b/common/print_dbus_interface_proto.cc
@@ -0,0 +1,146 @@
+// 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.
+
+// THIS CODE IS GENERATED.
+
+#include "tpm_manager/common/print_dbus_interface_proto.h"
+
+#include <string>
+
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/stringprintf.h>
+
+#include "tpm_manager/common/print_local_data_proto.h"
+
+namespace tpm_manager {
+
+std::string GetProtoDebugString(TpmManagerStatus value) {
+ return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(TpmManagerStatus value,
+ int indent_size) {
+ if (value == STATUS_SUCCESS) {
+ return "STATUS_SUCCESS";
+ }
+ if (value == STATUS_UNEXPECTED_DEVICE_ERROR) {
+ return "STATUS_UNEXPECTED_DEVICE_ERROR";
+ }
+ if (value == STATUS_NOT_AVAILABLE) {
+ return "STATUS_NOT_AVAILABLE";
+ }
+ return "<unknown>";
+}
+
+std::string GetProtoDebugString(const GetTpmStatusRequest& value) {
+ return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const GetTpmStatusRequest& value,
+ int indent_size) {
+ std::string indent(indent_size, ' ');
+ std::string output =
+ base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+ output += indent + "}\n";
+ return output;
+}
+
+std::string GetProtoDebugString(const GetTpmStatusReply& value) {
+ return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const GetTpmStatusReply& value,
+ int indent_size) {
+ std::string indent(indent_size, ' ');
+ std::string output =
+ base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+ if (value.has_status()) {
+ output += indent + " status: ";
+ base::StringAppendF(
+ &output, "%s",
+ GetProtoDebugStringWithIndent(value.status(), indent_size + 2).c_str());
+ output += "\n";
+ }
+ if (value.has_enabled()) {
+ output += indent + " enabled: ";
+ base::StringAppendF(&output, "%s", value.enabled() ? "true" : "false");
+ output += "\n";
+ }
+ if (value.has_owned()) {
+ output += indent + " owned: ";
+ base::StringAppendF(&output, "%s", value.owned() ? "true" : "false");
+ output += "\n";
+ }
+ if (value.has_local_data()) {
+ output += indent + " local_data: ";
+ base::StringAppendF(&output, "%s", GetProtoDebugStringWithIndent(
+ value.local_data(), indent_size + 2)
+ .c_str());
+ output += "\n";
+ }
+ if (value.has_dictionary_attack_counter()) {
+ output += indent + " dictionary_attack_counter: ";
+ base::StringAppendF(&output, "%d", value.dictionary_attack_counter());
+ output += "\n";
+ }
+ if (value.has_dictionary_attack_threshold()) {
+ output += indent + " dictionary_attack_threshold: ";
+ base::StringAppendF(&output, "%d", value.dictionary_attack_threshold());
+ output += "\n";
+ }
+ if (value.has_dictionary_attack_lockout_in_effect()) {
+ output += indent + " dictionary_attack_lockout_in_effect: ";
+ base::StringAppendF(
+ &output, "%s",
+ value.dictionary_attack_lockout_in_effect() ? "true" : "false");
+ output += "\n";
+ }
+ if (value.has_dictionary_attack_lockout_seconds_remaining()) {
+ output += indent + " dictionary_attack_lockout_seconds_remaining: ";
+ base::StringAppendF(&output, "%d",
+ value.dictionary_attack_lockout_seconds_remaining());
+ output += "\n";
+ }
+ output += indent + "}\n";
+ return output;
+}
+
+std::string GetProtoDebugString(const TakeOwnershipRequest& value) {
+ return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const TakeOwnershipRequest& value,
+ int indent_size) {
+ std::string indent(indent_size, ' ');
+ std::string output =
+ base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+ output += indent + "}\n";
+ return output;
+}
+
+std::string GetProtoDebugString(const TakeOwnershipReply& value) {
+ return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const TakeOwnershipReply& value,
+ int indent_size) {
+ std::string indent(indent_size, ' ');
+ std::string output =
+ base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+ if (value.has_status()) {
+ output += indent + " status: ";
+ base::StringAppendF(
+ &output, "%s",
+ GetProtoDebugStringWithIndent(value.status(), indent_size + 2).c_str());
+ output += "\n";
+ }
+ output += indent + "}\n";
+ return output;
+}
+
+} // namespace tpm_manager
diff --git a/common/print_dbus_interface_proto.h b/common/print_dbus_interface_proto.h
new file mode 100644
index 0000000..d0e01d2
--- /dev/null
+++ b/common/print_dbus_interface_proto.h
@@ -0,0 +1,34 @@
+// 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.
+
+// THIS CODE IS GENERATED.
+
+#ifndef TPM_MANAGER_COMMON_PRINT_DBUS_INTERFACE_PROTO_H_
+#define TPM_MANAGER_COMMON_PRINT_DBUS_INTERFACE_PROTO_H_
+
+#include <string>
+
+#include "tpm_manager/common/dbus_interface.pb.h"
+
+namespace tpm_manager {
+
+std::string GetProtoDebugStringWithIndent(TpmManagerStatus value,
+ int indent_size);
+std::string GetProtoDebugString(TpmManagerStatus value);
+std::string GetProtoDebugStringWithIndent(const GetTpmStatusRequest& value,
+ int indent_size);
+std::string GetProtoDebugString(const GetTpmStatusRequest& value);
+std::string GetProtoDebugStringWithIndent(const GetTpmStatusReply& value,
+ int indent_size);
+std::string GetProtoDebugString(const GetTpmStatusReply& value);
+std::string GetProtoDebugStringWithIndent(const TakeOwnershipRequest& value,
+ int indent_size);
+std::string GetProtoDebugString(const TakeOwnershipRequest& value);
+std::string GetProtoDebugStringWithIndent(const TakeOwnershipReply& value,
+ int indent_size);
+std::string GetProtoDebugString(const TakeOwnershipReply& value);
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_COMMON_PRINT_DBUS_INTERFACE_PROTO_H_
diff --git a/common/print_local_data_proto.cc b/common/print_local_data_proto.cc
new file mode 100644
index 0000000..c25dcaf
--- /dev/null
+++ b/common/print_local_data_proto.cc
@@ -0,0 +1,49 @@
+// 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.
+
+// THIS CODE IS GENERATED.
+
+#include "tpm_manager/common/print_local_data_proto.h"
+
+#include <string>
+
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/stringprintf.h>
+
+namespace tpm_manager {
+
+std::string GetProtoDebugString(const LocalData& value) {
+ return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const LocalData& value,
+ int indent_size) {
+ std::string indent(indent_size, ' ');
+ std::string output =
+ base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+ if (value.has_owned_by_this_install()) {
+ output += indent + " owned_by_this_install: ";
+ base::StringAppendF(&output, "%s",
+ value.owned_by_this_install() ? "true" : "false");
+ output += "\n";
+ }
+ if (value.has_owner_password()) {
+ output += indent + " owner_password: ";
+ base::StringAppendF(&output, "%s",
+ base::HexEncode(value.owner_password().data(),
+ value.owner_password().size())
+ .c_str());
+ output += "\n";
+ }
+ output += indent + " owner_dependency: {";
+ for (int i = 0; i < value.owner_dependency_size(); ++i) {
+ base::StringAppendF(&output, "%s", value.owner_dependency(i).c_str());
+ }
+ output += "}\n";
+ output += indent + "}\n";
+ return output;
+}
+
+} // namespace tpm_manager
diff --git a/common/print_local_data_proto.h b/common/print_local_data_proto.h
new file mode 100644
index 0000000..2114a32
--- /dev/null
+++ b/common/print_local_data_proto.h
@@ -0,0 +1,22 @@
+// 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.
+
+// THIS CODE IS GENERATED.
+
+#ifndef TPM_MANAGER_COMMON_PRINT_LOCAL_DATA_PROTO_H_
+#define TPM_MANAGER_COMMON_PRINT_LOCAL_DATA_PROTO_H_
+
+#include <string>
+
+#include "tpm_manager/common/local_data.pb.h"
+
+namespace tpm_manager {
+
+std::string GetProtoDebugStringWithIndent(const LocalData& value,
+ int indent_size);
+std::string GetProtoDebugString(const LocalData& value);
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_COMMON_PRINT_LOCAL_DATA_PROTO_H_
diff --git a/common/tpm_manager_interface.h b/common/tpm_manager_interface.h
new file mode 100644
index 0000000..bee631f
--- /dev/null
+++ b/common/tpm_manager_interface.h
@@ -0,0 +1,38 @@
+// 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_TPM_MANAGER_INTERFACE_H_
+#define TPM_MANAGER_COMMON_TPM_MANAGER_INTERFACE_H_
+
+#include <base/callback.h>
+
+#include "tpm_manager/common/dbus_interface.pb.h"
+#include "tpm_manager/common/export.h"
+
+namespace tpm_manager {
+
+// This is the main TpmManager interface that is implemented by the proxies
+// and services.
+class TPM_MANAGER_EXPORT TpmManagerInterface {
+ public:
+ virtual ~TpmManagerInterface() = default;
+
+ // Performs initialization tasks. This method must be called before calling
+ // any other method on this interface.
+ virtual bool Initialize() = 0;
+
+ // Processes a GetTpmStatusRequest and responds with a GetTpmStatusReply.
+ 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
+
+#endif // TPM_MANAGER_COMMON_TPM_MANAGER_INTERFACE_H_
diff --git a/server/dbus_service.cc b/server/dbus_service.cc
new file mode 100644
index 0000000..e326f0c
--- /dev/null
+++ b/server/dbus_service.cc
@@ -0,0 +1,70 @@
+// 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/dbus_service.h"
+
+#include <memory>
+#include <string>
+
+#include <chromeos/bind_lambda.h>
+#include <dbus/bus.h>
+#include <dbus/object_path.h>
+
+#include "tpm_manager/common/dbus_interface.h"
+
+using chromeos::dbus_utils::DBusMethodResponse;
+
+namespace tpm_manager {
+
+DBusService::DBusService(const scoped_refptr<dbus::Bus>& bus,
+ TpmManagerInterface* service)
+ : dbus_object_(nullptr, bus, dbus::ObjectPath(kTpmManagerServicePath)),
+ service_(service) {}
+
+void DBusService::Register(const CompletionAction& callback) {
+ chromeos::dbus_utils::DBusInterface* dbus_interface =
+ dbus_object_.AddOrGetInterface(kTpmManagerInterface);
+
+ dbus_interface->AddMethodHandler(kGetTpmStatus, base::Unretained(this),
+ &DBusService::HandleGetTpmStatus);
+ dbus_interface->AddMethodHandler(kTakeOwnership, base::Unretained(this),
+ &DBusService::HandleTakeOwnership);
+ dbus_object_.RegisterAsync(callback);
+}
+
+void DBusService::HandleGetTpmStatus(
+ std::unique_ptr<DBusMethodResponse<const GetTpmStatusReply&>> response,
+ const GetTpmStatusRequest& request) {
+ // Convert |response| to a shared_ptr so |service_| can safely copy the
+ // callback.
+ using SharedResponsePointer = std::shared_ptr<
+ DBusMethodResponse<const GetTpmStatusReply&>>;
+ // A callback that sends off the reply protobuf.
+ auto callback = [](const SharedResponsePointer& response,
+ const GetTpmStatusReply& reply) {
+ response->Return(reply);
+ };
+ service_->GetTpmStatus(
+ request,
+ 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
new file mode 100644
index 0000000..8286ced
--- /dev/null
+++ b/server/dbus_service.h
@@ -0,0 +1,59 @@
+// 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_DBUS_SERVICE_H_
+#define TPM_MANAGER_SERVER_DBUS_SERVICE_H_
+
+#include <memory>
+
+#include <chromeos/dbus/dbus_method_response.h>
+#include <chromeos/dbus/dbus_object.h>
+#include <dbus/bus.h>
+
+#include "tpm_manager/common/tpm_manager_interface.h"
+
+namespace tpm_manager {
+
+using CompletionAction =
+ chromeos::dbus_utils::AsyncEventSequencer::CompletionAction;
+
+// Handles D-Bus communtion with the TpmManager daemon.
+class DBusService {
+ public:
+ // Does not take ownership of |service|. |service| must remain valid for the
+ // lifetime of this instance.
+ DBusService(const scoped_refptr<dbus::Bus>& bus,
+ TpmManagerInterface* service);
+ virtual ~DBusService() = default;
+
+ // Connects to D-Bus system bus and exports TpmManager methods.
+ void Register(const CompletionAction& callback);
+
+ void set_service(TpmManagerInterface* service) {
+ service_ = service;
+ }
+
+ 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);
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_DBUS_SERVICE_H_
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/local_data_store_impl.cc b/server/local_data_store_impl.cc
new file mode 100644
index 0000000..a3da4d7
--- /dev/null
+++ b/server/local_data_store_impl.cc
@@ -0,0 +1,86 @@
+// 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/local_data_store_impl.h"
+
+#include <fcntl.h>
+
+#include <string>
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/files/important_file_writer.h>
+
+using base::FilePath;
+
+namespace tpm_manager {
+
+const char kTpmLocalDataFile[] =
+ "/mnt/stateful_partition/unencrypted/preserve/local_tpm_data";
+const mode_t kLocalDataPermissions = 0600;
+
+bool LocalDataStoreImpl::Read(LocalData* data) {
+ CHECK(data);
+ const int kMask = base::FILE_PERMISSION_OTHERS_MASK;
+ FilePath path(kTpmLocalDataFile);
+ int permissions = 0;
+ if (base::GetPosixFilePermissions(path, &permissions) &&
+ (permissions & kMask) != 0) {
+ base::SetPosixFilePermissions(path, permissions & ~kMask);
+ }
+ std::string file_data;
+ if (!ReadFileToString(path, &file_data)) {
+ LOG(ERROR) << "Error reading data store file.";
+ return false;
+ }
+ if (!data->ParseFromString(file_data)) {
+ LOG(ERROR) << "Error parsing file data into protobuf.";
+ return false;
+ }
+ return true;
+}
+
+bool LocalDataStoreImpl::Write(const LocalData& data) {
+ std::string file_data;
+ if (!data.SerializeToString(&file_data)) {
+ LOG(ERROR) << "Error serializing file to string.";
+ return false;
+ }
+ FilePath path(kTpmLocalDataFile);
+ if (!base::CreateDirectory(path.DirName())) {
+ LOG(ERROR) << "Cannot create directory: " << path.DirName().value();
+ return false;
+ }
+ if (!base::ImportantFileWriter::WriteFileAtomically(path, file_data)) {
+ LOG(ERROR) << "Failed to write file: " << path.value();
+ return false;
+ }
+ if (!base::SetPosixFilePermissions(path, kLocalDataPermissions)) {
+ LOG(ERROR) << "Failed to set permissions for file: " << path.value();
+ return false;
+ }
+ // Sync the parent directory.
+ std::string dir_name = path.DirName().value();
+ int dir_fd = HANDLE_EINTR(open(dir_name.c_str(), O_RDONLY|O_DIRECTORY));
+ if (dir_fd < 0) {
+ PLOG(WARNING) << "Could not open " << dir_name << " for syncing";
+ return false;
+ }
+ // POSIX specifies EINTR as a possible return value of fsync().
+ int result = HANDLE_EINTR(fsync(dir_fd));
+ if (result < 0) {
+ PLOG(WARNING) << "Failed to sync " << dir_name;
+ close(dir_fd);
+ return false;
+ }
+ // close() may not be retried on error.
+ result = IGNORE_EINTR(close(dir_fd));
+ if (result < 0) {
+ PLOG(WARNING) << "Failed to close after sync " << dir_name;
+ return false;
+ }
+ return true;
+}
+
+} // namespace tpm_manager
diff --git a/server/local_data_store_impl.h b/server/local_data_store_impl.h
new file mode 100644
index 0000000..cb2d897
--- /dev/null
+++ b/server/local_data_store_impl.h
@@ -0,0 +1,33 @@
+// 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_IMPL_H_
+#define TPM_MANAGER_SERVER_LOCAL_DATA_STORE_IMPL_H_
+
+#include "tpm_manager/server/local_data_store.h"
+
+#include <string>
+
+#include <base/macros.h>
+
+namespace tpm_manager {
+
+class LocalDataStoreImpl : public LocalDataStore {
+ public:
+ LocalDataStoreImpl() = default;
+ ~LocalDataStoreImpl() override = default;
+
+ // LocalDataStore methods.
+ bool Read(LocalData* data) override;
+ bool Write(const LocalData& data) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LocalDataStoreImpl);
+};
+
+
+} // namespace tpm_manager
+
+
+#endif // TPM_MANAGER_SERVER_LOCAL_DATA_STORE_IMPL_H_
diff --git a/server/main.cc b/server/main.cc
new file mode 100644
index 0000000..f7dcc45
--- /dev/null
+++ b/server/main.cc
@@ -0,0 +1,93 @@
+// 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 <sysexits.h>
+#include <string>
+
+#include <base/command_line.h>
+#include <chromeos/daemons/dbus_daemon.h>
+#include <chromeos/dbus/async_event_sequencer.h>
+#include <chromeos/minijail/minijail.h>
+#include <chromeos/syslog_logging.h>
+#include <chromeos/userdb_utils.h>
+
+#include "tpm_manager/common/dbus_interface.h"
+#include "tpm_manager/server/dbus_service.h"
+#include "tpm_manager/server/local_data_store_impl.h"
+#include "tpm_manager/server/tpm_manager_service.h"
+
+#if USE_TPM2
+#include "tpm_manager/server/tpm2_initializer_impl.h"
+#include "tpm_manager/server/tpm2_status_impl.h"
+#else
+#include "tpm_manager/server/tpm_initializer_impl.h"
+#include "tpm_manager/server/tpm_status_impl.h"
+#endif
+
+using chromeos::dbus_utils::AsyncEventSequencer;
+
+namespace {
+
+const char kWaitForOwnershipTriggerSwitch[] = "wait_for_ownership_trigger";
+
+class TpmManagerDaemon : public chromeos::DBusServiceDaemon {
+ public:
+ TpmManagerDaemon()
+ : chromeos::DBusServiceDaemon(tpm_manager::kTpmManagerServiceName) {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ local_data_store_.reset(new tpm_manager::LocalDataStoreImpl());
+#if USE_TPM2
+ tpm_status_.reset(new tpm_manager::Tpm2StatusImpl);
+ tpm_initializer_.reset(new tpm_manager::Tpm2InitializerImpl(
+ local_data_store_.get(),
+ tpm_status_.get()));
+#else
+ tpm_status_.reset(new tpm_manager::TpmStatusImpl);
+ tpm_initializer_.reset(new tpm_manager::TpmInitializerImpl(
+ local_data_store_.get(),
+ tpm_status_.get()));
+#endif
+ tpm_manager_service_.reset(new tpm_manager::TpmManagerService(
+ command_line->HasSwitch(kWaitForOwnershipTriggerSwitch),
+ local_data_store_.get(),
+ tpm_status_.get(),
+ tpm_initializer_.get()));
+ }
+
+ protected:
+ int OnInit() override {
+ int result = chromeos::DBusServiceDaemon::OnInit();
+ if (result != EX_OK) {
+ LOG(ERROR) << "Error starting tpm_manager dbus daemon.";
+ return result;
+ }
+ CHECK(tpm_manager_service_->Initialize());
+ return EX_OK;
+ }
+
+ void RegisterDBusObjectsAsync(AsyncEventSequencer* sequencer) override {
+ dbus_service_.reset(new tpm_manager::DBusService(
+ bus_, tpm_manager_service_.get()));
+ dbus_service_->Register(sequencer->GetHandler("Register() failed.", true));
+ }
+
+ private:
+ std::unique_ptr<tpm_manager::LocalDataStore> local_data_store_;
+ std::unique_ptr<tpm_manager::TpmStatus> tpm_status_;
+ std::unique_ptr<tpm_manager::TpmInitializer> tpm_initializer_;
+ std::unique_ptr<tpm_manager::TpmManagerInterface> tpm_manager_service_;
+ std::unique_ptr<tpm_manager::DBusService> dbus_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(TpmManagerDaemon);
+};
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ base::CommandLine::Init(argc, argv);
+ chromeos::InitLog(chromeos::kLogToSyslog | chromeos::kLogToStderr);
+ TpmManagerDaemon daemon;
+ LOG(INFO) << "TpmManager Daemon Started.";
+ 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/openssl_crypto_util.cc b/server/openssl_crypto_util.cc
new file mode 100644
index 0000000..0edaf05
--- /dev/null
+++ b/server/openssl_crypto_util.cc
@@ -0,0 +1,26 @@
+// 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/openssl_crypto_util.h"
+
+#include <base/logging.h>
+#include <base/stl_util.h>
+#include <openssl/rand.h>
+
+namespace tpm_manager {
+
+bool OpensslCryptoUtil::GetRandomBytes(size_t num_bytes,
+ std::string* random_data) {
+ random_data->resize(num_bytes);
+ unsigned char* random_buffer =
+ reinterpret_cast<unsigned char*>(string_as_array(random_data));
+ if (RAND_bytes(random_buffer, num_bytes) != 1) {
+ LOG(ERROR) << "Error getting random bytes using Openssl.";
+ random_data->clear();
+ return false;
+ }
+ return true;
+}
+
+} // namespace tpm_manager
diff --git a/server/openssl_crypto_util.h b/server/openssl_crypto_util.h
new file mode 100644
index 0000000..f252e57
--- /dev/null
+++ b/server/openssl_crypto_util.h
@@ -0,0 +1,36 @@
+// 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_OPENSSL_CRYPTO_UTIL_H_
+#define TPM_MANAGER_SERVER_OPENSSL_CRYPTO_UTIL_H_
+
+#include <string>
+
+#include <base/compiler_specific.h>
+#include <base/macros.h>
+
+namespace tpm_manager {
+
+// This class is used to provide a mockable interface for openssl calls.
+// Example usage:
+// OpensslCryptoUtil util;
+// std::string random_bytes;
+// bool result = util.GetRandomBytes(5, &random_bytes);
+class OpensslCryptoUtil {
+ public:
+ OpensslCryptoUtil() = default;
+ ~OpensslCryptoUtil() = default;
+
+ // This method sets the out argument |random_data| to a string with at
+ // least |num_bytes| of random data and returns true on success.
+ bool GetRandomBytes(size_t num_bytes,
+ std::string* random_data) WARN_UNUSED_RESULT;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OpensslCryptoUtil);
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_OPENSSL_CRYPTO_UTIL_H_
diff --git a/server/org.chromium.TpmManager.conf b/server/org.chromium.TpmManager.conf
new file mode 100644
index 0000000..70eca0f
--- /dev/null
+++ b/server/org.chromium.TpmManager.conf
@@ -0,0 +1,15 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <policy user="tpm_manager">
+ <allow own="org.chromium.TpmManager" />
+ <allow send_destination="org.chromium.TpmManager" />
+ </policy>
+ <policy context="default">
+ <allow send_destination="org.chromium.TpmManager" />
+ <!-- introspection denied -->
+ <deny send_destination="org.chromium.TpmManager"
+ send_interface="org.freedesktop.DBus.Introspectable" />
+ </policy>
+</busconfig>
diff --git a/server/tpm2_initializer_impl.cc b/server/tpm2_initializer_impl.cc
new file mode 100644
index 0000000..63b4a66
--- /dev/null
+++ b/server/tpm2_initializer_impl.cc
@@ -0,0 +1,121 @@
+// 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/tpm2_initializer_impl.h"
+
+#include <string>
+
+#include <base/logging.h>
+#include <trunks/tpm_utility.h>
+#include <trunks/trunks_factory_impl.h>
+
+#include "tpm_manager/common/local_data.pb.h"
+
+namespace {
+const size_t kDefaultPasswordSize = 20;
+} // namespace
+
+namespace tpm_manager {
+
+Tpm2InitializerImpl::Tpm2InitializerImpl(LocalDataStore* local_data_store,
+ TpmStatus* tpm_status)
+ : trunks_factory_(new trunks::TrunksFactoryImpl()),
+ openssl_util_(new OpensslCryptoUtil()),
+ local_data_store_(local_data_store),
+ tpm_status_(tpm_status) {}
+
+Tpm2InitializerImpl::Tpm2InitializerImpl(trunks::TrunksFactory* factory,
+ OpensslCryptoUtil* openssl_util,
+ LocalDataStore* local_data_store,
+ TpmStatus* tpm_status)
+ : trunks_factory_(factory),
+ openssl_util_(openssl_util),
+ local_data_store_(local_data_store),
+ tpm_status_(tpm_status) {}
+
+bool Tpm2InitializerImpl::InitializeTpm() {
+ if (!SeedTpmRng()) {
+ return false;
+ }
+ if (tpm_status_->IsTpmOwned()) {
+ // Tpm is already owned, so we do not need to do anything.
+ VLOG(1) << "Tpm already owned.";
+ return true;
+ }
+ // First we read the local data. If the |owned_by_this_install| flag is set,
+ // either we did not finish removing owner dependencies or TakeOwnership
+ // failed. In either case, we want to retake ownership with the same
+ // passwords.
+ LocalData local_data;
+ if (!local_data_store_->Read(&local_data)) {
+ LOG(ERROR) << "Error reading local data.";
+ return false;
+ }
+ std::string owner_password;
+ std::string endorsement_password;
+ std::string lockout_password;
+ // TODO(usanghi): Use owner dependency information rather than the
+ // |owned_by_this_install| flag here.
+ if (local_data.owned_by_this_install()) {
+ owner_password.assign(local_data.owner_password());
+ endorsement_password.assign(local_data.endorsement_password());
+ lockout_password.assign(local_data.lockout_password());
+ } else {
+ if (!GetTpmRandomData(kDefaultPasswordSize, &owner_password)) {
+ LOG(ERROR) << "Error generating a random owner password.";
+ return false;
+ }
+ if (!GetTpmRandomData(kDefaultPasswordSize, &endorsement_password)) {
+ LOG(ERROR) << "Error generating a random endorsement password.";
+ return false;
+ }
+ if (!GetTpmRandomData(kDefaultPasswordSize, &lockout_password)) {
+ LOG(ERROR) << "Error generating a random lockout password.";
+ return false;
+ }
+ }
+ // We write the passwords to disk, in case there is an error while taking
+ // ownership.
+ local_data.set_owned_by_this_install(true);
+ local_data.set_owner_password(owner_password);
+ local_data.set_endorsement_password(endorsement_password);
+ local_data.set_lockout_password(lockout_password);
+ // TODO(usanghi): Add ownership dependencies here.
+ if (!local_data_store_->Write(local_data)) {
+ LOG(ERROR) << "Error saving local data.";
+ return false;
+ }
+ trunks::TPM_RC result = trunks_factory_->GetTpmUtility()->TakeOwnership(
+ owner_password, endorsement_password, lockout_password);
+ if (result != trunks::TPM_RC_SUCCESS) {
+ LOG(ERROR) << "Error taking ownership of TPM2.0";
+ return false;
+ }
+ return true;
+}
+
+bool Tpm2InitializerImpl::SeedTpmRng() {
+ std::string random_bytes;
+ if (!openssl_util_->GetRandomBytes(kDefaultPasswordSize, &random_bytes)) {
+ return false;
+ }
+ trunks::TPM_RC result = trunks_factory_->GetTpmUtility()->StirRandom(
+ random_bytes, nullptr /* No Authorization */);
+ if (result != trunks::TPM_RC_SUCCESS) {
+ return false;
+ }
+ return true;
+}
+
+bool Tpm2InitializerImpl::GetTpmRandomData(size_t num_bytes,
+ std::string* random_data) {
+ trunks::TPM_RC result = trunks_factory_->GetTpmUtility()->GenerateRandom(
+ num_bytes, nullptr /* No Authorization */, random_data);
+ if (result != trunks::TPM_RC_SUCCESS) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace tpm_manager
diff --git a/server/tpm2_initializer_impl.h b/server/tpm2_initializer_impl.h
new file mode 100644
index 0000000..a50abea
--- /dev/null
+++ b/server/tpm2_initializer_impl.h
@@ -0,0 +1,66 @@
+// 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_TPM2_INITIALIZER_IMPL_H_
+#define TPM_MANAGER_SERVER_TPM2_INITIALIZER_IMPL_H_
+
+#include "tpm_manager/server/tpm_initializer.h"
+
+#include <string>
+#include <memory>
+
+#include <base/macros.h>
+#include <trunks/trunks_factory.h>
+
+#include "tpm_manager/server/local_data_store.h"
+#include "tpm_manager/server/openssl_crypto_util.h"
+#include "tpm_manager/server/tpm_status.h"
+
+namespace tpm_manager {
+
+// This class initializes a Tpm2.0 chip by taking ownership. Example use of
+// this class is:
+// LocalDataStore data_store;
+// Tpm2StatusImpl status;
+// Tpm2InitializerImpl initializer(&data_store, &status);
+// initializer.InitializeTpm();
+// If the tpm is unowned, InitializeTpm injects random owner, endorsement and
+// lockout passwords, intializes the SRK with empty authorization, and persists
+// the passwords to disk until all the owner dependencies are satisfied.
+class Tpm2InitializerImpl : public TpmInitializer {
+ public:
+ // Does not take ownership of |local_data_store| or |tpm_status|.
+ Tpm2InitializerImpl(LocalDataStore* local_data_store,
+ TpmStatus* tpm_status);
+ // Does not take ownership of |openssl_util|, |local_data_store| or
+ // |tpm_status|. Takes ownership of |factory|.
+ Tpm2InitializerImpl(trunks::TrunksFactory* factory,
+ OpensslCryptoUtil* openssl_util,
+ LocalDataStore* local_data_store,
+ TpmStatus* tpm_status);
+ ~Tpm2InitializerImpl() override = default;
+
+ // TpmInitializer methods.
+ bool InitializeTpm() override;
+
+ private:
+ // Seeds the onboard Tpm random number generator with random bytes from
+ // Openssl, if the Tpm RNG has not been seeded yet. Returns true on success.
+ bool SeedTpmRng();
+
+ // Gets random bytes of length |num_bytes| and populates the string at
+ // |random_data|. Returns true on success.
+ bool GetTpmRandomData(size_t num_bytes, std::string* random_data);
+
+ std::unique_ptr<trunks::TrunksFactory> trunks_factory_;
+ OpensslCryptoUtil* openssl_util_;
+ LocalDataStore* local_data_store_;
+ TpmStatus* tpm_status_;
+
+ DISALLOW_COPY_AND_ASSIGN(Tpm2InitializerImpl);
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_TPM2_INITIALIZER_IMPL_H_
diff --git a/server/tpm2_initializer_test.cc b/server/tpm2_initializer_test.cc
new file mode 100644
index 0000000..9d1bfd0
--- /dev/null
+++ b/server/tpm2_initializer_test.cc
@@ -0,0 +1,138 @@
+// 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/tpm2_initializer_impl.h"
+
+#include <memory>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <trunks/mock_tpm_utility.h>
+#include <trunks/trunks_factory_for_test.h>
+
+#include "tpm_manager/server/mock_local_data_store.h"
+#include "tpm_manager/server/mock_openssl_crypto_util.h"
+#include "tpm_manager/server/mock_tpm_status.h"
+
+using testing::_;
+using testing::DoAll;
+using testing::NiceMock;
+using testing::Return;
+using testing::SaveArg;
+using testing::SetArgPointee;
+
+namespace tpm_manager {
+
+class Tpm2InitializerTest : public testing::Test {
+ public:
+ Tpm2InitializerTest() = default;
+ virtual ~Tpm2InitializerTest() = default;
+
+ void SetUp() {
+ trunks::TrunksFactoryForTest* factory = new trunks::TrunksFactoryForTest();
+ factory->set_tpm_utility(&mock_tpm_utility_);
+ tpm_initializer_.reset(new Tpm2InitializerImpl(factory,
+ &mock_openssl_util_,
+ &mock_data_store_,
+ &mock_tpm_status_));
+ }
+
+ protected:
+ NiceMock<MockOpensslCryptoUtil> mock_openssl_util_;
+ NiceMock<MockLocalDataStore> mock_data_store_;
+ NiceMock<MockTpmStatus> mock_tpm_status_;
+ NiceMock<trunks::MockTpmUtility> mock_tpm_utility_;
+ std::unique_ptr<TpmInitializer> tpm_initializer_;
+};
+
+TEST_F(Tpm2InitializerTest, InitializeTpmNoSeedTpm) {
+ EXPECT_CALL(mock_tpm_utility_, StirRandom(_, _))
+ .WillRepeatedly(Return(trunks::TPM_RC_FAILURE));
+ EXPECT_FALSE(tpm_initializer_->InitializeTpm());
+}
+
+TEST_F(Tpm2InitializerTest, InitializeTpmAlreadyOwned) {
+ EXPECT_CALL(mock_tpm_status_, IsTpmOwned())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(mock_tpm_utility_, TakeOwnership(_, _, _))
+ .Times(0);
+ EXPECT_TRUE(tpm_initializer_->InitializeTpm());
+}
+
+TEST_F(Tpm2InitializerTest, InitializeTpmLocalDataReadError) {
+ EXPECT_CALL(mock_tpm_status_, IsTpmOwned())
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(mock_data_store_, Read(_))
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(mock_tpm_utility_, TakeOwnership(_, _, _))
+ .Times(0);
+ EXPECT_FALSE(tpm_initializer_->InitializeTpm());
+}
+
+TEST_F(Tpm2InitializerTest, InitializeTpmLocalDataWriteError) {
+ EXPECT_CALL(mock_tpm_status_, IsTpmOwned())
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(mock_data_store_, Write(_))
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(mock_tpm_utility_, TakeOwnership(_, _, _))
+ .Times(0);
+ EXPECT_FALSE(tpm_initializer_->InitializeTpm());
+}
+
+TEST_F(Tpm2InitializerTest, InitializeTpmOwnershipError) {
+ EXPECT_CALL(mock_tpm_status_, IsTpmOwned())
+ .WillOnce(Return(false));
+ EXPECT_CALL(mock_tpm_utility_, TakeOwnership(_, _, _))
+ .WillRepeatedly(Return(trunks::TPM_RC_FAILURE));
+ EXPECT_FALSE(tpm_initializer_->InitializeTpm());
+}
+
+TEST_F(Tpm2InitializerTest, InitializeTpmSuccess) {
+ EXPECT_CALL(mock_tpm_status_, IsTpmOwned())
+ .WillOnce(Return(false));
+ std::string owner_password;
+ std::string endorsement_password;
+ std::string lockout_password;
+ LocalData local_data;
+ local_data.set_owned_by_this_install(false);
+ EXPECT_CALL(mock_data_store_, Read(_))
+ .WillOnce(DoAll(SetArgPointee<0>(local_data),
+ Return(true)));
+ EXPECT_CALL(mock_tpm_utility_, GenerateRandom(_, _, _))
+ .Times(3) // Once for owner, endorsement and lockout passwords
+ .WillRepeatedly(Return(trunks::TPM_RC_SUCCESS));
+ EXPECT_CALL(mock_tpm_utility_, TakeOwnership(_, _, _))
+ .WillOnce(Return(trunks::TPM_RC_SUCCESS));
+ EXPECT_TRUE(tpm_initializer_->InitializeTpm());
+}
+
+TEST_F(Tpm2InitializerTest, InitializeTpmSuccessAfterError) {
+ EXPECT_CALL(mock_tpm_status_, IsTpmOwned())
+ .WillOnce(Return(false));
+ std::string owner_password("owner");
+ std::string endorsement_password("endorsement");
+ std::string lockout_password("lockout");
+ LocalData local_data;
+ local_data.set_owned_by_this_install(true);
+ local_data.set_owner_password(owner_password);
+ local_data.set_endorsement_password(endorsement_password);
+ local_data.set_lockout_password(lockout_password);
+ EXPECT_CALL(mock_data_store_, Read(_))
+ .WillOnce(DoAll(SetArgPointee<0>(local_data),
+ Return(true)));
+ EXPECT_CALL(mock_data_store_, Write(_))
+ .WillOnce(DoAll(SaveArg<0>(&local_data),
+ Return(true)));
+ EXPECT_EQ(true, local_data.owned_by_this_install());
+ EXPECT_EQ(owner_password, local_data.owner_password());
+ EXPECT_EQ(endorsement_password, local_data.endorsement_password());
+ EXPECT_EQ(lockout_password, local_data.lockout_password());
+ EXPECT_CALL(mock_tpm_utility_, TakeOwnership(owner_password,
+ endorsement_password,
+ lockout_password))
+ .WillOnce(Return(trunks::TPM_RC_SUCCESS));
+ EXPECT_TRUE(tpm_initializer_->InitializeTpm());
+}
+
+} // namespace tpm_manager
diff --git a/server/tpm2_status_impl.cc b/server/tpm2_status_impl.cc
new file mode 100644
index 0000000..53a9274
--- /dev/null
+++ b/server/tpm2_status_impl.cc
@@ -0,0 +1,75 @@
+// 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/tpm2_status_impl.h"
+
+#include <base/logging.h>
+#include <trunks/error_codes.h>
+#include <trunks/tpm_generated.h>
+#include <trunks/trunks_factory_impl.h>
+
+using trunks::TPM_RC;
+using trunks::TPM_RC_SUCCESS;
+
+namespace tpm_manager {
+
+Tpm2StatusImpl::Tpm2StatusImpl()
+ : default_trunks_factory_(new trunks::TrunksFactoryImpl()),
+ trunks_factory_(default_trunks_factory_.get()),
+ trunks_tpm_state_(trunks_factory_->GetTpmState()) {}
+
+Tpm2StatusImpl::Tpm2StatusImpl(trunks::TrunksFactory* factory)
+ : trunks_factory_(factory),
+ trunks_tpm_state_(trunks_factory_->GetTpmState()) {}
+
+bool Tpm2StatusImpl::IsTpmEnabled() {
+ if (!initialized_) {
+ Refresh();
+ }
+ return trunks_tpm_state_->IsEnabled();
+}
+
+bool Tpm2StatusImpl::IsTpmOwned() {
+ if (!is_owned_) {
+ Refresh();
+ }
+ is_owned_ = trunks_tpm_state_->IsOwned();
+ return is_owned_;
+}
+
+bool Tpm2StatusImpl::GetDictionaryAttackInfo(int* counter,
+ int* threshold,
+ bool* lockout,
+ int* seconds_remaining) {
+ if (!Refresh()) {
+ return false;
+ }
+ if (counter) {
+ *counter = trunks_tpm_state_->GetLockoutCounter();
+ }
+ if (threshold) {
+ *threshold = trunks_tpm_state_->GetLockoutThreshold();
+ }
+ if (lockout) {
+ *lockout = trunks_tpm_state_->IsInLockout();
+ }
+ if (seconds_remaining) {
+ *seconds_remaining = trunks_tpm_state_->GetLockoutCounter() *
+ trunks_tpm_state_->GetLockoutInterval();
+ }
+ return true;
+}
+
+bool Tpm2StatusImpl::Refresh() {
+ TPM_RC result = trunks_tpm_state_->Initialize();
+ if (result != TPM_RC_SUCCESS) {
+ LOG(WARNING) << "Error initializing trunks tpm state: "
+ << trunks::GetErrorString(result);
+ return false;
+ }
+ initialized_ = true;
+ return true;
+}
+
+} // namespace tpm_manager
diff --git a/server/tpm2_status_impl.h b/server/tpm2_status_impl.h
new file mode 100644
index 0000000..0bde61c
--- /dev/null
+++ b/server/tpm2_status_impl.h
@@ -0,0 +1,50 @@
+// 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_TPM2_STATUS_IMPL_H_
+#define TPM_MANAGER_SERVER_TPM2_STATUS_IMPL_H_
+
+#include "tpm_manager/server/tpm_status.h"
+
+#include <memory>
+
+#include <base/macros.h>
+#include <trunks/tpm_state.h>
+#include <trunks/trunks_factory.h>
+
+namespace tpm_manager {
+
+class Tpm2StatusImpl : public TpmStatus {
+ public:
+ Tpm2StatusImpl();
+ // Does not take ownership of |factory|.
+ explicit Tpm2StatusImpl(trunks::TrunksFactory* factory);
+ ~Tpm2StatusImpl() override = default;
+
+ // TpmState methods.
+ bool IsTpmEnabled() override;
+ bool IsTpmOwned() override;
+ bool GetDictionaryAttackInfo(int* counter,
+ int* threshold,
+ bool* lockout,
+ int* seconds_remaining) override;
+
+ private:
+ // Refreshes the Tpm state information. Can be called as many times as needed
+ // to refresh the cached information in this class. Return true if the
+ // refresh operation succeeded.
+ bool Refresh();
+
+ bool initialized_{false};
+ bool is_owned_{false};
+ std::unique_ptr<trunks::TrunksFactory> default_trunks_factory_;
+ trunks::TrunksFactory* trunks_factory_;
+ scoped_ptr<trunks::TpmState> trunks_tpm_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(Tpm2StatusImpl);
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_TPM2_STATUS_IMPL_H_
diff --git a/server/tpm2_status_test.cc b/server/tpm2_status_test.cc
new file mode 100644
index 0000000..82da4ba
--- /dev/null
+++ b/server/tpm2_status_test.cc
@@ -0,0 +1,147 @@
+// 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/tpm2_status_impl.h"
+
+#include <memory>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <trunks/mock_tpm_state.h>
+#include <trunks/trunks_factory_for_test.h>
+
+using testing::NiceMock;
+using testing::Return;
+using trunks::TPM_RC_FAILURE;
+using trunks::TPM_RC_SUCCESS;
+
+namespace tpm_manager {
+
+class Tpm2StatusTest : public testing::Test {
+ public:
+ Tpm2StatusTest() : factory_(new trunks::TrunksFactoryForTest()) {}
+ virtual ~Tpm2StatusTest() = default;
+
+ void SetUp() {
+ factory_->set_tpm_state(&mock_tpm_state_);
+ tpm_status_.reset(new Tpm2StatusImpl(factory_.get()));
+ }
+
+ protected:
+ NiceMock<trunks::MockTpmState> mock_tpm_state_;
+ std::unique_ptr<trunks::TrunksFactoryForTest> factory_;
+ std::unique_ptr<TpmStatus> tpm_status_;
+};
+
+
+TEST_F(Tpm2StatusTest, IsEnabledSuccess) {
+ EXPECT_CALL(mock_tpm_state_, Initialize())
+ .WillRepeatedly(Return(TPM_RC_SUCCESS));
+ EXPECT_CALL(mock_tpm_state_, IsEnabled())
+ .WillRepeatedly(Return(true));
+ EXPECT_TRUE(tpm_status_->IsTpmEnabled());
+}
+
+TEST_F(Tpm2StatusTest, IsEnabledFailure) {
+ EXPECT_CALL(mock_tpm_state_, IsEnabled())
+ .WillRepeatedly(Return(false));
+ EXPECT_FALSE(tpm_status_->IsTpmEnabled());
+}
+
+TEST_F(Tpm2StatusTest, IsEnabledNoRepeatedInitialization) {
+ EXPECT_CALL(mock_tpm_state_, Initialize())
+ .WillOnce(Return(TPM_RC_SUCCESS));
+ EXPECT_TRUE(tpm_status_->IsTpmEnabled());
+ EXPECT_TRUE(tpm_status_->IsTpmEnabled());
+}
+
+TEST_F(Tpm2StatusTest, IsOwnedSuccess) {
+ EXPECT_CALL(mock_tpm_state_, Initialize())
+ .WillRepeatedly(Return(TPM_RC_SUCCESS));
+ EXPECT_CALL(mock_tpm_state_, IsOwned())
+ .WillRepeatedly(Return(true));
+ EXPECT_TRUE(tpm_status_->IsTpmOwned());
+}
+
+TEST_F(Tpm2StatusTest, IsOwnedFailure) {
+ EXPECT_CALL(mock_tpm_state_, IsOwned())
+ .WillRepeatedly(Return(false));
+ EXPECT_FALSE(tpm_status_->IsTpmOwned());
+}
+
+TEST_F(Tpm2StatusTest, IsOwnedRepeatedInitializationOnFalse) {
+ EXPECT_CALL(mock_tpm_state_, Initialize())
+ .Times(2)
+ .WillRepeatedly(Return(TPM_RC_SUCCESS));
+ EXPECT_CALL(mock_tpm_state_, IsOwned())
+ .WillOnce(Return(false));
+ EXPECT_FALSE(tpm_status_->IsTpmOwned());
+ EXPECT_CALL(mock_tpm_state_, IsOwned())
+ .WillRepeatedly(Return(true));
+ EXPECT_TRUE(tpm_status_->IsTpmOwned());
+}
+
+TEST_F(Tpm2StatusTest, IsOwnedNoRepeatedInitializationOnTrue) {
+ EXPECT_CALL(mock_tpm_state_, Initialize())
+ .WillOnce(Return(TPM_RC_SUCCESS));
+ EXPECT_CALL(mock_tpm_state_, IsOwned())
+ .WillRepeatedly(Return(true));
+ EXPECT_TRUE(tpm_status_->IsTpmOwned());
+ EXPECT_TRUE(tpm_status_->IsTpmOwned());
+}
+
+TEST_F(Tpm2StatusTest, GetDictionaryAttackInfoInitializeFailure) {
+ EXPECT_CALL(mock_tpm_state_, Initialize())
+ .WillRepeatedly(Return(TPM_RC_FAILURE));
+ int count;
+ int threshold;
+ bool lockout;
+ int seconds_remaining;
+ EXPECT_FALSE(tpm_status_->GetDictionaryAttackInfo(&count,
+ &threshold,
+ &lockout,
+ &seconds_remaining));
+}
+
+TEST_F(Tpm2StatusTest, GetDictionaryAttackInfoForwarding) {
+ int lockout_count = 3;
+ int lockout_threshold = 16;
+ bool is_locked = true;
+ int lockout_interval = 3600;
+ EXPECT_CALL(mock_tpm_state_, GetLockoutCounter())
+ .WillRepeatedly(Return(lockout_count));
+ EXPECT_CALL(mock_tpm_state_, GetLockoutThreshold())
+ .WillRepeatedly(Return(lockout_threshold));
+ EXPECT_CALL(mock_tpm_state_, IsInLockout())
+ .WillRepeatedly(Return(is_locked));
+ EXPECT_CALL(mock_tpm_state_, GetLockoutInterval())
+ .WillRepeatedly(Return(lockout_interval));
+ int count;
+ int threshold;
+ bool lockout;
+ int seconds_remaining;
+ EXPECT_TRUE(tpm_status_->GetDictionaryAttackInfo(&count,
+ &threshold,
+ &lockout,
+ &seconds_remaining));
+ EXPECT_EQ(count, lockout_count);
+ EXPECT_EQ(threshold, lockout_threshold);
+ EXPECT_EQ(lockout, is_locked);
+ EXPECT_EQ(seconds_remaining, lockout_count * lockout_interval);
+}
+
+TEST_F(Tpm2StatusTest, GetDictionaryAttackInfoAlwaysRefresh) {
+ EXPECT_CALL(mock_tpm_state_, Initialize())
+ .WillRepeatedly(Return(TPM_RC_SUCCESS));
+ int count;
+ int threshold;
+ bool lockout;
+ int seconds_remaining;
+ EXPECT_TRUE(tpm_status_->GetDictionaryAttackInfo(&count,
+ &threshold,
+ &lockout,
+ &seconds_remaining));
+}
+
+} // namespace tpm_manager
diff --git a/server/tpm_connection.cc b/server/tpm_connection.cc
new file mode 100644
index 0000000..ee57f3a
--- /dev/null
+++ b/server/tpm_connection.cc
@@ -0,0 +1,96 @@
+// 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/tpm_connection.h"
+
+#include <base/logging.h>
+#include <base/stl_util.h>
+#include <base/threading/platform_thread.h>
+#include <base/time/time.h>
+#include <trousers/tss.h>
+#include <trousers/trousers.h> // NOLINT(build/include_alpha)
+
+#include "tpm_manager/server/tpm_util.h"
+
+namespace {
+
+const int kTpmConnectRetries = 10;
+const int kTpmConnectIntervalMs = 100;
+
+} // namespace
+
+namespace tpm_manager {
+
+TSS_HCONTEXT TpmConnection::GetContext() {
+ if (!ConnectContextIfNeeded()) {
+ return 0;
+ }
+ return context_.value();
+}
+
+TSS_HTPM TpmConnection::GetTpm() {
+ if (!ConnectContextIfNeeded()) {
+ return 0;
+ }
+ TSS_RESULT result;
+ TSS_HTPM tpm_handle;
+ if (TPM_ERROR(result = Tspi_Context_GetTpmObject(context_.value(),
+ &tpm_handle))) {
+ TPM_LOG(ERROR, result) << "Error getting a handle to the TPM.";
+ return 0;
+ }
+ return tpm_handle;
+}
+
+TSS_HTPM TpmConnection::GetTpmWithAuth(const std::string& owner_password) {
+ TSS_HTPM tpm_handle = GetTpm();
+ if (tpm_handle == 0) {
+ return 0;
+ }
+ TSS_RESULT result;
+ TSS_HPOLICY tpm_usage_policy;
+ if (TPM_ERROR(result = Tspi_GetPolicyObject(tpm_handle,
+ TSS_POLICY_USAGE,
+ &tpm_usage_policy))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_GetPolicyObject";
+ return false;
+ }
+ if (TPM_ERROR(result = Tspi_Policy_SetSecret(
+ tpm_usage_policy,
+ TSS_SECRET_MODE_PLAIN,
+ owner_password.size(),
+ reinterpret_cast<BYTE *>(const_cast<char*>(owner_password.data()))))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret";
+ return false;
+ }
+ return tpm_handle;
+}
+
+bool TpmConnection::ConnectContextIfNeeded() {
+ if (context_.value() != 0) {
+ return true;
+ }
+ TSS_RESULT result;
+ if (TPM_ERROR(result = Tspi_Context_Create(context_.ptr()))) {
+ TPM_LOG(ERROR, result) << "Error connecting to TPM.";
+ return false;
+ }
+ // We retry on failure. It might be that tcsd is starting up.
+ for (int i = 0; i < kTpmConnectRetries; i++) {
+ if (TPM_ERROR(result = Tspi_Context_Connect(context_, nullptr))) {
+ if (ERROR_CODE(result) == TSS_E_COMM_FAILURE) {
+ base::PlatformThread::Sleep(
+ base::TimeDelta::FromMilliseconds(kTpmConnectIntervalMs));
+ } else {
+ TPM_LOG(ERROR, result) << "Error connecting to TPM.";
+ return false;
+ }
+ } else {
+ break;
+ }
+ }
+ return (context_.value() != 0);
+}
+
+} // namespace tpm_manager
diff --git a/server/tpm_connection.h b/server/tpm_connection.h
new file mode 100644
index 0000000..833a972
--- /dev/null
+++ b/server/tpm_connection.h
@@ -0,0 +1,43 @@
+// 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_CONNECTION_H_
+#define TPM_MANAGER_SERVER_TPM_CONNECTION_H_
+
+#include <string>
+
+#include <base/macros.h>
+#include <trousers/scoped_tss_type.h>
+
+namespace tpm_manager {
+
+class TpmConnection {
+ public:
+ TpmConnection() = default;
+ ~TpmConnection() = default;
+
+ // This method returns a handle to the current Tpm context.
+ // Note: this method still retains ownership of the context. If this class
+ // is deleted, the context handle will be invalidated. Returns 0 on failure.
+ TSS_HCONTEXT GetContext();
+
+ // This method tries to get a handle to the TPM. Returns 0 on failure.
+ TSS_HTPM GetTpm();
+
+ // This method tries to get a handle to the TPM and with the given owner
+ // password. Returns 0 on failure.
+ TSS_HTPM GetTpmWithAuth(const std::string& owner_password);
+
+ private:
+ // This method connects to the Tpm. Returns true on success.
+ bool ConnectContextIfNeeded();
+
+ trousers::ScopedTssContext context_;
+
+ DISALLOW_COPY_AND_ASSIGN(TpmConnection);
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_TPM_CONNECTION_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_initializer_impl.cc b/server/tpm_initializer_impl.cc
new file mode 100644
index 0000000..a33d5b6
--- /dev/null
+++ b/server/tpm_initializer_impl.cc
@@ -0,0 +1,246 @@
+// 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/tpm_initializer_impl.h"
+
+#include <string>
+
+#include <base/logging.h>
+#include <base/stl_util.h>
+#include <trousers/scoped_tss_type.h>
+
+#include "tpm_manager/server/local_data_store.h"
+#include "tpm_manager/server/tpm_connection.h"
+#include "tpm_manager/server/tpm_status.h"
+#include "tpm_manager/server/tpm_util.h"
+
+namespace {
+
+const char kDefaultOwnerPassword[] = TSS_WELL_KNOWN_SECRET;
+const size_t kDefaultPasswordSize = 20;
+const int kMaxOwnershipTimeoutRetries = 5;
+const char* kWellKnownSrkSecret = "well_known_srk_secret";
+
+} // namespace
+
+namespace tpm_manager {
+
+TpmInitializerImpl::TpmInitializerImpl(LocalDataStore* local_data_store,
+ TpmStatus* tpm_status)
+ : local_data_store_(local_data_store),
+ tpm_status_(tpm_status) {}
+
+bool TpmInitializerImpl::InitializeTpm() {
+ if (tpm_status_->IsTpmOwned() && !TestTpmAuth(kDefaultOwnerPassword)) {
+ // Tpm is already owned, so we do not need to do anything.
+ VLOG(1) << "Tpm already owned.";
+ return true;
+ }
+ TSS_HTPM tpm_handle = tpm_connection_.GetTpm();
+ if (tpm_handle == 0) {
+ return false;
+ }
+ if (!InitializeEndorsementKey(tpm_handle) ||
+ !TakeOwnership(tpm_handle) ||
+ !InitializeSrk(tpm_handle)) {
+ return false;
+ }
+ std::string owner_password;
+ if (!openssl_util_.GetRandomBytes(kDefaultPasswordSize, &owner_password)) {
+ return false;
+ }
+ LocalData local_data;
+ local_data.set_owned_by_this_install(true);
+ local_data.set_owner_password(owner_password);
+ // TODO(usanghi): Add ownership dependencies here.
+ if (!local_data_store_->Write(local_data)) {
+ LOG(ERROR) << "Error saving local data.";
+ return false;
+ }
+ if (!ChangeOwnerPassword(tpm_handle, owner_password)) {
+ return false;
+ }
+ return true;
+}
+
+bool TpmInitializerImpl::InitializeEndorsementKey(TSS_HTPM tpm_handle) {
+ trousers::ScopedTssKey local_key_handle(tpm_connection_.GetContext());
+ TSS_RESULT result = Tspi_TPM_GetPubEndorsementKey(tpm_handle,
+ false,
+ nullptr,
+ local_key_handle.ptr());
+ if (TPM_ERROR(result) == TPM_SUCCESS) {
+ // In this case the EK already exists, so we can return true here.
+ return true;
+ }
+ // At this point the EK does not exist, so we create it.
+ TSS_FLAG init_flags = TSS_KEY_TYPE_LEGACY | TSS_KEY_SIZE_2048;
+ if (TPM_ERROR(result = Tspi_Context_CreateObject(tpm_connection_.GetContext(),
+ TSS_OBJECT_TYPE_RSAKEY,
+ init_flags,
+ local_key_handle.ptr()))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
+ return false;
+ }
+ if (TPM_ERROR(result = Tspi_TPM_CreateEndorsementKey(tpm_handle,
+ local_key_handle,
+ NULL))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_CreateEndorsementKey";
+ return false;
+ }
+ return true;
+}
+
+bool TpmInitializerImpl::TakeOwnership(TSS_HTPM tpm_handle) {
+ if (TestTpmAuth(kDefaultOwnerPassword)) {
+ VLOG(1) << "The Tpm already has the default owner password.";
+ return true;
+ }
+ TSS_RESULT result;
+ trousers::ScopedTssKey srk_handle(tpm_connection_.GetContext());
+ TSS_FLAG init_flags = TSS_KEY_TSP_SRK | TSS_KEY_AUTHORIZATION;
+ if (TPM_ERROR(result = Tspi_Context_CreateObject(tpm_connection_.GetContext(),
+ TSS_OBJECT_TYPE_RSAKEY,
+ init_flags,
+ srk_handle.ptr()))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
+ return false;
+ }
+ TSS_HPOLICY srk_usage_policy;
+ if (TPM_ERROR(result = Tspi_GetPolicyObject(srk_handle,
+ TSS_POLICY_USAGE,
+ &srk_usage_policy))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_GetPolicyObject";
+ return false;
+ }
+ if (TPM_ERROR(result = Tspi_Policy_SetSecret(
+ srk_usage_policy,
+ TSS_SECRET_MODE_PLAIN,
+ strlen(kWellKnownSrkSecret),
+ const_cast<BYTE *>(reinterpret_cast<const BYTE *>(
+ kWellKnownSrkSecret))))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret";
+ return false;
+ }
+ // Tspi_TPM_TakeOwnership can potentailly take a long time to complete,
+ // so we retry if there is a timeout in any layer. I chose 5, because the
+ // longest TakeOwnership call that I have seen took ~2min, and the default
+ // TSS timeout is 30s. This means that after 5 calls, it is quite likely that
+ // this call will succeed.
+ int retry_count = 0;
+ do {
+ result = Tspi_TPM_TakeOwnership(tpm_handle, srk_handle, 0);
+ retry_count++;
+ } while (((result == TDDL_E_TIMEOUT) ||
+ (result == (TSS_LAYER_TDDL | TDDL_E_TIMEOUT)) ||
+ (result == (TSS_LAYER_TDDL | TDDL_E_IOERROR))) &&
+ (retry_count < kMaxOwnershipTimeoutRetries));
+ if (result) {
+ TPM_LOG(ERROR, result)
+ << "Error calling Tspi_TPM_TakeOwnership, attempts: " << retry_count;
+ return false;
+ }
+ return true;
+}
+
+bool TpmInitializerImpl::InitializeSrk(TSS_HTPM tpm_handle) {
+ TSS_RESULT result;
+ trousers::ScopedTssKey srk_handle(tpm_connection_.GetContext());
+ TSS_UUID SRK_UUID = TSS_UUID_SRK;
+ if (TPM_ERROR(result = Tspi_Context_LoadKeyByUUID(
+ tpm_connection_.GetContext(),
+ TSS_PS_TYPE_SYSTEM,
+ SRK_UUID,
+ srk_handle.ptr()))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_Context_LoadKeyByUUID";
+ return false;
+ }
+
+ trousers::ScopedTssPolicy policy_handle(tpm_connection_.GetContext());
+ if (TPM_ERROR(result = Tspi_Context_CreateObject(tpm_connection_.GetContext(),
+ TSS_OBJECT_TYPE_POLICY,
+ TSS_POLICY_USAGE,
+ policy_handle.ptr()))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
+ return false;
+ }
+ BYTE new_password[0];
+ if (TPM_ERROR(result = Tspi_Policy_SetSecret(policy_handle,
+ TSS_SECRET_MODE_PLAIN,
+ 0,
+ new_password))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret";
+ return false;
+ }
+
+ if (TPM_ERROR(result = Tspi_ChangeAuth(srk_handle,
+ tpm_handle,
+ policy_handle))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_ChangeAuth";
+ return false;
+ }
+ TSS_BOOL is_srk_restricted = false;
+ if (TPM_ERROR(result = Tspi_TPM_GetStatus(tpm_handle,
+ TSS_TPMSTATUS_DISABLEPUBSRKREAD,
+ &is_srk_restricted))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetStatus";
+ return false;
+ }
+ // If the SRK is restricted, we unrestrict it.
+ if (is_srk_restricted) {
+ if (TPM_ERROR(result = Tspi_TPM_SetStatus(tpm_handle,
+ TSS_TPMSTATUS_DISABLEPUBSRKREAD,
+ false))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_SetStatus";
+ return false;
+ }
+ }
+ return true;
+}
+
+bool TpmInitializerImpl::ChangeOwnerPassword(
+ TSS_HTPM tpm_handle, const std::string& owner_password) {
+ TSS_RESULT result;
+ trousers::ScopedTssPolicy policy_handle(tpm_connection_.GetContext());
+ if (TPM_ERROR(result = Tspi_Context_CreateObject(tpm_connection_.GetContext(),
+ TSS_OBJECT_TYPE_POLICY,
+ TSS_POLICY_USAGE,
+ policy_handle.ptr()))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
+ return false;
+ }
+ std::string mutable_owner_password(owner_password);
+ if (TPM_ERROR(result = Tspi_Policy_SetSecret(policy_handle,
+ TSS_SECRET_MODE_PLAIN,
+ owner_password.size(),
+ reinterpret_cast<BYTE *>(string_as_array(&mutable_owner_password))))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret";
+ return false;
+ }
+
+ if (TPM_ERROR(result = Tspi_ChangeAuth(tpm_handle, 0, policy_handle))) {
+ TPM_LOG(ERROR, result) << "Error calling Tspi_ChangeAuth";
+ return false;
+ }
+
+ return true;
+}
+
+bool TpmInitializerImpl::TestTpmAuth(const std::string& owner_password) {
+ TSS_HTPM tpm_handle = tpm_connection_.GetTpmWithAuth(owner_password);
+ if (tpm_handle == 0) {
+ return false;
+ }
+ // Call Tspi_TPM_GetStatus to test the |owner_password| provided.
+ TSS_RESULT result;
+ TSS_BOOL current_status = false;
+ if (TPM_ERROR(result = Tspi_TPM_GetStatus(tpm_handle,
+ TSS_TPMSTATUS_DISABLED,
+ &current_status))) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace tpm_manager
diff --git a/server/tpm_initializer_impl.h b/server/tpm_initializer_impl.h
new file mode 100644
index 0000000..58adf55
--- /dev/null
+++ b/server/tpm_initializer_impl.h
@@ -0,0 +1,80 @@
+// 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_IMPL_H_
+#define TPM_MANAGER_SERVER_TPM_INITIALIZER_IMPL_H_
+
+#include <string>
+
+#include <base/macros.h>
+#include <trousers/tss.h>
+#include <trousers/trousers.h> // NOLINT(build/include_alpha)
+
+#include "tpm_manager/server/openssl_crypto_util.h"
+#include "tpm_manager/server/tpm_connection.h"
+#include "tpm_manager/server/tpm_initializer.h"
+
+namespace tpm_manager {
+
+class LocalDataStore;
+class TpmStatus;
+
+// This class initializes a Tpm1.2 chip by taking ownership. Example use of
+// this class is:
+// LocalDataStore data_store;
+// TpmStatusImpl status;
+// TpmInitializerImpl initializer(&data_store, &status);
+// initializer.InitializeTpm();
+// If the tpm is unowned, InitializeTpm injects a random owner password,
+// initializes and unrestricts the SRK, and persists the owner password to disk
+// until all the owner dependencies are satisfied.
+class TpmInitializerImpl : public TpmInitializer {
+ public:
+ // Does not take ownership of |local_data_store| or |tpm_status|.
+ TpmInitializerImpl(LocalDataStore* local_data_store,
+ TpmStatus* tpm_status);
+ ~TpmInitializerImpl() override = default;
+
+ // TpmInitializer methods.
+ bool InitializeTpm() override;
+
+ private:
+ // This method checks if an EndorsementKey exists on the Tpm and creates it
+ // if not. Returns true on success, else false. |tpm_handle| is a handle to
+ // the Tpm with the owner_password injected.
+ bool InitializeEndorsementKey(TSS_HTPM tpm_handle);
+
+ // This method takes ownership of the Tpm with the default TSS password.
+ // Returns true on success, else false. |tpm_handle| is a handle to the Tpm
+ // with the owner_password injected.
+ bool TakeOwnership(TSS_HTPM tpm_handle);
+
+ // This method initializes the SRK if it does not exist, zero's the SRK
+ // password and unrestricts its usage. Returns true on success, else false.
+ // |tpm_handle| is a handle to the Tpm with the owner_password injected.
+ bool InitializeSrk(TSS_HTPM tpm_handle);
+
+ // This method changes the Tpm owner password from the default TSS password
+ // to the password provided in the |owner_password| argument.
+ // Returns true on success, else false. |tpm_handle| is a handle to the Tpm
+ // with the old owner_password injected.
+ bool ChangeOwnerPassword(TSS_HTPM tpm_handle,
+ const std::string& owner_password);
+
+ // This method return true iff the provided |owner_password| is the current
+ // owner password in the Tpm. This method can also return false if there was
+ // an error communicating with the Tpm.
+ bool TestTpmAuth(const std::string& owner_password);
+
+ OpensslCryptoUtil openssl_util_;
+ TpmConnection tpm_connection_;
+ LocalDataStore* local_data_store_;
+ TpmStatus* tpm_status_;
+
+ DISALLOW_COPY_AND_ASSIGN(TpmInitializerImpl);
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_TPM_INITIALIZER_IMPL_H_
diff --git a/server/tpm_manager-seccomp-amd64.policy b/server/tpm_manager-seccomp-amd64.policy
new file mode 100644
index 0000000..641bce6
--- /dev/null
+++ b/server/tpm_manager-seccomp-amd64.policy
@@ -0,0 +1,63 @@
+# 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.
+
+# Tested on link
+gettid: 1
+getuid: 1
+geteuid: 1
+getgid: 1
+getegid: 1
+getresuid: 1
+getresgid: 1
+
+clock_getres: 1
+clock_gettime: 1
+gettimeofday: 1
+time: 1
+
+# Allow socket(domain==PF_LOCAL) or socket(domain==PF_NETLINK)
+socket: arg0 == 0x1 || arg0 == 0x10
+socketpair: 1
+connect: 1
+getsockname: 1
+pipe: 1
+sendmsg: 1
+sendto: 1
+recvmsg: 1
+recvfrom: 1
+
+epoll_create: 1
+epoll_wait: 1
+epoll_ctl: 1
+poll: 1
+
+open: 1
+read: 1
+write: 1
+close: 1
+
+fstat: 1
+stat: 1
+lseek: 1
+fcntl: 1
+
+futex: 1
+set_robust_list: 1
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+rt_sigprocmask: 1
+signalfd4: 1
+
+brk: 1
+mmap: 1
+madvise: 1
+mprotect: 1
+munmap: 1
+
+clone: 1
+# These calls are attempted but apparently not necessary; return EPERM.
+prctl: return 1
+ioctl: return 1
diff --git a/server/tpm_manager-seccomp-arm.policy b/server/tpm_manager-seccomp-arm.policy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/server/tpm_manager-seccomp-arm.policy
diff --git a/server/tpm_manager-seccomp-x86.policy b/server/tpm_manager-seccomp-x86.policy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/server/tpm_manager-seccomp-x86.policy
diff --git a/server/tpm_manager_service.cc b/server/tpm_manager_service.cc
new file mode 100644
index 0000000..f7077d4
--- /dev/null
+++ b/server/tpm_manager_service.cc
@@ -0,0 +1,114 @@
+// 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/tpm_manager_service.h"
+
+#include <base/callback.h>
+#include <base/command_line.h>
+#include <chromeos/bind_lambda.h>
+
+namespace tpm_manager {
+
+TpmManagerService::TpmManagerService(bool wait_for_ownership,
+ LocalDataStore* local_data_store,
+ TpmStatus* tpm_status,
+ TpmInitializer* tpm_initializer)
+ : local_data_store_(local_data_store),
+ tpm_status_(tpm_status),
+ tpm_initializer_(tpm_initializer),
+ 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>();
+ base::Closure task = base::Bind(&TpmManagerService::GetTpmStatusTask,
+ base::Unretained(this), request, result);
+ base::Closure reply = base::Bind(
+ &TpmManagerService::TaskRelayCallback<GetTpmStatusReply>,
+ weak_factory_.GetWeakPtr(),
+ callback,
+ result);
+ worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply);
+}
+
+void TpmManagerService::GetTpmStatusTask(
+ const GetTpmStatusRequest& request,
+ const std::shared_ptr<GetTpmStatusReply>& result) {
+ VLOG(1) << __func__;
+ result->set_enabled(tpm_status_->IsTpmEnabled());
+ result->set_owned(tpm_status_->IsTpmOwned());
+ LocalData local_data;
+ if (local_data_store_ && 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;
+ }
+ result->set_status(STATUS_SUCCESS);
+}
+
+} // namespace tpm_manager
diff --git a/server/tpm_manager_service.h b/server/tpm_manager_service.h
new file mode 100644
index 0000000..d715816
--- /dev/null
+++ b/server/tpm_manager_service.h
@@ -0,0 +1,103 @@
+// 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_MANAGER_SERVICE_H_
+#define TPM_MANAGER_SERVER_TPM_MANAGER_SERVICE_H_
+
+#include "tpm_manager/common/tpm_manager_interface.h"
+
+#include <memory>
+
+#include <base/callback.h>
+#include <base/macros.h>
+#include <base/memory/weak_ptr.h>
+#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
+// asynchronous, except for the initial setup in Initialize().
+// Usage:
+// std::unique_ptr<TpmManagerInterface> tpm_manager = new TpmManagerService();
+// CHECK(tpm_manager->Initialize());
+// tpm_manager->GetTpmStatus(...);
+//
+// THREADING NOTES:
+// This class runs a worker thread and delegates all calls to it. This keeps the
+// public methods non-blocking while allowing complex implementation details
+// with dependencies on the TPM, network, and filesystem to be coded in a more
+// readable way. It also serves to serialize method execution which reduces
+// complexity with TPM state.
+//
+// Tasks that run on the worker thread are bound with base::Unretained which is
+// safe because the thread is owned by this class (so it is guaranteed not to
+// process a task after destruction). Weak pointers are used to post replies
+// back to the main thread.
+class TpmManagerService : public TpmManagerInterface {
+ public:
+ // If |wait_for_ownership| is set, TPM initialization will be postponed until
+ // an explicit TakeOwnership request is received. Does not take ownership of
+ // |local_data_store|, |tpm_status| or |tpm_initializer|.
+ explicit TpmManagerService(bool wait_for_ownership,
+ LocalDataStore* local_data_store,
+ TpmStatus* tpm_status,
+ TpmInitializer* tpm_initializer);
+ ~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;
+
+ private:
+ // A relay callback which allows the use of weak pointer semantics for a reply
+ // to TaskRunner::PostTaskAndReply.
+ template<typename ReplyProtobufType>
+ void TaskRelayCallback(
+ const base::Callback<void(const ReplyProtobufType&)> callback,
+ const std::shared_ptr<ReplyProtobufType>& reply) {
+ callback.Run(*reply);
+ }
+
+ // Blocking implementation of GetTpmStatus that can be executed on the
+ // background worker thread.
+ void GetTpmStatusTask(const GetTpmStatusRequest& request,
+ const std::shared_ptr<GetTpmStatusReply>& result);
+
+ // 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_;
+ TpmStatus* tpm_status_;
+ TpmInitializer* tpm_initializer_;
+ // 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.
+ base::WeakPtrFactory<TpmManagerService> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(TpmManagerService);
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_TPM_MANAGER_SERVICE_H_
diff --git a/server/tpm_manager_service_test.cc b/server/tpm_manager_service_test.cc
new file mode 100644
index 0000000..d1c36fb
--- /dev/null
+++ b/server/tpm_manager_service_test.cc
@@ -0,0 +1,226 @@
+// 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*/,
+ &mock_local_data_store_,
+ &mock_tpm_status_,
+ &mock_tpm_initializer_));
+ 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() {
+ 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*/,
+ &mock_local_data_store_,
+ &mock_tpm_status_,
+ &mock_tpm_initializer_));
+ }
+};
+
+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_managerd.conf b/server/tpm_managerd.conf
new file mode 100644
index 0000000..60b5bc8
--- /dev/null
+++ b/server/tpm_managerd.conf
@@ -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.
+
+description "Chromium OS device tpm_manager service."
+author "chromium-os-dev@chromium.org"
+
+start on starting system-services
+stop on stopping system-services
+respawn
+
+# Minijail forks off our process
+expect fork
+
+exec minijail0 -i -g tpm_manager -u tpm_manager -G -n \
+ -S /usr/share/policy/tpm_managerd-seccomp.policy /usr/sbin/tpm_managerd
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/server/tpm_status_impl.cc b/server/tpm_status_impl.cc
new file mode 100644
index 0000000..f390e68
--- /dev/null
+++ b/server/tpm_status_impl.cc
@@ -0,0 +1,104 @@
+// 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/tpm_status_impl.h"
+
+#include <vector>
+
+#include <base/logging.h>
+#include <trousers/tss.h>
+#include <trousers/trousers.h> // NOLINT(build/include_alpha)
+
+namespace tpm_manager {
+
+// Minimum size of TPM_DA_INFO struct.
+const size_t kMinimumDaInfoSize = 21;
+
+bool TpmStatusImpl::IsTpmEnabled() {
+ if (!is_enable_initialized_) {
+ RefreshOwnedEnabledInfo();
+ }
+ return is_enabled_;
+}
+
+bool TpmStatusImpl::IsTpmOwned() {
+ if (!is_owned_) {
+ RefreshOwnedEnabledInfo();
+ }
+ return is_owned_;
+}
+
+bool TpmStatusImpl::GetDictionaryAttackInfo(int* counter,
+ int* threshold,
+ bool* lockout,
+ int* seconds_remaining) {
+ std::string capability_data;
+ if (!GetCapability(TSS_TPMCAP_DA_LOGIC, TPM_ET_KEYHANDLE,
+ &capability_data, nullptr) ||
+ capability_data.size() < kMinimumDaInfoSize) {
+ LOG(ERROR) << "Error getting tpm capability data.";
+ return false;
+ }
+ if (static_cast<uint16_t>(capability_data[1]) == TPM_TAG_DA_INFO) {
+ TPM_DA_INFO da_info;
+ uint64_t offset = 0;
+ std::vector<BYTE> bytes(capability_data.begin(), capability_data.end());
+ Trspi_UnloadBlob_DA_INFO(&offset, bytes.data(), &da_info);
+ if (counter) { *counter = da_info.currentCount; }
+ if (threshold) { *threshold = da_info.thresholdCount; }
+ if (lockout) { *lockout = (da_info.state == TPM_DA_STATE_ACTIVE); }
+ if (seconds_remaining) { *seconds_remaining = da_info.actionDependValue; }
+ }
+ return true;
+}
+
+void TpmStatusImpl::RefreshOwnedEnabledInfo() {
+ TSS_RESULT result;
+ std::string capability_data;
+ if (!GetCapability(TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_OWNER,
+ &capability_data, &result)) {
+ if (ERROR_CODE(result) == TPM_E_DISABLED) {
+ is_enable_initialized_ = true;
+ is_enabled_ = false;
+ }
+ } else {
+ is_enable_initialized_ = true;
+ is_enabled_ = true;
+ // |capability_data| should be populated with a TSS_BOOL which is true iff
+ // the Tpm is owned.
+ if (capability_data.size() != sizeof(TSS_BOOL)) {
+ LOG(ERROR) << "Error refreshing Tpm ownership information.";
+ return;
+ }
+ is_owned_ = (capability_data[0] != 0);
+ }
+}
+
+bool TpmStatusImpl::GetCapability(uint32_t capability,
+ uint32_t sub_capability,
+ std::string* data,
+ TSS_RESULT* tpm_result) {
+ CHECK(data);
+ TSS_HTPM tpm_handle = tpm_connection_.GetTpm();
+ if (tpm_handle == 0) {
+ return false;
+ }
+ uint32_t length = 0;
+ trousers::ScopedTssMemory buf(tpm_connection_.GetContext());
+ TSS_RESULT result = Tspi_TPM_GetCapability(
+ tpm_handle, capability, sizeof(uint32_t),
+ reinterpret_cast<BYTE*>(&sub_capability),
+ &length, buf.ptr());
+ if (tpm_result) {
+ *tpm_result = result;
+ }
+ if (TPM_ERROR(result)) {
+ LOG(ERROR) << "Error getting TPM capability data.";
+ return false;
+ }
+ data->assign(buf.value(), buf.value() + length);
+ return true;
+}
+
+} // namespace tpm_manager
diff --git a/server/tpm_status_impl.h b/server/tpm_status_impl.h
new file mode 100644
index 0000000..cbc3c88
--- /dev/null
+++ b/server/tpm_status_impl.h
@@ -0,0 +1,56 @@
+// 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_IMPL_H_
+#define TPM_MANAGER_SERVER_TPM_STATUS_IMPL_H_
+
+#include "tpm_manager/server/tpm_status.h"
+
+#include <memory>
+#include <string>
+
+#include <base/macros.h>
+#include <trousers/tss.h>
+#include <trousers/trousers.h> // NOLINT(build/include_alpha)
+
+#include <tpm_manager/server/tpm_connection.h>
+
+namespace tpm_manager {
+
+class TpmStatusImpl : public TpmStatus {
+ public:
+ TpmStatusImpl() = default;
+ ~TpmStatusImpl() override = default;
+
+ // TpmState methods.
+ bool IsTpmEnabled() override;
+ bool IsTpmOwned() override;
+ bool GetDictionaryAttackInfo(int* counter,
+ int* threshold,
+ bool* lockout,
+ int* seconds_remaining) override;
+
+ private:
+ // This method refreshes the |is_owned_| and |is_enabled_| status of the
+ // Tpm. It can be called multiple times.
+ void RefreshOwnedEnabledInfo();
+ // This method wraps calls to Tspi_TPM_GetCapability. |data| is set to
+ // the raw capability data. If the optional out argument |tpm_result| is
+ // provided, it is set to the result of the |Tspi_TPM_GetCapability| call.
+ bool GetCapability(uint32_t capability,
+ uint32_t sub_capability,
+ std::string* data,
+ TSS_RESULT* tpm_result);
+
+ TpmConnection tpm_connection_;
+ bool is_enabled_{false};
+ bool is_owned_{false};
+ bool is_enable_initialized_{false};
+
+ DISALLOW_COPY_AND_ASSIGN(TpmStatusImpl);
+};
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_TPM_STATUS_IMPL_H_
diff --git a/server/tpm_util.h b/server/tpm_util.h
new file mode 100644
index 0000000..3b7c93b
--- /dev/null
+++ b/server/tpm_util.h
@@ -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.
+
+#ifndef TPM_MANAGER_SERVER_TPM_UTIL_H_
+#define TPM_MANAGER_SERVER_TPM_UTIL_H_
+
+namespace tpm_manager {
+
+#define TPM_LOG(severity, result) \
+ LOG(severity) << "TPM error 0x" << std::hex << result \
+ << " (" << Trspi_Error_String(result) << "): "
+
+} // namespace tpm_manager
+
+#endif // TPM_MANAGER_SERVER_TPM_UTIL_H_
diff --git a/tpm_manager.gyp b/tpm_manager.gyp
new file mode 100644
index 0000000..1f213ad
--- /dev/null
+++ b/tpm_manager.gyp
@@ -0,0 +1,163 @@
+# 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.
+
+{
+ 'target_defaults': {
+ 'includes': ['../common-mk/common.gypi'],
+ 'variables': {
+ 'deps': [ # This is a list of pkg-config dependencies
+ 'libchrome-<(libbase_ver)',
+ 'libchromeos-<(libbase_ver)',
+ 'openssl',
+ 'protobuf-lite',
+ ],
+ },
+ 'defines': [ 'USE_TPM2=<(USE_tpm2)' ],
+ },
+ 'targets': [
+ # A library for just the protobufs.
+ {
+ 'target_name': 'proto_library',
+ 'type': 'static_library',
+ 'variables': {
+ 'proto_in_dir': 'common',
+ 'proto_out_dir': 'include/tpm_manager/common',
+ },
+ 'sources': [
+ '<(proto_in_dir)/dbus_interface.proto',
+ '<(proto_in_dir)/local_data.proto',
+ 'common/print_dbus_interface_proto.cc',
+ 'common/print_local_data_proto.cc',
+ ],
+ 'includes': ['../common-mk/protoc.gypi'],
+ },
+ # A shared library for clients.
+ {
+ 'target_name': 'libtpm_manager',
+ 'type': 'shared_library',
+ 'sources': [
+ 'client/dbus_proxy.cc',
+ ],
+ 'dependencies': [
+ 'proto_library',
+ ],
+ },
+ # A client command line utility.
+ {
+ 'target_name': 'tpm_manager_client',
+ 'type': 'executable',
+ 'sources': [
+ 'client/main.cc',
+ ],
+ 'dependencies': [
+ 'libtpm_manager',
+ 'proto_library',
+ ]
+ },
+ # A library for server code.
+ {
+ 'target_name': 'server_library',
+ 'type': 'static_library',
+ 'sources': [
+ 'server/dbus_service.cc',
+ 'server/local_data_store_impl.cc',
+ 'server/openssl_crypto_util.cc',
+ 'server/tpm_manager_service.cc',
+ ],
+ 'conditions': [
+ ['USE_tpm2 == 1', {
+ 'sources': [
+ 'server/tpm2_status_impl.cc',
+ 'server/tpm2_initializer_impl.cc',
+ ],
+ 'all_dependent_settings': {
+ 'libraries': [
+ '-ltrunks',
+ ],
+ },
+ }],
+ ['USE_tpm2 == 0', {
+ 'sources': [
+ 'server/tpm_connection.cc',
+ 'server/tpm_status_impl.cc',
+ 'server/tpm_initializer_impl.cc',
+ ],
+ 'all_dependent_settings': {
+ 'libraries': [
+ '-ltspi',
+ ],
+ },
+ }],
+ ],
+ 'dependencies': [
+ 'proto_library',
+ ],
+ },
+ # The tpm_manager daemon.
+ {
+ 'target_name': 'tpm_managerd',
+ 'type': 'executable',
+ 'sources': [
+ 'server/main.cc',
+ ],
+ 'variables': {
+ 'deps': [
+ 'libminijail',
+ ],
+ },
+ 'dependencies': [
+ 'proto_library',
+ 'server_library',
+ ],
+ },
+ ],
+ 'conditions': [
+ ['USE_test == 1', {
+ 'targets': [
+ {
+ 'target_name': 'tpm_manager_testrunner',
+ 'type': 'executable',
+ 'includes': ['../common-mk/common_test.gypi'],
+ 'variables': {
+ 'deps': [
+ 'libchrome-test-<(libbase_ver)',
+ 'libchromeos-test-<(libbase_ver)',
+ ],
+ },
+ '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',
+ ],
+ 'conditions': [
+ ['USE_tpm2 == 1', {
+ 'sources': [
+ '../trunks/mock_blob_parser.cc',
+ '../trunks/mock_hmac_session.cc',
+ '../trunks/mock_policy_session.cc',
+ '../trunks/mock_session_manager.cc',
+ '../trunks/mock_tpm.cc',
+ '../trunks/mock_tpm_state.cc',
+ '../trunks/mock_tpm_utility.cc',
+ '../trunks/trunks_factory_for_test.cc',
+ 'server/tpm2_status_test.cc',
+ 'server/tpm2_initializer_test.cc',
+ ],
+ }],
+ ],
+ 'dependencies': [
+ 'libtpm_manager',
+ 'proto_library',
+ 'server_library',
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/tpm_manager_testrunner.cc b/tpm_manager_testrunner.cc
new file mode 100644
index 0000000..3380ea6
--- /dev/null
+++ b/tpm_manager_testrunner.cc
@@ -0,0 +1,19 @@
+// 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/at_exit.h>
+#include <base/command_line.h>
+#include <base/logging.h>
+#include <chromeos/syslog_logging.h>
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+ base::CommandLine::Init(argc, argv);
+ chromeos::InitLog(chromeos::kLogToStderr);
+ // Enable verbose logging while running unit tests.
+ logging::SetMinLogLevel(logging::LOG_VERBOSE);
+ base::AtExitManager exit_manager;
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}