Teels: TEE + TLS, for the web
The Problem of Verifiable Web Apps
Web applications face a fundamental trust issue: users have no reliable way to verify they’re running the code the developer claims. Consider a trivial app that many developers might find useful: a JWT validation service that parses JWTs and looks for issues - users must trust that the code validates tokens without stealing them. Another more complex example is Signal, which deliberately doesn’t offer a web app because they can’t guarantee users receive trustworthy code rather than a backdoored version designed to leak private messages.
Facebook attempted to address this with CodeVerify, a browser extension that validates code hashes. While innovative, it only works for users who install the extension and has a somewhat limited threat model.
Trusted Execution Environments (TEEs)
TEEs provide hardware-enforced isolation where code execution can be cryptographically verified. This makes it possible for a client to verify that they’re running precisely the code that was intended, with guarantees that even the host system can’t tamper with execution (though see this post for a more careful analysis of TEEs).
However, TEEs only provide security if someone validates the attestations. If no one is validating the attestations, someone could easily lie about their code executing inside of a TEE. And so far, the web platform doesn’t offer any way to verify TEE attestations, so TEEs alone aren’t a solution here.
Attested TLS: A Step Forward
Attested TLS proposes binding TEE attestations directly to TLS sessions. This allows secure connections to verify not just the identity of the server, but also what code it’s running.
Unfortunately, this approach still requires two things that are difficult to retrofit to the web platform:
- The client-side (i.e. the web browser) needs to verify TEE attestations. AFAIK, there haven’t been any discussions of this in the w3c, so I’m skeptical that this is coming very soon. Browsers would need to understand various attestation formats (AMD SEV-SNP, Intel TDX, AWS Nitro, Intel SGX, …) and maintain knowledge of trusted measurement values (PCR hashes) for each site.
- New x509 extensions. Attested TLS relies on putting metadata in an x509 extension which is something generally discouraged by CAB standards, so this would likely need to be further standardized before it could be adopted with publicly trusted TLS certs.
So while I think Attested TLS is great, I’m skeptical that this will solve the problem for the web.
Introducing Teels (TEE + TLS)
Teels (TEE + TLS) aims to offer a pragmatic solution working with today’s web infrastructure. It functions as follows:
- An application runs inside a TEE, generating an attestation at startup. This attestation proves that the TEE is running certain verifiable code (e.g. the Signal Web App verifiably built from GitHub).
- The attestation is hashed, and this hash is encoded in a subdomain name (e.g.
$hash.hash.example.com
) - The application creates a TLS certificate that covers the application domain (e.g.
example.com
) in addition to the above encoded subdomain. - Browsers connect normally, performing standard TLS certificate validation and Certificate Transparency (CT) log checking.
- Independent auditors monitor CT logs to verify certificates are bound to valid attestations. They can check that all TLS certs that cover the application domain (
example.com
) also have an associated hash, and that the hash binds them to a verifiable TEE attestation.
Why This Architecture Works
The advantage of Teels lies in its three-role split:
- TEE applications create verifiable attestations bound to a TLS key
- Browsers perform their existing security checks without modification
- Auditors handle the specialized task of attestation verification
This approach requires no browser changes, no new web standards, and no complex PKI modifications. It offloads the complex verification of attestation formats and trusted measurements to specialized auditors rather than requiring every browser to implement this logic.
I’ve spent the last week hacking on this and have a prototype implementation available at github.com/ddworken/teels that proves that this seems to work. Docs and more development are incoming, but I do think this is potentially an exciting idea worth exploring further. :)
Warning
So what are the shortcomings of teels?
Admittedly this project is very much in the prototyping/ideation phase, so this is very much TBD.
One potentially significant gap I see is the maximum merge delay. Essentially, CT logs aren’t actually live DBs of all TLS certs–they only are guaranteed to contain all TLS certs from more than 24 hours ago. So even with teels there is potentially a 24 hour window where an application could go malicious, and auditors wouldn’t notice for 24 hours. Auditors could attempt to mitigate this by also making live connections to the application and checking those certs, but a malicious application could selectively serve a verifiable cert to auditors (e.g. using p0f) while serving an unverifiable cert to selected victims. Practically, I’m not sure if this can easily be fixed.
Another gap is that we are mis-using attestations a bit. In theory, TEE attestations are generally meant to be short-lived and verified interactively by applications. Our cert verifier explicitly disables time-based checks when validating AWS Nitro attestations to work around this, which isn’t great from a security POV.
If you have any other thoughts, ideas, or feedback, please open an issue here!
Demo
For a full working demo of this, see verified.teels.dev
. The demo instance offers an introduction to Teels, a page containing verified attestation info, and a variety of trustworthy demo applications (a formatter, a diffchecker, and CyberChef).