Wednesday, April 30, 2014


Common LibreSSL porting mistakes



The other day I wrote an article discussing LibreSSL, and the common mistakes being made by those thinking they know how to port it to other platforms. Since then, I've seen even more non-official ports pop up, and even some discussions about various Linux distros or other projects switching from OpenSSL to LibreSSL via one of the ports. I've also gotten multiple requests to elaborate a bit on some of the most common mistakes I'm seeing across these porting projects.

So here is a more verbose explanation of some of the most common problems I'm seeing:

explicit_bzero() isn't.

This function needs to ensure it cannot be optimized out. However, several projects are either using macros to define explicit_bzero as bzero, or are wrapping explicit_bzero() to bzero() without using any optimization parameters which will ensure the function call stays in. Especially problematic in the case of using link-time optimizations (LTO).

reallocarray() directly wrapped to realloc()

The former function receives the size of the element, and how many elements we're dealing with, and the latter just takes a raw amount. It's a good thing to use reallocarray() when you need to reallocate say a struct whatever[5000] to a struct whatever[30000], so you can pass sizeof(struct whatever) and 30000 as two separate parameters, as opposed to calulcating sizeof(struct whatever)*30000 which may overflow. But the naive implementations are just directly wrapping to realloc(), reintroducing the problem that reallocarray() is supposed to be fixing.

There's also issues of alignment to consider when blindly multiplying where small values are concerned, but I won't go into them here.

Poor arc4random_buf() implementations

This function is supposed to fill a buffer using a cryptographically secure pseudorandom number generator. However, I'm seeing a whole class of dumbness here:
  • Using classical pseudorandom number generators.
  • Using older less secure implementations.
  • Using poor sources of entropy like /dev/urandom on Linux, or worse, gettimeofday(), and using them to generate long-lived keys.   

OpenBSD functions may be more secure than counterparts elsewhere

This is a generic issue where OpenBSD is deleting some silly platform wrappers, or reducing multiple functions calls with glue logic down to a single standardized function. OpenBSD is depending on the security of their implementation of said function, while the porters have no idea that their platform is less secure, and have no inkling that something is wrong, because there are no compiler errors about missing functions in this scenario. One common case where this scenario is true is with the calloc() function, where the OpenBSD implementation checks for issues, but several other platforms unfortunately do not.

The future

I've actually predicted all the above problems would appear in ports once I saw what OpenBSD is doing to OpenSSL, before any of the ports of LibreSSL became public. There's a couple of other significant mistakes I'm expecting to see appear in LibreSSL ports, but have not seen yet. These probably already exists in ports I haven't reviewed, or will exist in the wild soon enough. Chief among them is implementing timingsafe_bcmp(). I'm expecting to see implementations which directly wrap to regular bcmp(), which unlike the former, is not performed in constant-time, and can expose the application to timing attacks. I'm confident in this because it's not the first time I've seen OpenBSD projects ported, and all these issues exist till this day in various projects in the wild. If you're going to port a project, please take a moment to really understand the functions you're porting, reviewing the manpages and all the comments in the source code, and truly understanding the ramifications of what you're doing.

As I said before, avoid any LibreSSL port which is not from the LibreSSL team itself, or from another team with a proven track record for knowing how to develop a secure environment.

Lastly, here's some Google searches which may turn up some of the issues mentioned here, but is by no means exhaustive:
https://www.google.com/search?q="-Dexplicit_bzero%3Dbzero"
https://www.google.com/search?q="%23define+explicit_bzero+bzero"
https://www.google.com/search?q="-Dtimingsafe_bcmp%3Dbcmp"
https://www.google.com/search?q="%23define+timingsafe_bcmp+bcmp"

15 comments:

carlos said...

Are you posting these problems to their issue tracker? Or better yet, send patches fixing them?

insane coder said...

I specifically told the author of one of the porting projects floating around out there about it.

Unfortunately though, there are a bunch of porting projects popping up, and I'm not going to stay on top of all of them.

Furthermore, I myself don't necessarily even know the full extent of problems out there. This is meant as a warning to not use any LibreSSL port except from the LibreSSL team itself.

voodooKobra said...

http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/

Max said...

Poor arc4random_buf() implementations. This function is supposed to fill a buffer using a cryptographically secure pseudorandom number generator. However, I'm seeing a whole class of dumbness here: ... Using poor sources of entropy like /dev/urandom on Linux ... and using them to generate long-lived keys.

I'm curious about this statement. /dev/urandom on Linux works by collecting entropy and then running it through a cryptographically secure number generator, so I'm not clear on the difference between that and arc4random_buf(). Especially given recent statements by cryptographers that (except for during boot when there isn't much entropy in the pool) /dev/urandom is good enough for actual use ( http://www.2uo.de/myths-about-urandom/#experts ). Am I missing something?

insane coder said...

Max,

There are a ton of gotchas to using /dev/urandom (or /dev/random for that matter). I will write an article about that.

William Ahern said...

There is nothing inherently wrong with the entropy of /dev/urandom. This blogger is wrong about that, IMHO. You certainly can't use /dev/random on Linux, because it could block indefinitely. And in any event if /dev/urandom is broken so is /dev/random. Entropy guesstimation in this kind of application context is a flawed and unworkable idea, which is why OpenBSD doesn't even have a blocking /dev/random.

There are inherent problems with using a /dev device, though. 1) It won't exist in most chroot jails (ideally your chroot jail is mounted nodev); and 2) even if it exists, it might not be openable because you've hit the process descriptor limit.

The safest way to gather entropy in Linux is by using a little known sysctl. The mibs are CTL_KERN + KERN_RANDOM + RANDOM_UUID. This pulls from the same internal entropy source as /dev/urandom, but doesn't require acquiring a file descriptor.

OpenBSD, NetBSD, and FreeBSD (as of 10.0) all use a sysctl to access the kernel CSPRNG.

Max said...

Thank you William for your comments, and I'll look forward to the blog post from insane coder.

insane coder said...

William, I don't think you understood what I was getting at here. This was not about /dev/random vs dev/urandom.

The problems are way more severe than you describe.

Your safest way to gather entropy in Linux has also been removed some time ago.

Max, and everyone else: The follow up

Max said...

I'm sorry; I'll take the blame for the divergence on /dev/random vs /dev/urandom. My link to quotes by cryptographers on /dev/urandom happened to be part of a larger article about why the blocking nature of /dev/random is unnecessary.

Now I see that the problem isn't in whether the bytes are sufficiently unpredictable (what the cryptographers were commenting on) but on potential trouble with the interface.

insane coder said...

Max, I wouldn't blame you, on rereading what I wrote, I think my line was somewhat confusing. I received half a dozen e-mails from people seeming to think I was fixating specifically on /dev/urandom, and that I was suggesting one must use /dev/random on Linux. So you're not alone.

I meant to say some existing practices were unsafe, and I was referring to some specific examples.

I probably should have written something like: Using /dev/urandom unsafely on Linux, with a fallback on gettimeofday(), is a poor source of entropy. Doing so to generate long-lived keys is dangerous.
I wrote this article in a rush in a response to those asking me to clarify my previous article with some specifics, and in this section, I wasn't careful in how I phrased it.

Unfortunately most readers seem to focus on one thing which doesn't sound right to them, and ignore all the good points raised :(

insane coder said...

Since enough people were writing to me about /dev/random vs. /dev/urandom, I wrote an article about it an other practical problems.

. said...

Carlos is correct. Talking shit without the community sense to solve it is just being a bitchy gossip.

Furthermore, it shows that by LibreSSL not taking leadership over the threshold in a way that OpenSSH Portable has become widely popular. It would be cleaner and less net effort to consolidate porting efforts to a single project under OpenBSD.

Joe P. said...

> I'm on my period said...
> Carlos is correct. Talking shit without the community sense to solve it is just being a bitchy gossip.

So Insane Coder should quit his job, give up his house, family, and friends, and move into the alley next to his local free internet cafe, all so that he can devote enough time to finding each and every one of these horrendous ports that keep popping up and fixing them one by one? Sorry, but "community sense" doesn't apply when the "community" shouldn't exist in the first place.

LibreSSL has said that they're planning to do proper ports if and when they have the funding and the stable codebase to work from, but the "community" knew better, and started making unofficial ports within a week of LibreSSL starting up, with no release version in sight, and without a clue about what the LibreSSL team was actually trying to accomplish. And rather than understanding the mistakes the "community" is making and avoiding these cheap knock-offs, you instead blame the person pointing out the mistakes for "not fixing them"? I don't know how it works where you come from, but in my world, people are responsible for their own mistakes. The people who made these terrible ports are responsible for the security flaws in them, and the people who blindly use them are responsible for their own ignorance. End of story.

Harry Tuttle said...

hej insane coder;

noice read although, although, what i learned from people who (probably) have a clue about crypto, and are talking/writing about it: i'd better stay away from it.

lately i came across the following article and would like your short opinion about it:

http://www.2uo.de/myths-about-urandom/


cheers,

lharry

insane coder said...

Hello Harry,

Regarding that article, it's mostly accurate, although misses some key points.

It doesn't discuss actual difficulty in using /dev/(u)random correctly.

It takes a stance which conflicts with the actual stance by the creator of /dev/(u)random (you can't have it both ways, either you trust its design and use it as its meant to, or you don't trust its design and avoid it).

It also fails to take into account that some implementations which may still be in use have a slew of problems.


Please see my following two articles:

http://insanecoding.blogspot.com/2014/05/a-good-idea-with-bad-usage-devurandom.html

http://insanecoding.blogspot.com/2014/05/dealing-with-randomness.html

To summarize them:
1) /dev/(u)random is hard to use correctly.
2) /dev/(u)random in some situations doesn't return random enough data.
3) /dev/(u)random despite its problems is generally the best option available, but there's ways to improve upon it.
4) Even if you use /dev/(u)random correctly, the code making use of it still has many ways it can go wrong, so your application may still not be safe.