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