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 
26 namespace {
27 
28 const char kTpmDevice[] = "/dev/tpm0";
29 const uint32_t kTpmBufferSize = 4096;
30 const int kInvalidFileDescriptor = -1;
31 
32 }  // namespace
33 
34 namespace trunks {
35 
TpmHandle()36 TpmHandle::TpmHandle() : fd_(kInvalidFileDescriptor) {}
37 
~TpmHandle()38 TpmHandle::~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 
Init()46 bool 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 
SendCommand(const std::string & command,const ResponseCallback & callback)60 void TpmHandle::SendCommand(const std::string& command,
61                             const ResponseCallback& callback) {
62   callback.Run(SendCommandAndWait(command));
63 }
64 
SendCommandAndWait(const std::string & command)65 std::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 
SendCommandInternal(const std::string & command,std::string * response)74 TPM_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