oasis_core_runtime/
attestation.rs

1//! Functionality related to the enclave attestation flow.
2use std::sync::Arc;
3
4use anyhow::{bail, Result};
5use slog::{info, Logger};
6
7use crate::{
8    app::App,
9    common::{
10        crypto::signature::Signer, logger::get_logger, namespace::Namespace, panic::AbortOnPanic,
11        sgx::Quote, version::Version,
12    },
13    consensus::{
14        registry::{EndorsedCapabilityTEE, SGXAttestation, ATTESTATION_SIGNATURE_CONTEXT},
15        verifier::Verifier,
16    },
17    host::Host,
18    identity::Identity,
19    policy::PolicyVerifier,
20    types::Body,
21};
22
23/// Attestation flow handler.
24#[derive(Clone)]
25pub struct Handler {
26    identity: Arc<Identity>,
27    host: Arc<dyn Host>,
28    consensus_verifier: Arc<dyn Verifier>,
29    runtime_id: Namespace,
30    version: Version,
31    app: Arc<dyn App>,
32    logger: Logger,
33}
34
35impl Handler {
36    /// Create a new instance of the attestation flow handler.
37    pub fn new(
38        identity: Arc<Identity>,
39        host: Arc<dyn Host>,
40        consensus_verifier: Arc<dyn Verifier>,
41        runtime_id: Namespace,
42        version: Version,
43        app: Arc<dyn App>,
44    ) -> Self {
45        Self {
46            identity,
47            host,
48            consensus_verifier,
49            runtime_id,
50            version,
51            app,
52            logger: get_logger("runtime/attestation"),
53        }
54    }
55}
56
57impl Handler {
58    /// Handle an attestation flow request.
59    pub async fn handle(&self, request: Body) -> Result<Body> {
60        match request {
61            Body::RuntimeCapabilityTEERakInitRequest { target_info } => {
62                self.target_info_init(target_info)
63            }
64            Body::RuntimeCapabilityTEERakReportRequest {} => self.report_init(),
65            Body::RuntimeCapabilityTEERakAvrRequest { avr } => {
66                // TODO: Remove this once we want to break the runtime host protocol.
67                self.set_quote(Quote::Ias(avr)).await
68            }
69            Body::RuntimeCapabilityTEERakQuoteRequest { quote } => self.set_quote(quote).await,
70            Body::RuntimeCapabilityTEEUpdateEndorsementRequest { ect } => {
71                self.update_endorsement(ect).await
72            }
73
74            _ => bail!("unsupported attestation request"),
75        }
76    }
77
78    fn target_info_init(&self, target_info: Vec<u8>) -> Result<Body> {
79        // Make sure to abort the process on panics during attestation process.
80        let _guard = AbortOnPanic;
81
82        info!(self.logger, "Initializing the runtime target info");
83        self.identity.init_target_info(target_info)?;
84        Ok(Body::RuntimeCapabilityTEERakInitResponse {})
85    }
86
87    fn report_init(&self) -> Result<Body> {
88        // Make sure to abort the process on panics during attestation process.
89        let _guard = AbortOnPanic;
90
91        info!(self.logger, "Initializing the runtime key report");
92        let (rak_pub, rek_pub, report, nonce) = self.identity.init_report()?;
93
94        Ok(Body::RuntimeCapabilityTEERakReportResponse {
95            rak_pub,
96            rek_pub,
97            report,
98            nonce,
99        })
100    }
101
102    async fn set_quote_policy(&self) -> Result<()> {
103        info!(self.logger, "Configuring quote policy");
104
105        // Use the correct quote policy for verifying our own identity based on what kind of
106        // application this is. For ROFL, ask the application, for RONL, query consensus.
107        let policy = if self.app.is_rofl() {
108            // ROFL, ask the app for policy.
109            self.app.quote_policy().await?
110        } else {
111            // RONL.
112            // TODO: Make async.
113            let consensus_verifier = self.consensus_verifier.clone();
114            let version = self.version;
115            let runtime_id = self.runtime_id;
116            tokio::task::block_in_place(move || {
117                // Obtain current quote policy from (verified) consensus state.
118                PolicyVerifier::new(consensus_verifier).quote_policy(&runtime_id, Some(version))
119            })?
120        };
121
122        self.identity.set_quote_policy(policy)?;
123
124        Ok(())
125    }
126
127    async fn set_quote(&self, quote: Quote) -> Result<Body> {
128        // Make sure to abort the process on panics during attestation process.
129        let _guard = AbortOnPanic;
130
131        // Ensure a quote policy is configured.
132        self.set_quote_policy().await?;
133
134        info!(
135            self.logger,
136            "Configuring quote for the runtime attestation key binding"
137        );
138
139        // Configure the quote and policy on the identity.
140        let node_id = self.host.identity().await?;
141        let verified_quote = self.identity.set_quote(node_id, quote)?;
142
143        // Sign the report data, latest verified consensus height, REK and host node ID.
144        let consensus_state = self.consensus_verifier.latest_state().await?;
145        let height = consensus_state.height();
146        let rek = self.identity.public_rek();
147        let h = SGXAttestation::hash(&verified_quote.report_data, &node_id, height, &rek);
148        let signature = self.identity.sign(ATTESTATION_SIGNATURE_CONTEXT, &h)?;
149
150        Ok(Body::RuntimeCapabilityTEERakQuoteResponse { height, signature })
151    }
152
153    async fn update_endorsement(&self, ect: EndorsedCapabilityTEE) -> Result<Body> {
154        info!(self.logger, "Updating endorsed TEE capability");
155
156        // Update the endorsed TEE capability. This also performs the necessary verification.
157        self.identity.set_endorsed_capability_tee(ect)?;
158
159        Ok(Body::RuntimeCapabilityTEEUpdateEndorsementResponse {})
160    }
161}