From 365a1864fd285fc6ee9d9fa1f8770b39d4dab830 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Thu, 12 Feb 2009 07:35:29 +0000 Subject: Fixes Issue #3745: Fix hashlib to always reject unicode and non buffer-api supporting objects as input no matter how it was compiled (built in implementations or external openssl library). --- Lib/test/test_hashlib.py | 12 ++++++++++++ Misc/NEWS | 4 ++++ Modules/_hashopenssl.c | 31 +++++-------------------------- Modules/hashlib.h | 28 ++++++++++++++++++++++++++++ Modules/md5module.c | 17 ++++++++++++----- Modules/sha1module.c | 17 ++++++++++++----- Modules/sha256module.c | 46 ++++++++++++++++++++++++++++++---------------- Modules/sha512module.c | 46 ++++++++++++++++++++++++++++++---------------- 8 files changed, 133 insertions(+), 68 deletions(-) create mode 100644 Modules/hashlib.h diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index e69c704..9b51459 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -63,6 +63,18 @@ class HashLibTestCase(unittest.TestCase): computed = hashlib.new(name, data).hexdigest() self.assertEqual(computed, digest) + def check_no_unicode(self, algorithm_name): + # Unicode objects are not allowed as input. + self.assertRaises(TypeError, getattr(hashlib, algorithm_name), 'spam') + self.assertRaises(TypeError, hashlib.new, algorithm_name, 'spam') + + def test_no_unicode(self): + self.check_no_unicode('md5') + self.check_no_unicode('sha1') + self.check_no_unicode('sha224') + self.check_no_unicode('sha256') + self.check_no_unicode('sha384') + self.check_no_unicode('sha512') def test_case_md5_0(self): self.check('md5', b'', 'd41d8cd98f00b204e9800998ecf8427e') diff --git a/Misc/NEWS b/Misc/NEWS index 7f99d45..c31c1a7 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -491,6 +491,10 @@ C-API Extension Modules ----------------- +- Issue #3745: Fix hashlib to always reject unicode and non buffer-api + supporting objects as input no matter how it was compiled (built in + implementations or external openssl library). + - Issue #4397: Fix occasional test_socket failure on OS X. - Issue #4279: Fix build of parsermodule under Cygwin. diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index bd15b01..569d441 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -15,6 +15,7 @@ #include "Python.h" #include "structmember.h" +#include "hashlib.h" /* EVP is the preferred interface to hashing in OpenSSL */ #include @@ -203,28 +204,6 @@ EVP_hexdigest(EVPobject *self, PyObject *unused) return retval; } -#define MY_GET_BUFFER_VIEW_OR_ERROUT(obj, viewp) do { \ - if (PyUnicode_Check((obj))) { \ - PyErr_SetString(PyExc_TypeError, \ - "Unicode-objects must be encoded before hashing");\ - return NULL; \ - } \ - if (!PyObject_CheckBuffer((obj))) { \ - PyErr_SetString(PyExc_TypeError, \ - "object supporting the buffer API required"); \ - return NULL; \ - } \ - if (PyObject_GetBuffer((obj), (viewp), PyBUF_SIMPLE) == -1) { \ - return NULL; \ - } \ - if ((viewp)->ndim > 1) { \ - PyErr_SetString(PyExc_BufferError, \ - "Buffer must be single dimension"); \ - PyBuffer_Release((viewp)); \ - return NULL; \ - } \ - } while(0); - PyDoc_STRVAR(EVP_update__doc__, "Update this hash object's state with the provided string."); @@ -237,7 +216,7 @@ EVP_update(EVPobject *self, PyObject *args) if (!PyArg_ParseTuple(args, "O:update", &obj)) return NULL; - MY_GET_BUFFER_VIEW_OR_ERROUT(obj, &view); + GET_BUFFER_VIEW_OR_ERROUT(obj, &view); #ifdef WITH_THREAD if (self->lock == NULL && view.len >= HASHLIB_GIL_MINSIZE) { @@ -344,7 +323,7 @@ EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds) } if (data_obj) - MY_GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); + GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); if (!PyArg_Parse(name_obj, "s", &nameStr)) { PyErr_SetString(PyExc_TypeError, "name must be a string"); @@ -507,7 +486,7 @@ EVP_new(PyObject *self, PyObject *args, PyObject *kwdict) } if (data_obj) - MY_GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); + GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); digest = EVP_get_digestbyname(name); @@ -538,7 +517,7 @@ EVP_new(PyObject *self, PyObject *args, PyObject *kwdict) } \ \ if (data_obj) \ - MY_GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); \ + GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); \ \ ret_obj = EVPnew( \ CONST_ ## NAME ## _name_obj, \ diff --git a/Modules/hashlib.h b/Modules/hashlib.h new file mode 100644 index 0000000..db39cea --- /dev/null +++ b/Modules/hashlib.h @@ -0,0 +1,28 @@ +/* Common code for use by all hashlib related modules. */ + +/* + * Given a PyObject* obj, fill in the Py_buffer* viewp with the result + * of PyObject_GetBuffer. Sets and exception and issues a return NULL + * on any errors. + */ +#define GET_BUFFER_VIEW_OR_ERROUT(obj, viewp) do { \ + if (PyUnicode_Check((obj))) { \ + PyErr_SetString(PyExc_TypeError, \ + "Unicode-objects must be encoded before hashing");\ + return NULL; \ + } \ + if (!PyObject_CheckBuffer((obj))) { \ + PyErr_SetString(PyExc_TypeError, \ + "object supporting the buffer API required"); \ + return NULL; \ + } \ + if (PyObject_GetBuffer((obj), (viewp), PyBUF_SIMPLE) == -1) { \ + return NULL; \ + } \ + if ((viewp)->ndim > 1) { \ + PyErr_SetString(PyExc_BufferError, \ + "Buffer must be single dimension"); \ + PyBuffer_Release((viewp)); \ + return NULL; \ + } \ + } while(0); diff --git a/Modules/md5module.c b/Modules/md5module.c index 3d54131..ac98433 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -17,6 +17,7 @@ /* MD5 objects */ #include "Python.h" +#include "hashlib.h" /* Some useful types */ @@ -411,11 +412,14 @@ PyDoc_STRVAR(MD5_update__doc__, static PyObject * MD5_update(MD5object *self, PyObject *args) { + PyObject *obj; Py_buffer buf; - if (!PyArg_ParseTuple(args, "s*:update", &buf)) + if (!PyArg_ParseTuple(args, "O:update", &obj)) return NULL; + GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); + md5_process(&self->hash_state, buf.buf, buf.len); PyBuffer_Release(&buf); @@ -511,14 +515,17 @@ MD5_new(PyObject *self, PyObject *args, PyObject *kwdict) { static char *kwlist[] = {"string", NULL}; MD5object *new; + PyObject *data_obj = NULL; Py_buffer buf; - buf.buf = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s*:new", kwlist, - &buf)) { + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist, + &data_obj)) { return NULL; } + if (data_obj) + GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf); + if ((new = newMD5object()) == NULL) return NULL; @@ -528,7 +535,7 @@ MD5_new(PyObject *self, PyObject *args, PyObject *kwdict) Py_DECREF(new); return NULL; } - if (buf.buf) { + if (data_obj) { md5_process(&new->hash_state, buf.buf, buf.len); PyBuffer_Release(&buf); } diff --git a/Modules/sha1module.c b/Modules/sha1module.c index 4d8ed1d..a7f6ad2 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -17,6 +17,7 @@ /* SHA1 objects */ #include "Python.h" +#include "hashlib.h" /* Some useful types */ @@ -387,11 +388,14 @@ PyDoc_STRVAR(SHA1_update__doc__, static PyObject * SHA1_update(SHA1object *self, PyObject *args) { + PyObject *obj; Py_buffer buf; - if (!PyArg_ParseTuple(args, "s*:update", &buf)) + if (!PyArg_ParseTuple(args, "O:update", &obj)) return NULL; + GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); + sha1_process(&self->hash_state, buf.buf, buf.len); PyBuffer_Release(&buf); @@ -487,14 +491,17 @@ SHA1_new(PyObject *self, PyObject *args, PyObject *kwdict) { static char *kwlist[] = {"string", NULL}; SHA1object *new; + PyObject *data_obj = NULL; Py_buffer buf; - buf.buf = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s*:new", kwlist, - &buf)) { + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist, + &data_obj)) { return NULL; } + if (data_obj) + GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf); + if ((new = newSHA1object()) == NULL) return NULL; @@ -504,7 +511,7 @@ SHA1_new(PyObject *self, PyObject *args, PyObject *kwdict) Py_DECREF(new); return NULL; } - if (buf.buf) { + if (data_obj) { sha1_process(&new->hash_state, buf.buf, buf.len); PyBuffer_Release(&buf); } diff --git a/Modules/sha256module.c b/Modules/sha256module.c index 523f528..c653416 100644 --- a/Modules/sha256module.c +++ b/Modules/sha256module.c @@ -18,6 +18,7 @@ #include "Python.h" #include "structmember.h" +#include "hashlib.h" /* Endianness testing and definitions */ @@ -480,14 +481,17 @@ PyDoc_STRVAR(SHA256_update__doc__, static PyObject * SHA256_update(SHAobject *self, PyObject *args) { - unsigned char *cp; - int len; + PyObject *obj; + Py_buffer buf; - if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) + if (!PyArg_ParseTuple(args, "O:update", &obj)) return NULL; - sha_update(self, cp, len); + GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); + sha_update(self, buf.buf, buf.len); + + PyBuffer_Release(&buf); Py_INCREF(Py_None); return Py_None; } @@ -614,14 +618,17 @@ SHA256_new(PyObject *self, PyObject *args, PyObject *kwdict) { static char *kwlist[] = {"string", NULL}; SHAobject *new; - unsigned char *cp = NULL; - int len; + PyObject *data_obj = NULL; + Py_buffer buf; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, - &cp, &len)) { + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist, + &data_obj)) { return NULL; } + if (data_obj) + GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf); + if ((new = newSHA256object()) == NULL) return NULL; @@ -631,8 +638,10 @@ SHA256_new(PyObject *self, PyObject *args, PyObject *kwdict) Py_DECREF(new); return NULL; } - if (cp) - sha_update(new, cp, len); + if (data_obj) { + sha_update(new, buf.buf, buf.len); + PyBuffer_Release(&buf); + } return (PyObject *)new; } @@ -645,14 +654,17 @@ SHA224_new(PyObject *self, PyObject *args, PyObject *kwdict) { static char *kwlist[] = {"string", NULL}; SHAobject *new; - unsigned char *cp = NULL; - int len; + PyObject *data_obj = NULL; + Py_buffer buf; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, - &cp, &len)) { + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist, + &data_obj)) { return NULL; } + if (data_obj) + GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf); + if ((new = newSHA224object()) == NULL) return NULL; @@ -662,8 +674,10 @@ SHA224_new(PyObject *self, PyObject *args, PyObject *kwdict) Py_DECREF(new); return NULL; } - if (cp) - sha_update(new, cp, len); + if (data_obj) { + sha_update(new, buf.buf, buf.len); + PyBuffer_Release(&buf); + } return (PyObject *)new; } diff --git a/Modules/sha512module.c b/Modules/sha512module.c index 7d67a23..17e417e 100644 --- a/Modules/sha512module.c +++ b/Modules/sha512module.c @@ -18,6 +18,7 @@ #include "Python.h" #include "structmember.h" +#include "hashlib.h" #ifdef PY_LONG_LONG /* If no PY_LONG_LONG, don't compile anything! */ @@ -546,14 +547,17 @@ PyDoc_STRVAR(SHA512_update__doc__, static PyObject * SHA512_update(SHAobject *self, PyObject *args) { - unsigned char *cp; - int len; + PyObject *obj; + Py_buffer buf; - if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) + if (!PyArg_ParseTuple(args, "O:update", &obj)) return NULL; - sha512_update(self, cp, len); + GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); + sha512_update(self, buf.buf, buf.len); + + PyBuffer_Release(&buf); Py_INCREF(Py_None); return Py_None; } @@ -680,14 +684,17 @@ SHA512_new(PyObject *self, PyObject *args, PyObject *kwdict) { static char *kwlist[] = {"string", NULL}; SHAobject *new; - unsigned char *cp = NULL; - int len; + PyObject *data_obj = NULL; + Py_buffer buf; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, - &cp, &len)) { + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist, + &data_obj)) { return NULL; } + if (data_obj) + GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf); + if ((new = newSHA512object()) == NULL) return NULL; @@ -697,8 +704,10 @@ SHA512_new(PyObject *self, PyObject *args, PyObject *kwdict) Py_DECREF(new); return NULL; } - if (cp) - sha512_update(new, cp, len); + if (data_obj) { + sha512_update(new, buf.buf, buf.len); + PyBuffer_Release(&buf); + } return (PyObject *)new; } @@ -711,14 +720,17 @@ SHA384_new(PyObject *self, PyObject *args, PyObject *kwdict) { static char *kwlist[] = {"string", NULL}; SHAobject *new; - unsigned char *cp = NULL; - int len; + PyObject *data_obj = NULL; + Py_buffer buf; - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, - &cp, &len)) { + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist, + &data_obj)) { return NULL; } + if (data_obj) + GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf); + if ((new = newSHA384object()) == NULL) return NULL; @@ -728,8 +740,10 @@ SHA384_new(PyObject *self, PyObject *args, PyObject *kwdict) Py_DECREF(new); return NULL; } - if (cp) - sha512_update(new, cp, len); + if (data_obj) { + sha512_update(new, buf.buf, buf.len); + PyBuffer_Release(&buf); + } return (PyObject *)new; } -- cgit v0.12