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 <stddef.h>
19
20 #include <tss2/tss2_esys.h>
21 #include <tss2/tss2_rc.h>
22
23 #include <android-base/endian.h>
24
25 #include "host/commands/secure_env/tpm_commands.h"
26
27 extern "C" {
28 #ifndef _WIN32
29 typedef int SOCKET;
30 #endif
31 #include "TpmBuildSwitches.h"
32 #include "TpmTcpProtocol.h"
33 #pragma clang diagnostic push
34 #pragma clang diagnostic ignored "-Wmain" // tolerate extern "C" int main()
35 #include "Simulator_fp.h"
36 #pragma clang diagnostic pop
37 #include "Manufacture_fp.h"
38 #define delete delete_
39 #include "Platform_fp.h"
40 #undef delete
41 #undef DEBUG
42 }
43
44 #include <android-base/logging.h>
45
46 #include <mutex>
47
48 namespace cuttlefish {
49
50 struct __attribute__((__packed__)) tpm_message_header {
51 uint16_t tag;
52 uint32_t length;
53 uint32_t ordinal;
54 };
55
56 class InProcessTpm::Impl {
57 public:
FromContext(TSS2_TCTI_CONTEXT * context)58 static Impl* FromContext(TSS2_TCTI_CONTEXT* context) {
59 auto offset = offsetof(Impl, tcti_context_);
60 char* context_char = reinterpret_cast<char*>(context);
61 return reinterpret_cast<Impl*>(context_char - offset);
62 }
63
Transmit(TSS2_TCTI_CONTEXT * context,size_t size,uint8_t const * command)64 static TSS2_RC Transmit(
65 TSS2_TCTI_CONTEXT *context, size_t size, uint8_t const *command) {
66 auto impl = FromContext(context);
67 std::lock_guard lock(impl->queue_mutex_);
68 impl->command_queue_.emplace_back(command, command + size);
69 return TSS2_RC_SUCCESS;
70 }
71
Receive(TSS2_TCTI_CONTEXT * context,size_t * size,uint8_t * response,int32_t)72 static TSS2_RC Receive(
73 TSS2_TCTI_CONTEXT *context,
74 size_t* size,
75 uint8_t* response,
76 int32_t /* timeout */) {
77 auto impl = FromContext(context);
78 // TODO(schuffelen): Use the timeout argument
79 std::vector<uint8_t> request;
80 {
81 std::lock_guard lock(impl->queue_mutex_);
82 if (impl->command_queue_.empty()) {
83 return TSS2_TCTI_RC_GENERAL_FAILURE;
84 }
85 request = std::move(impl->command_queue_.front());
86 impl->command_queue_.pop_front();
87 }
88 auto header = reinterpret_cast<tpm_message_header*>(request.data());
89 LOG(VERBOSE) << "Sending TPM command "
90 << TpmCommandName(be32toh(header->ordinal));
91 _IN_BUFFER input = {
92 .BufferSize = static_cast<unsigned long>(request.size()),
93 .Buffer = request.data(),
94 };
95 _OUT_BUFFER output = {
96 .BufferSize = (uint32_t) *size,
97 .Buffer = response,
98 };
99 _rpc__Send_Command(3, input, &output);
100 *size = output.BufferSize;
101 header = reinterpret_cast<tpm_message_header*>(response);
102 auto rc = be32toh(header->ordinal);
103 LOG(VERBOSE) << "Received TPM response " << Tss2_RC_Decode(rc)
104 << " (" << rc << ")";
105 return TSS2_RC_SUCCESS;
106 }
107
Impl()108 Impl() {
109 {
110 std::lock_guard<std::mutex> lock(global_mutex);
111 // This is a limitation of ms-tpm-20-ref
112 CHECK(!global_instance) << "InProcessTpm internally uses global data, so "
113 << "only one can exist.";
114 global_instance = this;
115 }
116
117 tcti_context_.v1.magic = 0xFAD;
118 tcti_context_.v1.version = 1;
119 tcti_context_.v1.transmit = Impl::Transmit;
120 tcti_context_.v1.receive = Impl::Receive;
121 _plat__NVEnable(NULL);
122 if (_plat__NVNeedsManufacture()) {
123 // Can't use android logging here due to a macro conflict with TPM
124 // internals
125 LOG(DEBUG) << "Manufacturing TPM state";
126 if (TPM_Manufacture(1)) {
127 LOG(FATAL) << "Failed to manufacture TPM state";
128 }
129 }
130 _rpc__Signal_PowerOn(false);
131 _rpc__Signal_NvOn();
132
133 ESYS_CONTEXT* esys = nullptr;
134 auto rc = Esys_Initialize(&esys, TctiContext(), nullptr);
135 if (rc != TPM2_RC_SUCCESS) {
136 LOG(FATAL) << "Could not initialize esys: " << Tss2_RC_Decode(rc) << " ("
137 << rc << ")";
138 }
139
140 rc = Esys_Startup(esys, TPM2_SU_CLEAR);
141 if (rc != TPM2_RC_SUCCESS) {
142 LOG(FATAL) << "TPM2_Startup failed: " << Tss2_RC_Decode(rc) << " (" << rc
143 << ")";
144 }
145
146 TPM2B_AUTH auth = {};
147 Esys_TR_SetAuth(esys, ESYS_TR_RH_LOCKOUT, &auth);
148
149 rc = Esys_DictionaryAttackLockReset(
150 /* esysContext */ esys,
151 /* lockHandle */ ESYS_TR_RH_LOCKOUT,
152 /* shandle1 */ ESYS_TR_PASSWORD,
153 /* shandle2 */ ESYS_TR_NONE,
154 /* shandle3 */ ESYS_TR_NONE);
155
156 if (rc != TPM2_RC_SUCCESS) {
157 LOG(FATAL) << "Could not reset TPM lockout: " << Tss2_RC_Decode(rc)
158 << " (" << rc << ")";
159 }
160
161 Esys_Finalize(&esys);
162 }
163
~Impl()164 ~Impl() {
165 _rpc__Signal_NvOff();
166 _rpc__Signal_PowerOff();
167 std::lock_guard<std::mutex> lock(global_mutex);
168 global_instance = nullptr;
169 }
170
TctiContext()171 TSS2_TCTI_CONTEXT* TctiContext() {
172 return reinterpret_cast<TSS2_TCTI_CONTEXT*>(&tcti_context_);
173 }
174
175 private:
176 static std::mutex global_mutex;
177 static Impl* global_instance;
178 TSS2_TCTI_CONTEXT_COMMON_CURRENT tcti_context_;
179 std::list<std::vector<uint8_t>> command_queue_;
180 std::mutex queue_mutex_;
181 };
182
183 std::mutex InProcessTpm::Impl::global_mutex;
184 InProcessTpm::Impl* InProcessTpm::Impl::global_instance;
185
InProcessTpm()186 InProcessTpm::InProcessTpm() : impl_(new Impl()) {}
187
188 InProcessTpm::~InProcessTpm() = default;
189
TctiContext()190 TSS2_TCTI_CONTEXT* InProcessTpm::TctiContext() { return impl_->TctiContext(); }
191
192 } // namespace cuttlefish
193