Skip to content

Commit b577aaa

Browse files
committed
security/intel/cbnt/measurement.c: support MTL and newer
Differences from the previous way of measurements: - must log CRTM version to PCR-0 - must log IBB hash (as is, provided in BPM)to PCR-0 - need to extend PCR-0 with POLICY_DATA which is a subset of PCR0_DATA from the original ("conventional") way Half of the changes is just moving things into if-statement. Upstream-Status: Pending Change-Id: Icc101aa03db99a741c3b7142aa00d42ec6569ae9 Signed-off-by: Sergii Dmytruk <[email protected]>
1 parent fbf6fcc commit b577aaa

File tree

1 file changed

+157
-53
lines changed

1 file changed

+157
-53
lines changed

src/security/intel/cbnt/measurement.c

Lines changed: 157 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@
3838
#define KM_HASH_USAGE_SDEV (1 << 3)
3939
#define KM_HASH_USAGE_PFR_CPLD (1 << 4)
4040

41+
/*
42+
* SRTM version is an upper-case hex dump of ACM's "Date" (offset 20) and "TXT SVN" (offset 28)
43+
* fields as a NUL-terminated UTF16 string.
44+
*/
45+
#define SCRTM_VERSION_LENGTH 13
46+
4147
/*
4248
* Definitions of the structures come from Intel document #575623 CBnT BWG v1.2.5 ("Intel
4349
* Converged Boot Guard and Intel Trusted Execution Technology (Intel TXT) BIOS Specification").
@@ -179,7 +185,8 @@ static const void *find_in_fit(uint8_t type, size_t *size)
179185
return addr;
180186
}
181187

182-
static enum cb_err get_ibbs_flags(bool *auth_measure, uint64_t *biosacm_sts_mask)
188+
static enum cb_err get_flags(bool *conventional_measurements, bool *auth_measure,
189+
uint64_t *biosacm_sts_mask)
183190
{
184191
size_t bpm_len;
185192
const struct bpm_header *bpm = find_in_fit(FIT_ENTRY_TYPE_BPM, &bpm_len);
@@ -188,6 +195,11 @@ static enum cb_err get_ibbs_flags(bool *auth_measure, uint64_t *biosacm_sts_mask
188195
return CB_ERR;
189196
}
190197

198+
/* Meteor Lake seems to be the first generation with new (more TCG-like) style of
199+
measurements. */
200+
*conventional_measurements = !CONFIG(SOC_INTEL_METEORLAKE)
201+
&& !CONFIG(SOC_INTEL_PANTHERLAKE_BASE);
202+
191203
const struct bpm_ibbs *ibbs = (const void *)bpm->se_element;
192204
*auth_measure = (ibbs->flags & BPM_IBBS_FLAG_AUTH_MEASURE) != 0;
193205
*biosacm_sts_mask =
@@ -613,6 +625,13 @@ static enum cb_err cap_pcrs(union cbnt_biosacm_policy biosacm_sts)
613625
return CB_SUCCESS;
614626
}
615627

628+
static char hex_digit(int nibble)
629+
{
630+
if (nibble < 10)
631+
return '0' + nibble;
632+
return 'A' + nibble - 10;
633+
}
634+
616635
void intel_cbnt_inject_ibg_measurements(void)
617636
{
618637
const union cbnt_biosacm_policy biosacm_sts = {
@@ -639,25 +658,11 @@ void intel_cbnt_inject_ibg_measurements(void)
639658
return;
640659
}
641660

642-
/*
643-
* Making and hashing PCR-0 data.
644-
*
645-
* Pseudo-code of the data to be measured into PCR-0 for TigerLake and newer (older
646-
* hardware isn't supported yet):
647-
*
648-
* struct {
649-
* uint64_t ACM_POLICY_STATUS;
650-
* uint16_t ACM.Header.SVN;
651-
* uint8_t ACM.Signature[ACM signature size];
652-
* uint8_t KM.Signature[KM signature size];
653-
* uint8_t BPM.Signature[BPM signature size];
654-
* uint8_t IBB.Digest[IBB digest size];
655-
* } PCR0_DATA;
656-
*/
657-
661+
bool conventional_measurements;
658662
bool auth_measure;
659663
uint64_t biosacm_sts_mask;
660-
if (get_ibbs_flags(&auth_measure, &biosacm_sts_mask) != CB_SUCCESS) {
664+
if (get_flags(&conventional_measurements, &auth_measure, &biosacm_sts_mask) !=
665+
CB_SUCCESS) {
661666
printk(BIOS_ERR, "CBnT: failed to obtain IBBS flags from BPM\n");
662667
return;
663668
}
@@ -671,52 +676,151 @@ void intel_cbnt_inject_ibg_measurements(void)
671676
struct obuf data_ob;
672677
obuf_init(&data_ob, data, sizeof(data));
673678

674-
/* ACM_POLICY_STATUS (won't run out of space on this one) */
675-
(void)obuf_write_le64(&data_ob, biosacm_sts.raw & biosacm_sts_mask);
679+
if (conventional_measurements) {
680+
/*
681+
* Making and hashing PCR-0 data.
682+
*
683+
* Pseudo-code of the data to be measured into PCR-0 for TigerLake and newer
684+
* (older hardware isn't supported yet):
685+
*
686+
* struct {
687+
* uint64_t ACM_POLICY_STATUS;
688+
* uint16_t ACM.Header.SVN;
689+
* uint8_t ACM.Signature[ACM signature size];
690+
* uint8_t KM.Signature[KM signature size];
691+
* uint8_t BPM.Signature[BPM signature size];
692+
* uint8_t IBB.Digest[IBB digest size];
693+
* } PCR0_DATA;
694+
*/
695+
696+
/* ACM_POLICY_STATUS (won't run out of space on this one) */
697+
(void)obuf_write_le64(&data_ob, biosacm_sts.raw & biosacm_sts_mask);
698+
699+
if (fill_pcr0_acm_fields(&data_ob) != CB_SUCCESS) {
700+
printk(BIOS_ERR,
701+
"CBnT: failed to fill ACM fields of PCR-0 measurement data\n");
702+
return;
703+
}
676704

677-
if (fill_pcr0_acm_fields(&data_ob) != CB_SUCCESS) {
678-
printk(BIOS_ERR, "CBnT: failed to fill ACM fields of PCR-0 measurement data\n");
679-
return;
680-
}
705+
if (copy_km_signature(&data_ob) != CB_SUCCESS) {
706+
printk(BIOS_ERR,
707+
"CBnT: failed to copy KM signature for PCR-0 measurement\n");
708+
return;
709+
}
681710

682-
if (copy_km_signature(&data_ob) != CB_SUCCESS) {
683-
printk(BIOS_ERR, "CBnT: failed to copy KM signature for PCR-0 measurement\n");
684-
return;
685-
}
711+
if (copy_bpm_signature(&data_ob) != CB_SUCCESS) {
712+
printk(BIOS_ERR,
713+
"CBnT: failed to copy BPM signature for PCR-0 measurement\n");
714+
return;
715+
}
686716

687-
if (copy_bpm_signature(&data_ob) != CB_SUCCESS) {
688-
printk(BIOS_ERR, "CBnT: failed to copy BPM signature for PCR-0 measurement\n");
689-
return;
690-
}
717+
struct vb2_hash hash;
718+
if (vb2_hash_calculate(vboot_hwcrypto_allowed(), data,
719+
obuf_nr_written(&data_ob), tpm_log_alg(), &hash)) {
720+
printk(BIOS_ERR, "CBnT: failed to hash PCR-0 measurement data\n");
721+
return;
722+
}
691723

692-
struct vb2_hash hash;
693-
if (vb2_hash_calculate(vboot_hwcrypto_allowed(), data, obuf_nr_written(&data_ob),
694-
tpm_log_alg(), &hash)) {
695-
printk(BIOS_ERR, "CBnT: failed to hash PCR-0 measurement data\n");
696-
return;
697-
}
724+
/* Per BWG this should be logged with EV_S_CRTM_CONTENTS type. */
725+
tpm_log_add_table_entry(CBNT_EVENT_LOG_MESSAGE, 0, hash.algo, hash.raw,
726+
vb2_digest_size(hash.algo));
698727

699-
/* Per BWG this should be logged with EV_S_CRTM_CONTENTS type. */
700-
tpm_log_add_table_entry(CBNT_EVENT_LOG_MESSAGE, 0, hash.algo, hash.raw,
701-
vb2_digest_size(hash.algo));
728+
/* Optionally making and hashing PCR-7 data (not supported since MTL). */
729+
if (auth_measure) {
730+
/* Reuse the first 2 fields of PCR-0 data which are identical in both
731+
cases. */
732+
obuf_init(&data_ob, data, sizeof(data));
733+
(void)obuf_oob_fill(&data_ob, sizeof(uint64_t) + sizeof(uint16_t));
734+
735+
if (!make_pcr7_hash(&data_ob, &hash)) {
736+
printk(BIOS_ERR,
737+
"CBnT: failed to build and hash PCR-7 measurement data\n");
738+
return;
739+
}
740+
741+
/* Per BWG this should be logged with EV_EFI_VARIABLE_DRIVER_CONFIG type
742+
and event name should be a Unicode string. */
743+
tpm_log_add_table_entry(CBNT_EVENT_LOG_MESSAGE, 7, hash.algo, hash.raw,
744+
vb2_digest_size(hash.algo));
745+
printk(BIOS_INFO, "CBnT: reconstructed PCR-7 measurement\n");
746+
}
702747

703-
/* Making and hashing PCR-7 data. */
704-
if (auth_measure) {
705-
/* Reuse the first 2 fields of PCR-0 data which are identical in both cases. */
748+
} else {
749+
size_t acm_len;
750+
const struct acm_header_v3 *acm = find_in_fit(FIT_ENTRY_TYPE_SACM, &acm_len);
751+
if (acm == NULL) {
752+
printk(BIOS_ERR, "CBnT: failed to find SACM\n");
753+
return;
754+
}
755+
756+
uint8_t crtm_version[6];
757+
memcpy(&crtm_version[0], &acm->date, 4);
758+
memcpy(&crtm_version[4], &acm->txt_svn, 2);
759+
760+
char crtm_version_str[SCRTM_VERSION_LENGTH] = {0};
761+
uint16_t crtm_version_utf16[SCRTM_VERSION_LENGTH] = {0};
762+
for (int i = 0; i < sizeof(crtm_version); ++i) {
763+
crtm_version_str[i*2 + 0] = hex_digit(crtm_version[i] >> 4);
764+
crtm_version_str[i*2 + 1] = hex_digit(crtm_version[i] & 0xf);
765+
766+
crtm_version_utf16[i*2 + 0] = crtm_version_str[i*2 + 0];
767+
crtm_version_utf16[i*2 + 1] = crtm_version_str[i*2 + 1];
768+
}
769+
770+
struct vb2_hash hash;
771+
if (vb2_hash_calculate(vboot_hwcrypto_allowed(), crtm_version_utf16,
772+
sizeof(crtm_version_utf16), tpm_log_alg(), &hash)) {
773+
printk(BIOS_ERR, "CBnT: failed to hash CRTM version\n");
774+
return;
775+
}
776+
/* Per BWG this should be logged with EV_S_CRTM_VERSION type. */
777+
tpm_log_add_table_entry(crtm_version_str, 0, hash.algo, hash.raw,
778+
vb2_digest_size(hash.algo));
779+
780+
if (copy_ibb_hash(&data_ob, tpm2_alg_from_vb2_hash(tpm_log_alg())) !=
781+
CB_SUCCESS) {
782+
printk(BIOS_ERR, "CBnT: failed to obtain IBB digest\n");
783+
return;
784+
}
785+
/* Per BWG this should be logged with EV_POST_CODE type. */
786+
tpm_log_add_table_entry("Boot Guard Measured IBB", 0, tpm_log_alg(), data,
787+
obuf_nr_written(&data_ob));
788+
789+
/*
790+
* struct {
791+
* uint64_t ACM_POLICY_STATUS;
792+
* uint8_t KM.Signature[KM signature size];
793+
* uint8_t BPM.Signature[BPM signature size];
794+
* } POLICY_DATA;
795+
*/
706796
obuf_init(&data_ob, data, sizeof(data));
707-
(void)obuf_oob_fill(&data_ob, sizeof(uint64_t) + sizeof(uint16_t));
708797

709-
if (!make_pcr7_hash(&data_ob, &hash)) {
798+
/* ACM_POLICY_STATUS (won't run out of space on this one) */
799+
(void)obuf_write_le64(&data_ob, biosacm_sts.raw & biosacm_sts_mask);
800+
if (copy_acm_signature(&data_ob) != CB_SUCCESS) {
801+
printk(BIOS_ERR, "CBnT: failed to copy ACM signature\n");
802+
return;
803+
}
804+
if (copy_km_signature(&data_ob) != CB_SUCCESS) {
805+
printk(BIOS_ERR, "CBnT: failed to copy KM signature\n");
806+
return;
807+
}
808+
if (copy_bpm_signature(&data_ob) != CB_SUCCESS) {
710809
printk(BIOS_ERR,
711-
"CBnT: failed to build and hash PCR-7 measurement data\n");
810+
"CBnT: failed to copy BPM signature for PCR-0 measurement\n");
811+
return;
812+
}
813+
if (vb2_hash_calculate(vboot_hwcrypto_allowed(), data,
814+
obuf_nr_written(&data_ob), tpm_log_alg(), &hash)) {
815+
printk(BIOS_ERR, "CBnT: failed to hash POLICY_DATA\n");
816+
return;
817+
}
818+
/* Per BWG this should be logged with EV_POST_CODE type. */
819+
if (tpm_extend_pcr(0, hash.algo, hash.raw, vb2_digest_size(hash.algo),
820+
"BIOS Measured Boot Guard Policy") != TPM_SUCCESS) {
821+
printk(BIOS_ERR, "CBnT: failed to extend POLICY_DATA\n");
712822
return;
713823
}
714-
715-
/* Per BWG this should be logged with EV_EFI_VARIABLE_DRIVER_CONFIG type and
716-
event name should be a Unicode string. */
717-
tpm_log_add_table_entry(CBNT_EVENT_LOG_MESSAGE, 7, hash.algo, hash.raw,
718-
vb2_digest_size(hash.algo));
719-
printk(BIOS_INFO, "CBnT: reconstructed PCR-7 measurement\n");
720824
}
721825

722826
/*

0 commit comments

Comments
 (0)