# Using Rust's `std` (EDP) https://edp.fortanix.com/docs/concepts/rust-std/ Links: [[EDP]], [[Rust]] ## Different functionality The following primitives work slightly differently than a “standard” operating environment, but should still work for most purposes. ## [Docs > Using Rust's `std`](https://edp.fortanix.com/docs/concepts/rust-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. ### Things that work directly - Environment variables: `std::env::vars` ### `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: - `Instant::now` - `Instant::elapsed` - `SystemTime::now` - `SystemTime::elapsed` **SECURITY WARNING**: Do not use the time obtained from these functions as the sole time source for making security decisions such as credential expiry. ### 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 infrastructure. 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: ```rust 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: ```rust 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: - `TcpStream::shutdown` - `TcpStream::set_nodelay` - `TcpStream::set_ttl` - `TcpStream::set_nonblocking` - `TcpListener::set_ttl` - `TcpListener::set_only_v6` - `TcpListener::set_nonblocking` The following functions in `std::net` return a default value: - `TcpStream::nodelay` - `TcpStream::ttl` - `TcpListener::ttl` - `TcpListener::only_v6` ## 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](https://github.com/fortanix/rust-sgx/issues/31). The following functions panic unconditionally: - `thread::sleep` - `thread::sleep_ms` - `thread::park_timeout` - `thread::park_timeout_ms` - `sync::Condvar::wait_timeout` 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: - `net::TcpStream::connect_timeout` - `net::TcpStream::set_read_timeout` - `net::TcpStream::set_write_timeout` The following functions always return a default value: - `net::TcpStream::read_timeout` - `net::TcpStream::write_timeout` ### `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 a blob sealed with authenticated encryption. #### 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](https://edp.fortanix.com/concepts/sgx/) for more information. Configuration data may also be appended after build but before signing, see [appending enclave data](https://edp.fortanix.com/docs/tasks/deployment/#creating-an-unsized-enclave-advanced). Configuration data that isn't relevant to security may be provided as a command-line argument, read from stdin, or appended as unmeasured data. ### Filesystem-related functionality in `std::env` In addition to the `fs` module being unavailable, the following functions in `std::env` always return an error: - `current_dir` - `current_exe` - `home_dir` - `join_paths` The following function does nothing but does not return an error: - `set_current_dir` The following functions panic unconditionally: - `split_paths` - `temp_dir` ### 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: - `spawn` - `output` - `status` 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](https://github.com/fortanix/rust-sgx/issues/75).