mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
d1301953fe
commit
923df6f22a
|
@ -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 (
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue