diff --git a/.changelog/5113.breaking.md b/.changelog/5113.breaking.md new file mode 100644 index 00000000000..61c62975384 --- /dev/null +++ b/.changelog/5113.breaking.md @@ -0,0 +1 @@ +go/sgx/ias: Add support for blacklisting GIDs diff --git a/go/common/sgx/ias/avr.go b/go/common/sgx/ias/avr.go index 598b821d000..0af32a1ece8 100644 --- a/go/common/sgx/ias/avr.go +++ b/go/common/sgx/ias/avr.go @@ -81,6 +81,9 @@ type QuotePolicy struct { // // Note: QuoteOK and QuoteSwHardeningNeeded are ALWAYS allowed, and do not need to be specified. AllowedQuoteStatuses []ISVEnclaveQuoteStatus `json:"allowed_quote_statuses,omitempty"` + + // GIDBlackList is a list of blocked platform EPID group IDs. + GIDBlacklist []uint32 `json:"gid_blacklist,omitempty"` } // ISVEnclaveQuoteStatus is the status of an enclave quote. @@ -216,6 +219,17 @@ func (b *AVRBundle) Open(policy *QuotePolicy, trustRoots *x509.CertPool, ts time return nil, fmt.Errorf("quote status not allowed by policy") } + quote, err := avr.Quote() + if err != nil { + return nil, fmt.Errorf("quote open failure: %w", err) + } + // Validate EPID GID not blacklisted. + for _, blocked := range policy.GIDBlacklist { + if blocked == quote.Body.GID { + return nil, fmt.Errorf("blacklisted quote GID") + } + } + return avr, nil } diff --git a/go/common/sgx/ias/quote_test.go b/go/common/sgx/ias/quote_test.go index b76e2ab7265..70d21fae097 100644 --- a/go/common/sgx/ias/quote_test.go +++ b/go/common/sgx/ias/quote_test.go @@ -68,4 +68,20 @@ func TestQuote(t *testing.T) { bQuote, err := quote.MarshalBinary() require.NoError(t, err, "EncodeQuote") require.Equal(t, rawQuote, bQuote, "BinaryQuote") + + // Test blacklisted GID. + bundle := &AVRBundle{ + Body: raw, + Signature: sig, + CertificateChain: certs, + } + quotePolicy := &QuotePolicy{ + GIDBlacklist: []uint32{}, + } + _, err = bundle.Open(quotePolicy, IntelTrustRoots, time.Now()) + require.NoError(t, err, "AVRBundle.Open") + + quotePolicy.GIDBlacklist = []uint32{quote.Body.GID} + _, err = bundle.Open(quotePolicy, IntelTrustRoots, time.Now()) + require.Error(t, err, "AVRBundle.Open should fail with blacklisted GID") } diff --git a/runtime/src/common/sgx/ias.rs b/runtime/src/common/sgx/ias.rs index 19fdd7e5b58..2417c239dcb 100644 --- a/runtime/src/common/sgx/ias.rs +++ b/runtime/src/common/sgx/ias.rs @@ -55,6 +55,8 @@ enum AVRError { InvalidSignature, #[error("IAS quotes are disabled by policy")] Disabled, + #[error("blacklisted IAS quote GID")] + BlacklistedGID, } pub const QUOTE_CONTEXT_LEN: usize = 8; @@ -128,6 +130,10 @@ pub struct QuotePolicy { /// specified. #[cbor(optional)] pub allowed_quote_statuses: Vec, // TODO: Define ISVEnclaveQuoteStatus type. + + /// List of blocked platform EPID group IDs. + #[cbor(optional)] + pub gid_blacklist: Vec, } /// Decoded quote body. @@ -280,6 +286,15 @@ pub fn verify(avr: &AVR, policy: &QuotePolicy) -> Result { _ => return Err(AVRError::MalformedQuote.into()), }; + // Verify EPID GID not blacklisted. + if policy + .gid_blacklist + .iter() + .any(|gid| gid == "e_body.gid) + { + return Err(AVRError::BlacklistedGID.into()); + } + // Disallow debug enclaves, if we are in production environment and disallow production enclaves, // if we are in debug environment. let is_debug = quote_body diff --git a/runtime/src/consensus/registry.rs b/runtime/src/consensus/registry.rs index 3274e61b07d..3d04afe89a9 100644 --- a/runtime/src/consensus/registry.rs +++ b/runtime/src/consensus/registry.rs @@ -551,6 +551,7 @@ impl SGXConstraints { ias: Some(sgx::ias::QuotePolicy { disabled: false, allowed_quote_statuses: allowed_quote_statuses.clone(), + gid_blacklist: Vec::new(), }), ..Default::default() },