Don’t Install .NET 4.6 Just Yet

Nick Craver and team at Stack Exchange just published a very interesting bug they uncovered in RyuJIT.

For those that aren’t familiar with RyuJIT, it is a replacement just-in-time compiler that is shipped as part of the .NET Framework 4.6.

I won’t go into detail on the bug, Nick’s blog post does a great job on that, and he includes specific steps to take if you already jumped on the 4.6 train which involves disabling RyuJIT. To summarize it, under the right circumstances, a method may be called with parameter values that aren’t actually correct. What it will look like is happening is a method is being called with bogus parameters. Nick pointed out the specifics on what is actually happening in the comments.

This has pretty strong consequences, which Nick is right to point out. While it might be parameter that is more harmless, like numberOfTimesToBeep, it could be a parameter that has very real-world consequences, like amountOfMoneyToTransfer.

AWS Elastic Load Balancers and HTTPS Healthchecks

I ran into an interesting problem where some HTTPS changes on my servers broke their elastic load balancer. More specifically, I tuned Nginx to not support DHE cipher suites, leaving only ECDHE as the key exchange. The exact cipher suite being used was now:

TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027)
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA    (0xc013)

As a quick refresher, Elliptic Curve Diffie-Hellman Ephemeral is what we are supporting here, and removing the non elliptic curve algorithms. As I wrote a bit in a previous post, I didn’t feel that supporting DHE was worth it anymore.

After a configuration reload, I pulled up the site by going to a server’s IP address (thus bypassing the ELB) and everything looked pretty good. However within a few moments the actual site went down, and the ELB was convinced that all of the servers were unhealthy and took them out of server.

After seeing that the sites were still coming up OK, I refreshed myself as to what the health check in the ELB actually looked like.

ELB Check

Ah OK, so the ELB is checking HTTPS and it isn’t happy about the HTTPS configuration. I haven’t found any specific documentation calling it up, but it appears that the ELB does not support establishing an HTTPS handshake using the limited cipher suites listed above.

After changing my ELB check to use TCP port-establishment as the health check, the ELB was happy to bring the instances back online.

Public Key Pinning Afterthoughts

Not so long ago I decided to use HPKP (Public Key Pinning) on my website and see how it goes. For those curious as to “why”, it’s because I often use my own website to use and learn about new things in the ever evolving world of HTTPS, such as HSTS, HPKP, ECC, etc. Experimenting with these things is not an opportunity I can do at a job, however becoming familiar with them lets me make recommendations to people, including my employer.

After using HPKP for almost half a year, I am happy using it and haven’t run into any significant issues, and no visitors have complained about anything. A visitor shouldn’t see anything different as long as HPKP is working correctly. I do however, wish I had done a few things differently.

I wish I had made more than one backup key. HPKP requires you to have a pinned hash that isn’t in the certificate chain such that the key that hash was created from can be used if the currently deployed key is compromised. I talk about that a bit more in a different post. I created another RSA 2048-bit key and safely stored it elsewhere. In hindsight, I wish I had done more than that. If you are going to deploy HPKP, chances are you are in it for the long haul. As time passes, computers get faster, and people smarter than me think of better ways to factor integers. We don’t know how long RSA 2048 will be around. It’s many, many years out (barring any major discovery like proving N=NP). Using a key that relies on elliptic curves, like ECDSA, has some benefits. Performance is one, and better security is another. This leads me to wish I had also deployed an ECC key.

I’ve since added an ECC backup key for an ECDSA certificate. The process is a little different than I wrote about previously for RSA. To make a backup ECC key, I used this process:

openssl pkey -pubout -outform der -in ecc.key |
openssl dgst -sha256 -binary |
base64

This approach works for RSA and ECC keys. If you have a build of openssl that does not support the pkey command, you can use the ec command:

openssl ec -pubout -outform der -in ecc.key |
openssl dgst -sha256 -binary |
base64

This gives me a hash to pin, but before I can start using an ECC certificate, I must wait the max-age the keys have been pinned for. Currently I had it set to 60 days. In 60 days I’ll be switching to an ECC certificate.

Even if you don’t plan on completely switching to ECC, pinning one as a backup is still advisable if you ever plan on deploying multiple certificates. Apache supports this today, and Nginx is working on it.

Going ECC

For a while now I’ve wanted Nginx to support dual certificates. I don’t mean SNI, I mean the server choosing a different certificate depending on how the negotiation goes for the protocol. The reason I wanted this was to use an ECC certificate for my domain.

After thinking about it though, do I really need dual certificates, or will just going full-ECC be enough? Using the ever resourceful SSLLabs, I looked at the clients I support today. I had already eliminated Windows XP browsers and Java 6 from accessing the site due to a lack of SSLv3 and using 2048-bit DH parameters. So by switching to ECC, what more would I eliminate that I haven’t already? Turns out the list is a bit short:

  • Android 2.x
  • OpenSSL 0.9.8y

I’m not feeling all that big of a loss by not supporting those clients. Doing so would also allow me to eliminate all DHE ciphers from my cipher suite as well. I have added a new public key to my HPKP header for an ECDSA certificate. Before I can deploy the ECC certificate, I need to wait for my HPKP header to expire, which is at 60 days. In advance though, I’ve eliminated support for DHE in the cipher suite.

Another unrelated change is support for IPv6. The site now has IPv6 addresses. The DNS resolvers are not IPv6, that might be something I tackle later.

Authenticating ASP.NET 5 to AD FS OAuth Part 3: Validating JWTs

In our first part of handling OAuth, we handle the response from AD FS and parse the JWT back to the application.

OAuth 2.0 by nature depends on transport security (TLS). Without HTTPS, OAuth 2.0 is completely insecure. However the JWT that AD FS returns is in fact, signed. It’s signed by the Token Signing Certificate in AD FS, and using the Public Key we can validate it. You can get the certificate from AD FS by simply exporting to to disk and saving it as a .cer file.

Previously, we weren’t validating the JWT – which isn’t unreasonable if you have correct transport security in place. If you want to validate the signature of the JWT, you can modify your middleware configuration like so:

OnGetUserInformationAsync = context =>
{
    var handler = new JwtSecurityTokenHandler();
    var signingCert = new X509Certificate2(Path.Combine(_appEnv.ApplicationBasePath, "jwtToken.cer"), (string)null);
    SecurityToken securityToken;
    var validationOptions = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new X509SecurityKey(signingCert),
        ValidateAudience = true,
        ValidateIssuer = true,
        ValidAudience = "http://www.example.com/",
        ValidIssuer = "http://www.example.com/",
        NameClaimType = ClaimTypes.Upn,
        RoleClaimType = ClaimTypes.Role,
        AuthenticationType = "oauth2",
        RequireSignedTokens = true,
    };
    var principle = handler.ValidateToken(context.AccessToken, validationOptions, out securityToken);
    context.Principal = principle;
    return Task.FromResult(0);
}

The first thing we’ll need is the certificate – in this case I named it jwtToken.cer and put it in the application base path, one level up from wwwroot. You can change the validation as you like, such as not validating the audience or issuer.

Alternatively, you can obtain the certificate from a certificate store:

X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var thumbprint = "get-thumbprint-from-configuration";
var certificates = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
if (certificates.Count == 0)
{
    throw new System.Security.SecurityException($"Unable to find certificate with thumbprint \"{thumbprint}\".");
}
var certificate = certificates[0];