1 //**********************************************************************;
2 // Copyright (c) 2017, Intel Corporation
3 // All rights reserved.
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
15 // 3. Neither the name of Intel Corporation nor the names of its contributors
16 // may be used to endorse or promote products derived from this software without
17 // specific prior written permission.
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29 // THE POSSIBILITY OF SUCH DAMAGE.
30 //**********************************************************************;
37 #include <tss2/tss2_sys.h>
38 #include <tss2/tss2_mu.h>
42 #include "tpm2_util.h"
44 bool files_get_file_size(FILE *fp, unsigned long *file_size, const char *path) {
46 long current = ftell(fp);
49 LOG_ERR("Error getting current file offset for file \"%s\" error: %s", path, strerror(errno));
54 int rc = fseek(fp, 0, SEEK_END);
57 LOG_ERR("Error seeking to end of file \"%s\" error: %s", path, strerror(errno));
62 long size = ftell(fp);
65 LOG_ERR("ftell on file \"%s\" failed: %s", path, strerror(errno));
70 rc = fseek(fp, current, SEEK_SET);
73 LOG_ERR("Could not restore initial stream position for file \"%s\" failed: %s", path, strerror(errno));
78 /* size cannot be negative at this point */
79 *file_size = (unsigned long)size;
83 static bool read_bytes_from_file(FILE *f, UINT8 *buf, UINT16 *size,
85 unsigned long file_size;
86 bool result = files_get_file_size(f, &file_size, path);
88 /* get_file_size() logs errors */
92 /* max is bounded on UINT16 */
93 if (file_size > *size) {
96 "File \"%s\" size is larger than buffer, got %lu expected less than %u",
97 path, file_size, *size);
102 result = files_read_bytes(f, buf, file_size);
105 LOG_ERR("Could not read data from file \"%s\"", path);
115 bool files_load_bytes_from_path(const char *path, UINT8 *buf, UINT16 *size) {
116 if (!buf || !size || !path) {
120 FILE *f = fopen(path, "rb");
122 LOG_ERR("Could not open file \"%s\" error %s", path, strerror(errno));
126 bool result = read_bytes_from_file(f, buf, size, path);
132 bool files_save_bytes_to_file(const char *path, UINT8 *buf, UINT16 size) {
138 FILE *fp = fopen(path, "wb+");
140 LOG_ERR("Could not open file \"%s\", error: %s", path, strerror(errno));
144 bool result = files_write_bytes(fp, buf, size);
146 LOG_ERR("Could not write data to file \"%s\"", path);
153 * Current version to write TPMS_CONTEXT to disk.
155 #define CONTEXT_VERSION 1
157 bool files_save_tpm_context_to_file(TSS2_SYS_CONTEXT *sysContext, TPM2_HANDLE handle,
160 TPMS_CONTEXT context;
162 TSS2_RC rval = Tss2_Sys_ContextSave(sysContext, handle, &context);
163 if (rval != TPM2_RC_SUCCESS) {
164 LOG_PERR(Tss2_Sys_ContextSave, rval);
169 * Saving the TPMS_CONTEXT structure to disk, format:
170 * TPM2.0-TOOLS HEADER
174 * U16 contextBlobLength
177 bool result = files_write_header(stream, CONTEXT_VERSION);
179 LOG_ERR("Could not write context file header");
184 result = files_write_32(stream, context.hierarchy);
186 LOG_ERR("Could not write hierarchy");
190 result = files_write_32(stream, context.savedHandle);
192 LOG_ERR("Could not write savedHandle");
197 result = files_write_64(stream, context.sequence);
199 LOG_ERR("Could not write sequence");
204 result = files_write_16(stream, context.contextBlob.size);
206 LOG_ERR("Could not write contextBob size");
210 // BYTE[] contextBlob
211 result = files_write_bytes(stream, context.contextBlob.buffer,
212 context.contextBlob.size);
214 LOG_ERR("Could not write contextBlob buffer");
216 /* result is set by file_write_bytes() */
222 bool files_save_tpm_context_to_path(TSS2_SYS_CONTEXT *sysContext, TPM2_HANDLE handle,
225 FILE *f = fopen(path, "w+b");
227 LOG_ERR("Error opening file \"%s\" due to error: %s", path,
232 bool result = files_save_tpm_context_to_file(sysContext, handle, f);
238 bool files_load_tpm_context_from_file(TSS2_SYS_CONTEXT *sapi_context,
239 TPM2_HANDLE *handle, FILE *fstream) {
244 * Reading the TPMS_CONTEXT structure to disk, format:
245 * TPM2.0-TOOLS HEADER
249 * U16 contextBlobLength
253 TPMS_CONTEXT context;
254 bool result = files_read_header(fstream, &version);
257 "The loaded tpm context does not appear to be in the proper format,"
258 "assuming old format, this will be converted on the next save.");
260 result = files_read_bytes(fstream, (UINT8 *) &context, sizeof(context));
262 LOG_ERR("Could not load tpm context file");
265 /* Success load the context into the TPM */
269 if (version != CONTEXT_VERSION) {
270 LOG_ERR("Unsupported context file format version found, got: %"PRIu32,
276 result = files_read_32(fstream, &context.hierarchy);
278 LOG_ERR("Error reading hierarchy!");
282 result = files_read_32(fstream, &context.savedHandle);
284 LOG_ERR("Error reading savedHandle!");
288 result = files_read_64(fstream, &context.sequence);
290 LOG_ERR("Error reading sequence!");
294 result = files_read_16(fstream, &context.contextBlob.size);
296 LOG_ERR("Error reading contextBlob.size!");
300 if (context.contextBlob.size > sizeof(context.contextBlob.buffer)) {
302 "Size mismatch found on contextBlob, got %"PRIu16" expected less than or equal to %zu",
303 context.contextBlob.size,
304 sizeof(context.contextBlob.buffer));
309 result = files_read_bytes(fstream, context.contextBlob.buffer,
310 context.contextBlob.size);
312 LOG_ERR("Error reading contextBlob.size!");
317 rval = Tss2_Sys_ContextLoad(sapi_context, &context, handle);
318 if (rval != TPM2_RC_SUCCESS) {
319 LOG_PERR(Tss2_Sys_ContextLoad, rval);
330 bool files_load_tpm_context_from_path(TSS2_SYS_CONTEXT *sapi_context,
331 TPM2_HANDLE *handle, const char *path) {
333 FILE *f = fopen(path, "rb");
335 LOG_ERR("Error opening file \"%s\" due to error: %s", path,
340 bool result = files_load_tpm_context_from_file(sapi_context, handle, f);
346 bool files_does_file_exist(const char *path) {
349 LOG_ERR("Path cannot be NULL");
353 FILE *fp = fopen(path,"rb");
356 LOG_ERR("Path: %s already exists. Please rename or delete the file!",
363 bool files_get_file_size_path(const char *path, unsigned long *file_size) {
368 LOG_ERR("Must specify a path argument, cannot be NULL!");
373 LOG_ERR("Must specify a file size argument, cannot be NULL!");
377 FILE *fp = fopen(path,"rb");
379 LOG_ERR("Could not open file: \"%s\" error: %s", path, strerror(errno));
383 result = files_get_file_size(fp, file_size, path);
390 * This is the magic for the file header. The header is organized
391 * as a big endian U32 (BEU32) of MAGIC followed by a BEU32 of the
392 * version number. Tools can define their own, individual file
393 * formats as they make sense, but they should always have the header.
395 static const UINT32 MAGIC = 0xBADCC0DE;
398 * Writes size bytes to a file, continuing on EINTR short writes.
400 * The file to write to.
404 * The size, in bytes, of that data.
406 * True on success, False otherwise.
408 static bool writex(FILE *f, UINT8 *data, size_t size) {
413 wrote = fwrite(&data[index], 1, size, f);
415 if (errno != EINTR) {
418 /* continue on EINTR */
428 * Reads size bytes from a file, continuing on EINTR short reads.
430 * The file to read from.
432 * The data buffer to read into.
434 * The size of the buffer, which is also the amount of bytes to read.
436 * True on success, False otherwise.
438 static bool readx(FILE *f, UINT8 *data, size_t size) {
443 bread = fread(&data[index], 1, size, f);
445 if (feof(f) || (errno != EINTR)) {
448 /* continue on EINTR */
457 #define BAIL_ON_NULL(param, x) \
460 LOG_ERR(param" must be specified"); \
465 #define BE_CONVERT(value, size) \
467 if (!tpm2_util_is_big_endian()) { \
468 value = tpm2_util_endian_swap_##size(value); \
472 #define FILE_WRITE(size) \
473 bool files_write_##size(FILE *out, UINT##size data) { \
474 BAIL_ON_NULL("FILE", out); \
475 BE_CONVERT(data, size); \
476 return writex(out, (UINT8 *)&data, sizeof(data)); \
479 #define FILE_READ(size) \
480 bool files_read_##size(FILE *out, UINT##size *data) { \
481 BAIL_ON_NULL("FILE", out); \
482 BAIL_ON_NULL("data", data); \
483 bool res = readx(out, (UINT8 *)data, sizeof(*data)); \
485 BE_CONVERT(*data, size); \
491 * all the files_read|write_bytes_16|32|64 functions
502 bool files_read_bytes(FILE *out, UINT8 bytes[], size_t len) {
504 BAIL_ON_NULL("FILE", out);
505 BAIL_ON_NULL("bytes", bytes);
506 return readx(out, bytes, len);
509 bool files_write_bytes(FILE *out, uint8_t bytes[], size_t len) {
511 BAIL_ON_NULL("FILE", out);
512 BAIL_ON_NULL("bytes", bytes);
513 return writex(out, bytes, len);
516 bool files_write_header(FILE *out, UINT32 version) {
518 BAIL_ON_NULL("FILE", out);
520 bool res = files_write_32(out, MAGIC);
524 return files_write_32(out, version);
527 bool files_read_header(FILE *out, uint32_t *version) {
529 BAIL_ON_NULL("FILE", out);
530 BAIL_ON_NULL("version", version);
533 bool res = files_read_32(out, &magic);
538 if (magic != MAGIC) {
539 LOG_ERR("Found magic 0x%x did not match expected magic of 0x%x!",
544 return files_read_32(out, version);
547 bool files_load_bytes_from_file_or_stdin(const char *path, UINT16 *size, BYTE *buf) {
549 FILE *file = path ? fopen(path, "rb") : stdin;
550 path = file != stdin ? path : "<stdin>";
552 LOG_ERR("Could not open file: \"%s\", error: %s", path,
558 * Attempt to accurately read the file based on the file size.
559 * This may fail on stdin when it's a pipe.
565 UINT16 original_size = *size;
566 bool res = files_load_bytes_from_path(path, buf,
570 *size = fread(buf, 1,
573 LOG_ERR("Data to be sealed larger than expected. Got %u expected %u",
577 else if (ferror(file)) {
578 LOG_ERR("Error reading sealed data from \"<stdin>\"");
590 #define SAVE_TYPE(type, name) \
591 bool files_save_##name(type *name, const char *path) { \
594 UINT8 buffer[sizeof(*name)]; \
595 TSS2_RC rc = Tss2_MU_##type##_Marshal(name, buffer, sizeof(buffer), &offset); \
596 if (rc != TSS2_RC_SUCCESS) { \
597 LOG_ERR("Error serializing "str(name)" structure: 0x%x", rc); \
601 return files_save_bytes_to_file(path, buffer, offset); \
604 #define LOAD_TYPE(type, name) \
605 bool files_load_##name(const char *path, type *name) { \
607 UINT8 buffer[sizeof(*name)]; \
608 UINT16 size = sizeof(buffer); \
609 bool res = files_load_bytes_from_path(path, buffer, &size); \
615 TSS2_RC rc = Tss2_MU_##type##_Unmarshal(buffer, size, &offset, name); \
616 if (rc != TSS2_RC_SUCCESS) { \
617 LOG_ERR("Error serializing "str(name)" structure: 0x%x", rc); \
621 return rc == TPM2_RC_SUCCESS; \
624 SAVE_TYPE(TPM2B_PUBLIC, public)
625 LOAD_TYPE(TPM2B_PUBLIC, public)
627 SAVE_TYPE(TPMT_SIGNATURE, signature)
628 LOAD_TYPE(TPMT_SIGNATURE, signature)
630 SAVE_TYPE(TPMT_TK_VERIFIED, ticket)
631 LOAD_TYPE(TPMT_TK_VERIFIED, ticket)
633 SAVE_TYPE(TPM2B_SENSITIVE, sensitive)
634 LOAD_TYPE(TPM2B_SENSITIVE, sensitive)
636 SAVE_TYPE(TPMT_TK_HASHCHECK, validation)
637 LOAD_TYPE(TPMT_TK_HASHCHECK, validation)
639 SAVE_TYPE(TPM2B_PRIVATE, private)
640 LOAD_TYPE(TPM2B_PRIVATE, private)