Privasys
Enclave OS

Config & Merkle Tree

How Enclave OS captures all configuration in a Merkle tree and embeds the root in the RA-TLS certificate.

Enclave OS maintains a Merkle tree over all enclave configuration. The root hash is embedded in the RA-TLS certificate, allowing verifiers to check not just the enclave code identity (MRENCLAVE) but also the complete runtime configuration — which CA certificate is loaded, which WASM modules are deployed, and their exact code.

The Problem

MRENCLAVE tells a verifier which binary is running — but it says nothing about how the binary is configured. Two enclaves with the same MRENCLAVE could have:

  • Different CA certificates (issuing different TLS certs to clients).
  • Different WASM modules deployed (running different application code).
  • Different KV store contents.

Without configuration attestation, a verifier can only trust the infrastructure, not the application.

The Solution: Configuration Merkle Tree

A Merkle tree is a binary hash tree where:

  • Leaf nodes are SHA-256 hashes of individual configuration items.
  • Internal nodes are SHA-256 hashes of their two children concatenated.
  • The root is a single 32-byte hash representing the entire configuration.
                    Root
               ┌─────┴─────┐
            H(0,1)       H(2,3)
           ┌──┴──┐      ┌──┴──┐
          L0    L1      L2    L3
          │      │       │      │
       CA cert CA key  App A  App B
       hash    hash    hash   hash

Any change to any leaf changes the root, and a verifier can prove the inclusion of any specific leaf with a logarithmic-size proof.

Leaf Structure

Each leaf in the Merkle tree is identified by a module OID (Object Identifier) and contains a SHA-256 hash of the configuration item:

LeafOIDContent
CA Certificate1.3.6.1.4.1.1337.1.2SHA-256(DER-encoded CA cert)
CA Private Key1.3.6.1.4.1.1337.1.3SHA-256(DER-encoded CA key)
WASM App 1 Name1.3.6.1.4.1.1337.2.1SHA-256("app-name")
WASM App 1 Route1.3.6.1.4.1.1337.2.2SHA-256("/route-prefix")
WASM App 1 Code1.3.6.1.4.1.1337.2.3SHA-256(WASM binary)
WASM App 2 Name1.3.6.1.4.1.1337.2.1SHA-256("app-name-2")
.........

Leaf Ordering

Leaves are sorted by their OID in lexicographic order before tree construction. This ensures the same set of configuration items always produces the same root hash, regardless of insertion order.

Padding

If the number of leaves is not a power of two, the tree is padded with zero-hash leaves (32 bytes of zeros) to the next power of two. This is a standard Merkle tree construction that simplifies proof generation.

ConfigManifest

The ConfigManifest struct manages the Merkle tree inside the enclave:

struct ConfigManifest {
    leaves: Vec<MerkleLeaf>,
    root: [u8; 32],
}

struct MerkleLeaf {
    oid: String,            // e.g., "1.3.6.1.4.1.1337.2.3"
    hash: [u8; 32],         // SHA-256 of the configuration item
    description: String,    // Human-readable label
}

The root is recomputed whenever a leaf is added or modified, and the new root is embedded in the next RA-TLS certificate generated by the enclave.

X.509 Extension

The Merkle root is embedded in the RA-TLS certificate as a custom X.509 extension:

FieldValue
OID1.3.6.1.4.1.1337.1.1
CriticalNo
Value32 bytes — the SHA-256 Merkle root

This OID is under the Privasys Private Enterprise Number (PEN) 1337, registered with IANA.

Verification Flow

A verifier checking an RA-TLS certificate can:

  1. Extract the Merkle root from extension OID 1.3.6.1.4.1.1337.1.1.
  2. Compare against expected root: If the verifier knows the expected configuration, they can compute the expected Merkle root independently and compare.
  3. Verify individual leaves: If the verifier only cares about specific configuration items (e.g., "is WASM app X deployed?"), they can request a Merkle proof for that leaf and verify it against the root.

Lifecycle

Enclave Startup

  1. MRENCLAVE is verified by the SGX hardware (code identity).
  2. The sealed config is unsealed, recovering the master key and CA material.
  3. Each configuration item is hashed and added as a Merkle leaf:
    • CA certificate hash
    • CA private key hash
    • For each WASM module: name hash, route hash, code hash
  4. The Merkle root is computed.
  5. The RA-TLS certificate is generated, embedding the Merkle root.

Module Deployment

When a new WASM module is deployed:

  1. Its SHA-256 code hash is computed.
  2. New leaves are added (app name, route, code hash).
  3. The Merkle root is recomputed.
  4. A new RA-TLS certificate is generated with the updated root.

From this point forward, all new TLS connections receive the updated certificate that attests the new configuration.

Trust Chain

The complete trust chain from hardware to application:

Intel CPU Hardware Key


SGX DCAP Quote (platform attestation)

        ├── MRENCLAVE (enclave code identity)

        ├── ReportData (binds TLS key to quote)
        │       │
        │       └── SHA-512(SHA-256(pubkey) || binding)

        └── RA-TLS Certificate

                ├── TLS public key (enclave-generated)

                ├── Config Merkle Root (OID 1337.1.1)
                │       │
                │       ├── CA cert hash
                │       ├── CA key hash
                │       └── WASM app code hashes

                └── WASM Module Extensions (OID 1337.2.*)

                        ├── App name
                        ├── App route
                        └── App code hash (SHA-256)

A verifier inspecting this certificate knows:

  1. Which hardware is running (Intel SGX, specific CPU).
  2. Which enclave binary (MRENCLAVE).
  3. Which TLS key (bound via ReportData).
  4. Which configuration and applications (Merkle root + individual app extensions).

This is full-stack attestation — from silicon to application code — delivered over a standard TLS handshake.