Skip to content

Commit

Permalink
Fix verification tests to pass against Caliptra emulator
Browse files Browse the repository at this point in the history
1. Refactor ExtendTCI to calculate the cumulative measurement properly
2. Refactor some helpers for better readability
3. Skip bad locality test for targets that don't have locality control
  • Loading branch information
jhand2 committed Nov 21, 2023
1 parent b62fe70 commit fb105d9
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 100 deletions.
71 changes: 4 additions & 67 deletions verification/certifyKey.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
69 changes: 69 additions & 0 deletions verification/certs.go
Original file line number Diff line number Diff line change
@@ -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
}
60 changes: 29 additions & 31 deletions verification/extendTCI.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
package verification

import (
"bytes"
"crypto/sha256"
"crypto/sha512"
"crypto/x509"
"hash"

"testing"
Expand All @@ -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)
}
}
9 changes: 7 additions & 2 deletions verification/negativeCases.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions verification/simulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 2 additions & 0 deletions verification/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit fb105d9

Please sign in to comment.