diff --git a/.changelog/5728.internal.md b/.changelog/5728.internal.md new file mode 100644 index 00000000000..2095071b277 --- /dev/null +++ b/.changelog/5728.internal.md @@ -0,0 +1,5 @@ +runtime: Add VerifiedAttestation with more metadata + +Since verified attestations generated from TEE capabilities can include +additional metadata like the enclave's view of consensus layer height at +time of attestation, this allows such data to be used by callers. diff --git a/keymanager/src/churp/handler.rs b/keymanager/src/churp/handler.rs index d73bed4b022..a611def8831 100644 --- a/keymanager/src/churp/handler.rs +++ b/keymanager/src/churp/handler.rs @@ -1272,7 +1272,7 @@ impl Churp { fn remote_enclave(ctx: &RpcContext) -> Result<&EnclaveIdentity> { let si = ctx.session_info.as_ref(); let si = si.ok_or(Error::NotAuthenticated)?; - Ok(&si.verified_quote.identity) + Ok(&si.verified_attestation.quote.identity) } /// Returns true if key manager policies should be ignored. diff --git a/keymanager/src/runtime/secrets.rs b/keymanager/src/runtime/secrets.rs index 10b2b326829..b5210c1836c 100644 --- a/keymanager/src/runtime/secrets.rs +++ b/keymanager/src/runtime/secrets.rs @@ -513,7 +513,7 @@ impl Secrets { fn authenticate(ctx: &RpcContext) -> Result<&EnclaveIdentity> { let si = ctx.session_info.as_ref(); let si = si.ok_or(KeyManagerError::NotAuthenticated)?; - Ok(&si.verified_quote.identity) + Ok(&si.verified_attestation.quote.identity) } /// Fetch current epoch from the consensus layer. diff --git a/runtime/src/consensus/registry.rs b/runtime/src/consensus/registry.rs index de80d2a3dd9..939939a2bc8 100644 --- a/runtime/src/consensus/registry.rs +++ b/runtime/src/consensus/registry.rs @@ -161,7 +161,7 @@ impl CapabilityTEE { &self, policy: &sgx::QuotePolicy, node_id: &signature::PublicKey, - ) -> anyhow::Result { + ) -> anyhow::Result { match self.hardware { TEEHardware::TEEHardwareInvalid => bail!("invalid TEE hardware"), TEEHardware::TEEHardwareIntelSGX => { @@ -216,12 +216,12 @@ impl EndorsedCapabilityTEE { self.verify_endorsement()?; // Verify TEE capability. - let verified_quote = self + let verified_attestation = self .capability_tee .verify(policy, &self.node_endorsement.public_key)?; Ok(VerifiedEndorsedCapabilityTEE { - verified_quote, + verified_attestation, node_id: Some(self.node_endorsement.public_key), }) } @@ -230,16 +230,25 @@ impl EndorsedCapabilityTEE { /// A verified endorsed CapabilityTEE structure. #[derive(Clone, Debug, Default)] pub struct VerifiedEndorsedCapabilityTEE { - /// Verified TEE quote. - pub verified_quote: sgx::VerifiedQuote, + /// Verified TEE remote attestation. + pub verified_attestation: VerifiedAttestation, /// Optional identifier of the node that endorsed the TEE capability. pub node_id: Option, } +impl From for VerifiedEndorsedCapabilityTEE { + fn from(verified_attestation: VerifiedAttestation) -> Self { + Self { + verified_attestation, + node_id: None, + } + } +} + impl From for VerifiedEndorsedCapabilityTEE { fn from(verified_quote: sgx::VerifiedQuote) -> Self { Self { - verified_quote, + verified_attestation: verified_quote.into(), node_id: None, } } @@ -701,13 +710,17 @@ pub enum SGXConstraints { } impl SGXConstraints { - /// Checks whether the given enclave identity is whitelisted. - pub fn contains_enclave(&self, eid: &sgx::EnclaveIdentity) -> bool { - let enclaves = match self { + /// Identities of allowed enclaves. + pub fn enclaves(&self) -> &Vec { + match self { Self::V0 { ref enclaves, .. } => enclaves, Self::V1 { ref enclaves, .. } => enclaves, - }; - enclaves.contains(eid) + } + } + + /// Checks whether the given enclave identity is whitelisted. + pub fn contains_enclave(&self, eid: &sgx::EnclaveIdentity) -> bool { + self.enclaves().contains(eid) } /// SGX quote policy. @@ -730,6 +743,24 @@ impl SGXConstraints { } } +/// Verified remote attestation. +#[derive(Clone, Debug, Default)] +pub struct VerifiedAttestation { + /// Verified enclave quote. + pub quote: sgx::VerifiedQuote, + /// Enclave's view of the consensus layer height at the time of attestation. + pub height: Option, +} + +impl From for VerifiedAttestation { + fn from(quote: sgx::VerifiedQuote) -> Self { + Self { + quote, + height: None, + } + } +} + /// Intel SGX remote attestation. #[derive(Clone, Debug, cbor::Encode, cbor::Decode)] #[cbor(tag = "v")] @@ -783,7 +814,7 @@ impl SGXAttestation { node_id: &signature::PublicKey, rak: &signature::PublicKey, rek: &x25519::PublicKey, - ) -> anyhow::Result { + ) -> anyhow::Result { // Verify the quote. let verified_quote = self.quote().verify(policy)?; @@ -797,11 +828,14 @@ impl SGXAttestation { } => { let h = Self::hash(&verified_quote.report_data, node_id, *height, rek); signature.verify(rak, ATTESTATION_SIGNATURE_CONTEXT, &h)?; + + Ok(VerifiedAttestation { + quote: verified_quote, + height: Some(*height), + }) } _ => bail!("V0 attestation not supported"), } - - Ok(verified_quote) } } diff --git a/runtime/src/enclave_rpc/session.rs b/runtime/src/enclave_rpc/session.rs index 27cf5a14a33..6f406a2215c 100644 --- a/runtime/src/enclave_rpc/session.rs +++ b/runtime/src/enclave_rpc/session.rs @@ -9,10 +9,10 @@ use crate::{ common::{ crypto::signature::{self, PublicKey, Signature, Signer}, namespace::Namespace, - sgx::{ias, EnclaveIdentity, Quote, QuotePolicy, VerifiedQuote}, + sgx::{ias, EnclaveIdentity, Quote, QuotePolicy}, }, consensus::{ - registry::{EndorsedCapabilityTEE, VerifiedEndorsedCapabilityTEE}, + registry::{EndorsedCapabilityTEE, VerifiedAttestation, VerifiedEndorsedCapabilityTEE}, state::registry::ImmutableState as RegistryState, verifier::Verifier, }, @@ -53,8 +53,8 @@ enum SessionError { pub struct SessionInfo { /// RAK binding. pub rak_binding: RAKBinding, - /// Verified TEE quote. - pub verified_quote: VerifiedQuote, + /// Verified TEE remote attestation. + pub verified_attestation: VerifiedAttestation, /// Identifier of the node that endorsed the TEE. pub endorsed_by: Option, } @@ -281,7 +281,7 @@ impl Session { Ok(Some(Arc::new(SessionInfo { rak_binding, - verified_quote: vect.verified_quote, + verified_attestation: vect.verified_attestation, endorsed_by: vect.node_id, }))) } @@ -428,11 +428,11 @@ impl RAKBinding { // Ensure that the report data includes the hash of the node's RAK. // NOTE: For V2 this check is part of verify_inner so it is not really needed. - Identity::verify_binding(&vect.verified_quote, &self.rak_pub())?; + Identity::verify_binding(&vect.verified_attestation.quote, &self.rak_pub())?; // Verify MRENCLAVE/MRSIGNER. if let Some(ref remote_enclaves) = remote_enclaves { - if !remote_enclaves.contains(&vect.verified_quote.identity) { + if !remote_enclaves.contains(&vect.verified_attestation.quote.identity) { return Err(SessionError::MismatchedEnclaveIdentity.into()); } }