Skip to content

Commit 5c2b576

Browse files
authored
Merge pull request #6331 from oasisprotocol/peternose/feature/whitelist-fmspcs
go/common/sgx/pcs/policy: Add FMSP whitelist to quote policy
2 parents 631ddc1 + 8ca2ad2 commit 5c2b576

34 files changed

Lines changed: 269 additions & 63 deletions

File tree

.changelog/6331.breaking.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
go/common/sgx/pcs/policy: Add FMSPC whitelist to quote policy

go/common/node/node.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ func HashRAK(rak signature.PublicKey) hash.Hash {
574574
}
575575

576576
// Verify verifies the node's TEE capabilities, at the provided timestamp and height.
577-
func (c *CapabilityTEE) Verify(teeCfg *TEEFeatures, ts time.Time, height uint64, constraints []byte, nodeID signature.PublicKey) error {
577+
func (c *CapabilityTEE) Verify(teeCfg *TEEFeatures, ts time.Time, height uint64, constraints []byte, nodeID signature.PublicKey, isFeatureVersion242 bool) error {
578578
switch c.Hardware {
579579
case TEEHardwareIntelSGX:
580580
// Parse SGX remote attestation.
@@ -591,7 +591,7 @@ func (c *CapabilityTEE) Verify(teeCfg *TEEFeatures, ts time.Time, height uint64,
591591
if err := cbor.Unmarshal(constraints, &sc); err != nil {
592592
return fmt.Errorf("node: malformed SGX constraints: %w", err)
593593
}
594-
if err := sc.ValidateBasic(teeCfg); err != nil {
594+
if err := sc.ValidateBasic(teeCfg, isFeatureVersion242); err != nil {
595595
return fmt.Errorf("node: malformed SGX constraints: %w", err)
596596
}
597597

go/common/node/sgx.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func (sc *SGXConstraints) MarshalCBOR() ([]byte, error) {
9797
}
9898

9999
// ValidateBasic performs basic structure validity checks.
100-
func (sc *SGXConstraints) ValidateBasic(cfg *TEEFeatures) error {
100+
func (sc *SGXConstraints) ValidateBasic(cfg *TEEFeatures, isFeatureVersion242 bool) error {
101101
if cfg == nil {
102102
cfg = &emptyFeatures
103103
}
@@ -116,6 +116,13 @@ func (sc *SGXConstraints) ValidateBasic(cfg *TEEFeatures) error {
116116
return fmt.Errorf("TDX policy not supported")
117117
}
118118

119+
// Check that policy is compliant with the current feature version.
120+
if sc.Policy != nil {
121+
if err := sc.Policy.Validate(isFeatureVersion242); err != nil {
122+
return fmt.Errorf("invalid policy: %w", err)
123+
}
124+
}
125+
119126
return nil
120127
}
121128

go/common/node/sgx_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func TestSGXConstraintsV0(t *testing.T) {
2727
err = cbor.Unmarshal(raw, &sc)
2828
require.NoError(err, "Decode V0 SGX constraints")
2929

30-
err = sc.ValidateBasic(nil)
30+
err = sc.ValidateBasic(nil, true)
3131
require.NoError(err, "ValidateBasic V0 SGX constraints")
3232

3333
enc := cbor.Marshal(sc)
@@ -60,11 +60,11 @@ func TestSGXConstraintsV1(t *testing.T) {
6060
},
6161
},
6262
}
63-
err = sc.ValidateBasic(nil)
63+
err = sc.ValidateBasic(nil, true)
6464
require.Error(err, "ValidateBasic V1 SGX constraints without PCS support")
65-
err = sc.ValidateBasic(&TEEFeatures{})
65+
err = sc.ValidateBasic(&TEEFeatures{}, true)
6666
require.Error(err, "ValidateBasic V1 SGX constraints without PCS support")
67-
err = sc.ValidateBasic(&TEEFeatures{SGX: TEEFeaturesSGX{PCS: true}})
67+
err = sc.ValidateBasic(&TEEFeatures{SGX: TEEFeaturesSGX{PCS: true}}, true)
6868
require.NoError(err, "ValidateBasic V1 SGX constraints")
6969
}
7070

go/common/sgx/pcs/policy.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ type QuotePolicy struct {
1616
// valid. TCB bundles containing smaller values will be invalid.
1717
MinTCBEvaluationDataNumber uint32 `json:"min_tcb_evaluation_data_number" yaml:"min_tcb_evaluation_data_number"`
1818

19+
// FMSPCWhitelist is a list of hexadecimal encoded FMSPCs specifying which processor
20+
// packages and platform instances are allowed.
21+
FMSPCWhitelist []string `json:"fmspc_whitelist,omitempty" yaml:"fmspc_whitelist,omitempty"`
22+
1923
// FMSPCBlacklist is a list of hexadecimal encoded FMSPCs specifying which processor
2024
// packages and platform instances are blocked.
2125
FMSPCBlacklist []string `json:"fmspc_blacklist,omitempty" yaml:"fmspc_blacklist,omitempty"`

go/common/sgx/pcs/quote.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ func (q *Quote) Verify(policy *QuotePolicy, ts time.Time, tcb *TCBBundle) (*sgx.
144144
policy = &QuotePolicy{
145145
TCBValidityPeriod: 30,
146146
MinTCBEvaluationDataNumber: DefaultMinTCBEvaluationDataNumber,
147-
FMSPCBlacklist: []string{},
147+
FMSPCWhitelist: make([]string, 0),
148+
FMSPCBlacklist: make([]string, 0),
148149
}
149150
}
150151

go/common/sgx/pcs/quote_test.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,37 @@ func TestQuoteV3_ECDSA_P256_PCK_CertificateChain(t *testing.T) {
121121
require.Error(err, "Quote verification should fail for invalid TCB evaluation data number")
122122
require.ErrorContains(err, "pcs/quote: failed to verify TCB bundle: pcs/tcb: failed to verify QE identity: pcs/tcb: invalid QE identity: pcs/tcb: invalid QE evaluation data number")
123123

124+
// Test whitelisted FMSPC.
125+
quotePolicy = &QuotePolicy{
126+
TCBValidityPeriod: 90,
127+
FMSPCWhitelist: []string{},
128+
}
129+
_, err = quote.Verify(quotePolicy, now, &tcbBundle)
130+
require.NoError(err, "Quote verification should succeed for whitelisted FMSPCs")
131+
132+
quotePolicy = &QuotePolicy{
133+
TCBValidityPeriod: 90,
134+
FMSPCWhitelist: []string{"00606A000000"},
135+
}
136+
_, err = quote.Verify(quotePolicy, now, &tcbBundle)
137+
require.NoError(err, "Quote verification should succeed for whitelisted FMSPCs")
138+
139+
quotePolicy = &QuotePolicy{
140+
TCBValidityPeriod: 90,
141+
FMSPCWhitelist: []string{"00606A000001"},
142+
}
143+
_, err = quote.Verify(quotePolicy, now, &tcbBundle)
144+
require.Error(err, "Quote verification should fail for non-whitelisted FMSPCs")
145+
require.ErrorContains(err, "pcs/quote: failed to verify TCB bundle: pcs/tcb: failed to verify TCB info: pcs/tcb: invalid TCB info: pcs/tcb: FMSPC is not whitelisted")
146+
124147
// Test blacklisted FMSPC.
125148
quotePolicy = &QuotePolicy{
126149
TCBValidityPeriod: 90,
127150
FMSPCBlacklist: []string{"00606A000000"},
128151
}
129152
_, err = quote.Verify(quotePolicy, now, &tcbBundle)
130153
require.Error(err, "Quote verification should fail for blacklisted FMSPCs")
131-
require.ErrorContains(err, "pcs/quote: failed to verify TCB bundle: pcs/tcb: failed to verify TCB info: pcs/tcb: invalid TCB info: pcs/tcb: blacklisted FMSPC")
154+
require.ErrorContains(err, "pcs/quote: failed to verify TCB bundle: pcs/tcb: failed to verify TCB info: pcs/tcb: invalid TCB info: pcs/tcb: FMSPC is blacklisted")
132155

133156
// Test TCB info certificates missing.
134157
tcbBundle2 := TCBBundle{

go/common/sgx/pcs/tcb.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,14 @@ func (ti *TCBInfo) validate(teeType TeeType, ts time.Time, policy *QuotePolicy)
270270
return fmt.Errorf("pcs/tcb: invalid TCB evaluation data number")
271271
}
272272

273-
// Validate FMSPC not blacklisted.
273+
// Validate FMSPC is whitelisted.
274+
if len(policy.FMSPCWhitelist) > 0 && !slices.Contains(policy.FMSPCWhitelist, ti.FMSPC) {
275+
return fmt.Errorf("pcs/tcb: FMSPC is not whitelisted")
276+
}
277+
278+
// Validate FMSPC is not blacklisted.
274279
if slices.Contains(policy.FMSPCBlacklist, ti.FMSPC) {
275-
return fmt.Errorf("pcs/tcb: blacklisted FMSPC")
280+
return fmt.Errorf("pcs/tcb: FMSPC is blacklisted")
276281
}
277282

278283
return nil

go/common/sgx/quote/quote.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,20 @@ type Policy struct {
6464
IAS *ias.QuotePolicy `json:"ias,omitempty" yaml:"ias,omitempty"`
6565
PCS *pcs.QuotePolicy `json:"pcs,omitempty" yaml:"pcs,omitempty"`
6666
}
67+
68+
// Validate validates the policy.
69+
func (p *Policy) Validate(isFeatureVersion242 bool) error {
70+
if isFeatureVersion242 {
71+
return nil
72+
}
73+
74+
if p.PCS == nil {
75+
return nil
76+
}
77+
78+
if len(p.PCS.FMSPCWhitelist) == 0 {
79+
return nil
80+
}
81+
82+
return fmt.Errorf("fmspc whitelist should be empty")
83+
}

go/common/sgx/quote/quote_test.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@ pcs:
1515
disabled: false
1616
tcb_validity_period: 30
1717
min_tcb_evaluation_data_number: 17
18-
fmspc_blacklist:
18+
fmspc_whitelist:
1919
- "000000000000"
2020
- "00606A000000"
21+
fmspc_blacklist:
22+
- "000000000001"
23+
- "00606A000001"
2124
`
2225
var dec Policy
2326
err := yaml.Unmarshal([]byte(testCase1), &dec)
@@ -27,7 +30,10 @@ pcs:
2730
require.EqualValues(false, dec.PCS.Disabled)
2831
require.EqualValues(30, dec.PCS.TCBValidityPeriod)
2932
require.EqualValues(17, dec.PCS.MinTCBEvaluationDataNumber)
33+
require.Len(dec.PCS.FMSPCWhitelist, 2)
34+
require.EqualValues("000000000000", dec.PCS.FMSPCWhitelist[0])
35+
require.EqualValues("00606A000000", dec.PCS.FMSPCWhitelist[1])
3036
require.Len(dec.PCS.FMSPCBlacklist, 2)
31-
require.EqualValues("000000000000", dec.PCS.FMSPCBlacklist[0])
32-
require.EqualValues("00606A000000", dec.PCS.FMSPCBlacklist[1])
37+
require.EqualValues("000000000001", dec.PCS.FMSPCBlacklist[0])
38+
require.EqualValues("00606A000001", dec.PCS.FMSPCBlacklist[1])
3339
}

0 commit comments

Comments
 (0)