88 comments

[ 2.5 ms ] story [ 153 ms ] thread
> These vulnerabilities affect all LibreSSL versions, including LibreSSL 2.0.0 (the first public release) and LibreSSL 2.3.0 (the latest release at the time of writing). OpenSSL is not affected.
is keeping score what we're interested in today?

https://www.openssl.org/news/vulnerabilities.html

Whether this bug affects the upstream project is a legitimate concern, I think. It would be like worrying that a vulnerability in OpenBSD affected NetBSD, too, especially if it was found relatively close to when OpenBSD forked.
I blame C. People that are much smarter than me fail at writing C. I am not even trolling. It is a thought that has been gnawing away at me for some time. I no longer think it's a question of being "good enough" to write good C code.

The only one I know of that has written almost bug-free C code is djb, and that code is a fucking pain to look at regardless of what Aaron Schwartz said. It is good, but it is not how anyone in their right mind writes C. If that is what is required to write safe C then I'm all for using another language.

Edit: I do like how Zed Shaw writes C, but I have no idea if the software he wrote is safe...

I've always assumed LibreSSL was just a first step toward a secure implementation. I always thought that it made sense to try to fork/fix OpenSSL at first, but eventually move to a non-C implementation. I still think that will happen.
> I've always assumed LibreSSL was just a first step toward a secure implementation. I always thought that it made sense to try to fork/fix OpenSSL at first, but eventually move to a non-C implementation.

Yes and no.

No in that LibreSSL aims to be mostly drop-in compatible with OpenSSL (modulo deprecations/removals) and OpenSSL has a very complex API exposing lots of internal gunk to the user, so moving to a non-C implementation may not be possible at all.

Yes because there's a related `libtls`[0] project which aims to define more abstracted API (with the reference implementation being done on top of libressl). As POC, tedu has/had an implementation of the API using golang's TLS stack[1], and noted that you could build the same on e.g. the OCaml/Mirage TLS stack[2]. If `libtls` fulfils its promises, it would become much easier to swap TLS stack and indeed move to non-C implementations.

[0] http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/... HN discussion: https://news.ycombinator.com/item?id=8572029 (some comments may not apply anymore IIRC the discussion was the initial API which has been extended since)

[1] http://www.tedunangst.com/flak/post/goreSSL

[2] https://mirage.io/blog/introducing-ocaml-tls

If we accept that C is here to stay for the time being, but is difficult to manage memory, then why don't we use a mid-way solution?

Lua is built on c, and is much more (than C) memory safe. It retains all the advantages of C (ie, can go anywhere), and we limit the C to 17.3k (as of 5.2.3) lines of c, which is relatively static (won't change, won't bloat in the same way maintaining/building on current C SSL implementations), and could allow us to handle memory safely.

I'm curious why this approach is not used. Portability? Proficiency? Lua is quite possibly the most beautiful language to read. I can't see any downsides, but I'll gladly be enlightened!

Well for a start lua not having integers would be an issue when implementing cryptographic primitives. The second issue is while lua is relatively lightweight, carrying a full lua runtime for each of the libraries you're using would still get unwieldy and costly, adding ~400K to each embedder according to the About page ("Under 64-bit Linux, […] the Lua library takes 414K")
Apologies. I should have referenced Lua 5.3 instead as it has both integer and bitwise operator support. This should satisfy the concerns regarding crypto implementation.

As for the space considerations, I have two ways to reason this:

* Wouldn't it only take up 1x414K? If you create luaSSL as a drop in replacement to OpenSSL, you'd only need one copy in your filesystem, just as you only have one OpenSSL.

* Even if you bloat your binary sizes by 414K per executable, isn't it worth it to go from "yes, it could be unsafe, we'll never know... let's wait for the next CVE" to 100% guaranteed no memory faults EVER? Nothing is free, and this could be a cheap price to pay for the guarantee of memory safety, and the implications that come with it.

Edit: wording

For crypto-primitives, you usually want them to be constant-time. This is basically impossible to do in an interpreter or a JIT, indeed optimizing compilers can and will optimize contant-time operations out so inline assembly is commonly used.
Thank you for the info!
Speed and ease of using low level techniques, probably.
The nice thing about C has always been how close you can get to the hardware, while still having some sensible flow control. The bad thing about C is how close you need to get to the hardware.

I really think that everyone serious about programming should learn C, to the level where they can read parts of the Linux kernel or something, but never actually deploy C code to a production environment. It's not a "must" -- not a requirement to be a good programmer or developer at all -- but you'll understand something much closer to the hardware than you will in a more modern language. Just don't expose that program to an adversary if you can avoid it, because that proximity to the hardware makes a single mistake catastrophic.

Plus, if you ever need to do embedded work, you often don't have a choice other than C.

Writing C is like handling venomous snakes. There's lots of people that think they can do it safely and, for the most part, they usually do. But if you do it for long enough, you're going to get bitten. All it takes is the smallest mistake. And when that happens, you better hope it's not in the wild, because if left untreated, it gets bad in a hurry.

Rust can't mature fast enough.

Would Rust be a good alternative? Can you get constant time calculations in Rust?
Could you please summarize how djb's code is different?
Well... Someone said of his code that the only reason it is bug-free is because it scares bugs away. Large amounts of pointer arithmetic. Religious checks (heck, he even checks if printf (not fprintf) succeeds or not), and... odd (not sure if it's the right word. maybe insane is better) macros. Plenty of one letter variables.

Misunderstand me correctly, he writes solid software. He's not just a guy I would like to work with :)

Your concerns are legitimate, but I wouldn't jump to blaming C here. Yes, this deals with memory management, but the cost presented is not conceptually difficult. We can rephrase this issue in any other context and not raise a C argument---you have some set of resources that need to be closed (file descriptors, database connections, etc), and you forget to close it. I was writing a daemon in Node.js for my employer and during development I noticed that it leaking file descriptors until the kernel killed it. That can happen in any language.

Nothing against the programmer; these things happen. But I wouldn't say because of C in this case.

C makes these sort of problems more common and occupy more time/energy/source code than they need to. The language doesn't try to help the programmer with even the most basic of these sort of resource management problems. Most modern languages offer tools to handle some subset of them (e.g. GC for memory in managed languages, or destructors for memory and more in C++/Rust), reducing the burden on the programmer for normal resource life cycles and hopefully making it easier to handle the abnormal cases better.

Sure, it's not generally possible for a language to perfectly manage every resource all the time, but this doesn't mean we should just give up and throw away computer assistance in cases when we can have it.

C is an important language, but there's no need to look at it through rose-coloured glasses.

"... but it is not how anyone in their right mind writes C."

If I were going to place blame (I think a better approach is to skip that and just solve the problem), then I would blame developers, not the language.

To me, the code you are criticizing is very "regular" -- it follows predictable patterns. I find it easier to follow than most other C code I read.

More importantly I believe it is worth following. Obviously he is doing something right as reliability, performance and paucity of bugs shows.

All this despite not being in the "right mind", whatever that means.

I wish all the programs I am forced to use were written with such care.

I wish all C was written with such care as well. I just wish they had less pointer arithmetic, less one-character variables and was commented, you know, at all...
(comment deleted)
So you'd think that if anything, these kinds of 'trivial' bugs, memory leaks and buffer overflows, would not be present in LibreSSL. Especially not in the same function. I wonder what went wrong and how it can be prevented.
I know this opinion won't be popular, and I know encryption is a very complex topic, but ... TLS is simply vastly too complicated. How many of us here could write a TLS library even if we wanted to? So you end up with code so complex that even the smartest people can barely understand it, let alone debug it, and you get terrifyingly long CVE lists like for OpenSSL as a result.

Compare that to a basic unencrypted HTTP server, which you can write in ~10KiB of code. Complexity breeds these kinds of problems as a natural consequence.

I do know that verifiability is significantly easier than all of this (signatures; hashing), but it's quite possible there is no simpler solution for the secrecy aspect of TLS. I certainly wish there was more support for HTTP+integrity, for those who didn't need the secrecy component. These constant CVEs in every TLS library put our servers at risk in cases where secrecy simply isn't necessary.

> Complexity breeds these kinds of problems as a natural consequence.

But the bugs described are not complex - they are local problems that can be understood by just reading one function. The problem here is not complexity, but size (not enough people spend enough time to review all of the code) and the fact that the library is written in a language with manual memory management and unsafe memory access.

> I do know that verifiability is significantly easier than all of this (signatures; hashing), but it's quite possible there is no simpler solution for the secrecy aspect of TLS.

In this case, the affected component was related to the identity part (certificates), which are needed for verifiability. It was not directly related to secrecy.

> the library is written in a language with manual memory management and unsafe memory access.

C's simplicity is certainly a blessing and a curse. Right now, I'm of the opinion that C++ is the best we've got, even if not perfectly ideal. RAII, shared pointers and smart containers with bounds checking allows you to keep nearly all of the performance without the drastic downsides of tracing garbage collectors (obscene amounts of memory usage, nasty stalls, etc.)

And when you get into the really high-level languages (Python, Ruby), they simply don't scale.

Everyone's darling right now is Rust. I still think it's too early in its life to know how it'll play out (hot new languages follow a predictable path of gaining negative baggage and shortcomings as they increase in real-world usage), but I guess we'll see. Maybe it will indeed be a great panacea to these issues.

> In this case, the affected component was related to the identity part (certificates), which are needed for verifiability. It was not directly related to secrecy.

Sure, but I'm generalizing here.

I can (and did) write a SHA256 hashing algorithm in 3KiB of code. Combined with a package gist updater (these use signing with local keys for updates), that's enough to secure binary package downloads on the BSDs over plain-text HTTP.

Surely we can come up with a less complex system for verification alone. Something akin to signify, perhaps. I know that doesn't solve how to universally handle anonymously verifying public key authenticity, but surely we can make something less complex than the clusterfuck that is TLS and the CAs. Yet it doesn't seem there's much, if any, interest in even trying. Everyone has hitched their wagons to HTTP/2 and mandatory TLS; which to me feels like a huge step backward by means of making tech vastly more complex.

Building a system for verification alone seems like a bad idea. You end up with something like DNSSEC and then there's no easy way to add privacy later on.
> And when you get into the really high-level languages (Python, Ruby), they simply don't scale.

I think you need to qualify what "scale" means in this context. Otherwise java is, for all its warts, more or less as high level as ruby and python, and it's probably been proven to scale up (to big machines, or many developers) reasonably well.

http://martinfowler.com/articles/lmax.html

> The system is built on the JVM platform ... in fact they ended up by doing all the business logic for their platform: all trades, from all customers, in all markets - on a single thread. A thread that will process 6 million orders per second using commodity hardware

To be fair, one of the ways they achieved this is by using off-heap memory which needs to be handled in a way similar to how a C allocator would handle it.
Just as a random example:

https://www.reddit.com/r/programming/comments/3p6r2v/i_wrote...

I've constantly had similar experiences. I tried to write the GUI portion of my programs with Python and PyGTK. I needed to write a simple function that scaled up a bitmap from 256x224 to 512x448. A nearest-neighbor pixel doubler with no interpolation, color conversion, or anything else. It ended up running at around 30fps with nothing but the scaling, on a Core i7-2600k processor. And when I asked for help in optimizing it, nobody could really improve the Python, and they recommended I write "the slow parts" in C as a shared library, and invoke that from the Python GUI.

It's okay to be 10%, 30% or even 50% slower than C. But to be 2500% slower or more is completely unacceptable for production code. That level of performance only works on websites with small amounts of traffic, or on the simplest of applications.

The root problem here is of course dynamic typing. That makes scaling both performance and code size much more challenging.

Java is certainly vastly better, but the garbage collection and its stalls, wasteful memory usage (I've seen our production servers bog down with Tomcat eating up all the RAM on the server for simple programs), and overall extreme negatives of the language itself (no unsigned integers, limited to single inheritance, terrible support for generics [maybe this has changed recently?], etc), plus the legal issues that Oracle is saddling the language with, make it an unacceptable alternative.

C# might have been better if Microsoft ever cared about any platform other than Windows.

Both dynamic typing and garbage collection are the wrong ways to solve the problems of C. Rust is the closest I've seen to addressing the real problems, but it coming from Mozilla (with their terrible record with Firefox), and the syntax being so radically different from C, I think will chase a lot of people off.

As far as http+integrity goes: Integrity checks are also based on a shared secret, see https://en.wikipedia.org/wiki/Hash-based_message_authenticat.... So for http+integrity, without the secrecy aspect of TLS, ie the hmac key being public, it would be trivial to generate your own valid integrity hash.
Public hmac key is same as posting hash of iso next to the ISO on ftp severs without gpg signature of the hash. No protection at all.
I'm not the right person to design the entire system, obviously. But as a starting point, I'd consider using a PGP signing key on responses from a server. Your keys would be hosted on an HTTPS server somewhere. Let's say httpi.org or something.

signify also looks really promising. Get the key down to the size of a QR code, and you could separate the issue of signing from signature validation entirely ... post it on your HTTPS Twitter feed, put it on your business card, whatever.

I think it would be a positive step to get users to think about how they are verifying integrity themselves and the sources they trust.

You could even have a dozen sources and let there be a little button in the URL bar to show you which sources agree on a public key provided by a server.

This doesn't seem to be a case of a complicated spec causing a logic error. Just another case of a memory unsafe language in action. So it's more an issue of people wanting fast, runtime-free, portable code, and being OK with the security implications C brings in exchange. (A TLS lib written in Rust might eventually be an answer, maybe.)
Is it TLS specifically or X509 (both by itself and because it uses ASN.1)? I dimly remember X509 and ASN.1 being commonly criticised for their complexity, does TLS pile on additional complexity or just inherit it?
It's everything. ASN.1 is complex - people still make mistakes in the DER parsers as seen in this CVE. X509 is even more complex - it's not just ASN.1. It can be DER in DER in DER (parameters of certificate extensions). Have fun with that and memory ownership! (you have to recalculate and replace an object 2 levels above what you're actually changing) TLS is even worse, because it includes X509 as a format and then a ton more of actual processing logic, state machines, cryptography code, ...

I don't trust any implementation of it that uses unmanaged code. (yes, pretty much assuming everything based on openssl will be broken time and time again)

In this case it's definitely ASN.1; the problem is that "objects" are defined with OIDs, which are sequences of integers (called arcs numbers) like { 1 2 840 113549 1 }. The first integer is always 0, 1 or 2, and with 0 or 1, the second is between 0 and 39. But the other integers can be arbitrarily large, and it's important not to overflow: https://www.viathinksoft.de/~daniel-marschall/asn.1/oid_fact...

You need to use some sort of bignum function if you want to display large arc numbers in decimal. Which is what OpenSSL and LibreSSL do, and that involves creating and destroying BIGNUM objects. The problem is that someone in LibreSSL moved the free() to outside the loop body handling the arc numbers while they were cleaning up. So only the last BIGNUM used gets freed.

Oh, did I tell you that arc numbers are encoded in base 128, with the first bit of every octet used to signal whether it's the last octet of that arc number? Because they are.

Well these are ASN.1 facts I did not need to know and I would like to not subscribe to that mailing list, but regardless thank you for the explanation.
Why does ASN.1 allow such large arc numbers? Is this a result of being designed before a reasonable (32 bit) word size was common enough to depend on? Ie that everyone would have to implement "bignum" so might as well set no limit?

It still seems questionable that they'd let any length be set, especially since you can just chain numbers together into a longer OID.

Base128 encoding seems fair though; the other varint formats are more exotic and only work with many ints at once.

> Why does ASN.1 allow such large arc numbers? Is this a result of being designed before a reasonable (32 bit) word size was common enough to depend on? Ie that everyone would have to implement "bignum" so might as well set no limit?

I assume that's because OID nodes are essentially namespaces, giving an arbitrary upper bound to node ids would artificially and "unnecessarily" limit the size of the corresponding namespace. That looks like a "correct versus realistic" debate which was won by the "correct" side.

Stop writing unmanaged code? This is just the same ol' story...
If you want interoperability you are kinda stuck with C. Nearly every Language can use C Libraries either directly or via FFI.

While Rust can export functions the same way C does it you are in unmanaged land again then.

With http://www.ponylang.org/ its much better, it can export functions like C does it, but its fully managed. The only limitation are the Data Types, you are restricted to those C knows.

Do you have more info about Pony's ability to expose C-compatible functions? I can't see anything in the docs (e.g. http://tutorial.ponylang.org/c-ffi/c-abi/ talks about going the other direction).

Also, FWIW, I don't think Rust should be considered unmanaged for these purposes: it bridges the divide between "managed" and "unmanaged" by bringing the memory safety of the former to a language that doesn't require a complicated runtime. So strictly speaking, yes, it's unmanaged, but it doesn't suffer the worst of the problems of existing unmanaged languages like C or C++.

I belive all you have to do is to prefix a Actor or function with a "@" and then call ponyc with --library, which generates a header and library you can use in your c program.
> With http://www.ponylang.org/ its much better, it can export functions like C does it, but its fully managed.

You can do that with most "managed" languages. You can call Python, Haskell, Go or OCaml from C, pony isn't exactly special here.

One issue in all these cases is you're carrying a whole runtime with you, possibly one per library you're using, praying they don't conflict with one another[0] and limiting the portability of the whole[1]. You're also significantly increasing the cost of using the library in question as it now brings in megabytes of runtime along for the ride.

[0] with conflicting signal handling for instance

[1] if only because all those runtimes you're bringing in might be doing stuff like spawning their own threads and the like, so that needs to be available on the target platform

Communicating via the C ABI between safe languages isn't inherently unsafe, as long as you drop pointers and other unsafe things from the passed structures. It becomes just another protocol that you handle in your safe language.
Communicating via the C ABI is as safe as coding in C in the first place.

Possibly less as there's a pretty high chance to get the ownership rules wrong on the callee side in a way which'll fault (because the callee will have freed the structure) rather than "just" leak memory (because the caller will not send the structure back for deallocation).

Example: https://blog.filippo.io/building-python-modules-with-go-1-5/ in the third snippet (AddDot) the author returns a Go string which may (will?) be freed next time the GC runs[0] regardless of the caller still using it.

[0] https://www.reddit.com/r/golang/comments/3ieiiu/building_pyt...

Ownership rules sound a lot like pointers which I excluded.

Think pass-by-value structs with only fixed size fields. Or JSON, protobufs etc. (Ok, you need the one pointer for the JSON/PB data, but it's not kept around after null check and decode)

> Think pass-by-value structs with only fixed size fields.

There are (at least) three issues with that:

1. not all FFIs can handle structs, according to the Rust FFI omnibus GHC's doesn't[0]

2. the callee side must be able to express on-stack by-value structs, many (most?) managed languages don't, either not supporting them or having them only as optimisation (based on escape analysis)

3. and finally the layout (and size) of the struct must be deterministic, which further restricts (2)

> Or JSON, protobufs etc. (Ok, you need the one pointer for the JSON/PB data, but it's not kept around after null check and decode)

Depending on the callee's implementation that may be too late already, there is absolutely no guarantee the data will even go through the FFI without being released, so you'd be relying on garbage data not being zeroed/reused/moved in the interval, which would be an implementation detail.

[0] http://jakegoulding.com/rust-ffi-omnibus/tuples/#haskell

> 2. the callee side must be able to express on-stack by-value structs, many (most?) managed languages don't

I think the FFI could well express this. Just generate a C thunk that converts the value from the stack to a suitable representation.

> 3. and finally the layout (and size) of the struct must be deterministic

The layout and padding of structs is deterministic in all C environments I know of since they end up as part of ABIs.

> Depending on the callee's implementation that may be too late already, there is absolutely no guarantee the data will even go through the FFI without being released

So you make a C FFI call from a safe language to libfoo.so function void foo(char *jsondata) and before the callee returns your safe runtime yanks the data from under it in another thread?

Yeah, you would also need the caller's FFI to guarantee against this to get safety. In absence of such guarantees you should stick to only passing pass-by-value structures!

> I think the FFI could well express this. Just generate a C thunk that converts the value from the stack to a suitable representation.

Oh definitely, I'm just saying not all of them do (if you follow the link, the Ruby/MRI, CPython and Node FFIs all provide for that at least on the caller side)

> So you make a C FFI call from a safe language to libfoo.so function void foo(char *jsondata) and before the callee returns your safe runtime yanks the data from under it in another thread?

Yup, could happen with a concurrent GC kicking it at an inconvenient time, or with a refcounting GC.

> Yeah, you would also need the FFI to guarantee against this to get safety.

I'm not sure it could (without caller cooperation), best I can see is offer side-channels to "leak" memory (allocate non-managed memory and copy stuff into it) or recommend that you keep an internal strong reference of some sort (e.g. a global list/set).

Why isn't static analysis or "sanitizers" finding this?
Good question. I'd expect static analysis to find the leak automatically - it's pretty obvious. The off by one however is behind many branches and only detectable if you know the buffer size at the call site... I'd be surprised if it triggered any scanning tool.

As a general answer though: static analysis will give you better answers if you write your code in a clean and well structured way. If you goto from a branch from a branch from a (potentially infinite) for-loop from a (not counting) while-loop - good luck :) OpenSSL's OBJ_/BN_/... functions seem to strive for complexity.

They have major limitations. C is unsafe even with all the mitigation tools in the world and in the end they're only going to catch the low-hanging fruit.
> We would like to thank the LibreSSL team for their great work and their incredibly quick response, and Red Hat Product Security for promptly assigning CVE-IDs to these issues.

> Patch: http://ftp.openbsd.org/pub/OpenBSD/patches/5.8/common/007_ob...

> Releases: http://ftp.openbsd.org/pub/OpenBSD/LibreSSL/

I am glad that bugs are found. It shows that the audit is thorough, since bugs can still be expected in LibreSSL (still quite new) and OpenSMTPD (audit was explicitly requested).

Delude yourself all day, CIA. You must face God. If I wait 12 years, I am CEO of intel for 12 years. If I wait 15 years, I am CEO of INtel for 15 years.

I'm patient. You gotta pay the piper. Yer in deep shit, retard.

I have no knowledge of C, but reading their code I was surprised to see some gotos ... is this OK in C to use goto ?
It's a very common C error-handling pattern, essentially emulating RAII with forwards-only function-local goto statements. It's possible to do without, but that tends to yield much more deeply nested code (especially if it's complex) and possibly some amount of duplication.

See http://eli.thegreenplace.net/2009/04/27/using-goto-for-error... for a short rundown, or http://blog.regehr.org/archives/894 where regehr — who works specifically in correctness and verifiability — states:

> many people, including me, prefer the goto version

(comment deleted)
Most languages use unconditional jumps to break flow when necessary, it might be called "exception" instead of "goto" but it's conceptually the same thing.
In many high level languages a break, continue, pass, that sort of thing (where you want to skip or escape a loop iteration) is usually implemented with a goto as well.

Also, a common use of goto in C is when you're doing something in nested for loops and want to break out of all of them. A goto is actually much cleaner here than using sentinel values or boolean flags, or naughty things like setting your loop variables to be outside of the conditional bounds.

Well if you go that way, fundamentally all structured programming techniques are implemented with a goto, that's what jumps are.
C lacks exception handling. goto is used to implement it.

Every conditional is a goto (jump) at the machine level.

OS X 10.11 El Capitan is using LibreSSL: `ssh -V` How I patch this? ;) If anybody has infos when Apple is releasing a fix please tell me.
Install your own LibreSSL with Homebrew or wait for a fix from Apple.

I think Apple never discloses information about security vulnerabilities until a fix is out.

afaik this only applies to x509, which openSSH doesn't use.
seems OS X 10.11.1 did not fixed this. The version is 2.1.7 there but newest one is 2.1.8 :(
So much for LibreSSL being a better choice than OpenSSL.
LibreSSL has had roughly half (22 to 43) as many vulnerabilities as OpenSSL since the fork and, before this, 0 sev:high, compared to OpenSSL's 5 sev:high.

Would you really disregard all that because of a 1-byte buffer overflow and a memory leak?

False:

CVE-2015-0204 affected LibreSSL, but they thought it was a low priority vulnerability, when it actually is a high priority. They fixed it, didn't notify upstream afaict and just issued a new release.

LibreSSL isn't a panacea, and based on that, they can't even classify vulnerabilities correctly.

Most of the vulnerabilities in OpenSSL are in parts (e.g. DTLS) which are disabled in lots of builds.

Here we go. Another round of "damn it, it's written in C. that's the root of all evil". I think by this point a Markov chain can easily generate responses to the OpenSSL/LibreSSL vulnerability announcements so we don't have to. Yes, C sucks because buffer overflows are still possible. That's by design. At the same time, it goes something like this:

1. OpenSSL (or this time LibreSSL) has a vulnerability discovered.

2. Everyone gets in an uproar about how we need a clean implementation in a language that prevents stupid errors.

3. Someone suggests unit testing. tptacek tells them to go away.

4. Someone actually points out a Haskell project (https://news.ycombinator.com/item?id=7557089).

5. People poo poo any alternative to OpenSSL because it's not 100% feature complete and besides the best crypto people are already working on OpenSSL so what do these schmucks know?

6. Someone points out that in higher level languages it's hard to write code that is resistant against timing attacks. The discussion dies.

I see only two alternatives. Either as a community we actually stop bike shedding and throw our weight behind a project that might actually become a good alternative to OpenSSL, or we accept that the canonical TLS library will be written in C and have bugs that are periodically discovered and quickly patched.

> 5. People poo poo any alternative to OpenSSL because it's not 100% feature complete and besides the best crypto people are already working on OpenSSL so what do these schmucks know?

Here's a strategy:

Take OpenSSL, remove a bunch of stuff that almost nobody needs, rearrange the code to make it clearer. You will get BoringSSL.

Take the BoringSSL code, remove more stuff that people outside of Google generally don't need. Temporarily remove the X.509 code and the TLS code so that you can remove even more stuff.

Next, write bindings for the remaining code for a safe language like Rust, so that the replacement X.509 and TLS code can be written in the safer language, while still using the OpenSSL crypto code.

Then, write the new X.509 code, focusing on what really is needed and ignoring all the extra cruft that was added to X.509 but which doesn't actually improve security.

Then, over time, refactor the the language bindings so more code is written in the safe language and less code is written in C, with the goal of almost all the code that isn't implementing directly crypto algorithms being in the safe language.

Then, add a good, clean TLS implementation in the safe language, that focuses on the good parts of TLS, and that avoids all the legacy cruft that makes TLS seem complicated.

I've been doing an experiment along these lines. I've open sourced two parts so far:

1. https://github.com/briansmith/ring 2. https://github.com/briansmith/webpki

It is a big project, but I am pretty sure it is going to succeed.

> 6. Someone points out that in higher level languages it's hard to write code that is resistant against timing attacks. The discussion dies.

This doesn't matter, because the code that should be resistant to timing attacks should be written in assembly language or a language specially designed for that purpose (that doesn't exist yet) anyway. High-level languages have ways of accessing code written in assembly language.

Anyway, my point is that all these things are solvable.

Rust has some compiler plugin magic that can help you write code resistant to timing attacks.
> This doesn't matter, because the code that should be resistant to timing attacks should be written in assembly language

This would put you right back into buffer overflow territory...

It's unfortunate, but the approach would hopefully be to write the smallest possible primitives in assembly and then use a safer language for the rest of the code that either doesn't need constant time guarantees, or gets those guarantees by building on the primitives. This means that verification against these sort of basic attacks can be focused on a much smaller amount of code, rather than every single location in the whole code-base that manipulates memory (as in C). (And, one can go a step further: extract assembly from some higher-level language/DSL designed to create constant time code.)

In any case, the code in question for this post doesn't seem to be written to be timing sensitive.

Hey, I'm not anti-unit-testing! I just think a TDD reimplementation of OpenSSL is a silly idea.