• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2020 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 #include "in_process_tpm.h"
17 
18 #include <endian.h>
19 #include <stddef.h>
20 
21 #include <tss2/tss2_esys.h>
22 #include <tss2/tss2_rc.h>
23 
24 #include "host/commands/secure_env/tpm_commands.h"
25 
26 extern "C" {
27 typedef int SOCKET;
28 #include "TpmBuildSwitches.h"
29 #include "TpmTcpProtocol.h"
30 #include "Simulator_fp.h"
31 #include "Manufacture_fp.h"
32 #define delete delete_
33 #include "Platform_fp.h"
34 #undef delete
35 #undef DEBUG
36 }
37 
38 #include <android-base/logging.h>
39 
40 struct __attribute__((__packed__)) tpm_message_header {
41   uint16_t tag;
42   uint32_t length;
43   uint32_t ordinal;
44 };
45 
46 struct InProcessTpm::Impl {
FromContextInProcessTpm::Impl47   static Impl* FromContext(TSS2_TCTI_CONTEXT* context) {
48     auto offset = offsetof(Impl, tcti_context_);
49     char* context_char = reinterpret_cast<char*>(context);
50     return reinterpret_cast<Impl*>(context_char - offset);
51   }
52 
TransmitInProcessTpm::Impl53   static TSS2_RC Transmit(
54       TSS2_TCTI_CONTEXT *context, size_t size, uint8_t const *command) {
55     auto impl = FromContext(context);
56     std::lock_guard lock(impl->queue_mutex_);
57     impl->command_queue_.emplace_back(command, command + size);
58     return TSS2_RC_SUCCESS;
59   }
60 
ReceiveInProcessTpm::Impl61   static TSS2_RC Receive(
62       TSS2_TCTI_CONTEXT *context,
63       size_t* size,
64       uint8_t* response,
65       int32_t /* timeout */) {
66     auto impl = FromContext(context);
67     // TODO(schuffelen): Use the timeout argument
68     std::vector<uint8_t> request;
69     {
70       std::lock_guard lock(impl->queue_mutex_);
71       if (impl->command_queue_.empty()) {
72         return TSS2_TCTI_RC_GENERAL_FAILURE;
73       }
74       request = std::move(impl->command_queue_.front());
75       impl->command_queue_.pop_front();
76     }
77     auto header = reinterpret_cast<tpm_message_header*>(request.data());
78     LOG(VERBOSE) << "Sending TPM command "
79                 << TpmCommandName(be32toh(header->ordinal));
80     _IN_BUFFER input = {
81         .BufferSize = request.size(),
82         .Buffer = request.data(),
83     };
84     _OUT_BUFFER output = {
85         .BufferSize = (uint32_t) *size,
86         .Buffer = response,
87     };
88     _rpc__Send_Command(3, input, &output);
89     *size = output.BufferSize;
90     header = reinterpret_cast<tpm_message_header*>(response);
91     auto rc = be32toh(header->ordinal);
92     LOG(VERBOSE) << "Received TPM response " << Tss2_RC_Decode(rc)
93                 << " (" << rc << ")";
94     return TSS2_RC_SUCCESS;
95   }
96 
97   TSS2_TCTI_CONTEXT_COMMON_CURRENT tcti_context_;
98   std::list<std::vector<uint8_t>> command_queue_;
99   std::mutex queue_mutex_;
100 };
101 
InProcessTpm()102 InProcessTpm::InProcessTpm() : impl_(new Impl()) {
103   impl_->tcti_context_.v1.magic = 0xFAD;
104   impl_->tcti_context_.v1.version = 1;
105   impl_->tcti_context_.v1.transmit = Impl::Transmit;
106   impl_->tcti_context_.v1.receive = Impl::Receive;
107   _plat__NVEnable(NULL);
108   if (_plat__NVNeedsManufacture()) {
109     // Can't use android logging here due to a macro conflict with TPM internals
110     LOG(DEBUG) << "Manufacturing TPM state";
111     if (TPM_Manufacture(1)) {
112       LOG(FATAL) << "Failed to manufacture TPM state";
113     }
114   }
115   _rpc__Signal_PowerOn(false);
116   _rpc__Signal_NvOn();
117 
118   ESYS_CONTEXT* esys = nullptr;
119   auto rc = Esys_Initialize(&esys, TctiContext(), nullptr);
120   if (rc != TPM2_RC_SUCCESS) {
121     LOG(FATAL) << "Could not initialize esys: " << Tss2_RC_Decode(rc)
122                << " (" << rc << ")";
123   }
124 
125   rc = Esys_Startup(esys, TPM2_SU_CLEAR);
126   if (rc != TPM2_RC_SUCCESS) {
127     LOG(FATAL) << "TPM2_Startup failed: " << Tss2_RC_Decode(rc)
128                << " (" << rc << ")";
129   }
130 
131   TPM2B_AUTH auth = {};
132   Esys_TR_SetAuth(esys, ESYS_TR_RH_LOCKOUT, &auth);
133 
134   rc = Esys_DictionaryAttackLockReset(
135     /* esysContext */ esys,
136     /* lockHandle */ ESYS_TR_RH_LOCKOUT,
137     /* shandle1 */ ESYS_TR_PASSWORD,
138     /* shandle2 */ ESYS_TR_NONE,
139     /* shandle3 */ ESYS_TR_NONE);
140 
141   if (rc != TPM2_RC_SUCCESS) {
142     LOG(FATAL) << "Could not reset TPM lockout: " << Tss2_RC_Decode(rc)
143                << " (" << rc << ")";
144   }
145 
146   Esys_Finalize(&esys);
147 }
148 
~InProcessTpm()149 InProcessTpm::~InProcessTpm() {
150   _rpc__Signal_NvOff();
151   _rpc__Signal_PowerOff();
152 }
153 
TctiContext()154 TSS2_TCTI_CONTEXT* InProcessTpm::TctiContext() {
155   return reinterpret_cast<TSS2_TCTI_CONTEXT*>(&impl_->tcti_context_);
156 }
157