Skip to content

Commit 9ab9e08

Browse files
committed
go/common/sgx/pcs/policy: Add FMSP whitelist to quote policy
1 parent 631ddc1 commit 9ab9e08

10 files changed

Lines changed: 96 additions & 16 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/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_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
}

go/upgrade/migrations/consensus_242.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ import (
1111
// Consensus242 is the name of the upgrade that enables features introduced in Oasis Core 24.2.
1212
//
1313
// This upgrade includes:
14-
// - The `MayQuery field in the CHURP SGX policy, which defines which enclave identities
14+
// - The `MayQuery` field in the CHURP SGX policy, which defines which enclave identities
1515
// are allowed to query runtime key shares.
16+
// - The `FMSPCWhitelist` field in the quote policy, which defines which processor packages
17+
// and platform instances are allowed.
1618
// - An updated key manager policy update transaction that applies a new policy at the epoch
1719
// boundary.
1820
const Consensus242 = "consensus242"

runtime/src/common/sgx/pcs/mod.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ pub enum Error {
4141
TCBMismatch,
4242
#[error("TCB evaluation data number is invalid")]
4343
TCBEvaluationDataNumberInvalid,
44+
#[error("FMSPC is not whitelisted")]
45+
NotWhitelistedFMSPC,
4446
#[error("FMSPC is blacklisted")]
4547
BlacklistedFMSPC,
4648
#[error("QE report is malformed")]
@@ -217,19 +219,48 @@ mod tests {
217219
}
218220

219221
#[test]
220-
fn test_quote_blacklisted_fmscp() {
222+
fn test_quote_whitelisted_fmscp() {
221223
// From Go implementation.
222224
const RAW_QUOTE_BUNDLE: &[u8] =
223225
include_bytes!("../../../../testdata/pcs_quote_bundle.cbor");
224226

225227
let qb: QuoteBundle = cbor::from_slice(RAW_QUOTE_BUNDLE).unwrap();
228+
let now = Utc.timestamp_opt(1671497404, 0).unwrap();
229+
230+
let policy = &QuotePolicy {
231+
..Default::default()
232+
};
233+
qb.verify(policy, now)
234+
.expect("quote verification should succeed for whitelisted FMSPCs");
235+
236+
let policy = &QuotePolicy {
237+
fmspc_whitelist: vec!["00606A000000".to_string()],
238+
..Default::default()
239+
};
240+
qb.verify(policy, now)
241+
.expect("quote verification should succeed for whitelisted FMSPCs");
242+
243+
let policy: &QuotePolicy = &QuotePolicy {
244+
fmspc_whitelist: vec!["00606A000001".to_string()],
245+
..Default::default()
246+
};
247+
qb.verify(policy, now)
248+
.expect_err("quote verification should fail for non-whitelisted FMSPCs");
249+
}
226250

251+
#[test]
252+
fn test_quote_blacklisted_fmscp() {
253+
// From Go implementation.
254+
const RAW_QUOTE_BUNDLE: &[u8] =
255+
include_bytes!("../../../../testdata/pcs_quote_bundle.cbor");
256+
257+
let qb: QuoteBundle = cbor::from_slice(RAW_QUOTE_BUNDLE).unwrap();
227258
let now = Utc.timestamp_opt(1671497404, 0).unwrap();
259+
228260
let policy = &QuotePolicy {
229261
fmspc_blacklist: vec!["00606A000000".to_string()],
230262
..Default::default()
231263
};
232-
233264
qb.verify(policy, now)
234265
.expect_err("quote verification should fail for blacklisted FMSPCs");
235266
}

runtime/src/common/sgx/pcs/policy.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ pub struct QuotePolicy {
1515
/// smaller values will be invalid.
1616
pub min_tcb_evaluation_data_number: u32,
1717

18+
/// A list of hexadecimal encoded FMSPCs specifying which processor packages and platform
19+
/// instances are allowed.
20+
#[cbor(optional)]
21+
pub fmspc_whitelist: Vec<String>,
22+
1823
/// A list of hexadecimal encoded FMSPCs specifying which processor packages and platform
1924
/// instances are blocked.
2025
#[cbor(optional)]
@@ -31,6 +36,7 @@ impl Default for QuotePolicy {
3136
disabled: false,
3237
tcb_validity_period: 30,
3338
min_tcb_evaluation_data_number: DEFAULT_MIN_TCB_EVALUATION_DATA_NUMBER,
39+
fmspc_whitelist: Vec::new(),
3440
fmspc_blacklist: Vec::new(),
3541
tdx: None,
3642
}

runtime/src/common/sgx/pcs/tcb.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -229,12 +229,13 @@ impl TCBInfo {
229229
return Err(Error::TCBEvaluationDataNumberInvalid);
230230
}
231231

232-
// Validate FMSPC not blacklisted.
233-
let blocked = policy
234-
.fmspc_blacklist
235-
.iter()
236-
.any(|blocked| blocked == &self.fmspc);
237-
if blocked {
232+
// Validate FMSPC is whitelisted.
233+
if !policy.fmspc_whitelist.is_empty() && !policy.fmspc_whitelist.contains(&self.fmspc) {
234+
return Err(Error::NotWhitelistedFMSPC);
235+
}
236+
237+
// Validate FMSPC is not blacklisted.
238+
if policy.fmspc_blacklist.contains(&self.fmspc) {
238239
return Err(Error::BlacklistedFMSPC);
239240
}
240241

0 commit comments

Comments
 (0)