SecureValueRecovery2/enclave
Graeme Connell e61eab3f32
Some checks failed
CI / test (push) Has been cancelled
Enclave releases: 24s.ced8217b, 2s.3c699f49, 8s.2048e20f
2026-04-17 10:01:45 -07:00
..
attestation Log OpenEnclave errors everywhere we can. 2025-07-17 10:07:49 -07:00
boringssl@eb895133fb Update dependencies. 2025-09-25 13:28:57 -07:00
client Use ADs to protect multipart Noise messages from truncation. 2026-04-15 10:58:24 -07:00
context Try to push out all current logs when we crash. 2024-01-24 10:03:16 -07:00
core Gate high-value operations on attestation from quorum timestamp 2026-04-17 09:48:10 -07:00
db Check for TRIES==0 during DB2 replication. 2026-04-08 14:37:48 -07:00
ecalls Squashed history. 2023-05-05 16:25:12 -06:00
env Log OpenEnclave errors everywhere we can. 2025-07-17 10:07:49 -07:00
fs Some better GCPSNP errors/names. 2024-04-12 11:20:06 -06:00
googletest@52eb8108c5 Update dependencies. 2025-09-25 13:28:57 -07:00
groupclock Gate high-value operations on attestation from quorum timestamp 2026-04-17 09:48:10 -07:00
gtest Squashed history. 2023-05-05 16:25:12 -06:00
hmac Ristretto type-safety, test fix, and SHA256/512 refactoring. 2024-08-07 09:05:42 -07:00
initmain Get AMD SEV-SNP attestation report. 2023-06-14 15:23:45 -06:00
libsodium@d24faf5621 Update dependencies and release new enclaves. 2026-01-09 11:39:47 -08:00
merkle Ristretto type-safety, test fix, and SHA256/512 refactoring. 2024-08-07 09:05:42 -07:00
metrics Gate high-value operations on attestation from quorum timestamp 2026-04-17 09:48:10 -07:00
minimums Fix handling of multi-key minimums::MinimumLimits. 2024-05-03 16:21:11 -06:00
noise Use ADs to protect multipart Noise messages from truncation. 2026-04-15 10:58:24 -07:00
noise-c@6d94035818 Update noise-c to use mlkem-libjade for ML-KEM-1024 2026-02-12 11:43:12 -08:00
noisewrap Add context into Env API to enable monitoring. 2023-06-21 08:58:08 -06:00
peerid Clean up SIP-hash C++ library to avoid "extern C" includes. 2023-11-15 10:57:28 -07:00
peers Gate high-value operations on attestation from quorum timestamp 2026-04-17 09:48:10 -07:00
proto SVRB-specific, stripped-down SVR, storing as little as possible while maintaining security. 2025-08-06 09:19:32 -07:00
protobuf@dab4d24d44 Squashed history. 2023-05-05 16:25:12 -06:00
protobuf-lite Squashed history. 2023-05-05 16:25:12 -06:00
queue Try to push out all current logs when we crash. 2024-01-24 10:03:16 -07:00
raft SVR4 - test and fix issues with DB4 replication. 2024-08-23 17:15:54 -07:00
rapidjson@24b5e7a8b2 Update dependencies. 2025-09-25 13:28:57 -07:00
releases Enclave releases: 24s.ced8217b, 2s.3c699f49, 8s.2048e20f 2026-04-17 10:01:45 -07:00
ristretto Allow single-server use by allowing zero_secretshare to be zero. 2025-07-17 11:40:48 -07:00
sender Try to push out all current logs when we crash. 2024-01-24 10:03:16 -07:00
sev-guest@62317d7de4 AMD SEV-SNP attestation verification. 2023-06-22 13:03:09 -06:00
sevtypes AMD SEV-SNP attestation verification. 2023-06-22 13:03:09 -06:00
sha Ristretto type-safety, test fix, and SHA256/512 refactoring. 2024-08-07 09:05:42 -07:00
sip Try to push out all current logs when we crash. 2024-01-24 10:03:16 -07:00
SipHash@68c8a7cb77 Update submodules/dependencies. 2023-11-15 10:56:53 -07:00
socketmain Optimize writes by using a byte double-buffer to avoid write lock contention. 2024-03-06 10:32:34 -07:00
socketwrap Optimize writes by using a byte double-buffer to avoid write lock contention. 2024-03-06 10:32:34 -07:00
svr2 Squashed history. 2023-05-05 16:25:12 -06:00
testhost Nitro attestation 2023-05-24 09:44:47 -06:00
timeout Code cleanup, fixes, and tests. 2024-09-26 15:59:59 -07:00
tinycbor@c0aad2fb21 Update dependencies. 2025-09-25 13:28:57 -07:00
util Clear keys on destructor as well as move. 2025-07-02 09:45:50 -07:00
.gitignore Squashed history. 2023-05-05 16:25:12 -06:00
find_header.sh Squashed history. 2023-05-05 16:25:12 -06:00
Makefile Update dependencies. 2025-09-25 13:28:57 -07:00
Makefile.base Update to Ubuntu 22.04 and Debian 12. 2025-03-21 15:06:38 -07:00
Makefile.HOST Squashed history. 2023-05-05 16:25:12 -06:00
Makefile.SGX Squashed history. 2023-05-05 16:25:12 -06:00
Makefile.subdir Squashed history. 2023-05-05 16:25:12 -06:00
Makefile.TEST Squashed history. 2023-05-05 16:25:12 -06:00
Makefile.X86 Get AMD SEV-SNP attestation report. 2023-06-14 15:23:45 -06:00
README.md Documentation updates 2023-05-17 09:16:55 -06:00
svr2_Standard_DC2s_v3.conf Rename enclave releases for Azure SGX machine types. 2025-07-10 16:21:53 -07:00
svr2_Standard_DC8s_v3.conf Rename enclave releases for Azure SGX machine types. 2025-07-10 16:21:53 -07:00
svr2_Standard_DC24s_v3.conf Rename enclave releases for Azure SGX machine types. 2025-07-10 16:21:53 -07:00
svr2_test.conf Code cleanup, fixes, and tests. 2024-09-26 15:59:59 -07:00
test_deps.sh Valgrind automatically in github. 2024-01-26 10:39:36 -07:00

SVR2 Enclave Code

SVR2 uses C++ as its language for building an in-enclave binary. The details of the build process and the host-enclave interaction depend on the platform. Since SVR2 is deployed on Intel SGX, this document will describe SGX-specific implementation details.

For SGX, the enclave binary is built with the OpenEnclave (hereafter 'OE') SDK. The binary, enclave.bin is then signed via OE's oesign, which doesn't matter to us because we don't trust the signature, just the unique ID (SGX "mrenclave") of the resulting signed config. However, the oesign process does one important thing: it binds a config (either svr2_test.conf or svr2.conf to the resulting object. Once this process is complete, the resulting enclave.signed file is ready to be loaded into a DCAP-based SGX enclave.

Host/enclave communication

After initialization, all host/enclave communication happens through a single ocall/ecall combination, defined in ../shared/svr2.edl:

  • svr2_input_message: Enclave receives a message (a serialized HostToEnclaveMessage protobuf) from the host.
  • svr2_output_message: Enclave sends a message (a serialized EnclaveToHostMessage protobuf) to the host.

Certain messages are 'transactions', or messages with a Request that want a specific Reply. It is important to note that if a request is passed in via a message, the response associated with it may not be part of the returned list. IE: the host may pass in a transaction request, above, via EnclaveToHostMessage1, but may not get back the reply until HostToEnclaveMessage4.1. Transactions have associated transaction IDs, which allow for disambiguating requests and their associated responses. Hosts may send transactions to enclaves and enclaves to hosts. Each direction maintains a unique keyspace for transaction IDs (so HostToEnclave transaction 1 and EnclaveToHost transaction 1 are distinct), and each is responsible for making sure that transaction requests that they pass are uniquely identified.

Code Layout

Code is broken into a set of modules, where each module is a one-level-deep subdirectory within the top-level enclave directory. Each module is independently compiled, then all modules are combined in a final linking step to form the resulting binary. Modules are listed as LIBRARIES within Makefile, and must form a DAG of dependencies. Within the LIBRARIES list, higher libraries may depend on lower libraries, but not vice versa.

Code roughly follows the Google C++ Style Guide.

Concurrency in SVR2 Enclave

With SVR2, we're aiming to utilize a single replica group to serve all traffic. This, of course, brings up issues around scalability. We can of course add new replicas to the replica group, but with a strong consensus model relying on agreement between a quorum (in our case, a simple majority) of voting replicas, additional replicas have the potential to add load rather than shed it.

To handle this, SVR2 is built to, as much as possible, utilize the resources of non-leader and non-voting replicas. While we're unable to shed or reduce load on RAM with added members (each replica needs to store the entire database), we can shed load in the form of CPU and network resources.

Utilizing multiple cores

Even without considering excess replicas, we aim to utilize the resources of each replica to the fullest extent. To do this, the SVR2 enclave binary is built as a true multi-threaded process, with targetted locking of code subsections allowing parallel processing as much as possible.

One of the most CPU-intensive tasks that SVR2 partakes in is encryption and decryption. This takes place when replicas communicate with each other ("peer communication") and when they accept and service connections from clients ("client communication"). When establishing these secure connections, the initial handshake is more CPU-intensive, followed by less intensive block cipher encryption/decryption. Peer communication uses long-lived sessions that amortize handshake cost over a long period of time, while client communication requires a new handshake, a small amount of communication, and a subsequent closing of the connection.

For both peer and client communication, we aim to be highly parallel on a single machine: handshaking and block-cipher encryption/decryption are done with client- and peer-level locks, rather than global ones. This approach, though, lays some requirements on the host side, as for both cases, reordering of messages breaks the block-cipher assumptions of the clients/peers. Internally, SVR2 maintains correct order of messages it outputs to peers and clients: if message A to a peer or client happens before message B, then svr2_output_message(A) will be called and allowed to complete before svr2_output_message(B). However, on the host side, care must be taken to respect this ordering: when messages are forwarded externally or received from external hosts, their calls to svr2_input_message should follow the same pattern: if A is received before B in either a peer or client stream, then svr2_input_message(A) should be called and allowed to complete before svr2_input_message(B) is called.

Some global locks are of course still required, in particular around Raft and its associated logs/database. However, these locked sections are kept at a minimimum, with as much work done as possible before/after the locks are acquired.

Utilizing multiple machines

The primary means to scale SVR2 is the addition of replicas. However, as mentioned, this has the potential to hinder scaling, especially if the leader alone is allowed to perform CPU-intensive tasks like servicing client requests. For this reason, SVR2 is built to allow any replica to service requests from any client.

When a client connects to SVR2 in a non-leader replica, it will perform the client handshake and receive/decrypt the client's request entirely on its own. Once it has done so, it will forward the request to the current leader as an enclave-to-enclave transaction, receiving in response either a failure or a log location (an (index, term) pair) associated with the write. Failures are immediately returned to the client. A success, though, creates a watch-point in the non-leader replica's raft log at index. The replica will wait until index is a committed part of its own log (via normal Raft AppendEntries mechanisms), then will check the term of the committed log. If that matches the term returned from its write request, by definition the log at index contains the client's request, and when applying that request to its local database, it can safely return the response to that client over its still-open channel.

By this mechanism, load (especially client handshake and communication load) can be shared across all replicas. Crucially, this includes non-voting replicas, which can be added with minimal increase to the load on the voting replicas. As non-voting replicas still receive Raft logs and their commitments, they can happily service client requests.

More topics