Commits

Benjamin Peterson committed 2606d9a

fix possible integer overflows in _hashopenssl #3886

  • Participants
  • Parent commits e2429e2
  • Branches legacy-trunk

Comments (0)

Files changed (3)

File Lib/test/test_hashlib.py

 import hashlib
 import unittest
 from test import test_support
-
+from test.test_support import _4G, precisionbigmemtest
 
 def hexstr(s):
     import string
             m2.update(aas + bees + cees)
             self.assertEqual(m1.digest(), m2.digest())
 
-
     def check(self, name, data, digest):
         # test the direct constructors
         computed = getattr(hashlib, name)(data).hexdigest()
         self.check('md5', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
                    'd174ab98d277d9f5a5611c2c9f419d9f')
 
+    @precisionbigmemtest(size=_4G + 5, memuse=1)
+    def test_case_md5_huge(self, size):
+        if size == _4G + 5:
+            try:
+                self.check('md5', 'A'*size, 'c9af2dff37468ce5dfee8f2cfc0a9c6d')
+            except OverflowError:
+                pass # 32-bit arch
+
+    @precisionbigmemtest(size=_4G - 1, memuse=1)
+    def test_case_md5_uintmax(self, size):
+        if size == _4G - 1:
+            try:
+                self.check('md5', 'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3')
+            except OverflowError:
+                pass # 32-bit arch
 
     # use the three examples from Federal Information Processing Standards
     # Publication 180-1, Secure Hash Standard,  1995 April 17
 Core and Builtins
 -----------------
 
-Library
--------
+Extension Modules
+-----------------
+
+- Issue #3886: Possible integer overflows in the _hashopenssl module were
+  closed.
 
 Tools/Demos
 -----------

File Modules/_hashopenssl.c

 /* EVP is the preferred interface to hashing in OpenSSL */
 #include <openssl/evp.h>
 
+#define MUNCH_SIZE INT_MAX
+
 
 #ifndef HASH_OBJ_CONSTRUCTOR
 #define HASH_OBJ_CONSTRUCTOR 0
     if (!PyArg_ParseTuple(args, "s#:update", &cp, &len))
         return NULL;
 
+    if (len > 0 && len <= MUNCH_SIZE) {
     EVP_DigestUpdate(&self->ctx, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t,
                                                       unsigned int));
-
+    } else {
+        Py_ssize_t offset = 0;
+        while (len) {
+            unsigned int process = len > MUNCH_SIZE ? MUNCH_SIZE : len;
+            EVP_DigestUpdate(&self->ctx, cp + offset, process);
+            len -= process;
+            offset += process;
+        }
+    }
     Py_INCREF(Py_None);
     return Py_None;
 }
     self->name = name_obj;
     Py_INCREF(self->name);
 
-    if (cp && len)
+    if (cp && len) {
+        if (len > 0 && len <= MUNCH_SIZE) {
         EVP_DigestUpdate(&self->ctx, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t,
                                                           unsigned int));
-
+        } else {
+            Py_ssize_t offset = 0;
+            while (len) {
+                unsigned int process = len > MUNCH_SIZE ? MUNCH_SIZE : len;
+                EVP_DigestUpdate(&self->ctx, cp + offset, process);
+                len -= process;
+                offset += process;
+            }
+        }
+    }
+    
     return 0;
 }
 #endif
 static PyObject *
 EVPnew(PyObject *name_obj,
        const EVP_MD *digest, const EVP_MD_CTX *initial_ctx,
-       const unsigned char *cp, unsigned int len)
+       const unsigned char *cp, Py_ssize_t len)
 {
     EVPobject *self;
 
         EVP_DigestInit(&self->ctx, digest);
     }
 
-    if (cp && len)
-        EVP_DigestUpdate(&self->ctx, cp, len);
+    if (cp && len) {
+        if (len > 0 && len <= MUNCH_SIZE) {
+            EVP_DigestUpdate(&self->ctx, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t,
+                                                              unsigned int));
+        } else {
+            Py_ssize_t offset = 0;
+            while (len) {
+                unsigned int process = len > MUNCH_SIZE ? MUNCH_SIZE : len;
+                EVP_DigestUpdate(&self->ctx, cp + offset, process);
+                len -= process;
+                offset += process;
+            }
+        }
+    }
 
     return (PyObject *)self;
 }
 
     digest = EVP_get_digestbyname(name);
 
-    return EVPnew(name_obj, digest, NULL, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t,
-                                                               unsigned int));
+    return EVPnew(name_obj, digest, NULL, cp, len);
 }
 
 /*
                 CONST_ ## NAME ## _name_obj, \
                 NULL, \
                 CONST_new_ ## NAME ## _ctx_p, \
-                cp, Py_SAFE_DOWNCAST(len, Py_ssize_t, unsigned int)); \
+                cp, len); \
     }
 
 /* a PyMethodDef structure for the constructor */