2 * Copyright (C) 2018 Tobias Brunner
3 * Copyright (C) 2018-2019 Andreas Steffen
4 * HSR Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 #include "tpm_tss_tss2.h"
18 #include "tpm_tss_tss2_names.h"
22 #include <asn1/asn1.h>
24 #include <bio/bio_reader.h>
25 #include <threading/mutex.h>
27 #include <tss2/tss2_sys.h>
30 #include <sys/types.h>
34 #define LABEL "TPM 2.0 -"
36 #define PLATFORM_PCR 24
38 typedef struct private_tpm_tss_tss2_t private_tpm_tss_tss2_t
;
41 * Private data of an tpm_tss_tss2_t object.
43 struct private_tpm_tss_tss2_t
{
46 * Public tpm_tss_tss2_t interface.
53 TSS2_TCTI_CONTEXT
*tcti_context
;
58 TSS2_SYS_CONTEXT
*sys_context
;
61 * Number of supported algorithms
63 size_t supported_algs_count
;
66 * List of supported algorithms
68 TPM2_ALG_ID supported_algs
[TPM2_PT_ALGORITHM_SET
];
71 * Is TPM FIPS 186-4 compliant ?
76 * Mutex controlling access to the TPM 2.0 context
83 * Global TCTI dynamic library handle and init function
85 static void *tcti_handle
;
87 static TSS2_TCTI_INIT_FUNC tcti_init
;
89 static char *tcti_opts
;
94 static const TPMS_AUTH_COMMAND auth_cmd_empty
;
97 * Convert hash algorithm to TPM2_ALG_ID
99 static TPM2_ALG_ID
hash_alg_to_tpm_alg_id(hash_algorithm_t alg
)
104 return TPM2_ALG_SHA1
;
106 return TPM2_ALG_SHA256
;
108 return TPM2_ALG_SHA384
;
110 return TPM2_ALG_SHA512
;
112 return TPM2_ALG_ERROR
;
117 * Convert TPM2_ALG_ID to hash algorithm
119 static hash_algorithm_t
hash_alg_from_tpm_alg_id(TPM2_ALG_ID alg
)
125 case TPM2_ALG_SHA256
:
127 case TPM2_ALG_SHA384
:
129 case TPM2_ALG_SHA512
:
137 * Check if an algorithm given by its TPM2_ALG_ID is supported by the TPM
139 static bool is_supported_alg(private_tpm_tss_tss2_t
*this, TPM2_ALG_ID alg_id
)
143 if (alg_id
== TPM2_ALG_ERROR
)
148 for (i
= 0; i
< this->supported_algs_count
; i
++)
150 if (this->supported_algs
[i
] == alg_id
)
160 * Get a list of supported algorithms
162 static bool get_algs_capability(private_tpm_tss_tss2_t
*this)
164 TPMS_CAPABILITY_DATA cap_data
;
165 TPMS_TAGGED_PROPERTY tp
;
166 TPMI_YES_NO more_data
;
168 bool fips_140_2
= FALSE
;
169 uint32_t rval
, i
, offset
, revision
= 0, year
= 0;
170 size_t len
= BUF_LEN
;
171 char buf
[BUF_LEN
], manufacturer
[5], vendor_string
[17];
175 /* get fixed properties */
176 this->mutex
->lock(this->mutex
);
177 rval
= Tss2_Sys_GetCapability(this->sys_context
, 0, TPM2_CAP_TPM_PROPERTIES
,
178 TPM2_PT_FIXED
, TPM2_MAX_TPM_PROPERTIES
,
179 &more_data
, &cap_data
, 0);
180 this->mutex
->unlock(this->mutex
);
181 if (rval
!= TPM2_RC_SUCCESS
)
183 DBG1(DBG_PTS
, "%s GetCapability failed for TPM2_CAP_TPM_PROPERTIES: 0x%06x",
187 memset(manufacturer
, '\0', sizeof(manufacturer
));
188 memset(vendor_string
, '\0', sizeof(vendor_string
));
190 /* print fixed properties */
191 for (i
= 0; i
< cap_data
.data
.tpmProperties
.count
; i
++)
193 tp
= cap_data
.data
.tpmProperties
.tpmProperty
[i
];
196 case TPM2_PT_REVISION
:
202 case TPM2_PT_MANUFACTURER
:
203 htoun32(manufacturer
, tp
.value
);
205 case TPM2_PT_VENDOR_STRING_1
:
206 case TPM2_PT_VENDOR_STRING_2
:
207 case TPM2_PT_VENDOR_STRING_3
:
208 case TPM2_PT_VENDOR_STRING_4
:
209 offset
= 4 * (tp
.property
- TPM2_PT_VENDOR_STRING_1
);
210 htoun32(vendor_string
+ offset
, tp
.value
);
213 if (tp
.value
& TPMA_MODES_FIPS_140_2
)
215 this->fips_186_4
= fips_140_2
= TRUE
;
225 this->fips_186_4
= lib
->settings
->get_bool(lib
->settings
,
226 "%s.plugins.tpm.fips_186_4", FALSE
, lib
->ns
);
228 DBG2(DBG_PTS
, "%s manufacturer: %s (%s) rev: %05.2f %u %s", LABEL
,
229 manufacturer
, vendor_string
, (float)revision
/100, year
,
230 fips_140_2 ?
"FIPS 140-2" : (this->fips_186_4 ?
"FIPS 186-4" : ""));
232 /* get supported algorithms */
233 this->mutex
->lock(this->mutex
);
234 rval
= Tss2_Sys_GetCapability(this->sys_context
, 0, TPM2_CAP_ALGS
,
235 0, TPM2_PT_ALGORITHM_SET
, &more_data
, &cap_data
, 0);
236 this->mutex
->unlock(this->mutex
);
237 if (rval
!= TPM2_RC_SUCCESS
)
239 DBG1(DBG_PTS
, "%s GetCapability failed for TPM2_CAP_ALGS: 0x%06x",
244 /* Number of supported algorithms */
245 this->supported_algs_count
= cap_data
.data
.algorithms
.count
;
247 /* store and print supported algorithms */
248 for (i
= 0; i
< this->supported_algs_count
; i
++)
250 alg
= cap_data
.data
.algorithms
.algProperties
[i
].alg
;
251 this->supported_algs
[i
] = alg
;
253 written
= snprintf(pos
, len
, " %N", tpm_alg_id_names
, alg
);
254 if (written
< 0 || written
>= len
)
261 DBG2(DBG_PTS
, "%s algorithms:%s", LABEL
, buf
);
263 /* get supported ECC curves */
264 this->mutex
->lock(this->mutex
);
265 rval
= Tss2_Sys_GetCapability(this->sys_context
, 0, TPM2_CAP_ECC_CURVES
,
266 0, TPM2_PT_LOADED_CURVES
, &more_data
, &cap_data
, 0);
267 this->mutex
->unlock(this->mutex
);
268 if (rval
!= TPM2_RC_SUCCESS
)
270 DBG1(DBG_PTS
, "%s GetCapability failed for TPM2_ECC_CURVES: 0x%06x",
275 /* reset print buffer */
279 /* print supported ECC curves */
280 for (i
= 0; i
< cap_data
.data
.eccCurves
.count
; i
++)
282 written
= snprintf(pos
, len
, " %N", tpm_ecc_curve_names
,
283 cap_data
.data
.eccCurves
.eccCurves
[i
]);
284 if (written
< 0 || written
>= len
)
291 DBG2(DBG_PTS
, "%s ECC curves:%s", LABEL
, buf
);
297 * Initialize TSS2 TCTI context
299 static bool initialize_tcti_context(private_tpm_tss_tss2_t
*this)
301 size_t tcti_context_size
;
309 /* determine size of tcti context */
310 rval
= tcti_init(NULL
, &tcti_context_size
, tcti_opts
);
311 if (rval
!= TSS2_RC_SUCCESS
)
313 DBG1(DBG_PTS
, "%s tcti init setup failed: 0x%06x", LABEL
, rval
);
317 /* allocate and initialize memory for tcti context */
318 this->tcti_context
= (TSS2_TCTI_CONTEXT
*)malloc(tcti_context_size
);
319 memset(this->tcti_context
, 0x00, tcti_context_size
);
321 /* initialize tcti context */
322 rval
= tcti_init(this->tcti_context
, &tcti_context_size
, tcti_opts
);
323 if (rval
!= TSS2_RC_SUCCESS
)
325 DBG1(DBG_PTS
, "%s tcti init allocation failed: 0x%06x", LABEL
,rval
);
332 * Initialize TSS2 Sys context
334 static bool initialize_sys_context(private_tpm_tss_tss2_t
*this)
336 uint32_t sys_context_size
;
339 TSS2_ABI_VERSION abi_version
= {
346 /* determine size of sys context */
347 sys_context_size
= Tss2_Sys_GetContextSize(0);
349 /* allocate memory for sys context */
350 this->sys_context
= (TSS2_SYS_CONTEXT
*)malloc(sys_context_size
);
352 /* initialize sys context */
353 rval
= Tss2_Sys_Initialize(this->sys_context
, sys_context_size
,
354 this->tcti_context
, &abi_version
);
355 if (rval
!= TSS2_RC_SUCCESS
)
357 DBG1(DBG_PTS
, "%s could not get sys_context: 0x%06x",
362 /* get a list of supported algorithms and ECC curves */
363 return get_algs_capability(this);
367 * Finalize TSS context
369 static void finalize_context(private_tpm_tss_tss2_t
*this)
371 if (this->tcti_context
)
373 Tss2_Tcti_Finalize(this->tcti_context
);
374 free(this->tcti_context
);
376 if (this->sys_context
)
378 Tss2_Sys_Finalize(this->sys_context
);
379 free(this->sys_context
);
383 METHOD(tpm_tss_t
, get_version
, tpm_version_t
,
384 private_tpm_tss_tss2_t
*this)
386 return TPM_VERSION_2_0
;
389 METHOD(tpm_tss_t
, get_version_info
, chunk_t
,
390 private_tpm_tss_tss2_t
*this)
396 * read the public key portion of a TSS 2.0 key from NVRAM
398 bool read_public(private_tpm_tss_tss2_t
*this, TPMI_DH_OBJECT handle
,
399 TPM2B_PUBLIC
*public)
403 TPM2B_NAME name
= { sizeof(TPM2B_NAME
)-2, };
404 TPM2B_NAME qualified_name
= { sizeof(TPM2B_NAME
)-2, };
405 TSS2L_SYS_AUTH_RESPONSE auth_rsp
;
408 /* read public key for a given object handle from TPM 2.0 NVRAM */
409 this->mutex
->lock(this->mutex
);
410 rval
= Tss2_Sys_ReadPublic(this->sys_context
, handle
, 0, public, &name
,
411 &qualified_name
, &auth_rsp
);
412 this->mutex
->unlock(this->mutex
);
413 if (rval
!= TPM2_RC_SUCCESS
)
415 DBG1(DBG_PTS
, "%s could not read public key from handle 0x%08x: 0x%06x",
416 LABEL
, handle
, rval
);
422 METHOD(tpm_tss_t
, generate_aik
, bool,
423 private_tpm_tss_tss2_t
*this, chunk_t ca_modulus
, chunk_t
*aik_blob
,
424 chunk_t
*aik_pubkey
, chunk_t
*identity_req
)
429 METHOD(tpm_tss_t
, get_public
, chunk_t
,
430 private_tpm_tss_tss2_t
*this, uint32_t handle
)
432 TPM2B_PUBLIC
public = { 0, };
433 TPM2_ALG_ID sig_alg
, digest_alg
;
434 chunk_t aik_blob
, aik_pubkey
= chunk_empty
;
436 if (!read_public(this, handle
, &public))
441 aik_blob
= chunk_create((u_char
*)&public, sizeof(public));
442 DBG3(DBG_LIB
, "%s public key blob: %B", LABEL
, &aik_blob
);
444 /* convert TSS 2.0 public key blot into PKCS#1 format */
445 switch (public.publicArea
.type
)
449 TPM2B_PUBLIC_KEY_RSA
*rsa
;
450 TPMT_RSA_SCHEME
*scheme
;
451 chunk_t aik_exponent
= chunk_from_chars(0x01, 0x00, 0x01);
455 scheme
= &public.publicArea
.parameters
.rsaDetail
.scheme
;
456 sig_alg
= scheme
->scheme
;
457 digest_alg
= scheme
->details
.anySig
.hashAlg
;
459 rsa
= &public.publicArea
.unique
.rsa
;
460 aik_modulus
= chunk_create(rsa
->buffer
, rsa
->size
);
461 exponent
= htonl(public.publicArea
.parameters
.rsaDetail
.exponent
);
464 aik_exponent
= chunk_from_thing(exponent
);
467 /* subjectPublicKeyInfo encoding of RSA public key */
468 if (!lib
->encoding
->encode(lib
->encoding
, PUBKEY_SPKI_ASN1_DER
,
469 NULL
, &aik_pubkey
, CRED_PART_RSA_MODULUS
, aik_modulus
,
470 CRED_PART_RSA_PUB_EXP
, aik_exponent
, CRED_PART_END
))
472 DBG1(DBG_PTS
, "%s subjectPublicKeyInfo encoding of public key "
481 TPMT_ECC_SCHEME
*scheme
;
485 scheme
= &public.publicArea
.parameters
.eccDetail
.scheme
;
486 sig_alg
= scheme
->scheme
;
487 digest_alg
= scheme
->details
.anySig
.hashAlg
;
489 ecc
= &public.publicArea
.unique
.ecc
;
491 /* allocate space for bit string */
492 pos
= asn1_build_object(&ecc_point
, ASN1_BIT_STRING
,
493 2 + ecc
->x
.size
+ ecc
->y
.size
);
494 /* bit string length is a multiple of octets */
496 /* uncompressed ECC point format */
498 /* copy x coordinate of ECC point */
499 memcpy(pos
, ecc
->x
.buffer
, ecc
->x
.size
);
501 /* copy y coordinate of ECC point */
502 memcpy(pos
, ecc
->y
.buffer
, ecc
->y
.size
);
503 /* subjectPublicKeyInfo encoding of ECC public key */
504 aik_pubkey
= asn1_wrap(ASN1_SEQUENCE
, "mm",
505 asn1_wrap(ASN1_SEQUENCE
, "mm",
506 asn1_build_known_oid(OID_EC_PUBLICKEY
),
507 asn1_build_known_oid(ecc
->x
.size
== 32 ?
508 OID_PRIME256V1
: OID_SECT384R1
)),
513 DBG1(DBG_PTS
, "%s unsupported key type", LABEL
);
516 DBG1(DBG_PTS
, "signature algorithm is %N with %N hash",
517 tpm_alg_id_names
, sig_alg
, tpm_alg_id_names
, digest_alg
);
521 METHOD(tpm_tss_t
, supported_signature_schemes
, enumerator_t
*,
522 private_tpm_tss_tss2_t
*this, uint32_t handle
)
524 TPM2B_PUBLIC
public = { 0, };
525 hash_algorithm_t digest
;
526 signature_params_t supported_scheme
;
528 if (!read_public(this, handle
, &public))
530 return enumerator_create_empty();
533 switch (public.publicArea
.type
)
538 TPMT_RSA_SCHEME
*scheme
;
540 rsa
= &public.publicArea
.parameters
.rsaDetail
;
541 scheme
= &rsa
->scheme
;
542 digest
= hash_alg_from_tpm_alg_id(scheme
->details
.anySig
.hashAlg
);
544 switch (scheme
->scheme
)
546 case TPM2_ALG_RSAPSS
:
550 salt_len
= this->fips_186_4 ? RSA_PSS_SALT_LEN_DEFAULT
:
551 RSA_PSS_SALT_LEN_MAX
;
552 rsa_pss_params_t pss_params
= {
555 .salt_len
= salt_len
,
557 supported_scheme
= (signature_params_t
){
558 .scheme
= SIGN_RSA_EMSA_PSS
,
559 .params
= &pss_params
,
561 if (!rsa_pss_params_set_salt_len(&pss_params
, rsa
->keyBits
))
563 return enumerator_create_empty();
567 case TPM2_ALG_RSASSA
:
568 supported_scheme
= (signature_params_t
){
569 .scheme
= signature_scheme_from_oid(
570 hasher_signature_algorithm_to_oid(digest
,
575 return enumerator_create_empty();
581 TPMT_ECC_SCHEME
*scheme
;
583 scheme
= &public.publicArea
.parameters
.eccDetail
.scheme
;
584 digest
= hash_alg_from_tpm_alg_id(scheme
->details
.anySig
.hashAlg
);
586 switch (scheme
->scheme
)
589 supported_scheme
= (signature_params_t
){
590 .scheme
= signature_scheme_from_oid(
591 hasher_signature_algorithm_to_oid(digest
,
596 return enumerator_create_empty();
601 DBG1(DBG_PTS
, "%s unsupported key type", LABEL
);
602 return enumerator_create_empty();
604 return enumerator_create_single(signature_params_clone(&supported_scheme
),
605 (void*)signature_params_destroy
);
609 * Configure a PCR Selection assuming a maximum of 24 registers
611 static bool init_pcr_selection(private_tpm_tss_tss2_t
*this, uint32_t pcrs
,
612 hash_algorithm_t alg
, TPML_PCR_SELECTION
*pcr_sel
)
617 /* check if hash algorithm is supported by TPM */
618 alg_id
= hash_alg_to_tpm_alg_id(alg
);
619 if (!is_supported_alg(this, alg_id
))
621 DBG1(DBG_PTS
, "%s %N hash algorithm not supported by TPM",
622 LABEL
, hash_algorithm_short_names
, alg
);
626 /* initialize the PCR Selection structure,*/
628 pcr_sel
->pcrSelections
[0].hash
= alg_id
;
629 pcr_sel
->pcrSelections
[0].sizeofSelect
= 3;
630 pcr_sel
->pcrSelections
[0].pcrSelect
[0] = 0;
631 pcr_sel
->pcrSelections
[0].pcrSelect
[1] = 0;
632 pcr_sel
->pcrSelections
[0].pcrSelect
[2] = 0;
634 /* set the selected PCRs */
635 for (pcr
= 0; pcr
< PLATFORM_PCR
; pcr
++)
637 if (pcrs
& (1 << pcr
))
639 pcr_sel
->pcrSelections
[0].pcrSelect
[pcr
/ 8] |= ( 1 << (pcr
% 8) );
645 METHOD(tpm_tss_t
, read_pcr
, bool,
646 private_tpm_tss_tss2_t
*this, uint32_t pcr_num
, chunk_t
*pcr_value
,
647 hash_algorithm_t alg
)
649 TPML_PCR_SELECTION pcr_selection
;
650 TPML_DIGEST pcr_values
;
652 uint32_t pcr_update_counter
, rval
;
653 uint8_t *pcr_value_ptr
;
654 size_t pcr_value_len
;
656 if (pcr_num
>= PLATFORM_PCR
)
658 DBG1(DBG_PTS
, "%s maximum number of supported PCR is %d",
659 LABEL
, PLATFORM_PCR
);
663 if (!init_pcr_selection(this, (1 << pcr_num
), alg
, &pcr_selection
))
668 /* initialize the PCR Digest structure */
669 memset(&pcr_values
, 0, sizeof(TPML_DIGEST
));
671 /* read the PCR value */
672 this->mutex
->lock(this->mutex
);
673 rval
= Tss2_Sys_PCR_Read(this->sys_context
, 0, &pcr_selection
,
674 &pcr_update_counter
, &pcr_selection
, &pcr_values
, 0);
675 this->mutex
->unlock(this->mutex
);
676 if (rval
!= TPM2_RC_SUCCESS
)
678 DBG1(DBG_PTS
, "%s PCR bank could not be read: 0x%60x",
682 pcr_value_ptr
= (uint8_t *)pcr_values
.digests
[0].buffer
;
683 pcr_value_len
= (size_t) pcr_values
.digests
[0].size
;
685 *pcr_value
= chunk_clone(chunk_create(pcr_value_ptr
, pcr_value_len
));
690 METHOD(tpm_tss_t
, extend_pcr
, bool,
691 private_tpm_tss_tss2_t
*this, uint32_t pcr_num
, chunk_t
*pcr_value
,
692 chunk_t data
, hash_algorithm_t alg
)
696 TPML_DIGEST_VALUES digest_values
;
697 TSS2L_SYS_AUTH_COMMAND auth_cmd
= { 1, { auth_cmd_empty
} };
698 TSS2L_SYS_AUTH_RESPONSE auth_rsp
;
700 auth_cmd
.auths
[0].sessionHandle
= TPM2_RS_PW
;
702 /* check if hash algorithm is supported by TPM */
703 alg_id
= hash_alg_to_tpm_alg_id(alg
);
704 if (!is_supported_alg(this, alg_id
))
706 DBG1(DBG_PTS
, "%s %N hash algorithm not supported by TPM",
707 LABEL
, hash_algorithm_short_names
, alg
);
711 digest_values
.count
= 1;
712 digest_values
.digests
[0].hashAlg
= alg_id
;
717 if (data
.len
!= HASH_SIZE_SHA1
)
721 memcpy(digest_values
.digests
[0].digest
.sha1
, data
.ptr
,
725 if (data
.len
!= HASH_SIZE_SHA256
)
729 memcpy(digest_values
.digests
[0].digest
.sha256
, data
.ptr
,
733 if (data
.len
!= HASH_SIZE_SHA384
)
737 memcpy(digest_values
.digests
[0].digest
.sha384
, data
.ptr
,
741 if (data
.len
!= HASH_SIZE_SHA512
)
745 memcpy(digest_values
.digests
[0].digest
.sha512
, data
.ptr
,
753 this->mutex
->lock(this->mutex
);
754 rval
= Tss2_Sys_PCR_Extend(this->sys_context
, pcr_num
, &auth_cmd
,
755 &digest_values
, &auth_rsp
);
756 this->mutex
->unlock(this->mutex
);
757 if (rval
!= TPM2_RC_SUCCESS
)
759 DBG1(DBG_PTS
, "%s PCR %02u could not be extended: 0x%06x",
760 LABEL
, pcr_num
, rval
);
764 /* get updated PCR value */
765 return read_pcr(this, pcr_num
, pcr_value
, alg
);
768 METHOD(tpm_tss_t
, quote
, bool,
769 private_tpm_tss_tss2_t
*this, uint32_t aik_handle
, uint32_t pcr_sel
,
770 hash_algorithm_t alg
, chunk_t data
, tpm_quote_mode_t
*quote_mode
,
771 tpm_tss_quote_info_t
**quote_info
, chunk_t
*quote_sig
)
773 chunk_t quoted_chunk
, qualified_signer
, extra_data
, clock_info
,
774 firmware_version
, pcr_select
, pcr_digest
;
775 hash_algorithm_t pcr_digest_alg
;
776 bio_reader_t
*reader
;
779 TPM2B_DATA qualifying_data
;
780 TPML_PCR_SELECTION pcr_selection
;
781 TPM2B_ATTEST quoted
= { sizeof(TPM2B_ATTEST
)-2, };
782 TPMT_SIG_SCHEME scheme
;
784 TPMI_ALG_HASH hash_alg
;
785 TSS2L_SYS_AUTH_COMMAND auth_cmd
= { 1, { auth_cmd_empty
} };
786 TSS2L_SYS_AUTH_RESPONSE auth_rsp
;
788 auth_cmd
.auths
[0].sessionHandle
= TPM2_RS_PW
;
790 qualifying_data
.size
= data
.len
;
791 memcpy(qualifying_data
.buffer
, data
.ptr
, data
.len
);
793 scheme
.scheme
= TPM2_ALG_NULL
;
794 memset(&sig
, 0x00, sizeof(sig
));
797 *quote_mode
= TPM_QUOTE_TPM2
;
799 if (!init_pcr_selection(this, pcr_sel
, alg
, &pcr_selection
))
804 this->mutex
->lock(this->mutex
);
805 rval
= Tss2_Sys_Quote(this->sys_context
, aik_handle
, &auth_cmd
,
806 &qualifying_data
, &scheme
, &pcr_selection
, "ed
,
808 this->mutex
->unlock(this->mutex
);
809 if (rval
!= TPM2_RC_SUCCESS
)
811 DBG1(DBG_PTS
,"%s Tss2_Sys_Quote failed: 0x%06x", LABEL
, rval
);
814 quoted_chunk
= chunk_create(quoted
.attestationData
, quoted
.size
);
816 reader
= bio_reader_create(chunk_skip(quoted_chunk
, 6));
817 if (!reader
->read_data16(reader
, &qualified_signer
) ||
818 !reader
->read_data16(reader
, &extra_data
) ||
819 !reader
->read_data (reader
, 17, &clock_info
) ||
820 !reader
->read_data (reader
, 8, &firmware_version
) ||
821 !reader
->read_data (reader
, 10, &pcr_select
) ||
822 !reader
->read_data16(reader
, &pcr_digest
))
824 DBG1(DBG_PTS
, "%s parsing of quoted struct failed", LABEL
);
825 reader
->destroy(reader
);
828 reader
->destroy(reader
);
830 DBG2(DBG_PTS
, "PCR Composite digest: %B", &pcr_digest
);
831 DBG2(DBG_PTS
, "TPM Quote Info: %B", "ed_chunk
);
832 DBG2(DBG_PTS
, "qualifiedSigner: %B", &qualified_signer
);
833 DBG2(DBG_PTS
, "extraData: %B", &extra_data
);
834 DBG2(DBG_PTS
, "clockInfo: %B", &clock_info
);
835 DBG2(DBG_PTS
, "firmwareVersion: %B", &firmware_version
);
836 DBG2(DBG_PTS
, "pcrSelect: %B", &pcr_select
);
838 /* extract signature */
841 case TPM2_ALG_RSASSA
:
842 case TPM2_ALG_RSAPSS
:
843 *quote_sig
= chunk_clone(
845 sig
.signature
.rsassa
.sig
.buffer
,
846 sig
.signature
.rsassa
.sig
.size
));
847 hash_alg
= sig
.signature
.rsassa
.hash
;
852 case TPM2_ALG_ECSCHNORR
:
853 *quote_sig
= chunk_cat("cc",
855 sig
.signature
.ecdsa
.signatureR
.buffer
,
856 sig
.signature
.ecdsa
.signatureR
.size
),
858 sig
.signature
.ecdsa
.signatureS
.buffer
,
859 sig
.signature
.ecdsa
.signatureS
.size
));
860 hash_alg
= sig
.signature
.ecdsa
.hash
;
863 DBG1(DBG_PTS
, "%s unsupported %N signature algorithm",
864 LABEL
, tpm_alg_id_names
, sig
.sigAlg
);
868 DBG2(DBG_PTS
, "PCR digest algorithm is %N", tpm_alg_id_names
, hash_alg
);
869 pcr_digest_alg
= hash_alg_from_tpm_alg_id(hash_alg
);
871 DBG2(DBG_PTS
, "TPM Quote Signature: %B", quote_sig
);
873 /* Create and initialize Quote Info object */
874 *quote_info
= tpm_tss_quote_info_create(*quote_mode
, pcr_digest_alg
,
876 (*quote_info
)->set_tpm2_info(*quote_info
, qualified_signer
, clock_info
,
878 (*quote_info
)->set_version_info(*quote_info
, firmware_version
);
883 METHOD(tpm_tss_t
, sign
, bool,
884 private_tpm_tss_tss2_t
*this, uint32_t hierarchy
, uint32_t handle
,
885 signature_scheme_t scheme
, void *params
, chunk_t data
, chunk_t pin
,
889 hash_algorithm_t hash_alg
;
890 rsa_pss_params_t
*rsa_pss_params
;
894 TPM2B_MAX_BUFFER buffer
;
895 TPM2B_DIGEST hash
= { sizeof(TPM2B_DIGEST
)-2, };
896 TPMT_TK_HASHCHECK validation
;
897 TPM2B_PUBLIC
public = { 0, };
898 TPMT_SIG_SCHEME sig_scheme
;
900 TPMS_AUTH_COMMAND
*cmd
;
901 TSS2L_SYS_AUTH_COMMAND auth_cmd
= { 1, { auth_cmd_empty
} };
902 TSS2L_SYS_AUTH_RESPONSE auth_rsp
;
904 cmd
= &auth_cmd
.auths
[0];
905 cmd
->sessionHandle
= TPM2_RS_PW
;
909 cmd
->hmac
.size
= min(sizeof(cmd
->hmac
)-2, pin
.len
);
910 memcpy(cmd
->hmac
.buffer
, pin
.ptr
, cmd
->hmac
.size
);
913 if (scheme
== SIGN_RSA_EMSA_PSS
)
916 rsa_pss_params
= (rsa_pss_params_t
*)params
;
917 hash_alg
= rsa_pss_params
->hash
;
921 key_type
= key_type_from_signature_scheme(scheme
);
922 hash_alg
= hasher_from_signature_scheme(scheme
, NULL
);
925 /* Check if hash algorithm is supported by TPM */
926 alg_id
= hash_alg_to_tpm_alg_id(hash_alg
);
927 if (!is_supported_alg(this, alg_id
))
929 DBG1(DBG_PTS
, "%s %N hash algorithm not supported by TPM",
930 LABEL
, hash_algorithm_short_names
, hash_alg
);
935 if (!read_public(this, handle
, &public))
940 if (key_type
== KEY_RSA
&& public.publicArea
.type
== TPM2_ALG_RSA
)
942 if (scheme
== SIGN_RSA_EMSA_PSS
)
944 sig_scheme
.scheme
= TPM2_ALG_RSAPSS
;
945 sig_scheme
.details
.rsapss
.hashAlg
= alg_id
;
949 sig_scheme
.scheme
= TPM2_ALG_RSASSA
;
950 sig_scheme
.details
.rsassa
.hashAlg
= alg_id
;
953 else if (key_type
== KEY_ECDSA
&& public.publicArea
.type
== TPM2_ALG_ECC
)
955 sig_scheme
.scheme
= TPM2_ALG_ECDSA
;
956 sig_scheme
.details
.ecdsa
.hashAlg
= alg_id
;
961 DBG1(DBG_PTS
, "%s signature scheme %N not supported by TPM key",
962 LABEL
, signature_scheme_names
, scheme
);
966 if (data
.len
<= TPM2_MAX_DIGEST_BUFFER
)
968 memcpy(buffer
.buffer
, data
.ptr
, data
.len
);
969 buffer
.size
= data
.len
;
971 this->mutex
->lock(this->mutex
);
972 rval
= Tss2_Sys_Hash(this->sys_context
, 0, &buffer
, alg_id
, hierarchy
,
973 &hash
, &validation
, 0);
974 this->mutex
->unlock(this->mutex
);
975 if (rval
!= TPM2_RC_SUCCESS
)
977 DBG1(DBG_PTS
,"%s Tss2_Sys_Hash failed: 0x%06x", LABEL
, rval
);
983 TPMI_DH_OBJECT sequence_handle
;
984 TPM2B_AUTH null_auth
;
987 this->mutex
->lock(this->mutex
);
988 rval
= Tss2_Sys_HashSequenceStart(this->sys_context
, 0, &null_auth
,
989 alg_id
, &sequence_handle
, 0);
990 if (rval
!= TPM2_RC_SUCCESS
)
992 DBG1(DBG_PTS
,"%s Tss2_Sys_HashSequenceStart failed: 0x%06x",
994 this->mutex
->unlock(this->mutex
);
1000 buffer
.size
= min(data
.len
, TPM2_MAX_DIGEST_BUFFER
);
1001 memcpy(buffer
.buffer
, data
.ptr
, buffer
.size
);
1002 data
.ptr
+= buffer
.size
;
1003 data
.len
-= buffer
.size
;
1005 rval
= Tss2_Sys_SequenceUpdate(this->sys_context
, sequence_handle
,
1006 &auth_cmd
, &buffer
, 0);
1007 if (rval
!= TPM2_RC_SUCCESS
)
1009 DBG1(DBG_PTS
,"%s Tss2_Sys_SequenceUpdate failed: 0x%06x",
1011 this->mutex
->unlock(this->mutex
);
1017 rval
= Tss2_Sys_SequenceComplete(this->sys_context
, sequence_handle
,
1018 &auth_cmd
, &buffer
, hierarchy
,
1019 &hash
, &validation
, 0);
1020 this->mutex
->unlock(this->mutex
);
1021 if (rval
!= TPM2_RC_SUCCESS
)
1023 DBG1(DBG_PTS
,"%s Tss2_Sys_SequenceComplete failed: 0x%06x",
1029 this->mutex
->lock(this->mutex
);
1030 rval
= Tss2_Sys_Sign(this->sys_context
, handle
, &auth_cmd
, &hash
,
1031 &sig_scheme
, &validation
, &sig
, &auth_rsp
);
1032 this->mutex
->unlock(this->mutex
);
1033 if (rval
!= TPM2_RC_SUCCESS
)
1035 DBG1(DBG_PTS
,"%s Tss2_Sys_Sign failed: 0x%06x", LABEL
, rval
);
1039 /* extract signature */
1042 case SIGN_RSA_EMSA_PKCS1_SHA1
:
1043 case SIGN_RSA_EMSA_PKCS1_SHA2_256
:
1044 case SIGN_RSA_EMSA_PKCS1_SHA2_384
:
1045 case SIGN_RSA_EMSA_PKCS1_SHA2_512
:
1046 *signature
= chunk_clone(
1048 sig
.signature
.rsassa
.sig
.buffer
,
1049 sig
.signature
.rsassa
.sig
.size
));
1051 case SIGN_RSA_EMSA_PSS
:
1052 *signature
= chunk_clone(
1054 sig
.signature
.rsapss
.sig
.buffer
,
1055 sig
.signature
.rsapss
.sig
.size
));
1057 case SIGN_ECDSA_256
:
1058 case SIGN_ECDSA_384
:
1059 case SIGN_ECDSA_521
:
1060 *signature
= chunk_cat("cc",
1062 sig
.signature
.ecdsa
.signatureR
.buffer
,
1063 sig
.signature
.ecdsa
.signatureR
.size
),
1065 sig
.signature
.ecdsa
.signatureS
.buffer
,
1066 sig
.signature
.ecdsa
.signatureS
.size
));
1068 case SIGN_ECDSA_WITH_SHA256_DER
:
1069 case SIGN_ECDSA_WITH_SHA384_DER
:
1070 case SIGN_ECDSA_WITH_SHA512_DER
:
1071 *signature
= asn1_wrap(ASN1_SEQUENCE
, "mm",
1074 sig
.signature
.ecdsa
.signatureR
.buffer
,
1075 sig
.signature
.ecdsa
.signatureR
.size
)),
1078 sig
.signature
.ecdsa
.signatureS
.buffer
,
1079 sig
.signature
.ecdsa
.signatureS
.size
)));
1082 DBG1(DBG_PTS
, "%s unsupported %N signature scheme",
1083 LABEL
, signature_scheme_names
, scheme
);
1090 METHOD(tpm_tss_t
, get_random
, bool,
1091 private_tpm_tss_tss2_t
*this, size_t bytes
, uint8_t *buffer
)
1093 size_t len
, random_len
= sizeof(TPM2B_DIGEST
)-2;
1094 TPM2B_DIGEST random
= { random_len
, };
1095 uint8_t *pos
= buffer
;
1100 len
= min(bytes
, random_len
);
1102 this->mutex
->lock(this->mutex
);
1103 rval
= Tss2_Sys_GetRandom(this->sys_context
, NULL
, len
, &random
, NULL
);
1104 this->mutex
->unlock(this->mutex
);
1105 if (rval
!= TSS2_RC_SUCCESS
)
1107 DBG1(DBG_PTS
,"%s Tss2_Sys_GetRandom failed: 0x%06x", LABEL
, rval
);
1110 memcpy(pos
, random
.buffer
, random
.size
);
1112 bytes
-= random
.size
;
1118 METHOD(tpm_tss_t
, get_data
, bool,
1119 private_tpm_tss_tss2_t
*this, uint32_t hierarchy
, uint32_t handle
,
1120 chunk_t pin
, chunk_t
*data
)
1122 uint16_t max_data_size
, nv_size
, nv_offset
= 0;
1125 TPMS_CAPABILITY_DATA cap_data
;
1126 TPMI_YES_NO more_data
;
1127 TPM2B_NAME nv_name
= { sizeof(TPM2B_NAME
)-2, };
1128 TPM2B_NV_PUBLIC nv_public
= { 0, };
1129 TPM2B_MAX_NV_BUFFER nv_data
= { TPM2_MAX_NV_BUFFER_SIZE
, };
1130 TPMS_AUTH_COMMAND
*cmd
;
1131 TSS2L_SYS_AUTH_COMMAND auth_cmd
= { 1, { auth_cmd_empty
} };
1132 TSS2L_SYS_AUTH_RESPONSE auth_rsp
;
1134 /* query maximum TPM data transmission size */
1135 this->mutex
->lock(this->mutex
);
1136 rval
= Tss2_Sys_GetCapability(this->sys_context
, 0, TPM2_CAP_TPM_PROPERTIES
,
1137 TPM2_PT_NV_BUFFER_MAX
, 1, &more_data
, &cap_data
, 0);
1138 this->mutex
->unlock(this->mutex
);
1139 if (rval
!= TPM2_RC_SUCCESS
)
1141 DBG1(DBG_PTS
,"%s Tss2_Sys_GetCapability failed for "
1142 "TPM2_CAP_TPM_PROPERTIES: 0x%06x", LABEL
, rval
);
1145 max_data_size
= min(cap_data
.data
.tpmProperties
.tpmProperty
[0].value
,
1146 TPM2_MAX_NV_BUFFER_SIZE
);
1148 /* get size of NV object */
1149 this->mutex
->lock(this->mutex
);
1150 rval
= Tss2_Sys_NV_ReadPublic(this->sys_context
, handle
, 0, &nv_public
,
1152 this->mutex
->unlock(this->mutex
);
1153 if (rval
!= TPM2_RC_SUCCESS
)
1155 DBG1(DBG_PTS
,"%s Tss2_Sys_NV_ReadPublic failed: 0x%06x", LABEL
, rval
);
1158 nv_size
= nv_public
.nvPublic
.dataSize
;
1159 *data
= chunk_alloc(nv_size
);
1161 /* prepare NV read session */
1162 cmd
= &auth_cmd
.auths
[0];
1163 cmd
->sessionHandle
= TPM2_RS_PW
;
1167 cmd
->hmac
.size
= min(sizeof(cmd
->hmac
)-2, pin
.len
);
1168 memcpy(cmd
->hmac
.buffer
, pin
.ptr
, cmd
->hmac
.size
);
1171 /* read NV data a maximum data size block at a time */
1174 this->mutex
->lock(this->mutex
);
1175 rval
= Tss2_Sys_NV_Read(this->sys_context
, hierarchy
, handle
, &auth_cmd
,
1176 min(nv_size
, max_data_size
), nv_offset
, &nv_data
, &auth_rsp
);
1177 this->mutex
->unlock(this->mutex
);
1178 if (rval
!= TPM2_RC_SUCCESS
)
1180 DBG1(DBG_PTS
,"%s Tss2_Sys_NV_Read failed: 0x%06x", LABEL
, rval
);
1184 memcpy(data
->ptr
+ nv_offset
, nv_data
.buffer
, nv_data
.size
);
1185 nv_offset
+= nv_data
.size
;
1186 nv_size
-= nv_data
.size
;
1192 METHOD(tpm_tss_t
, destroy
, void,
1193 private_tpm_tss_tss2_t
*this)
1195 finalize_context(this);
1196 this->mutex
->destroy(this->mutex
);
1203 tpm_tss_t
*tpm_tss_tss2_create()
1205 private_tpm_tss_tss2_t
*this;
1210 .get_version
= _get_version
,
1211 .get_version_info
= _get_version_info
,
1212 .generate_aik
= _generate_aik
,
1213 .get_public
= _get_public
,
1214 .supported_signature_schemes
= _supported_signature_schemes
,
1215 .read_pcr
= _read_pcr
,
1216 .extend_pcr
= _extend_pcr
,
1219 .get_random
= _get_random
,
1220 .get_data
= _get_data
,
1221 .destroy
= _destroy
,
1223 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
1226 available
= initialize_tcti_context(this);
1229 available
= initialize_sys_context(this);
1231 DBG1(DBG_PTS
, "TPM 2.0 via TSS2 v2 %savailable", available ?
"" : "not ");
1238 return &this->public;
1244 bool tpm_tss_tss2_init(void)
1246 TSS2_TCTI_INFO_FUNC infofn
;
1247 const TSS2_TCTI_INFO
*info
;
1248 char tcti_lib_format
[] = "libtss2-tcti-%s.so.0";
1249 char tcti_lib
[BUF_LEN
];
1250 char *tcti_names
[] = { "device", "tabrmd", "mssim" };
1251 char *tcti_options
[] = { "/dev/tpmrm0", "", "" };
1257 /* check for the existence of an in-kernel TPM resource manager */
1258 if (stat(tcti_options
[i
], &st
))
1262 DBG2(DBG_PTS
, "%s \"%s\" in-kernel resource manager is %spresent",
1263 LABEL
, tcti_options
[0], i ?
"not " : "");
1265 /* select a dynamic TCTI library (device, tabrmd or mssim) */
1266 tcti_name
= lib
->settings
->get_str(lib
->settings
,
1267 "%s.plugins.tpm.tcti.name", tcti_names
[i
], lib
->ns
);
1268 snprintf(tcti_lib
, BUF_LEN
, tcti_lib_format
, tcti_name
);
1270 for (i
= 0; i
< countof(tcti_names
); i
++)
1272 if (streq(tcti_name
, tcti_names
[i
]))
1280 DBG1(DBG_PTS
, "%s \"%s\" is not a valid TCTI library name",
1285 tcti_opts
= lib
->settings
->get_str(lib
->settings
,
1286 "%s.plugins.tpm.tcti.opts", tcti_options
[i
], lib
->ns
);
1288 /* open the selected dynamic TCTI library */
1289 tcti_handle
= dlopen(tcti_lib
, RTLD_LAZY
);
1292 DBG1(DBG_PTS
, "%s could not load \"%s\"", LABEL
, tcti_lib
);
1296 infofn
= (TSS2_TCTI_INFO_FUNC
)dlsym(tcti_handle
, TSS2_TCTI_INFO_SYMBOL
);
1299 DBG1(DBG_PTS
, "%s symbol \"%s\" not found in \"%s\"", LABEL
,
1300 TSS2_TCTI_INFO_SYMBOL
, tcti_lib
);
1301 tpm_tss_tss2_deinit();
1305 DBG2(DBG_PTS
, "%s \"%s\" successfully loaded", LABEL
, tcti_lib
);
1307 tcti_init
= info
->init
;
1315 void tpm_tss_tss2_deinit(void)
1317 dlclose(tcti_handle
);
1323 #else /* TSS_TSS2_V2 */
1328 bool tpm_tss_tss2_init(void)
1336 void tpm_tss_tss2_deinit(void)
1341 #endif /* TSS_TSS2_V2 */