diff options
-rw-r--r-- | Doc/library/ssl.rst | 26 | ||||
-rw-r--r-- | Lib/ssl.py | 2 | ||||
-rw-r--r-- | Lib/test/ssl_servers.py | 5 | ||||
-rw-r--r-- | Lib/test/test_ssl.py | 10 | ||||
-rw-r--r-- | Misc/NEWS | 4 | ||||
-rw-r--r-- | Modules/_ssl.c | 30 |
6 files changed, 76 insertions, 1 deletions
diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 69eaf8b..7017b8f 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -428,6 +428,14 @@ Constants .. versionadded:: 3.3 +.. data:: OP_SINGLE_ECDH_USE + + Prevents re-use of the same ECDH key for several SSL sessions. This + improves forward secrecy but requires more computational resources. + This option only applies to server sockets. + + .. versionadded:: 3.3 + .. data:: HAS_SNI Whether the OpenSSL library has built-in support for the *Server Name @@ -672,6 +680,24 @@ to speed up repeated connections from the same clients. when connected, the :meth:`SSLSocket.cipher` method of SSL sockets will give the currently selected cipher. +.. method:: SSLContext.set_ecdh_curve(curve_name) + + Set the curve name for Elliptic Curve-based Diffie-Hellman (abbreviated + ECDH) key exchange. Using Diffie-Hellman key exchange improves forward + secrecy at the expense of computational resources (both on the server and + on the client). The *curve_name* parameter should be a string describing + a well-known elliptic curve, for example ``prime256v1`` for a widely + supported curve. + + This setting doesn't apply to client sockets. You can also use the + :data:`OP_SINGLE_ECDH_USE` option to further improve security. + + .. versionadded:: 3.3 + + .. seealso:: + `SSL/TLS & Perfect Forward Secrecy <http://vincent.bernat.im/en/blog/2011-ssl-perfect-forward-secrecy.html>`_ + Vincent Bernat. + .. method:: SSLContext.wrap_socket(sock, server_side=False, \ do_handshake_on_connect=True, suppress_ragged_eofs=True, \ server_hostname=None) @@ -68,7 +68,7 @@ from _ssl import ( from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED from _ssl import ( OP_ALL, OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_TLSv1, - OP_CIPHER_SERVER_PREFERENCE, + OP_CIPHER_SERVER_PREFERENCE, OP_SINGLE_ECDH_USE, ) from _ssl import RAND_status, RAND_egd, RAND_add, RAND_bytes, RAND_pseudo_bytes from _ssl import ( diff --git a/Lib/test/ssl_servers.py b/Lib/test/ssl_servers.py index 77be381..86bc950 100644 --- a/Lib/test/ssl_servers.py +++ b/Lib/test/ssl_servers.py @@ -176,6 +176,9 @@ if __name__ == "__main__": action='store_false', help='be less verbose') parser.add_argument('-s', '--stats', dest='use_stats_handler', default=False, action='store_true', help='always return stats page') + parser.add_argument('--curve-name', dest='curve_name', type=str, + action='store', + help='curve name for EC-based Diffie-Hellman') args = parser.parse_args() support.verbose = args.verbose @@ -186,6 +189,8 @@ if __name__ == "__main__": handler_class.root = os.getcwd() context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) context.load_cert_chain(CERTFILE) + if args.curve_name: + context.set_ecdh_curve(args.curve_name) server = HTTPSServer(("", args.port), handler_class, context) if args.verbose: diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 288b714..505550f 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -99,6 +99,7 @@ class BasicSocketTests(unittest.TestCase): ssl.CERT_OPTIONAL ssl.CERT_REQUIRED ssl.OP_CIPHER_SERVER_PREFERENCE + ssl.OP_SINGLE_ECDH_USE self.assertIn(ssl.HAS_SNI, {True, False}) def test_random(self): @@ -558,6 +559,15 @@ class ContextTests(unittest.TestCase): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ctx.set_default_verify_paths() + def test_set_ecdh_curve(self): + ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + ctx.set_ecdh_curve("prime256v1") + ctx.set_ecdh_curve(b"prime256v1") + self.assertRaises(TypeError, ctx.set_ecdh_curve) + self.assertRaises(TypeError, ctx.set_ecdh_curve, None) + self.assertRaises(ValueError, ctx.set_ecdh_curve, "foo") + self.assertRaises(ValueError, ctx.set_ecdh_curve, b"foo") + class NetworkedTests(unittest.TestCase): @@ -419,6 +419,10 @@ Core and Builtins Library ------- +- Issue #13627: Add support for SSL Elliptic Curve-based Diffie-Hellman + key exchange, through the SSLContext.set_ecdh_curve() method and the + ssl.OP_SINGLE_ECDH_USE option. + - Issue #13635: Add ssl.OP_CIPHER_SERVER_PREFERENCE, so that SSL servers choose the cipher based on their own preferences, rather than on the client's. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 0f3d2c1..725f148 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -1986,6 +1986,33 @@ set_default_verify_paths(PySSLContext *self, PyObject *unused) Py_RETURN_NONE; } +static PyObject * +set_ecdh_curve(PySSLContext *self, PyObject *name) +{ + PyObject *name_bytes; + int nid; + EC_KEY *key; + + if (!PyUnicode_FSConverter(name, &name_bytes)) + return NULL; + assert(PyBytes_Check(name_bytes)); + nid = OBJ_sn2nid(PyBytes_AS_STRING(name_bytes)); + Py_DECREF(name_bytes); + if (nid == 0) { + PyErr_Format(PyExc_ValueError, + "unknown elliptic curve name %R", name); + return NULL; + } + key = EC_KEY_new_by_curve_name(nid); + if (key == NULL) { + _setSSLError(NULL, 0, __FILE__, __LINE__); + return NULL; + } + SSL_CTX_set_tmp_ecdh(self->ctx, key); + EC_KEY_free(key); + Py_RETURN_NONE; +} + static PyGetSetDef context_getsetlist[] = { {"options", (getter) get_options, (setter) set_options, NULL}, @@ -2007,6 +2034,8 @@ static struct PyMethodDef context_methods[] = { METH_NOARGS, NULL}, {"set_default_verify_paths", (PyCFunction) set_default_verify_paths, METH_NOARGS, NULL}, + {"set_ecdh_curve", (PyCFunction) set_ecdh_curve, + METH_O, NULL}, {NULL, NULL} /* sentinel */ }; @@ -2452,6 +2481,7 @@ PyInit__ssl(void) PyModule_AddIntConstant(m, "OP_NO_TLSv1", SSL_OP_NO_TLSv1); PyModule_AddIntConstant(m, "OP_CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE); + PyModule_AddIntConstant(m, "OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE); #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME r = Py_True; |