Because OpenSSL is everywhere and everything requires it and all instructions say `do apt-get install libopenssl-dev` or something. Or the setup script does exactly that.
It was started in a situation where OpenSSL had bad security practices, a chaotic coding style and plenty of obsolete garbage. None of that is true any more.
If you look at the vuln posted here it's a sign how mature OpenSSL became: They rate it HIGH, but it's a rather insignificant vuln that will barely matter in practice.
The openssl api is still a painful, compare it with libtls which is much nicer. if I were to use something today I would probably use https://github.com/michaelforney/libtls-bearssl which is a wrapper around bearssl that exposes a libtls api.
You should only use BearSSL when you control the server and the certificate that it uses, since BearSSL's certificate validation implementation is intentionally limited so that it can be more efficient on embedded devices at the cost of being unable to correctly handle all publicly-trusted certificates. See https://medium.com/@sleevi_/path-building-vs-path-verifying-...
Dependencies. For example, the Python TLS library of record is based on OpenSSL.
OpenSSL is old and supports lots of platforms. Some people need to use OpenSSL because of the platform they're running on. I do hope the situation gets better, and over time we have seen competing TLS libraries replace OpenSSL in more and more places. It's not an easy problem to solve.
Genuinely ? Seriously ? You don't have to look far in the man page to see the distinct lack of feature parity.
Its been a while since I looked, but IIRC, there's some pretty major stuff missing like PKCS11 which means you can't do the CLI smartcard stuff you can do with OpenSSL.
OpenSSL is FIPS-certified. It supports everything and its mother. LibreSSL also breaks ABI pretty regularly. Finally, OpenSSL is the standard: no one ever got fired for buying IBM, or for using OpenSSL.
FIPS and similar certifications (Common Criteria) have a pretty bad reputation. Plenty of pretty severe crypto vulns that should've been caught by certifications were missed, and more importantly that didn't lead to any critical reflection on the side of the certification bodies.
But it's common that if you work with governments that FIPS certification is a requriement.
Yes, there are plenty of regulated environments (whether government or commercial) that require FIPS because it means the specified ciphers are all approved and the libraries are to have passed certification.
It's a pain in the ass at times because it means things like Ed25519 and ECDSA not over NIST certified curves is not allowed...
Better question is why use OpenSSL over the platform's native TLS library? It's incredibly annoying dealing with OpenSSL when MITMing the connection or just working internal services that I don't want to see the insecure connection warnings on.
You should make and trust an internal CA to issue certs for those, at least. You just have to add your root to whatever CAfile equivalent the program uses.
Configuring the internal CA is exactly the issue here. Programs that use OpenSSL don't respect the Windows cert store. I have a couple environment variables set to point to a PEM file with the cert, but that only helps in a few cases. Sometimes the easiest thing is going the risky route of using a flag to disable to cert check.
Using a library you control (even if it's fairly bad) instead of the platform TLS library is super useful.
Some platforms don't have a TLS library, but TLS is sometimes required. Some platforms have an outdated library and no reasonable update method. Some platforms have nasty bugs in their libraries. Some platforms have very inconsistent libraries depending on version. You might want to send extensions the platform library doesn't support (SNI used to be pretty hard to use), or to manage the acceptable CA roots (which I understand you dislike). You might want more control over ciphers, so as not to offer ciphers that are outdated. Having one buggy library you ship with your code is better than dealing with a different buggy platform library for each platform.
When determining whether a certificate has been revoked, is an Error<T> really more desirable than a segfault? Would you even expect a "is certificate revoked" function to return an Error<T>?
> Would you even expect a "is certificate revoked" function to return an Error<T>?
Depends on how it's doing the check. If it has to fetch the CRL from the CRLdp or do OCSP with the OSCP AIA, like CAPI does, then it definitely has to have an error for when certificate revocation status is not available.
Honestly, even if I provide the cert & CRL, it should probably be able to throw an error if either one has invalid ASN.1 encoding or such.
In Rust, the signature of the function would be along the lines of `-> Result<whatever, Error>` and you'd have no choice but to handle the Error case of the Result or to panic. Either way, not a segfault.
The code in question [1] does indeed return Result<(), Error>. This makes sense - more than one thing can go wrong during the verification, and the details can be important in some situations.
> is an Error<T> really more desirable than a segfault?
It's only by happy coincidence that it manifests cleanly as a segfault. In the C language, dereferencing NULL causes undefined behaviour, so all manner of peculiar things can happen. This isn't just theoretical nit-picking, it can happen with real code:
You have no choice in rust. It wont compile unless you handle all error conditions.
You get Result< Data T, Error>. And you have to handle Error condition (usually kick it up stack, but it has to be handled somewhere) for it to compile.
What rust wouldn't prevent you from is forgetting to check for revocation, or doing it wrong.
Clearly Rust can't solve all bugs, but I bet it would have prevented this one.
GENERAL_NAME[1] is a struct containing a type tag "enum" and a union of the data (d) for each type. If I'm reading it right the bug here is reading the union as 'other' when the tag says its `GEN_EDIPARTY`.
In rust this would just be a fat enum where the variants of the enum would actually contain the data that this has in the union. Then the Rust compiler would only allow you to read the data as the type it's stored as.
With the massive increase in fuzzing, especially around core projects like OpenSSL, I'm surprised that there was still a crash reachable from an x509 cert in the x509 parser. Anyone have any insight on why it wasn't found sooner?
Does anyone know how easy it is to execute this attack? I realize it's high severity, but can't accurately say if I should drop everything I'm doing and upgrade all servers, or wait until this evening..
Seems like the most likely attack vector is having a server check a malicious certificate, which happens automatically in some cases. But not always. And it's unclear what prompts the automatic check in the first place - perhaps the server executing a remote HTTPS request a malicious user specifies?
It's a crash only. So it's not gonna compromise your machine, worst case is something not running any more.
The conditions are also rather special, it seems the most likely scenario is that you have any software that verifies certificates and automatically checks CRLs and there's a way for an attacker to provide you a bad certificate and a CRL. That's not something that I'd expect to be very common.
As someone who doesn’t dig much into security fixes, when does a simple crash become exploitable? Because my understanding is that a crash is an indication that something could be exploitable, so how de we know this one isn’t?
In this case it appears to be a Null pointer de-reference. That type of bug is almost never exploitable since it almost always just leads to the program immediately terminating. An exploitable bug is one that has some way for the attacker to pivot and use it to do something else. For instance, a buffer overflow might allow an attacker to write some data in memory that could change the execution flow of a program.
It's exploitable (more or less, depending on details) if the attacker can convince the program to map memory at address zero. Linux and possibly others usually refuse that without root approval, but I don't know of any systems where it's actually officially impossible. That said, it is rather difficult to exploit in practice, since being able to map memory at address zero is practically a vulnerablity in its own right, and you'd need to chain through that to get anywhere.
It's generally not exploitable if the crash is triggered by a read, not a write, and it's not clear from the advisory which it is; writes to NULL can be exploitable if NULL is mapped (which is a configuration issue more than a permissions issue; it is most frequently not) or, more commonly, if the write address includes an attacker-controlled offset (though it may be the case that we've stopped referring to those conditions as NULL-involved).
The ability to map arbitrary memory is, of course, as you point out, a game-over vulnerability by itself.
Have there been any examples of an exploitable crash handler? E.g. a process traps SIGSEGV to print a backtrace upon NULL dereference, and then that signal handler is itself somehow exploitable?
Not sure on the Linux situation. But this is an established technique on Windows, where stack canaries can be bypassed by overwriting SEH chains (trap handlers) on 32bit windows processes. Which are, strangely enough, recorded as function pointers on the stack.
I've seen some cute work with corrupt DWARF tables (DWARF is internally a Turing complete VM). That work was more focused on hiding computation from virus scanners (so an edited binary), but I wonder if that could be used towards what you're getting at via runtime corruption.
OpenSSL has very strange connections with American intelligence and Huawei. They also have an odd British nuclear weapons joke I've noticed. Possible NSA front?
Re: C# and especially F#, unfortunately the runtime they run on supports nullable references front-and-center, so even if your code doesn't use nullable references, the standard library and your dependencies will.
Of course you can write translation code at the boundaries between your code and the other code to convert `OtherCode.MightBeNullType` to `OtherCode.MightBeNullType option`, but that still doesn't help for `OtherCode.MightBeNullType`'s fields unless you redefine all the types and write conversion functions for all of them.
Does anyone ever actually use EDIPARTYNAME? Or is it just legacy cruft in X.509 that we pay for through security vulnerabilities like this? It is in obscure, rarely or never used features that vulnerabilities tend to lurk, since bugs in the more commonly used features get discovered and fixed much faster.
If hardly anyone is using EDIPARTYNAME, maybe support for it should just be dropped? Reject as invalid every certificate containing it? Release a new streamlined version of X.509 with the legacy cruft removed or deprecated?
57 comments
[ 2.6 ms ] story [ 112 ms ] threadAnd changing that introduces a lot of risk.
It was started in a situation where OpenSSL had bad security practices, a chaotic coding style and plenty of obsolete garbage. None of that is true any more.
If you look at the vuln posted here it's a sign how mature OpenSSL became: They rate it HIGH, but it's a rather insignificant vuln that will barely matter in practice.
OpenSSL is old and supports lots of platforms. Some people need to use OpenSSL because of the platform they're running on. I do hope the situation gets better, and over time we have seen competing TLS libraries replace OpenSSL in more and more places. It's not an easy problem to solve.
Its been a while since I looked, but IIRC, there's some pretty major stuff missing like PKCS11 which means you can't do the CLI smartcard stuff you can do with OpenSSL.
I mean, I wouldn't be surprised if it lets you check a box on PCI checklist; but only people who are forced to use that checklist.
But it's common that if you work with governments that FIPS certification is a requriement.
So yea - great stuff!
It's a pain in the ass at times because it means things like Ed25519 and ECDSA not over NIST certified curves is not allowed...
Some platforms don't have a TLS library, but TLS is sometimes required. Some platforms have an outdated library and no reasonable update method. Some platforms have nasty bugs in their libraries. Some platforms have very inconsistent libraries depending on version. You might want to send extensions the platform library doesn't support (SNI used to be pretty hard to use), or to manage the acceptable CA roots (which I understand you dislike). You might want more control over ciphers, so as not to offer ciphers that are outdated. Having one buggy library you ship with your code is better than dealing with a different buggy platform library for each platform.
I do seem to recall a few OpenSSL advisories in the last few years for which libressl was not vulnerable though.
[1] https://github.com/ctz/rustls
https://github.com/openssl/openssl/commit/f960d81215ebf3f65e...
I highly doubt that rust would have prevented this.
Rust is not a silver bullet that solves all bugs.
Depends on how it's doing the check. If it has to fetch the CRL from the CRLdp or do OCSP with the OSCP AIA, like CAPI does, then it definitely has to have an error for when certificate revocation status is not available.
Honestly, even if I provide the cert & CRL, it should probably be able to throw an error if either one has invalid ASN.1 encoding or such.
[1]: https://docs.rs/webpki/0.21.4/webpki/struct.EndEntityCert.ht...
It's only by happy coincidence that it manifests cleanly as a segfault. In the C language, dereferencing NULL causes undefined behaviour, so all manner of peculiar things can happen. This isn't just theoretical nit-picking, it can happen with real code:
• Raymond Chen's Undefined behavior can result in time travel (among other things, but time travel is the funkiest), https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=63...
• John Regehr's A Guide to Undefined Behavior in C and C++, Part 1, https://blog.regehr.org/archives/213 (ctrl-f for A Fun Case Analysis)
You get Result< Data T, Error>. And you have to handle Error condition (usually kick it up stack, but it has to be handled somewhere) for it to compile.
What rust wouldn't prevent you from is forgetting to check for revocation, or doing it wrong.
GENERAL_NAME[1] is a struct containing a type tag "enum" and a union of the data (d) for each type. If I'm reading it right the bug here is reading the union as 'other' when the tag says its `GEN_EDIPARTY`.
In rust this would just be a fat enum where the variants of the enum would actually contain the data that this has in the union. Then the Rust compiler would only allow you to read the data as the type it's stored as.
[1] https://github.com/openssl/openssl/blob/13a574d8bb2523181f81...
If you created a combined X.509 + CRL parser fuzzer you might have found it. Probably nobody has done that.
Seems like the most likely attack vector is having a server check a malicious certificate, which happens automatically in some cases. But not always. And it's unclear what prompts the automatic check in the first place - perhaps the server executing a remote HTTPS request a malicious user specifies?
Thanks in advance!
The conditions are also rather special, it seems the most likely scenario is that you have any software that verifies certificates and automatically checks CRLs and there's a way for an attacker to provide you a bad certificate and a CRL. That's not something that I'd expect to be very common.
The ability to map arbitrary memory is, of course, as you point out, a game-over vulnerability by itself.
Including read vs write, and what the read is used for, yes.
https://www.corelan.be/index.php/2009/07/25/writing-buffer-o...
[1] - https://blog.12security.com/openssl-expands-partnership-with...
[2] - https://awe.com
[0]: https://www.metalevel.at/prolog/videos/
Of course you can write translation code at the boundaries between your code and the other code to convert `OtherCode.MightBeNullType` to `OtherCode.MightBeNullType option`, but that still doesn't help for `OtherCode.MightBeNullType`'s fields unless you redefine all the types and write conversion functions for all of them.
If hardly anyone is using EDIPARTYNAME, maybe support for it should just be dropped? Reject as invalid every certificate containing it? Release a new streamlined version of X.509 with the legacy cruft removed or deprecated?
https://itlaw.wikia.org/wiki/Electronic_Data_Interchange_Per...