blob: 7a42df791bdda17531f1591c70dc8570146bc786 [file] [log] [blame]
NingSun535535b2018-02-28 18:24:31 -08001//**********************************************************************;
2// Copyright (c) 2017, Intel Corporation
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are met:
7//
8// 1. Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10//
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.
14//
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.
18//
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//**********************************************************************;
31#include <ctype.h>
32#include <errno.h>
33#include <stdbool.h>
34
35#include "log.h"
36#include "files.h"
37#include "tpm2_alg_util.h"
38#include "tpm2_attr_util.h"
39#include "tpm2_util.h"
40bool output_enabled;
41bool tpm2_util_concat_buffer(TPM2B_MAX_BUFFER *result, TPM2B *append) {
42
43 if (!result || !append) {
44 return false;
45 }
46
47 if ((result->size + append->size) < result->size) {
48 return false;
49 }
50
51 if ((result->size + append->size) > TPM2_MAX_DIGEST_BUFFER) {
52 return false;
53 }
54
55 memcpy(&result->buffer[result->size], append->buffer, append->size);
56 result->size += append->size;
57
58 return true;
59}
60
61bool tpm2_util_string_to_uint16(const char *str, uint16_t *value) {
62
63 uint32_t tmp;
64 bool result = tpm2_util_string_to_uint32(str, &tmp);
65 if (!result) {
66 return false;
67 }
68
69 /* overflow on 16 bits? */
70 if (tmp > UINT16_MAX) {
71 return false;
72 }
73
74 *value = (uint16_t) tmp;
75 return true;
76}
77
78bool tpm2_util_string_to_uint32(const char *str, uint32_t *value) {
79
80 char *endptr;
81
82 if (str == NULL || *str == '\0') {
83 return false;
84 }
85
86 /* clear errno before the call, should be 0 afterwards */
87 errno = 0;
88 uint32_t tmp = strtoul(str, &endptr, 0);
89 if (errno) {
90 return false;
91 }
92
93 /*
94 * The entire string should be able to be converted or fail
95 * We already checked that str starts with a null byte, so no
96 * need to check that again per the man page.
97 */
98 if (*endptr != '\0') {
99 return false;
100 }
101
102 *value = tmp;
103 return true;
104}
105
106int tpm2_util_hex_to_byte_structure(const char *inStr, UINT16 *byteLength,
107 BYTE *byteBuffer) {
108 int strLength; //if the inStr likes "1a2b...", no prefix "0x"
109 int i = 0;
110 if (inStr == NULL || byteLength == NULL || byteBuffer == NULL)
111 return -1;
112 strLength = strlen(inStr);
113 if (strLength % 2)
114 return -2;
115 for (i = 0; i < strLength; i++) {
116 if (!isxdigit(inStr[i]))
117 return -3;
118 }
119
120 if (*byteLength < strLength / 2)
121 return -4;
122
123 *byteLength = strLength / 2;
124
125 for (i = 0; i < *byteLength; i++) {
126 char tmpStr[4] = { 0 };
127 tmpStr[0] = inStr[i * 2];
128 tmpStr[1] = inStr[i * 2 + 1];
129 byteBuffer[i] = strtol(tmpStr, NULL, 16);
130 }
131 return 0;
132}
133
134void tpm2_util_hexdump(const BYTE *data, size_t len, bool plain) {
135
136 if (!output_enabled) {
137 return;
138 }
139
140 if (plain) {
141 size_t i;
142 for (i=0; i < len; i++) {
143 printf("%02x", data[i]);
144 }
145 return;
146 }
147
148 size_t i;
149 size_t j;
150 for (i = 0; i < len; i += 16) {
151 printf("%06zx: ", i);
152
153 for (j = 0; j < 16; j++) {
154 if (i + j < len) {
155 printf("%02x ", data[i + j]);
156 } else {
157 printf(" ");
158 }
159 }
160
161 printf(" ");
162
163 for (j = 0; j < 16; j++) {
164 if (i + j < len) {
165 printf("%c", isprint(data[i + j]) ? data[i + j] : '.');
166 }
167 }
168 printf("\n");
169 }
170}
171
172bool tpm2_util_hexdump_file(FILE *fd, size_t len, bool plain) {
173 BYTE* buff = (BYTE*)malloc(len);
174 if (!buff) {
175 LOG_ERR("malloc() failed");
176 return false;
177 }
178
179 bool res = files_read_bytes(fd, buff, len);
180 if (!res) {
181 LOG_ERR("Failed to read file");
182 free(buff);
183 return false;
184 }
185
186 tpm2_util_hexdump(buff, len, plain);
187
188 free(buff);
189 return true;
190}
191
192bool tpm2_util_print_tpm2b_file(FILE *fd)
193{
194 UINT16 len;
195 bool res = files_read_16(fd, &len);
196 if(!res) {
197 LOG_ERR("File read failed");
198 return false;
199 }
200 return tpm2_util_hexdump_file(fd, len, true);
201}
202
203/* TODO OPTIMIZE ME */
204UINT16 tpm2_util_copy_tpm2b(TPM2B *dest, TPM2B *src) {
205 int i;
206 UINT16 rval = 0;
207
208 if (dest != 0) {
209 if (src == 0) {
210 dest->size = 0;
211 rval = 0;
212 } else {
213 dest->size = src->size;
214 for (i = 0; i < src->size; i++)
215 dest->buffer[i] = src->buffer[i];
216 rval = (sizeof(UINT16) + src->size);
217 }
218 } else {
219 rval = 0;
220 }
221
222 return rval;
223}
224
225bool tpm2_util_is_big_endian(void) {
226
227 uint32_t test_word;
228 uint8_t *test_byte;
229
230 test_word = 0xFF000000;
231 test_byte = (uint8_t *) (&test_word);
232
233 return test_byte[0] == 0xFF;
234}
235
236#define STRING_BYTES_ENDIAN_CONVERT(size) \
237 UINT##size tpm2_util_endian_swap_##size(UINT##size data) { \
238 \
239 UINT##size converted; \
240 UINT8 *bytes = (UINT8 *)&data; \
241 UINT8 *tmp = (UINT8 *)&converted; \
242 \
243 size_t i; \
244 for(i=0; i < sizeof(UINT##size); i ++) { \
245 tmp[i] = bytes[sizeof(UINT##size) - i - 1]; \
246 } \
247 \
248 return converted; \
249 }
250
251STRING_BYTES_ENDIAN_CONVERT(16)
252STRING_BYTES_ENDIAN_CONVERT(32)
253STRING_BYTES_ENDIAN_CONVERT(64)
254
255#define STRING_BYTES_ENDIAN_HTON(size) \
256 UINT##size tpm2_util_hton_##size(UINT##size data) { \
257 \
258 bool is_big_endian = tpm2_util_is_big_endian(); \
259 if (is_big_endian) { \
260 return data; \
261 } \
262 \
263 return tpm2_util_endian_swap_##size(data); \
264 }
265
266STRING_BYTES_ENDIAN_HTON(16)
267STRING_BYTES_ENDIAN_HTON(32)
268STRING_BYTES_ENDIAN_HTON(64)
269
270/*
271 * Converting from host-to-network (hton) or network-to-host (ntoh) is
272 * the same operation: if endianess differs between host and data, swap
273 * endianess. Thus we can just call the hton routines, but have some nice
274 * names for folks.
275 */
276UINT16 tpm2_util_ntoh_16(UINT16 data) {
277 return tpm2_util_hton_16(data);
278}
279
280UINT32 tpm2_util_ntoh_32(UINT32 data) {
281 return tpm2_util_hton_32(data);
282}
283UINT64 tpm2_util_ntoh_64(UINT64 data) {
284 return tpm2_util_hton_64(data);
285}
286
287UINT32 tpm2_util_pop_count(UINT32 data) {
288
289 static const UINT8 bits_per_nibble[] =
290 {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
291
292 UINT8 count = 0;
293 UINT8 *d = (UINT8 *)&data;
294
295 size_t i;
296 for (i=0; i < sizeof(data); i++) {
297 count += bits_per_nibble[d[i] & 0x0f];
298 count += bits_per_nibble[d[i] >> 4];
299 }
300
301 return count;
302}
303
304#define TPM2_UTIL_KEYDATA_INIT { .len = 0 };
305
306typedef struct tpm2_util_keydata tpm2_util_keydata;
307struct tpm2_util_keydata {
308 UINT16 len;
309 struct {
310 const char *name;
311 TPM2B *value;
312 } entries[2];
313};
314
315static void tpm2_util_public_to_keydata(TPM2B_PUBLIC *public, tpm2_util_keydata *keydata) {
316
317 switch (public->publicArea.type) {
318 case TPM2_ALG_RSA:
319 keydata->len = 1;
320 keydata->entries[0].name = tpm2_alg_util_algtostr(public->publicArea.type);
321 keydata->entries[0].value = (TPM2B *)&public->publicArea.unique.rsa;
322 return;
323 case TPM2_ALG_KEYEDHASH:
324 keydata->len = 1;
325 keydata->entries[0].name = tpm2_alg_util_algtostr(public->publicArea.type);
326 keydata->entries[0].value = (TPM2B *)&public->publicArea.unique.keyedHash;
327 return;
328 case TPM2_ALG_SYMCIPHER:
329 keydata->len = 1;
330 keydata->entries[0].name = tpm2_alg_util_algtostr(public->publicArea.type);
331 keydata->entries[0].value = (TPM2B *)&public->publicArea.unique.sym;
332 return;
333 case TPM2_ALG_ECC:
334 keydata->len = 2;
335 keydata->entries[0].name = "x";
336 keydata->entries[0].value = (TPM2B *)&public->publicArea.unique.ecc.x;
337 keydata->entries[1].name = "y";
338 keydata->entries[1].value = (TPM2B *)&public->publicArea.unique.ecc.y;
339 return;
340 default:
341 LOG_WARN("The algorithm type(0x%4.4x) is not supported",
342 public->publicArea.type);
343 }
344
345 return;
346}
347
348void print_yaml_indent(size_t indent_count) {
349 while (indent_count--) {
350 tpm2_tool_output(" ");
351 }
352}
353
354void tpm2_util_tpma_object_to_yaml(TPMA_OBJECT obj) {
355
356 char *attrs = tpm2_attr_util_obj_attrtostr(obj);
357 tpm2_tool_output("attributes:\n");
358 tpm2_tool_output(" value: %s\n", attrs);
359 tpm2_tool_output(" raw: 0x%x\n", obj);
360 free(attrs);
361}
362
363void tpm2_util_public_to_yaml(TPM2B_PUBLIC *public) {
364
365 tpm2_tool_output("algorithm:\n");
366 tpm2_tool_output(" value: %s\n", tpm2_alg_util_algtostr(public->publicArea.nameAlg));
367 tpm2_tool_output(" raw: 0x%x\n", public->publicArea.nameAlg);
368
369 tpm2_util_tpma_object_to_yaml(public->publicArea.objectAttributes);
370
371 tpm2_tool_output("type: \n");
372 tpm2_tool_output(" value: %s\n", tpm2_alg_util_algtostr(public->publicArea.type));
373 tpm2_tool_output(" raw: 0x%x\n", public->publicArea.type);
374
375 tpm2_util_keydata keydata = TPM2_UTIL_KEYDATA_INIT;
376 tpm2_util_public_to_keydata(public, &keydata);
377
378 UINT16 i;
379 /* if no keydata len will be 0 and it wont print */
380 for (i=0; i < keydata.len; i++) {
381 tpm2_tool_output(" %s: ", keydata.entries[i].name);
382 tpm2_util_print_tpm2b(keydata.entries[i].value);
383 tpm2_tool_output("\n");
384 }
385
386 if (public->publicArea.authPolicy.size) {
387 tpm2_tool_output("authorization policy: ");
388 tpm2_util_hexdump(public->publicArea.authPolicy.buffer,
389 public->publicArea.authPolicy.size, true);
390 tpm2_tool_output("\n");
391 }
392}