1//
2// Copyright (C) 2014 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "trunks/tpm_handle.h"
18
19#include <fcntl.h>
20#include <unistd.h>
21
22#include <base/callback.h>
23#include <base/logging.h>
24#include <base/posix/eintr_wrapper.h>
25
26namespace {
27
28const char kTpmDevice[] = "/dev/tpm0";
29const uint32_t kTpmBufferSize = 4096;
30const int kInvalidFileDescriptor = -1;
31
32}  // namespace
33
34namespace trunks {
35
36TpmHandle::TpmHandle() : fd_(kInvalidFileDescriptor) {}
37
38TpmHandle::~TpmHandle() {
39  int result = IGNORE_EINTR(close(fd_));
40  if (result == -1) {
41    PLOG(ERROR) << "TPM: couldn't close " << kTpmDevice;
42  }
43  LOG(INFO) << "TPM: " << kTpmDevice << " closed successfully";
44}
45
46bool TpmHandle::Init() {
47  if (fd_ != kInvalidFileDescriptor) {
48    VLOG(1) << "Tpm already initialized.";
49    return true;
50  }
51  fd_ = HANDLE_EINTR(open(kTpmDevice, O_RDWR));
52  if (fd_ == kInvalidFileDescriptor) {
53    PLOG(ERROR) << "TPM: Error opening tpm0 file descriptor at " << kTpmDevice;
54    return false;
55  }
56  LOG(INFO) << "TPM: " << kTpmDevice << " opened successfully";
57  return true;
58}
59
60void TpmHandle::SendCommand(const std::string& command,
61                            const ResponseCallback& callback) {
62  callback.Run(SendCommandAndWait(command));
63}
64
65std::string TpmHandle::SendCommandAndWait(const std::string& command) {
66  std::string response;
67  TPM_RC result = SendCommandInternal(command, &response);
68  if (result != TPM_RC_SUCCESS) {
69    response = CreateErrorResponse(result);
70  }
71  return response;
72}
73
74TPM_RC TpmHandle::SendCommandInternal(const std::string& command,
75                                      std::string* response) {
76  CHECK_NE(fd_, kInvalidFileDescriptor);
77  int result = HANDLE_EINTR(write(fd_, command.data(), command.length()));
78  if (result < 0) {
79    PLOG(ERROR) << "TPM: Error writing to TPM handle.";
80    return TRUNKS_RC_WRITE_ERROR;
81  }
82  if (static_cast<size_t>(result) != command.length()) {
83    LOG(ERROR) << "TPM: Error writing to TPM handle: " << result << " vs "
84               << command.length();
85    return TRUNKS_RC_WRITE_ERROR;
86  }
87  char response_buf[kTpmBufferSize];
88  result = HANDLE_EINTR(read(fd_, response_buf, kTpmBufferSize));
89  if (result < 0) {
90    PLOG(ERROR) << "TPM: Error reading from TPM handle.";
91    return TRUNKS_RC_READ_ERROR;
92  }
93  response->assign(response_buf, static_cast<size_t>(result));
94  return TPM_RC_SUCCESS;
95}
96
97}  // namespace trunks
98