blob: ec1770b4ec6fdedf0316065ff3e5d4c9ae553ec3 [file] [log] [blame]
Zentaro Kavanagh04eb2b02018-10-25 18:21:22 -07001// Copyright 2018 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "libtpmcrypto/tpm1_impl.h"
6
Amin Hassani3ee8c802018-10-24 17:01:45 -07007#include <memory>
8#include <string>
9
Qijiang Fan713061e2021-03-08 15:45:12 +090010#include <base/check.h>
Zentaro Kavanagh04eb2b02018-10-25 18:21:22 -070011#include <base/logging.h>
12#include <base/threading/platform_thread.h>
13#include <base/time/time.h>
14#include <brillo/secure_blob.h>
15#include <trousers/scoped_tss_type.h>
16
17using base::PlatformThread;
18using base::TimeDelta;
19using brillo::Blob;
20using brillo::SecureBlob;
21using trousers::ScopedTssContext;
22using trousers::ScopedTssKey;
23using trousers::ScopedTssMemory;
Amin Hassani3ee8c802018-10-24 17:01:45 -070024using trousers::ScopedTssNvStore;
Zentaro Kavanagh04eb2b02018-10-25 18:21:22 -070025using trousers::ScopedTssPcrs;
26
27namespace tpmcrypto {
28
29#define TPM_LOG(severity, result) \
30 LOG(severity) << "TPM error 0x" << std::hex << result << " (" \
31 << Trspi_Error_String(result) << "): "
32
33constexpr unsigned char kDefaultSrkAuth[] = {};
34constexpr unsigned int kTpmConnectRetries = 10;
35constexpr unsigned int kTpmConnectIntervalMs = 100;
36
37Tpm1Impl::Tpm1Impl() = default;
38Tpm1Impl::~Tpm1Impl() = default;
39
Amin Hassani3ee8c802018-10-24 17:01:45 -070040std::unique_ptr<Tpm> CreateTpmInstance() {
41 return std::make_unique<Tpm1Impl>();
42}
43
Sarthak Kukreti95f75a02019-01-15 18:34:17 -080044bool Tpm1Impl::SealToPCR0(const SecureBlob& value, SecureBlob* sealed_value) {
Zentaro Kavanagh04eb2b02018-10-25 18:21:22 -070045 CHECK(sealed_value);
46 ScopedTssContext context_handle;
47 TSS_HTPM tpm_handle;
48 if (!ConnectContextAsUser(context_handle.ptr(), &tpm_handle)) {
49 LOG(ERROR) << "SealToPCR0: Failed to connect to the TPM.";
50 return false;
51 }
52 // Load the Storage Root Key.
53 TSS_RESULT result;
54 ScopedTssKey srk_handle(context_handle);
55 if (!LoadSrk(context_handle, srk_handle.ptr(), &result)) {
56 TPM_LOG(ERROR, result) << "SealToPCR0: Failed to load SRK.";
57 return false;
58 }
59
60 // Check the SRK public key
61 unsigned int size_n = 0;
62 ScopedTssMemory public_srk(context_handle);
63 if (TPM_ERROR(
64 result = Tspi_Key_GetPubKey(srk_handle, &size_n, public_srk.ptr()))) {
65 TPM_LOG(ERROR, result) << "SealToPCR0: Unable to get the SRK public key";
66 return false;
67 }
68
69 // Create a PCRS object which holds the value of PCR0.
70 ScopedTssPcrs pcrs_handle(context_handle);
71 if (TPM_ERROR(result = Tspi_Context_CreateObject(
72 context_handle, TSS_OBJECT_TYPE_PCRS, TSS_PCRS_STRUCT_INFO,
73 pcrs_handle.ptr()))) {
74 TPM_LOG(ERROR, result)
75 << "SealToPCR0: Error calling Tspi_Context_CreateObject";
76 return false;
77 }
78
79 // Create a ENCDATA object to receive the sealed data.
80 UINT32 pcr_len = 0;
81 ScopedTssMemory pcr_value(context_handle);
82 Tspi_TPM_PcrRead(tpm_handle, 0, &pcr_len, pcr_value.ptr());
83 Tspi_PcrComposite_SetPcrValue(pcrs_handle, 0, pcr_len, pcr_value.value());
84
85 ScopedTssKey enc_handle(context_handle);
86 if (TPM_ERROR(result = Tspi_Context_CreateObject(
87 context_handle, TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_SEAL,
88 enc_handle.ptr()))) {
89 TPM_LOG(ERROR, result)
90 << "SealToPCR0: Error calling Tspi_Context_CreateObject";
91 return false;
92 }
93
94 // Seal the given value with the SRK.
95 if (TPM_ERROR(result = Tspi_Data_Seal(enc_handle, srk_handle, value.size(),
96 const_cast<BYTE*>(value.data()),
97 pcrs_handle))) {
98 TPM_LOG(ERROR, result) << "SealToPCR0: Error calling Tspi_Data_Seal";
99 return false;
100 }
101
102 // Extract the sealed value.
103 ScopedTssMemory enc_data(context_handle);
104 UINT32 enc_data_length = 0;
105 if (TPM_ERROR(result =
106 Tspi_GetAttribData(enc_handle, TSS_TSPATTRIB_ENCDATA_BLOB,
107 TSS_TSPATTRIB_ENCDATABLOB_BLOB,
108 &enc_data_length, enc_data.ptr()))) {
109 TPM_LOG(ERROR, result) << "SealToPCR0: Error calling Tspi_GetAttribData";
110 return false;
111 }
112 sealed_value->assign(&enc_data.value()[0],
113 &enc_data.value()[enc_data_length]);
114 return true;
115}
116
Sarthak Kukreti95f75a02019-01-15 18:34:17 -0800117bool Tpm1Impl::Unseal(const SecureBlob& sealed_value, SecureBlob* value) {
Zentaro Kavanagh04eb2b02018-10-25 18:21:22 -0700118 CHECK(value);
119 ScopedTssContext context_handle;
120 TSS_HTPM tpm_handle;
121 if (!ConnectContextAsUser(context_handle.ptr(), &tpm_handle)) {
122 LOG(ERROR) << "Unseal: Failed to connect to the TPM.";
123 return false;
124 }
125 // Load the Storage Root Key.
126 TSS_RESULT result;
127 ScopedTssKey srk_handle(context_handle);
128 if (!LoadSrk(context_handle, srk_handle.ptr(), &result)) {
129 TPM_LOG(ERROR, result) << "Unseal: Failed to load SRK.";
130 return false;
131 }
132
133 // Create an ENCDATA object with the sealed value.
134 ScopedTssKey enc_handle(context_handle);
135 if (TPM_ERROR(result = Tspi_Context_CreateObject(
136 context_handle, TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_SEAL,
137 enc_handle.ptr()))) {
138 TPM_LOG(ERROR, result) << "Unseal: Error calling Tspi_Context_CreateObject";
139 return false;
140 }
141
142 if (TPM_ERROR(result = Tspi_SetAttribData(
143 enc_handle, TSS_TSPATTRIB_ENCDATA_BLOB,
144 TSS_TSPATTRIB_ENCDATABLOB_BLOB, sealed_value.size(),
145 const_cast<BYTE*>(sealed_value.data())))) {
146 TPM_LOG(ERROR, result) << "Unseal: Error calling Tspi_SetAttribData";
147 return false;
148 }
149
150 // Unseal using the SRK.
151 ScopedTssMemory dec_data(context_handle);
152 UINT32 dec_data_length = 0;
153 if (TPM_ERROR(result = Tspi_Data_Unseal(enc_handle, srk_handle,
154 &dec_data_length, dec_data.ptr()))) {
155 TPM_LOG(ERROR, result) << "Unseal: Error calling Tspi_Data_Unseal";
156 return false;
157 }
158 value->assign(&dec_data.value()[0], &dec_data.value()[dec_data_length]);
Tom Hughesbd48f332021-01-07 10:18:05 -0800159 brillo::SecureClearBytes(dec_data.value(), dec_data_length);
Zentaro Kavanagh04eb2b02018-10-25 18:21:22 -0700160 return true;
161}
162
163TSS_HCONTEXT Tpm1Impl::ConnectContext() {
164 TSS_RESULT result;
165 TSS_HCONTEXT context_handle = 0;
166 if (!OpenAndConnectTpm(&context_handle, &result)) {
167 return 0;
168 }
169 return context_handle;
170}
171
172bool Tpm1Impl::OpenAndConnectTpm(TSS_HCONTEXT* context_handle,
173 TSS_RESULT* result) {
174 TSS_RESULT local_result;
175 ScopedTssContext local_context_handle;
176 if (TPM_ERROR(local_result =
177 Tspi_Context_Create(local_context_handle.ptr()))) {
178 TPM_LOG(ERROR, local_result) << "Error calling Tspi_Context_Create";
179 if (result)
180 *result = local_result;
181 return false;
182 }
183
184 for (unsigned int i = 0; i < kTpmConnectRetries; i++) {
185 LOG(INFO) << "Attempting to connect to TPM";
186 if (TPM_ERROR(local_result =
187 Tspi_Context_Connect(local_context_handle, NULL))) {
188 // If there was a communications failure, try sleeping a bit here--it may
189 // be that tcsd is still starting
190 if (ERROR_CODE(local_result) == TSS_E_COMM_FAILURE) {
191 LOG(INFO) << "Sleeping to wait for TPM";
192 PlatformThread::Sleep(
193 TimeDelta::FromMilliseconds(kTpmConnectIntervalMs));
194 } else {
195 TPM_LOG(ERROR, local_result) << "Error calling Tspi_Context_Connect";
196 if (result)
197 *result = local_result;
198 return false;
199 }
200 } else {
201 break;
202 }
203 }
204 if (TPM_ERROR(local_result)) {
205 TPM_LOG(ERROR, local_result) << "Error calling Tspi_Context_Connect";
206 if (result)
207 *result = local_result;
208 return false;
209 }
210
211 *context_handle = local_context_handle.release();
212 if (result)
213 *result = local_result;
214 return (*context_handle != 0);
215}
216
217bool Tpm1Impl::GetTpm(TSS_HCONTEXT context_handle, TSS_HTPM* tpm_handle) {
218 TSS_RESULT result;
219 TSS_HTPM local_tpm_handle;
220 if (TPM_ERROR(result = Tspi_Context_GetTpmObject(context_handle,
221 &local_tpm_handle))) {
222 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_GetTpmObject";
223 return false;
224 }
225 *tpm_handle = local_tpm_handle;
226 return true;
227}
228
229bool Tpm1Impl::ConnectContextAsUser(TSS_HCONTEXT* context, TSS_HTPM* tpm) {
230 *context = 0;
231 *tpm = 0;
232 if ((*context = ConnectContext()) == 0) {
233 LOG(ERROR) << "ConnectContextAsUser: Could not open the TPM";
234 return false;
235 }
236 if (!GetTpm(*context, tpm)) {
237 LOG(ERROR) << "ConnectContextAsUser: failed to get a TPM object";
238 Tspi_Context_Close(*context);
239 *context = 0;
240 *tpm = 0;
241 return false;
242 }
243 return true;
244}
245
246bool Tpm1Impl::LoadSrk(TSS_HCONTEXT context_handle,
247 TSS_HKEY* srk_handle,
248 TSS_RESULT* result) const {
249 *result = TSS_SUCCESS;
250
251 // Load the Storage Root Key
252 TSS_UUID SRK_UUID = TSS_UUID_SRK;
253 ScopedTssKey local_srk_handle(context_handle);
254 if (TPM_ERROR(*result = Tspi_Context_LoadKeyByUUID(
255 context_handle, TSS_PS_TYPE_SYSTEM, SRK_UUID,
256 local_srk_handle.ptr()))) {
257 return false;
258 }
259
260 // Check if the SRK wants a password
261 UINT32 srk_authusage;
262 if (TPM_ERROR(*result = Tspi_GetAttribUint32(
263 local_srk_handle, TSS_TSPATTRIB_KEY_INFO,
264 TSS_TSPATTRIB_KEYINFO_AUTHUSAGE, &srk_authusage))) {
265 return false;
266 }
267
268 // Give it the password if needed
269 if (srk_authusage) {
270 TSS_HPOLICY srk_usage_policy;
271 if (TPM_ERROR(*result = Tspi_GetPolicyObject(
272 local_srk_handle, TSS_POLICY_USAGE, &srk_usage_policy))) {
273 return false;
274 }
275
276 *result = Tspi_Policy_SetSecret(srk_usage_policy, TSS_SECRET_MODE_PLAIN,
277 sizeof(kDefaultSrkAuth),
278 const_cast<BYTE*>(kDefaultSrkAuth));
279 if (TPM_ERROR(*result)) {
280 return false;
281 }
282 }
283
284 *srk_handle = local_srk_handle.release();
285 return true;
286}
287
Amin Hassani3ee8c802018-10-24 17:01:45 -0700288bool Tpm1Impl::GetNVAttributes(uint32_t index, uint32_t* attributes) {
289 CHECK(attributes);
290 ScopedTssContext context_handle;
291 TSS_HTPM tpm_handle;
292 if (!ConnectContextAsUser(context_handle.ptr(), &tpm_handle)) {
293 LOG(ERROR) << "GetNVAttributes: Failed to connect to the TPM.";
294 return false;
295 }
296
297 TSS_RESULT result;
298 UINT32 nv_index_data_length = sizeof(TPM_NV_DATA_PUBLIC);
299 ScopedTssMemory nv_index_data(context_handle);
300 if (TPM_ERROR(result = Tspi_TPM_GetCapability(
301 tpm_handle, TSS_TPMCAP_NV_INDEX, sizeof(index),
302 reinterpret_cast<BYTE*>(&index), &nv_index_data_length,
303 nv_index_data.ptr()))) {
304 TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetCapability";
305 return false;
306 }
307 if (nv_index_data_length == 0) {
308 LOG(ERROR) << "The NV index public data length is not valid";
309 return false;
310 }
311
312 TPM_NV_DATA_PUBLIC nv_data_public;
313 UINT64 offset = 0;
314 if (TPM_ERROR(result = Trspi_UnloadBlob_NV_DATA_PUBLIC(
315 &offset, *nv_index_data.ptr(), &nv_data_public))) {
316 TPM_LOG(ERROR, result) << "Error unloading NV public data.";
317 return false;
318 }
319
320 *attributes = nv_data_public.permission.attributes;
321 return true;
322}
323
324bool Tpm1Impl::NVReadNoAuth(uint32_t index,
325 uint32_t offset,
326 size_t size,
327 std::string* data) {
328 CHECK(data);
329 ScopedTssContext context_handle;
330 TSS_HTPM tpm_handle;
331 if (!ConnectContextAsUser(context_handle.ptr(), &tpm_handle)) {
332 LOG(ERROR) << "NVReadNoAuth: Failed to connect to the TPM.";
333 return false;
334 }
335
336 // Create an NVRAM store object handle.
337 TSS_RESULT result;
338 ScopedTssNvStore nv_handle(context_handle);
339 result = Tspi_Context_CreateObject(context_handle, TSS_OBJECT_TYPE_NV, 0,
340 nv_handle.ptr());
341 if (TPM_ERROR(result)) {
342 TPM_LOG(ERROR, result) << "Could not acquire an NVRAM object handle";
343 return false;
344 }
345 result = Tspi_SetAttribUint32(nv_handle, TSS_TSPATTRIB_NV_INDEX, 0, index);
346 if (TPM_ERROR(result)) {
347 TPM_LOG(ERROR, result) << "Could not set index on NVRAM object: " << index;
348 return false;
349 }
350
351 SecureBlob blob(size);
352 // Read from NVRAM in conservatively small chunks. This is a limitation of the
353 // TPM that is left for the application layer to deal with. The maximum size
354 // that is supported here can vary between vendors / models, so we'll be
355 // conservative. FWIW, the Infineon chips seem to handle up to 1024.
356 const UINT32 kMaxDataSize = 128;
357 UINT32 offset_l = 0;
358 while (offset_l < size) {
359 UINT32 chunk_size = size - offset_l;
360 if (chunk_size > kMaxDataSize)
361 chunk_size = kMaxDataSize;
362 ScopedTssMemory space_data(context_handle);
363 if ((result = Tspi_NV_ReadValue(nv_handle, offset_l + offset, &chunk_size,
364 space_data.ptr()))) {
365 TPM_LOG(ERROR, result) << "Could not read from NVRAM space: " << index;
366 return false;
367 }
368 if (!space_data.value()) {
369 LOG(ERROR) << "No data read from NVRAM space: " << index;
370 return false;
371 }
372 CHECK(offset_l + chunk_size <= blob.size());
373 unsigned char* buffer = blob.data() + offset_l;
374 memcpy(buffer, space_data.value(), chunk_size);
375 offset_l += chunk_size;
376 }
377 *data = std::string(blob.begin(), blob.end());
378 return true;
379}
380
Zentaro Kavanagh04eb2b02018-10-25 18:21:22 -0700381} // namespace tpmcrypto