2 * Copyright (C) 2016 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
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>.
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
16 #include "tpm_tss_tss2.h"
17 #include "tpm_tss_tss2_names.h"
21 #include <asn1/asn1.h>
23 #include <asn1/asn1_parser.h>
24 #include <bio/bio_reader.h>
28 #ifdef TSS2_TCTI_TABRMD
29 #include <tcti/tcti-tabrmd.h>
30 #endif /* TSS2_TCTI_TABRMD */
32 #ifdef TSS2_TCTI_SOCKET
33 #include <tcti_socket.h>
35 #define TCTI_SOCKET_DEFAULT_ADDRESS "127.0.0.1"
36 #define TCTI_SOCKET_DEFAULT_PORT 2323
37 #endif /* TSS2_TCTI_SOCKET */
39 #define LABEL "TPM 2.0 -"
41 typedef struct private_tpm_tss_tss2_t private_tpm_tss_tss2_t
;
44 * Private data of an tpm_tss_tss2_t object.
46 struct private_tpm_tss_tss2_t
{
49 * Public tpm_tss_tss2_t interface.
56 TSS2_TCTI_CONTEXT
*tcti_context
;
61 TSS2_SYS_CONTEXT
*sys_context
;
64 * Number of supported algorithms
66 size_t supported_algs_count
;
69 * List of supported algorithms
71 TPM_ALG_ID supported_algs
[TPM_PT_ALGORITHM_SET
];
75 * Some symbols required by libtctisocket
78 uint8_t simulator
= 1;
80 int TpmClientPrintf (uint8_t type
, const char *format
, ...)
86 * Convert hash algorithm to TPM_ALG_ID
88 static TPM_ALG_ID
hash_alg_to_tpm_alg_id(hash_algorithm_t alg
)
95 return TPM_ALG_SHA256
;
97 return TPM_ALG_SHA384
;
99 return TPM_ALG_SHA512
;
101 return TPM_ALG_ERROR
;
106 * Convert TPM_ALG_ID to hash algorithm
108 static hash_algorithm_t
hash_alg_from_tpm_alg_id(TPM_ALG_ID alg
)
126 * Check if an algorithm given by its TPM_ALG_ID is supported by the TPM
128 static bool is_supported_alg(private_tpm_tss_tss2_t
*this, TPM_ALG_ID alg_id
)
132 if (alg_id
== TPM_ALG_ERROR
)
137 for (i
= 0; i
< this->supported_algs_count
; i
++)
139 if (this->supported_algs
[i
] == alg_id
)
149 * Get a list of supported algorithms
151 static bool get_algs_capability(private_tpm_tss_tss2_t
*this)
153 TPMS_CAPABILITY_DATA cap_data
;
154 TPMS_TAGGED_PROPERTY tp
;
155 TPMI_YES_NO more_data
;
157 uint32_t rval
, i
, offset
, revision
= 0, year
= 0;
158 size_t len
= BUF_LEN
;
159 char buf
[BUF_LEN
], manufacturer
[5], vendor_string
[17];
163 /* get fixed properties */
164 rval
= Tss2_Sys_GetCapability(this->sys_context
, 0, TPM_CAP_TPM_PROPERTIES
,
165 PT_FIXED
, MAX_TPM_PROPERTIES
, &more_data
, &cap_data
, 0);
166 if (rval
!= TPM_RC_SUCCESS
)
168 DBG1(DBG_PTS
, "%s GetCapability failed for TPM_CAP_TPM_PROPERTIES: 0x%06x",
172 memset(manufacturer
, '\0', sizeof(manufacturer
));
173 memset(vendor_string
, '\0', sizeof(vendor_string
));
175 /* print fixed properties */
176 for (i
= 0; i
< cap_data
.data
.tpmProperties
.count
; i
++)
178 tp
= cap_data
.data
.tpmProperties
.tpmProperty
[i
];
181 case TPM_PT_REVISION
:
187 case TPM_PT_MANUFACTURER
:
188 htoun32(manufacturer
, tp
.value
);
190 case TPM_PT_VENDOR_STRING_1
:
191 case TPM_PT_VENDOR_STRING_2
:
192 case TPM_PT_VENDOR_STRING_3
:
193 case TPM_PT_VENDOR_STRING_4
:
194 offset
= 4 * (tp
.property
- TPM_PT_VENDOR_STRING_1
);
195 htoun32(vendor_string
+ offset
, tp
.value
);
201 DBG2(DBG_PTS
, "%s manufacturer: %s (%s) rev: %05.2f %u", LABEL
, manufacturer
,
202 vendor_string
, (float)revision
/100, year
);
204 /* get supported algorithms */
205 rval
= Tss2_Sys_GetCapability(this->sys_context
, 0, TPM_CAP_ALGS
,
206 0, TPM_PT_ALGORITHM_SET
, &more_data
, &cap_data
, 0);
207 if (rval
!= TPM_RC_SUCCESS
)
209 DBG1(DBG_PTS
, "%s GetCapability failed for TPM_CAP_ALGS: 0x%06x",
214 /* Number of supported algorithms */
215 this->supported_algs_count
= cap_data
.data
.algorithms
.count
;
217 /* store and print supported algorithms */
218 for (i
= 0; i
< this->supported_algs_count
; i
++)
220 alg
= cap_data
.data
.algorithms
.algProperties
[i
].alg
;
221 this->supported_algs
[i
] = alg
;
223 written
= snprintf(pos
, len
, " %N", tpm_alg_id_names
, alg
);
224 if (written
< 0 || written
>= len
)
231 DBG2(DBG_PTS
, "%s algorithms:%s", LABEL
, buf
);
233 /* get supported ECC curves */
234 rval
= Tss2_Sys_GetCapability(this->sys_context
, 0, TPM_CAP_ECC_CURVES
,
235 0, TPM_PT_LOADED_CURVES
, &more_data
, &cap_data
, 0);
236 if (rval
!= TPM_RC_SUCCESS
)
238 DBG1(DBG_PTS
, "%s GetCapability failed for TPM_ECC_CURVES: 0x%06x",
243 /* reset print buffer */
247 /* print supported ECC curves */
248 for (i
= 0; i
< cap_data
.data
.eccCurves
.count
; i
++)
250 written
= snprintf(pos
, len
, " %N", tpm_ecc_curve_names
,
251 cap_data
.data
.eccCurves
.eccCurves
[i
]);
252 if (written
< 0 || written
>= len
)
259 DBG2(DBG_PTS
, "%s ECC curves:%s", LABEL
, buf
);
265 * Initialize TSS2 TCTI TABRMD context
267 static bool initialize_tcti_tabrmd_context(private_tpm_tss_tss2_t
*this)
269 #ifdef TSS2_TCTI_TABRMD
270 size_t tcti_context_size
;
273 /* determine size of tcti context */
274 rval
= tss2_tcti_tabrmd_init(NULL
, &tcti_context_size
);
275 if (rval
!= TSS2_RC_SUCCESS
)
277 DBG1(DBG_PTS
, "%s could not get tcti_context size: 0x%06x",
282 /* allocate and initialize memory for tcti context */
283 this->tcti_context
= (TSS2_TCTI_CONTEXT
*)malloc(tcti_context_size
);
284 memset(this->tcti_context
, 0x00, tcti_context_size
);
286 /* initialize tcti context */
287 rval
= tss2_tcti_tabrmd_init(this->tcti_context
, &tcti_context_size
);
288 if (rval
!= TSS2_RC_SUCCESS
)
290 DBG1(DBG_PTS
, "%s could not get tcti_context: 0x%06x "
291 "via tabrmd interface", LABEL
, rval
);
295 #else /* TSS2_TCTI_TABRMD */
297 #endif /* TSS2_TCTI_TABRMD */
301 * Initialize TSS2 TCTI Socket context
303 static bool initialize_tcti_socket_context(private_tpm_tss_tss2_t
*this)
305 #ifdef TSS2_TCTI_SOCKET
306 size_t tcti_context_size
;
309 TCTI_SOCKET_CONF rm_if_config
= { TCTI_SOCKET_DEFAULT_ADDRESS
,
310 TCTI_SOCKET_DEFAULT_PORT
313 /* determine size of tcti context */
314 rval
= InitSocketTcti(NULL
, &tcti_context_size
, &rm_if_config
, 0);
315 if (rval
!= TSS2_RC_SUCCESS
)
317 DBG1(DBG_PTS
, "%s could not get tcti_context size: 0x%06x",
322 /* allocate memory for tcti context */
323 this->tcti_context
= (TSS2_TCTI_CONTEXT
*)malloc(tcti_context_size
);
325 /* initialize tcti context */
326 rval
= InitSocketTcti(this->tcti_context
, &tcti_context_size
,
328 if (rval
!= TSS2_RC_SUCCESS
)
330 DBG1(DBG_PTS
, "%s could not get tcti_context: 0x%06x "
331 "via socket interface", LABEL
, rval
);
335 #else /* TSS2_TCTI_SOCKET */
337 #endif /* TSS2_TCTI_SOCKET */
341 * Initialize TSS2 Sys context
343 static bool initialize_sys_context(private_tpm_tss_tss2_t
*this)
345 uint32_t sys_context_size
;
348 TSS2_ABI_VERSION abi_version
= { TSSWG_INTEROP
,
349 TSS_SAPI_FIRST_FAMILY
,
350 TSS_SAPI_FIRST_LEVEL
,
351 TSS_SAPI_FIRST_VERSION
354 /* determine size of sys context */
355 sys_context_size
= Tss2_Sys_GetContextSize(0);
357 /* allocate memory for sys context */
358 this->sys_context
= malloc(sys_context_size
);
360 /* initialize sys context */
361 rval
= Tss2_Sys_Initialize(this->sys_context
, sys_context_size
,
362 this->tcti_context
, &abi_version
);
363 if (rval
!= TSS2_RC_SUCCESS
)
365 DBG1(DBG_PTS
, "%s could not get sys_context: 0x%06x",
370 /* get a list of supported algorithms and ECC curves */
371 return get_algs_capability(this);
375 * Finalize TSS context
377 static void finalize_context(private_tpm_tss_tss2_t
*this)
379 if (this->tcti_context
)
381 tss2_tcti_finalize(this->tcti_context
);
382 free(this->tcti_context
);
384 if (this->sys_context
)
386 Tss2_Sys_Finalize(this->sys_context
);
387 free(this->sys_context
);
391 METHOD(tpm_tss_t
, get_version
, tpm_version_t
,
392 private_tpm_tss_tss2_t
*this)
394 return TPM_VERSION_2_0
;
397 METHOD(tpm_tss_t
, get_version_info
, chunk_t
,
398 private_tpm_tss_tss2_t
*this)
404 * read the public key portion of a TSS 2.0 AIK key from NVRAM
406 bool read_public(private_tpm_tss_tss2_t
*this, TPMI_DH_OBJECT handle
,
407 TPM2B_PUBLIC
*public)
411 TPM2B_NAME name
= { { sizeof(TPM2B_NAME
)-2, } };
412 TPM2B_NAME qualified_name
= { { sizeof(TPM2B_NAME
)-2, } };
414 TPMS_AUTH_RESPONSE session_data
;
415 TSS2_SYS_RSP_AUTHS sessions_data
;
416 TPMS_AUTH_RESPONSE
*session_data_array
[1];
418 session_data_array
[0] = &session_data
;
419 sessions_data
.rspAuths
= &session_data_array
[0];
420 sessions_data
.rspAuthsCount
= 1;
422 /* read public key for a given object handle from TPM 2.0 NVRAM */
423 rval
= Tss2_Sys_ReadPublic(this->sys_context
, handle
, 0, public, &name
,
424 &qualified_name
, &sessions_data
);
425 if (rval
!= TPM_RC_SUCCESS
)
427 DBG1(DBG_PTS
, "%s could not read public key from handle 0x%08x: 0x%06x",
428 LABEL
, handle
, rval
);
434 METHOD(tpm_tss_t
, generate_aik
, bool,
435 private_tpm_tss_tss2_t
*this, chunk_t ca_modulus
, chunk_t
*aik_blob
,
436 chunk_t
*aik_pubkey
, chunk_t
*identity_req
)
441 METHOD(tpm_tss_t
, get_public
, chunk_t
,
442 private_tpm_tss_tss2_t
*this, uint32_t handle
)
444 TPM2B_PUBLIC
public = { { 0, } };
445 TPM_ALG_ID sig_alg
, digest_alg
;
446 chunk_t aik_blob
, aik_pubkey
= chunk_empty
;
448 if (!read_public(this, handle
, &public))
453 aik_blob
= chunk_create((u_char
*)&public, sizeof(public));
454 DBG3(DBG_LIB
, "%s AIK public key blob: %B", LABEL
, &aik_blob
);
456 /* convert TSS 2.0 AIK public key blot into PKCS#1 format */
457 switch (public.t
.publicArea
.type
)
461 TPM2B_PUBLIC_KEY_RSA
*rsa
;
462 TPMT_RSA_SCHEME
*scheme
;
463 chunk_t aik_exponent
, aik_modulus
;
465 scheme
= &public.t
.publicArea
.parameters
.rsaDetail
.scheme
;
466 sig_alg
= scheme
->scheme
;
467 digest_alg
= scheme
->details
.anySig
.hashAlg
;
469 rsa
= &public.t
.publicArea
.unique
.rsa
;
470 aik_modulus
= chunk_create(rsa
->t
.buffer
, rsa
->t
.size
);
471 aik_exponent
= chunk_from_chars(0x01, 0x00, 0x01);
473 /* subjectPublicKeyInfo encoding of AIK RSA key */
474 if (!lib
->encoding
->encode(lib
->encoding
, PUBKEY_SPKI_ASN1_DER
,
475 NULL
, &aik_pubkey
, CRED_PART_RSA_MODULUS
, aik_modulus
,
476 CRED_PART_RSA_PUB_EXP
, aik_exponent
, CRED_PART_END
))
478 DBG1(DBG_PTS
, "%s subjectPublicKeyInfo encoding of AIK key "
487 TPMT_ECC_SCHEME
*scheme
;
491 scheme
= &public.t
.publicArea
.parameters
.eccDetail
.scheme
;
492 sig_alg
= scheme
->scheme
;
493 digest_alg
= scheme
->details
.anySig
.hashAlg
;
495 ecc
= &public.t
.publicArea
.unique
.ecc
;
497 /* allocate space for bit string */
498 pos
= asn1_build_object(&ecc_point
, ASN1_BIT_STRING
,
499 2 + ecc
->x
.t
.size
+ ecc
->y
.t
.size
);
500 /* bit string length is a multiple of octets */
502 /* uncompressed ECC point format */
504 /* copy x coordinate of ECC point */
505 memcpy(pos
, ecc
->x
.t
.buffer
, ecc
->x
.t
.size
);
506 pos
+= ecc
->x
.t
.size
;
507 /* copy y coordinate of ECC point */
508 memcpy(pos
, ecc
->y
.t
.buffer
, ecc
->y
.t
.size
);
509 /* subjectPublicKeyInfo encoding of AIK ECC key */
510 aik_pubkey
= asn1_wrap(ASN1_SEQUENCE
, "mm",
511 asn1_wrap(ASN1_SEQUENCE
, "mm",
512 asn1_build_known_oid(OID_EC_PUBLICKEY
),
513 asn1_build_known_oid(ecc
->x
.t
.size
== 32 ?
514 OID_PRIME256V1
: OID_SECT384R1
)),
519 DBG1(DBG_PTS
, "%s unsupported AIK key type", LABEL
);
522 DBG1(DBG_PTS
, "AIK signature algorithm is %N with %N hash",
523 tpm_alg_id_names
, sig_alg
, tpm_alg_id_names
, digest_alg
);
528 * Configure a PCR Selection assuming a maximum of 24 registers
530 static bool init_pcr_selection(private_tpm_tss_tss2_t
*this, uint32_t pcrs
,
531 hash_algorithm_t alg
, TPML_PCR_SELECTION
*pcr_sel
)
536 /* check if hash algorithm is supported by TPM */
537 alg_id
= hash_alg_to_tpm_alg_id(alg
);
538 if (!is_supported_alg(this, alg_id
))
540 DBG1(DBG_PTS
, "%s %N hash algorithm not supported by TPM",
541 LABEL
, hash_algorithm_short_names
, alg
);
545 /* initialize the PCR Selection structure,*/
547 pcr_sel
->pcrSelections
[0].hash
= alg_id
;
548 pcr_sel
->pcrSelections
[0].sizeofSelect
= 3;
549 pcr_sel
->pcrSelections
[0].pcrSelect
[0] = 0;
550 pcr_sel
->pcrSelections
[0].pcrSelect
[1] = 0;
551 pcr_sel
->pcrSelections
[0].pcrSelect
[2] = 0;
553 /* set the selected PCRs */
554 for (pcr
= 0; pcr
< PLATFORM_PCR
; pcr
++)
556 if (pcrs
& (1 << pcr
))
558 pcr_sel
->pcrSelections
[0].pcrSelect
[pcr
/ 8] |= ( 1 << (pcr
% 8) );
564 METHOD(tpm_tss_t
, read_pcr
, bool,
565 private_tpm_tss_tss2_t
*this, uint32_t pcr_num
, chunk_t
*pcr_value
,
566 hash_algorithm_t alg
)
568 TPML_PCR_SELECTION pcr_selection
;
569 TPML_DIGEST pcr_values
;
571 uint32_t pcr_update_counter
, rval
;
572 uint8_t *pcr_value_ptr
;
573 size_t pcr_value_len
;
575 if (pcr_num
>= PLATFORM_PCR
)
577 DBG1(DBG_PTS
, "%s maximum number of supported PCR is %d",
578 LABEL
, PLATFORM_PCR
);
582 if (!init_pcr_selection(this, (1 << pcr_num
), alg
, &pcr_selection
))
587 /* initialize the PCR Digest structure */
588 memset(&pcr_values
, 0, sizeof(TPML_DIGEST
));
590 /* read the PCR value */
591 rval
= Tss2_Sys_PCR_Read(this->sys_context
, 0, &pcr_selection
,
592 &pcr_update_counter
, &pcr_selection
, &pcr_values
, 0);
593 if (rval
!= TPM_RC_SUCCESS
)
595 DBG1(DBG_PTS
, "%s PCR bank could not be read: 0x%60x",
599 pcr_value_ptr
= (uint8_t *)pcr_values
.digests
[0].t
.buffer
;
600 pcr_value_len
= (size_t) pcr_values
.digests
[0].t
.size
;
602 *pcr_value
= chunk_clone(chunk_create(pcr_value_ptr
, pcr_value_len
));
607 METHOD(tpm_tss_t
, extend_pcr
, bool,
608 private_tpm_tss_tss2_t
*this, uint32_t pcr_num
, chunk_t
*pcr_value
,
609 chunk_t data
, hash_algorithm_t alg
)
613 TPML_DIGEST_VALUES digest_values
;
614 TPMS_AUTH_COMMAND session_data_cmd
;
615 TPMS_AUTH_RESPONSE session_data_rsp
;
616 TSS2_SYS_CMD_AUTHS sessions_data_cmd
;
617 TSS2_SYS_RSP_AUTHS sessions_data_rsp
;
618 TPMS_AUTH_COMMAND
*session_data_cmd_array
[1];
619 TPMS_AUTH_RESPONSE
*session_data_rsp_array
[1];
621 session_data_cmd_array
[0] = &session_data_cmd
;
622 session_data_rsp_array
[0] = &session_data_rsp
;
624 sessions_data_cmd
.cmdAuths
= &session_data_cmd_array
[0];
625 sessions_data_rsp
.rspAuths
= &session_data_rsp_array
[0];
627 sessions_data_cmd
.cmdAuthsCount
= 1;
628 sessions_data_rsp
.rspAuthsCount
= 1;
630 session_data_cmd
.sessionHandle
= TPM_RS_PW
;
631 session_data_cmd
.hmac
.t
.size
= 0;
632 session_data_cmd
.nonce
.t
.size
= 0;
634 *( (uint8_t *)((void *)&session_data_cmd
.sessionAttributes
) ) = 0;
636 /* check if hash algorithm is supported by TPM */
637 alg_id
= hash_alg_to_tpm_alg_id(alg
);
638 if (!is_supported_alg(this, alg_id
))
640 DBG1(DBG_PTS
, "%s %N hash algorithm not supported by TPM",
641 LABEL
, hash_algorithm_short_names
, alg
);
645 digest_values
.count
= 1;
646 digest_values
.digests
[0].hashAlg
= alg_id
;
651 if (data
.len
!= HASH_SIZE_SHA1
)
655 memcpy(digest_values
.digests
[0].digest
.sha1
, data
.ptr
,
659 if (data
.len
!= HASH_SIZE_SHA256
)
663 memcpy(digest_values
.digests
[0].digest
.sha256
, data
.ptr
,
667 if (data
.len
!= HASH_SIZE_SHA384
)
671 memcpy(digest_values
.digests
[0].digest
.sha384
, data
.ptr
,
675 if (data
.len
!= HASH_SIZE_SHA512
)
679 memcpy(digest_values
.digests
[0].digest
.sha512
, data
.ptr
,
687 rval
= Tss2_Sys_PCR_Extend(this->sys_context
, pcr_num
, &sessions_data_cmd
,
688 &digest_values
, &sessions_data_rsp
);
689 if (rval
!= TPM_RC_SUCCESS
)
691 DBG1(DBG_PTS
, "%s PCR %02u could not be extended: 0x%06x",
692 LABEL
, pcr_num
, rval
);
696 /* get updated PCR value */
697 return read_pcr(this, pcr_num
, pcr_value
, alg
);
700 METHOD(tpm_tss_t
, quote
, bool,
701 private_tpm_tss_tss2_t
*this, uint32_t aik_handle
, uint32_t pcr_sel
,
702 hash_algorithm_t alg
, chunk_t data
, tpm_quote_mode_t
*quote_mode
,
703 tpm_tss_quote_info_t
**quote_info
, chunk_t
*quote_sig
)
705 chunk_t quoted_chunk
, qualified_signer
, extra_data
, clock_info
,
706 firmware_version
, pcr_select
, pcr_digest
;
707 hash_algorithm_t pcr_digest_alg
;
708 bio_reader_t
*reader
;
711 TPM2B_DATA qualifying_data
;
712 TPML_PCR_SELECTION pcr_selection
;
713 TPM2B_ATTEST quoted
= { { sizeof(TPM2B_ATTEST
)-2, } };
714 TPMT_SIG_SCHEME scheme
;
716 TPMI_ALG_HASH hash_alg
;
717 TPMS_AUTH_COMMAND session_data_cmd
;
718 TPMS_AUTH_RESPONSE session_data_rsp
;
719 TSS2_SYS_CMD_AUTHS sessions_data_cmd
;
720 TSS2_SYS_RSP_AUTHS sessions_data_rsp
;
721 TPMS_AUTH_COMMAND
*session_data_cmd_array
[1];
722 TPMS_AUTH_RESPONSE
*session_data_rsp_array
[1];
724 session_data_cmd_array
[0] = &session_data_cmd
;
725 session_data_rsp_array
[0] = &session_data_rsp
;
727 sessions_data_cmd
.cmdAuths
= &session_data_cmd_array
[0];
728 sessions_data_rsp
.rspAuths
= &session_data_rsp_array
[0];
730 sessions_data_cmd
.cmdAuthsCount
= 1;
731 sessions_data_rsp
.rspAuthsCount
= 1;
733 session_data_cmd
.sessionHandle
= TPM_RS_PW
;
734 session_data_cmd
.hmac
.t
.size
= 0;
735 session_data_cmd
.nonce
.t
.size
= 0;
737 *( (uint8_t *)((void *)&session_data_cmd
.sessionAttributes
) ) = 0;
739 qualifying_data
.t
.size
= data
.len
;
740 memcpy(qualifying_data
.t
.buffer
, data
.ptr
, data
.len
);
742 scheme
.scheme
= TPM_ALG_NULL
;
743 memset(&sig
, 0x00, sizeof(sig
));
746 *quote_mode
= TPM_QUOTE_TPM2
;
748 if (!init_pcr_selection(this, pcr_sel
, alg
, &pcr_selection
))
753 rval
= Tss2_Sys_Quote(this->sys_context
, aik_handle
, &sessions_data_cmd
,
754 &qualifying_data
, &scheme
, &pcr_selection
, "ed
,
755 &sig
, &sessions_data_rsp
);
756 if (rval
!= TPM_RC_SUCCESS
)
758 DBG1(DBG_PTS
,"%s Tss2_Sys_Quote failed: 0x%06x", LABEL
, rval
);
761 quoted_chunk
= chunk_create(quoted
.t
.attestationData
, quoted
.t
.size
);
763 reader
= bio_reader_create(chunk_skip(quoted_chunk
, 6));
764 if (!reader
->read_data16(reader
, &qualified_signer
) ||
765 !reader
->read_data16(reader
, &extra_data
) ||
766 !reader
->read_data (reader
, 17, &clock_info
) ||
767 !reader
->read_data (reader
, 8, &firmware_version
) ||
768 !reader
->read_data (reader
, 10, &pcr_select
) ||
769 !reader
->read_data16(reader
, &pcr_digest
))
771 DBG1(DBG_PTS
, "%s parsing of quoted struct failed", LABEL
);
772 reader
->destroy(reader
);
775 reader
->destroy(reader
);
777 DBG2(DBG_PTS
, "PCR Composite digest: %B", &pcr_digest
);
778 DBG2(DBG_PTS
, "TPM Quote Info: %B", "ed_chunk
);
779 DBG2(DBG_PTS
, "qualifiedSigner: %B", &qualified_signer
);
780 DBG2(DBG_PTS
, "extraData: %B", &extra_data
);
781 DBG2(DBG_PTS
, "clockInfo: %B", &clock_info
);
782 DBG2(DBG_PTS
, "firmwareVersion: %B", &firmware_version
);
783 DBG2(DBG_PTS
, "pcrSelect: %B", &pcr_select
);
785 /* extract signature */
790 *quote_sig
= chunk_clone(
792 sig
.signature
.rsassa
.sig
.t
.buffer
,
793 sig
.signature
.rsassa
.sig
.t
.size
));
794 hash_alg
= sig
.signature
.rsassa
.hash
;
799 case TPM_ALG_ECSCHNORR
:
800 *quote_sig
= chunk_cat("cc",
802 sig
.signature
.ecdsa
.signatureR
.t
.buffer
,
803 sig
.signature
.ecdsa
.signatureR
.t
.size
),
805 sig
.signature
.ecdsa
.signatureS
.t
.buffer
,
806 sig
.signature
.ecdsa
.signatureS
.t
.size
));
807 hash_alg
= sig
.signature
.ecdsa
.hash
;
810 DBG1(DBG_PTS
, "%s unsupported %N signature algorithm",
811 LABEL
, tpm_alg_id_names
, sig
.sigAlg
);
815 DBG2(DBG_PTS
, "PCR digest algorithm is %N", tpm_alg_id_names
, hash_alg
);
816 pcr_digest_alg
= hash_alg_from_tpm_alg_id(hash_alg
);
818 DBG2(DBG_PTS
, "TPM Quote Signature: %B", quote_sig
);
820 /* Create and initialize Quote Info object */
821 *quote_info
= tpm_tss_quote_info_create(*quote_mode
, pcr_digest_alg
,
823 (*quote_info
)->set_tpm2_info(*quote_info
, qualified_signer
, clock_info
,
825 (*quote_info
)->set_version_info(*quote_info
, firmware_version
);
830 METHOD(tpm_tss_t
, sign
, bool,
831 private_tpm_tss_tss2_t
*this, uint32_t hierarchy
, uint32_t handle
,
832 signature_scheme_t scheme
, chunk_t data
, chunk_t pin
, chunk_t
*signature
)
835 hash_algorithm_t hash_alg
;
839 TPM2B_MAX_BUFFER buffer
;
840 TPM2B_DIGEST hash
= { { sizeof(TPM2B_DIGEST
)-2, } };
841 TPMT_TK_HASHCHECK validation
;
842 TPM2B_PUBLIC
public = { { 0, } };
843 TPMT_SIG_SCHEME sig_scheme
;
845 TPMS_AUTH_COMMAND session_data_cmd
;
846 TPMS_AUTH_RESPONSE session_data_rsp
;
847 TSS2_SYS_CMD_AUTHS sessions_data_cmd
;
848 TSS2_SYS_RSP_AUTHS sessions_data_rsp
;
849 TPMS_AUTH_COMMAND
*session_data_cmd_array
[1];
850 TPMS_AUTH_RESPONSE
*session_data_rsp_array
[1];
852 session_data_cmd_array
[0] = &session_data_cmd
;
853 session_data_rsp_array
[0] = &session_data_rsp
;
855 sessions_data_cmd
.cmdAuths
= &session_data_cmd_array
[0];
856 sessions_data_rsp
.rspAuths
= &session_data_rsp_array
[0];
858 sessions_data_cmd
.cmdAuthsCount
= 1;
859 sessions_data_rsp
.rspAuthsCount
= 1;
861 session_data_cmd
.sessionHandle
= TPM_RS_PW
;
862 session_data_cmd
.nonce
.t
.size
= 0;
863 session_data_cmd
.hmac
.t
.size
= 0;
867 session_data_cmd
.hmac
.t
.size
= min(sizeof(session_data_cmd
.hmac
.t
) - 2,
869 memcpy(session_data_cmd
.hmac
.t
.buffer
, pin
.ptr
,
870 session_data_cmd
.hmac
.t
.size
);
872 *( (uint8_t *)((void *)&session_data_cmd
.sessionAttributes
) ) = 0;
874 key_type
= key_type_from_signature_scheme(scheme
);
875 hash_alg
= hasher_from_signature_scheme(scheme
, NULL
);
877 /* Check if hash algorithm is supported by TPM */
878 alg_id
= hash_alg_to_tpm_alg_id(hash_alg
);
879 if (!is_supported_alg(this, alg_id
))
881 DBG1(DBG_PTS
, "%s %N hash algorithm not supported by TPM",
882 LABEL
, hash_algorithm_short_names
, hash_alg
);
887 if (!read_public(this, handle
, &public))
892 if (key_type
== KEY_RSA
&& public.t
.publicArea
.type
== TPM_ALG_RSA
)
894 sig_scheme
.scheme
= TPM_ALG_RSASSA
;
895 sig_scheme
.details
.rsassa
.hashAlg
= alg_id
;
897 else if (key_type
== KEY_ECDSA
&& public.t
.publicArea
.type
== TPM_ALG_ECC
)
899 sig_scheme
.scheme
= TPM_ALG_ECDSA
;
900 sig_scheme
.details
.ecdsa
.hashAlg
= alg_id
;
905 DBG1(DBG_PTS
, "%s signature scheme %N not supported by TPM key",
906 LABEL
, signature_scheme_names
, scheme
);
910 if (data
.len
<= MAX_DIGEST_BUFFER
)
912 memcpy(buffer
.t
.buffer
, data
.ptr
, data
.len
);
913 buffer
.t
.size
= data
.len
;
915 rval
= Tss2_Sys_Hash(this->sys_context
, 0, &buffer
, alg_id
, hierarchy
,
916 &hash
, &validation
, 0);
917 if (rval
!= TPM_RC_SUCCESS
)
919 DBG1(DBG_PTS
,"%s Tss2_Sys_Hash failed: 0x%06x", LABEL
, rval
);
925 TPMI_DH_OBJECT sequence_handle
;
926 TPM2B_AUTH null_auth
;
928 null_auth
.t
.size
= 0;
929 rval
= Tss2_Sys_HashSequenceStart(this->sys_context
, 0, &null_auth
,
930 alg_id
, &sequence_handle
, 0);
931 if (rval
!= TPM_RC_SUCCESS
)
933 DBG1(DBG_PTS
,"%s Tss2_Sys_HashSequenceStart failed: 0x%06x",
940 buffer
.t
.size
= min(data
.len
, MAX_DIGEST_BUFFER
);
941 memcpy(buffer
.t
.buffer
, data
.ptr
, buffer
.t
.size
);
942 data
.ptr
+= buffer
.t
.size
;
943 data
.len
-= buffer
.t
.size
;
945 rval
= Tss2_Sys_SequenceUpdate(this->sys_context
, sequence_handle
,
946 &sessions_data_cmd
, &buffer
, 0);
947 if (rval
!= TPM_RC_SUCCESS
)
949 DBG1(DBG_PTS
,"%s Tss2_Sys_SequenceUpdate failed: 0x%06x",
956 rval
= Tss2_Sys_SequenceComplete(this->sys_context
, sequence_handle
,
957 &sessions_data_cmd
, &buffer
, hierarchy
,
958 &hash
, &validation
, 0);
959 if (rval
!= TPM_RC_SUCCESS
)
961 DBG1(DBG_PTS
,"%s Tss2_Sys_SequenceComplete failed: 0x%06x",
967 rval
= Tss2_Sys_Sign(this->sys_context
, handle
, &sessions_data_cmd
, &hash
,
968 &sig_scheme
, &validation
, &sig
, &sessions_data_rsp
);
969 if (rval
!= TPM_RC_SUCCESS
)
971 DBG1(DBG_PTS
,"%s Tss2_Sys_Sign failed: 0x%06x", LABEL
, rval
);
975 /* extract signature */
978 case SIGN_RSA_EMSA_PKCS1_SHA1
:
979 case SIGN_RSA_EMSA_PKCS1_SHA2_256
:
980 case SIGN_RSA_EMSA_PKCS1_SHA2_384
:
981 case SIGN_RSA_EMSA_PKCS1_SHA2_512
:
982 *signature
= chunk_clone(
984 sig
.signature
.rsassa
.sig
.t
.buffer
,
985 sig
.signature
.rsassa
.sig
.t
.size
));
990 *signature
= chunk_cat("cc",
992 sig
.signature
.ecdsa
.signatureR
.t
.buffer
,
993 sig
.signature
.ecdsa
.signatureR
.t
.size
),
995 sig
.signature
.ecdsa
.signatureS
.t
.buffer
,
996 sig
.signature
.ecdsa
.signatureS
.t
.size
));
998 case SIGN_ECDSA_WITH_SHA256_DER
:
999 case SIGN_ECDSA_WITH_SHA384_DER
:
1000 case SIGN_ECDSA_WITH_SHA512_DER
:
1001 *signature
= asn1_wrap(ASN1_SEQUENCE
, "mm",
1004 sig
.signature
.ecdsa
.signatureR
.t
.buffer
,
1005 sig
.signature
.ecdsa
.signatureR
.t
.size
)),
1008 sig
.signature
.ecdsa
.signatureS
.t
.buffer
,
1009 sig
.signature
.ecdsa
.signatureS
.t
.size
)));
1012 DBG1(DBG_PTS
, "%s unsupported %N signature scheme",
1013 LABEL
, signature_scheme_names
, scheme
);
1020 METHOD(tpm_tss_t
, get_random
, bool,
1021 private_tpm_tss_tss2_t
*this, size_t bytes
, uint8_t *buffer
)
1023 size_t len
, random_len
= sizeof(TPM2B_DIGEST
)-2;
1024 TPM2B_DIGEST random
= { { random_len
, } };
1025 uint8_t *pos
= buffer
;
1030 len
= min(bytes
, random_len
);
1032 rval
= Tss2_Sys_GetRandom(this->sys_context
, NULL
, len
, &random
, NULL
);
1033 if (rval
!= TSS2_RC_SUCCESS
)
1035 DBG1(DBG_PTS
,"%s Tss2_Sys_GetRandom failed: 0x%06x", LABEL
, rval
);
1038 memcpy(pos
, random
.t
.buffer
, random
.t
.size
);
1039 pos
+= random
.t
.size
;
1040 bytes
-= random
.t
.size
;
1046 METHOD(tpm_tss_t
, get_data
, bool,
1047 private_tpm_tss_tss2_t
*this, uint32_t hierarchy
, uint32_t handle
,
1048 chunk_t pin
, chunk_t
*data
)
1050 uint16_t nv_size
, nv_offset
= 0;
1053 TPM2B_NAME nv_name
= { { sizeof(TPM2B_NAME
)-2, } };
1054 TPM2B_NV_PUBLIC nv_public
= { { 0, } };
1055 TPM2B_MAX_NV_BUFFER nv_data
= { { sizeof(TPM2B_MAX_NV_BUFFER
)-2, } };
1056 TPMS_AUTH_COMMAND session_data_cmd
;
1057 TPMS_AUTH_RESPONSE session_data_rsp
;
1058 TSS2_SYS_CMD_AUTHS sessions_data_cmd
;
1059 TSS2_SYS_RSP_AUTHS sessions_data_rsp
;
1060 TPMS_AUTH_COMMAND
*session_data_cmd_array
[1];
1061 TPMS_AUTH_RESPONSE
*session_data_rsp_array
[1];
1063 /* get size of NV object */
1064 rval
= Tss2_Sys_NV_ReadPublic(this->sys_context
, handle
, 0, &nv_public
,
1066 if (rval
!= TPM_RC_SUCCESS
)
1068 DBG1(DBG_PTS
,"%s Tss2_Sys_NV_ReadPublic failed: 0x%06x", LABEL
, rval
);
1071 nv_size
= nv_public
.t
.nvPublic
.dataSize
;
1072 *data
= chunk_alloc(nv_size
);
1074 /*prepare NV read session */
1075 session_data_cmd_array
[0] = &session_data_cmd
;
1076 session_data_rsp_array
[0] = &session_data_rsp
;
1078 sessions_data_cmd
.cmdAuths
= &session_data_cmd_array
[0];
1079 sessions_data_rsp
.rspAuths
= &session_data_rsp_array
[0];
1081 sessions_data_cmd
.cmdAuthsCount
= 1;
1082 sessions_data_rsp
.rspAuthsCount
= 1;
1084 session_data_cmd
.sessionHandle
= TPM_RS_PW
;
1085 session_data_cmd
.nonce
.t
.size
= 0;
1086 session_data_cmd
.hmac
.t
.size
= 0;
1090 session_data_cmd
.hmac
.t
.size
= min(sizeof(session_data_cmd
.hmac
.t
) - 2,
1092 memcpy(session_data_cmd
.hmac
.t
.buffer
, pin
.ptr
,
1093 session_data_cmd
.hmac
.t
.size
);
1095 *( (uint8_t *)((void *)&session_data_cmd
.sessionAttributes
) ) = 0;
1097 /* read NV data an NV buffer block at a time */
1100 rval
= Tss2_Sys_NV_Read(this->sys_context
, hierarchy
, handle
,
1101 &sessions_data_cmd
, min(nv_size
, MAX_NV_BUFFER_SIZE
),
1102 nv_offset
, &nv_data
, &sessions_data_rsp
);
1104 if (rval
!= TPM_RC_SUCCESS
)
1106 DBG1(DBG_PTS
,"%s Tss2_Sys_NV_Read failed: 0x%06x", LABEL
, rval
);
1110 memcpy(data
->ptr
+ nv_offset
, nv_data
.t
.buffer
, nv_data
.t
.size
);
1111 nv_offset
+= nv_data
.t
.size
;
1112 nv_size
-= nv_data
.t
.size
;
1119 * ASN.1 definition of a PKCS#1 RSA private key
1121 static const asn1Object_t privkeyObjects
[] = {
1122 { 0, "RSAPrivateKey", ASN1_SEQUENCE
, ASN1_NONE
}, /* 0 */
1123 { 1, "version", ASN1_INTEGER
, ASN1_BODY
}, /* 1 */
1124 { 1, "modulus", ASN1_INTEGER
, ASN1_BODY
}, /* 2 */
1125 { 1, "publicExponent", ASN1_INTEGER
, ASN1_BODY
}, /* 3 */
1126 { 1, "privateExponent", ASN1_INTEGER
, ASN1_BODY
}, /* 4 */
1127 { 1, "prime1", ASN1_INTEGER
, ASN1_BODY
}, /* 5 */
1128 { 1, "prime2", ASN1_INTEGER
, ASN1_BODY
}, /* 6 */
1129 { 1, "exponent1", ASN1_INTEGER
, ASN1_BODY
}, /* 7 */
1130 { 1, "exponent2", ASN1_INTEGER
, ASN1_BODY
}, /* 8 */
1131 { 1, "coefficient", ASN1_INTEGER
, ASN1_BODY
}, /* 9 */
1132 { 1, "otherPrimeInfos", ASN1_SEQUENCE
, ASN1_OPT
|
1133 ASN1_LOOP
}, /* 10 */
1134 { 2, "otherPrimeInfo", ASN1_SEQUENCE
, ASN1_NONE
}, /* 11 */
1135 { 3, "prime", ASN1_INTEGER
, ASN1_BODY
}, /* 12 */
1136 { 3, "exponent", ASN1_INTEGER
, ASN1_BODY
}, /* 13 */
1137 { 3, "coefficient", ASN1_INTEGER
, ASN1_BODY
}, /* 14 */
1138 { 1, "end opt or loop", ASN1_EOC
, ASN1_END
}, /* 15 */
1139 { 0, "exit", ASN1_EOC
, ASN1_EXIT
}
1142 #define PRIV_KEY_VERSION 1
1143 #define PRIV_KEY_MODULUS 2
1144 #define PRIV_KEY_PUB_EXP 3
1145 #define PRIV_KEY_PRIME1 5
1148 * Build a TPM 2.0 RSA key from an ASN.1 encoded private key blob.
1150 static bool build_rsa_key(chunk_t blob
, TPMT_SENSITIVE
*priv
, TPMT_PUBLIC
*pub
)
1153 asn1_parser_t
*parser
;
1156 bool success
= FALSE
;
1158 TPM2B_PRIVATE_KEY_RSA
*priv_rsa
= &priv
->sensitive
.rsa
;
1159 TPM2B_PUBLIC_KEY_RSA
*pub_rsa
= &pub
->unique
.rsa
;
1161 priv
->sensitiveType
= TPM_ALG_RSA
;
1162 pub
->type
= TPM_ALG_RSA
;
1163 pub
->parameters
.rsaDetail
.symmetric
.algorithm
= TPM_ALG_NULL
;
1164 pub
->parameters
.rsaDetail
.scheme
.scheme
= TPM_ALG_RSASSA
;
1165 pub
->parameters
.rsaDetail
.scheme
.details
.anySig
.hashAlg
= TPM_ALG_SHA256
;
1167 parser
= asn1_parser_create(privkeyObjects
, blob
);
1168 parser
->set_flags(parser
, FALSE
, TRUE
);
1170 while (parser
->iterate(parser
, &objectID
, &object
))
1174 case PRIV_KEY_VERSION
:
1175 if (object
.len
> 0 && *object
.ptr
!= 0)
1180 case PRIV_KEY_MODULUS
:
1182 if (n
.len
> 0 && *n
.ptr
== 0x00)
1184 n
= chunk_skip(n
, 1);
1186 if (n
.len
> MAX_RSA_KEY_BYTES
)
1190 memcpy(pub_rsa
->t
.buffer
, n
.ptr
, n
.len
);
1191 pub_rsa
->t
.size
= n
.len
;
1192 pub
->parameters
.rsaDetail
.keyBits
= 8 * n
.len
;
1194 case PRIV_KEY_PUB_EXP
:
1196 /* we only accept the standard public exponent 2'16+1 */
1197 if (chunk_equals(e
, chunk_from_str("\x01\x00\x01")))
1202 case PRIV_KEY_PRIME1
:
1204 if (p
.len
> 0 && *p
.ptr
== 0x00)
1206 p
= chunk_skip(p
, 1);
1208 if (p
.len
> MAX_RSA_KEY_BYTES
/ 2)
1212 memcpy(priv_rsa
->t
.buffer
, p
.ptr
, p
.len
);
1213 priv_rsa
->t
.size
= p
.len
;
1217 success
= parser
->success(parser
);
1220 parser
->destroy(parser
);
1226 * Build a TPM 2.0 ECC key from an ASN.1 encoded private key blob.
1228 static bool build_ecc_key(chunk_t blob
, TPMT_SENSITIVE
*priv
, TPMT_PUBLIC
*pub
)
1230 priv
->sensitiveType
= TPM_ALG_RSA
;
1231 pub
->type
= TPM_ALG_RSA
;
1236 METHOD(tpm_tss_t
, load_key
, bool,
1237 private_tpm_tss_tss2_t
*this, uint32_t hierarchy
, uint32_t handle
,
1238 chunk_t pin
, key_type_t type
, chunk_t encoding
)
1240 bool success
= FALSE
;
1241 uint32_t obj_handle
, rval
;
1243 TPM2B_SENSITIVE sensitive
= { { sizeof(TPM2B_SENSITIVE
)-2, } };
1244 TPM2B_PUBLIC
public = { { sizeof(TPM2B_PUBLIC
)-2, } };
1245 TPMT_SENSITIVE
*priv
= &sensitive
.t
.sensitiveArea
;
1246 TPMT_PUBLIC
*pub
= &public.t
.publicArea
;
1248 chunk_t priv_chunk
= { (uint8_t*)priv
, (size_t)sensitive
.t
.size
};
1249 chunk_t pub_chunk
= { (uint8_t*)pub
, (size_t)public.t
.size
};
1251 TPM2B_NAME name
= { { sizeof(TPM2B_NAME
)-2, } };
1253 TPMS_AUTH_RESPONSE session_data
;
1254 TSS2_SYS_RSP_AUTHS sessions_data
;
1255 TPMS_AUTH_RESPONSE
*session_data_array
[1];
1257 session_data_array
[0] = &session_data
;
1258 sessions_data
.rspAuths
= &session_data_array
[0];
1259 sessions_data
.rspAuthsCount
= 1;
1261 pub
->nameAlg
= TPM_ALG_SHA256
; /* TODO make nameAlg configurable */
1262 pub
->objectAttributes
.val
= 0x00040060;
1267 success
= build_rsa_key(encoding
, priv
, pub
);
1270 success
= build_ecc_key(encoding
, priv
, pub
);
1280 DBG1(DBG_PTS
, "TPM2B_SENSITIVE: %B", &priv_chunk
);
1281 DBG1(DBG_PTS
, "TPM2B_PUBLIC: %B", &pub_chunk
);
1283 rval
= Tss2_Sys_LoadExternal(this->sys_context
, 0, &sensitive
, &public,
1284 hierarchy
, &obj_handle
, &name
, &sessions_data
);
1285 if (rval
!= TPM_RC_SUCCESS
)
1287 DBG1(DBG_PTS
,"%s Tss2_Sys_LoadExternal failed: 0x%06x", LABEL
, rval
);
1290 DBG1(DBG_PTS
, "handle = 0x%08x", obj_handle
);
1295 METHOD(tpm_tss_t
, destroy
, void,
1296 private_tpm_tss_tss2_t
*this)
1298 finalize_context(this);
1305 tpm_tss_t
*tpm_tss_tss2_create()
1307 private_tpm_tss_tss2_t
*this;
1312 .get_version
= _get_version
,
1313 .get_version_info
= _get_version_info
,
1314 .generate_aik
= _generate_aik
,
1315 .get_public
= _get_public
,
1316 .read_pcr
= _read_pcr
,
1317 .extend_pcr
= _extend_pcr
,
1320 .get_random
= _get_random
,
1321 .get_data
= _get_data
,
1322 .load_key
= _load_key
,
1323 .destroy
= _destroy
,
1327 available
= initialize_tcti_tabrmd_context(this);
1330 available
= initialize_tcti_socket_context(this);
1334 available
= initialize_sys_context(this);
1336 DBG1(DBG_PTS
, "TPM 2.0 via TSS2 %savailable", available
? "" : "not ");
1343 return &this->public;
1346 #else /* TSS_TSS2 */
1348 tpm_tss_t
*tpm_tss_tss2_create()
1353 #endif /* TSS_TSS2 */