diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 3cd9554c081..9b3306cdd14 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -445,6 +445,14 @@ Constants .. versionadded:: 3.3 +.. data:: HAS_ECDH + + Whether the OpenSSL library has built-in support for Elliptic Curve-based + Diffie-Hellman key exchange. This should be true unless the feature was + explicitly disabled by the distributor. + + .. versionadded:: 3.3 + .. data:: HAS_SNI Whether the OpenSSL library has built-in support for the *Server Name @@ -711,6 +719,8 @@ to speed up repeated connections from the same clients. This setting doesn't apply to client sockets. You can also use the :data:`OP_SINGLE_ECDH_USE` option to further improve security. + This method is not available if :data:`HAS_ECDH` is False. + .. versionadded:: 3.3 .. seealso:: diff --git a/Lib/ssl.py b/Lib/ssl.py index 0b2f743f227..d43d25512ef 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -86,7 +86,7 @@ from _ssl import ( SSL_ERROR_EOF, SSL_ERROR_INVALID_ERROR_CODE, ) -from _ssl import HAS_SNI +from _ssl import HAS_SNI, HAS_ECDH from _ssl import (PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1) from _ssl import _OPENSSL_API_VERSION diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 8bbe0f77fe2..1960e143473 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -103,6 +103,7 @@ class BasicSocketTests(unittest.TestCase): if ssl.OPENSSL_VERSION_INFO >= (1, 0): ssl.OP_NO_COMPRESSION self.assertIn(ssl.HAS_SNI, {True, False}) + self.assertIn(ssl.HAS_ECDH, {True, False}) def test_random(self): v = ssl.RAND_status() @@ -561,6 +562,7 @@ class ContextTests(unittest.TestCase): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ctx.set_default_verify_paths() + @unittest.skipUnless(ssl.HAS_ECDH, "ECDH disabled on this OpenSSL build") def test_set_ecdh_curve(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ctx.set_ecdh_curve("prime256v1") diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 480543cbe16..02fe5f356ec 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2006,6 +2006,7 @@ set_default_verify_paths(PySSLContext *self, PyObject *unused) Py_RETURN_NONE; } +#ifndef OPENSSL_NO_ECDH static PyObject * set_ecdh_curve(PySSLContext *self, PyObject *name) { @@ -2032,6 +2033,7 @@ set_ecdh_curve(PySSLContext *self, PyObject *name) EC_KEY_free(key); Py_RETURN_NONE; } +#endif static PyGetSetDef context_getsetlist[] = { {"options", (getter) get_options, @@ -2054,8 +2056,10 @@ static struct PyMethodDef context_methods[] = { METH_NOARGS, NULL}, {"set_default_verify_paths", (PyCFunction) set_default_verify_paths, METH_NOARGS, NULL}, +#ifndef OPENSSL_NO_ECDH {"set_ecdh_curve", (PyCFunction) set_ecdh_curve, METH_O, NULL}, +#endif {NULL, NULL} /* sentinel */ }; @@ -2523,6 +2527,14 @@ PyInit__ssl(void) Py_INCREF(r); PyModule_AddObject(m, "HAS_TLS_UNIQUE", r); +#ifdef OPENSSL_NO_ECDH + r = Py_False; +#else + r = Py_True; +#endif + Py_INCREF(r); + PyModule_AddObject(m, "HAS_ECDH", r); + /* OpenSSL version */ /* SSLeay() gives us the version of the library linked against, which could be different from the headers version.