libtpmtss: Support for TSS2 v2 libraries
[strongswan.git] / src / libtpmtss / tpm_tss_tss2_v2.c
1 /*
2 * Copyright (C) 2018 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "tpm_tss_tss2.h"
17 #include "tpm_tss_tss2_names.h"
18
19 #ifdef TSS_TSS2_V2
20
21 #include <asn1/asn1.h>
22 #include <asn1/oid.h>
23 #include <bio/bio_reader.h>
24
25 #include <tss2/tss2_sys.h>
26 #include <dlfcn.h>
27
28 #define LABEL "TPM 2.0 -"
29
30 #define PLATFORM_PCR 24
31
32 typedef struct private_tpm_tss_tss2_t private_tpm_tss_tss2_t;
33
34 /**
35 * Private data of an tpm_tss_tss2_t object.
36 */
37 struct private_tpm_tss_tss2_t {
38
39 /**
40 * Public tpm_tss_tss2_t interface.
41 */
42 tpm_tss_t public;
43
44 /**
45 * TCTI context
46 */
47 TSS2_TCTI_CONTEXT *tcti_context;
48
49 /**
50 * SYS context
51 */
52 TSS2_SYS_CONTEXT *sys_context;
53
54 /**
55 * Number of supported algorithms
56 */
57 size_t supported_algs_count;
58
59 /**
60 * List of supported algorithms
61 */
62 TPM2_ALG_ID supported_algs[TPM2_PT_ALGORITHM_SET];
63 };
64
65 /**
66 * Global TCTI dynamic library handle and init function
67 */
68 static void *tcti_handle;
69
70 static TSS2_TCTI_INIT_FUNC tcti_init;
71
72 /**
73 * Empty AUTH_COMMAND
74 */
75 static const TPMS_AUTH_COMMAND auth_cmd_empty;
76
77 /**
78 * Convert hash algorithm to TPM2_ALG_ID
79 */
80 static TPM2_ALG_ID hash_alg_to_tpm_alg_id(hash_algorithm_t alg)
81 {
82 switch (alg)
83 {
84 case HASH_SHA1:
85 return TPM2_ALG_SHA1;
86 case HASH_SHA256:
87 return TPM2_ALG_SHA256;
88 case HASH_SHA384:
89 return TPM2_ALG_SHA384;
90 case HASH_SHA512:
91 return TPM2_ALG_SHA512;
92 default:
93 return TPM2_ALG_ERROR;
94 }
95 }
96
97 /**
98 * Convert TPM2_ALG_ID to hash algorithm
99 */
100 static hash_algorithm_t hash_alg_from_tpm_alg_id(TPM2_ALG_ID alg)
101 {
102 switch (alg)
103 {
104 case TPM2_ALG_SHA1:
105 return HASH_SHA1;
106 case TPM2_ALG_SHA256:
107 return HASH_SHA256;
108 case TPM2_ALG_SHA384:
109 return HASH_SHA384;
110 case TPM2_ALG_SHA512:
111 return HASH_SHA512;
112 default:
113 return HASH_UNKNOWN;
114 }
115 }
116
117 /**
118 * Check if an algorithm given by its TPM2_ALG_ID is supported by the TPM
119 */
120 static bool is_supported_alg(private_tpm_tss_tss2_t *this, TPM2_ALG_ID alg_id)
121 {
122 int i;
123
124 if (alg_id == TPM2_ALG_ERROR)
125 {
126 return FALSE;
127 }
128
129 for (i = 0; i < this->supported_algs_count; i++)
130 {
131 if (this->supported_algs[i] == alg_id)
132 {
133 return TRUE;
134 }
135 }
136
137 return FALSE;
138 }
139
140 /**
141 * Get a list of supported algorithms
142 */
143 static bool get_algs_capability(private_tpm_tss_tss2_t *this)
144 {
145 TPMS_CAPABILITY_DATA cap_data;
146 TPMS_TAGGED_PROPERTY tp;
147 TPMI_YES_NO more_data;
148 TPM2_ALG_ID alg;
149 uint32_t rval, i, offset, revision = 0, year = 0;
150 size_t len = BUF_LEN;
151 char buf[BUF_LEN], manufacturer[5], vendor_string[17];
152 char *pos = buf;
153 int written;
154
155 /* get fixed properties */
156 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM2_CAP_TPM_PROPERTIES,
157 TPM2_PT_FIXED, TPM2_MAX_TPM_PROPERTIES,
158 &more_data, &cap_data, 0);
159 if (rval != TPM2_RC_SUCCESS)
160 {
161 DBG1(DBG_PTS, "%s GetCapability failed for TPM2_CAP_TPM_PROPERTIES: 0x%06x",
162 LABEL, rval);
163 return FALSE;
164 }
165 memset(manufacturer, '\0', sizeof(manufacturer));
166 memset(vendor_string, '\0', sizeof(vendor_string));
167
168 /* print fixed properties */
169 for (i = 0; i < cap_data.data.tpmProperties.count; i++)
170 {
171 tp = cap_data.data.tpmProperties.tpmProperty[i];
172 switch (tp.property)
173 {
174 case TPM2_PT_REVISION:
175 revision = tp.value;
176 break;
177 case TPM2_PT_YEAR:
178 year = tp.value;
179 break;
180 case TPM2_PT_MANUFACTURER:
181 htoun32(manufacturer, tp.value);
182 break;
183 case TPM2_PT_VENDOR_STRING_1:
184 case TPM2_PT_VENDOR_STRING_2:
185 case TPM2_PT_VENDOR_STRING_3:
186 case TPM2_PT_VENDOR_STRING_4:
187 offset = 4 * (tp.property - TPM2_PT_VENDOR_STRING_1);
188 htoun32(vendor_string + offset, tp.value);
189 break;
190 default:
191 break;
192 }
193 }
194 DBG2(DBG_PTS, "%s manufacturer: %s (%s) rev: %05.2f %u", LABEL, manufacturer,
195 vendor_string, (float)revision/100, year);
196
197 /* get supported algorithms */
198 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM2_CAP_ALGS,
199 0, TPM2_PT_ALGORITHM_SET, &more_data, &cap_data, 0);
200 if (rval != TPM2_RC_SUCCESS)
201 {
202 DBG1(DBG_PTS, "%s GetCapability failed for TPM2_CAP_ALGS: 0x%06x",
203 LABEL, rval);
204 return FALSE;
205 }
206
207 /* Number of supported algorithms */
208 this->supported_algs_count = cap_data.data.algorithms.count;
209
210 /* store and print supported algorithms */
211 for (i = 0; i < this->supported_algs_count; i++)
212 {
213 alg = cap_data.data.algorithms.algProperties[i].alg;
214 this->supported_algs[i] = alg;
215
216 written = snprintf(pos, len, " %N", tpm_alg_id_names, alg);
217 if (written < 0 || written >= len)
218 {
219 break;
220 }
221 pos += written;
222 len -= written;
223 }
224 DBG2(DBG_PTS, "%s algorithms:%s", LABEL, buf);
225
226 /* get supported ECC curves */
227 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM2_CAP_ECC_CURVES,
228 0, TPM2_PT_LOADED_CURVES, &more_data, &cap_data, 0);
229 if (rval != TPM2_RC_SUCCESS)
230 {
231 DBG1(DBG_PTS, "%s GetCapability failed for TPM2_ECC_CURVES: 0x%06x",
232 LABEL, rval);
233 return FALSE;
234 }
235
236 /* reset print buffer */
237 pos = buf;
238 len = BUF_LEN;
239
240 /* print supported ECC curves */
241 for (i = 0; i < cap_data.data.eccCurves.count; i++)
242 {
243 written = snprintf(pos, len, " %N", tpm_ecc_curve_names,
244 cap_data.data.eccCurves.eccCurves[i]);
245 if (written < 0 || written >= len)
246 {
247 break;
248 }
249 pos += written;
250 len -= written;
251 }
252 DBG2(DBG_PTS, "%s ECC curves:%s", LABEL, buf);
253
254 return TRUE;
255 }
256
257 /**
258 * Initialize TSS2 TCTI context
259 */
260 static bool initialize_tcti_context(private_tpm_tss_tss2_t *this)
261 {
262 size_t tcti_context_size;
263 uint32_t rval;
264
265 if (!tcti_init)
266 {
267 return FALSE;
268 }
269
270 /* determine size of tcti context */
271 rval = tcti_init(NULL, &tcti_context_size, "");
272 if (rval != TSS2_RC_SUCCESS)
273 {
274 DBG1(DBG_PTS, "%s tcti init setup failed: 0x%06x", LABEL, rval);
275 return FALSE;
276 }
277
278 /* allocate and initialize memory for tcti context */
279 this->tcti_context = (TSS2_TCTI_CONTEXT*)malloc(tcti_context_size);
280 memset(this->tcti_context, 0x00, tcti_context_size);
281
282 /* initialize tcti context */
283 rval = tcti_init(this->tcti_context, &tcti_context_size, "");
284 if (rval != TSS2_RC_SUCCESS)
285 {
286 DBG1(DBG_PTS, "%s tcti init allocation failed: 0x%06x", LABEL,rval);
287 return FALSE;
288 }
289 return TRUE;
290 }
291
292 /**
293 * Initialize TSS2 Sys context
294 */
295 static bool initialize_sys_context(private_tpm_tss_tss2_t *this)
296 {
297 uint32_t sys_context_size;
298 uint32_t rval;
299
300 TSS2_ABI_VERSION abi_version = {
301 .tssCreator = 1,
302 .tssFamily = 2,
303 .tssLevel = 1,
304 .tssVersion = 108
305 };
306
307 /* determine size of sys context */
308 sys_context_size = Tss2_Sys_GetContextSize(0);
309
310 /* allocate memory for sys context */
311 this->sys_context = (TSS2_SYS_CONTEXT*)malloc(sys_context_size);
312
313 /* initialize sys context */
314 rval = Tss2_Sys_Initialize(this->sys_context, sys_context_size,
315 this->tcti_context, &abi_version);
316 if (rval != TSS2_RC_SUCCESS)
317 {
318 DBG1(DBG_PTS, "%s could not get sys_context: 0x%06x",
319 LABEL, rval);
320 return FALSE;
321 }
322
323 /* get a list of supported algorithms and ECC curves */
324 return get_algs_capability(this);
325 }
326
327 /**
328 * Finalize TSS context
329 */
330 static void finalize_context(private_tpm_tss_tss2_t *this)
331 {
332 if (this->tcti_context)
333 {
334 Tss2_Tcti_Finalize(this->tcti_context);
335 free(this->tcti_context);
336 }
337 if (this->sys_context)
338 {
339 Tss2_Sys_Finalize(this->sys_context);
340 free(this->sys_context);
341 }
342 }
343
344 METHOD(tpm_tss_t, get_version, tpm_version_t,
345 private_tpm_tss_tss2_t *this)
346 {
347 return TPM_VERSION_2_0;
348 }
349
350 METHOD(tpm_tss_t, get_version_info, chunk_t,
351 private_tpm_tss_tss2_t *this)
352 {
353 return chunk_empty;
354 }
355
356 /**
357 * read the public key portion of a TSS 2.0 AIK key from NVRAM
358 */
359 bool read_public(private_tpm_tss_tss2_t *this, TPMI_DH_OBJECT handle,
360 TPM2B_PUBLIC *public)
361 {
362 uint32_t rval;
363
364 TPM2B_NAME name = { sizeof(TPM2B_NAME)-2, };
365 TPM2B_NAME qualified_name = { sizeof(TPM2B_NAME)-2, };
366 TSS2L_SYS_AUTH_RESPONSE auth_rsp;
367
368
369 /* read public key for a given object handle from TPM 2.0 NVRAM */
370 rval = Tss2_Sys_ReadPublic(this->sys_context, handle, 0, public, &name,
371 &qualified_name, &auth_rsp);
372 if (rval != TPM2_RC_SUCCESS)
373 {
374 DBG1(DBG_PTS, "%s could not read public key from handle 0x%08x: 0x%06x",
375 LABEL, handle, rval);
376 return FALSE;
377 }
378 return TRUE;
379 }
380
381 METHOD(tpm_tss_t, generate_aik, bool,
382 private_tpm_tss_tss2_t *this, chunk_t ca_modulus, chunk_t *aik_blob,
383 chunk_t *aik_pubkey, chunk_t *identity_req)
384 {
385 return FALSE;
386 }
387
388 METHOD(tpm_tss_t, get_public, chunk_t,
389 private_tpm_tss_tss2_t *this, uint32_t handle)
390 {
391 TPM2B_PUBLIC public = { 0, };
392 TPM2_ALG_ID sig_alg, digest_alg;
393 chunk_t aik_blob, aik_pubkey = chunk_empty;
394
395 if (!read_public(this, handle, &public))
396 {
397 return chunk_empty;
398 }
399
400 aik_blob = chunk_create((u_char*)&public, sizeof(public));
401 DBG3(DBG_LIB, "%s AIK public key blob: %B", LABEL, &aik_blob);
402
403 /* convert TSS 2.0 AIK public key blot into PKCS#1 format */
404 switch (public.publicArea.type)
405 {
406 case TPM2_ALG_RSA:
407 {
408 TPM2B_PUBLIC_KEY_RSA *rsa;
409 TPMT_RSA_SCHEME *scheme;
410 chunk_t aik_exponent, aik_modulus;
411
412 scheme = &public.publicArea.parameters.rsaDetail.scheme;
413 sig_alg = scheme->scheme;
414 digest_alg = scheme->details.anySig.hashAlg;
415
416 rsa = &public.publicArea.unique.rsa;
417 aik_modulus = chunk_create(rsa->buffer, rsa->size);
418 aik_exponent = chunk_from_chars(0x01, 0x00, 0x01);
419
420 /* subjectPublicKeyInfo encoding of AIK RSA key */
421 if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER,
422 NULL, &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus,
423 CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END))
424 {
425 DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of AIK key "
426 "failed", LABEL);
427 return chunk_empty;
428 }
429 break;
430 }
431 case TPM2_ALG_ECC:
432 {
433 TPMS_ECC_POINT *ecc;
434 TPMT_ECC_SCHEME *scheme;
435 chunk_t ecc_point;
436 uint8_t *pos;
437
438 scheme = &public.publicArea.parameters.eccDetail.scheme;
439 sig_alg = scheme->scheme;
440 digest_alg = scheme->details.anySig.hashAlg;
441
442 ecc = &public.publicArea.unique.ecc;
443
444 /* allocate space for bit string */
445 pos = asn1_build_object(&ecc_point, ASN1_BIT_STRING,
446 2 + ecc->x.size + ecc->y.size);
447 /* bit string length is a multiple of octets */
448 *pos++ = 0x00;
449 /* uncompressed ECC point format */
450 *pos++ = 0x04;
451 /* copy x coordinate of ECC point */
452 memcpy(pos, ecc->x.buffer, ecc->x.size);
453 pos += ecc->x.size;
454 /* copy y coordinate of ECC point */
455 memcpy(pos, ecc->y.buffer, ecc->y.size);
456 /* subjectPublicKeyInfo encoding of AIK ECC key */
457 aik_pubkey = asn1_wrap(ASN1_SEQUENCE, "mm",
458 asn1_wrap(ASN1_SEQUENCE, "mm",
459 asn1_build_known_oid(OID_EC_PUBLICKEY),
460 asn1_build_known_oid(ecc->x.size == 32 ?
461 OID_PRIME256V1 : OID_SECT384R1)),
462 ecc_point);
463 break;
464 }
465 default:
466 DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL);
467 return chunk_empty;
468 }
469 DBG1(DBG_PTS, "AIK signature algorithm is %N with %N hash",
470 tpm_alg_id_names, sig_alg, tpm_alg_id_names, digest_alg);
471 return aik_pubkey;
472 }
473
474 /**
475 * Configure a PCR Selection assuming a maximum of 24 registers
476 */
477 static bool init_pcr_selection(private_tpm_tss_tss2_t *this, uint32_t pcrs,
478 hash_algorithm_t alg, TPML_PCR_SELECTION *pcr_sel)
479 {
480 TPM2_ALG_ID alg_id;
481 uint32_t pcr;
482
483 /* check if hash algorithm is supported by TPM */
484 alg_id = hash_alg_to_tpm_alg_id(alg);
485 if (!is_supported_alg(this, alg_id))
486 {
487 DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM",
488 LABEL, hash_algorithm_short_names, alg);
489 return FALSE;
490 }
491
492 /* initialize the PCR Selection structure,*/
493 pcr_sel->count = 1;
494 pcr_sel->pcrSelections[0].hash = alg_id;
495 pcr_sel->pcrSelections[0].sizeofSelect = 3;
496 pcr_sel->pcrSelections[0].pcrSelect[0] = 0;
497 pcr_sel->pcrSelections[0].pcrSelect[1] = 0;
498 pcr_sel->pcrSelections[0].pcrSelect[2] = 0;
499
500 /* set the selected PCRs */
501 for (pcr = 0; pcr < PLATFORM_PCR; pcr++)
502 {
503 if (pcrs & (1 << pcr))
504 {
505 pcr_sel->pcrSelections[0].pcrSelect[pcr / 8] |= ( 1 << (pcr % 8) );
506 }
507 }
508 return TRUE;
509 }
510
511 METHOD(tpm_tss_t, read_pcr, bool,
512 private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
513 hash_algorithm_t alg)
514 {
515 TPML_PCR_SELECTION pcr_selection;
516 TPML_DIGEST pcr_values;
517
518 uint32_t pcr_update_counter, rval;
519 uint8_t *pcr_value_ptr;
520 size_t pcr_value_len;
521
522 if (pcr_num >= PLATFORM_PCR)
523 {
524 DBG1(DBG_PTS, "%s maximum number of supported PCR is %d",
525 LABEL, PLATFORM_PCR);
526 return FALSE;
527 }
528
529 if (!init_pcr_selection(this, (1 << pcr_num), alg, &pcr_selection))
530 {
531 return FALSE;
532 }
533
534 /* initialize the PCR Digest structure */
535 memset(&pcr_values, 0, sizeof(TPML_DIGEST));
536
537 /* read the PCR value */
538 rval = Tss2_Sys_PCR_Read(this->sys_context, 0, &pcr_selection,
539 &pcr_update_counter, &pcr_selection, &pcr_values, 0);
540 if (rval != TPM2_RC_SUCCESS)
541 {
542 DBG1(DBG_PTS, "%s PCR bank could not be read: 0x%60x",
543 LABEL, rval);
544 return FALSE;
545 }
546 pcr_value_ptr = (uint8_t *)pcr_values.digests[0].buffer;
547 pcr_value_len = (size_t) pcr_values.digests[0].size;
548
549 *pcr_value = chunk_clone(chunk_create(pcr_value_ptr, pcr_value_len));
550
551 return TRUE;
552 }
553
554 METHOD(tpm_tss_t, extend_pcr, bool,
555 private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
556 chunk_t data, hash_algorithm_t alg)
557 {
558 uint32_t rval;
559 TPM2_ALG_ID alg_id;
560 TPML_DIGEST_VALUES digest_values;
561 TSS2L_SYS_AUTH_COMMAND auth_cmd = { 1, { auth_cmd_empty } };
562 TSS2L_SYS_AUTH_RESPONSE auth_rsp;
563
564 auth_cmd.auths[0].sessionHandle = TPM2_RS_PW;
565
566 /* check if hash algorithm is supported by TPM */
567 alg_id = hash_alg_to_tpm_alg_id(alg);
568 if (!is_supported_alg(this, alg_id))
569 {
570 DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM",
571 LABEL, hash_algorithm_short_names, alg);
572 return FALSE;
573 }
574
575 digest_values.count = 1;
576 digest_values.digests[0].hashAlg = alg_id;
577
578 switch (alg)
579 {
580 case HASH_SHA1:
581 if (data.len != HASH_SIZE_SHA1)
582 {
583 return FALSE;
584 }
585 memcpy(digest_values.digests[0].digest.sha1, data.ptr,
586 HASH_SIZE_SHA1);
587 break;
588 case HASH_SHA256:
589 if (data.len != HASH_SIZE_SHA256)
590 {
591 return FALSE;
592 }
593 memcpy(digest_values.digests[0].digest.sha256, data.ptr,
594 HASH_SIZE_SHA256);
595 break;
596 case HASH_SHA384:
597 if (data.len != HASH_SIZE_SHA384)
598 {
599 return FALSE;
600 }
601 memcpy(digest_values.digests[0].digest.sha384, data.ptr,
602 HASH_SIZE_SHA384);
603 break;
604 case HASH_SHA512:
605 if (data.len != HASH_SIZE_SHA512)
606 {
607 return FALSE;
608 }
609 memcpy(digest_values.digests[0].digest.sha512, data.ptr,
610 HASH_SIZE_SHA512);
611 break;
612 default:
613 return FALSE;
614 }
615
616 /* extend PCR */
617 rval = Tss2_Sys_PCR_Extend(this->sys_context, pcr_num, &auth_cmd,
618 &digest_values, &auth_rsp);
619 if (rval != TPM2_RC_SUCCESS)
620 {
621 DBG1(DBG_PTS, "%s PCR %02u could not be extended: 0x%06x",
622 LABEL, pcr_num, rval);
623 return FALSE;
624 }
625
626 /* get updated PCR value */
627 return read_pcr(this, pcr_num, pcr_value, alg);
628 }
629
630 METHOD(tpm_tss_t, quote, bool,
631 private_tpm_tss_tss2_t *this, uint32_t aik_handle, uint32_t pcr_sel,
632 hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t *quote_mode,
633 tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig)
634 {
635 chunk_t quoted_chunk, qualified_signer, extra_data, clock_info,
636 firmware_version, pcr_select, pcr_digest;
637 hash_algorithm_t pcr_digest_alg;
638 bio_reader_t *reader;
639 uint32_t rval;
640
641 TPM2B_DATA qualifying_data;
642 TPML_PCR_SELECTION pcr_selection;
643 TPM2B_ATTEST quoted = { sizeof(TPM2B_ATTEST)-2, };
644 TPMT_SIG_SCHEME scheme;
645 TPMT_SIGNATURE sig;
646 TPMI_ALG_HASH hash_alg;
647 TSS2L_SYS_AUTH_COMMAND auth_cmd = { 1, { auth_cmd_empty } };
648 TSS2L_SYS_AUTH_RESPONSE auth_rsp;
649
650 auth_cmd.auths[0].sessionHandle = TPM2_RS_PW;
651
652 qualifying_data.size = data.len;
653 memcpy(qualifying_data.buffer, data.ptr, data.len);
654
655 scheme.scheme = TPM2_ALG_NULL;
656 memset(&sig, 0x00, sizeof(sig));
657
658 /* set Quote mode */
659 *quote_mode = TPM_QUOTE_TPM2;
660
661 if (!init_pcr_selection(this, pcr_sel, alg, &pcr_selection))
662 {
663 return FALSE;
664 }
665
666 rval = Tss2_Sys_Quote(this->sys_context, aik_handle, &auth_cmd,
667 &qualifying_data, &scheme, &pcr_selection, &quoted,
668 &sig, &auth_rsp);
669 if (rval != TPM2_RC_SUCCESS)
670 {
671 DBG1(DBG_PTS,"%s Tss2_Sys_Quote failed: 0x%06x", LABEL, rval);
672 return FALSE;
673 }
674 quoted_chunk = chunk_create(quoted.attestationData, quoted.size);
675
676 reader = bio_reader_create(chunk_skip(quoted_chunk, 6));
677 if (!reader->read_data16(reader, &qualified_signer) ||
678 !reader->read_data16(reader, &extra_data) ||
679 !reader->read_data (reader, 17, &clock_info) ||
680 !reader->read_data (reader, 8, &firmware_version) ||
681 !reader->read_data (reader, 10, &pcr_select) ||
682 !reader->read_data16(reader, &pcr_digest))
683 {
684 DBG1(DBG_PTS, "%s parsing of quoted struct failed", LABEL);
685 reader->destroy(reader);
686 return FALSE;
687 }
688 reader->destroy(reader);
689
690 DBG2(DBG_PTS, "PCR Composite digest: %B", &pcr_digest);
691 DBG2(DBG_PTS, "TPM Quote Info: %B", &quoted_chunk);
692 DBG2(DBG_PTS, "qualifiedSigner: %B", &qualified_signer);
693 DBG2(DBG_PTS, "extraData: %B", &extra_data);
694 DBG2(DBG_PTS, "clockInfo: %B", &clock_info);
695 DBG2(DBG_PTS, "firmwareVersion: %B", &firmware_version);
696 DBG2(DBG_PTS, "pcrSelect: %B", &pcr_select);
697
698 /* extract signature */
699 switch (sig.sigAlg)
700 {
701 case TPM2_ALG_RSASSA:
702 case TPM2_ALG_RSAPSS:
703 *quote_sig = chunk_clone(
704 chunk_create(
705 sig.signature.rsassa.sig.buffer,
706 sig.signature.rsassa.sig.size));
707 hash_alg = sig.signature.rsassa.hash;
708 break;
709 case TPM2_ALG_ECDSA:
710 case TPM2_ALG_ECDAA:
711 case TPM2_ALG_SM2:
712 case TPM2_ALG_ECSCHNORR:
713 *quote_sig = chunk_cat("cc",
714 chunk_create(
715 sig.signature.ecdsa.signatureR.buffer,
716 sig.signature.ecdsa.signatureR.size),
717 chunk_create(
718 sig.signature.ecdsa.signatureS.buffer,
719 sig.signature.ecdsa.signatureS.size));
720 hash_alg = sig.signature.ecdsa.hash;
721 break;
722 default:
723 DBG1(DBG_PTS, "%s unsupported %N signature algorithm",
724 LABEL, tpm_alg_id_names, sig.sigAlg);
725 return FALSE;
726 };
727
728 DBG2(DBG_PTS, "PCR digest algorithm is %N", tpm_alg_id_names, hash_alg);
729 pcr_digest_alg = hash_alg_from_tpm_alg_id(hash_alg);
730
731 DBG2(DBG_PTS, "TPM Quote Signature: %B", quote_sig);
732
733 /* Create and initialize Quote Info object */
734 *quote_info = tpm_tss_quote_info_create(*quote_mode, pcr_digest_alg,
735 pcr_digest);
736 (*quote_info)->set_tpm2_info(*quote_info, qualified_signer, clock_info,
737 pcr_select);
738 (*quote_info)->set_version_info(*quote_info, firmware_version);
739
740 return TRUE;
741 }
742
743 METHOD(tpm_tss_t, sign, bool,
744 private_tpm_tss_tss2_t *this, uint32_t hierarchy, uint32_t handle,
745 signature_scheme_t scheme, chunk_t data, chunk_t pin, chunk_t *signature)
746 {
747 key_type_t key_type;
748 hash_algorithm_t hash_alg;
749 uint32_t rval;
750
751 TPM2_ALG_ID alg_id;
752 TPM2B_MAX_BUFFER buffer;
753 TPM2B_DIGEST hash = { sizeof(TPM2B_DIGEST)-2, };
754 TPMT_TK_HASHCHECK validation;
755 TPM2B_PUBLIC public = { 0, };
756 TPMT_SIG_SCHEME sig_scheme;
757 TPMT_SIGNATURE sig;
758 TPMS_AUTH_COMMAND *cmd;
759 TSS2L_SYS_AUTH_COMMAND auth_cmd = { 1, { auth_cmd_empty } };
760 TSS2L_SYS_AUTH_RESPONSE auth_rsp;
761
762 cmd = &auth_cmd.auths[0];
763 cmd->sessionHandle = TPM2_RS_PW;
764
765 if (pin.len > 0)
766 {
767 cmd->hmac.size = min(sizeof(cmd->hmac)-2, pin.len);
768 memcpy(cmd->hmac.buffer, pin.ptr, cmd->hmac.size);
769 }
770
771 key_type = key_type_from_signature_scheme(scheme);
772 hash_alg = hasher_from_signature_scheme(scheme, NULL);
773
774 /* Check if hash algorithm is supported by TPM */
775 alg_id = hash_alg_to_tpm_alg_id(hash_alg);
776 if (!is_supported_alg(this, alg_id))
777 {
778 DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM",
779 LABEL, hash_algorithm_short_names, hash_alg);
780 return FALSE;
781 }
782
783 /* Get public key */
784 if (!read_public(this, handle, &public))
785 {
786 return FALSE;
787 }
788
789 if (key_type == KEY_RSA && public.publicArea.type == TPM2_ALG_RSA)
790 {
791 sig_scheme.scheme = TPM2_ALG_RSASSA;
792 sig_scheme.details.rsassa.hashAlg = alg_id;
793 }
794 else if (key_type == KEY_ECDSA && public.publicArea.type == TPM2_ALG_ECC)
795 {
796 sig_scheme.scheme = TPM2_ALG_ECDSA;
797 sig_scheme.details.ecdsa.hashAlg = alg_id;
798
799 }
800 else
801 {
802 DBG1(DBG_PTS, "%s signature scheme %N not supported by TPM key",
803 LABEL, signature_scheme_names, scheme);
804 return FALSE;
805 }
806
807 if (data.len <= TPM2_MAX_DIGEST_BUFFER)
808 {
809 memcpy(buffer.buffer, data.ptr, data.len);
810 buffer.size = data.len;
811
812 rval = Tss2_Sys_Hash(this->sys_context, 0, &buffer, alg_id, hierarchy,
813 &hash, &validation, 0);
814 if (rval != TPM2_RC_SUCCESS)
815 {
816 DBG1(DBG_PTS,"%s Tss2_Sys_Hash failed: 0x%06x", LABEL, rval);
817 return FALSE;
818 }
819 }
820 else
821 {
822 TPMI_DH_OBJECT sequence_handle;
823 TPM2B_AUTH null_auth;
824
825 null_auth.size = 0;
826 rval = Tss2_Sys_HashSequenceStart(this->sys_context, 0, &null_auth,
827 alg_id, &sequence_handle, 0);
828 if (rval != TPM2_RC_SUCCESS)
829 {
830 DBG1(DBG_PTS,"%s Tss2_Sys_HashSequenceStart failed: 0x%06x",
831 LABEL, rval);
832 return FALSE;
833 }
834
835 while (data.len > 0)
836 {
837 buffer.size = min(data.len, TPM2_MAX_DIGEST_BUFFER);
838 memcpy(buffer.buffer, data.ptr, buffer.size);
839 data.ptr += buffer.size;
840 data.len -= buffer.size;
841
842 rval = Tss2_Sys_SequenceUpdate(this->sys_context, sequence_handle,
843 &auth_cmd, &buffer, 0);
844 if (rval != TPM2_RC_SUCCESS)
845 {
846 DBG1(DBG_PTS,"%s Tss2_Sys_SequenceUpdate failed: 0x%06x",
847 LABEL, rval);
848 return FALSE;
849 }
850 }
851 buffer.size = 0;
852
853 rval = Tss2_Sys_SequenceComplete(this->sys_context, sequence_handle,
854 &auth_cmd, &buffer, hierarchy,
855 &hash, &validation, 0);
856 if (rval != TPM2_RC_SUCCESS)
857 {
858 DBG1(DBG_PTS,"%s Tss2_Sys_SequenceComplete failed: 0x%06x",
859 LABEL, rval);
860 return FALSE;
861 }
862 }
863
864 rval = Tss2_Sys_Sign(this->sys_context, handle, &auth_cmd, &hash,
865 &sig_scheme, &validation, &sig, &auth_rsp);
866 if (rval != TPM2_RC_SUCCESS)
867 {
868 DBG1(DBG_PTS,"%s Tss2_Sys_Sign failed: 0x%06x", LABEL, rval);
869 return FALSE;
870 }
871
872 /* extract signature */
873 switch (scheme)
874 {
875 case SIGN_RSA_EMSA_PKCS1_SHA1:
876 case SIGN_RSA_EMSA_PKCS1_SHA2_256:
877 case SIGN_RSA_EMSA_PKCS1_SHA2_384:
878 case SIGN_RSA_EMSA_PKCS1_SHA2_512:
879 *signature = chunk_clone(
880 chunk_create(
881 sig.signature.rsassa.sig.buffer,
882 sig.signature.rsassa.sig.size));
883 break;
884 case SIGN_ECDSA_256:
885 case SIGN_ECDSA_384:
886 case SIGN_ECDSA_521:
887 *signature = chunk_cat("cc",
888 chunk_create(
889 sig.signature.ecdsa.signatureR.buffer,
890 sig.signature.ecdsa.signatureR.size),
891 chunk_create(
892 sig.signature.ecdsa.signatureS.buffer,
893 sig.signature.ecdsa.signatureS.size));
894 break;
895 case SIGN_ECDSA_WITH_SHA256_DER:
896 case SIGN_ECDSA_WITH_SHA384_DER:
897 case SIGN_ECDSA_WITH_SHA512_DER:
898 *signature = asn1_wrap(ASN1_SEQUENCE, "mm",
899 asn1_integer("c",
900 chunk_create(
901 sig.signature.ecdsa.signatureR.buffer,
902 sig.signature.ecdsa.signatureR.size)),
903 asn1_integer("c",
904 chunk_create(
905 sig.signature.ecdsa.signatureS.buffer,
906 sig.signature.ecdsa.signatureS.size)));
907 break;
908 default:
909 DBG1(DBG_PTS, "%s unsupported %N signature scheme",
910 LABEL, signature_scheme_names, scheme);
911 return FALSE;
912 };
913
914 return TRUE;
915 }
916
917 METHOD(tpm_tss_t, get_random, bool,
918 private_tpm_tss_tss2_t *this, size_t bytes, uint8_t *buffer)
919 {
920 size_t len, random_len= sizeof(TPM2B_DIGEST)-2;
921 TPM2B_DIGEST random = { random_len, };
922 uint8_t *pos = buffer;
923 uint32_t rval;
924
925 while (bytes > 0)
926 {
927 len = min(bytes, random_len);
928
929 rval = Tss2_Sys_GetRandom(this->sys_context, NULL, len, &random, NULL);
930 if (rval != TSS2_RC_SUCCESS)
931 {
932 DBG1(DBG_PTS,"%s Tss2_Sys_GetRandom failed: 0x%06x", LABEL, rval);
933 return FALSE;
934 }
935 memcpy(pos, random.buffer, random.size);
936 pos += random.size;
937 bytes -= random.size;
938 }
939
940 return TRUE;
941 }
942
943 METHOD(tpm_tss_t, get_data, bool,
944 private_tpm_tss_tss2_t *this, uint32_t hierarchy, uint32_t handle,
945 chunk_t pin, chunk_t *data)
946 {
947 uint16_t max_data_size, nv_size, nv_offset = 0;
948 uint32_t rval;
949
950 TPMS_CAPABILITY_DATA cap_data;
951 TPMI_YES_NO more_data;
952 TPM2B_NAME nv_name = { sizeof(TPM2B_NAME)-2, };
953 TPM2B_NV_PUBLIC nv_public = { 0, };
954 TPM2B_MAX_NV_BUFFER nv_data = { TPM2_MAX_NV_BUFFER_SIZE, };
955 TPMS_AUTH_COMMAND *cmd;
956 TSS2L_SYS_AUTH_COMMAND auth_cmd = { 1, { auth_cmd_empty } };
957 TSS2L_SYS_AUTH_RESPONSE auth_rsp;
958
959 /* query maximum TPM data transmission size */
960 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM2_CAP_TPM_PROPERTIES,
961 TPM2_PT_NV_BUFFER_MAX, 1, &more_data, &cap_data, 0);
962 if (rval != TPM2_RC_SUCCESS)
963 {
964 DBG1(DBG_PTS,"%s Tss2_Sys_GetCapability failed for "
965 "TPM2_CAP_TPM_PROPERTIES: 0x%06x", LABEL, rval);
966 return FALSE;
967 }
968 max_data_size = min(cap_data.data.tpmProperties.tpmProperty[0].value,
969 TPM2_MAX_NV_BUFFER_SIZE);
970
971 /* get size of NV object */
972 rval = Tss2_Sys_NV_ReadPublic(this->sys_context, handle, 0, &nv_public,
973 &nv_name, 0);
974 if (rval != TPM2_RC_SUCCESS)
975 {
976 DBG1(DBG_PTS,"%s Tss2_Sys_NV_ReadPublic failed: 0x%06x", LABEL, rval);
977 return FALSE;
978 }
979 nv_size = nv_public.nvPublic.dataSize;
980 *data = chunk_alloc(nv_size);
981
982 /* prepare NV read session */
983 cmd = &auth_cmd.auths[0];
984 cmd->sessionHandle = TPM2_RS_PW;
985
986 if (pin.len > 0)
987 {
988 cmd->hmac.size = min(sizeof(cmd->hmac)-2, pin.len);
989 memcpy(cmd->hmac.buffer, pin.ptr, cmd->hmac.size);
990 }
991
992 /* read NV data a maximum data size block at a time */
993 while (nv_size > 0)
994 {
995 rval = Tss2_Sys_NV_Read(this->sys_context, hierarchy, handle, &auth_cmd,
996 min(nv_size, max_data_size), nv_offset, &nv_data, &auth_rsp);
997
998 if (rval != TPM2_RC_SUCCESS)
999 {
1000 DBG1(DBG_PTS,"%s Tss2_Sys_NV_Read failed: 0x%06x", LABEL, rval);
1001 chunk_free(data);
1002 return FALSE;
1003 }
1004 memcpy(data->ptr + nv_offset, nv_data.buffer, nv_data.size);
1005 nv_offset += nv_data.size;
1006 nv_size -= nv_data.size;
1007 }
1008
1009 return TRUE;
1010 }
1011
1012 METHOD(tpm_tss_t, destroy, void,
1013 private_tpm_tss_tss2_t *this)
1014 {
1015 finalize_context(this);
1016 free(this);
1017 }
1018
1019 /**
1020 * See header
1021 */
1022 tpm_tss_t *tpm_tss_tss2_create()
1023 {
1024 private_tpm_tss_tss2_t *this;
1025 bool available;
1026
1027 INIT(this,
1028 .public = {
1029 .get_version = _get_version,
1030 .get_version_info = _get_version_info,
1031 .generate_aik = _generate_aik,
1032 .get_public = _get_public,
1033 .read_pcr = _read_pcr,
1034 .extend_pcr = _extend_pcr,
1035 .quote = _quote,
1036 .sign = _sign,
1037 .get_random = _get_random,
1038 .get_data = _get_data,
1039 .destroy = _destroy,
1040 },
1041 );
1042
1043 available = initialize_tcti_context(this);
1044 if (available)
1045 {
1046 available = initialize_sys_context(this);
1047 }
1048 DBG1(DBG_PTS, "TPM 2.0 via TSS2 v2 %savailable", available ? "" : "not ");
1049
1050 if (!available)
1051 {
1052 destroy(this);
1053 return NULL;
1054 }
1055 return &this->public;
1056 }
1057
1058 /**
1059 * See header
1060 */
1061 bool tpm_tss_tss2_init(void)
1062 {
1063 TSS2_TCTI_INFO_FUNC infofn;
1064 const TSS2_TCTI_INFO *info;
1065 char tcti_lib_format[] = "libtss2-tcti-%s.so.0";
1066 char tcti_lib[BUF_LEN];
1067 char *tcti_names[] = { "tabrmd", "device", "mssim" };
1068 char *tcti_name;
1069 bool match = FALSE;
1070 int i;
1071
1072 /* select a dynamic TCTI library */
1073 tcti_name = lib->settings->get_str(lib->settings,
1074 "%s.plugins.tpm.tcti.name", tcti_names[0], lib->ns);
1075 snprintf(tcti_lib, BUF_LEN, tcti_lib_format, tcti_name);
1076
1077 for (i = 0; i < countof(tcti_names); i++)
1078 {
1079 if (streq(tcti_name, tcti_names[i]))
1080 {
1081 match = TRUE;
1082 }
1083 }
1084 if (!match)
1085 {
1086 DBG1(DBG_PTS, "%s \"%s\" is not a valid TCTI library name",
1087 LABEL, tcti_lib);
1088 return FALSE;
1089 }
1090
1091 /* open the selected dynamic TCTI library */
1092 tcti_handle = dlopen(tcti_lib, RTLD_LAZY);
1093 if (!tcti_handle)
1094 {
1095 DBG1(DBG_PTS, "%s could not load \"%s\"", LABEL, tcti_lib);
1096 return FALSE;
1097 }
1098
1099 infofn = (TSS2_TCTI_INFO_FUNC)dlsym(tcti_handle, TSS2_TCTI_INFO_SYMBOL);
1100 if (!infofn)
1101 {
1102 DBG1(DBG_PTS, "%s symbol \"%s\" not found in \"%s\"", LABEL,
1103 TSS2_TCTI_INFO_SYMBOL, tcti_lib);
1104 tpm_tss_tss2_deinit();
1105
1106 return FALSE;
1107 }
1108 DBG2(DBG_PTS, "%s \"%s\" successfully loaded", LABEL, tcti_lib);
1109 info = infofn();
1110 tcti_init = info->init;
1111
1112 return TRUE;
1113 }
1114
1115 /**
1116 * See header
1117 */
1118 void tpm_tss_tss2_deinit(void)
1119 {
1120 dlclose(tcti_handle);
1121 tcti_handle = tcti_init = NULL;
1122 }
1123
1124 #else /* TSS_TSS2_V2 */
1125
1126 /**
1127 * See header
1128 */
1129 bool tpm_tss_tss2_init(void)
1130 {
1131 return TRUE;
1132 }
1133
1134 /**
1135 * See header
1136 */
1137 void tpm_tss_tss2_deinit(void)
1138 {
1139 /* empty */
1140 }
1141
1142 #endif /* TSS_TSS2_V2 */
1143