Skip to content

Commit 612f055

Browse files
committed
optionally verify TcbEvaluationDataNumber
Signed-off-by: Markus Rudy <mr@edgeless.systems>
1 parent e6425e8 commit 612f055

File tree

4 files changed

+51
-6
lines changed

4 files changed

+51
-6
lines changed

pcs/pcs.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,11 @@ func TcbInfoURL(fmspc string) string {
521521
return fmt.Sprintf("%s/tcb?fmspc=%s", TdxBaseURL, fmspc)
522522
}
523523

524+
// TcbInfoURLWithEvaluationDataNumber returns the Intel PCS URL for retrieving TCB Info at a specific evaluationDataNumber.
525+
func TcbInfoURLWithEvaluationDataNumber(fmspc string, evaluationDataNumber int) string {
526+
return fmt.Sprintf("%s/tcb?fmspc=%s&tcbEvaluationDataNumber=%d", TdxBaseURL, fmspc, evaluationDataNumber)
527+
}
528+
524529
// QeIdentityURL returns the Intel PCS URL for retrieving QE identity
525530
func QeIdentityURL() string {
526531
return fmt.Sprintf("%s/qe/identity", TdxBaseURL)

testing/test_cases.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ var TestGetter = &Getter{
5858
Header: TcbInfoHeader,
5959
Body: testdata.TcbInfoBody,
6060
},
61+
"https://api.trustedservices.intel.com/tdx/certification/v4/tcb?fmspc=50806f000000&tcbEvaluationDataNumber=255": {
62+
Header: TcbInfoHeader,
63+
Body: testdata.TcbInfoBody,
64+
},
6165
"https://api.trustedservices.intel.com/sgx/certification/v4/pckcrl?ca=platform&encoding=der": {
6266
Header: PckCrlHeader,
6367
Body: testdata.PckCrlBody,

verify/verify.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ type Options struct {
191191
// If nil, embedded certificate will be used
192192
TrustedRoots *x509.CertPool
193193

194+
// EvaluationDataNumber for TCB info that should be requested from PCS.
195+
// If this is non-zero and verification succeeds, the TCB info was at EvaluationDataNumber or newer.
196+
// If GetCollateral is false, the TCBInfo will not be fetched and thus the number is not checked.
197+
EvaluationDataNumber int
198+
194199
chain *PCKCertificateChain
195200
collateral *Collateral
196201
pckCertExtensions *pcs.PckExtensions
@@ -391,11 +396,15 @@ func getPckCrl(ctx context.Context, ca string, getter trust.HTTPSGetter, collate
391396
return nil
392397
}
393398

394-
func getTcbInfo(ctx context.Context, fmspc string, getter trust.HTTPSGetter, collateral *Collateral) error {
399+
func getTcbInfo(ctx context.Context, fmspc string, getter trust.HTTPSGetter, collateral *Collateral, evaluationDataNumber int) error {
395400
tcbInfoURL := pcs.TcbInfoURL(fmspc)
401+
if evaluationDataNumber > 0 {
402+
tcbInfoURL = pcs.TcbInfoURLTcbInfoURLWithEvaluationDataNumber(fmspc, evaluationDataNumber)
403+
}
396404
logger.V(2).Info("Getting TCB Info: ", tcbInfoURL)
397405
header, body, err := trust.GetWith(ctx, getter, tcbInfoURL)
398406
if err != nil {
407+
// TODO(burgerdev): 410 means evaluationDataNumber is too old, but the HTTPSGetter interface does not allow inspection of the return code.
399408
return &trust.AttestationRecreationErr{
400409
Msg: fmt.Sprintf("could not receive tcbInfo response: %v", err),
401410
}
@@ -417,6 +426,17 @@ func getTcbInfo(ctx context.Context, fmspc string, getter trust.HTTPSGetter, col
417426
}
418427
}
419428

429+
// According to the docs [1], if we explicitly requested an evaluation number and the request
430+
// succeeded, the response should contain exactly that number. If there's a mismatch, we're
431+
// either dealing with a non-compliant PCS or being MITM'd.
432+
//
433+
// [1]: https://api.portal.trustedservices.intel.com/content/documentation.html#pcs-tcb-info-tdx-v4
434+
if evaluationDataNumber > 0 && collateral.TdxTcbInfo.TcbInfo.TcbEvaluationDataNumber < evaluationDataNumber {
435+
return &trust.AttestationRecreationErr{
436+
Msg: fmt.Sprintf("PCS responded with an outdated TcbEvaluationDataNumber (got %d, requested %d)", collateral.TdxTcbInfo.TcbInfo.TcbEvaluationDataNumber, evaluationDataNumber),
437+
}
438+
}
439+
420440
tcbInfoRawBody, err := bodyToRawMessage(tcbInfoPhrase, body)
421441
if err != nil {
422442
return &trust.AttestationRecreationErr{
@@ -494,7 +514,7 @@ func obtainCollateral(ctx context.Context, fmspc string, ca string, options *Opt
494514
}
495515
collateral := &Collateral{}
496516
logger.V(1).Info("Getting TCB Info API response from the Intel PCS")
497-
if err := getTcbInfo(ctx, fmspc, getter, collateral); err != nil {
517+
if err := getTcbInfo(ctx, fmspc, getter, collateral, options.EvaluationDataNumber); err != nil {
498518
return nil, fmt.Errorf("unable to receive tcbInfo: %v", err)
499519
}
500520
logger.V(1).Info("Successfully received TCB Info API response from the Intel PCS")

verify/verify_test.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -397,11 +397,27 @@ func TestGetTcbInfo(t *testing.T) {
397397
fmspc := hex.EncodeToString(fmspcBytes)
398398

399399
collateral := &Collateral{}
400-
if err := getTcbInfo(context.Background(), fmspc, getter, collateral); err != nil {
400+
if err := getTcbInfo(context.Background(), fmspc, getter, collateral, 0); err != nil {
401401
t.Error(err)
402402
}
403403
}
404404

405+
func TestGetTcbInfoOutdatedTcbEvalutationDataNumber(t *testing.T) {
406+
getter := testcases.TestGetter
407+
fmspcBytes := []byte{80, 128, 111, 0, 0, 0}
408+
fmspc := hex.EncodeToString(fmspcBytes)
409+
410+
collateral := &Collateral{}
411+
412+
err := getTcbInfo(context.Background(), fmspc, getter, collateral, 255)
413+
if err == nil {
414+
t.Fatal("expected an error when PCS returns outdated TcbEvalutationDataNumber")
415+
}
416+
if !strings.Contains(err.Error(), "outdated TcbEvaluationDataNumber") {
417+
t.Fatalf("unexpected error when PCS returns outdated TcbEvalutationDataNumber: %v", err)
418+
}
419+
}
420+
405421
func TestGetQeIdentity(t *testing.T) {
406422
getter := testcases.TestGetter
407423
collateral := &Collateral{}
@@ -492,7 +508,7 @@ func TestVerifyUsingTcbInfoV4(t *testing.T) {
492508
fmspc := hex.EncodeToString(fmspcBytes)
493509

494510
collateral := &Collateral{}
495-
if err := getTcbInfo(context.Background(), fmspc, getter, collateral); err != nil {
511+
if err := getTcbInfo(context.Background(), fmspc, getter, collateral, 0); err != nil {
496512
t.Fatal(err)
497513
}
498514
anyQuote, err := abi.QuoteToProto(testdata.RawQuote)
@@ -542,7 +558,7 @@ func TestNegativeVerifyUsingTcbInfoV4(t *testing.T) {
542558
fmspc := hex.EncodeToString(fmspcBytes)
543559

544560
collateral := &Collateral{}
545-
if err := getTcbInfo(context.Background(), fmspc, getter, collateral); err != nil {
561+
if err := getTcbInfo(context.Background(), fmspc, getter, collateral, 0); err != nil {
546562
t.Fatal(err)
547563
}
548564
anyQuote, err := abi.QuoteToProto(testdata.RawQuote)
@@ -675,7 +691,7 @@ func TestNegativeTcbInfoTcbStatusV4(t *testing.T) {
675691
fmspc := hex.EncodeToString(fmspcBytes)
676692

677693
collateral := &Collateral{}
678-
if err := getTcbInfo(context.Background(), fmspc, getter, collateral); err != nil {
694+
if err := getTcbInfo(context.Background(), fmspc, getter, collateral, 0); err != nil {
679695
t.Fatal(err)
680696
}
681697
anyQuote, err := abi.QuoteToProto(testdata.RawQuote)

0 commit comments

Comments
 (0)