make sure to handle r2i extensions (like proxyCertInfo) without segfaulting
diff --git a/setup.py b/setup.py
index 1ebba4f..0bc6580 100755
--- a/setup.py
+++ b/setup.py
@@ -72,7 +72,8 @@
dep = globals()[name.lower() + '_dep']
return Extension(modname, src, libraries=Libraries, depends=dep,
include_dirs=IncludeDirs, library_dirs=LibraryDirs,
- extra_objects=ExtraObjects)
+ extra_objects=ExtraObjects,
+ extra_compile_args=["-O0"])
setup(name='pyOpenSSL', version=__version__,
package_dir = {'OpenSSL': '.'},
diff --git a/src/crypto/x509ext.c b/src/crypto/x509ext.c
index 1d412da..53dc48a 100644
--- a/src/crypto/x509ext.c
+++ b/src/crypto/x509ext.c
@@ -55,13 +55,19 @@
crypto_X509ExtensionObj *
crypto_X509Extension_New(char *type_name, int critical, char *value)
{
+ X509V3_CTX ctx;
crypto_X509ExtensionObj *self;
char* value_with_critical = NULL;
+ /* We have no configuration database - but perhaps we should. Anyhow, the
+ * context is necessary for any extension which uses the r2i conversion
+ * method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx. */
+ X509V3_set_ctx_nodb(&ctx);
+
self = PyObject_New(crypto_X509ExtensionObj, &crypto_X509Extension_Type);
if (self == NULL) {
- return NULL;
+ goto error;
}
self->dealloc = 0;
@@ -74,6 +80,10 @@
* invoke. I do not know where to get the ext_struc it desires for its
* last parameter, though.) */
value_with_critical = malloc(strlen("critical,") + strlen(value) + 1);
+ if (!value_with_critical) {
+ goto critical_malloc_error;
+ }
+
if (critical) {
strcpy(value_with_critical, "critical,");
strcpy(value_with_critical + strlen("critical,"), value);
@@ -82,18 +92,26 @@
}
self->x509_extension = X509V3_EXT_nconf(
- NULL, NULL, type_name, value_with_critical);
+ NULL, &ctx, type_name, value_with_critical);
free(value_with_critical);
if (!self->x509_extension) {
- PyObject_Free(self);
- exception_from_error_queue();
- return NULL;
+ goto nconf_error;
}
self->dealloc = 1;
return self;
+
+ nconf_error:
+ exception_from_error_queue();
+
+ critical_malloc_error:
+ PyObject_Free(self);
+
+ error:
+ return NULL;
+
}
/*
diff --git a/test/test_crypto.py b/test/test_crypto.py
index d4c4b68..2ddb84d 100644
--- a/test/test_crypto.py
+++ b/test/test_crypto.py
@@ -90,13 +90,13 @@
L{X509Extension} accepts an extension type name, a critical flag,
and an extension value and returns an L{X509ExtensionType} instance.
"""
- basic = X509Extension('basicConstraints', 1, 'CA:true')
+ basic = X509Extension('basicConstraints', True, 'CA:true')
self.assertTrue(
isinstance(basic, X509ExtensionType),
"%r is of type %r, should be %r" % (
basic, type(basic), X509ExtensionType))
- comment = X509Extension('nsComment', 0, 'pyOpenSSL unit test')
+ comment = X509Extension('nsComment', False, 'pyOpenSSL unit test')
self.assertTrue(
isinstance(comment, X509ExtensionType),
"%r is of type %r, should be %r" % (
@@ -113,15 +113,23 @@
self.assertRaises(
Error, X509Extension, 'basicConstraints', False, 'blah blah')
+ # Exercise a weird one (an extension which uses the r2i method). This
+ # exercises the codepath that requires a non-NULL ctx to be passed to
+ # X509V3_EXT_nconf. It can't work now because we provide no
+ # configuration database. It might be made to work in the future.
+ self.assertRaises(
+ Error, X509Extension, 'proxyCertInfo', True,
+ 'language:id-ppl-anyLanguage,pathlen:1,policy:text:AB')
+
def test_get_critical(self):
"""
L{X509ExtensionType.get_critical} returns the value of the
extension's critical flag.
"""
- ext = X509Extension('basicConstraints', 1, 'CA:true')
+ ext = X509Extension('basicConstraints', True, 'CA:true')
self.assertTrue(ext.get_critical())
- ext = X509Extension('basicConstraints', 0, 'CA:true')
+ ext = X509Extension('basicConstraints', False, 'CA:true')
self.assertFalse(ext.get_critical())