Documentation Index
Fetch the complete documentation index at: https://mintlify.com/concrete-security/umbra/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Exported Keying Material (EKM) channel binding cryptographically links TLS connections to application-layer attestations, preventing man-in-the-middle attacks and quote replay attacks. Umbra implements EKM according to RFC 9266 with an additional HMAC signature layer for defense-in-depth.The Problem: Quote Replay Attacks
Without channel binding, an attacker could:- Intercept a valid TDX quote from a legitimate TEE
- Set up a malicious server
- Replay the stolen quote to clients
- Client believes it’s talking to the TEE, but it’s actually talking to the attacker
RFC 9266 EKM Specification
What is EKM?
EKM is a mechanism defined in TLS 1.3 (RFC 8446) that allows applications to derive additional key material from the TLS master secret:- Session-specific: Different for every TLS connection
- Unguessable: Derived from TLS master secret
- Extractable by both peers: Both client and server can compute the same EKM
- Cannot be forged: Requires knowledge of the TLS session keys
How Nginx Extracts EKM
Umbra’s nginx (cert-manager) is configured with a custom module that extracts EKM from the TLS connection:The actual nginx configuration uses Lua scripting to compute HMAC. The above is simplified for clarity.
HMAC-SHA256 Signature Layer
Why HMAC on Top of TLS?
Even though nginx and the attestation service run inside the same TEE, we add HMAC signatures for defense-in-depth:- Bypass Protection: If an attacker somehow bypasses nginx (e.g., container escape), they cannot forge EKM headers
- Network Isolation: If network isolation fails, HMAC prevents header injection
- Audit Trail: Logs can detect forged headers
- Zero Trust: Assume every component might be compromised
Header Format
TheX-TLS-EKM-Channel-Binding header uses the format:
HMAC Computation
The HMAC is computed as:Key Derivation from Dstack
The HMAC key is never configured manually. Instead, it’s derived deterministically inside the TEE:Key Derivation Properties
- Deterministic:
get_key("ekm/hmac-key/v1")always returns the same key for the same TEE - Derived from TEE identity: Key is based on RTMR2 (docker-compose hash) and bootchain
- Operator-invisible: The key never appears in logs, environment variables, or configuration files
- Synchronized automatically: Both nginx and attestation service derive the same key
Validation Code
The attestation service validates EKM headers before trusting them:Timing Attack Protection: The code uses
secrets.compare_digest() for constant-time comparison. This prevents attackers from learning information about the HMAC key through timing analysis.Complete Flow
Here’s the full EKM channel binding flow:Security Properties
What EKM Channel Binding Provides
✅ Session Binding: Quote is cryptographically bound to the specific TLS connection ✅ Replay Prevention: Attacker cannot reuse a quote on a different TLS session ✅ MITM Detection: If attacker terminates TLS and re-establishes it, EKM will differ ✅ Freshness: Combined with client nonce, proves quote was generated for THIS requestDefense Layers
Umbra’s EKM implementation has multiple security layers:- TLS 1.3 Encryption: EKM derived from TLS master secret
- TEE Isolation: Nginx and attestation service run in same TEE
- HMAC Signature: Prevents header forgery even if network isolation fails
- Constant-Time Validation: Prevents timing attacks
- Key Derivation: HMAC key derived from TEE identity, never exposed
- Client-Side Verification: Client independently verifies EKM in report_data
Development Mode
For local testing without dstack:Troubleshooting
403 Forbidden: Invalid EKM header signature
- Nginx and attestation service using different HMAC keys
EKM_SHARED_SECRETmismatch in development mode- dstack key derivation failing on one service but not the other
- Header corruption (check nginx buffer sizes)
400 Bad Request: Missing EKM header
- Nginx not configured to extract EKM
- TLS connection terminated outside nginx (e.g., load balancer)
- Client using HTTP instead of HTTPS
- Request bypassing nginx (direct access to attestation service)
Report Data Mismatch
- EKM extraction failed (nginx forwarded wrong value)
- Client computed EKM incorrectly
- MITM attack (TLS terminated outside TEE)
- Quote replay attack
Testing EKM Validation
The attestation service includes a debug endpoint for testing:Implementation Checklist
When implementing EKM channel binding:- Configure nginx to extract EKM from TLS connections
- Ensure nginx and attestation service derive HMAC key from same dstack path
- Validate header format (129 characters, colon at position 64)
- Use constant-time comparison (
secrets.compare_digest) - Include EKM in report_data:
SHA512(nonce || EKM) - Client verifies report_data matches its own EKM computation
- Log HMAC validation failures for security monitoring
- Never log the actual HMAC key or EKM values
- Test with invalid HMAC signatures to ensure rejection
- Verify key derivation works in production environment
Next Steps
TDX Attestation
See how EKM is included in TDX quotes
RA-TLS (aTLS)
Explore the complete aTLS implementation
Attestation Service
View the validation code
RFC 9266
Read the EKM specification
