Skip to content

Commit

Permalink
Update TCB Info verification logic. (#38)
Browse files Browse the repository at this point in the history
* Update TCB Info verification logic.

* Remove unnecessary code.

* Fix lint errors.

* Address review comments.
  • Loading branch information
vbalain authored Feb 16, 2024
1 parent 686ff34 commit 43efd1f
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 27 deletions.
30 changes: 20 additions & 10 deletions pcs/pcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,17 @@ type TdxTcbInfo struct {

// TcbInfo struct is used to map response from tcbInfo field
type TcbInfo struct {
ID string `json:"id"`
Version byte `json:"version"`
IssueDate time.Time `json:"issueDate"`
NextUpdate time.Time `json:"nextUpdate"`
Fmspc string `json:"fmspc"`
PceID string `json:"pceId"`
TcbType byte `json:"tcbType"`
TcbEvaluationDataNumber int `json:"tcbEvaluationDataNumber"`
TdxModule TdxModule `json:"tdxModule"`
TcbLevels []TcbLevel `json:"tcbLevels"`
ID string `json:"id"`
Version byte `json:"version"`
IssueDate time.Time `json:"issueDate"`
NextUpdate time.Time `json:"nextUpdate"`
Fmspc string `json:"fmspc"`
PceID string `json:"pceId"`
TcbType byte `json:"tcbType"`
TcbEvaluationDataNumber int `json:"tcbEvaluationDataNumber"`
TdxModule TdxModule `json:"tdxModule"`
TdxModuleIdentities []TdxModuleIdentity `json:"tdxModuleIdentities"`
TcbLevels []TcbLevel `json:"tcbLevels"`
}

// TdxModule struct is used to map response from tcbInfo for tdxModule field
Expand All @@ -95,6 +96,15 @@ type TdxModule struct {
AttributesMask HexBytes `json:"attributesMask"`
}

// TdxModuleIdentity struct is used to map response from tcbInfo for TdxModuleIdentity field
type TdxModuleIdentity struct {
ID string `json:"id"`
Mrsigner HexBytes `json:"mrsigner"`
Attributes HexBytes `json:"attributes"`
AttributesMask HexBytes `json:"attributesMask"`
TcbLevels []TcbLevel `json:"tcbLevels"`
}

// TcbLevel struct is used to map TCB Level field
type TcbLevel struct {
Tcb Tcb `json:"tcb"`
Expand Down
4 changes: 2 additions & 2 deletions tools/check/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ func populateConfig() error {
*dest = value
}
}
setRtmrs := func(dest *[][]byte, name, flag string) error {
setRtmrs := func(dest *[][]byte, flag string) error {
if flag != "" {
val, err := parseRtmrs(flag)
if err != nil {
Expand All @@ -361,7 +361,7 @@ func populateConfig() error {
return multierr.Combine(
setUint32(&policy.HeaderPolicy.MinimumQeSvn, "minimum_qe_svn", *minqesvn, defaultMinQeSvn),
setUint32(&policy.HeaderPolicy.MinimumPceSvn, "minimum_pce_svn", *minpcesvn, defaultMinPceSvn),
setRtmrs(&policy.TdQuoteBodyPolicy.Rtmrs, "rtmrs", *rtmrs),
setRtmrs(&policy.TdQuoteBodyPolicy.Rtmrs, *rtmrs),
)
}

Expand Down
4 changes: 2 additions & 2 deletions tools/check/check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func setField(p *ccpb.Policy, policy string, name string, value any) {
}

func bytesSetter(name string, policy string) setterFn {
return func(p *ccpb.Policy, value string, t *testing.T) bool {
return func(p *ccpb.Policy, value string, _ *testing.T) bool {
v, err := hex.DecodeString(value)
if err != nil {
return true
Expand All @@ -101,7 +101,7 @@ func bytesSetter(name string, policy string) setterFn {
}

func uint32setter(name string, policy string) setterFn {
return func(p *ccpb.Policy, value string, t *testing.T) bool {
return func(p *ccpb.Policy, value string, _ *testing.T) bool {
u, err := strconv.ParseUint(value, 10, 32)
if err != nil {
return true
Expand Down
65 changes: 56 additions & 9 deletions verify/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ const (
tcbInfoID = "TDX"
qeIdentityID = "TD_QE"
tcbSigningPhrase = "Intel SGX TCB Signing"
tcbInfoTdxModuleIDPrefix = "TDX_"
)

// Options represents verification options for a TDX attestation quote.
Expand Down Expand Up @@ -866,20 +867,58 @@ func verifyHash256(quote *pb.QuoteV4) error {
return nil
}

func isSvnHigherOrEqual(svn []byte, components []pcs.TcbComponent) bool {
for i := range svn {
if svn[i] < components[i].Svn {
func isCPUSvnHigherOrEqual(pckCertCPUSvnComponents []byte, sgxTcbcomponents []pcs.TcbComponent) bool {
if len(pckCertCPUSvnComponents) != len(sgxTcbcomponents) {
return false
}
for i := range pckCertCPUSvnComponents {
if pckCertCPUSvnComponents[i] < sgxTcbcomponents[i].Svn {
return false
}
}
return true
}

func isTdxTcbSvnHigherOrEqual(teeTcbSvn []byte, tdxTcbcomponents []pcs.TcbComponent) bool {
if len(teeTcbSvn) != len(tdxTcbcomponents) {
return false
}
start := 0
if teeTcbSvn[1] > 0 {
start = 2
}
for i := start; i < len(teeTcbSvn); i++ {
if teeTcbSvn[i] < tdxTcbcomponents[i].Svn {
return false
}
}
return true
}

func getMatchingTdxModuleTcbLevel(tcbInfoTdxModuleIdentities []pcs.TdxModuleIdentity, teeTcbSvn []byte) (*pcs.TcbLevel, error) {
tdxModuleVersion := []byte(teeTcbSvn[1:2])
tdxModuleIdentityID := tcbInfoTdxModuleIDPrefix + hex.EncodeToString(tdxModuleVersion)
tdxModuleIsvSvn := uint32(teeTcbSvn[0])

for _, tdxModuleIdentity := range tcbInfoTdxModuleIdentities {
if tdxModuleIdentityID == tdxModuleIdentity.ID {
for _, tcbLevel := range tdxModuleIdentity.TcbLevels {
if tdxModuleIsvSvn >= tcbLevel.Tcb.Isvsvn {
logger.V(2).Infof("TDX Module Identity's TCB Level's ISVSVN(%q) matched the TDX Module's ISVSVN(%q)", tcbLevel.Tcb.Isvsvn, tdxModuleIsvSvn)
return &tcbLevel, nil
}
}
return nil, fmt.Errorf("could not find a TDX Module Identity TCB Level matching the TDX Module's ISVSVN (%d)", tdxModuleIsvSvn)
}
}
return nil, fmt.Errorf("could not find a TDX Module Identity (%q) matching the given TEE TDX version (%q)", tdxModuleIdentityID, tdxModuleVersion)
}

func getMatchingTcbLevel(tcbLevels []pcs.TcbLevel, tdReport *pb.TDQuoteBody, pckCertPceSvn uint16, pckCertCPUSvnComponents []byte) (pcs.TcbLevel, error) {
for _, tcbLevel := range tcbLevels {
if isSvnHigherOrEqual(pckCertCPUSvnComponents, tcbLevel.Tcb.SgxTcbcomponents) &&
if isCPUSvnHigherOrEqual(pckCertCPUSvnComponents, tcbLevel.Tcb.SgxTcbcomponents) &&
pckCertPceSvn >= tcbLevel.Tcb.Pcesvn &&
isSvnHigherOrEqual(tdReport.GetTeeTcbSvn(), tcbLevel.Tcb.TdxTcbcomponents) {
isTdxTcbSvnHigherOrEqual(tdReport.GetTeeTcbSvn(), tcbLevel.Tcb.TdxTcbcomponents) {
return tcbLevel, nil
}
}
Expand All @@ -898,15 +937,23 @@ func checkQeTcbStatus(tcbLevels []pcs.TcbLevel, isvsvn uint32) error {
return ErrTcbStatus
}

func checkTcbInfoTcbStatus(tcbLevels []pcs.TcbLevel, tdQuoteBody *pb.TDQuoteBody, pckCertExtensions *pcs.PckExtensions) error {
func checkTcbInfoTcbStatus(tcbInfo pcs.TcbInfo, tdQuoteBody *pb.TDQuoteBody, pckCertExtensions *pcs.PckExtensions) error {
tcbLevels := tcbInfo.TcbLevels
matchingTcbLevel, err := getMatchingTcbLevel(tcbLevels, tdQuoteBody, pckCertExtensions.TCB.PCESvn, pckCertExtensions.TCB.CPUSvnComponents)
if err != nil {
return err
}
logger.V(2).Info("Matching TCB Level found: ", matchingTcbLevel)

if matchingTcbLevel.Tcb.TdxTcbcomponents[1].Svn != tdQuoteBody.GetTeeTcbSvn()[1] {
return fmt.Errorf("SVN at index 1(%v) in Tcb.TdxTcbcomponents is not equal to TD Quote Body's index 1(%v) TEE TCB svn value", matchingTcbLevel.Tcb.TdxTcbcomponents[1].Svn, tdQuoteBody.GetTeeTcbSvn()[1])
if tdQuoteBody.GetTeeTcbSvn()[1] > 0 {
matchingTdxModuleTcbLevel, err := getMatchingTdxModuleTcbLevel(tcbInfo.TdxModuleIdentities, tdQuoteBody.GetTeeTcbSvn())
if err != nil {
return err
}
logger.V(2).Info("Tdx Module TCB Status found: ", matchingTdxModuleTcbLevel.TcbStatus)
if matchingTdxModuleTcbLevel.TcbStatus != pcs.TcbComponentStatusUpToDate {
return fmt.Errorf("TDX Module TCB Status is not %q, found %q", pcs.TcbComponentStatusUpToDate, matchingTdxModuleTcbLevel.TcbStatus)
}
}

logger.V(2).Info("TCB Status found: ", matchingTcbLevel.TcbStatus)
Expand Down Expand Up @@ -942,7 +989,7 @@ func verifyTdQuoteBody(tdQuoteBody *pb.TDQuoteBody, tdQuoteBodyOptions *tdQuoteB
return fmt.Errorf("AttributesMask value(%q) is not equal to TdxModule.Attributes field in Intel PCS's reported TDX TCB info(%q)", hex.EncodeToString(attributesMask), hex.EncodeToString(tdQuoteBodyOptions.tcbInfo.TdxModule.Attributes.Bytes))
}

if err := checkTcbInfoTcbStatus(tdQuoteBodyOptions.tcbInfo.TcbLevels, tdQuoteBody, tdQuoteBodyOptions.pckCertExtensions); err != nil {
if err := checkTcbInfoTcbStatus(tdQuoteBodyOptions.tcbInfo, tdQuoteBody, tdQuoteBodyOptions.pckCertExtensions); err != nil {
return fmt.Errorf("TDX TCB info reported by Intel PCS failed TCB status check: %v", err)
}
return nil
Expand Down
8 changes: 4 additions & 4 deletions verify/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -656,25 +656,25 @@ func TestNegativeTcbInfoTcbStatusV4(t *testing.T) {

setTcbSvnValues(10, 0, &tcbInfo.TcbLevels[0].Tcb.TdxTcbcomponents, &tcbInfo.TcbLevels[0].Tcb.SgxTcbcomponents)
wantErr := "no matching TCB level found"
if err := checkTcbInfoTcbStatus(tcbInfo.TcbLevels, quote.GetTdQuoteBody(), ext); err == nil || err.Error() != wantErr {
if err := checkTcbInfoTcbStatus(tcbInfo, quote.GetTdQuoteBody(), ext); err == nil || err.Error() != wantErr {
t.Errorf("SgxTcbComponents values greater: checkTcbInfoTcbStatus() = %v. Want error %v", err, wantErr)
}

setTcbSvnValues(0, 10, &tcbInfo.TcbLevels[0].Tcb.TdxTcbcomponents, &tcbInfo.TcbLevels[0].Tcb.SgxTcbcomponents)
if err := checkTcbInfoTcbStatus(tcbInfo.TcbLevels, quote.GetTdQuoteBody(), ext); err == nil || err.Error() != wantErr {
if err := checkTcbInfoTcbStatus(tcbInfo, quote.GetTdQuoteBody(), ext); err == nil || err.Error() != wantErr {
t.Errorf("TdxTcbComponents values greater: checkTcbInfoTcbStatus() = %v. Want error %v", err, wantErr)
}

tcbInfo.TcbLevels[0].Tcb.Pcesvn = 20
setTcbSvnValues(0, 0, &tcbInfo.TcbLevels[0].Tcb.TdxTcbcomponents, &tcbInfo.TcbLevels[0].Tcb.SgxTcbcomponents)
if err := checkTcbInfoTcbStatus(tcbInfo.TcbLevels, quote.GetTdQuoteBody(), ext); err == nil || err.Error() != wantErr {
if err := checkTcbInfoTcbStatus(tcbInfo, quote.GetTdQuoteBody(), ext); err == nil || err.Error() != wantErr {
t.Errorf("PCESvn value greater: checkTcbInfoTcbStatus() = %v. Want error %v", err, wantErr)
}

tcbInfo.TcbLevels[0].Tcb.Pcesvn = 0
tcbInfo.TcbLevels[0].TcbStatus = "OutOfDate"
wantErr = `TCB Status is not "UpToDate", found "OutOfDate"`
if err := checkTcbInfoTcbStatus(tcbInfo.TcbLevels, quote.GetTdQuoteBody(), ext); err == nil || err.Error() != wantErr {
if err := checkTcbInfoTcbStatus(tcbInfo, quote.GetTdQuoteBody(), ext); err == nil || err.Error() != wantErr {
t.Errorf("TCB status expired: checkTcbInfoTcbStatus() = %v. Want error %v", err, wantErr)
}
}
Expand Down

0 comments on commit 43efd1f

Please sign in to comment.