1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
//! Functionality related to the enclave attestation flow.
use std::sync::Arc;

use anyhow::{bail, Result};
use slog::{info, Logger};

use crate::{
    app::App,
    common::{
        crypto::signature::Signer, logger::get_logger, namespace::Namespace, panic::AbortOnPanic,
        sgx::Quote, version::Version,
    },
    consensus::{
        registry::{EndorsedCapabilityTEE, SGXAttestation, ATTESTATION_SIGNATURE_CONTEXT},
        verifier::Verifier,
    },
    host::Host,
    identity::Identity,
    policy::PolicyVerifier,
    types::Body,
};

/// Attestation flow handler.
#[derive(Clone)]
pub struct Handler {
    identity: Arc<Identity>,
    host: Arc<dyn Host>,
    consensus_verifier: Arc<dyn Verifier>,
    runtime_id: Namespace,
    version: Version,
    app: Arc<dyn App>,
    logger: Logger,
}

impl Handler {
    /// Create a new instance of the attestation flow handler.
    pub fn new(
        identity: Arc<Identity>,
        host: Arc<dyn Host>,
        consensus_verifier: Arc<dyn Verifier>,
        runtime_id: Namespace,
        version: Version,
        app: Arc<dyn App>,
    ) -> Self {
        Self {
            identity,
            host,
            consensus_verifier,
            runtime_id,
            version,
            app,
            logger: get_logger("runtime/attestation"),
        }
    }
}

impl Handler {
    /// Handle an attestation flow request.
    pub async fn handle(&self, request: Body) -> Result<Body> {
        match request {
            Body::RuntimeCapabilityTEERakInitRequest { target_info } => {
                self.target_info_init(target_info)
            }
            Body::RuntimeCapabilityTEERakReportRequest {} => self.report_init(),
            Body::RuntimeCapabilityTEERakAvrRequest { avr } => {
                // TODO: Remove this once we want to break the runtime host protocol.
                self.set_quote(Quote::Ias(avr)).await
            }
            Body::RuntimeCapabilityTEERakQuoteRequest { quote } => self.set_quote(quote).await,
            Body::RuntimeCapabilityTEEUpdateEndorsementRequest { ect } => {
                self.update_endorsement(ect).await
            }

            _ => bail!("unsupported attestation request"),
        }
    }

    fn target_info_init(&self, target_info: Vec<u8>) -> Result<Body> {
        // Make sure to abort the process on panics during attestation process.
        let _guard = AbortOnPanic;

        info!(self.logger, "Initializing the runtime target info");
        self.identity.init_target_info(target_info)?;
        Ok(Body::RuntimeCapabilityTEERakInitResponse {})
    }

    fn report_init(&self) -> Result<Body> {
        // Make sure to abort the process on panics during attestation process.
        let _guard = AbortOnPanic;

        info!(self.logger, "Initializing the runtime key report");
        let (rak_pub, rek_pub, report, nonce) = self.identity.init_report()?;

        Ok(Body::RuntimeCapabilityTEERakReportResponse {
            rak_pub,
            rek_pub,
            report,
            nonce,
        })
    }

    async fn set_quote_policy(&self) -> Result<()> {
        info!(self.logger, "Configuring quote policy");

        // Use the correct quote policy for verifying our own identity based on what kind of
        // application this is. For ROFL, ask the application, for RONL, query consensus.
        let policy = if self.app.is_rofl() {
            // ROFL, ask the app for policy.
            self.app.quote_policy().await?
        } else {
            // RONL.
            // TODO: Make async.
            let consensus_verifier = self.consensus_verifier.clone();
            let version = self.version;
            let runtime_id = self.runtime_id;
            tokio::task::block_in_place(move || {
                // Obtain current quote policy from (verified) consensus state.
                PolicyVerifier::new(consensus_verifier).quote_policy(&runtime_id, Some(version))
            })?
        };

        self.identity.set_quote_policy(policy)?;

        Ok(())
    }

    async fn set_quote(&self, quote: Quote) -> Result<Body> {
        // Make sure to abort the process on panics during attestation process.
        let _guard = AbortOnPanic;

        // Ensure a quote policy is configured.
        self.set_quote_policy().await?;

        info!(
            self.logger,
            "Configuring quote for the runtime attestation key binding"
        );

        // Configure the quote and policy on the identity.
        let node_id = self.host.identity().await?;
        let verified_quote = self.identity.set_quote(node_id, quote)?;

        // Sign the report data, latest verified consensus height, REK and host node ID.
        let consensus_state = self.consensus_verifier.latest_state().await?;
        let height = consensus_state.height();
        let rek = self.identity.public_rek();
        let h = SGXAttestation::hash(&verified_quote.report_data, &node_id, height, &rek);
        let signature = self.identity.sign(ATTESTATION_SIGNATURE_CONTEXT, &h)?;

        Ok(Body::RuntimeCapabilityTEERakQuoteResponse { height, signature })
    }

    async fn update_endorsement(&self, ect: EndorsedCapabilityTEE) -> Result<Body> {
        info!(self.logger, "Updating endorsed TEE capability");

        // Update the endorsed TEE capability. This also performs the necessary verification.
        self.identity.set_endorsed_capability_tee(ect)?;

        Ok(Body::RuntimeCapabilityTEEUpdateEndorsementResponse {})
    }
}