[Cryptography] Heartbleed and fundamental crypto programming practices

Jay Sulzberger jays at panix.com
Thu Apr 10 23:44:48 EDT 2014




On Thu, 10 Apr 2014, Bill Cox <waywardgeek at gmail.com> wrote:

> On Thu, Apr 10, 2014 at 7:15 AM, Jerry Leichter <leichter at lrw.com> wrote:
>> We've all by now heard of the Heartbleed security disaster.  I haven't seen the actual coding error, but the descriptions indicate that an attacker could cause the server to allocate and return a large buffer, almost all of which was left uninitialized - and often ended up containing various pieces of left-over sensitive information from previously-deleted and now-reused memory blocks.
>>
>> Years ago, when I developed some software in C++, I had a pair of classes called RedString and BlackString, imitating classic crypto usage of the colors.  A RedString contained "sensitive" data - data to be encrypted or that had been encrypted, keys in the clear, etc.  You could convert a RedString to a BlackString by encryption, or the other way around by decryption.  You could not misused a RedString in many obvious ways - e.g., the services that sent data over a link wouldn't access a RedString.
>
> Sounds cool.  Any code I security wrote over a decade ago like that
> should probably be carefully reviewed and patched.  For example, now
> days it is difficult to force the compiler not to optimize away
> clearing of memory on object destruction.  Here's the zeroing function
> from Blake2 I'm using for this purpose:
>
> static inline void secureZeroMemory(void *v, uint32_t n) {
>    volatile uint8_t *p = (volatile uint8_t *)v;
>    while(n--) {
>        *p++ = 0;
>    }
> }
>
> Casting to a volatile pointer is a trick that might not work on all
> compilers, so it should be checked with each.  Even so, you'll still
> leak data.  For example, a password length might have been passed as a
> parameter (as above, when I clear it), and it might be on the stack,
> or in a register.  When interrupts happen, those registers get written
> to different places, and a leak can happen.  If your program gets
> written to swap, core-dumped to a file, or if it's a laptop in
> hibernation, chances are you're red-data can get written to disk.
> With SSDs, you can't erase that data because of the algorithms to
> uniformly distribute writes so that some locations don't wear out too
> fast.

For such code one should not use a compiler which requires a
trick to get a fundamental routine to compile to code which does
the job.

That means no standard C nor C++ compiler.

oo--JS.


>
> Still, I very strongly agree that we should at least *attempt* to
> clear sensitive data ASAP.  One of the silliest things I see in crypto
> APIs is:
>
>    const unsigned char *password
>
> It's even in the PHC (password hashing competition) required "PHS"
> API.  I certainly hope no one actually uses this PHS interface in real
> systems.  It's very tempting, because every one of the 24 entries has
> one, and you can use it to quickly plug any of them into your system.
> I personally would much prefer a generic API to the password hashing
> system than hard-coding a specific one.  It makes the code more
> future-proof.
>
>> More to the point, the destructor of a RedString cleared its memory before releasing it to the free pool.  A Heartbleed attack that revealed 64K of former RedString's would have revealed ... 64K blocks of zeros.
>>
>> It is - or should be - just a fundamental principle of secure coding that you minimize the amount and time you keep "sensitive" data around in memory - *and that you never release control of it*.  It's your responsibility - you don't hand it to the memory allocator.
>
> True, but it doesn't mean you replace the allocator, or defeat various
> memory checks for the sake of speed.  Doing it with a destructor hook,
> like you did, sounds right to me.
>
>> People will tell you they can't afford the extra CPU cost of zeroing the memory.  Nonsense.  The vast bulk of this stuff is material you're encrypting or decrypting.  Think of the zeroization as part of the encryption or decryption process.  How many cycles does it cost to zero one byte of memory?  Not in isolation, but as part of a stream of at least tens of bytes?  It's a fraction of a cycle, added to the multiple cycles you're already paying.
>
> This, unfortunately, does depend on the application somewhat.  Linux
> already zeros memory for you when you return pages back to the kernel:
>
>    http://en.wikipedia.org/wiki/Sbrk
>
> I'm working on memory-hard password hashing for an entry in the PHC,
> and I hash about 3GiB/s on my 3.4GHz Ivy Bridge machine.  Of that,
> maybe 25% is kernel allocation overhead, which probably includes the
> zeroing.  Zeroing before freeing would double that.  At the same time,
> if compiling on a non-Linux box, the safe thing is to zero it as you
> suggest.
>
> Unfortunately, zeroing seems highly system/compiler specific.  We need
> to verify it on every combination.
>
>> I happened to develop a system in C++, which is the only widely-used language that offers *compiler enforced*, user-programmable, cradle-to-grave control over memory allocation.  By putting the code to zero the memory into the destructor, I could guarantee that no RedString could make it back to the free list without being cleared.  There's no way to do that in any other language I know of.  That means you have to enforce the discipline yourself.  Make sure your analogue of a RedString is never simply free'd, or left to the garbage collector - have an explicit routine for marking it no longer used.  There are some tricks you can apply to make it more obvious if this discipline isn't followed.  In a language like C, you can have a library routine to create a RedString that allocates extra memory and returns an address offset into the block malloc() gave you.  If someone tries to free() it directly, there's a good chance the memory allocator will crash, and someone will find
> th
>>  e problem.  In Java, you could have every constructor register the newly-allocated RedString in a hash map somewhere.  Calling the "finish()" function to clear the memory would also remove it from the hash map.  If you just abandon the RedString, it will leak - and your server will eventually run out of memory, again inducing someone to fix the damn bug.  Programmers are trained to hate crashes.  Crashes that reveal hidden bugs in security- critical are a *good* thing!  (Actually, in Java you can use a weak reference to have the GC inform you that the object is ready to be collected, and you can clear it at that point.  Whether you want to rely on a mechanism that leaves sensitive data floating around in memory - but not available to the memory allocator - for an indeterminate time is a legitimate design question.  Also, since String's are immutable in Java, you have the problem that even if you know you've got sensitive data you no longer need stored in a String ... ther
 e
> 's
>>   nothing you can do to get rid of it.)
>>
>> I've seen comments over the years that crypto- (and all security-)related programming should not be left to "general" programmers with no domain expertise.  I'm not aware of any attempt to collect a list of "issues and programming techniques a crypto programmer must know".  Might be useful to have....
>>                                                         -- Jerry
>
> The current state of affairs is terrible.  For example, how should a
> programmer read a password?  Here's an interesting thread on
> Stackoverflow:
>
> http://stackoverflow.com/questions/6856635/hide-password-input-on-terminal
>
> For years, the getpass manpage said getpass was obsolete and not to
> use it.  At the same time, it did not recommend any other solution,
> and AKAIK, there was none.  The current manpage does say in the BUGs
> section that it is critical for the user to clear the password ASAP,
> but there is no hint about how to actually do that in a way that the
> optimizer will honor.
>
> Password security should be simple, and workable.  One critical
> GNU/Linux utility, gksu, is an absolutely evil pile of grotesque code
> that should be erased from existence (it has major bugs that even I
> can't figure out how to fix, which have been there for many years,
> most likely related to it's illegal calling of GTK+ GUI functions on
> non-main thread).  If users feel the way to learn how to write secure
> code is to read what Linux relies on... ugh...
>
> Seriously, a "Writing Secure Code for Dummies" guide would be great.
> I could certainly use it myself.
>
> Bill
> _______________________________________________
> The cryptography mailing list
> cryptography at metzdowd.com
> http://www.metzdowd.com/mailman/listinfo/cryptography
>
>


More information about the cryptography mailing list