Join our public slack channel for support, discussions and more...
Contents

Using Rust's std

Most of Rust's standard library is available: collections and data structures, synchronization primitives, threading, streaming network connections, etc. Some parts of the standard library work slightly differently than you're used to and other parts don't work at all. This page documents all the differences.

Different functionality

The following primitives work slightly differently than a “standard” operating environment, but should still work for most purposes.

std::env::vars and friends

Environment variables can be read, written, and removed as normal. Note that, for security, enclave applications start with an empty environment. There is no way to inject environment variables from userspace. You can of course set whatever variables you want at the start of your program in fn main:

1
2
3
4
fn main() {
    std::env::set_var("RUST_BACKTRACE", "1");
    panic!("Expecting a backtrace");
}

std::is_x86_feature_detected

The is_x86_feature_detected! macro is used to detect available CPU features. Since the CPUID instruction is not supported in SGX, this returns false for any features not enabled at compile-time. Improvements are planned in GitHub issue #26.

std::time

Timekeeping in secure enclaves is an unsolved problem. The following functions use the current time as reported by the Operating System, which may or may not be the actual current time:

Security warning

Do not use the time obtained from these functions as the sole time source for making security decisions such as credential expiry.

std::os::fortanix_sgx

Just like other platforms, the Fortanix SGX target has its own module in std with platform-specific functionality. View the fortanix_sgx API documentation.

Stream networking

Stream networking using TCP as exposed by the std::net module is supported.

Security warning

An enclave can't trust the OS or the rest of the infrastructure to do things in networking correctly. Enclave applications should use cryptographic protocols (such as TLS) with authentication of remote parties (such as remote attestation or TLS certificates) to ensure correct operation of the network infrastrucutre.

Hostname resolution is not done in the enclave, but by userspace. Therefore, using std::net::ToSocketAddrs for hostname resolution is not supported. You must pass the hostname directly to TcpStream::connect. For example, this won't work:

1
2
3
4
fn connect_sdkms() -> io::Result<TcpStream> {
    let addrs = "sdkms.fortanix.com:443".to_socket_addrs()?.collect();
    TcpStream::connect(Vec::as_slice(&addrs))
}

But this will:

1
2
3
fn connect_sdkms() -> IoResult<TcpStream> {
    TcpStream::connect("sdkms.fortanix.com:443")
}

Advanced socket options

Because the enclave can't rely on any particular behavior from the operating system, advanced socket options are not supported. The following functions in std::net do nothing but don't return an error:

The following functions in std::net return a default value:

Restricted functionality

Some primitives don't work when compiling for x86_64-fortanix-unknown-sgx. The following sections describe which behavior you get when these primitives are called and what alternatives exist.

Timeouts

As mentioned above, timekeeping in secure enclaves is problematic, and the OS can trivially deny service to an enclave. Therefore, the utility of timeout functions in enclave applications is unclear. Currently, timeouts are not supported at all. Improvements are planned in GitHub issue #31.

The following functions panic unconditionally:

Instead of blocking if the channel is empty, sync::mpsc::Receiver::recv_timeout will either panic or return prematurely indicating the timeout was reached.

The following functions don't configure a timeout at all and revert back to default behavior:

The following functions always return a default value:

std::fs

No filesystem is available in the enclave for security reasons. All functions in std::fs return an error when called. Depending on your scenario, you can use one of the following recommended alternatives.

Storing persistent data

Use a storage or database service to store an blob sealed with authenticated encryption.

Security warning

When reading from an untrusted storage or database service, the service may perform a rollback attack by not returning the latest stored data. One possible defense against this attack is to use a trusted freshness tracking service.

Also, if your enclave stores more than one blob, the service may perform a partial rollback attack by returing different versions of different blobs. One possible defense against this attack is to track the integrity of all blobs as a whole, for example with a Merkle tree.

Configuration files

Configuration that affects security parameters should be compiled into the enclave so that it is included in the enclave measurement. See enclave identity for more information. Configuration data may also be appended after build but before signing, see appending enclave data.

Configuration data that isn't relevant to security may be provided as a command-line argument, read from stdin, or appended as unmeasured data.

In addition to the fs module being unavailable, the following functions in std::env always return an error:

The following function does nothing but does not return an error:

The following functions panic unconditionally:

Processes

Multi-processing is not supported. Instead, call out to network services to interact with out-of-enclave functionality.

The following methods in std::process::Command always return an error:

The std::process::id function panics unconditionally.

std::net::UdpSocket

Datagram networking is not supported. UdpSocket::bind always returns an error. Support is being considered in GitHub issue #75.

Contents