From 3d58c70c6ae8b9d1240e50f653d8c929835f3868 Mon Sep 17 00:00:00 2001 From: Tom D <40675700+twitchy-jsonp@users.noreply.github.com> Date: Thu, 8 Aug 2019 11:31:09 +1000 Subject: [PATCH] Add firmware version to TPMInfo for TPM 2.0 devices. (#67) --- attest/attest.go | 6 ++++++ attest/tpm.go | 38 ++++++++++++++++++++++++++++++-------- attest/tpm_linux.go | 23 +++++++++++++---------- attest/tpm_windows.go | 24 +++++++++++++----------- 4 files changed, 62 insertions(+), 29 deletions(-) diff --git a/attest/attest.go b/attest/attest.go index 7edaee3..994987a 100644 --- a/attest/attest.go +++ b/attest/attest.go @@ -274,6 +274,12 @@ type TPMInfo struct { Interface TPMInterface VendorInfo string Manufacturer TCGVendorID + + // FirmwareVersionMajor and FirmwareVersionMinor describe + // the firmware version of the TPM, but are only available + // for TPM 2.0 devices. + FirmwareVersionMajor int + FirmwareVersionMinor int } // probedTPM identifies a TPM device on the system, which diff --git a/attest/tpm.go b/attest/tpm.go index d84bdb1..2cf82bb 100644 --- a/attest/tpm.go +++ b/attest/tpm.go @@ -30,8 +30,9 @@ import ( ) const ( - tpmPtManufacturer = 0x00000100 + 5 // PT_FIXED + offset of 5 - tpmPtVendorString = 0x00000100 + 6 // PT_FIXED + offset of 6 + tpmPtManufacturer = 0x00000100 + 5 // PT_FIXED + offset of 5 + tpmPtVendorString = 0x00000100 + 6 // PT_FIXED + offset of 6 + tpmPtFwVersion1 = 0x00000100 + 11 // PT_FIXED + offset of 11 // Defined in "Registry of reserved TPM 2.0 handles and localities". nvramCertIndex = 0x1c00002 @@ -95,7 +96,14 @@ var ( } ) -func readTPM2VendorAttributes(tpm io.ReadWriter) (TCGVendorID, string, error) { +type tpm20Info struct { + vendor string + manufacturer TCGVendorID + fwMajor int + fwMinor int +} + +func readTPM2VendorAttributes(tpm io.ReadWriter) (tpm20Info, error) { var vendorInfo string // The Vendor String is split up into 4 sections of 4 bytes, // for a maximum length of 16 octets of ASCII text. We iterate @@ -104,11 +112,11 @@ func readTPM2VendorAttributes(tpm io.ReadWriter) (TCGVendorID, string, error) { for i := 0; i < 4; i++ { caps, _, err := tpm2.GetCapability(tpm, tpm2.CapabilityTPMProperties, 1, tpmPtVendorString+uint32(i)) if err != nil { - return TCGVendorID(0), "", fmt.Errorf("tpm2.GetCapability(PT_VENDOR_STRING_%d) failed: %v", i+1, err) + return tpm20Info{}, fmt.Errorf("tpm2.GetCapability(PT_VENDOR_STRING_%d) failed: %v", i+1, err) } subset, ok := caps[0].(tpm2.TaggedProperty) if !ok { - return TCGVendorID(0), "", fmt.Errorf("got capability of type %T, want tpm2.TaggedProperty", caps[0]) + return tpm20Info{}, fmt.Errorf("got capability of type %T, want tpm2.TaggedProperty", caps[0]) } // Reconstruct the 4 ASCII octets from the uint32 value. vendorInfo += string(subset.Value&0xFF000000) + string(subset.Value&0xFF0000) + string(subset.Value&0xFF00) + string(subset.Value&0xFF) @@ -116,14 +124,28 @@ func readTPM2VendorAttributes(tpm io.ReadWriter) (TCGVendorID, string, error) { caps, _, err := tpm2.GetCapability(tpm, tpm2.CapabilityTPMProperties, 1, tpmPtManufacturer) if err != nil { - return TCGVendorID(0), "", fmt.Errorf("tpm2.GetCapability(PT_MANUFACTURER) failed: %v", err) + return tpm20Info{}, fmt.Errorf("tpm2.GetCapability(PT_MANUFACTURER) failed: %v", err) } manu, ok := caps[0].(tpm2.TaggedProperty) if !ok { - return TCGVendorID(0), "", fmt.Errorf("got capability of type %T, want tpm2.TaggedProperty", caps[0]) + return tpm20Info{}, fmt.Errorf("got capability of type %T, want tpm2.TaggedProperty", caps[0]) } - return TCGVendorID(manu.Value), strings.Trim(vendorInfo, "\x00"), nil + caps, _, err = tpm2.GetCapability(tpm, tpm2.CapabilityTPMProperties, 1, tpmPtFwVersion1) + if err != nil { + return tpm20Info{}, fmt.Errorf("tpm2.GetCapability(PT_FIRMWARE_VERSION_1) failed: %v", err) + } + fw, ok := caps[0].(tpm2.TaggedProperty) + if !ok { + return tpm20Info{}, fmt.Errorf("got capability of type %T, want tpm2.TaggedProperty", caps[0]) + } + + return tpm20Info{ + vendor: strings.Trim(vendorInfo, "\x00"), + manufacturer: TCGVendorID(manu.Value), + fwMajor: int((fw.Value & 0xffff0000) >> 16), + fwMinor: int(fw.Value & 0x0000ffff), + }, nil } func parseCert(ekCert []byte) (*x509.Certificate, error) { diff --git a/attest/tpm_linux.go b/attest/tpm_linux.go index f3100bd..a98a9ae 100644 --- a/attest/tpm_linux.go +++ b/attest/tpm_linux.go @@ -163,14 +163,22 @@ func readTPM12VendorAttributes(context *tspi.Context) (TCGVendorID, string, erro // Info returns information about the TPM. func (t *TPM) Info() (*TPMInfo, error) { - var manufacturer TCGVendorID - var vendorInfo string + tInfo := TPMInfo{ + Version: t.version, + Interface: t.interf, + } + var err error switch t.version { case TPMVersion12: - manufacturer, vendorInfo, err = readTPM12VendorAttributes(t.ctx) + tInfo.Manufacturer, tInfo.VendorInfo, err = readTPM12VendorAttributes(t.ctx) case TPMVersion20: - manufacturer, vendorInfo, err = readTPM2VendorAttributes(t.rwc) + var t2Info tpm20Info + t2Info, err = readTPM2VendorAttributes(t.rwc) + tInfo.Manufacturer = t2Info.manufacturer + tInfo.VendorInfo = t2Info.vendor + tInfo.FirmwareVersionMajor = t2Info.fwMajor + tInfo.FirmwareVersionMinor = t2Info.fwMinor default: return nil, fmt.Errorf("unsupported TPM version: %x", t.version) } @@ -178,12 +186,7 @@ func (t *TPM) Info() (*TPMInfo, error) { return nil, err } - return &TPMInfo{ - Version: t.version, - Interface: t.interf, - VendorInfo: vendorInfo, - Manufacturer: manufacturer, - }, nil + return &tInfo, nil } // Return value: handle, whether we generated a new one, error diff --git a/attest/tpm_windows.go b/attest/tpm_windows.go index fdfc54a..2f8b6ec 100644 --- a/attest/tpm_windows.go +++ b/attest/tpm_windows.go @@ -123,18 +123,25 @@ func readTPM12VendorAttributes(tpm io.ReadWriter) (TCGVendorID, string, error) { // Info returns information about the TPM. func (t *TPM) Info() (*TPMInfo, error) { - var manufacturer TCGVendorID - var vendorInfo string - var err error + tInfo := TPMInfo{ + Version: t.version, + Interface: TPMInterfaceKernelManaged, + } tpm, err := t.pcp.TPMCommandInterface() if err != nil { return nil, err } + switch t.version { case TPMVersion12: - manufacturer, vendorInfo, err = readTPM12VendorAttributes(tpm) + tInfo.Manufacturer, tInfo.VendorInfo, err = readTPM12VendorAttributes(tpm) case TPMVersion20: - manufacturer, vendorInfo, err = readTPM2VendorAttributes(tpm) + var t2Info tpm20Info + t2Info, err = readTPM2VendorAttributes(tpm) + tInfo.Manufacturer = t2Info.manufacturer + tInfo.VendorInfo = t2Info.vendor + tInfo.FirmwareVersionMajor = t2Info.fwMajor + tInfo.FirmwareVersionMinor = t2Info.fwMinor default: return nil, fmt.Errorf("unsupported TPM version: %x", t.version) } @@ -142,12 +149,7 @@ func (t *TPM) Info() (*TPMInfo, error) { return nil, err } - return &TPMInfo{ - Version: t.version, - Interface: TPMInterfaceKernelManaged, - VendorInfo: vendorInfo, - Manufacturer: manufacturer, - }, nil + return &tInfo, nil } // EKs returns the Endorsement Keys burned-in to the platform.