diff options
author | Jean-Paul Calderone <exarkun@divmod.com> | 2011-05-10 20:24:34 -0400 |
---|---|---|
committer | Jean-Paul Calderone <exarkun@divmod.com> | 2011-05-10 20:24:34 -0400 |
commit | 9eff5699339c34439d7085e937abd0f3b9235afe (patch) | |
tree | 6f169497a82281d9f5bebb9a0ea4ab3335c6255e | |
parent | 78705f2e0adb0f6cbe88027ef5451a229521774c (diff) | |
parent | 24dfb333d9282289d7010eee26f16b6612d8347c (diff) | |
download | pyopenssl-9eff5699339c34439d7085e937abd0f3b9235afe.tar.gz |
Support OpenSSL 1.0
-rw-r--r-- | ChangeLog | 24 | ||||
-rw-r--r-- | OpenSSL/crypto/crypto.h | 13 | ||||
-rw-r--r-- | OpenSSL/crypto/pkcs12.c | 28 | ||||
-rw-r--r-- | OpenSSL/ssl/context.c | 21 | ||||
-rw-r--r-- | OpenSSL/test/test_crypto.py | 28 | ||||
-rw-r--r-- | OpenSSL/test/test_ssl.py | 14 | ||||
-rw-r--r-- | OpenSSL/test/util.py | 16 |
7 files changed, 119 insertions, 25 deletions
@@ -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 |