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
162
163
164
165
166
167
168
169
170
//! Oasis Core runtime SDK.
//!
//! # Examples
//!
//! To create a minimal runtime that doesn't expose any APIs to the
//! outside world, you need to call the `start_runtime` function:
//! ```rust,ignore
//! oasis_core_runtime::start_runtime(Some(Box::new(reg)), config);
//! ```
//!
//! This will start the required services needed to communicate with
//! the worker host.
#![feature(test)]
#![feature(arbitrary_self_types)]
#![feature(const_option)]

use lazy_static::lazy_static;
#[cfg(target_env = "sgx")]
use sgx_isa::{AttributesFlags, Report};

#[cfg_attr(test, macro_use)]
extern crate base64_serde;

#[macro_use]
pub mod common;
pub mod app;
mod attestation;
pub mod cache;
pub mod config;
pub mod consensus;
pub mod dispatcher;
pub mod enclave_rpc;
pub mod future;
pub mod host;
pub mod identity;
pub mod init;
pub mod policy;
pub mod protocol;
pub mod storage;
pub mod transaction;
pub mod types;

use common::{
    sgx::{EnclaveIdentity, MrSigner},
    version::{Version, PROTOCOL_VERSION},
};

// Validate features.
#[cfg(all(target_env = "sgx", feature = "debug-mock-sgx"))]
compile_error!("the debug-mock-sgx feature can only be enabled on non-sgx targets");

#[cfg(all(target_env = "sgx", feature = "tdx"))]
compile_error!("the tdx feature can only be enabled on non-sgx targets");

#[cfg(all(feature = "tdx", feature = "debug-mock-sgx"))]
compile_error!("the tdx feature can't be enabled together with debug-mock-sgx");

lazy_static! {
    pub static ref BUILD_INFO: BuildInfo = {
        // Determine TEE type.
        let tee_type = if cfg!(any(target_env = "sgx", feature = "debug-mock-sgx")) {
            TeeType::Sgx
        } else if cfg!(feature = "tdx") {
            TeeType::Tdx
        } else {
            TeeType::None
        };

        // Determine build security.
        #[allow(clippy::let_and_return)]
        let is_secure = match tee_type {
            TeeType::Sgx => {
                // SGX build security depends on how it was built.
                //
                // Optimistically start out as "it could be secure", and any single insecure build time
                // option will propagate failure.
                let maybe_secure = true;

                // Quote signature verification MUST be enabled.
                let maybe_secure = maybe_secure && option_env!("OASIS_UNSAFE_SKIP_AVR_VERIFY").is_none();

                // Disallow debug enclaves MUST be enabled.
                let maybe_secure = maybe_secure && option_env!("OASIS_UNSAFE_ALLOW_DEBUG_ENCLAVES").is_none();

                // Attestation `OutOfDate` and `ConfigurationNeeded` responses MUST count as attestation
                // failure.
                //
                // Rationale: This is how remote attestation signifies that the host environment is
                // insecure (eg: SMT is enabled when it should not be).
                let maybe_secure = maybe_secure && option_env!("OASIS_UNSAFE_LAX_AVR_VERIFY").is_none();

                // The enclave MUST NOT be a debug one.
                #[cfg(target_env = "sgx")]
                let maybe_secure = maybe_secure && !Report::for_self().attributes.flags.contains(AttributesFlags::DEBUG);

                // The enclave MUST NOT be signed by a test key,
                let enclave_identity = EnclaveIdentity::current().unwrap();
                let fortanix_mrsigner = MrSigner::from("9affcfae47b848ec2caf1c49b4b283531e1cc425f93582b36806e52a43d78d1a");
                let maybe_secure = maybe_secure && (enclave_identity.mr_signer != fortanix_mrsigner);

                maybe_secure
            }
            TeeType::Tdx => {
                // TDX build security depends on how it was built.
                //
                // Optimistically start out as "it could be secure", and any single insecure build time
                // option will propagate failure.
                let maybe_secure = true;

                // Quote signature verification MUST be enabled.
                let maybe_secure = maybe_secure && option_env!("OASIS_UNSAFE_SKIP_AVR_VERIFY").is_none();

                // Disallow debug enclaves MUST be enabled.
                let maybe_secure = maybe_secure && option_env!("OASIS_UNSAFE_ALLOW_DEBUG_ENCLAVES").is_none();

                // Attestation `OutOfDate` and `ConfigurationNeeded` responses MUST count as attestation
                // failure.
                //
                // Rationale: This is how remote attestation signifies that the host environment is
                // insecure (eg: SMT is enabled when it should not be).
                let maybe_secure = maybe_secure && option_env!("OASIS_UNSAFE_LAX_AVR_VERIFY").is_none();

                // TODO: Debug TD attributes.

                maybe_secure
            }
            TeeType::None => {
                // Non-TEE builds are insecure by definition.
                false
            }
        };

        BuildInfo {
            tee_type,
            protocol_version: PROTOCOL_VERSION,
            is_secure,
        }
    };
}

/// TEE type this build is for.
#[derive(Debug, Default, PartialEq, Eq)]
pub enum TeeType {
    #[default]
    None,
    Sgx,
    Tdx,
}

/// Runtime build information.
#[derive(Debug)]
pub struct BuildInfo {
    /// TEE type this build is for.
    pub tee_type: TeeType,
    /// Supported runtime protocol version.
    pub protocol_version: Version,
    /// True iff the build can provide integrity and confidentiality.
    pub is_secure: bool,
}

// Re-exports.
pub use self::{
    enclave_rpc::{demux::Demux as RpcDemux, dispatcher::Dispatcher as RpcDispatcher},
    init::start_runtime,
    protocol::Protocol,
    transaction::dispatcher::Dispatcher as TxnDispatcher,
};

// Re-export the cbor crate.
pub use cbor;