Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 365a186

Browse files
committed
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).
1 parent 3072921 commit 365a186

8 files changed

Lines changed: 133 additions & 68 deletions

File tree

Lib/test/test_hashlib.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ def check(self, name, data, digest):
6363
computed = hashlib.new(name, data).hexdigest()
6464
self.assertEqual(computed, digest)
6565

66+
def check_no_unicode(self, algorithm_name):
67+
# Unicode objects are not allowed as input.
68+
self.assertRaises(TypeError, getattr(hashlib, algorithm_name), 'spam')
69+
self.assertRaises(TypeError, hashlib.new, algorithm_name, 'spam')
70+
71+
def test_no_unicode(self):
72+
self.check_no_unicode('md5')
73+
self.check_no_unicode('sha1')
74+
self.check_no_unicode('sha224')
75+
self.check_no_unicode('sha256')
76+
self.check_no_unicode('sha384')
77+
self.check_no_unicode('sha512')
6678

6779
def test_case_md5_0(self):
6880
self.check('md5', b'', 'd41d8cd98f00b204e9800998ecf8427e')

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,10 @@ C-API
491491
Extension Modules
492492
-----------------
493493

494+
- Issue #3745: Fix hashlib to always reject unicode and non buffer-api
495+
supporting objects as input no matter how it was compiled (built in
496+
implementations or external openssl library).
497+
494498
- Issue #4397: Fix occasional test_socket failure on OS X.
495499

496500
- Issue #4279: Fix build of parsermodule under Cygwin.

Modules/_hashopenssl.c

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "Python.h"
1717
#include "structmember.h"
18+
#include "hashlib.h"
1819

1920
/* EVP is the preferred interface to hashing in OpenSSL */
2021
#include <openssl/evp.h>
@@ -203,28 +204,6 @@ EVP_hexdigest(EVPobject *self, PyObject *unused)
203204
return retval;
204205
}
205206

206-
#define MY_GET_BUFFER_VIEW_OR_ERROUT(obj, viewp) do { \
207-
if (PyUnicode_Check((obj))) { \
208-
PyErr_SetString(PyExc_TypeError, \
209-
"Unicode-objects must be encoded before hashing");\
210-
return NULL; \
211-
} \
212-
if (!PyObject_CheckBuffer((obj))) { \
213-
PyErr_SetString(PyExc_TypeError, \
214-
"object supporting the buffer API required"); \
215-
return NULL; \
216-
} \
217-
if (PyObject_GetBuffer((obj), (viewp), PyBUF_SIMPLE) == -1) { \
218-
return NULL; \
219-
} \
220-
if ((viewp)->ndim > 1) { \
221-
PyErr_SetString(PyExc_BufferError, \
222-
"Buffer must be single dimension"); \
223-
PyBuffer_Release((viewp)); \
224-
return NULL; \
225-
} \
226-
} while(0);
227-
228207
PyDoc_STRVAR(EVP_update__doc__,
229208
"Update this hash object's state with the provided string.");
230209

@@ -237,7 +216,7 @@ EVP_update(EVPobject *self, PyObject *args)
237216
if (!PyArg_ParseTuple(args, "O:update", &obj))
238217
return NULL;
239218

240-
MY_GET_BUFFER_VIEW_OR_ERROUT(obj, &view);
219+
GET_BUFFER_VIEW_OR_ERROUT(obj, &view);
241220

242221
#ifdef WITH_THREAD
243222
if (self->lock == NULL && view.len >= HASHLIB_GIL_MINSIZE) {
@@ -344,7 +323,7 @@ EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds)
344323
}
345324

346325
if (data_obj)
347-
MY_GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view);
326+
GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view);
348327

349328
if (!PyArg_Parse(name_obj, "s", &nameStr)) {
350329
PyErr_SetString(PyExc_TypeError, "name must be a string");
@@ -507,7 +486,7 @@ EVP_new(PyObject *self, PyObject *args, PyObject *kwdict)
507486
}
508487

509488
if (data_obj)
510-
MY_GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view);
489+
GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view);
511490

512491
digest = EVP_get_digestbyname(name);
513492

@@ -538,7 +517,7 @@ EVP_new(PyObject *self, PyObject *args, PyObject *kwdict)
538517
} \
539518
\
540519
if (data_obj) \
541-
MY_GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); \
520+
GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); \
542521
\
543522
ret_obj = EVPnew( \
544523
CONST_ ## NAME ## _name_obj, \

Modules/hashlib.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* Common code for use by all hashlib related modules. */
2+
3+
/*
4+
* Given a PyObject* obj, fill in the Py_buffer* viewp with the result
5+
* of PyObject_GetBuffer. Sets and exception and issues a return NULL
6+
* on any errors.
7+
*/
8+
#define GET_BUFFER_VIEW_OR_ERROUT(obj, viewp) do { \
9+
if (PyUnicode_Check((obj))) { \
10+
PyErr_SetString(PyExc_TypeError, \
11+
"Unicode-objects must be encoded before hashing");\
12+
return NULL; \
13+
} \
14+
if (!PyObject_CheckBuffer((obj))) { \
15+
PyErr_SetString(PyExc_TypeError, \
16+
"object supporting the buffer API required"); \
17+
return NULL; \
18+
} \
19+
if (PyObject_GetBuffer((obj), (viewp), PyBUF_SIMPLE) == -1) { \
20+
return NULL; \
21+
} \
22+
if ((viewp)->ndim > 1) { \
23+
PyErr_SetString(PyExc_BufferError, \
24+
"Buffer must be single dimension"); \
25+
PyBuffer_Release((viewp)); \
26+
return NULL; \
27+
} \
28+
} while(0);

Modules/md5module.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
/* MD5 objects */
1818

1919
#include "Python.h"
20+
#include "hashlib.h"
2021

2122

2223
/* Some useful types */
@@ -411,11 +412,14 @@ PyDoc_STRVAR(MD5_update__doc__,
411412
static PyObject *
412413
MD5_update(MD5object *self, PyObject *args)
413414
{
415+
PyObject *obj;
414416
Py_buffer buf;
415417

416-
if (!PyArg_ParseTuple(args, "s*:update", &buf))
418+
if (!PyArg_ParseTuple(args, "O:update", &obj))
417419
return NULL;
418420

421+
GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
422+
419423
md5_process(&self->hash_state, buf.buf, buf.len);
420424

421425
PyBuffer_Release(&buf);
@@ -511,14 +515,17 @@ MD5_new(PyObject *self, PyObject *args, PyObject *kwdict)
511515
{
512516
static char *kwlist[] = {"string", NULL};
513517
MD5object *new;
518+
PyObject *data_obj = NULL;
514519
Py_buffer buf;
515-
buf.buf = NULL;
516520

517-
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s*:new", kwlist,
518-
&buf)) {
521+
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist,
522+
&data_obj)) {
519523
return NULL;
520524
}
521525

526+
if (data_obj)
527+
GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf);
528+
522529
if ((new = newMD5object()) == NULL)
523530
return NULL;
524531

@@ -528,7 +535,7 @@ MD5_new(PyObject *self, PyObject *args, PyObject *kwdict)
528535
Py_DECREF(new);
529536
return NULL;
530537
}
531-
if (buf.buf) {
538+
if (data_obj) {
532539
md5_process(&new->hash_state, buf.buf, buf.len);
533540
PyBuffer_Release(&buf);
534541
}

Modules/sha1module.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
/* SHA1 objects */
1818

1919
#include "Python.h"
20+
#include "hashlib.h"
2021

2122

2223
/* Some useful types */
@@ -387,11 +388,14 @@ PyDoc_STRVAR(SHA1_update__doc__,
387388
static PyObject *
388389
SHA1_update(SHA1object *self, PyObject *args)
389390
{
391+
PyObject *obj;
390392
Py_buffer buf;
391393

392-
if (!PyArg_ParseTuple(args, "s*:update", &buf))
394+
if (!PyArg_ParseTuple(args, "O:update", &obj))
393395
return NULL;
394396

397+
GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
398+
395399
sha1_process(&self->hash_state, buf.buf, buf.len);
396400

397401
PyBuffer_Release(&buf);
@@ -487,14 +491,17 @@ SHA1_new(PyObject *self, PyObject *args, PyObject *kwdict)
487491
{
488492
static char *kwlist[] = {"string", NULL};
489493
SHA1object *new;
494+
PyObject *data_obj = NULL;
490495
Py_buffer buf;
491-
buf.buf = NULL;
492496

493-
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s*:new", kwlist,
494-
&buf)) {
497+
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist,
498+
&data_obj)) {
495499
return NULL;
496500
}
497501

502+
if (data_obj)
503+
GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf);
504+
498505
if ((new = newSHA1object()) == NULL)
499506
return NULL;
500507

@@ -504,7 +511,7 @@ SHA1_new(PyObject *self, PyObject *args, PyObject *kwdict)
504511
Py_DECREF(new);
505512
return NULL;
506513
}
507-
if (buf.buf) {
514+
if (data_obj) {
508515
sha1_process(&new->hash_state, buf.buf, buf.len);
509516
PyBuffer_Release(&buf);
510517
}

Modules/sha256module.c

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "Python.h"
2020
#include "structmember.h"
21+
#include "hashlib.h"
2122

2223

2324
/* Endianness testing and definitions */
@@ -480,14 +481,17 @@ PyDoc_STRVAR(SHA256_update__doc__,
480481
static PyObject *
481482
SHA256_update(SHAobject *self, PyObject *args)
482483
{
483-
unsigned char *cp;
484-
int len;
484+
PyObject *obj;
485+
Py_buffer buf;
485486

486-
if (!PyArg_ParseTuple(args, "s#:update", &cp, &len))
487+
if (!PyArg_ParseTuple(args, "O:update", &obj))
487488
return NULL;
488489

489-
sha_update(self, cp, len);
490+
GET_BUFFER_VIEW_OR_ERROUT(obj, &buf);
490491

492+
sha_update(self, buf.buf, buf.len);
493+
494+
PyBuffer_Release(&buf);
491495
Py_INCREF(Py_None);
492496
return Py_None;
493497
}
@@ -614,14 +618,17 @@ SHA256_new(PyObject *self, PyObject *args, PyObject *kwdict)
614618
{
615619
static char *kwlist[] = {"string", NULL};
616620
SHAobject *new;
617-
unsigned char *cp = NULL;
618-
int len;
621+
PyObject *data_obj = NULL;
622+
Py_buffer buf;
619623

620-
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist,
621-
&cp, &len)) {
624+
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist,
625+
&data_obj)) {
622626
return NULL;
623627
}
624628

629+
if (data_obj)
630+
GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf);
631+
625632
if ((new = newSHA256object()) == NULL)
626633
return NULL;
627634

@@ -631,8 +638,10 @@ SHA256_new(PyObject *self, PyObject *args, PyObject *kwdict)
631638
Py_DECREF(new);
632639
return NULL;
633640
}
634-
if (cp)
635-
sha_update(new, cp, len);
641+
if (data_obj) {
642+
sha_update(new, buf.buf, buf.len);
643+
PyBuffer_Release(&buf);
644+
}
636645

637646
return (PyObject *)new;
638647
}
@@ -645,14 +654,17 @@ SHA224_new(PyObject *self, PyObject *args, PyObject *kwdict)
645654
{
646655
static char *kwlist[] = {"string", NULL};
647656
SHAobject *new;
648-
unsigned char *cp = NULL;
649-
int len;
657+
PyObject *data_obj = NULL;
658+
Py_buffer buf;
650659

651-
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist,
652-
&cp, &len)) {
660+
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new", kwlist,
661+
&data_obj)) {
653662
return NULL;
654663
}
655664

665+
if (data_obj)
666+
GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf);
667+
656668
if ((new = newSHA224object()) == NULL)
657669
return NULL;
658670

@@ -662,8 +674,10 @@ SHA224_new(PyObject *self, PyObject *args, PyObject *kwdict)
662674
Py_DECREF(new);
663675
return NULL;
664676
}
665-
if (cp)
666-
sha_update(new, cp, len);
677+
if (data_obj) {
678+
sha_update(new, buf.buf, buf.len);
679+
PyBuffer_Release(&buf);
680+
}
667681

668682
return (PyObject *)new;
669683
}

0 commit comments

Comments
 (0)