From d3ef680701ce1333bb6014037f08cbc99674b24d Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Fri, 16 Sep 2011 14:33:32 -0400 Subject: [PATCH 2/4] Add error-handling to initialization of _hashlib --- Modules/_hashopenssl.c | 89 +++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 77 insertions(+), 12 deletions(-) diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index f921a17..0ee98cf 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -37,6 +37,7 @@ #endif /* EVP is the preferred interface to hashing in OpenSSL */ +#include #include /* We use the object interface to discover what hashes OpenSSL supports. */ #include @@ -76,8 +77,13 @@ typedef struct { EVP_MD_CTX ctx; - /* ctx_ptr will point to ctx above */ + /* ctx_ptr will point to ctx above, unless an initialization error + occurred, when it will be NULL: */ EVP_MD_CTX *ctx_ptr; + + /* If there was an error, we store the error message here (or NULL if the + error string cannot be allocated): */ + PyObject *error_msg; } EVPConstructorCache; #define DEFINE_CONSTS_FOR_NEW(Name) \ @@ -126,6 +132,26 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len) } } +/* Get an error msg for the last error, clearing the error */ +static char * +errstr_for_last_error(void) +{ + char *errstr; + + errstr = ERR_error_string(ERR_peek_last_error(), NULL); + ERR_clear_error(); + + return errstr; +} + +static void +set_exception_for_evp_error(void) +{ + PyErr_SetString(PyExc_ValueError, + errstr_for_last_error()); +} + + /* Internal methods for a hash object */ static void @@ -341,7 +367,12 @@ EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds) PyBuffer_Release(&view); return -1; } - EVP_DigestInit(&self->ctx, digest); + EVP_MD_CTX_init(&self->ctx); + if (!EVP_DigestInit_ex(&self->ctx, digest, NULL)) { + set_exception_for_evp_error(); + PyBuffer_Release(&view); + return -1; + } self->name = name_obj; Py_INCREF(self->name); @@ -440,7 +471,12 @@ EVPnew(PyObject *name_obj, if (initial_ctx) { EVP_MD_CTX_copy(&self->ctx, initial_ctx); } else { - EVP_DigestInit(&self->ctx, digest); + EVP_MD_CTX_init(&self->ctx); + if (!EVP_DigestInit_ex(&self->ctx, digest, NULL)) { + set_exception_for_evp_error(); + Py_DECREF(self); + return NULL; + } } if (cp && len) { @@ -589,11 +625,28 @@ implement_specific_EVP_new(PyObject *self, PyObject *args, if (data_obj) GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); - ret_obj = EVPnew(cached_info->name_obj, - NULL, - cached_info->ctx_ptr, - (unsigned char*)view.buf, - view.len); + /* + * If an error occurred during creation of the global content, the ctx_ptr + * will be NULL, and the error_msg will, if non-NULL, contain the error + * message: + */ + if (cached_info->ctx_ptr) { + /* This context was successfully initialized when _hashlib was + initialized; copy it: */ + ret_obj = EVPnew(cached_info->name_obj, + NULL, + cached_info->ctx_ptr, + (unsigned char*)view.buf, view.len); + } else { + /* Some kind of error happened initializing the cached context for + this digest when _hashlib was initialized. + Raise an exception with the saved error message: */ + if (cached_info->error_msg) { + PyErr_SetObject(PyExc_ValueError, cached_info->error_msg); + } else { + PyErr_SetString(PyExc_ValueError, "Error initializing hash"); + } + } if (data_obj) PyBuffer_Release(&view); @@ -608,7 +661,11 @@ implement_specific_EVP_new(PyObject *self, PyObject *args, " hash object; optionally initialized with a string") \ } -/* used in the init function to setup a constructor */ +/* used in the init function to setup a constructor + + Any that have errors during initialization will end up with a NULL ctx_ptr + entry, and err_msg will be set (unless we're very low on memory) +*/ #define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \ init_constructor_constant(&cached_info_ ## NAME, #NAME); \ } while (0); @@ -619,9 +676,17 @@ init_constructor_constant(EVPConstructorCache *cached_info, const char *name) assert(cached_info); cached_info->name_obj = PyUnicode_FromString(name); if (EVP_get_digestbyname(name)) { - cached_info->ctx_ptr = &cached_info->ctx; - EVP_DigestInit(&cached_info->ctx, - EVP_get_digestbyname(name)); + EVP_MD_CTX_init(&cached_info->ctx); + if (EVP_DigestInit_ex(&cached_info->ctx, + EVP_get_digestbyname(name), NULL)) { + /* Success: */ + cached_info->ctx_ptr = &cached_info->ctx; + } else { + /* Failure: */ + cached_info->ctx_ptr = NULL; + cached_info->error_msg = PyUnicode_FromString(errstr_for_last_error()); + /* this could fail, e.g. low on memory, or encodings */ + } } } -- 1.7.6