On Friday 08 January 2016 06:57:54 Amos Jeffries wrote:
On 8/01/2016 4:30 a.m., Tim Ruehsen wrote:
On Thursday 07 January 2016 15:05:38 Niels Möller wrote:
Tim Ruehsen writes:
But what's wrong with providing a larger buffer than needed ?
I don't think about it as the size of the provided buffer, but as the requested size of the digest (intended for the usecase of truncated digests). And it's not defined how to produce a 20-byte md5 digest. If
md5_digest(&md5, 20, digest);
were allowed, what should it do? Write 16 bytes, and leave the remaining 4 bytes untouched?
You put the answer into my mouth... yes, that seems intuitive to me.
Then what will the application do with 4 random bytes of output? It clearly is not aware of the 16-byte digest size limit. So what basis do we have to be certain it will output or use only those 16 bytes, and not doing something such as sending the buffer to snprintf with length parameter of 20 there as well. Or worse, passing just the (unterminated) buffer start pointer to sprintf.
???
It is a very bad policy for any code, let alone security code, to just blindly trust that the external software will operate correctly.
Sorry, that is IMO bullshit. You say a low-level function is responsible for what the (high-level caller | application) is doing. *head shake* It is absolutely in the callers responsibility to use the output of any function correctly - and his basis is the documentation.
The choice is also not so black and white. There are a bunch of other "intuitive" actions that could be performed:
You are right, 'intuition' is not the point. The point is what is documented and what not.
Here on Debian I have no man pages for any nettle functions - so I looked into the header files to find the function prototypes and used them 'intuitive'. Which worked immediately until I started to use a larger digest buffer than 'allowed'. I am using the same buffer for other algorithms/hash functions as well, so using 'sizeof' was straight forward. Nettle functions unexpectedly crashed of my application instead of a sane return value(all those function are void, *_digest() could return error or the number of bytes written).
I meanwhile found the nettle docs on the web (http://www.lysator.liu.se/~nisse/nettle/nettle.html#MD5):
########### Function: void md5_digest (struct md5_ctx *ctx, size_t length, uint8_t *digest)
Performs final processing and extracts the message digest, writing it to digest. length may be smaller than MD5_DIGEST_SIZE, in which case only the first length octets of the digest are written. ###########
Not a simple word saying 'If length is larger than MD5_DIGEST_SIZE' the function does not return - it calls abort()'.
I would like to see that documented for every *_digest() function !
Some admins have their jobs due to 'stop-by-assertion' software - at least that is good thing about assertions ;)
I suspect that 'continue-with-silent-data-corruption' software would give them even more work...
Definitely. That's why I try to avoid either of them.
An assertion doesn't give the higher layers a chance to intervene.
The higher layers are clearly broken in their designed use of the nettle API. This is not a dynamic limit being checked, but an explicit and fixed global value of MD5_DIGEST_SIZE.
See the excerpt from the docs above. What you say is not correct, you can provide a smaller digest buffer than MD5_DIGEST_SIZE. If you were right, the 'length' param wouldn't make sense. In my eyes it makes sense as saying: 'digest' is 'length' bytes large - please do not overwrite (= put at most 'length' bytes into 'digest'). The typical C buffer over flow prevention. But any such functions generally are fine with larger buffers - they put their payload into the buffer and leave the rest alone (except otherwise documented). Returning the actual number of bytes put into 'digest' would be of large help as well.
Just an impression for you what I am doing and why fixed digest sizes doesn't matter resp. are uninteresting here:
For my high-level hash function I use GnuTLS (wrapper around nettle|other), Nettle or Gcrypt (configurable).
unsigned char digest[128]; // *should* be large enough, if not we get an error char *algo = <user input> if ((len=hash(algo,text,textlen,digest,digestsize)) < 0) { // error like 'unknown algo', 'digest size too small', ... } else { // got <len> bytes in digest, e.g. print as hex values }
At this level MD5_DIGEST_SIZE etc. is unknown and not interesting.
(For nettle i found the nettle_hash structure variables and it's digest_size variable. Everything is working fine.)
Regards, Tim