[tpmdd-devel,3/4] Autodetect TCG event log version

Submitted by Petr Vandrovec on March 29, 2017, 7:43 a.m.

Details

Message ID 20170329074328.y5rmk5wh3rj5kgcg@petr-dev3.eng.vmware.com
State New
Headers show

Commit Message

Petr Vandrovec March 29, 2017, 7:43 a.m.
From: Petr Vandrovec <petr@vmware.com>

Code expects that TPM1 devices use TPM1 version of the log,
and TPM2 devices use TPM2 version of the log.  While that
is strongly recommended by the spec, and now required by
Microsoft certification, there are systems that use TPM2
chip with SHA-1 only log.

So let's do detection based on first event in the log -
if it is Spec ID Event03, log is crypto-agile log. otherwise
it is SHA-1 log, or malformed bunch of bytes.

I'm not entirely sure how this works on PPC64: tpm1_eventlog.c
uses do_endian_conversion() on all accesses, while tpm2_eventlog.c
never does conversion.  I'm assuming that it is an ommission
from tpm2_eventlog.c code.  If PPC64 logs are really big-endian
for TPM1 while native-endian for TPM2, let me know, and I'll
modify detection code to handle both native and big endian formats.

Signed-off-by: Petr Vandrovec <petr@vmware.com>
---
 drivers/char/tpm/tpm1_eventlog.c | 53 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 51 insertions(+), 2 deletions(-)

Comments

Jarkko Sakkinen April 5, 2017, 11:40 a.m.
On Wed, Mar 29, 2017 at 12:43:28AM -0700, Petr Vandrovec wrote:
> From: Petr Vandrovec <petr@vmware.com>
> 
> Code expects that TPM1 devices use TPM1 version of the log,
> and TPM2 devices use TPM2 version of the log.  While that
> is strongly recommended by the spec, and now required by
> Microsoft certification, there are systems that use TPM2
> chip with SHA-1 only log.

Do you have example of such system? I don't know any.

> So let's do detection based on first event in the log -
> if it is Spec ID Event03, log is crypto-agile log. otherwise
> it is SHA-1 log, or malformed bunch of bytes.

"Spec ID Event03" is not even english. Why are using it as it was
part of an english sentence? I'm not a native speaker either but
you should at least try to write understandable language.

1. What specification are you talking about?
2. What structure in that specification has this data and what
   is the purpose of that structure?
3. Which field in that structure contains this string value.

/Jarkko

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
Petr Vandrovec April 5, 2017, 8:44 p.m.
Jarkko Sakkinen wrote:
> On Wed, Mar 29, 2017 at 12:43:28AM -0700, Petr Vandrovec wrote:
>> From: Petr Vandrovec<petr@vmware.com>
>>
>> Code expects that TPM1 devices use TPM1 version of the log,
>> and TPM2 devices use TPM2 version of the log.  While that
>> is strongly recommended by the spec, and now required by
>> Microsoft certification, there are systems that use TPM2
>> chip with SHA-1 only log.
>
> Do you have example of such system? I don't know any.

My Dell Inspiron laptop after I upgraded firmware on TPM from TPM1.2 to 
TPM2.0.  I can select that I want to use SHA-256 in the firmware's 
setup, but when I do so TPM PCR registers are updated with both SHA-1 
and SHA-256, while TCG log is TPM1 format, with SHA-1 hashes only.

>> So let's do detection based on first event in the log -
>> if it is Spec ID Event03, log is crypto-agile log. otherwise
>> it is SHA-1 log, or malformed bunch of bytes.
>
> "Spec ID Event03" is not even english. Why are using it as it was
> part of an english sentence? I'm not a native speaker either but
> you should at least try to write understandable language.

"Spec ID Event03" is name of the TPM2 log format.  See for example Table 
15 in 
https://trustedcomputinggroup.org/wp-content/uploads/PC-ClientPlatform_Profile_for_TPM_2p0_Systems_v49_161114_public-review.pdf. 
  I use "Spec ID Event03" to make it clear that I'm talking about 
current version of crypto-agile TPM2 log format, not about earlier versions.

> 1. What specification are you talking about?

PC Client Platform Profile for TPM 2.0 systems.  It is also referenced 
from TPM2's EFI Protocol specification 
(https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-rev13-160330final.pdf) 
Table 3.

> 2. What structure in that specification has this data and what
>     is the purpose of that structure?

It describes format of the log.  If first event in the log is not "Spec 
ID Event03" (see chapter 9.4.5.1 in PC Client platform profile mentioned 
above), then log is not TPM2 log described by current TPM spec, and 
should not be parsed as such (it may be "Spec ID Event02" format, or it 
may be TPM1 log format, as is the case with my Dell box).

> 3. Which field in that structure contains this string value.

Signature.  You can see 
https://drive.google.com/open?id=0B7WL11GSMhrQQ1RCMmRmM2paR3c for TPM2 
log formatted according to the PC Client Platform Profile spec.

							Petr

>
> /Jarkko

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot

Patch hide | download patch | download mbox

diff --git a/drivers/char/tpm/tpm1_eventlog.c b/drivers/char/tpm/tpm1_eventlog.c
index 9a8605e500b5..aafcecf19c48 100644
--- a/drivers/char/tpm/tpm1_eventlog.c
+++ b/drivers/char/tpm/tpm1_eventlog.c
@@ -375,6 +375,51 @@  static int tpm_read_log(struct tpm_chip *chip)
 }
 
 /*
+ * tpm_check_log_version - Check version of the event log.
+ *
+ * Returns 0 if it is TPM1 (SHA1-only) log, 1 if it is TPM2
+ * log.  -EIO if log appears to be malformed.
+ */
+static int tpm_check_log_version(const struct tpm_chip *chip)
+{
+	const struct tcpa_event *event = chip->log.bios_event_log;
+	size_t log_len = chip->log.bios_event_log_end - chip->log.bios_event_log;
+	u32 event_len;
+	const struct tcg_efi_specid_event *specid;
+	u32 num_algs;
+
+	if (log_len < sizeof *event)
+		return -EIO;	/* Too short for anything. */
+	if (do_endian_conversion(event->pcr_index) != 0 ||
+            do_endian_conversion(event->event_type) != NO_ACTION)
+		return 0;	/* Not SpecID.  Must be TPM1 log. */
+	event_len = do_endian_conversion(event->event_size);
+	if (log_len - sizeof *event < event_len)
+		return -EIO;	/* Too short for TPM1 or header event. */
+
+	/*
+	 * Only Spec ID Event03 format is supported for TPM2.
+	 * There was Spec ID Event02 format that did not include
+	 * number of algorithms or digest sizes.  To my knowledge
+	 * there are no systems using that format.
+	 */
+	if (event_len < offsetof(struct tcg_efi_specid_event, digest_sizes))
+		return 0;	/* Too short for SpecID.  Must be TPM1 log. */
+	event_len -= offsetof(struct tcg_efi_specid_event, digest_sizes);
+	specid = (const struct tcg_efi_specid_event *)event->event_data;
+	if (memcmp(specid->signature, "Spec ID Event03", 16))
+		return 0;	/* Not Spec ID Event03, not TPM2. */
+
+	num_algs = do_endian_conversion(specid->num_algs);
+	/* Use division to avoid overflow if num_algs is huge number. */
+	if (event_len / sizeof(struct tcg_efi_specid_event_algs) < num_algs)
+		return -EIO;	/* Too short for digest sizes. */
+
+	/* Looks like TPM2 log. */
+	return 1;
+}
+
+/*
  * tpm_bios_log_setup() - Read the event log from the firmware
  * @chip: TPM chip to use.
  *
@@ -394,6 +439,10 @@  int tpm_bios_log_setup(struct tpm_chip *chip)
 	if (rc)
 		return rc;
 
+	rc = tpm_check_log_version(chip);
+	if (rc < 0)
+		return rc;
+
 	cnt = 0;
 	chip->bios_dir[cnt] = securityfs_create_dir(name, NULL);
 	/* NOTE: securityfs_create_dir can return ENODEV if securityfs is
@@ -404,7 +453,7 @@  int tpm_bios_log_setup(struct tpm_chip *chip)
 	cnt++;
 
 	chip->bin_log_seqops.chip = chip;
-	if (chip->flags & TPM_CHIP_FLAG_TPM2)
+	if (rc != 0)
 		chip->bin_log_seqops.seqops =
 			&tpm2_binary_b_measurements_seqops;
 	else
@@ -421,7 +470,7 @@  int tpm_bios_log_setup(struct tpm_chip *chip)
 		goto err;
 	cnt++;
 
-	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
+	if (rc == 0) {
 
 		chip->ascii_log_seqops.chip = chip;
 		chip->ascii_log_seqops.seqops =