bbe23b1fb0e4120e4cc347f794df918e5d795b62
[strongswan.git] / src / libtpmtss / tpm_tss_tss2.c
1 /*
2 * Copyright (C) 2016 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
20
21 #include <asn1/asn1.h>
22 #include <asn1/oid.h>
23 #include <bio/bio_reader.h>
24
25 #include <tss2/tpm20.h>
26 #include <tcti/tcti_socket.h>
27
28 #define LABEL "TPM 2.0 -"
29
30 typedef struct private_tpm_tss_tss2_t private_tpm_tss_tss2_t;
31
32 /**
33 * Private data of an tpm_tss_tss2_t object.
34 */
35 struct private_tpm_tss_tss2_t {
36
37 /**
38 * Public tpm_tss_tss2_t interface.
39 */
40 tpm_tss_t public;
41
42 /**
43 * TCTI context
44 */
45 TSS2_TCTI_CONTEXT *tcti_context;
46
47 /**
48 * SYS context
49 */
50 TSS2_SYS_CONTEXT *sys_context;
51
52 /**
53 * Number of supported algorithms
54 */
55 size_t supported_algs_count;
56
57 /**
58 * List of supported algorithms
59 */
60 TPM_ALG_ID supported_algs[TPM_PT_ALGORITHM_SET];
61 };
62
63 /**
64 * Some symbols required by libtctisocket
65 */
66 FILE *outFp;
67 uint8_t simulator = 1;
68
69 int TpmClientPrintf (uint8_t type, const char *format, ...)
70 {
71 return 0;
72 }
73
74 /**
75 * Convert hash algorithm to TPM_ALG_ID
76 */
77 static TPM_ALG_ID hash_alg_to_tpm_alg_id(hash_algorithm_t alg)
78 {
79 switch (alg)
80 {
81 case HASH_SHA1:
82 return TPM_ALG_SHA1;
83 case HASH_SHA256:
84 return TPM_ALG_SHA256;
85 case HASH_SHA384:
86 return TPM_ALG_SHA384;
87 case HASH_SHA512:
88 return TPM_ALG_SHA512;
89 default:
90 return TPM_ALG_ERROR;
91 }
92 }
93
94 /**
95 * Convert TPM_ALG_ID to hash algorithm
96 */
97 static hash_algorithm_t hash_alg_from_tpm_alg_id(TPM_ALG_ID alg)
98 {
99 switch (alg)
100 {
101 case TPM_ALG_SHA1:
102 return HASH_SHA1;
103 case TPM_ALG_SHA256:
104 return HASH_SHA256;
105 case TPM_ALG_SHA384:
106 return HASH_SHA384;
107 case TPM_ALG_SHA512:
108 return HASH_SHA512;
109 default:
110 return HASH_UNKNOWN;
111 }
112 }
113
114 /**
115 * Check if an algorithm given by its TPM_ALG_ID is supported by the TPM
116 */
117 static bool is_supported_alg(private_tpm_tss_tss2_t *this, TPM_ALG_ID alg_id)
118 {
119 int i;
120
121 if (alg_id == TPM_ALG_ERROR)
122 {
123 return FALSE;
124 }
125
126 for (i = 0; i < this->supported_algs_count; i++)
127 {
128 if (this->supported_algs[i] == alg_id)
129 {
130 return TRUE;
131 }
132 }
133
134 return FALSE;
135 }
136
137 /**
138 * Get a list of supported algorithms
139 */
140 static bool get_algs_capability(private_tpm_tss_tss2_t *this)
141 {
142 TPMS_CAPABILITY_DATA cap_data;
143 TPMI_YES_NO more_data;
144 TPM_ALG_ID alg;
145 uint32_t rval, i;
146 size_t len = BUF_LEN;
147 char buf[BUF_LEN];
148 char *pos = buf;
149 int written;
150
151 /* get supported algorithms */
152 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ALGS,
153 0, TPM_PT_ALGORITHM_SET, &more_data, &cap_data, 0);
154 if (rval != TPM_RC_SUCCESS)
155 {
156 DBG1(DBG_PTS, "%s GetCapability failed for TPM_CAP_ALGS: 0x%06x",
157 LABEL, rval);
158 return FALSE;
159 }
160
161 /* Number of supported algorithms */
162 this->supported_algs_count = cap_data.data.algorithms.count;
163
164 /* store and print supported algorithms */
165 for (i = 0; i < this->supported_algs_count; i++)
166 {
167 alg = cap_data.data.algorithms.algProperties[i].alg;
168 this->supported_algs[i] = alg;
169
170 written = snprintf(pos, len, " %N", tpm_alg_id_names, alg);
171 if (written < 0 || written >= len)
172 {
173 break;
174 }
175 pos += written;
176 len -= written;
177 }
178 DBG2(DBG_PTS, "%s algorithms:%s", LABEL, buf);
179
180 /* get supported ECC curves */
181 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ECC_CURVES,
182 0, TPM_PT_LOADED_CURVES, &more_data, &cap_data, 0);
183 if (rval != TPM_RC_SUCCESS)
184 {
185 DBG1(DBG_PTS, "%s GetCapability failed for TPM_ECC_CURVES: 0x%06x",
186 LABEL, rval);
187 return FALSE;
188 }
189
190 /* reset print buffer */
191 pos = buf;
192 len = BUF_LEN;
193
194 /* print supported ECC curves */
195 for (i = 0; i < cap_data.data.eccCurves.count; i++)
196 {
197 written = snprintf(pos, len, " %N", tpm_ecc_curve_names,
198 cap_data.data.eccCurves.eccCurves[i]);
199 if (written < 0 || written >= len)
200 {
201 break;
202 }
203 pos += written;
204 len -= written;
205 }
206 DBG2(DBG_PTS, "%s ECC curves:%s", LABEL, buf);
207
208 return TRUE;
209 }
210
211 /**
212 * Initialize TSS context
213 */
214 static bool initialize_context(private_tpm_tss_tss2_t *this)
215 {
216 size_t tcti_context_size;
217 uint32_t sys_context_size;
218 uint32_t rval;
219
220 TCTI_SOCKET_CONF rm_if_config = { DEFAULT_HOSTNAME,
221 DEFAULT_RESMGR_TPM_PORT
222 };
223
224 TSS2_ABI_VERSION abi_version = { TSSWG_INTEROP,
225 TSS_SAPI_FIRST_FAMILY,
226 TSS_SAPI_FIRST_LEVEL,
227 TSS_SAPI_FIRST_VERSION
228 };
229
230 /* determine size of tcti context */
231 rval = InitSocketTcti(NULL, &tcti_context_size, &rm_if_config, 0);
232 if (rval != TSS2_RC_SUCCESS)
233 {
234 DBG1(DBG_PTS, "%s could not get tcti_context size: 0x%06x",
235 LABEL, rval);
236 return FALSE;
237 }
238
239 /* allocate memory for tcti context */
240 this->tcti_context = (TSS2_TCTI_CONTEXT*)malloc(tcti_context_size);
241
242 /* initialize tcti context */
243 rval = InitSocketTcti(this->tcti_context, &tcti_context_size,
244 &rm_if_config, 0);
245 if (rval != TSS2_RC_SUCCESS)
246 {
247 DBG1(DBG_PTS, "%s could not get tcti_context: 0x%06x",
248 LABEL, rval);
249 return FALSE;
250 }
251
252 /* determine size of sys context */
253 sys_context_size = Tss2_Sys_GetContextSize(0);
254
255 /* allocate memory for sys context */
256 this->sys_context = malloc(sys_context_size);
257
258 /* initialize sys context */
259 rval = Tss2_Sys_Initialize(this->sys_context, sys_context_size,
260 this->tcti_context, &abi_version);
261 if (rval != TSS2_RC_SUCCESS)
262 {
263 DBG1(DBG_PTS, "%s could not get sys_context: 0x%06x",
264 LABEL, rval);
265 return FALSE;
266 }
267
268 /* get a list of supported algorithms and ECC curves */
269 return get_algs_capability(this);
270 }
271
272 /**
273 * Finalize TSS context
274 */
275 static void finalize_context(private_tpm_tss_tss2_t *this)
276 {
277 if (this->tcti_context)
278 {
279 TeardownSocketTcti(this->tcti_context);
280 }
281 if (this->sys_context)
282 {
283 Tss2_Sys_Finalize(this->sys_context);
284 free(this->sys_context);
285 }
286 }
287
288 METHOD(tpm_tss_t, get_version, tpm_version_t,
289 private_tpm_tss_tss2_t *this)
290 {
291 return TPM_VERSION_2_0;
292 }
293
294 METHOD(tpm_tss_t, get_version_info, chunk_t,
295 private_tpm_tss_tss2_t *this)
296 {
297 return chunk_empty;
298 }
299
300 /**
301 * read the public key portion of a TSS 2.0 AIK key from NVRAM
302 */
303 bool read_public(private_tpm_tss_tss2_t *this, TPMI_DH_OBJECT handle,
304 TPM2B_PUBLIC *public)
305 {
306 uint32_t rval;
307
308 TPM2B_NAME name = { { sizeof(TPM2B_NAME)-2, } };
309 TPM2B_NAME qualified_name = { { sizeof(TPM2B_NAME)-2, } };
310
311 TPMS_AUTH_RESPONSE session_data;
312 TSS2_SYS_RSP_AUTHS sessions_data;
313 TPMS_AUTH_RESPONSE *session_data_array[1];
314
315 session_data_array[0] = &session_data;
316 sessions_data.rspAuths = &session_data_array[0];
317 sessions_data.rspAuthsCount = 1;
318
319 /* always send simulator platform command, ignored by true RM */
320 PlatformCommand(this->tcti_context ,MS_SIM_POWER_ON );
321 PlatformCommand(this->tcti_context, MS_SIM_NV_ON );
322
323 /* read public key for a given object handle from TPM 2.0 NVRAM */
324 rval = Tss2_Sys_ReadPublic(this->sys_context, handle, 0, public, &name,
325 &qualified_name, &sessions_data);
326
327 PlatformCommand(this->tcti_context, MS_SIM_POWER_OFF);
328
329 if (rval != TPM_RC_SUCCESS)
330 {
331 DBG1(DBG_PTS, "%s could not read public key from handle 0x%08x: 0x%06x",
332 LABEL, handle, rval);
333 return FALSE;
334 }
335 return TRUE;
336 }
337
338 METHOD(tpm_tss_t, generate_aik, bool,
339 private_tpm_tss_tss2_t *this, chunk_t ca_modulus, chunk_t *aik_blob,
340 chunk_t *aik_pubkey, chunk_t *identity_req)
341 {
342 return FALSE;
343 }
344
345 METHOD(tpm_tss_t, get_public, chunk_t,
346 private_tpm_tss_tss2_t *this, uint32_t handle)
347 {
348 TPM2B_PUBLIC public = { { 0, } };
349 chunk_t aik_blob, aik_pubkey = chunk_empty;
350
351 if (!read_public(this, handle, &public))
352 {
353 return chunk_empty;
354 }
355
356 aik_blob = chunk_create((u_char*)&public, sizeof(public));
357 DBG3(DBG_LIB, "%s AIK public key blob: %B", LABEL, &aik_blob);
358
359 /* convert TSS 2.0 AIK public key blot into PKCS#1 format */
360 switch (public.t.publicArea.type)
361 {
362 case TPM_ALG_RSA:
363 {
364 TPM2B_PUBLIC_KEY_RSA *rsa;
365 chunk_t aik_exponent, aik_modulus;
366
367 rsa = &public.t.publicArea.unique.rsa;
368 aik_modulus = chunk_create(rsa->t.buffer, rsa->t.size);
369 aik_exponent = chunk_from_chars(0x01, 0x00, 0x01);
370
371 /* subjectPublicKeyInfo encoding of AIK RSA key */
372 if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER,
373 NULL, &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus,
374 CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END))
375 {
376 DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of AIK key "
377 "failed", LABEL);
378 }
379 break;
380 }
381 case TPM_ALG_ECC:
382 {
383 TPMS_ECC_POINT *ecc;
384 chunk_t ecc_point;
385 uint8_t *pos;
386
387 ecc = &public.t.publicArea.unique.ecc;
388
389 /* allocate space for bit string */
390 pos = asn1_build_object(&ecc_point, ASN1_BIT_STRING,
391 2 + ecc->x.t.size + ecc->y.t.size);
392 /* bit string length is a multiple of octets */
393 *pos++ = 0x00;
394 /* uncompressed ECC point format */
395 *pos++ = 0x04;
396 /* copy x coordinate of ECC point */
397 memcpy(pos, ecc->x.t.buffer, ecc->x.t.size);
398 pos += ecc->x.t.size;
399 /* copy y coordinate of ECC point */
400 memcpy(pos, ecc->y.t.buffer, ecc->y.t.size);
401 /* subjectPublicKeyInfo encoding of AIK ECC key */
402 aik_pubkey = asn1_wrap(ASN1_SEQUENCE, "mm",
403 asn1_wrap(ASN1_SEQUENCE, "mm",
404 asn1_build_known_oid(OID_EC_PUBLICKEY),
405 asn1_build_known_oid(ecc->x.t.size == 32 ?
406 OID_PRIME256V1 : OID_SECT384R1)),
407 ecc_point);
408 break;
409 }
410 default:
411 DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL);
412 }
413
414 return aik_pubkey;
415 }
416
417 /**
418 * Configure a PCR Selection assuming a maximum of 24 registers
419 */
420 static bool init_pcr_selection(private_tpm_tss_tss2_t *this, uint32_t pcrs,
421 hash_algorithm_t alg, TPML_PCR_SELECTION *pcr_sel)
422 {
423 TPM_ALG_ID alg_id;
424 uint32_t pcr;
425
426 /* check if hash algorithm is supported by TPM */
427 alg_id = hash_alg_to_tpm_alg_id(alg);
428 if (!is_supported_alg(this, alg_id))
429 {
430 DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM",
431 LABEL, hash_algorithm_short_names, alg);
432 return FALSE;
433 }
434
435 /* initialize the PCR Selection structure,*/
436 pcr_sel->count = 1;
437 pcr_sel->pcrSelections[0].hash = alg_id;
438 pcr_sel->pcrSelections[0].sizeofSelect = 3;
439 pcr_sel->pcrSelections[0].pcrSelect[0] = 0;
440 pcr_sel->pcrSelections[0].pcrSelect[1] = 0;
441 pcr_sel->pcrSelections[0].pcrSelect[2] = 0;
442
443 /* set the selected PCRs */
444 for (pcr = 0; pcr < PLATFORM_PCR; pcr++)
445 {
446 if (pcrs & (1 << pcr))
447 {
448 pcr_sel->pcrSelections[0].pcrSelect[pcr / 8] |= ( 1 << (pcr % 8) );
449 }
450 }
451 return TRUE;
452 }
453
454 METHOD(tpm_tss_t, read_pcr, bool,
455 private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
456 hash_algorithm_t alg)
457 {
458 TPML_PCR_SELECTION pcr_selection;
459 TPML_DIGEST pcr_values;
460
461 uint32_t pcr_update_counter, rval;
462 uint8_t *pcr_value_ptr;
463 size_t pcr_value_len;
464
465 if (pcr_num >= PLATFORM_PCR)
466 {
467 DBG1(DBG_PTS, "%s maximum number of supported PCR is %d",
468 LABEL, PLATFORM_PCR);
469 return FALSE;
470 }
471
472 if (!init_pcr_selection(this, (1 << pcr_num), alg, &pcr_selection))
473 {
474 return FALSE;
475 }
476
477 /* initialize the PCR Digest structure */
478 memset(&pcr_values, 0, sizeof(TPML_DIGEST));
479
480 /* read the PCR value */
481 rval = Tss2_Sys_PCR_Read(this->sys_context, 0, &pcr_selection,
482 &pcr_update_counter, &pcr_selection, &pcr_values, 0);
483 if (rval != TPM_RC_SUCCESS)
484 {
485 DBG1(DBG_PTS, "%s PCR bank could not be read: 0x%60x",
486 LABEL, rval);
487 return FALSE;
488 }
489 pcr_value_ptr = (uint8_t *)pcr_values.digests[0].t.buffer;
490 pcr_value_len = (size_t) pcr_values.digests[0].t.size;
491
492 *pcr_value = chunk_clone(chunk_create(pcr_value_ptr, pcr_value_len));
493
494 return TRUE;
495 }
496
497 METHOD(tpm_tss_t, extend_pcr, bool,
498 private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
499 chunk_t data, hash_algorithm_t alg)
500 {
501 /* TODO */
502 return FALSE;
503 }
504
505 METHOD(tpm_tss_t, quote, bool,
506 private_tpm_tss_tss2_t *this, uint32_t aik_handle, uint32_t pcr_sel,
507 hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t *quote_mode,
508 tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig)
509 {
510 chunk_t quoted_chunk, qualified_signer, extra_data, clock_info,
511 firmware_version, pcr_select, pcr_digest;
512 hash_algorithm_t pcr_digest_alg;
513 bio_reader_t *reader;
514 uint32_t rval;
515
516 TPM2B_DATA qualifying_data;
517 TPML_PCR_SELECTION pcr_selection;
518 TPM2B_ATTEST quoted = { { sizeof(TPM2B_ATTEST)-2, } };
519 TPMT_SIG_SCHEME scheme;
520 TPMT_SIGNATURE sig;
521 TPMI_ALG_HASH hash_alg;
522 TPMS_AUTH_COMMAND session_data_cmd;
523 TPMS_AUTH_RESPONSE session_data_rsp;
524 TSS2_SYS_CMD_AUTHS sessions_data_cmd;
525 TSS2_SYS_RSP_AUTHS sessions_data_rsp;
526 TPMS_AUTH_COMMAND *session_data_cmd_array[1];
527 TPMS_AUTH_RESPONSE *session_data_rsp_array[1];
528
529 session_data_cmd_array[0] = &session_data_cmd;
530 session_data_rsp_array[0] = &session_data_rsp;
531
532 sessions_data_cmd.cmdAuths = &session_data_cmd_array[0];
533 sessions_data_rsp.rspAuths = &session_data_rsp_array[0];
534
535 sessions_data_cmd.cmdAuthsCount = 1;
536 sessions_data_rsp.rspAuthsCount = 1;
537
538 session_data_cmd.sessionHandle = TPM_RS_PW;
539 session_data_cmd.hmac.t.size = 0;
540 session_data_cmd.nonce.t.size = 0;
541
542 *( (uint8_t *)((void *)&session_data_cmd.sessionAttributes ) ) = 0;
543
544 qualifying_data.t.size = data.len;
545 memcpy(qualifying_data.t.buffer, data.ptr, data.len);
546
547 scheme.scheme = TPM_ALG_NULL;
548 memset(&sig, 0x00, sizeof(sig));
549
550 /* set Quote mode */
551 *quote_mode = TPM_QUOTE_TPM2;
552
553 if (!init_pcr_selection(this, pcr_sel, alg, &pcr_selection))
554 {
555 return FALSE;
556 }
557
558 rval = Tss2_Sys_Quote(this->sys_context, aik_handle, &sessions_data_cmd,
559 &qualifying_data, &scheme, &pcr_selection, &quoted,
560 &sig, &sessions_data_rsp);
561 if (rval != TPM_RC_SUCCESS)
562 {
563 DBG1(DBG_PTS,"%s Tss2_Sys_Quote failed: 0x%06x", LABEL, rval);
564 return FALSE;
565 }
566 quoted_chunk = chunk_create(quoted.t.attestationData, quoted.t.size);
567
568 reader = bio_reader_create(chunk_skip(quoted_chunk, 6));
569 if (!reader->read_data16(reader, &qualified_signer) ||
570 !reader->read_data16(reader, &extra_data) ||
571 !reader->read_data (reader, 17, &clock_info) ||
572 !reader->read_data (reader, 8, &firmware_version) ||
573 !reader->read_data (reader, 10, &pcr_select) ||
574 !reader->read_data16(reader, &pcr_digest))
575 {
576 DBG1(DBG_PTS, "%s parsing of quoted struct failed", LABEL);
577 reader->destroy(reader);
578 return FALSE;
579 }
580 reader->destroy(reader);
581
582 DBG2(DBG_PTS, "PCR Composite digest: %B", &pcr_digest);
583 DBG2(DBG_PTS, "TPM Quote Info: %B", &quoted_chunk);
584 DBG2(DBG_PTS, "qualifiedSigner: %B", &qualified_signer);
585 DBG2(DBG_PTS, "extraData: %B", &extra_data);
586 DBG2(DBG_PTS, "clockInfo: %B", &clock_info);
587 DBG2(DBG_PTS, "firmwareVersion: %B", &firmware_version);
588 DBG2(DBG_PTS, "pcrSelect: %B", &pcr_select);
589
590 /* extract signature */
591 switch (sig.sigAlg)
592 {
593 case TPM_ALG_RSASSA:
594 case TPM_ALG_RSAPSS:
595 *quote_sig = chunk_clone(
596 chunk_create(
597 sig.signature.rsassa.sig.t.buffer,
598 sig.signature.rsassa.sig.t.size));
599 hash_alg = sig.signature.rsassa.hash;
600 break;
601 case TPM_ALG_ECDSA:
602 case TPM_ALG_ECDAA:
603 case TPM_ALG_SM2:
604 case TPM_ALG_ECSCHNORR:
605 *quote_sig = chunk_cat("cc",
606 chunk_create(
607 sig.signature.ecdsa.signatureR.t.buffer,
608 sig.signature.ecdsa.signatureR.t.size),
609 chunk_create(
610 sig.signature.ecdsa.signatureS.t.buffer,
611 sig.signature.ecdsa.signatureS.t.size));
612 hash_alg = sig.signature.ecdsa.hash;
613 break;
614 default:
615 DBG1(DBG_PTS, "%s unsupported %N signature algorithm",
616 LABEL, tpm_alg_id_names, sig.sigAlg);
617 return FALSE;
618 };
619
620 DBG2(DBG_PTS, "PCR digest algorithm is %N", tpm_alg_id_names, hash_alg);
621 pcr_digest_alg = hash_alg_from_tpm_alg_id(hash_alg);
622
623 DBG2(DBG_PTS, "TPM Quote Signature: %B", quote_sig);
624
625 /* Create and initialize Quote Info object */
626 *quote_info = tpm_tss_quote_info_create(*quote_mode, pcr_digest_alg,
627 pcr_digest);
628 (*quote_info)->set_tpm2_info(*quote_info, qualified_signer, clock_info,
629 pcr_select);
630 (*quote_info)->set_version_info(*quote_info, firmware_version);
631
632 return TRUE;
633 }
634
635 METHOD(tpm_tss_t, destroy, void,
636 private_tpm_tss_tss2_t *this)
637 {
638 finalize_context(this);
639 free(this);
640 }
641
642 /**
643 * See header
644 */
645 tpm_tss_t *tpm_tss_tss2_create()
646 {
647 private_tpm_tss_tss2_t *this;
648 bool available;
649
650 INIT(this,
651 .public = {
652 .get_version = _get_version,
653 .get_version_info = _get_version_info,
654 .generate_aik = _generate_aik,
655 .get_public = _get_public,
656 .read_pcr = _read_pcr,
657 .extend_pcr = _extend_pcr,
658 .quote = _quote,
659 .destroy = _destroy,
660 },
661 );
662
663 available = initialize_context(this);
664 DBG1(DBG_PTS, "TPM 2.0 via TSS2 %savailable", available ? "" : "not ");
665
666 if (!available)
667 {
668 destroy(this);
669 return NULL;
670 }
671 return &this->public;
672 }
673
674 #else /* TSS_TSS2 */
675
676 tpm_tss_t *tpm_tss_tss2_create()
677 {
678 return NULL;
679 }
680
681 #endif /* TSS_TSS2 */
682
683