[gnutls-dev] Re: bug in _gnutls_pkcs1_rsa_encrypt

Simon Josefsson jas at extundo.com
Tue Aug 17 11:39:44 CEST 2004

Robey Pointer <robey at danger.com> writes:

> I just figured out what was causing a rare (once every 1000 or so) 
> failure in the TLS handshake in our tests.
> In the "case 2" section of _gnutls_pkcs1_rsa_encrypt(), there's a big 
> loop that attempts to replace any zero bytes with a non-zero random 
> number.   This line in particular:
>                if (i<2) ps[i] = rnd[i];
>                else ps[i] = GMAX( rnd[2] + ps[i-1] + ps[i-2], rnd[1]);
> is wrong, because in some cases "rnd[2] + ps[i-1] + ps[i-2]" is 256 or 
> 512, which will be greater than the random byte, but end up being stored 
> as zero.


Further, the CPP macros GMIN/GMAX was using unquoted arguments.  I
fixed this in the development branch.

> After poking around in this function, I have to raise the question:  Is 
> this loop's complexity absolutely necessary?  For every byte in the 
> random buffer, 3 new random bytes are fetched from the random pool, and 
> almost always only the 3rd byte is used.  This seems like a waste of the 
> random pool

I agree.

> and my hunch is that the fetch of 3 random bytes was meant to go
> OUTSIDE the loop.

I'm not sure about this, but in either case, it appears to me that the
replaced zero byte would have a skewed bias (that is, more skewed than
might be expected from the knowledge that it must be 1-255).  Not that
this make any critical difference, though.

> Attached is a patch against 1.0.19 which moves the 3-random-byte fetch 
> outside the loop, and adds a mask inside the GMAX so that only the lower 
> 8 bits count.

Whatever the intention was, IMHO, the logic was convoluted, I have now
installed code which says:

	if ((ret =
	     _gnutls_get_random(ps, psize, GNUTLS_STRONG_RANDOM)) < 0) {
	    return ret;
	for (i = 0; i < psize; i++)
	  while (ps[i] == 0) {
	    if ((ret =
		 _gnutls_get_random(&ps[i], 1, GNUTLS_STRONG_RANDOM)) < 0) {
		return ret;

It seems easier to argue for correctness of the above.  As this is
important code, more eyes on it would be appreciated.  One might have
qualms about a possible infinite loop.  I looked at PKCS#1 1.5 type 2
padding in OpenSSL, and it also loop until non-zero random data is
generated.  Nettle just replace 0 with 1.  People that want to review
the code might find it helpful to review RFC 2313 section 8 and 8.1:

   A block type BT, a padding string PS, and the data D shall be
   formatted into an octet string EB, the encryption block.

              EB = 00 || BT || PS || 00 || D .           (1)

   The block type BT shall be a single octet indicating the structure of
   the encryption block. For this version of the document it shall have
   value 00, 01, or 02. For a private- key operation, the block type
   shall be 00 or 01. For a public-key operation, it shall be 02.

   The padding string PS shall consist of k-3-||D|| octets. For block
   type 00, the octets shall have value 00; for block type 01, they
   shall have value FF; and for block type 02, they shall be
   pseudorandomly generated and nonzero. This makes the length of the
   encryption block EB equal to k.


More information about the Gnutls-devel mailing list