Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 923df6f

Browse files
committed
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.
1 parent d130195 commit 923df6f

6 files changed

Lines changed: 76 additions & 1 deletion

File tree

Doc/library/ssl.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,14 @@ Constants
428428

429429
.. versionadded:: 3.3
430430

431+
.. data:: OP_SINGLE_ECDH_USE
432+
433+
Prevents re-use of the same ECDH key for several SSL sessions. This
434+
improves forward secrecy but requires more computational resources.
435+
This option only applies to server sockets.
436+
437+
.. versionadded:: 3.3
438+
431439
.. data:: HAS_SNI
432440

433441
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.
672680
when connected, the :meth:`SSLSocket.cipher` method of SSL sockets will
673681
give the currently selected cipher.
674682

683+
.. method:: SSLContext.set_ecdh_curve(curve_name)
684+
685+
Set the curve name for Elliptic Curve-based Diffie-Hellman (abbreviated
686+
ECDH) key exchange. Using Diffie-Hellman key exchange improves forward
687+
secrecy at the expense of computational resources (both on the server and
688+
on the client). The *curve_name* parameter should be a string describing
689+
a well-known elliptic curve, for example ``prime256v1`` for a widely
690+
supported curve.
691+
692+
This setting doesn't apply to client sockets. You can also use the
693+
:data:`OP_SINGLE_ECDH_USE` option to further improve security.
694+
695+
.. versionadded:: 3.3
696+
697+
.. seealso::
698+
`SSL/TLS & Perfect Forward Secrecy <http://vincent.bernat.im/en/blog/2011-ssl-perfect-forward-secrecy.html>`_
699+
Vincent Bernat.
700+
675701
.. method:: SSLContext.wrap_socket(sock, server_side=False, \
676702
do_handshake_on_connect=True, suppress_ragged_eofs=True, \
677703
server_hostname=None)

Lib/ssl.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED
6969
from _ssl import (
7070
OP_ALL, OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_TLSv1,
71-
OP_CIPHER_SERVER_PREFERENCE,
71+
OP_CIPHER_SERVER_PREFERENCE, OP_SINGLE_ECDH_USE,
7272
)
7373
from _ssl import RAND_status, RAND_egd, RAND_add, RAND_bytes, RAND_pseudo_bytes
7474
from _ssl import (

Lib/test/ssl_servers.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@ def cleanup():
176176
action='store_false', help='be less verbose')
177177
parser.add_argument('-s', '--stats', dest='use_stats_handler', default=False,
178178
action='store_true', help='always return stats page')
179+
parser.add_argument('--curve-name', dest='curve_name', type=str,
180+
action='store',
181+
help='curve name for EC-based Diffie-Hellman')
179182
args = parser.parse_args()
180183

181184
support.verbose = args.verbose
@@ -186,6 +189,8 @@ def cleanup():
186189
handler_class.root = os.getcwd()
187190
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
188191
context.load_cert_chain(CERTFILE)
192+
if args.curve_name:
193+
context.set_ecdh_curve(args.curve_name)
189194

190195
server = HTTPSServer(("", args.port), handler_class, context)
191196
if args.verbose:

Lib/test/test_ssl.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ def test_constants(self):
9999
ssl.CERT_OPTIONAL
100100
ssl.CERT_REQUIRED
101101
ssl.OP_CIPHER_SERVER_PREFERENCE
102+
ssl.OP_SINGLE_ECDH_USE
102103
self.assertIn(ssl.HAS_SNI, {True, False})
103104

104105
def test_random(self):
@@ -558,6 +559,15 @@ def test_set_default_verify_paths(self):
558559
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
559560
ctx.set_default_verify_paths()
560561

562+
def test_set_ecdh_curve(self):
563+
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
564+
ctx.set_ecdh_curve("prime256v1")
565+
ctx.set_ecdh_curve(b"prime256v1")
566+
self.assertRaises(TypeError, ctx.set_ecdh_curve)
567+
self.assertRaises(TypeError, ctx.set_ecdh_curve, None)
568+
self.assertRaises(ValueError, ctx.set_ecdh_curve, "foo")
569+
self.assertRaises(ValueError, ctx.set_ecdh_curve, b"foo")
570+
561571

562572
class NetworkedTests(unittest.TestCase):
563573

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,10 @@ Core and Builtins
419419
Library
420420
-------
421421

422+
- Issue #13627: Add support for SSL Elliptic Curve-based Diffie-Hellman
423+
key exchange, through the SSLContext.set_ecdh_curve() method and the
424+
ssl.OP_SINGLE_ECDH_USE option.
425+
422426
- Issue #13635: Add ssl.OP_CIPHER_SERVER_PREFERENCE, so that SSL servers
423427
choose the cipher based on their own preferences, rather than on the
424428
client's.

Modules/_ssl.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,6 +1986,33 @@ set_default_verify_paths(PySSLContext *self, PyObject *unused)
19861986
Py_RETURN_NONE;
19871987
}
19881988

1989+
static PyObject *
1990+
set_ecdh_curve(PySSLContext *self, PyObject *name)
1991+
{
1992+
PyObject *name_bytes;
1993+
int nid;
1994+
EC_KEY *key;
1995+
1996+
if (!PyUnicode_FSConverter(name, &name_bytes))
1997+
return NULL;
1998+
assert(PyBytes_Check(name_bytes));
1999+
nid = OBJ_sn2nid(PyBytes_AS_STRING(name_bytes));
2000+
Py_DECREF(name_bytes);
2001+
if (nid == 0) {
2002+
PyErr_Format(PyExc_ValueError,
2003+
"unknown elliptic curve name %R", name);
2004+
return NULL;
2005+
}
2006+
key = EC_KEY_new_by_curve_name(nid);
2007+
if (key == NULL) {
2008+
_setSSLError(NULL, 0, __FILE__, __LINE__);
2009+
return NULL;
2010+
}
2011+
SSL_CTX_set_tmp_ecdh(self->ctx, key);
2012+
EC_KEY_free(key);
2013+
Py_RETURN_NONE;
2014+
}
2015+
19892016
static PyGetSetDef context_getsetlist[] = {
19902017
{"options", (getter) get_options,
19912018
(setter) set_options, NULL},
@@ -2007,6 +2034,8 @@ static struct PyMethodDef context_methods[] = {
20072034
METH_NOARGS, NULL},
20082035
{"set_default_verify_paths", (PyCFunction) set_default_verify_paths,
20092036
METH_NOARGS, NULL},
2037+
{"set_ecdh_curve", (PyCFunction) set_ecdh_curve,
2038+
METH_O, NULL},
20102039
{NULL, NULL} /* sentinel */
20112040
};
20122041

@@ -2452,6 +2481,7 @@ PyInit__ssl(void)
24522481
PyModule_AddIntConstant(m, "OP_NO_TLSv1", SSL_OP_NO_TLSv1);
24532482
PyModule_AddIntConstant(m, "OP_CIPHER_SERVER_PREFERENCE",
24542483
SSL_OP_CIPHER_SERVER_PREFERENCE);
2484+
PyModule_AddIntConstant(m, "OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE);
24552485

24562486
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
24572487
r = Py_True;

0 commit comments

Comments
 (0)