Recently I created the Enclave.NET project, and it shipped with a simple in-memory storage service. It’s not particularly useful in it’s current form, so I created a sample a couple weeks ago that used Azure Key Vault as the storage and crypto service.

But Why?

Of course, you might be wondering why you’d want to use Enclave.NET this way, since Key Vault already provides isolation given that it’s hosted far away from your service. The obvious answer is that maybe you wouldn’t use it this way — it IS isolated enough. That said, this does provide you with some extra separation because your app now doesn’t have access to the secrets to connect to Key Vault — we’re working on the premise that every little bit helps.

And because it’s my project and my site and it seemed like a neat little idea. 😀

So how exactly does this work?

If you remember previously the service is supposed to be hosted locally, but outside of your own application, and relies on an HTTPS channel to offload data protection. That means we have a service host. In this case it’s just a console application. You’d likely want this running in a Windows service or Linux daemon in production so it’s not constantly having to spin up.

The service host looks for the settings.json file and spins up a web host given the provided server and client certificates.

You’ll also notice there’s a transform type that lets you setup your own services. This just injects the Key Vault storage and processing services.

You can find the KeyVaultStorageService and the KeyVaultCryptoProcessor in the sample project.

Once those are set, you can call the service from the client, and at this point the client has no idea where the keys are, or how they’re being used.

The neat thing about this is that it provides a great abstraction between the internal workings of the crypto bits, and the code that needs to protect data.

Recently I came across an interesting parameter of the New-SelfSignedCertificate PowerShell cmdlet — the -Signer parameter. This parameter allows you to provide a reference to an already-existing certificate that can be used to sign the newly-created certificate. This turns out to be an extremely useful little feature because sometimes you just need chained certificates to test stuff (so much so that I wrote a library that does this for me).

Not surprisingly, this cmdlet is much easier to use.

$ca = New-SelfSignedCertificate -DnsName "My Certificate Authority" -CertStoreLocation "cert:\LocalMachine\My"
New-SelfSignedCertificate -DnsName "child.domain.com" -CertStoreLocation "cert:\LocalMachine\My" -signer $ca

And voilà.

Signed Certificate

There’s a common problem that many applications run in to when executing cryptographic operations, and that’s the fact that the keys they use tend to exist within the application itself. This is problematic because there’s no protection of the keys — the keys are recoverable if you get a dump of the application memory, or you’re able to execute arbitrary code within the application. The solution to this problem is relatively straightforward — keep the keys out of the application.

In order for that to be effective you need to also move the crypto operations out of the application too. This means any attacks on the application won’t yield the keys. This is the fundamental design for services like Azure Key Vault, Amazon CloudHSM, or any other HSM service or device. In fact, even Windows subscribes to this design with CNG keys using LSASS.

I was thinking about this problem over the weekend and realized there isn’t really any good reference architecture out there that shows you how to build this design into your application. The services I mentioned earlier do great jobs at protecting secrets, but they’re kind of designed with certain applications in mind — greenfield, cloud first, or disconnected. This can make it difficult to migrate existing applications to use these services, or maybe you just can’t use them for whatever reason (regulatory, legal, etc.). On top of all that, you don’t even know how to start.

So, I did something dumb. I built a reference implementation that lets you move crypto operations out of your application and into a separate process.

Introducing: Enclave.NET.

READ THIS SECURITY WARNING

This is a reference implementation. That means it’s not designed to handle production loads, and absolutely is not built to withstand attack. It’s a sample intended to show how you might offload certain operations. There are probably some horrible bugs in here and there might even be vulnerabilities.

Was that sufficiently scary enough?

The basic idea is simple. You have an application that hosts a service. The service has a set of commands available to it:

  • Generate key
  • Encrypt
  • Decrypt
  • Sign
  • Validate

Your application calls these commands with the necessary payloads, the service does the thing, and returns a result. The service is HTTP-based, and protected with pinned client certificates.

The crypto operations are real, backed by the jose-jwt library, but they’re ephemeral — the keys are just stored in memory. The idea is that you can inject your own implementations as you see fit, so any migrations you might undergo can be gradual and painless.

There are two classes that need to be implemented — the crypto operations class, and the storage service. You can use the built-in crypto operations class InMemoryCryptoProcessor at your own risk, but you absolutely need to implement the storage, lest you lose all the keys when the app shuts down.

Crypto Processor

Storage Service

You can modify the startup code on your own, or you can implement IStartupTransform and configure it:

Calling the service is simple:

For more information take a look at the sample app.