Exploiting the Windows Cryptoapi Vulnerability
blog.trailofbits.com
blog.trailofbits.com
Why is that ironic? Well, Trail of Bits also published this article last year:
https://blog.trailofbits.com/2019/07/08/fuck-rsa/
(Note, the points there are still valid. I just find it funny.)
# cache signing objects and get chain
cache, chain = parse_chain_from_cert(full_cert)
root = chain[-1]
validate_root_authenticity(root)
# go up chain from leaf to the root
for cert in chain[:-1]:
parent = cert.parent()
# Wrong Signing object retrieved here:
signing_object = cache[parent.public_key]
signing_object.validate(cert)
So the leaf signing object is used instead of the roots, as they share the same public key, but that doesn't contain the parameters of the curve. from the_heavy_lifting_crypto_heavy_module import verify_signature
def is_known_trusted_ca(cert):
# BOOM
return cert in root_ca_cache[cert.pubkey]
def verify_cert(cert, issuer):
# BOOM
if verified_cache[(cert.pubkey, issuer.pubkey)]:
return True
if not verify_signature(cert, issuer):
return False
verified_cache[(cert.pubkey, issuer.pubkey)] = True
return True
# This has to be a search instead of simple chain-walking because servers
# do not send a "chain", they only send several additional certificates and
# let the client find a trusted path out of them, it is also how cross signing
# works. This justifies using a cache above.
def try_to_build_cert_chain(cert, cert_store):
if is_known_trusted_ca(cert):
return [cert]
for possible_issuer in cert_store.find_certs_with_dn(dn=cert.issuer_dn):
if verify_cert(cert, possible_issuer):
chain = try_to_build_cert_chain(possible_issuer, cert_store)
if chain:
return [cert] + chain
Then someone tasked with (why?!) "adding unnamed curve support" added (correct!) code to `the_heavy_lifting_crypto_heavy_module.verify_signature` but didn't know this breaks an assumption made in another module.The exact detail does not matter though, you can build up working exploits even if you don't know the details listed above.
The reason is that a server doesn't know which roots you actually trust, so maybe it thinks you trust X and X->A->B->C so it sends X->A, A->B, B->C but actually you trust A so you only needed to receive A->B, and B->C - X->A doesn't help you make a decision so your code needs to disregard it.
For example, Let's Encrypt Authority X3 is signed by both ISRG Root X1 (their own root CA) and DST Root CA X3. The server could send you:
1. Server cert
2. Let's Encrypt Authority X3 (Signed by ISRG Root X1)
3. Let's Encrypt Authority X3 (Signed by DST Root CA X3)
Combined with: 4. ISRG Root X1
5. DST Root CA X3
If the client trusts 4, then it could form a path of 1-2-4. If it does not but trusts 5, then 1-3-5 would be viable.In RSA for example there's a public exponent, yours is almost invariably going to be 65537 and most of the time nobody will even mention this parameter, but the "same" key with exponent 3 would actually be a different key than yours.
In code such shorthand becomes a bug.
If you only allow a handful of named algorithms the bug is essentially useless to adversaries. Microsoft's non-standard decision to allow parametrised curves makes it into a huge attack surface.
Sometimes I like to force things in such a way that you can’t avoid dealing with some issues. So, by putting these items in the public key, you are forced to look at them and deal with them when you write a library.
Often, engineers will write code correctly because they know all the context. But the next engineer will likely have less and less context as time goes by.
Thus forcing context acknowledgement, while seemingly redundant, might be essential to avoiding future bugs.
The right response to this vulnerability is to jettison support for anything but named curves.
This is probably an inside-baseball argument for people who don't pay attention to elliptic curve implementation details. But it's easy to quickly understand.
Go to SAFECURVES.CR.YP.TO; you'll see a big long list of curves, each with their parameters and some implementation details. In reality, only a subset of these curves are commonly used (P-224, P-256, Secp256k1, and Curve25519 probably account for 95% of all curves).
Further, most specific curves are implemented not as parameters plugged into a generic elliptic curve scalar multiplication routine, but rather as curve-specific code (one of the major reasons we have different curves is to allow specific implementation optimizations). A browser that supports Curve25519 certainly uses Curve25519 code, not generic code.
The "explicit curve" feature that blew up on Microsoft is designed to allow people to specify their own parameters, not for well-known curves but for curves they themselves generated. Nobody does that. There was a time, in the long long ago, when people thought that might be a good idea; nobody thinks that anymore; everyone thinks the opposite thing. If anything, we're trying to get rid of a bunch of curves. Certainly we shouldn't be randomly supplying new Weierstrass curves.
So that's the problem here. A lot of cryptography engineers were probably surprised this CryptoAPI feature even worked. We had considered it awhile ago as a cryptopals challenge (and Sean actually did add it as one in Set 8 a few years ago), but we never dreamed anyone would be crazy enough to let this bug happen in the real world.
In other words I would not be to surprised if NSA found this bug by accident because it caused some of their internal “secret” cryptosystem to not work at all instead of by actively looking for it.
Over time, this has been shown to open up a big security vulnerabilities such as this one, and also issues with key agility in TLS, etc.
I think the tendency today is to make make crypto more omakase where there are a few well studied, well implemented algorithms that you use for everything.
The Windows CryptoAPI is from that older time.
Part of the problem of the Windows CryptoAPI in question is that it has to serve "both customers", the omakase sort that need the best option, and the a la carte needs to higher level tools serving as the omakase option. That is, for some traditional/legacy C/C++ users that CrpytoAPI is about as high level as they will get, and it's up to the documentation to steer its consumers to the best omakase options. But crypto32.dll also is the low-level backend of tools like WinRT's Windows.Security.Cryptography and .NET's System.Security.Cryptography (on Windows).
The push towards omakase and somewhat getting applications away from micromanaging the a la carte stuff, definitely seems the smart path. Handling the onion of it all in what needs to be supported at a low level to keep the high level omakase shop running smooth seems like it still has a lot of pitfalls.
I'd be happier if nobody used the P-curves (they're unsafe for other reasons). But that's got nothing to do with whether people should literally be plugging their own Weierstrass coefficients and base points into X.509.
Standards should immediately deprecate support for explicit curve parameters.
I don't believe it exactly either, I just know it as a zeitgeist reason why some of the dialog about curve changes has been happening. In hindsight I supposed I'd have been better off not mentioning it.
> Standards should immediately deprecate support for explicit curve parameters.
I agree and that wasn't the intent of my post, if it came across that way. While elsewhere in the thread it is mentioned that many named curves are implemented standalone, my understanding is that not all of them are.
I was only suggesting that crypto32.dll is intended to be low level enough that it is possible that some of the higher-level APIs that Microsoft has built that do focus on named curves only (such as the UWP/WinRT and .NET APIs I mentioned) may rely on the explicit parameter support in the lower level library. I don't envy Microsoft the task of balancing what is in a low-level API like that versus backwards compatibility, "upwards" compatibility with high level components, etc.
Even if Firefox/Chrome use their own implementations of cryptographic algorithms, there's a decent chance that they are still using Windows's native API for certificate chain validation in order to plug into the enterprise certificate management features that come baked into Windows, which IT teams sometimes use to distribute internal PKI's. Without having seen how Firefox and Chrome deal with their chain building, I can't say "yes" or "no" definitively.
Credit to this person's comment in the Reddit discussion: https://www.reddit.com/r/netsec/comments/eooyil/cve20200601/...
Firefox also uses NSS to do certificate validation. In newer releases a config pref lets you ask Firefox to use Windows' local trust store to find any CA roots that are being additionally trusted on your PC, e.g. "enterprise" certificates or even a local cert on somebody's local web development setup. But the validation for those certificates is still NSS. If your corporation has (as one of my ex-employers did) really half-arsed certificates they'll be rejected by NSS even though Windows is happy with them and Firefox has fetched them from the Windows trust store. This is potentially annoying but probably also means security at your place of work is shot to hell.
Chrome on the other hand hands all normal certificate validation to Windows so as to deliver the same experience as other Windows products. This makes it a better drop-in replacement, but out-sources trust decisions (on Windows) to Microsoft. In this case that's bad news.
For some certs Chrome will reject them because they either claim to be logged in Certificate Transparency (and the proofs won't match for a bogus cert) or they don't claim to be logged but they claim to have been created after that was mandatory. But bad guys could work around this (for the next year or so) by picking date ranges for which CT logging wasn't yet mandatory and yet a compliant certificate isn't yet expired. A proof-of-concept of this has been done for Chrome on unpatched Windows.
Patching either Chrome or Windows to current fixes the problem for Chrome, but obviously patching Chrome doesn't fix other Windows software.
https://chromium-review.googlesource.com/c/chromium/src/+/19...
Version 79.0.3945.130.
It could also affect document signing (less commonly used, this is digital signatures not electronic signatures) or code signing (e.g. updates for software other than Windows itself might be affected, or installing new software you haven't separately validated as safe).
Plus, the whosecurve.com website includes the information you want if you only have 10 seconds and it's by the same authors as the blog linked in the OP.
Please excuse me if I got the origin story wrong.
Edit: Also, from the website:
> Who’s behind this?
> Trail of Bits
That could certainly be (mis)interpreted as taking credit for the vulnerability.
The branding thing is a joke, about the fact that neither Microsoft nor NSA branded the vulnerability. Lighten up.
It should also affect Chrome on Windows 10 if you haven't updated either your browser or your OS.
It won't affect Firefox on either platform.
I have problems getting Windows update to work under Arch Linux but I'm hoping to find something in the AUR.