2022-04-21 · 4 min read
Time in an enclave is difficult.
Why do we care about time in an enclave? #
- Knowing the time lets us detect replay attacks on sealed persistent data.
- We need the current time to decide whether a certificate/OCSP response/DNSSEC reply is stale or expired.
- With the current time, we can tell whether a PoW blockchain header is stale or recent.
- Various protocols rely on accurate clocks for security, e.g., DNSSEC, Kerberos, TLS, WireGuard.
Why is this problem so hard? #
- We can't rely on standard OS time services, since they can be modified by the host and must sit outside our TCB.
- CPU instructions that query an on-die Real-time Clock (RTC) are likewise untrustworthy.
- Intel's Platform Services Enclave (PSE) provides an interface to the Intel Management Engine's (IME) RTC, which is isolated from the host OS. Unfortunately, this is more trustworthy but still only provides you with a relative time. We want the absolute time.
What do we do about it? #
- We want absolute time, so we can communicate with others outside our own machine.
- The true time, as observed by other enclaves on the machine, should be strictly increasing.
- The platform operator is outside our TCB. They should not be able to make the true time go backwards.
- We are not secure against DoS by the platform operator. This doesn't significantly change our threat model however, since they can just turn off the machine. : )
- Minimize the startup latency of other enclaves by doing the bootstrap once in a shared enclave.
Shared Time-keeper Enclave #
Use a shared enclave that keeps track of time on the same machine. Other local enclaves can query the Time-keeper for the current true time.
The Time-keeper uses a combination of a remote, semi-trusted time service, and a local, trusted relative clock provided by the Intel ME and Platform Services Enclave (PSE) to keep track of the true time.
- The connection to the remote time service needs to be secure against the platform operator. We probably use NTP with NTS to some small, fixed set of NTP servers (that support NTS).
- On startup, we use the local insecure time to bootstrap our secure connection to the remote time service.
- We need the initial insecure time measurement so we can complete the TLS handshake.
- We could also attempt to bootstrap more securely with roughtime.
- Since platform operator DoS is out-of-scope, a bad initial insecure time is effectively the same as a DoS, since we'll just reject the server's TLS cert.
- We then use our secure channel to the remote time service to fix our trusted clock base.
- We then use the local, trusted relative clock to track the time since the clock base.
- Since the relative clock only provides second granularity, we use an intra-epoch counter stored in-memory that gets incremented after each request.
- On startup, we need to make sure we wait until the next second for the previous epoch to fully elapse.
- Depending on requirements, refresh the base time by re-bootstrapping from the remote time source to reduce clock-skew. This refresh could happen every hour or so.
- Other enclaves can request the current time from the time-keeper. The request should include a nonce for freshness/replay-prevention. The request should be (at least) MAC'd with a shared symmetric key derived via
EGETKEYwith the same
- RFC 8915 - Network Time Security (NTS) for NTP
- chrony - Notes on using NTS
- NTPsec - NTS Quickstart
- Intel - Trusted Time and Monotonic Counters with SGX Platform Services Enclave
- 2019 - Applications and Challenges in Securing Time
- Google Roughtime Protocol
- int08h/roughtime - Rust library
- Cloudflare - secure time.cloudflare.com announcement
- Cloudflare - Announcing cfnts: Cloudflare's implementation of NTS in Rust
- cloudflare/cfnts - supports NTS, looks unmaintained
- vpetrigo/sntpc - plain SNTP
- risoflora/sntp_request - plain SNTP
- ioerror/tlsdate - securely extract time from TLS handshake
- drand - distributed randomness beacon, emits timestamp+random every 30 sec, signed quorum as one BLS threshold signature