summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Paul Calderone <exarkun@divmod.com>2011-05-10 20:24:34 -0400
committerJean-Paul Calderone <exarkun@divmod.com>2011-05-10 20:24:34 -0400
commit9eff5699339c34439d7085e937abd0f3b9235afe (patch)
tree6f169497a82281d9f5bebb9a0ea4ab3335c6255e
parent78705f2e0adb0f6cbe88027ef5451a229521774c (diff)
parent24dfb333d9282289d7010eee26f16b6612d8347c (diff)
downloadpyopenssl-9eff5699339c34439d7085e937abd0f3b9235afe.tar.gz
Support OpenSSL 1.0
-rw-r--r--ChangeLog24
-rw-r--r--OpenSSL/crypto/crypto.h13
-rw-r--r--OpenSSL/crypto/pkcs12.c28
-rw-r--r--OpenSSL/ssl/context.c21
-rw-r--r--OpenSSL/test/test_crypto.py28
-rw-r--r--OpenSSL/test/test_ssl.py14
-rw-r--r--OpenSSL/test/util.py16
7 files changed, 119 insertions, 25 deletions
diff --git a/ChangeLog b/ChangeLog
index e4d0901..d16f254 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,26 @@
-2011-04-15 Jean-Paul CAlderone <exarkun@twistedmatrix.com>
+2011-05-10 Jean-Paul Calderone <exarkun@twistedmatrix.com>
+
+ * OpenSSL/crypto/crypto.h: Work around a Windows/OpenSSL 1.0 issue
+ explicitly including a Windows header before any OpenSSL headers.
+
+ * OpenSSL/crypto/pkcs12.c: Work around an OpenSSL 1.0 issue by
+ explicitly flushing errors known to be uninteresting after calling
+ PKCS12_parse.
+
+ * OpenSSL/ssl/context.c: Remove SSLv2 support if the underlying
+ OpenSSL library does not provide it.
+
+ * OpenSSL/test/test_crypto.py: Support an OpenSSL 1.0 change from
+ MD5 to SHA1 by allowing either hash algorithm's result as the
+ return value of X509.subject_name_hash.
+
+ * OpenSSL/test/test_ssl.py: Support an OpenSSL 1.0 change from MD5
+ to SHA1 by constructing certificate files named using both hash
+ algorithms' results when testing Context.load_verify_locations.
+
+ * Support OpenSSL 1.0.0a.
+
+2011-04-15 Jean-Paul Calderone <exarkun@twistedmatrix.com>
* OpenSSL/ssl/ssl.c: Add OPENSSL_VERSION_NUMBER, SSLeay_version
and related constants for retrieving version information about the
diff --git a/OpenSSL/crypto/crypto.h b/OpenSSL/crypto/crypto.h
index 35fbe74..4006e71 100644
--- a/OpenSSL/crypto/crypto.h
+++ b/OpenSSL/crypto/crypto.h
@@ -14,6 +14,19 @@
#define PyOpenSSL_CRYPTO_H_
#include <Python.h>
+/* Work around a bug in OpenSSL 1.0.0 which is caused by winsock.h being
+ included (from dtls1.h) too late by the OpenSSL header files, overriding
+ the fixes (in ossl_typ.h) for symbol clashes caused by this OS header
+ file.
+
+ In order to have those fixes still take effect, we include winsock.h
+ here, prior to including any OpenSSL header files.
+
+ */
+#ifdef _WIN32
+# include "winsock.h"
+#endif
+
#include "x509.h"
#include "x509name.h"
#include "netscape_spki.h"
diff --git a/OpenSSL/crypto/pkcs12.c b/OpenSSL/crypto/pkcs12.c
index 79047e3..a1a5a79 100644
--- a/OpenSSL/crypto/pkcs12.c
+++ b/OpenSSL/crypto/pkcs12.c
@@ -337,15 +337,25 @@ crypto_PKCS12_New(PKCS12 *p12, char *passphrase) {
}
/* parse the PKCS12 lump */
- if (p12 && !PKCS12_parse(p12, passphrase, &pkey, &cert, &cacerts)) {
- /*
- * If PKCS12_parse fails, and it allocated cacerts, it seems to free
- * cacerts, but not re-NULL the pointer. Zounds! Make sure it is
- * re-set to NULL here, else we'll have a double-free below.
- */
- cacerts = NULL;
- exception_from_error_queue(crypto_Error);
- goto error;
+ if (p12) {
+ if (!PKCS12_parse(p12, passphrase, &pkey, &cert, &cacerts)) {
+ /*
+ * If PKCS12_parse fails, and it allocated cacerts, it seems to
+ * free cacerts, but not re-NULL the pointer. Zounds! Make sure
+ * it is re-set to NULL here, else we'll have a double-free below.
+ */
+ cacerts = NULL;
+ exception_from_error_queue(crypto_Error);
+ goto error;
+ } else {
+ /*
+ * OpenSSL 1.0.0 sometimes leaves an X509_check_private_key error in
+ * the queue for no particular reason. This error isn't interesting
+ * to anyone outside this function. It's not even interesting to
+ * us. Get rid of it.
+ */
+ flush_error_queue();
+ }
}
if (!(self = PyObject_GC_New(crypto_PKCS12Obj, &crypto_PKCS12_Type))) {
diff --git a/OpenSSL/ssl/context.c b/OpenSSL/ssl/context.c
index 4edb012..f178eec 100644
--- a/OpenSSL/ssl/context.c
+++ b/OpenSSL/ssl/context.c
@@ -237,6 +237,15 @@ global_info_callback(const SSL *ssl, int where, int _ret)
return;
}
+/*
+ * More recent builds of OpenSSL may have SSLv2 completely disabled.
+ */
+#ifdef OPENSSL_NO_SSL2
+#define SSLv2_METHOD_TEXT ""
+#else
+#define SSLv2_METHOD_TEXT "SSLv2_METHOD, "
+#endif
+
static char ssl_Context_doc[] = "\n\
Context(method) -> Context instance\n\
@@ -244,10 +253,12 @@ Context(method) -> Context instance\n\
OpenSSL.SSL.Context instances define the parameters for setting up new SSL\n\
connections.\n\
\n\
-@param method: One of SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, or\n\
+@param method: One of " SSLv2_METHOD_TEXT "SSLv3_METHOD, SSLv23_METHOD, or\n\
TLSv1_METHOD.\n\
";
+#undef SSLv2_METHOD_TEXT
+
static char ssl_Context_load_verify_locations_doc[] = "\n\
Let SSL know where we can find trusted certificates for the certificate\n\
chain\n\
@@ -1107,11 +1118,19 @@ static PyMethodDef ssl_Context_methods[] = {
*/
static ssl_ContextObj*
ssl_Context_init(ssl_ContextObj *self, int i_method) {
+#if (OPENSSL_VERSION_NUMBER >> 28) == 0x01
+ const
+#endif
SSL_METHOD *method;
switch (i_method) {
case ssl_SSLv2_METHOD:
+#ifdef OPENSSL_NO_SSL2
+ PyErr_SetString(PyExc_ValueError, "SSLv2_METHOD not supported by this version of OpenSSL");
+ return NULL;
+#else
method = SSLv2_method();
+#endif
break;
case ssl_SSLv23_METHOD:
method = SSLv23_method();
diff --git a/OpenSSL/test/test_crypto.py b/OpenSSL/test/test_crypto.py
index 3d17767..496dc59 100644
--- a/OpenSSL/test/test_crypto.py
+++ b/OpenSSL/test/test_crypto.py
@@ -26,6 +26,13 @@ from OpenSSL.crypto import NetscapeSPKI, NetscapeSPKIType
from OpenSSL.crypto import sign, verify
from OpenSSL.test.util import TestCase, bytes, b
+def normalize_certificate_pem(pem):
+ return dump_certificate(FILETYPE_PEM, load_certificate(FILETYPE_PEM, pem))
+
+
+def normalize_privatekey_pem(pem):
+ return dump_privatekey(FILETYPE_PEM, load_privatekey(FILETYPE_PEM, pem))
+
root_cert_pem = b("""-----BEGIN CERTIFICATE-----
MIIC7TCCAlagAwIBAgIIPQzE4MbeufQwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE
@@ -80,7 +87,7 @@ uzujnS8YXWvM7DM1Ilozk4MzPug8jzFp5uhKCQ==
-----END CERTIFICATE-----
""")
-server_key_pem = b("""-----BEGIN RSA PRIVATE KEY-----
+server_key_pem = normalize_privatekey_pem(b("""-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQC+pvhuud1dLaQQvzipdtlcTotgr5SuE2LvSx0gz/bg1U3u1eQ+
U5eqsxaEUceaX5p5Kk+QflvW8qdjVNxQuYS5uc0gK2+OZnlIYxCf4n5GYGzVIx3Q
SBj/TAEFB2WuVinZBiCbxgL7PFM1Kpa+EwVkCAduPpSflJJPwkYGrK2MHQIDAQAB
@@ -95,7 +102,7 @@ FwwOhpahld+vqhYk+pfuWWUpQciE+Bu7ZQJASjfT4sQv4qbbKK/scePicnDdx9th
NaeNCFfH3aeTrX0LyQJAMBWjWmeKM2G2sCExheeQK0ROnaBC8itCECD4Jsve4nqf
r50+LF74iLXFwqysVCebPKMOpDWp/qQ1BbJQIPs7/A==
-----END RSA PRIVATE KEY-----
-""")
+"""))
client_cert_pem = b("""-----BEGIN CERTIFICATE-----
MIICJjCCAY+gAwIBAgIJAKxpFI5lODkjMA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
@@ -113,7 +120,7 @@ PSTJCjJOn3xo2NTKRgV1gaoTf2EhL+RG8TQ=
-----END CERTIFICATE-----
""")
-client_key_pem = b("""-----BEGIN RSA PRIVATE KEY-----
+client_key_pem = normalize_privatekey_pem(b("""-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDAZh/SRtNm5ntMT4qb6YzEpTroMlq2rn+GrRHRiZ+xkCw/CGNh
btPir7/QxaUj26BSmQrHw1bGKEbPsWiW7bdXSespl+xKiku4G/KvnnmWdeJHqsiX
eUZtqurMELcPQAw9xPHEuhqqUJvvEoMTsnCEqGM+7DtboCRajYyHfluARQIDAQAB
@@ -128,7 +135,7 @@ si6xwT7GzMDkk/ko684AV3KPc/h6G0yGtFIrMg7J3uExpR/VdH2KgwMkZXisSMvw
JJEQjOMCVsEJlRk54WWjAkEAzoZNH6UhDdBK5F38rVt/y4SEHgbSfJHIAmPS32Kq
f6GGcfNpip0Uk7q7udTKuX7Q/buZi/C4YW7u3VKAquv9NA==
-----END RSA PRIVATE KEY-----
-""")
+"""))
cleartextCertificatePEM = b("""-----BEGIN CERTIFICATE-----
MIIC7TCCAlagAwIBAgIIPQzE4MbeufQwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE
@@ -150,7 +157,8 @@ w/njVbKMXrvc83qmTdGl3TAM0fxQIpqgcglFLveEBgzn
-----END CERTIFICATE-----
""")
-cleartextPrivateKeyPEM = b("""-----BEGIN RSA PRIVATE KEY-----
+cleartextPrivateKeyPEM = normalize_privatekey_pem(b("""\
+-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQD5mkLpi7q6ROdu7khB3S9aanA0Zls7vvfGOmB80/yeylhGpsjA
jWen0VtSQke/NlEPGtO38tsV7CsuFnSmschvAnGrcJl76b0UOOHUgDTIoRxC6QDU
3claegwsrBA+sJEBbqx5RdXbIRGicPG/8qQ4Zm1SKOgotcbwiaor2yxZ2wIDAQAB
@@ -165,7 +173,7 @@ ttXigLnCqR486JDPTi9ZscoZkZ+w7y6e/hH8t6d5Vjt48JVyfjPIaJY+km58LcN3
6AWSeGAdtRFHVzR7oHjVAkB4hutvxiOeiIVQNBhM6RSI9aBPMI21DoX2JRoxvNW2
cbvAhow217X9V0dVerEOKxnNYspXRrh36h7k4mQA+sDq
-----END RSA PRIVATE KEY-----
-""")
+"""))
cleartextCertificateRequestPEM = b("""-----BEGIN CERTIFICATE REQUEST-----
MIIBnjCCAQcCAQAwXjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAklMMRAwDgYDVQQH
@@ -1465,7 +1473,11 @@ WpOdIpB8KksUTCzV591Nr1wd
name.
"""
cert = load_certificate(FILETYPE_PEM, self.pemData)
- self.assertEquals(cert.subject_name_hash(), 3350047874)
+ self.assertIn(
+ cert.subject_name_hash(),
+ [3350047874, # OpenSSL 0.9.8, MD5
+ 3278919224, # OpenSSL 1.0.0, SHA1
+ ])
@@ -1686,7 +1698,7 @@ class PKCS12Tests(TestCase):
dumped_p12 = p12.export(passphrase=passwd, iter=2, maciter=3)
reloaded_p12 = load_pkcs12(dumped_p12, passwd)
self.assertEqual(
- p12.get_friendlyname(),reloaded_p12.get_friendlyname())
+ p12.get_friendlyname(), reloaded_p12.get_friendlyname())
# We would use the openssl program to confirm the friendly
# name, but it is not possible. The pkcs12 command
# does not store the friendly name in the cert's
diff --git a/OpenSSL/test/test_ssl.py b/OpenSSL/test/test_ssl.py
index 99aa6fb..ff2e725 100644
--- a/OpenSSL/test/test_ssl.py
+++ b/OpenSSL/test/test_ssl.py
@@ -558,12 +558,14 @@ class ContextTests(TestCase, _LoopbackMixin):
"""
capath = self.mktemp()
makedirs(capath)
- # Hash value computed manually with c_rehash to avoid depending on
- # c_rehash in the test suite.
- cafile = join(capath, 'c7adac82.0')
- fObj = open(cafile, 'w')
- fObj.write(cleartextCertificatePEM.decode('ascii'))
- fObj.close()
+ # Hash values computed manually with c_rehash to avoid depending on
+ # c_rehash in the test suite. One is from OpenSSL 0.9.8, the other
+ # from OpenSSL 1.0.0.
+ for name in ['c7adac82.0', 'c3705638.0']:
+ cafile = join(capath, name)
+ fObj = open(cafile, 'w')
+ fObj.write(cleartextCertificatePEM.decode('ascii'))
+ fObj.close()
self._load_verify_locations_test(None, capath)
diff --git a/OpenSSL/test/util.py b/OpenSSL/test/util.py
index f6e9291..643fb91 100644
--- a/OpenSSL/test/util.py
+++ b/OpenSSL/test/util.py
@@ -50,6 +50,22 @@ class TestCase(TestCase):
self.fail("Left over errors in OpenSSL error queue: " + repr(e))
+ def failUnlessIn(self, containee, container, msg=None):
+ """
+ Fail the test if C{containee} is not found in C{container}.
+
+ @param containee: the value that should be in C{container}
+ @param container: a sequence type, or in the case of a mapping type,
+ will follow semantics of 'if key in dict.keys()'
+ @param msg: if msg is None, then the failure message will be
+ '%r not in %r' % (first, second)
+ """
+ if containee not in container:
+ raise self.failureException(msg or "%r not in %r"
+ % (containee, container))
+ return containee
+ assertIn = failUnlessIn
+
def failUnlessIdentical(self, first, second, msg=None):
"""
Fail the test if C{first} is not C{second}. This is an