
Common LibreSSL porting mistakes - edwintorok
http://insanecoding.blogspot.com/2014/04/common-libressl-porting-mistakes.html
======
frik
Have you noticed the annoying "blink" (and the Comics Sans) on
[http://www.libressl.org](http://www.libressl.org) ?

    
    
      <blink>Coming Soon Please Be Patient</blink>
    

As modern browser don't show the "blink" tag, I looked deeper in the source
(CSS):

    
    
      blink {
        animation:blink 1s;
        animation-iteration-count: infinite;
        -webkit-animation:blink 1s;
        -webkit-animation-iteration-count: infinite;
      }
      @keyframes blink {
        0%{opacity:0.0;}
        50%{opacity:0.0;}
        50.01%{opacity:1.0;}
        100%{opacity:1.0;}
      }
      @-webkit-keyframes blink {
        0%{opacity:0.0;}
        50%{opacity:0.0;}
        50.01%{opacity:1.0;}
        100%{opacity:1.0;}
      }
    

Well, later I saw their footer message.

~~~
sanderjd
Reminds me of the geocities bootstrap theme[0]. I'm surprised they don't have
a scrolling marquee!

[0]: [http://code.divshot.com/geo-bootstrap/](http://code.divshot.com/geo-
bootstrap/)

------
joosters
I thought /dev/urandom was meant to be just fine to use?

[http://www.2uo.de/myths-about-urandom/](http://www.2uo.de/myths-about-
urandom/)

~~~
brigade
They're probably referring to the bug/"feature" in Linux's implementation,
which will happily return data before the system has enough entropy, instead
of the sane behavior of blocking on _only_ the first calls to it.

Fortunately major distros work around this bug, so it's only an issue in
unusual cases, like cloud VMs.

See also [http://sockpuppet.org/blog/2014/02/25/safely-generate-
random...](http://sockpuppet.org/blog/2014/02/25/safely-generate-random-
numbers/)

~~~
sitkack
Your random number generator shouldn't block.

~~~
derefr
Would it help to think of it as a (kernel) RNG daemon that you're trying to
connect to, that doesn't finish starting up until it's seeded? That's
basically what the blocking means, in the OpenBSD case.

~~~
sitkack
Which is the correct behavior. `/dev/urandom` should really be the only source
of randomness on Linux. Mac [0] got this right, FreeBSD [1] gets this right. I
totally agree with sockpuppet. Solving the tabula rasa system boot is a
separate issue. _Temporarily_ blocking for seeding is fine, my __shouldn 't
__was an RFC shouldn 't.

[0]
[https://developer.apple.com/library/mac/documentation/Darwin...](https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man4/random.4.html)

[1]
[https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4](https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4)

------
loftsy
I've had a quick browse through the LibreSSL commits. There is some comedy
gold in there.

Check out:

[http://freshbsd.org/commit/openbsd/e5136d69ece4682e6167c8f4a...](http://freshbsd.org/commit/openbsd/e5136d69ece4682e6167c8f4a8122270236898bf)

[http://freshbsd.org/commit/openbsd/c862290df5533966091ded390...](http://freshbsd.org/commit/openbsd/c862290df5533966091ded3906da184f1cac8675)

[http://freshbsd.org/commit/openbsd/a35e815be16befe27ee3f7623...](http://freshbsd.org/commit/openbsd/a35e815be16befe27ee3f7623adfd5fc5e6693f4)

~~~
raverbashing
The big-endian x86 is probably the worse one, but they're all gold

~~~
Intermernet
That big-endian bug is a perfect example of OCD in coding.

"I can't ever reach that code path so I'll remove it".

I have caught myself doing this in some cases. I once removed a test to see if
the CSPRNG was actually working because the test coverage showed that I could
never reach that code-path. I then realised that this needed to be there,
because otherwise, if the CSPRNG ever _stopped_ working, the code wouldn't
know about it, and (maybe) start using streams of zeroes as it's entropy.

Sometimes you need to remember that hardware can fail, or be compromised, even
though in most cases it will just cause the program to crash.

------
jbert
Would it be possible to add system tests for some/all of these problems?

e.g. a test which calls explicit_bzero() in a way which would have it
optimised out in a platform with a low-quality port.

A reasonably descriptive comment in the header (or failure text) of the test
should guide a porter onto the path of wisdom.

(If there is a problem in that the test would need to inspect the output of
explicit_bzero(), hence negating the optimisation, it can be implemented as
multiple processes).

~~~
clarry
How does the other process inspect the memory at the right time? How do you
know all the scenarios where some compiler would optimize things out? It
doesn't sound like it'd be easy to do a portable & reliable test.

Testing that your entropy source is good sounds harder still.

reallocarray() should be pretty easy to test though.

But how many potential issues will your tests miss? If we had perfect test
coverage for everything (and the tests were perfect, or we had test for
_them_...), all software would be 100% bug-free.

Tests might not hurt, but I am not sure trying to cater for braindead porters
is a good idea. They might get the idea they're doing it right once they get
the tests to pass one way or another...

Reasonably descriptive commentary on the mentioned functions is there in the
man pages. That is where porters should look.

~~~
jbert
> How does the other process inspect the memory at the right time?

There must be some side effect of the optimisation, otherwise there wouldn't
be a problem. Detect that side effect (e.g. write a buffer of memory to disk,
check timing of some code, ptrace-attach to the other process and inspect it,
trigger a core dump and pick over the bones, code up an exploit which would
work if the explicit_bzero() wasn't present)

> How do you know all the scenarios where some compiler would optimize things
> out?

You only really need to know one case where the compiler will, if the prevent-
optimisation compiler magic isn't sprinkled on it.

> Tests might not hurt, but I am not sure trying to cater for braindead
> porters is a good idea. They might get the idea they're doing it right once
> they get the tests to pass one way or another...

At least they'd get an idea that something was up. I guess you might get away
with:

    
    
        #ifndef OPENBSD
        #error "You can't just call bcopy() for explicit_bcopy() - see http://good-description-here why not"
        #endif

~~~
clarry
> At least they'd get an idea that something was up.

If they are up for the job, they get that idea when they try to compile the
thing and it doesn't because they are missing a function. They will read that
function's documentation, and understand it; they may even take a peek at the
implementation too, before porting it or implementing their own.

Call me smug but I think porting security sensitive software should be left to
people who have a clue. If you have to litter the code with hints and
education for people who don't know what they are doing, then you end up with
a port that was done by someone who seemed like he might know what he's doing,
when there's a good chance that he doesn't. I would rather be able to
immediately recognize ports made by people who obviously don't have a clue. So
I know what to avoid...

I am all for education, by the way. There are good secure coding guides out
there, though having more wouldn't hurt. I just don't believe the approach you
proposed is a good one.

------
clarry
How many systems today get calloc() wrong? I checked the implementation of
quite a few open source implementations a year or two back, and I don't recall
seeing one get it wrong.

~~~
X-Istence
The question is whether they do overflow checks if you pass in two very large
integers...

~~~
clarry
Exactly. A conforming implementation must do that. I didn't find one that
doesn't, although I didn't look too hard either.

------
mzs
A bit off-topic (sorry) but the recent decision to allow ANSSI FRP256v1 in
libressl worries me:

[http://opensslrampage.org/post/84442190366/add-support-
for-t...](http://opensslrampage.org/post/84442190366/add-support-for-the-
french-anssi-frp256v1-elliptic)

I get that logic in the post, but there are concerns that FRP256v1 was
weakened in the standard similarly to the FIPS curves. So I'm not sure that is
good reasoning. Also I am unsure if the libressl/openssl implementation has
good small subgroup attack defenses even.

~~~
X-Istence
Are you suggesting they remove all curves that may be tainted and ship without
them? Thereby forcing application developers that do want to use them to
implement each and every single one themselves?

~~~
mzs
I suppose so, but I'd rather people not use anything other than Goldilocks or
41417. I'm hoping that for those applications if they are forced so use
something like p=192 they ignore the ECC option entirely, don't code it, and
fallback to some interoperable DSA or RSA scheme instead in whatever protocol
it may be. Maybe there is some case where that is not possible?

------
callesgg
To me it seams way to early to switch.

Wait until libreSSL is battle tested, and we know if it is actually better or
worse than the original.

~~~
scrollaway
How exactly do you think LibreSSL _will_ be battle tested?

~~~
callesgg
By OpenBSD

From [http://www.libressl.org/](http://www.libressl.org/) "LibreSSL is
primarily developed by the OpenBSD Project, and its first inclusion into an
operating system will be in OpenBSD 5.6. "

~~~
icebraining
OpenBSD will tests its implementation; it probably won't test ports to other
OSs. So unless you use OpenBSD yourself, it won't be of much help.

~~~
i386
Will they? Point me to their CI server

~~~
estebank
I can point you to their test rack:

[http://www.openbsd.org/images/rack2009.jpg](http://www.openbsd.org/images/rack2009.jpg)

They run every version of OpenBSD in every machine they support, including
32bit SPARC, HP 300 and SGI. By running in all those machines they uncover
subtle bugs that are made evident by architecture differences.

Also, please see [http://anoncvs.estpak.ee/cgi-bin/cgit/openbsd-
src/tree/regre...](http://anoncvs.estpak.ee/cgi-bin/cgit/openbsd-
src/tree/regress)

~~~
makomk
That wouldn't have caught Heartbleed, wouldn't have caught a vulnerability
like the one in Apple's TLS implementation, wouldn't have caught... Basically,
testing that your software works in normal operation isn't enough to ensure
it's secure, you need to explicitly test its behaviour under attack.

~~~
bsder
Actually, OpenBSD _did_ have things in place that would have caught
Heartbleed. OpenSSL went out of their way to create a situation that defeated
them.

Look, the whole OpenSSL debacle is the fact that OpenSSL has _ONE_ programmer
working on it reliably. LibreSSL now has 5x-10x the manpower that was working
on OpenSSL--and that's _STILL_ probably low by an order of magnitude.

Google should pledge 5 people to work on LibreSSL _by itself_. They clearly
have them since one of their internal audits uncovered Heartbleed.

The thing is nobody in the companies actually cared until the NSA started
spying on _them_.

------
bananas
I think some of this rant is invalid.

If you look at the portable versions of their products they tend to ship a
chunk of the OpenBSD library implementation with them to give consistency
guarantees.

Perhaps we need a consistent OpenBSD platform abstraction layer that gives
solid guarantees?

~~~
lplplplplp
Most is invalid in principle, perhaps not in practice (stupid as that is):

1\. Ye shall use C11 memset_s().

2\. Ye shall (as you note) use a reallocarray() with OpenBSD-like (ANSI C)
wrap checking.

3\. Ye shall use /dev/urandom on Linux (I know you guys love him, see
[https://news.ycombinator.com/item?id=7361868](https://news.ycombinator.com/item?id=7361868)
by tptacek)

4\. Also, timingsafe_bcmp() is 3 lines of ANSI C99 code (minus variable and
function declarations), include it with the code (as you note).

------
malkia
Not sure whether it helps, but here is way to force a "C" function to never be
inlined (by asking for it's address, and then calling it):

[http://www.flipcode.com/archives/Forcing_Functions_To_Be_Cal...](http://www.flipcode.com/archives/Forcing_Functions_To_Be_Called_Non-
inlined.shtml)

~~~
silvestrov
Both of the methods on the page are easy to optimize out. GCC does optimize
the first version out.

These methods are not safe and they do not ensure that the compiler doesn't
optimize out a call to bzero.

~~~
malkia
I guess you are right. 10+ years ago that made the trick :)

Probably there is some declspec/attribute for it.

------
frik
Is someone working on a Win32/64 port?

~~~
valarauca1
The problem with porting POSIX code to Win32/64 is other then windows not
being POSIX which causes a lot of problems to start with.

Windows lacks a lot of fundamental equals to Unix-Like system calls. I.E.:
Windows has no equal to Fork, instead you need to use something like spawn(),
and do some tricky memory cloning to get the same effect.

In fact one could say there _is no port_ of OpenSSL for windows. It hasn't
been updated since 2004, and lacks 64bit support.

~~~
cypher543
What are you talking about?

OpenSSL doesn't need the fork system call and it already builds just fine on
Win32 and Win64. You can even get pre-built binaries of the latest release:

[http://slproweb.com/products/Win32OpenSSL.html](http://slproweb.com/products/Win32OpenSSL.html)

