TPM-backed SSL

2012-02-04, Categories: security, network, coding, tpm, hsm

This is a short howto on setting up TPM-backed SSL. This means that the secret key belonging to an SSL cert is protected by the TPM and cannot be copied off of the machine or otherwise inspected.

Meaning even if you get hacked the attackers cannot impersonate you, if you manage to kick them off or just shut down the server. The secret key is safe. It has never been outside the TPM and never will be.

This can be used for both client and server certs.

Prerequisites

Initialize TPM

Create SSL certificate

Test it

On the server:
$ openssl s_server -accept 12345 -cert /path/to/server.crt -key /path/to/server.key -CAfile CA/ca.crt -Verify 1
On the client
$ openssl s_client -keyform engine -engine tpm -connect server-name-here:12345 -cert foo.crt -key foo.key

Use in your code

Instead of using SSL_CTX_load_verify_locations(), use ENGINE_*() and SSL_CTX_use_PrivateKey()

Without TPM:
1
2
3
4
void loadpriv(SSL_CTX* ctx, const char* file)
{
  SSL_CTX_use_PrivateKey_file(ctx, file, SSL_FILETYPE_PEM);
}

With TPM:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
void loadpriv(SSL_CTX* ctx, const char* file)
{
  ENGINE_load_builtin_engines();
  ENGINE* engine = ENGINE_by_id("tpm");
  ENGINE_init(engine);

  UI_METHOD* ui_method = UI_OpenSSL();
  EVP_PKEY* pkey = ENGINE_load_private_key(engine, file, ui_method, NULL);
  SSL_CTX_use_PrivateKey(ctx, pkey);
}
Error handling left as an exercise for the reader.

Use in the real world

Huh. I haven't actually seen this implemented in any Open Source software (besides the openssl command line interface) Well, actually curl and stunnel4 appear that they could support it, but it's not clear how. Here is someone else wondering how to get stunnel to do it. It's from 2006 with no replies.

The only thing I have that uses the TPM chip is my Chromebook. Client certs there are protected by it by default.

Please leave comments if you know of any TPM support in Open Source stuff.

tlssh

I have added support for tlssh to use TPM on both the server and client side. Add "-E tpm" on the client side, and have something like this on the server side config (or only on one side. There's no requirement that both sides use TPM):
1
2
3
PrivkeyEngine tpm
TpmSrkPassword
PrivkeyPassword secretpasswordhere
That last line is just needed if the key has a password. The client can be configured in the same way to not have to ask for the passwords.

If PrivkeyEngine tpm or -E tpm is supplied the secret key will be assumed to be TPM protected and should be in the form of a "BEGIN TSS KEY BLOB" section instead of a PEM format "BEGIN RSA PRIVATE KEY" section.

Performance

Oh, it's slow. Really slow. Luckily it's just used in the handshake. I haven't done proper benchmarks, but let's just say you won't be using it to power your webmail. I may do some benchmarking in a coming blog post.

Update: It can do about 1.4 connections per second. See Benchmarking TPM backed SSL for details.

Misc notes

Links