bpo-9146: Raise a ValueError if OpenSSL fails to init a hash func. (#1777)

This helps people in weird FIPS mode environments where common things
like MD5 are not available in the binary as a matter of policy.
This commit is contained in:
Gregory P. Smith 2017-05-24 00:04:38 -07:00 committed by GitHub
parent c9d6dbc290
commit 07244a8301
1 changed files with 36 additions and 9 deletions

View File

@ -139,7 +139,10 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
process = MUNCH_SIZE; process = MUNCH_SIZE;
else else
process = Py_SAFE_DOWNCAST(len, Py_ssize_t, unsigned int); process = Py_SAFE_DOWNCAST(len, Py_ssize_t, unsigned int);
EVP_DigestUpdate(self->ctx, (const void*)cp, process); if (!EVP_DigestUpdate(self->ctx, (const void*)cp, process)) {
_setException(PyExc_ValueError);
break;
}
len -= process; len -= process;
cp += process; cp += process;
} }
@ -209,7 +212,10 @@ EVP_digest(EVPobject *self, PyObject *unused)
return _setException(PyExc_ValueError); return _setException(PyExc_ValueError);
} }
digest_size = EVP_MD_CTX_size(temp_ctx); digest_size = EVP_MD_CTX_size(temp_ctx);
EVP_DigestFinal(temp_ctx, digest, NULL); if (!EVP_DigestFinal(temp_ctx, digest, NULL)) {
_setException(PyExc_ValueError);
return NULL;
}
retval = PyBytes_FromStringAndSize((const char *)digest, digest_size); retval = PyBytes_FromStringAndSize((const char *)digest, digest_size);
EVP_MD_CTX_free(temp_ctx); EVP_MD_CTX_free(temp_ctx);
@ -237,7 +243,10 @@ EVP_hexdigest(EVPobject *self, PyObject *unused)
return _setException(PyExc_ValueError); return _setException(PyExc_ValueError);
} }
digest_size = EVP_MD_CTX_size(temp_ctx); digest_size = EVP_MD_CTX_size(temp_ctx);
EVP_DigestFinal(temp_ctx, digest, NULL); if (!EVP_DigestFinal(temp_ctx, digest, NULL)) {
_setException(PyExc_ValueError);
return NULL;
}
EVP_MD_CTX_free(temp_ctx); EVP_MD_CTX_free(temp_ctx);
@ -362,7 +371,12 @@ EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds)
PyBuffer_Release(&view); PyBuffer_Release(&view);
return -1; return -1;
} }
EVP_DigestInit(self->ctx, digest); if (!EVP_DigestInit(self->ctx, digest)) {
_setException(PyExc_ValueError);
if (data_obj)
PyBuffer_Release(&view);
return -1;
}
self->name = name_obj; self->name = name_obj;
Py_INCREF(self->name); Py_INCREF(self->name);
@ -461,7 +475,11 @@ EVPnew(PyObject *name_obj,
if (initial_ctx) { if (initial_ctx) {
EVP_MD_CTX_copy(self->ctx, initial_ctx); EVP_MD_CTX_copy(self->ctx, initial_ctx);
} else { } else {
EVP_DigestInit(self->ctx, digest); if (!EVP_DigestInit(self->ctx, digest)) {
_setException(PyExc_ValueError);
Py_DECREF(self);
return NULL;
}
} }
if (cp && len) { if (cp && len) {
@ -902,6 +920,8 @@ generate_hash_name_list(void)
* the generic one passing it a python string and are noticeably * the generic one passing it a python string and are noticeably
* faster than calling a python new() wrapper. Thats important for * faster than calling a python new() wrapper. Thats important for
* code that wants to make hashes of a bunch of small strings. * code that wants to make hashes of a bunch of small strings.
* The first call will lazy-initialize, which reports an exception
* if initialization fails.
*/ */
#define GEN_CONSTRUCTOR(NAME) \ #define GEN_CONSTRUCTOR(NAME) \
static PyObject * \ static PyObject * \
@ -918,6 +938,17 @@ generate_hash_name_list(void)
if (!_PyArg_NoStackKeywords(#NAME, kwnames)) { \ if (!_PyArg_NoStackKeywords(#NAME, kwnames)) { \
return NULL; \ return NULL; \
} \ } \
\
if (CONST_new_ ## NAME ## _ctx_p == NULL) { \
EVP_MD_CTX *ctx_p = EVP_MD_CTX_new(); \
if (!EVP_get_digestbyname(#NAME) || \
!EVP_DigestInit(ctx_p, EVP_get_digestbyname(#NAME))) { \
_setException(PyExc_ValueError); \
EVP_MD_CTX_free(ctx_p); \
return NULL; \
} \
CONST_new_ ## NAME ## _ctx_p = ctx_p; \
} \
\ \
if (data_obj) \ if (data_obj) \
GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); \ GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); \
@ -946,10 +977,6 @@ generate_hash_name_list(void)
#define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \ #define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \
if (CONST_ ## NAME ## _name_obj == NULL) { \ if (CONST_ ## NAME ## _name_obj == NULL) { \
CONST_ ## NAME ## _name_obj = PyUnicode_FromString(#NAME); \ CONST_ ## NAME ## _name_obj = PyUnicode_FromString(#NAME); \
if (EVP_get_digestbyname(#NAME)) { \
CONST_new_ ## NAME ## _ctx_p = EVP_MD_CTX_new(); \
EVP_DigestInit(CONST_new_ ## NAME ## _ctx_p, EVP_get_digestbyname(#NAME)); \
} \
} \ } \
} while (0); } while (0);