[pycrypto] ERROR: testRsaUnversionedSignAndVerify failed

Hans-Peter Jansen hpj at urpla.net
Fri Aug 21 02:10:19 CST 2009


Dear Jan,

I found this changelog entry in SuSEs python-crypto package:

* Thu Oct 19 2006 jmatejek at suse.cz
- minor fixes for better 64bit PEP353 compatibility

and below is a current discussion about this topic.

Am Freitag, 21. August 2009 schrieb Dwayne C. Litzenberger:
> On Thu, Aug 20, 2009 at 11:11:46AM +0200, Hans-Peter Jansen wrote:
> > openSUSE incorporated two patches to 2.0.1:
> >
> > This one, I ported to trunk:
> > --- src/hash_template.c~	2009-08-16 23:39:34.053841534 +0200
> > +++ src/hash_template.c	2009-08-20 10:16:05.877840748 +0200
> > @@ -111,13 +111,15 @@ ALG_hexdigest(ALGobject *self, PyObject
> >  	PyObject *value, *retval;
> >  	unsigned char *raw_digest, *hex_digest;
> >  	int i, j, size;
> > +	Py_ssize_t ssize;
> >
> >  	if (!PyArg_ParseTuple(args, ""))
> >  		return NULL;
> >
> >  	/* Get the raw (binary) digest value */
> >  	value = (PyObject *)hash_digest(&(self->st));
> > -	size = PyString_Size(value);
> > +	ssize = PyString_Size(value);
> > +	size = (ssize > INT_MAX) ? INT_MAX : ssize;
> >  	raw_digest = (unsigned char *) PyString_AsString(value);
> >
> >  	/* Create a new string */
> >
> > Dwayne, is this in order or just plain silly?
>
> Hmm...  What's the purpose of this patch?
>
> I'm assuming this patch is for 64-bit machines, but even with the patch
> applied, you will still have other problems if ssize > INT_MAX (or even
> INT_MAX/2).
>
> Here's the code (with that patch applied) in context:
>
>   	/* Get the raw (binary) digest value */
>   	value = (PyObject *)hash_digest(&(self->st));
> 	ssize = PyString_Size(value);
> 	size = (ssize > INT_MAX) ? INT_MAX : ssize;
> 	raw_digest = (unsigned char *) PyString_AsString(value);
>
>         /* Create a new string */
>         retval = PyString_FromStringAndSize(NULL, size * 2 );
>         hex_digest = (unsigned char *) PyString_AsString(retval);
>
>         /* Make hex version of the digest */
>         for(i=j=0; i<size; i++)
>         {
>                 char c;
>                 c = raw_digest[i] / 16; c = (c>9) ? c+'a'-10 : c + '0';
>                 hex_digest[j++] = c;
>                 c = raw_digest[i] % 16; c = (c>9) ? c+'a'-10 : c + '0';
>                 hex_digest[j++] = c;
>         }
>         Py_DECREF(value);
>         return retval;
>
> If ssize > INT_MAX, then the "size * 2" argument passed to
> PyString_FromStringAndSize() will overflow, causing one of the following
> things to happen:
>
> - If size*2 overflows to a negative number, PyString_FromStringAndSize
> will presumably return NULL, causing a null-pointer dereference in the
> subsequent code.
>
> - If size*2 overflows to a positive number, PyString_FromStringAndSize
> will allocate a smaller buffer than we expect, and the subsequent loop
> wil overflow this buffer.  Even if we fixed that, if size ended up larger
> than INT_MAX/2, we would *still* overflow the buffer, since j would wrap
> around to a negative number.
>
> None of PyCrypto's hash functions return anything close to INT_MAX bytes
> (SHA256 outputs a whopping 32 bytes), so I wonder about the rationale
> behind this patch.  Does it suppress some lint warning?

Jan, while it's hard to believe, that a hash_digest size will ever come near 
INT_MAX for ints (>= 32bit), it's going to overflow anyway 5 lines below.

How about limiting it to a sane value (say 1024)? The biggest hash digest 
size, I found is sha512() with 64 bytes. With 1024, we're raising the limit 
by factor 16. If hashes are going to get bigger then that, further 
adjustment is in order.

Dwayne?

> /me runs splint against the code
>
> No, I doubt it's that.  The C code isn't even close to being lint-clean.
>
> /my adds a TODO item...
>
> Thanks,
>  - Dwayne

Cordially,
Pete


More information about the pycrypto mailing list