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