Certificate Transparency for .NET

Trust, but verify

Certificate Transparency (CT) is an initiative headed by Google to allow anyone to monitor and audit TLS certificates. The core objective is to have a free, secure and publicly available ledger of all certificates issued by Certificate Authoriates (CA) with three main goals,

  • Ensure domain owners have visibility over any certificates issued by CA’s for their domains
  • Allow any domain owner, or CA, to easily audit and monitor issued certificates to identify mistakes or malicious activity
  • Protect users from mistakenly or maliciously issued certificates, i.e. mitigate against man-in-the-middle (MITM) attacks

You may be familiar with HTTP Public Key Pinning (HPKP) which was a security feature that allowed a server to tell the client (via a HTTP header) to only accept specific public keys. The intent was to prevent clients trusting fraudulent or misissued certificates, unfortunately, it was easy for this approach to go wrong. If you incorrectly pin your website to a set of keys, or lose access to the pinned certificates, then clients that saw the HPKP header would be unable to access your site until the lifetime expired, known as HPKP Suicide. Should an attacker hijack your domain, or compromise your site, then they could inject a malicious HPKP header effectively shutting down access to your site, even after you regained control, known as RansomPKP. These issues lead to the deprecation of HPKP.

Certificate Transparency is intended to address the threat of MITM attacks, without the destructive issues associated with HPKP. When a valid certificate is issued, it is submitted to a log which responds with a signed certificate timestamp (SCT). The SCT is a cryptographically verifiable promise to add the certificate to the log within a time period, known as the maximum merge delay (MMD).

The CT logs have three important properties,

  • Append-only (modifying/deleting previous operations is not permitted)
  • Cryptographically assured (Merkle Tree Hashes to prevent tampering i.e. blockchain)
  • Publicly auditable (anyone can freely query the log at anytime, Certificate Search is an example of a CT log search engine)

Generally, certificates are required to have multiple SCTs (i.e. added to multiple logs) to be considered valid. There are three supported methods for delivering a SCT with a certificate.

X.509v3 Extension
When a CA is ready to issue a certificate it first submits a precertificate, a certificate with the same data but an added poison extension, to the log. The log will return a SCT which is added to the certificate in an extension and signed by the CA.
TLS Extension
This requires the server operator (i.e. you) to submit the issued certificate to the log and add the returned SCT as a TLS extension.
OCSP Stapling
The CA simultaneously issues the certificate and submits it to the log. Using the Online Certificate Status Protocol (OCSP) the server queries the CA for the SCT and includes the OCSP TLS extension.

Once a client has the SCTs it’s just a matter of validating the signatures against the list of log servers, both Google and Apple maintain a list of trusted CT logs.

.NET Framework Support

As far as I could tell there is no built-in support for CT validation in the .NET Framework. There is, however, a generally recognised standard library for performing CT validation on Android (which also does not have platform support) maintained by Babylon Health.

Originally I was asked to help to create a native binding for the Android library, but that proved tricky due to its use of Kotlin generics. The more I played around with the binding, the more I considered the option of just porting the code over to .NET. This would have the added advantage of being compatible with any .NET app.

As the Android version utilised Bouncy Castle, which also has a C# implementation, it turned out that porting over the code wasn’t too difficult, obviously huge kudos to Babylon Health for the core logic. It did take a while to correctly get the SCT signature validating, so I was quite pleased when the code started hitting my IsValid breakpoint.

The result is a .NET CT validation library that is easy to integrate with HttpClient, although currently it only supports receiving SCTs via a X.509v3 extension. Additionally, the relevant test cases have been ported across (as verbatim as possible), to provide some assurance that nothing nasty has been added in the process. There’s also a platform specific implementation of AndroidClientHandler that provides CT validation out of the box.

Best of all it’s all open source and available on NuGet!

The Code


comments powered by Disqus