diff --git a/verification/certifyKey.go b/verification/certifyKey.go index e7b59694..126478a3 100755 --- a/verification/certifyKey.go +++ b/verification/certifyKey.go @@ -4,14 +4,11 @@ package verification import ( "bytes" - "crypto/sha256" - "crypto/sha512" "crypto/x509" "encoding/asn1" "encoding/binary" "encoding/pem" "fmt" - "hash" "reflect" "testing" "time" @@ -221,69 +218,6 @@ func checkCertifyKeyTcgUeidExtension(t *testing.T, c *x509.Certificate, label [] } } -// A tcg-dice-MultiTcbInfo extension. -// This extension SHOULD be marked as critical. -func checkCertifyKeyMultiTcbInfoExtensionStructure(t *testing.T, c *x509.Certificate) (TcgMultiTcbInfo, error) { - t.Helper() - var multiTcbInfo TcgMultiTcbInfo - var err error - - // Check MultiTcbInfo Extension - //tcg-dice-MultiTcbInfo extension - for _, ext := range c.Extensions { - if ext.Id.Equal(OidExtensionTcgDiceMultiTcbInfo) { // OID for Tcg Dice MultiTcbInfo - if !ext.Critical { - t.Errorf("[ERROR]: TCG DICE MultiTcbInfo extension is not marked as CRITICAL") - } - _, err = asn1.Unmarshal(ext.Value, &multiTcbInfo) - if err != nil { - // multiTcb info is not provided in leaf - t.Errorf("[ERROR]: Failed to unmarshal MultiTcbInfo field: %v", err) - } - break - } - } - return multiTcbInfo, err -} - -// Checks the FWID block's Digest. -// FWID at index 0 has the TCI_CURRENT as digest -// FWID at index 1 has the TCI_CUMULATIVE as digest -// The length of FWID array in each DICE TCB information block is 2. -func checkCurrentDiceTcbMeasurements(t *testing.T, multiTcbInfo []DiceTcbInfo, expectedCurrentValue []byte) { - currentTci := multiTcbInfo[0].Fwids[0].Digest - cumulativeTci := multiTcbInfo[0].Fwids[1].Digest - - if !bytes.Equal(currentTci, expectedCurrentValue) { - t.Errorf("[ERROR]: Unexpected TCI_CURRENT digest, want %v but got %v", expectedCurrentValue, currentTci) - } - - // Calculate expected cumulative value - var expectedCumulativeValue []byte - var defaultTci []byte - var hasher hash.Hash - if multiTcbInfo[0].Fwids[1].HashAlg.Equal(OidSHA384) { - hasher = sha512.New384() - defaultTci = make([]byte, 48) - hasher.Write(defaultTci) - } else if multiTcbInfo[0].Fwids[1].HashAlg.Equal(OidSHA256) { - hasher = sha256.New() - defaultTci = make([]byte, 32) - hasher.Write(defaultTci) - } - - // The DiceTcbInfo blocks are listed with current node at index0 followed by parent TCI nodes. - for i := len(multiTcbInfo) - 1; i >= 0; i-- { - hasher.Write(multiTcbInfo[i].Fwids[0].Digest) - } - expectedCumulativeValue = hasher.Sum(nil) - - // Verify the FWID index-1 which has TCI_CUMULATIVE value of current node - if !bytes.Equal(cumulativeTci, expectedCumulativeValue) { - t.Errorf("[ERROR]: Unexpected cumulative TCI value, want %v but got %v", expectedCumulativeValue, cumulativeTci) - } -} - // Check whether certificate extended key usage is as per spec // OID for ExtendedKeyUsage Extension: 2.5.29.37 // The ExtendedKeyUsage extension SHOULD be marked as critical @@ -397,7 +331,10 @@ func validateCertifyKeyCert(t *testing.T, c *x509.Certificate, flags uint32, lab checkCertifyKeyTcgUeidExtension(t, c, label) // Check MultiTcbInfo Extension structure - checkCertifyKeyMultiTcbInfoExtensionStructure(t, c) + _, err := getMultiTcbInfo(c) + if err != nil { + t.Error(err) + } } func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate { diff --git a/verification/certs.go b/verification/certs.go new file mode 100644 index 00000000..7307c044 --- /dev/null +++ b/verification/certs.go @@ -0,0 +1,69 @@ +// Licensed under the Apache-2.0 license + +package verification + +import ( + "crypto/x509" + "encoding/asn1" + "fmt" +) + +// A tcg-dice-MultiTcbInfo extension. +// This extension SHOULD be marked as critical. +func getMultiTcbInfo(c *x509.Certificate) (TcgMultiTcbInfo, error) { + var multiTcbInfo TcgMultiTcbInfo + + // Check MultiTcbInfo Extension + //tcg-dice-MultiTcbInfo extension + for _, ext := range c.Extensions { + if ext.Id.Equal(OidExtensionTcgDiceMultiTcbInfo) { // OID for Tcg Dice MultiTcbInfo + if !ext.Critical { + return multiTcbInfo, fmt.Errorf("[ERROR]: TCG DICE MultiTcbInfo extension is not marked as CRITICAL") + } + _, err := asn1.Unmarshal(ext.Value, &multiTcbInfo) + if err != nil { + // multiTcb info is not provided in leaf + return multiTcbInfo, fmt.Errorf("[ERROR]: Failed to unmarshal MultiTcbInfo field: %v", err) + } + break + } + } + return multiTcbInfo, nil +} + +func getTcbInfoForHandle(c DPEClient, handle *ContextHandle) (DiceTcbInfo, error) { + // Get digest size + profile, err := c.GetProfile() + if err != nil { + return DiceTcbInfo{}, err + } + + digestLen := profile.Profile.GetDigestSize() + label := make([]byte, digestLen) + + certifiedKey, err := c.CertifyKey(handle, label, CertifyKeyX509, 0) + if err != nil { + return DiceTcbInfo{}, err + } + + leafCertBytes := certifiedKey.Certificate + + var leafCert *x509.Certificate + + // Check whether certificate is DER encoded. + if leafCert, err = x509.ParseCertificate(leafCertBytes); err != nil { + return DiceTcbInfo{}, err + } + + // Get DICE information from MultiTcbInfo Extension + multiTcbInfo, err := getMultiTcbInfo(leafCert) + if err != nil { + return DiceTcbInfo{}, err + } + + if len(multiTcbInfo) == 0 { + return DiceTcbInfo{}, fmt.Errorf("Certificate MutliTcbInfo is empty") + } + + return multiTcbInfo[0], nil +} diff --git a/verification/extendTCI.go b/verification/extendTCI.go index 3d2bcdbd..3397ca3b 100644 --- a/verification/extendTCI.go +++ b/verification/extendTCI.go @@ -3,9 +3,9 @@ package verification import ( + "bytes" "crypto/sha256" "crypto/sha512" - "crypto/x509" "hash" "testing" @@ -26,54 +26,52 @@ func TestExtendTCI(d TestDPEInstance, c DPEClient, t *testing.T) { } digestLen := profile.GetDigestSize() - // Initialize TCI inputs with all zeroes - // since, TCI_DEFAULT for default context is all zeroes - defaultTci := make([]byte, digestLen) - - // Initialize hasher - var hasher hash.Hash - if digestLen == 32 { - hasher = sha256.New() - } else if digestLen == 48 { - hasher = sha512.New384() - } - tciValue := make([]byte, digestLen) for i := range tciValue { tciValue[i] = byte(i) } + tcbInfo, err := getTcbInfoForHandle(c, handle) + if err != nil { + t.Fatal(err) + } + lastCumulative := tcbInfo.Fwids[1].Digest + // Set current TCI value _, err = c.ExtendTCI(handle, tciValue) if err != nil { t.Fatalf("[FATAL]: Could not extend TCI: %v", err) } + // Compute expected cumulative + var hasher hash.Hash + if digestLen == 32 { + hasher = sha256.New() + } else if digestLen == 48 { + hasher = sha512.New384() + } + hasher.Write(lastCumulative) + hasher.Write(tciValue) + expectedCumulative := hasher.Sum(nil) + // Cross-check current and cumulative measurement by CertifyKey - verifyMeasurementsByCertifyKey(c, t, handle, defaultTci, tciValue, hasher) + verifyMeasurements(c, t, handle, tciValue, expectedCumulative) } -func verifyMeasurementsByCertifyKey(c DPEClient, t *testing.T, handle *ContextHandle, label []byte, tciValue []byte, hasher hash.Hash) { - certifiedKey, err := c.CertifyKey(handle, label, CertifyKeyX509, 0) +func verifyMeasurements(c DPEClient, t *testing.T, handle *ContextHandle, expectedCurrent []byte, expectedCumulative []byte) { + tcbInfo, err := getTcbInfoForHandle(c, handle) if err != nil { - t.Fatalf("[FATAL]: Could not get Certified key: %v", err) + t.Fatal(err) } - leafCertBytes := certifiedKey.Certificate - - var leafCert *x509.Certificate - - // Check whether certificate is DER encoded. - if leafCert, err = x509.ParseCertificate(leafCertBytes); err != nil { - t.Fatalf("[FATAL]: Could not parse certificate using crypto/x509: %v", err) + // Check that the last TcbInfo current/cumulative are as expected + current := tcbInfo.Fwids[0].Digest + cumulative := tcbInfo.Fwids[1].Digest + if !bytes.Equal(current, expectedCurrent) { + t.Errorf("[ERROR]: Unexpected TCI_CURRENT digest, want %v but got %v", expectedCurrent, current) } - // Get DICE information from MultiTcbInfo Extension - multiTcbInfo, err := checkCertifyKeyMultiTcbInfoExtensionStructure(t, leafCert) - if err != nil { - t.Errorf("Error while unmarshalling MultiTCB information %v, skipping MultiTCB validation", err) - } else { - // Cross-verify cumulative value returned in MultiTcbInfo - checkCurrentDiceTcbMeasurements(t, multiTcbInfo, tciValue) + if !bytes.Equal(cumulative, expectedCumulative) { + t.Errorf("[ERROR]: Unexpected cumulative TCI value, want %v but got %v", expectedCumulative, cumulative) } } diff --git a/verification/negativeCases.go b/verification/negativeCases.go index ac39092c..24042403 100644 --- a/verification/negativeCases.go +++ b/verification/negativeCases.go @@ -69,9 +69,14 @@ func TestInvalidHandle(d TestDPEInstance, c DPEClient, t *testing.T) { // Exceptions are - GetProfile, InitializeContext, GetCertificateChain, commands // which do not need context handle as input and hence locality is irrelevant. func TestWrongLocality(d TestDPEInstance, c DPEClient, t *testing.T) { + if !d.HasLocalityControl() { + t.Skipf("Target does not have locality control") + } + // Modify and later restore the locality of DPE instance to test - d.SetLocality(DPE_SIMULATOR_OTHER_LOCALITY) - defer d.SetLocality(DPE_SIMULATOR_AUTO_INIT_LOCALITY) + currentLocality := d.GetLocality() + d.SetLocality(currentLocality + 1) + defer d.SetLocality(currentLocality) // Get default context handle handle := &DefaultContextHandle diff --git a/verification/simulator.go b/verification/simulator.go index dd7b4adf..f86d6747 100644 --- a/verification/simulator.go +++ b/verification/simulator.go @@ -171,6 +171,10 @@ func (s *DpeSimulator) GetSupportedLocalities() []uint32 { return []uint32{DPE_SIMULATOR_AUTO_INIT_LOCALITY, DPE_SIMULATOR_OTHER_LOCALITY} } +func (s *DpeSimulator) HasLocalityControl() bool { + return true +} + func (s *DpeSimulator) SetLocality(locality uint32) { s.currentLocality = locality } diff --git a/verification/transport.go b/verification/transport.go index 5d89371d..6feded7d 100644 --- a/verification/transport.go +++ b/verification/transport.go @@ -41,6 +41,8 @@ type TestDPEInstance interface { SetIsInitialized(bool) // Returns a slice of all the localities the instance supports. GetSupportedLocalities() []uint32 + // Whether the target can artificially control the locality of the caller + HasLocalityControl() bool // Sets the current locality. SetLocality(locality uint32) // Gets the current locality.