OpenSSL Audit
cryptoservices.github.io
cryptoservices.github.io
EDIT: What is the status of LibreSSL?
Last LibreSSL release was 2.1.4 last week, although a minor update should be coming soon. http://marc.info/?l=openbsd-announce&m=142543818707898&w=2
LibreSSL is going to track OpenBSD versions, so now that OpenBSD 5.7 is done, the LibreSSL 2.1.x series is done (except to receive patches). At some point a 2.2 release will be made, corresponding to new developments.
What does binary size have to do with quality?
OpenSSL has been around for a long time, and still is the standard for most deployments. It will take a long time before LibreSSL has been proven enough to become the standard for anything outside the BSD community.
For as nasty as the OpenSSL code appears to be, it sure did work (and worked well) for a long time.
Remember, OpenSSL really only had 1 developer and only received around $2,000 a year in donations prior to Heartbleed[1] (which is grossly pathetic for such a critical piece of software).
If those numbers had been tenfold or more, perhaps the bugs that led to Heartbleed may have been found and fixed long before they were an issue.
Thankfully the Linux Foundation and the Core Infrastructure Initiative are aiming to remedy this.
[1] http://arstechnica.com/information-technology/2014/04/tech-g...
I think grandparent meant that binary size is related to code size. The number of bugs being related to the number of lines of code, you could infer that a bigger binary means more lines of code which means more bugs. In my experience, this tends to be true. Of course this makes the big assumption that the binaries have been compiled with similar compilers using similar optimizations and are both stripped.
Do OS/2, 16 bit Windows, and Data General Unix support indicate quality to you?
It's all dead code that any of us here would remove from our own software projects - and your point about the OpenSSL team's lack of resources is quite relevant to that.
They also gutted more than 90,000 lines in the first month (something that would be naive to claim had absolutely no unintended side effects), and claimed the OpenSSL project would not accept a single change (sort of alluding to the OpenSSL project having some delusional desire to stay "broken"), mandating the fork[1][2].
OpenSSL was largely written by cryptographers. LibreSSL is being hacked on by OpenBSD developers.
OpenSSL's code may not be pretty, but I sure think it would have been a better use of time and efforts to have the OpenBSD developers work alongside the OpenSSL cryptographers.
[1] http://www.infoq.com/news/2014/05/libre-ssl-first-30-days
[2] http://arstechnica.com/information-technology/2014/04/openss...
OpenSSL: http://git.openssl.org/gitweb/?p=openssl.git;a=shortlog vs LibreSSL: https://github.com/libressl-portable/portable/commits/master
Seems LibreSSL is a mainly a one-man band?
This is closer, and a bit busier: https://github.com/libressl-portable/openbsd
Sure more people committing but several days with no changes, vs the commit changes on OpenSSL.
Regarding libressl I'm not sure how it works, but I think the OpenBSD cvs server is a better source that the github repo (http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libssl/), but I'm not sure.
Also I'm not sure that a rapid flow of commits are necessarily a good indicator of quality.
This is an exciting development.
On a side note - a lot of libs start to implement their own crypto because "OpenSSL code sux its terrible and buggy!" impression. This scares me. These won't get much exposure and will most likely be full of implementation bugs that nobody will ever review - except bad guys and the NSA.
What OpenSSL is, is a magic wand that can set up encrypted tunnels between peers that don't have pre-existing mutual key pairing, by making use of well-known X.509 certificates and the CA infrastructure. Don't try to make that kind of wand yourself; 99.999% of such wands are really misidentified Wands of +5 Foot Shooting.
[1] I rolled my own CA bundle this week, turns out I need to include 4 1024-bit certs because the endpoints I hit are chaining to them for legacy clients, and OpenSSL didn't understand to stop when it got to a cert it knew until 1.0.2 which was released in January. Given what happened the last time I upgraded OpenSSL versions, I'm not inclined to upgrade right away. Seriously, the week after we upgraded to OpenSSL 1.0.1, heartbleed came out; serves us right for wanting to support TLS 1.1 and 1.2 and PFS.
I don't think they'd do that - it's be far easier to grab libressl or boringssl. If you're aware that openssl is buggy, you're probably aware that writing your own crypto when you're not a cryptographer is worse.
http://veridicalsystems.com/blog/of-money-responsibility-and...
> OSF typically receives about US$2000 a year in outright donations and sells commercial software support contracts and does both hourly rate and fixed price “work-for-hire” consulting as shown on the OSF web site. The media have noted that in the five years since it was created OSF has never taken in over $1 million in gross revenues annually.
They were only getting about $2,000 a year and had one active developer.
[1] http://arstechnica.com/information-technology/2014/04/tech-g...
Are there decent implementations of OpenSSL in more secure languages like Rust?
But it's not in a more secure language.
Your best middleground is LibreSSL, which is still C but is at least written by developers with huge amounts of experience writing secure C.
Please stop perpetuating the myth that security is produced by a programming language. People make security happen just like they make it not happen. Obligatory Schneier: https://www.schneier.com/blog/archives/2008/03/the_security_...
The trouble is that everything is a trade off. It's very hard to get a buffer overrun in Java but that doesn't make Java a good language. It tries so hard to keep you from hanging yourself that it won't let you have any rope, so in the instances when you actually need rope you're forced to create your own and hang yourself with that.
For example, you're presented with garbage collection and then encouraged to ignore object lifetime. There are no destructors to clean up when an object goes out of scope. But when it does you still have to cleanup open files or write records to the database or notify network peers etc. Which leaves you to have to manage it manually and out of order, leading to bugs and race conditions.
In other words, C and C++ encourage you to write simple dangerous bugs while Java encourages you to write complicated dangerous bugs.
That isn't to say that some languages don't have advantages over others, but rather that the differences aren't scalar. And code quality is by far more important than the choice of language. BIND would still be less secure than djbdns even if it was written in Java.
"...the JSSE implementation of TLS has been providing virtually no security guarantee (no authentication, no integrity, no confidentiality) for the past several years."
Not that I know about security, but all you're doing right now is to fend off the claim of "more secure" by stating that java is not secure in an absolute sense - no one has claimed absolute security, only relatively more.
Yes, security issues are found in Java and every other language, but when these are patched all programs that use that language are patched against the issue. The attack surface is much smaller.
All patches work like that; when there is a bug in libssl and OpenSSL patches it then all the programs using libssl are patched. The difference with Java is that when a C library has a bug only programs using that library are exposed but when Java has a bug all Java programs are exposed. Moreover, Java itself is huge. It's an enormous attack surface. Your argument would hold more weight if the "much smaller" attack surface actually produced a scarcity of vulnerabilities.
There are several assumptions behind "if I use a language that doesn't allow buffer overflows to happen" which you aren't taking into account. For instance, are you entirely sure that the implementation of that language's compiler will not allow buffer overflows to happen? We have a good example of a possible failure of that model in Heartbleed: when it came up, a bunch of people in the OpenBSD community raised their eyebrows, thinking hmm, that shouldn't happen for us, we have mitigation techniques for that. Turns out -- for performance reasons -- OpenSSL was implementing its own wrappers over native malloc() and free(), doing some caching of its own. This, in turn, rendered OpenBSD's own prevention mechanisms (e.g. overwriting malloc()-ed areas before using them) useless. The language specifications may not allow such behaviour, but that doesn't mean the implementation won't, too.
You're also underestimating a programmer's ability to shoot himself in the foot. Since I already mentioned OpenBSD and Heartbleed, here's a good example of a Heartbleed-like bug in Rust: http://www.tedunangst.com/flak/post/heartbleed-in-rust . The sad truth is that most vulnerabilities like this one don't stem from accidental mistakes that languages could have prevented; they stem from fundamental misunderstanding of the mode of operation which are otherwise safe constructs in their respective languages.
Granted, this isn't a buffer overflow, which, in a language that doesn't allow arbitrary writes, would be an incorrect construct and would barf at runtime, if not at compile time; but then my remark about bugs above still stands (and I'm not talking out of my ass, I've seen buggy code produced by an Ada compiler allowing this to happen), buffer overflows can be increasingly well mitigated with ASLR, and the increased complexity in the language runtime is, in and by itself, an increased attack surface.
Edit: just to be clear, I do think writing software in a language like Go or Rust would do away with the most trivial security issues (like blatant buffer overflows) -- and that is, in itself, a gain. However, those are also the kind of security issues that are typically resolved within months of the first release. Most of the crap that shows up five, ten, fifteen years after the first release is in perfectly innocent-looking code, which the compiler could infer to be a mistake only if it "knew" what the programmer actually wanted to achieve.
https://www.reddit.com/r/rust/comments/2uii0u/heartbleed_in_...
> You should note that Rust does not allow unintialized value by design and thus it does prevent heartbleed from happening. But indeed no programming language will ever prevent logic bugs from happening.
Under OpenBSD, that values would not have been uninitialized, were it not for OpenSSL's silly malloc wrapper -- a contraption of the sort that, if they really wanted, they could probably implement on top of Rust as well. What is arguably a logic mistake compromised the protection of a runtime that, just like Rust, claimed that it would not allow uninitialized values, "by design".
Of course, idiomatic Rust code would not fall into that trap -- but then arguably neither would idiomatic C code. It's true that Rust also enforces some of the traits of its idioms (unlike C), but as soon as -- like the OpenSSL developers did in C, or like Unangst did in that trivial example -- you start making up your own, there's only that much the compiler can do.
At the end of the day, the only thing that is 100% efficient is writing correct code. Better languages help, but it's naive to hope they'll put an end to bugs like these when they haven't put an end to many other trivial bugs that we keep on making since the days of EDSAC and Z3.
I really disagree. Rust does not allow uninitialized values by design - end of story. If a piece of Rust code let's uninitialized values bleed through, then it is broken. The semantics of Rust demands this.
(OpenSSL on the other hand only broke/Overrode OpenBSD's malloc - they didn't break C.)
It is news to no one that you can break - break - Rust's semantics if you use anything that demands `unsafe`. That's why anyone who uses `unsafe` and intends to wrap that `unsafe` in a safe interface has to be very careful.
Complaining about Rust being unsafe - in the specific sense that the Rust devs use - by using the `unsafe` construct, is like complaining that Haskell is impure because you can use `unsafePerformIO` to `launchMissiles` from a non-IO context.
> Of course, idiomatic Rust code would not fall into that trap -- but then arguably neither would idiomatic C code.
It's not even a question of being idiomatic. If someone codes in safe (non-`unsafe`) Rust, then they should not fall into the trap that you describe. If they do, then someone who implemented something in an `unsafe` block messed up and broke Rust's semantics.
What if that same thing happened in C? Well, then it's just another bug.
---
I'd bet you'd be willing to take it to its next step, even if we assume that a language is 100% safe from X no matter what the programmer does - "what if the compiler implementation is broken?". And down the rabbit hole we go.
I'm not familiar enough with Rust (mostly on account of being more partial to Go...), so I will gladly stand corrected if I'm missing anything here.
If the OpenSSL did the same thing they did in C -- implement their own, custom allocator over a pre-allocated memory region, would anything in Rust prevent them from the same sequence of events? That is:
1. Program receives a packet and wants 100 bytes of memory for it. 2. It asks custom_allocator to give it a 100 byte chunk. custom_allocator gives it a fresh 100 byte chunk, which is correctly initialized because this is Rust. 3. Program is done with that chunk... 4. ...but custom_allocator is not. It marks the 100 byte chunk as free for it to use them again, but continues to retain ownership and does not clear its contents. 5. Program receives a packet that claims it has 100 bytes of payload, so it asks custom_allocator to give it a chunk of 100 bytes. custom_allocator gives it the same chunk as before, without asking the Rust runtime for another (initialized!) chunk. Program is free to roam around those 100 bytes, too.
I.e. the semantics of Rust do not allow for data to be uninitialized, but custom_allocator sidesteps that.
(Edit: I'm really really curious, not necessarily trying to prove a point. I deal with low-level code in safety-critical (think medical) stuff every day, and only lack of time is what makes me procrastinate that week when I'm finally going to learn Rust)
(We eventually plan on supporting this case, just haven't gotten there yet.)
So basically openssl_malloc() wasn't always malloc()-ing -- it would sometimes return a previously malloc()-ed aread that was never (actually) freed.
This rendered OpenBSD's hardened malloc() useless: you can configure OBSD to always initialize malloc-ed areas. If OpenSSL had used malloc() instead of openssl_malloc, even with the wrong (large and unchecked) size, the buffer would not have contained previous values, as it would have already been initialized to 0x0D. Instead, they'd return previous malloc()-ed -- and never actually free()-d -- buffers, that contained the old data. Since malloc() was not called for them, there was never a chance to re-initialize their contents.
This can trivially (if just as dumbly!) be implemented in Go. It's equally pointless (the reasons they did that were 100% historical), but possible. And -- assuming they'd have done away with the whole openssl_dothis() and openssl_dothat() crap -- heartbleed would have been trivially prevented in C by just sanely implementing malloc.
> (We eventually plan on supporting this case, just haven't gotten there yet.)
I'm really (and not maliciously!) curious about how this will be done :). You guys are doing some amazing work with Rust! Good luck!
However, Rust currently statically links in jemalloc - even when building a dynamic shared library. There is no easy way around it.
(because someone might ask: rustc -C prefer-dynamic dynamically links everything except jemalloc)
Having said that, I hope jemalloc gets linked externally soon so my code doesn't have to pay the memory penalty in each of my memory-constrained threads.
All those big security issues aren't in the Java language, they are in the JVM running untrusted Java byte code. Not to say that situation isn't bad, but you can't compare it to C++ because nobody ever thought running untrusted C++ code without some other sandboxing was a good idea.
That aside, memory safety is great for security. Of course there are 1000 other things that are important, too, and so I'd trust a C program written by a security expert much more then the same program written by someone who thinks his program is secure because he used Java. But I'd feel even better if the security expert used a memory-safe language because I am certain that all C programs above a certain size are vulnerable to memory attacks.
This is actually kind of a point for the other side. You can sandbox code regardless of what language it's written in. Maybe what we need is not better languages but better sandboxes. Even when code is "trusted", if the developer knows it doesn't need to e.g. write to the filesystem or bind any sockets then it should never do those things and if it does the OS should deny access if not kill it immediately.
People tend to base security on them. Google did in their AppEngine cloud, but they put a lot of engineering resources and defence-in-depth behind it.
Are there any sandboxes in existence which are definitely not worse than useless?
I wanted to move the goalpost from "Java is insecure" to "the Java sandbox is insecure". I completely agree with the second statement, so I don't think I made a point for any other side.
Rust and friends would aren't going to make all securty issues go away, just as sandboxing would not. There is no one true silver bullet in securty, at least not yet.
Security happens by taking care of what you're doing; if a language can eliminate a whole class of bugs then you might as well use it. That's why people keep arguing that some languages can eliminate some kind of bugs, but that absolutely doesn't make programs implemented in these languages bug-free.
Said differently: more secure (relatively) doesn't mean secure (in absolute).
> We only have to look at all the patches for java to see that it hasn't been secure.
We only have to look at all the patches for java to see how much it is analyzed; it doesn't mean java is relatively more or less secure than any other language.
I've seen no patches for this nim interpreter for brainfuck [0], does that mean it's more secure than java ? Absolutely not.
You can draw some parallel with crypto schemes: anybody can come up with some cipher, nobody will analyze it unless there is something to gain (that includes fun). When you've reached the state where you're under scrutiny of every crypto analyst and their student, and potential vulnerabilities are found, does that make it a weak scheme ? We don't know. Only a real analysis of the vulnerabilities can tell us.
Also, it might be vulnerable to side-channel timing attacks: https://www.imperialviolet.org/2013/02/04/luckythirteen.html
Regarding SSL, I just generally consider it borked and try not to trust it if possible. SSH/VPN are just about the only thing I do trust (and even then with trepidation).
Once again, I think the many eyes theory only works when the code is sufficiently simple/terse. I bet if you did a study on lines of code in proportion to security vulnerabilities you would find a correlation (obviously not necessarily a causation).