trunks: Add tpm simulator handle.
Add a handle so trunks can talk to a TPM simulator.
TEST=$ sudo tpm-simulator // in one terminal
$ sudo trunksd --simulator // in another terminal
run trunks_client in another terminal. --startup, --clear,
and --status all success. --own --owner_password="" fails
during salting key generation.
BUG=none
Change-Id: I815bf7cf11d6def69b7a5600dbb509b6d231ce19
Signed-off-by: Jocelyn Bohr <bohr@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/293570
Reviewed-by: Utkarsh Sanghi <usanghi@chromium.org>
diff --git a/tpm_simulator_handle.cc b/tpm_simulator_handle.cc
new file mode 100644
index 0000000..cae6b48
--- /dev/null
+++ b/tpm_simulator_handle.cc
@@ -0,0 +1,103 @@
+// Copyright 2014 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 "trunks/tpm_simulator_handle.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <base/callback.h>
+#include <base/logging.h>
+#include <base/posix/eintr_wrapper.h>
+
+namespace {
+
+const char kTpmSimRequestFile[] = "/dev/tpm-req";
+const char kTpmSimResponseFile[] = "/dev/tpm-resp";
+const uint32_t kTpmBufferSize = 4096;
+const int kInvalidFileDescriptor = -1;
+
+} // namespace
+
+namespace trunks {
+
+TpmSimulatorHandle::TpmSimulatorHandle() :
+ req_fd_(kInvalidFileDescriptor), resp_fd_(kInvalidFileDescriptor) {}
+
+TpmSimulatorHandle::~TpmSimulatorHandle() {
+ int result = IGNORE_EINTR(close(req_fd_));
+ if (result == -1) {
+ PLOG(ERROR) << "TPM: couldn't close " << kTpmSimRequestFile;
+ } else {
+ LOG(INFO) << "TPM: " << kTpmSimRequestFile << " closed successfully";
+ }
+ result = IGNORE_EINTR(close(resp_fd_));
+ if (result == -1) {
+ PLOG(ERROR) << "TPM: couldn't close " << kTpmSimResponseFile;
+ } else {
+ LOG(INFO) << "TPM: " << kTpmSimResponseFile << " closed successfully";
+ }
+}
+
+bool TpmSimulatorHandle::Init() {
+ if (req_fd_ == kInvalidFileDescriptor) {
+ req_fd_ = HANDLE_EINTR(open("/dev/tpm-req", O_RDWR));
+ if (req_fd_ == kInvalidFileDescriptor) {
+ PLOG(ERROR) << "TPM: Error opening file descriptor at "
+ << kTpmSimRequestFile;
+ return false;
+ }
+ LOG(INFO) << "TPM: " << kTpmSimRequestFile << " opened successfully";
+ }
+ if (resp_fd_ == kInvalidFileDescriptor) {
+ resp_fd_ = HANDLE_EINTR(open("/dev/tpm-resp", O_RDWR));
+ if (resp_fd_ == kInvalidFileDescriptor) {
+ PLOG(ERROR) << "TPM: Error opening file descriptor at "
+ << kTpmSimResponseFile;
+ return false;
+ }
+ LOG(INFO) << "TPM: " << kTpmSimResponseFile << " opened successfully";
+ }
+ return true;
+}
+
+void TpmSimulatorHandle::SendCommand(const std::string& command,
+ const ResponseCallback& callback) {
+ callback.Run(SendCommandAndWait(command));
+}
+
+std::string TpmSimulatorHandle::SendCommandAndWait(const std::string& command) {
+ std::string response;
+ TPM_RC result = SendCommandInternal(command, &response);
+ if (result != TPM_RC_SUCCESS) {
+ response = CreateErrorResponse(result);
+ }
+ return response;
+}
+
+TPM_RC TpmSimulatorHandle::SendCommandInternal(const std::string& command,
+ std::string* response) {
+ CHECK_NE(req_fd_, kInvalidFileDescriptor);
+ CHECK_NE(resp_fd_, kInvalidFileDescriptor);
+ int result = HANDLE_EINTR(write(req_fd_, command.data(), command.length()));
+ if (result < 0) {
+ PLOG(ERROR) << "TPM: Error writing to TPM simulator request handle.";
+ return TRUNKS_RC_WRITE_ERROR;
+ }
+ if (static_cast<size_t>(result) != command.length()) {
+ LOG(ERROR) << "TPM: Error writing to TPM simulator request handle: "
+ << result << " vs " << command.length();
+ return TRUNKS_RC_WRITE_ERROR;
+ }
+ char response_buf[kTpmBufferSize];
+ result = HANDLE_EINTR(read(resp_fd_, response_buf, kTpmBufferSize));
+ if (result < 0) {
+ PLOG(ERROR) << "TPM: Error reading from TPM simulator response handle.";
+ return TRUNKS_RC_READ_ERROR;
+ }
+ response->assign(response_buf, static_cast<size_t>(result));
+ return TPM_RC_SUCCESS;
+}
+
+} // namespace trunks
diff --git a/tpm_simulator_handle.h b/tpm_simulator_handle.h
new file mode 100644
index 0000000..bf406ec
--- /dev/null
+++ b/tpm_simulator_handle.h
@@ -0,0 +1,53 @@
+// Copyright 2014 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 TRUNKS_TPM_SIMULATOR_HANDLE_H_
+#define TRUNKS_TPM_SIMULATOR_HANDLE_H_
+
+#include "trunks/command_transceiver.h"
+
+#include <string>
+
+#include "trunks/error_codes.h"
+
+namespace trunks {
+
+// Sends command requests to a software TPM via a handle to /dev/tpm-req.
+// Receives command responses via a handle to /dev/tpm-resp. All commands are
+// sent synchronously. The SendCommand method is supported but does not return
+// until a response is received and the callback has been called. Command and
+// response data are opaque to this class; it performs no validation.
+//
+// Example:
+// TpmSimulatorHandle handle;
+// if (!handle.Init()) {...}
+// std::string response = handle.SendCommandAndWait(command);
+class TpmSimulatorHandle : public CommandTransceiver {
+ public:
+ TpmSimulatorHandle();
+ ~TpmSimulatorHandle() override;
+
+ // Initializes a TpmSimulatorHandle instance. This method must be called
+ // successfully before any other method. Returns true on success.
+ bool Init() override;
+
+ // CommandTranceiver methods.
+ void SendCommand(const std::string& command,
+ const ResponseCallback& callback) override;
+ std::string SendCommandAndWait(const std::string& command) override;
+
+ private:
+ // Writes a |command| to /dev/tpm-req and reads the |response| from
+ // /dev/tpm-resp. Returns TPM_RC_SUCCESS on success.
+ TPM_RC SendCommandInternal(const std::string& command, std::string* response);
+
+ int req_fd_; // A file descriptor for /dev/tpm-req.
+ int resp_fd_; // A file descriptor for /dev/tpm-resp.
+
+ DISALLOW_COPY_AND_ASSIGN(TpmSimulatorHandle);
+};
+
+} // namespace trunks
+
+#endif // TRUNKS_TPM_SIMULATOR_HANDLE_H_
diff --git a/trunks.gyp b/trunks.gyp
index 0084ac7..a352565 100644
--- a/trunks.gyp
+++ b/trunks.gyp
@@ -83,6 +83,7 @@
'background_command_transceiver.cc',
'resource_manager.cc',
'tpm_handle.cc',
+ 'tpm_simulator_handle.cc',
'trunks_service.cc',
],
'dependencies': [
diff --git a/trunksd.cc b/trunksd.cc
index f825177..106f6fa 100644
--- a/trunksd.cc
+++ b/trunksd.cc
@@ -18,6 +18,7 @@
#include "trunks/dbus_interface.h"
#include "trunks/resource_manager.h"
#include "trunks/tpm_handle.h"
+#include "trunks/tpm_simulator_handle.h"
#include "trunks/trunks_factory_impl.h"
#include "trunks/trunks_ftdi_spi.h"
#include "trunks/trunks_service.h"
@@ -107,6 +108,8 @@
trunks::CommandTransceiver *transceiver;
if (cl->HasSwitch("ftdi")) {
transceiver = new trunks::TrunksFtdiSpi();
+ } else if (cl->HasSwitch("simulator")) {
+ transceiver = new trunks::TpmSimulatorHandle();
} else {
transceiver = new trunks::TpmHandle();
}