3683b6e6d6e7ea0e6058bbf423497eaaec89cfe2
[aaf/sshsm.git] / TPM2-Plugin / lib / tpm2_alg_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 <stdbool.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include <tss2/tss2_sys.h>
36
37 #include "files.h"
38 #include "log.h"
39 #include "tpm2_hash.h"
40 #include "tpm2_alg_util.h"
41 #include "tpm2_util.h"
42
43 typedef struct alg_pair alg_pair;
44 struct alg_pair {
45     const char *name;
46     TPM2_ALG_ID id;
47 };
48
49 void tpm2_alg_util_for_each_alg(tpm2_alg_util_alg_iteraror iterator, void *userdata) {
50
51     static const alg_pair algs[] = {
52         { .name = "rsa", .id = TPM2_ALG_RSA },
53         { .name = "sha1", .id = TPM2_ALG_SHA1 },
54         { .name = "hmac", .id = TPM2_ALG_HMAC },
55         { .name = "aes", .id = TPM2_ALG_AES },
56         { .name = "mgf1", .id = TPM2_ALG_MGF1 },
57         { .name = "keyedhash", .id = TPM2_ALG_KEYEDHASH },
58         { .name = "xor", .id = TPM2_ALG_XOR },
59         { .name = "sha256", .id = TPM2_ALG_SHA256 },
60         { .name = "sha384", .id = TPM2_ALG_SHA384 },
61         { .name = "sha512", .id = TPM2_ALG_SHA512 },
62         { .name = "null", .id = TPM2_ALG_NULL },
63         { .name = "sm3_256", .id = TPM2_ALG_SM3_256 },
64         { .name = "sm4", .id = TPM2_ALG_SM4 },
65         { .name = "rsassa", .id = TPM2_ALG_RSASSA },
66         { .name = "rsaes", .id = TPM2_ALG_RSAES },
67         { .name = "rsapss", .id = TPM2_ALG_RSAPSS },
68         { .name = "oaep", .id = TPM2_ALG_OAEP },
69         { .name = "ecdsa", .id = TPM2_ALG_ECDSA },
70         { .name = "ecdh", .id = TPM2_ALG_ECDH },
71         { .name = "ecdaa", .id = TPM2_ALG_ECDAA },
72         { .name = "sm2", .id = TPM2_ALG_SM2 },
73         { .name = "ecschnorr", .id = TPM2_ALG_ECSCHNORR },
74         { .name = "ecmqv", .id = TPM2_ALG_ECMQV },
75         { .name = "kdf1_sp800_56a", .id = TPM2_ALG_KDF1_SP800_56A },
76         { .name = "kdf2", .id = TPM2_ALG_KDF2 },
77         { .name = "kdf1_sp800_108", .id = TPM2_ALG_KDF1_SP800_108 },
78         { .name = "ecc", .id = TPM2_ALG_ECC },
79         { .name = "symcipher", .id = TPM2_ALG_SYMCIPHER },
80         { .name = "camellia", .id = TPM2_ALG_CAMELLIA },
81         { .name = "sha3_256", .id = TPM2_ALG_SHA3_256 },
82         { .name = "sha3_384", .id = TPM2_ALG_SHA3_384 },
83         { .name = "sha3_512", .id = TPM2_ALG_SHA3_512 },
84         { .name = "ctr", .id = TPM2_ALG_CTR },
85         { .name = "ofb", .id = TPM2_ALG_OFB },
86         { .name = "cbc", .id = TPM2_ALG_CBC },
87         { .name = "cfb", .id = TPM2_ALG_CFB },
88         { .name = "ecb", .id = TPM2_ALG_ECB },
89     };
90
91     size_t i;
92     for (i=0; i < ARRAY_LEN(algs); i++) {
93         const alg_pair *alg = &algs[i];
94         bool result = iterator(alg->id, alg->name, userdata);
95         if (result) {
96             return;
97         }
98     }
99 }
100
101 static bool find_match(TPM2_ALG_ID id, const char *name, void *userdata) {
102
103     alg_pair *search_data = (alg_pair *)userdata;
104
105     /*
106      * if name, then search on name, else
107      * search by id.
108      */
109     if (search_data->name && !strcmp(search_data->name, name)) {
110         search_data->id = id;
111         return true;
112     } else if (search_data->id == id) {
113         search_data->name = name;
114         return true;
115     }
116
117     return false;
118 }
119
120 TPM2_ALG_ID tpm2_alg_util_strtoalg(const char *name) {
121
122     alg_pair userdata = {
123         .name = name,
124         .id = TPM2_ALG_ERROR
125     };
126
127     if (name) {
128         tpm2_alg_util_for_each_alg(find_match, &userdata);
129     }
130
131     return userdata.id;
132 }
133
134 const char *tpm2_alg_util_algtostr(TPM2_ALG_ID id) {
135
136     alg_pair userdata = {
137         .name = NULL,
138         .id = id
139     };
140
141     tpm2_alg_util_for_each_alg(find_match, &userdata);
142
143     return userdata.name;
144 }
145
146 TPM2_ALG_ID tpm2_alg_util_from_optarg(char *optarg) {
147
148     TPM2_ALG_ID halg;
149     bool res = tpm2_util_string_to_uint16(optarg, &halg);
150     if (!res) {
151         halg = tpm2_alg_util_strtoalg(optarg);
152     }
153     return halg;
154 }
155
156 bool tpm2_alg_util_is_hash_alg(TPM2_ALG_ID id) {
157
158     switch (id) {
159     case TPM2_ALG_SHA1 :
160         /* fallsthrough */
161     case TPM2_ALG_SHA256 :
162         /* fallsthrough */
163     case TPM2_ALG_SHA384 :
164         /* fallsthrough */
165     case TPM2_ALG_SHA512 :
166         /* fallsthrough */
167     case TPM2_ALG_SM3_256 :
168         return true;
169         /* no default */
170     }
171
172     return false;
173 }
174
175 UINT16 tpm2_alg_util_get_hash_size(TPMI_ALG_HASH id) {
176
177     switch (id) {
178     case TPM2_ALG_SHA1 :
179         return TPM2_SHA1_DIGEST_SIZE;
180     case TPM2_ALG_SHA256 :
181         return TPM2_SHA256_DIGEST_SIZE;
182     case TPM2_ALG_SHA384 :
183         return TPM2_SHA384_DIGEST_SIZE;
184     case TPM2_ALG_SHA512 :
185         return TPM2_SHA512_DIGEST_SIZE;
186     case TPM2_ALG_SM3_256 :
187         return TPM2_SM3_256_DIGEST_SIZE;
188         /* no default */
189     }
190
191     return 0;
192 }
193
194 static const char *hex_to_byte_err(int rc) {
195
196     switch (rc) {
197     case -2:
198         return "String not even in length";
199     case -3:
200         return "Non hex digit found";
201     case -4:
202         return "Hex value too big for digest";
203     }
204     return "unknown";
205 }
206
207 bool pcr_parse_digest_list(char **argv, int len,
208         tpm2_pcr_digest_spec *digest_spec) {
209
210     /*
211      * int is chosen because of what is passed in from main, avoids
212      * sign differences.
213      * */
214     int i;
215     for (i = 0; i < len; i++) {
216         tpm2_pcr_digest_spec *dspec = &digest_spec[i];
217
218         UINT32 count = 0;
219
220         /*
221          * Split <pcr index>:<hash alg>=<hash value>,... on : and separate with null byte, ie:
222          * <pce index> '\0' <hash alg>'\0'<data>
223          *
224          * Start by splitting out the pcr index, and validating it.
225          */
226         char *spec_str = argv[i];
227         char *pcr_index_str = spec_str;
228         char *digest_spec_str = strchr(spec_str, ':');
229         if (!digest_spec_str) {
230             LOG_ERR("Expecting : in digest spec, not found, got: \"%s\"", spec_str);
231             return false;
232         }
233
234         *digest_spec_str = '\0';
235         digest_spec_str++;
236
237         bool result = tpm2_util_string_to_uint32(pcr_index_str, &dspec->pcr_index);
238         if (!result) {
239             LOG_ERR("Got invalid PCR Index: \"%s\", in digest spec: \"%s\"",
240                     pcr_index_str, spec_str);
241             return false;
242         }
243
244         /* now that the pcr_index is removed, parse the remaining <hash_name>=<hash_value>,.. */
245         char *digest_hash_tok;
246         char *save_ptr = NULL;
247
248         /* keep track of digests we have seen */
249
250         while ((digest_hash_tok = strtok_r(digest_spec_str, ",", &save_ptr))) {
251             digest_spec_str = NULL;
252
253             if (count >= ARRAY_LEN(dspec->digests.digests)) {
254                 LOG_ERR("Specified too many digests per spec, max is: %zu",
255                         ARRAY_LEN(dspec->digests.digests));
256                 return false;
257             }
258
259             TPMT_HA *d = &dspec->digests.digests[count];
260
261             char *stralg = digest_hash_tok;
262             char *split = strchr(digest_hash_tok, '=');
263             if (!split) {
264                 LOG_ERR("Expecting = in <hash alg>=<hash value> spec, got: "
265                         "\"%s\"", digest_hash_tok);
266                 return false;
267             }
268             *split = '\0';
269             split++;
270
271             char *data = split;
272
273             /*
274              * Convert and validate the hash algorithm. It should be a hash algorithm
275              */
276             TPM2_ALG_ID alg = tpm2_alg_util_from_optarg(stralg);
277             if (alg == TPM2_ALG_ERROR) {
278                 LOG_ERR("Could not convert algorithm, got: \"%s\"", stralg);
279                 return false;
280             }
281
282             bool is_hash_alg = tpm2_alg_util_is_hash_alg(alg);
283             if (!is_hash_alg) {
284                 LOG_ERR("Algorithm is not a hash algorithm, got: \"%s\"",
285                         stralg);
286                 return false;
287             }
288
289             d->hashAlg = alg;
290
291             /* fill up the TPMT_HA structure with algorithm and digest */
292             BYTE *digest_data = (BYTE *) &d->digest;
293
294             UINT16 expected_hash_size = tpm2_alg_util_get_hash_size(alg);
295             /* strip any preceding hex on the data as tpm2_util_hex_to_byte_structure doesn't support it */
296             bool is_hex = !strncmp("0x", data, 2);
297             if (is_hex) {
298                 data += 2;
299             }
300
301             UINT16 size =  expected_hash_size;
302             int rc = tpm2_util_hex_to_byte_structure(data, &size,
303                     digest_data);
304             if (rc) {
305                 LOG_ERR("Error \"%s\" converting hex string as data, got:"
306                     " \"%s\"", hex_to_byte_err(rc), data);
307                 return false;
308             }
309
310             if (expected_hash_size != size) {
311                 LOG_ERR(
312                         "Algorithm \"%s\" expects a size of %u bytes, got: %u",
313                         stralg, expected_hash_size, size);
314                 return false;
315             }
316
317             count++;
318         }
319
320         if (!count) {
321             LOG_ERR("Missing or invalid <hash alg>=<hash value> spec for pcr:"
322                     " \"%s\"", pcr_index_str);
323             return false;
324         }
325
326         /* assign count at the end, so count is 0 on error */
327         dspec->digests.count = count;
328     }
329
330     return true;
331 }
332
333 UINT8* tpm2_extract_plain_signature(UINT16 *size, TPMT_SIGNATURE *signature) {
334
335     UINT8 *buffer = NULL;
336     *size = 0;
337
338     switch (signature->sigAlg) {
339     case TPM2_ALG_RSASSA:
340         *size = sizeof(signature->signature.rsassa.sig.buffer);
341         buffer = malloc(*size);
342         if (!buffer) {
343             goto nomem;
344         }
345         memcpy(buffer, signature->signature.rsassa.sig.buffer, *size);
346         break;
347     case TPM2_ALG_HMAC: {
348         TPMU_HA *hmac_sig = &(signature->signature.hmac.digest);
349         *size = tpm2_alg_util_get_hash_size(signature->signature.hmac.hashAlg);
350         buffer = malloc(*size);
351         if (!buffer) {
352             goto nomem;
353         }
354         memcpy(buffer, hmac_sig, *size);
355         break;
356     }
357     case TPM2_ALG_ECDSA: {
358         const size_t ECC_PAR_LEN = sizeof(TPM2B_ECC_PARAMETER);
359         *size = ECC_PAR_LEN * 2;
360         buffer = malloc(*size);
361         if (!buffer) {
362             goto nomem;
363         }
364         memcpy(buffer,
365             (UINT8*)&(signature->signature.ecdsa.signatureR),
366             ECC_PAR_LEN
367         );
368         memcpy(buffer + ECC_PAR_LEN,
369             (UINT8*)&(signature->signature.ecdsa.signatureS),
370             ECC_PAR_LEN
371         );
372         break;
373     }
374     default:
375         LOG_ERR("%s: unknown signature scheme: 0x%x", __func__,
376             signature->sigAlg);
377         return NULL;
378     }
379
380     return buffer;
381 nomem:
382     LOG_ERR("%s: couldn't allocate memory", __func__);
383     return NULL;
384 }
385
386 static bool get_key_type(TSS2_SYS_CONTEXT *sapi_context, TPMI_DH_OBJECT objectHandle,
387         TPMI_ALG_PUBLIC *type) {
388
389     TSS2L_SYS_AUTH_RESPONSE sessions_data_out;
390
391     TPM2B_PUBLIC out_public = TPM2B_EMPTY_INIT;
392
393     TPM2B_NAME name = TPM2B_TYPE_INIT(TPM2B_NAME, name);
394
395     TPM2B_NAME qaulified_name = TPM2B_TYPE_INIT(TPM2B_NAME, name);
396
397     TSS2_RC rval = Tss2_Sys_ReadPublic(sapi_context, objectHandle, 0, &out_public, &name,
398             &qaulified_name, &sessions_data_out);
399     if (rval != TPM2_RC_SUCCESS) {
400         LOG_ERR("Sys_ReadPublic failed, error code: 0x%x", rval);
401         return false;
402     }
403     *type = out_public.publicArea.type;
404     return true;
405 }
406
407 bool get_signature_scheme(TSS2_SYS_CONTEXT *sapi_context,
408         TPMI_DH_OBJECT keyHandle, TPMI_ALG_HASH halg,
409         TPMT_SIG_SCHEME *scheme) {
410
411     TPM2_ALG_ID type;
412     bool result = get_key_type(sapi_context, keyHandle, &type);
413     if (!result) {
414         return false;
415     }
416
417     switch (type) {
418     case TPM2_ALG_RSA :
419         scheme->scheme = TPM2_ALG_RSASSA;
420         scheme->details.rsassa.hashAlg = halg;
421         break;
422     case TPM2_ALG_KEYEDHASH :
423         scheme->scheme = TPM2_ALG_HMAC;
424         scheme->details.hmac.hashAlg = halg;
425         break;
426     case TPM2_ALG_ECC :
427         scheme->scheme = TPM2_ALG_ECDSA;
428         scheme->details.ecdsa.hashAlg = halg;
429         break;
430     case TPM2_ALG_SYMCIPHER :
431     default:
432         LOG_ERR("Unknown key type, got: 0x%x", type);
433         return false;
434     }
435
436     return true;
437 }