From 1461c491f6fd14170262f7dfb32f184a694a7777 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Thu, 3 Oct 2013 16:05:00 -0400 Subject: Try exposing TLSv1.1 and TLSv1.2. --- OpenSSL/ssl/context.c | 30 +++++++++++++++++++++--- OpenSSL/ssl/context.h | 2 ++ OpenSSL/ssl/ssl.c | 8 +++++++ OpenSSL/test/test_ssl.py | 35 +++++++++++++++++++--------- doc/api/ssl.rst | 59 +++++++++++++++++++++++++++++++++++++----------- 5 files changed, 107 insertions(+), 27 deletions(-) diff --git a/OpenSSL/ssl/context.c b/OpenSSL/ssl/context.c index e971c0a..208ab4d 100644 --- a/OpenSSL/ssl/context.c +++ b/OpenSSL/ssl/context.c @@ -282,9 +282,16 @@ global_tlsext_servername_callback(const SSL *ssl, int *alert, void *arg) { #ifdef OPENSSL_NO_SSL2 #define SSLv2_METHOD_TEXT "" #else -#define SSLv2_METHOD_TEXT "SSLv2_METHOD, " +#define SSLv2_METHOD_TEXT " SSLv2_METHOD" #endif +#ifdef SSL_OP_NO_TLSv1_1 +#define TLSv1_1_METHOD_TEXT " TLSv1_1_METHOD" +#endif + +#ifdef SSL_OP_NO_TLSv1_1 +#define TLSv1_2_METHOD_TEXT " TLSv1_2_METHOD" +#endif static char ssl_Context_doc[] = "\n\ Context(method) -> Context instance\n\ @@ -292,11 +299,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_TEXT "SSLv3_METHOD, SSLv23_METHOD, or\n\ - TLSv1_METHOD.\n\ +:param method: One of:" SSLv2_METHOD_TEXT " SSLv3_METHOD SSLv23_METHOD TLSv1_METHOD" TLSv1_1_METHOD_TEXT TLSv1_2_METHOD_TEXT "\n\ "; #undef SSLv2_METHOD_TEXT +#undef TLSv1_1_METHOD_TEXT +#undef TLSv1_2_METHOD_TEXT static char ssl_Context_load_verify_locations_doc[] = "\n\ Let SSL know where we can find trusted certificates for the certificate\n\ @@ -1262,6 +1270,22 @@ ssl_Context_init(ssl_ContextObj *self, int i_method) { case ssl_TLSv1_METHOD: method = TLSv1_method(); break; + case ssl_TLSv1_1_METHOD: +#ifdef SSL_OP_NO_TLSv1_1 + method = TLSv1_1_method(); +#else + PyErr_SetString(PyExc_ValueError, "TLSv1_1_method not supported by this version of OpenSSL"); + return NULL; +#endif + break; + case ssl_TLSv1_2_METHOD: +#ifdef SSL_OP_NO_TLSv1_2 + method = TLSv1_2_method(); +#else + PyErr_SetString(PyExc_ValueError, "TLSv1_2_method not supported by this version of OpenSSL"); + return NULL; +#endif + break; default: PyErr_SetString(PyExc_ValueError, "No such protocol"); return NULL; diff --git a/OpenSSL/ssl/context.h b/OpenSSL/ssl/context.h index 19b5e9e..989d8f1 100644 --- a/OpenSSL/ssl/context.h +++ b/OpenSSL/ssl/context.h @@ -38,6 +38,8 @@ typedef struct { #define ssl_SSLv3_METHOD (2) #define ssl_SSLv23_METHOD (3) #define ssl_TLSv1_METHOD (4) +#define ssl_TLSv1_1_METHOD (5) +#define ssl_TLSv1_2_METHOD (6) #endif diff --git a/OpenSSL/ssl/ssl.c b/OpenSSL/ssl/ssl.c index 5725d5d..6b0fd84 100644 --- a/OpenSSL/ssl/ssl.c +++ b/OpenSSL/ssl/ssl.c @@ -185,6 +185,8 @@ do { \ PyModule_AddIntConstant(module, "SSLv3_METHOD", ssl_SSLv3_METHOD); PyModule_AddIntConstant(module, "SSLv23_METHOD", ssl_SSLv23_METHOD); PyModule_AddIntConstant(module, "TLSv1_METHOD", ssl_TLSv1_METHOD); + PyModule_AddIntConstant(module, "TLSv1_1_METHOD", ssl_TLSv1_1_METHOD); + PyModule_AddIntConstant(module, "TLSv1_2_METHOD", ssl_TLSv1_2_METHOD); /* Verify constants */ PyModule_AddIntConstant(module, "VERIFY_NONE", SSL_VERIFY_NONE); @@ -204,6 +206,12 @@ do { \ PyModule_AddIntConstant(module, "OP_NO_SSLv2", SSL_OP_NO_SSLv2); PyModule_AddIntConstant(module, "OP_NO_SSLv3", SSL_OP_NO_SSLv3); PyModule_AddIntConstant(module, "OP_NO_TLSv1", SSL_OP_NO_TLSv1); +#ifdef SSL_OP_NO_TLSv1_1 + PyModule_AddIntConstant(module, "OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1); +#endif +#ifdef SSL_OP_NO_TLSv1_2 + PyModule_AddIntConstant(module, "OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2); +#endif /* More SSL option constants */ PyModule_AddIntConstant(module, "OP_MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG); diff --git a/OpenSSL/test/test_ssl.py b/OpenSSL/test/test_ssl.py index 3e4e3da..9517c9d 100644 --- a/OpenSSL/test/test_ssl.py +++ b/OpenSSL/test/test_ssl.py @@ -10,7 +10,7 @@ from errno import ECONNREFUSED, EINPROGRESS, EWOULDBLOCK from sys import platform, version_info from socket import error, socket from os import makedirs -from os.path import join, dirname +from os.path import join from unittest import main from weakref import ref @@ -22,8 +22,10 @@ from OpenSSL.crypto import dump_certificate, load_certificate from OpenSSL.SSL import OPENSSL_VERSION_NUMBER, SSLEAY_VERSION, SSLEAY_CFLAGS from OpenSSL.SSL import SSLEAY_PLATFORM, SSLEAY_DIR, SSLEAY_BUILT_ON from OpenSSL.SSL import SENT_SHUTDOWN, RECEIVED_SHUTDOWN -from OpenSSL.SSL import SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD -from OpenSSL.SSL import OP_NO_SSLv2, OP_NO_SSLv3, OP_SINGLE_DH_USE +from OpenSSL.SSL import ( + SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD, + TLSv1_1_METHOD, TLSv1_2_METHOD) +from OpenSSL.SSL import OP_SINGLE_DH_USE, OP_NO_SSLv2, OP_NO_SSLv3 from OpenSSL.SSL import ( VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_CLIENT_ONCE, VERIFY_NONE) @@ -67,6 +69,11 @@ try: except ImportError: MODE_RELEASE_BUFFERS = None +try: + from OpenSSL.SSL import OP_NO_TLSv1, OP_NO_TLSv1_1, OP_NO_TLSv1_2 +except ImportError: + OP_NO_TLSv1 = OP_NO_TLSv1_1 = OP_NO_TLSv1_2 = None + from OpenSSL.SSL import ( SSL_ST_CONNECT, SSL_ST_ACCEPT, SSL_ST_MASK, SSL_ST_INIT, SSL_ST_BEFORE, SSL_ST_OK, SSL_ST_RENEGOTIATE, @@ -306,17 +313,23 @@ class ContextTests(TestCase, _LoopbackMixin): def test_method(self): """ :py:obj:`Context` can be instantiated with one of :py:obj:`SSLv2_METHOD`, - :py:obj:`SSLv3_METHOD`, :py:obj:`SSLv23_METHOD`, or :py:obj:`TLSv1_METHOD`. + :py:obj:`SSLv3_METHOD`, :py:obj:`SSLv23_METHOD`, :py:obj:`TLSv1_METHOD`, + :py:obj:`TLSv1_1_METHOD`, or :py:obj:`TLSv1_2_METHOD`. """ - for meth in [SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD]: + methods = [ + SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD] + for meth in methods: Context(meth) - try: - Context(SSLv2_METHOD) - except (Error, ValueError): - # Some versions of OpenSSL have SSLv2, some don't. - # Difficult to say in advance. - pass + + maybe = [SSLv2_METHOD, TLSv1_1_METHOD, TLSv1_2_METHOD] + for meth in maybe: + try: + Context(meth) + except (Error, ValueError): + # Some versions of OpenSSL have SSLv2 / TLSv1.1 / TLSv1.2, some + # don't. Difficult to say in advance. + pass self.assertRaises(TypeError, Context, "") self.assertRaises(ValueError, Context, 10) diff --git a/doc/api/ssl.rst b/doc/api/ssl.rst index 872cd5a..b506757 100644 --- a/doc/api/ssl.rst +++ b/doc/api/ssl.rst @@ -14,9 +14,13 @@ Context, Connection. SSLv3_METHOD SSLv23_METHOD TLSv1_METHOD + TLSv1_1_METHOD + TLSv1_2_METHOD These constants represent the different SSL methods to use when creating a - context object. + context object. If the underlying OpenSSL build is missing support for any + of these protocols, constructing a :py:class:`Context` using the + corresponding :py:const:`*_METHOD` will raise an exception. .. py:data:: VERIFY_NONE @@ -35,22 +39,48 @@ Context, Connection. .. py:data:: OP_SINGLE_DH_USE - OP_EPHEMERAL_RSA - OP_NO_SSLv2 + + Constant used with :py:meth:`set_options` of Context objects. + + When this option is used, a new key will always be created when using + ephemeral Diffie-Hellman. + + +.. py:data:: OP_EPHEMERAL_RSA + + Constant used with :py:meth:`set_options` of Context objects. + + When this option is used, ephemeral RSA keys will always be used when doing + RSA operations. + + +.. py:data:: OP_NO_TICKET + + Constant used with :py:meth:`set_options` of Context objects. + + When this option is used, the session ticket extension will not be used. + + +.. py:data:: OP_NO_COMPRESSION + + Constant used with :py:meth:`set_options` of Context objects. + + When this option is used, compression will not be used. + + +.. py:data:: OP_NO_SSLv2 OP_NO_SSLv3 OP_NO_TLSv1 - OP_NO_TICKET - OP_NO_COMPRESSION + OP_NO_TLSv1_1 + OP_NO_TLSv1_2 Constants used with :py:meth:`set_options` of Context objects. - :py:const:`OP_SINGLE_DH_USE` means to always create a new key when using - ephemeral Diffie-Hellman. :py:const:`OP_EPHEMERAL_RSA` means to always use - ephemeral RSA keys when doing RSA operations. :py:const:`OP_NO_SSLv2`, - :py:const:`OP_NO_SSLv3` and :py:const:`OP_NO_TLSv1` means to disable those - specific protocols. This is interesting if you're using e.g. - :py:const:`SSLv23_METHOD` to get an SSLv2-compatible handshake, but don't want - to use SSLv2. + Each of these options disables one version of the SSL/TLS protocol. This + is interesting if you're using e.g. :py:const:`SSLv23_METHOD` to get an + SSLv2-compatible handshake, but don't want to use SSLv2. If the underlying + OpenSSL build is missing support for any of these protocols, the + :py:const:`OP_NO_*` constant may be undefined. .. py:data:: MODE_NO_COMPRESSION @@ -69,6 +99,7 @@ Context, Connection. information to retrieve. See the man page for the :py:func:`SSLeay_version` C API for details. + .. py:data:: SESS_CACHE_OFF SESS_CACHE_CLIENT SESS_CACHE_SERVER @@ -84,6 +115,7 @@ Context, Connection. .. versionadded:: 0.14 + .. py:data:: OPENSSL_VERSION_NUMBER An integer giving the version number of the OpenSSL library used to build this @@ -109,7 +141,8 @@ Context, Connection. more SSL connections. *method* should be :py:const:`SSLv2_METHOD`, :py:const:`SSLv3_METHOD`, - :py:const:`SSLv23_METHOD` or :py:const:`TLSv1_METHOD`. + :py:const:`SSLv23_METHOD`, :py:const:`TLSv1_METHOD`, :py:const:`TLSv1_1_METHOD`, + or :py:const:`TLSv1_2_METHOD`. .. py:class:: Session() -- cgit v1.2.1 From d1e969eddee9fe3d970aebdc860f95fccc40230d Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 4 Oct 2013 15:06:44 -0400 Subject: Oops. --- OpenSSL/ssl/context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSSL/ssl/context.c b/OpenSSL/ssl/context.c index 208ab4d..84180b8 100644 --- a/OpenSSL/ssl/context.c +++ b/OpenSSL/ssl/context.c @@ -289,7 +289,7 @@ global_tlsext_servername_callback(const SSL *ssl, int *alert, void *arg) { #define TLSv1_1_METHOD_TEXT " TLSv1_1_METHOD" #endif -#ifdef SSL_OP_NO_TLSv1_1 +#ifdef SSL_OP_NO_TLSv1_2 #define TLSv1_2_METHOD_TEXT " TLSv1_2_METHOD" #endif -- cgit v1.2.1