2 * Copyright (C) 2011-2012 Sansar Choinyambuu, 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
18 #include <utils/debug.h>
19 #include <crypto/hashers/hasher.h>
20 #include <bio/bio_writer.h>
21 #include <bio/bio_reader.h>
24 #include <trousers/tss.h>
25 #include <trousers/trousers.h>
27 #ifndef TPM_TAG_QUOTE_INFO2
28 #define TPM_TAG_QUOTE_INFO2 0x0036
31 #define TPM_LOC_ZERO 0x01
35 #include <sys/types.h>
37 #include <sys/utsname.h>
42 typedef struct private_pts_t private_pts_t
;
45 * Private data of a pts_t object.
48 struct private_pts_t
{
51 * Public pts_t interface.
56 * PTS Protocol Capabilities
58 pts_proto_caps_flag_t proto_caps
;
61 * PTS Measurement Algorithm
63 pts_meas_algorithms_t algorithm
;
68 pts_meas_algorithms_t dh_hash_algorithm
;
71 * PTS Diffie-Hellman Secret
76 * PTS Diffie-Hellman Initiator Nonce
78 chunk_t initiator_nonce
;
81 * PTS Diffie-Hellman Responder Nonce
83 chunk_t responder_nonce
;
86 * Secret assessment value to be used for TPM Quote as an external data
91 * Platform and OS Info
96 * TRUE if IMC-PTS, FALSE if IMV-PTS
101 * Do we have an activated TPM
106 * Contains a TPM_CAP_VERSION_INFO struct
108 chunk_t tpm_version_info
;
111 * Contains TSS Blob structure for AIK
116 * Contains a Attestation Identity Key or Certificate
127 METHOD(pts_t
, get_proto_caps
, pts_proto_caps_flag_t
,
130 return this->proto_caps
;
133 METHOD(pts_t
, set_proto_caps
, void,
134 private_pts_t
*this, pts_proto_caps_flag_t flags
)
136 this->proto_caps
= flags
;
137 DBG2(DBG_PTS
, "supported PTS protocol capabilities: %s%s%s%s%s",
138 flags
& PTS_PROTO_CAPS_C ?
"C" : ".",
139 flags
& PTS_PROTO_CAPS_V ?
"V" : ".",
140 flags
& PTS_PROTO_CAPS_D ?
"D" : ".",
141 flags
& PTS_PROTO_CAPS_T ?
"T" : ".",
142 flags
& PTS_PROTO_CAPS_X ?
"X" : ".");
145 METHOD(pts_t
, get_meas_algorithm
, pts_meas_algorithms_t
,
148 return this->algorithm
;
151 METHOD(pts_t
, set_meas_algorithm
, void,
152 private_pts_t
*this, pts_meas_algorithms_t algorithm
)
154 hash_algorithm_t hash_alg
;
156 hash_alg
= pts_meas_algo_to_hash(algorithm
);
157 DBG2(DBG_PTS
, "selected PTS measurement algorithm is %N",
158 hash_algorithm_names
, hash_alg
);
159 if (hash_alg
!= HASH_UNKNOWN
)
161 this->algorithm
= algorithm
;
165 METHOD(pts_t
, get_dh_hash_algorithm
, pts_meas_algorithms_t
,
168 return this->dh_hash_algorithm
;
171 METHOD(pts_t
, set_dh_hash_algorithm
, void,
172 private_pts_t
*this, pts_meas_algorithms_t algorithm
)
174 hash_algorithm_t hash_alg
;
176 hash_alg
= pts_meas_algo_to_hash(algorithm
);
177 DBG2(DBG_PTS
, "selected DH hash algorithm is %N",
178 hash_algorithm_names
, hash_alg
);
179 if (hash_alg
!= HASH_UNKNOWN
)
181 this->dh_hash_algorithm
= algorithm
;
186 METHOD(pts_t
, create_dh_nonce
, bool,
187 private_pts_t
*this, pts_dh_group_t group
, int nonce_len
)
189 diffie_hellman_group_t dh_group
;
193 dh_group
= pts_dh_group_to_ike(group
);
194 DBG2(DBG_PTS
, "selected PTS DH group is %N",
195 diffie_hellman_group_names
, dh_group
);
196 DESTROY_IF(this->dh
);
197 this->dh
= lib
->crypto
->create_dh(lib
->crypto
, dh_group
);
199 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_STRONG
);
202 DBG1(DBG_PTS
, "no rng available");
205 DBG2(DBG_PTS
, "nonce length is %d", nonce_len
);
206 nonce
= this->is_imc ?
&this->responder_nonce
: &this->initiator_nonce
;
208 if (!rng
->allocate_bytes(rng
, nonce_len
, nonce
))
210 DBG1(DBG_PTS
, "failed to allocate nonce");
218 METHOD(pts_t
, get_my_public_value
, void,
219 private_pts_t
*this, chunk_t
*value
, chunk_t
*nonce
)
221 this->dh
->get_my_public_value(this->dh
, value
);
222 *nonce
= this->is_imc ?
this->responder_nonce
: this->initiator_nonce
;
225 METHOD(pts_t
, set_peer_public_value
, void,
226 private_pts_t
*this, chunk_t value
, chunk_t nonce
)
228 this->dh
->set_other_public_value(this->dh
, value
);
230 nonce
= chunk_clone(nonce
);
233 this->initiator_nonce
= nonce
;
237 this->responder_nonce
= nonce
;
241 METHOD(pts_t
, calculate_secret
, bool,
245 hash_algorithm_t hash_alg
;
246 chunk_t shared_secret
;
248 /* Check presence of nonces */
249 if (!this->initiator_nonce
.len
|| !this->responder_nonce
.len
)
251 DBG1(DBG_PTS
, "initiator and/or responder nonce is not available");
254 DBG3(DBG_PTS
, "initiator nonce: %B", &this->initiator_nonce
);
255 DBG3(DBG_PTS
, "responder nonce: %B", &this->responder_nonce
);
257 /* Calculate the DH secret */
258 if (this->dh
->get_shared_secret(this->dh
, &shared_secret
) != SUCCESS
)
260 DBG1(DBG_PTS
, "shared DH secret computation failed");
263 DBG3(DBG_PTS
, "shared DH secret: %B", &shared_secret
);
265 /* Calculate the secret assessment value */
266 hash_alg
= pts_meas_algo_to_hash(this->dh_hash_algorithm
);
267 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, hash_alg
);
270 !hasher
->get_hash(hasher
, chunk_from_chars('1'), NULL
) ||
271 !hasher
->get_hash(hasher
, this->initiator_nonce
, NULL
) ||
272 !hasher
->get_hash(hasher
, this->responder_nonce
, NULL
) ||
273 !hasher
->allocate_hash(hasher
, shared_secret
, &this->secret
))
278 hasher
->destroy(hasher
);
280 /* The DH secret must be destroyed */
281 chunk_clear(&shared_secret
);
284 * Truncate the hash to 20 bytes to fit the ExternalData
285 * argument of the TPM Quote command
287 this->secret
.len
= min(this->secret
.len
, 20);
288 DBG3(DBG_PTS
, "secret assessment value: %B", &this->secret
);
295 * Print TPM 1.2 Version Info
297 static void print_tpm_version_info(private_pts_t
*this)
299 TPM_CAP_VERSION_INFO versionInfo
;
303 result
= Trspi_UnloadBlob_CAP_VERSION_INFO(&offset
,
304 this->tpm_version_info
.ptr
, &versionInfo
);
305 if (result
!= TSS_SUCCESS
)
307 DBG1(DBG_PTS
, "could not parse tpm version info: tss error 0x%x",
312 DBG2(DBG_PTS
, "TPM 1.2 Version Info: Chip Version: %hhu.%hhu.%hhu.%hhu,"
313 " Spec Level: %hu, Errata Rev: %hhu, Vendor ID: %.4s [%.*s]",
314 versionInfo
.version
.major
, versionInfo
.version
.minor
,
315 versionInfo
.version
.revMajor
, versionInfo
.version
.revMinor
,
316 versionInfo
.specLevel
, versionInfo
.errataRev
,
317 versionInfo
.tpmVendorID
, versionInfo
.vendorSpecificSize
,
318 versionInfo
.vendorSpecificSize ?
319 (char*)versionInfo
.vendorSpecific
: "");
321 free(versionInfo
.vendorSpecific
);
326 static void print_tpm_version_info(private_pts_t
*this)
328 DBG1(DBG_PTS
, "unknown TPM version: no TSS implementation available");
331 #endif /* TSS_TROUSERS */
333 METHOD(pts_t
, get_platform_info
, char*,
336 return this->platform_info
;
339 METHOD(pts_t
, set_platform_info
, void,
340 private_pts_t
*this, chunk_t name
, chunk_t version
)
342 int len
= name
.len
+ 1 + version
.len
+ 1;
344 /* platform info is a concatenation of OS name and OS version */
345 free(this->platform_info
);
346 this->platform_info
= malloc(len
);
347 snprintf(this->platform_info
, len
, "%.*s %.*s", (int)name
.len
, name
.ptr
,
348 (int)version
.len
, version
.ptr
);
351 METHOD(pts_t
, get_tpm_version_info
, bool,
352 private_pts_t
*this, chunk_t
*info
)
358 *info
= this->tpm_version_info
;
359 print_tpm_version_info(this);
363 METHOD(pts_t
, set_tpm_version_info
, void,
364 private_pts_t
*this, chunk_t info
)
366 this->tpm_version_info
= chunk_clone(info
);
367 print_tpm_version_info(this);
371 * Load an AIK Blob (TSS_TSPATTRIB_KEYBLOB_BLOB attribute)
373 static void load_aik_blob(private_pts_t
*this)
377 u_int32_t aikBlobLen
;
379 blob_path
= lib
->settings
->get_str(lib
->settings
,
380 "%s.plugins.imc-attestation.aik_blob", NULL
, lib
->ns
);
384 /* Read aik key blob from a file */
385 if ((fp
= fopen(blob_path
, "r")) == NULL
)
387 DBG1(DBG_PTS
, "unable to open AIK Blob file: %s", blob_path
);
391 fseek(fp
, 0, SEEK_END
);
392 aikBlobLen
= ftell(fp
);
393 fseek(fp
, 0L, SEEK_SET
);
395 this->aik_blob
= chunk_alloc(aikBlobLen
);
396 if (fread(this->aik_blob
.ptr
, 1, aikBlobLen
, fp
))
398 DBG2(DBG_PTS
, "loaded AIK Blob from '%s'", blob_path
);
399 DBG3(DBG_PTS
, "AIK Blob: %B", &this->aik_blob
);
403 DBG1(DBG_PTS
, "unable to read AIK Blob file '%s'", blob_path
);
409 DBG1(DBG_PTS
, "AIK Blob is not available");
413 * Load an AIK certificate or public key
414 * the certificate having precedence over the public key if both are present
416 static void load_aik(private_pts_t
*this)
418 char *cert_path
, *key_path
;
420 cert_path
= lib
->settings
->get_str(lib
->settings
,
421 "%s.plugins.imc-attestation.aik_cert", NULL
, lib
->ns
);
422 key_path
= lib
->settings
->get_str(lib
->settings
,
423 "%s.plugins.imc-attestation.aik_key", NULL
, lib
->ns
);
427 this->aik
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
,
428 CERT_X509
, BUILD_FROM_FILE
,
429 cert_path
, BUILD_END
);
432 DBG2(DBG_PTS
, "loaded AIK certificate from '%s'", cert_path
);
438 this->aik
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
,
439 CERT_TRUSTED_PUBKEY
, BUILD_FROM_FILE
,
440 key_path
, BUILD_END
);
443 DBG2(DBG_PTS
, "loaded AIK public key from '%s'", key_path
);
448 DBG1(DBG_PTS
, "neither AIK certificate nor public key is available");
451 METHOD(pts_t
, get_aik
, certificate_t
*,
457 METHOD(pts_t
, set_aik
, void,
458 private_pts_t
*this, certificate_t
*aik
)
460 DESTROY_IF(this->aik
);
461 this->aik
= aik
->get_ref(aik
);
464 METHOD(pts_t
, get_aik_keyid
, bool,
465 private_pts_t
*this, chunk_t
*keyid
)
467 public_key_t
*public;
472 DBG1(DBG_PTS
, "no AIK certificate available");
475 public = this->aik
->get_public_key(this->aik
);
478 DBG1(DBG_PTS
, "no AIK public key available");
481 success
= public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1
, keyid
);
484 DBG1(DBG_PTS
, "no SHA-1 AIK public key info ID available");
486 public->destroy(public);
491 METHOD(pts_t
, is_path_valid
, bool,
492 private_pts_t
*this, char *path
, pts_error_code_t
*error_code
)
498 if (!stat(path
, &st
))
502 else if (errno
== ENOENT
|| errno
== ENOTDIR
)
504 DBG1(DBG_PTS
, "file/directory does not exist %s", path
);
505 *error_code
= TCG_PTS_FILE_NOT_FOUND
;
507 else if (errno
== EFAULT
)
509 DBG1(DBG_PTS
, "bad address %s", path
);
510 *error_code
= TCG_PTS_INVALID_PATH
;
514 DBG1(DBG_PTS
, "error: %s occurred while validating path: %s",
515 strerror(errno
), path
);
523 * Obtain statistical information describing a file
525 static bool file_metadata(char *pathname
, pts_file_metadata_t
**entry
)
528 pts_file_metadata_t
*this;
530 this = malloc_thing(pts_file_metadata_t
);
532 if (stat(pathname
, &st
))
534 DBG1(DBG_PTS
, "unable to obtain statistics about '%s'", pathname
);
539 if (S_ISREG(st
.st_mode
))
541 this->type
= PTS_FILE_REGULAR
;
543 else if (S_ISDIR(st
.st_mode
))
545 this->type
= PTS_FILE_DIRECTORY
;
547 else if (S_ISCHR(st
.st_mode
))
549 this->type
= PTS_FILE_CHAR_SPEC
;
551 else if (S_ISBLK(st
.st_mode
))
553 this->type
= PTS_FILE_BLOCK_SPEC
;
555 else if (S_ISFIFO(st
.st_mode
))
557 this->type
= PTS_FILE_FIFO
;
559 else if (S_ISLNK(st
.st_mode
))
561 this->type
= PTS_FILE_SYM_LINK
;
563 else if (S_ISSOCK(st
.st_mode
))
565 this->type
= PTS_FILE_SOCKET
;
569 this->type
= PTS_FILE_OTHER
;
572 this->filesize
= st
.st_size
;
573 this->created
= st
.st_ctime
;
574 this->modified
= st
.st_mtime
;
575 this->accessed
= st
.st_atime
;
576 this->owner
= st
.st_uid
;
577 this->group
= st
.st_gid
;
583 METHOD(pts_t
, get_metadata
, pts_file_meta_t
*,
584 private_pts_t
*this, char *pathname
, bool is_directory
)
586 pts_file_meta_t
*metadata
;
587 pts_file_metadata_t
*entry
;
589 /* Create a metadata object */
590 metadata
= pts_file_meta_create();
594 enumerator_t
*enumerator
;
595 char *rel_name
, *abs_name
;
598 enumerator
= enumerator_create_directory(pathname
);
601 DBG1(DBG_PTS
," directory '%s' can not be opened, %s", pathname
,
603 metadata
->destroy(metadata
);
606 while (enumerator
->enumerate(enumerator
, &rel_name
, &abs_name
, &st
))
608 /* measure regular files only */
609 if (S_ISREG(st
.st_mode
) && *rel_name
!= '.')
611 if (!file_metadata(abs_name
, &entry
))
613 enumerator
->destroy(enumerator
);
614 metadata
->destroy(metadata
);
617 entry
->filename
= strdup(rel_name
);
618 metadata
->add(metadata
, entry
);
621 enumerator
->destroy(enumerator
);
625 if (!file_metadata(pathname
, &entry
))
627 metadata
->destroy(metadata
);
630 entry
->filename
= strdup(basename(pathname
));
631 metadata
->add(metadata
, entry
);
640 METHOD(pts_t
, read_pcr
, bool,
641 private_pts_t
*this, u_int32_t pcr_num
, chunk_t
*pcr_value
)
643 TSS_HCONTEXT hContext
;
648 bool success
= FALSE
;
650 result
= Tspi_Context_Create(&hContext
);
651 if (result
!= TSS_SUCCESS
)
653 DBG1(DBG_PTS
, "TPM context could not be created: tss error 0x%x", result
);
657 result
= Tspi_Context_Connect(hContext
, NULL
);
658 if (result
!= TSS_SUCCESS
)
662 result
= Tspi_Context_GetTpmObject (hContext
, &hTPM
);
663 if (result
!= TSS_SUCCESS
)
667 result
= Tspi_TPM_PcrRead(hTPM
, pcr_num
, (UINT32
*)&rgbPcrValue
.len
, &rgbPcrValue
.ptr
);
668 if (result
!= TSS_SUCCESS
)
672 *pcr_value
= chunk_clone(rgbPcrValue
);
673 DBG3(DBG_PTS
, "PCR %d value:%B", pcr_num
, pcr_value
);
679 DBG1(DBG_PTS
, "TPM not available: tss error 0x%x", result
);
681 Tspi_Context_FreeMemory(hContext
, NULL
);
682 Tspi_Context_Close(hContext
);
687 METHOD(pts_t
, extend_pcr
, bool,
688 private_pts_t
*this, u_int32_t pcr_num
, chunk_t input
, chunk_t
*output
)
690 TSS_HCONTEXT hContext
;
693 u_int32_t pcr_length
;
694 chunk_t pcr_value
= chunk_empty
;
696 result
= Tspi_Context_Create(&hContext
);
697 if (result
!= TSS_SUCCESS
)
699 DBG1(DBG_PTS
, "TPM context could not be created: tss error 0x%x",
703 result
= Tspi_Context_Connect(hContext
, NULL
);
704 if (result
!= TSS_SUCCESS
)
708 result
= Tspi_Context_GetTpmObject (hContext
, &hTPM
);
709 if (result
!= TSS_SUCCESS
)
714 pcr_value
= chunk_alloc(PTS_PCR_LEN
);
715 result
= Tspi_TPM_PcrExtend(hTPM
, pcr_num
, PTS_PCR_LEN
, input
.ptr
,
716 NULL
, &pcr_length
, &pcr_value
.ptr
);
717 if (result
!= TSS_SUCCESS
)
723 *output
= chunk_clone(*output
);
725 DBG3(DBG_PTS
, "PCR %d extended with: %B", pcr_num
, &input
);
726 DBG3(DBG_PTS
, "PCR %d value after extend: %B", pcr_num
, output
);
728 chunk_clear(&pcr_value
);
729 Tspi_Context_FreeMemory(hContext
, NULL
);
730 Tspi_Context_Close(hContext
);
735 DBG1(DBG_PTS
, "TPM not available: tss error 0x%x", result
);
737 chunk_clear(&pcr_value
);
738 Tspi_Context_FreeMemory(hContext
, NULL
);
739 Tspi_Context_Close(hContext
);
744 METHOD(pts_t
, quote_tpm
, bool,
745 private_pts_t
*this, bool use_quote2
, chunk_t
*pcr_comp
, chunk_t
*quote_sig
)
747 TSS_HCONTEXT hContext
;
751 TSS_HPOLICY srkUsagePolicy
;
752 TSS_UUID SRK_UUID
= TSS_UUID_SRK
;
753 BYTE secret
[] = TSS_WELL_KNOWN_SECRET
;
754 TSS_HPCRS hPcrComposite
;
755 TSS_VALIDATION valData
;
759 u_int32_t versionInfoSize
, pcr
;
760 enumerator_t
*enumerator
;
761 bool success
= FALSE
;
763 result
= Tspi_Context_Create(&hContext
);
764 if (result
!= TSS_SUCCESS
)
766 DBG1(DBG_PTS
, "TPM context could not be created: tss error 0x%x",
770 result
= Tspi_Context_Connect(hContext
, NULL
);
771 if (result
!= TSS_SUCCESS
)
775 result
= Tspi_Context_GetTpmObject (hContext
, &hTPM
);
776 if (result
!= TSS_SUCCESS
)
781 /* Retrieve SRK from TPM and set the authentication to well known secret*/
782 result
= Tspi_Context_LoadKeyByUUID(hContext
, TSS_PS_TYPE_SYSTEM
,
784 if (result
!= TSS_SUCCESS
)
789 result
= Tspi_GetPolicyObject(hSRK
, TSS_POLICY_USAGE
, &srkUsagePolicy
);
790 if (result
!= TSS_SUCCESS
)
794 result
= Tspi_Policy_SetSecret(srkUsagePolicy
, TSS_SECRET_MODE_SHA1
,
796 if (result
!= TSS_SUCCESS
)
801 result
= Tspi_Context_LoadKeyByBlob (hContext
, hSRK
, this->aik_blob
.len
,
802 this->aik_blob
.ptr
, &hAIK
);
803 if (result
!= TSS_SUCCESS
)
808 /* Create PCR composite object */
809 result
= use_quote2 ?
810 Tspi_Context_CreateObject(hContext
, TSS_OBJECT_TYPE_PCRS
,
811 TSS_PCRS_STRUCT_INFO_SHORT
, &hPcrComposite
) :
812 Tspi_Context_CreateObject(hContext
, TSS_OBJECT_TYPE_PCRS
,
813 TSS_PCRS_STRUCT_DEFAULT
, &hPcrComposite
);
814 if (result
!= TSS_SUCCESS
)
820 enumerator
= this->pcrs
->create_enumerator(this->pcrs
);
821 while (enumerator
->enumerate(enumerator
, &pcr
))
823 result
= use_quote2 ?
824 Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite
, pcr
,
825 TSS_PCRS_DIRECTION_RELEASE
) :
826 Tspi_PcrComposite_SelectPcrIndex(hPcrComposite
, pcr
);
827 if (result
!= TSS_SUCCESS
)
832 enumerator
->destroy(enumerator
);
834 if (result
!= TSS_SUCCESS
)
839 /* Set the Validation Data */
840 valData
.ulExternalDataLength
= this->secret
.len
;
841 valData
.rgbExternalData
= (BYTE
*)this->secret
.ptr
;
845 result
= use_quote2 ?
846 Tspi_TPM_Quote2(hTPM
, hAIK
, FALSE
, hPcrComposite
, &valData
,
847 &versionInfoSize
, &versionInfo
):
848 Tspi_TPM_Quote(hTPM
, hAIK
, hPcrComposite
, &valData
);
849 if (result
!= TSS_SUCCESS
)
854 /* Set output chunks */
855 *pcr_comp
= chunk_alloc(HASH_SIZE_SHA1
);
859 /* TPM_Composite_Hash is last 20 bytes of TPM_Quote_Info2 structure */
860 memcpy(pcr_comp
->ptr
, valData
.rgbData
+ valData
.ulDataLength
- HASH_SIZE_SHA1
,
865 /* TPM_Composite_Hash is 8-28th bytes of TPM_Quote_Info structure */
866 memcpy(pcr_comp
->ptr
, valData
.rgbData
+ 8, HASH_SIZE_SHA1
);
868 DBG3(DBG_PTS
, "Hash of PCR Composite: %#B", pcr_comp
);
870 quote_info
= chunk_create(valData
.rgbData
, valData
.ulDataLength
);
871 DBG3(DBG_PTS
, "TPM Quote Info: %B","e_info
);
873 *quote_sig
= chunk_clone(chunk_create(valData
.rgbValidationData
,
874 valData
.ulValidationDataLength
));
875 DBG3(DBG_PTS
, "TPM Quote Signature: %B",quote_sig
);
881 Tspi_Context_FreeMemory(hContext
, NULL
);
884 Tspi_Context_CloseObject(hContext
, hPcrComposite
);
887 Tspi_Context_CloseObject(hContext
, hAIK
);
890 Tspi_Context_Close(hContext
);
893 DBG1(DBG_PTS
, "TPM not available: tss error 0x%x", result
);
898 #else /* TSS_TROUSERS */
900 METHOD(pts_t
, read_pcr
, bool,
901 private_pts_t
*this, u_int32_t pcr_num
, chunk_t
*pcr_value
)
906 METHOD(pts_t
, extend_pcr
, bool,
907 private_pts_t
*this, u_int32_t pcr_num
, chunk_t input
, chunk_t
*output
)
912 METHOD(pts_t
, quote_tpm
, bool,
913 private_pts_t
*this, bool use_quote2
, chunk_t
*pcr_comp
, chunk_t
*quote_sig
)
918 #endif /* TSS_TROUSERS */
921 * TPM_QUOTE_INFO structure:
923 * 4 bytes 'Q' 'U' 'O' 'T'
924 * 20 byte SHA1 of TCPA_PCR_COMPOSITE
927 * TPM_QUOTE_INFO2 structure:
928 * 2 bytes Tag 0x0036 TPM_Tag_Quote_info2
929 * 4 bytes 'Q' 'U' 'T' '2'
931 * 26 bytes PCR_INFO_SHORT
934 METHOD(pts_t
, get_quote_info
, bool,
935 private_pts_t
*this, bool use_quote2
, bool use_ver_info
,
936 pts_meas_algorithms_t comp_hash_algo
,
937 chunk_t
*out_pcr_comp
, chunk_t
*out_quote_info
)
939 chunk_t selection
, pcr_comp
, hash_pcr_comp
;
940 bio_writer_t
*writer
;
943 if (!this->pcrs
->get_count(this->pcrs
))
945 DBG1(DBG_PTS
, "No extended PCR entries available, "
946 "unable to construct TPM Quote Info");
949 if (!this->secret
.ptr
)
951 DBG1(DBG_PTS
, "Secret assessment value unavailable, ",
952 "unable to construct TPM Quote Info");
955 if (use_quote2
&& use_ver_info
&& !this->tpm_version_info
.ptr
)
957 DBG1(DBG_PTS
, "TPM Version Information unavailable, ",
958 "unable to construct TPM Quote Info2");
962 pcr_comp
= this->pcrs
->get_composite(this->pcrs
);
965 /* Output the TPM_PCR_COMPOSITE expected from IMC */
968 hash_algorithm_t algo
;
970 algo
= pts_meas_algo_to_hash(comp_hash_algo
);
971 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, algo
);
973 /* Hash the PCR Composite Structure */
974 if (!hasher
|| !hasher
->allocate_hash(hasher
, pcr_comp
, out_pcr_comp
))
980 DBG3(DBG_PTS
, "constructed PCR Composite hash: %#B", out_pcr_comp
);
981 hasher
->destroy(hasher
);
985 *out_pcr_comp
= chunk_clone(pcr_comp
);
988 /* SHA1 hash of PCR Composite to construct TPM_QUOTE_INFO */
989 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
990 if (!hasher
|| !hasher
->allocate_hash(hasher
, pcr_comp
, &hash_pcr_comp
))
993 chunk_free(out_pcr_comp
);
997 hasher
->destroy(hasher
);
999 /* Construct TPM_QUOTE_INFO/TPM_QUOTE_INFO2 structure */
1000 writer
= bio_writer_create(TPM_QUOTE_INFO_LEN
);
1004 /* TPM Structure Tag */
1005 writer
->write_uint16(writer
, TPM_TAG_QUOTE_INFO2
);
1007 /* Magic QUT2 value */
1008 writer
->write_data(writer
, chunk_create("QUT2", 4));
1010 /* Secret assessment value 20 bytes (nonce) */
1011 writer
->write_data(writer
, this->secret
);
1014 selection
.ptr
= pcr_comp
.ptr
;
1015 selection
.len
= 2 + this->pcrs
->get_selection_size(this->pcrs
);
1016 writer
->write_data(writer
, selection
);
1018 /* TPM Locality Selection */
1019 writer
->write_uint8(writer
, TPM_LOC_ZERO
);
1021 /* PCR Composite Hash */
1022 writer
->write_data(writer
, hash_pcr_comp
);
1026 /* TPM version Info */
1027 writer
->write_data(writer
, this->tpm_version_info
);
1032 /* Version number */
1033 writer
->write_data(writer
, chunk_from_chars(1, 1, 0, 0));
1035 /* Magic QUOT value */
1036 writer
->write_data(writer
, chunk_create("QUOT", 4));
1038 /* PCR Composite Hash */
1039 writer
->write_data(writer
, hash_pcr_comp
);
1041 /* Secret assessment value 20 bytes (nonce) */
1042 writer
->write_data(writer
, this->secret
);
1045 /* TPM Quote Info */
1046 *out_quote_info
= writer
->extract_buf(writer
);
1047 DBG3(DBG_PTS
, "constructed TPM Quote Info: %B", out_quote_info
);
1049 writer
->destroy(writer
);
1051 free(hash_pcr_comp
.ptr
);
1056 METHOD(pts_t
, verify_quote_signature
, bool,
1057 private_pts_t
*this, chunk_t data
, chunk_t signature
)
1059 public_key_t
*aik_pub_key
;
1061 aik_pub_key
= this->aik
->get_public_key(this->aik
);
1064 DBG1(DBG_PTS
, "failed to get public key from AIK certificate");
1068 if (!aik_pub_key
->verify(aik_pub_key
, SIGN_RSA_EMSA_PKCS1_SHA1
,
1071 DBG1(DBG_PTS
, "signature verification failed for TPM Quote Info");
1072 DESTROY_IF(aik_pub_key
);
1076 aik_pub_key
->destroy(aik_pub_key
);
1080 METHOD(pts_t
, get_pcrs
, pts_pcr_t
*,
1081 private_pts_t
*this)
1086 METHOD(pts_t
, destroy
, void,
1087 private_pts_t
*this)
1089 DESTROY_IF(this->pcrs
);
1090 DESTROY_IF(this->aik
);
1091 DESTROY_IF(this->dh
);
1092 free(this->initiator_nonce
.ptr
);
1093 free(this->responder_nonce
.ptr
);
1094 free(this->secret
.ptr
);
1095 free(this->platform_info
);
1096 free(this->aik_blob
.ptr
);
1097 free(this->tpm_version_info
.ptr
);
1105 * Check for a TPM by querying for TPM Version Info
1107 static bool has_tpm(private_pts_t
*this)
1109 TSS_HCONTEXT hContext
;
1112 u_int32_t version_info_len
;
1114 result
= Tspi_Context_Create(&hContext
);
1115 if (result
!= TSS_SUCCESS
)
1117 DBG1(DBG_PTS
, "TPM context could not be created: tss error 0x%x",
1121 result
= Tspi_Context_Connect(hContext
, NULL
);
1122 if (result
!= TSS_SUCCESS
)
1126 result
= Tspi_Context_GetTpmObject (hContext
, &hTPM
);
1127 if (result
!= TSS_SUCCESS
)
1131 result
= Tspi_TPM_GetCapability(hTPM
, TSS_TPMCAP_VERSION_VAL
, 0, NULL
,
1133 &this->tpm_version_info
.ptr
);
1134 this->tpm_version_info
.len
= version_info_len
;
1135 if (result
!= TSS_SUCCESS
)
1139 this->tpm_version_info
= chunk_clone(this->tpm_version_info
);
1141 Tspi_Context_FreeMemory(hContext
, NULL
);
1142 Tspi_Context_Close(hContext
);
1146 DBG1(DBG_PTS
, "TPM not available: tss error 0x%x", result
);
1147 Tspi_Context_FreeMemory(hContext
, NULL
);
1148 Tspi_Context_Close(hContext
);
1152 #else /* TSS_TROUSERS */
1154 static bool has_tpm(private_pts_t
*this)
1159 #endif /* TSS_TROUSERS */
1165 pts_t
*pts_create(bool is_imc
)
1167 private_pts_t
*this;
1170 pcrs
= pts_pcr_create();
1173 DBG1(DBG_PTS
, "shadow PCR set could not be created");
1179 .get_proto_caps
= _get_proto_caps
,
1180 .set_proto_caps
= _set_proto_caps
,
1181 .get_meas_algorithm
= _get_meas_algorithm
,
1182 .set_meas_algorithm
= _set_meas_algorithm
,
1183 .get_dh_hash_algorithm
= _get_dh_hash_algorithm
,
1184 .set_dh_hash_algorithm
= _set_dh_hash_algorithm
,
1185 .create_dh_nonce
= _create_dh_nonce
,
1186 .get_my_public_value
= _get_my_public_value
,
1187 .set_peer_public_value
= _set_peer_public_value
,
1188 .calculate_secret
= _calculate_secret
,
1189 .get_platform_info
= _get_platform_info
,
1190 .set_platform_info
= _set_platform_info
,
1191 .get_tpm_version_info
= _get_tpm_version_info
,
1192 .set_tpm_version_info
= _set_tpm_version_info
,
1193 .get_aik
= _get_aik
,
1194 .set_aik
= _set_aik
,
1195 .get_aik_keyid
= _get_aik_keyid
,
1196 .is_path_valid
= _is_path_valid
,
1197 .get_metadata
= _get_metadata
,
1198 .read_pcr
= _read_pcr
,
1199 .extend_pcr
= _extend_pcr
,
1200 .quote_tpm
= _quote_tpm
,
1201 .get_pcrs
= _get_pcrs
,
1202 .get_quote_info
= _get_quote_info
,
1203 .verify_quote_signature
= _verify_quote_signature
,
1204 .destroy
= _destroy
,
1207 .proto_caps
= PTS_PROTO_CAPS_V
,
1208 .algorithm
= PTS_MEAS_ALGO_SHA256
,
1209 .dh_hash_algorithm
= PTS_MEAS_ALGO_SHA256
,
1217 this->has_tpm
= TRUE
;
1218 this->proto_caps
|= PTS_PROTO_CAPS_T
| PTS_PROTO_CAPS_D
;
1220 load_aik_blob(this);
1225 this->proto_caps
|= PTS_PROTO_CAPS_T
| PTS_PROTO_CAPS_D
;
1228 return &this->public;