blob: 2bcd58d9a2f328035e60f2772ab878416e5fd260 [file] [log] [blame]
// 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_handle_impl.h"
#include <fcntl.h>
#include <unistd.h>
#include <base/logging.h>
#include <base/posix/eintr_wrapper.h>
#include <base/sys_byteorder.h>
namespace {
const char kTpmDevice[] = "/dev/tpm0";
const uint32_t kTpmBufferSize = 4096;
const int kInvalidFileDescriptor = -1;
const uint32_t kTpmHeaderLength = 10;
const uint32_t kTpmHeaderLengthIndex = 2;
} // namespace
namespace trunks {
TpmHandleImpl::TpmHandleImpl(): fd_(kInvalidFileDescriptor) {}
TpmHandleImpl::~TpmHandleImpl() {
int result = IGNORE_EINTR(close(fd_));
if (result == -1) {
PLOG(ERROR) << "TPM: couldn't close " << kTpmDevice;
}
LOG(INFO) << "TPM: " << kTpmDevice << " closed successfully";
}
TPM_RC TpmHandleImpl::Init() {
CHECK_EQ(fd_, kInvalidFileDescriptor);
fd_ = HANDLE_EINTR(open(kTpmDevice, O_RDWR));
if (fd_ == kInvalidFileDescriptor) {
PLOG(ERROR) << "TPM: Error opening tpm0 file descriptor at " << kTpmDevice;
return TCTI_RC_GENERAL_FAILURE;
}
LOG(INFO) << "TPM: " << kTpmDevice << " opened successfully";
return TPM_RC_SUCCESS;
}
TPM_RC TpmHandleImpl::SendCommand(const std::string& command,
std::string* response) {
CHECK_NE(fd_, kInvalidFileDescriptor);
TPM_RC command_verify = VerifyCommand(command);
if (command_verify != TPM_RC_SUCCESS) {
return command_verify;
}
int result = HANDLE_EINTR(write(fd_, command.data(), command.length()));
if (result < 0 || static_cast<uint32_t>(result) < kTpmHeaderLength) {
PLOG(ERROR) << "TPM: Error writing to TPM Handle";
return TRUNKS_RC_WRITE_ERROR;
}
char response_buf[kTpmBufferSize];
result = HANDLE_EINTR(read(fd_, response_buf, kTpmBufferSize));
if (result < 0 || static_cast<uint32_t>(result) < kTpmHeaderLength) {
PLOG(ERROR) << "TPM: Error reading from TPM Handle";
return TRUNKS_RC_READ_ERROR;
}
response->assign(response_buf, static_cast<size_t>(result));
return TPM_RC_SUCCESS;
}
TPM_RC TpmHandleImpl::VerifyCommand(const std::string& command) {
uint32_t length = command.length();
if (length > kTpmBufferSize) {
LOG(ERROR) << "TPM: command length: " << length
<< " exceeds TPM buffer length: " << kTpmBufferSize;
return TCTI_RC_INSUFFICIENT_BUFFER;
}
if (length < kTpmHeaderLength) {
LOG(ERROR) << "TPM: command length " << length
<< " is smaller than TPM header length.";
return TCTI_RC_BAD_PARAMETER;
}
size_t command_length = GetMessageLength(command.data());
if (command_length != length) {
LOG(ERROR) << "TPM: length to transmit is: " << length
<< " but tpm_header says length is: " << command_length;
return TCTI_RC_BAD_PARAMETER;
}
VLOG(1) << "TPM: Command successfully verified.";
return TPM_RC_SUCCESS;
}
uint32_t TpmHandleImpl::GetMessageLength(const char* tpm_header) {
uint32_t value = 0;
memcpy(&value, &tpm_header[kTpmHeaderLengthIndex], sizeof(uint32_t));
return base::NetToHost32(value);
}
} // namespace trunks