From fc3386f38ca2f98564ddb0950688e54970dab352 Mon Sep 17 00:00:00 2001 From: Jeremias Giesecke Date: Fri, 26 Jan 2024 09:04:26 +0100 Subject: [PATCH] attestationreport, tpmdriver: added support for TPM_PCR_INIT_VALUE The TPM_PCR_INIT_VALUE contains the value that is used to initialize the specific PCR. It is prepended for each PCR specifically Signed-off-by: Jeremias Giesecke --- attestationreport/attestationreport.go | 3 +- attestationreport/tpm.go | 34 ++++++++++++-- tpmdriver/bioseventlog.go | 63 +++++++++++++++++++++++++- tpmdriver/tpmdriver.go | 9 +++- 4 files changed, 101 insertions(+), 8 deletions(-) diff --git a/attestationreport/attestationreport.go b/attestationreport/attestationreport.go index 8566a61f..be7117ef 100644 --- a/attestationreport/attestationreport.go +++ b/attestationreport/attestationreport.go @@ -112,7 +112,8 @@ type HashChainElem struct { Pcr int32 `json:"pcr" cbor:"1,keyasint"` Sha256 []HexByte `json:"sha256" cbor:"2,keyasint"` Summary bool `json:"summary" cbor:"3,keyasint"` // Indicates if element represents final PCR value or single artifact - EventData []EventData `json:"eventdata,omitempty" cbor:"4,keyasint,omitempty"` + EventName []string `json:"eventname,omitempty" cbor:"4,keyasint,omitempty"` + EventData []EventData `json:"eventdata,omitempty" cbor:"5,keyasint,omitempty"` } // TpmMeasurement represents the attestation report diff --git a/attestationreport/tpm.go b/attestationreport/tpm.go index c34c3663..a88545ff 100644 --- a/attestationreport/tpm.go +++ b/attestationreport/tpm.go @@ -160,9 +160,16 @@ func recalculatePcrs(tpmM *TpmMeasurement, referenceValues []ReferenceValue) (ma // reference values if _, ok := calculatedPcrs[*ref.Pcr]; !ok { calculatedPcrs[*ref.Pcr] = make([]byte, 32) + //first event could be a TPM_PCR_INIT_VALUE () + if ref.Name == "TPM_PCR_INIT_VALUE" { + calculatedPcrs[*ref.Pcr] = ref.Sha256 //the Sha256 should contain the init value + continue //break the loop iteration and continue with the next event + } } + calculatedPcrs[*ref.Pcr] = extendHash(calculatedPcrs[*ref.Pcr], ref.Sha256) refResult := DigestResult{ + // Type: "Reference Value", Pcr: ref.Pcr, Name: ref.Name, Digest: hex.EncodeToString(ref.Sha256), @@ -179,7 +186,7 @@ func recalculatePcrs(tpmM *TpmMeasurement, referenceValues []ReferenceValue) (ma if bytes.Equal(sha256, ref.Sha256) { found = true refResult.Success = true - if hce.EventData != nil { + if hce.EventData != nil && len(hce.EventData) > i { refResult.EventData = &hce.EventData[i] } break @@ -218,6 +225,13 @@ func recalculatePcrs(tpmM *TpmMeasurement, referenceValues []ReferenceValue) (ma // the final PCR value for comparison measurement = make([]byte, 32) for i, sha256 := range hce.Sha256 { + if i == 0 { + //if the first event is a TPM_PCR_INIT_VALUE + if hce.EventName != nil && len(hce.EventName) > i && hce.EventName[i] == "TPM_PCR_INIT_VALUE" { + measurement = sha256 //because the first element in the sha256 chain is the locality, (as part of the locality event) + continue //continues with next element from the hash chain + } + } measurement = extendHash(measurement, sha256) // Check, if a reference value exists for the measured value @@ -231,7 +245,11 @@ func recalculatePcrs(tpmM *TpmMeasurement, referenceValues []ReferenceValue) (ma Type: "Measurement", } - if hce.EventData != nil { + if hce.EventName != nil && len(hce.EventName) > i { + measResult.Name = hce.EventName[i] + } + + if hce.EventData != nil && len(hce.EventData) > i { measResult.EventData = &hce.EventData[i] } @@ -306,8 +324,16 @@ func recalculatePcrs(tpmM *TpmMeasurement, referenceValues []ReferenceValue) (ma // Measurement contains individual values which must be extended to result in // the final PCR value for comparison measurement = make([]byte, 32) - for _, sha256 := range hce.Sha256 { - measurement = extendHash(measurement, sha256) + for i, sha256 := range hce.Sha256 { + //first element is the TPM_PCR_INIT_VALUE + if i == 0 { + if hce.EventName[i] != "TPM_PCR_INIT_VALUE" { + log.Errorln("First event is not a TPM_PCR_INIT_VALUE") + } + measurement = sha256 + } else { + measurement = extendHash(measurement, sha256) + } } } diff --git a/tpmdriver/bioseventlog.go b/tpmdriver/bioseventlog.go index 1d34bd33..ebe06d82 100644 --- a/tpmdriver/bioseventlog.go +++ b/tpmdriver/bioseventlog.go @@ -38,6 +38,7 @@ const ( // Constants var ( + STARTUP_LOCALITY_SIGNATURE = [16]byte{0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4C, 0x6F, 0x63, 0x61, 0x6C, 0x69, 0x74, 0x79, 0x0} EV_PREBOOT_CERT = uint32(0) EV_POST_CODE = uint32(1) EV_UNUSED = uint32(2) @@ -137,6 +138,7 @@ func GetBiosMeasurements(file string) ([]ar.ReferenceValue, error) { func parseBiosMeasurements(data []byte) ([]ar.ReferenceValue, error) { extends := make([]ar.ReferenceValue, 0) + initializedPCR := make([]bool, 24) //bool array track of what pcrs have been initialized buf := bytes.NewBuffer(data) // Read initial TCG Event to detect event log format @@ -203,7 +205,29 @@ func parseBiosMeasurements(data []byte) ([]ar.ReferenceValue, error) { //bytes of the event should be added to the array eventData := make([]uint8, eventSize) binary.Read(buf, binary.LittleEndian, &eventData) - extendedeventData = ar.ParseEventData(eventData, eventName) + + parseEvent := true + + //checks for locality + if pcrIndex > 24 { + log.Errorf("Invalid PCR: %v", pcrIndex) + } + //pcr value has not been initialized + if !initializedPCR[pcrIndex] { + //generate the locality entry + entry, skipEvent, err := generateLocalityEntry(int(pcrIndex), eventType, eventData) + if err != nil { + log.Trace(err) + } else { + extends = append(extends, entry) + } + parseEvent = !skipEvent + initializedPCR[pcrIndex] = true + + } + if parseEvent { + extendedeventData = ar.ParseEventData(eventData, eventName) + } //either Sha256 or Sha384 must be present if !(len(sha384Digest) == SHA384_DIGEST_LEN || len(sha256Digest) == SHA256_DIGEST_LEN) { @@ -225,6 +249,43 @@ func parseBiosMeasurements(data []byte) ([]ar.ReferenceValue, error) { return extends, nil } +func generateLocalityEntry(pcrIndex int, eventType uint32, eventData []uint8) (ar.ReferenceValue, bool, error) { + var found_hcrtm bool + var locality byte + skipEvent := false + eventD := bytes.NewBuffer(eventData) + + if pcrIndex == 0 { + if eventType == EV_EFI_HCRTM_EVENT { + found_hcrtm = true + locality = 0x04 //startup locality shall be set to 0x04 if a H-CRTM event was found + } + + /* Handle StartupLocality in replay for PCR0 */ + if !found_hcrtm && eventType == EV_NO_ACTION && pcrIndex == 0 { + if eventD.Len() < 17 { // sizeof(EV_NO_ACTION_STRUCT)) + return ar.ReferenceValue{}, false, errors.New("eventsize is too small") + } + + signature := eventD.Next(16) + + if bytes.Equal(signature, STARTUP_LOCALITY_SIGNATURE[:]) { + + locality = eventD.Next(1)[0] + skipEvent = true + } + } + } + + digest := make([]byte, 32) + digest[31] = locality + + entry := ar.ReferenceValue{Type: "INITVAL", Sha256: digest, Sha384: nil, Name: "TPM_PCR_INIT_VALUE", Pcr: &pcrIndex, Snp: nil, Description: "", EventData: nil} + + //generate the Locality + return entry, skipEvent, nil +} + // switch for the event types func eventtypeToString(event_type uint32) string { switch event_type { diff --git a/tpmdriver/tpmdriver.go b/tpmdriver/tpmdriver.go index 7c150e27..68817311 100644 --- a/tpmdriver/tpmdriver.go +++ b/tpmdriver/tpmdriver.go @@ -214,14 +214,18 @@ func (t *Tpm) Measure(nonce []byte) (ar.Measurement, error) { hashChain := make([]*ar.HashChainElem, len(t.Pcrs)) for i, num := range t.Pcrs { sha256 := make([]ar.HexByte, 0) - eventDataArray := make([]ar.EventData, 0) //to capture additional EventData + eventNameArray := make([]string, 0) + eventDataArray := make([]ar.EventData, 0) if t.MeasurementLog { for _, digest := range biosMeasurements { if num == *digest.Pcr { sha256 = append(sha256, digest.Sha256) + eventNameArray = append(eventNameArray, digest.Name) - if t.MeasurementLog { + if digest.Name == "TPM_PCR_INIT_VALUE" { + eventDataArray = append(eventDataArray, ar.EventData{}) + } else { eventDataArray = append(eventDataArray, *digest.EventData) } } @@ -239,6 +243,7 @@ func (t *Tpm) Measure(nonce []byte) (ar.Measurement, error) { //appending EventData if t.MeasurementLog { hashChain[i].EventData = eventDataArray + hashChain[i].EventName = eventNameArray } }