Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fancier ECDHE support #57

Closed
wants to merge 13 commits into from
3 changes: 2 additions & 1 deletion .gitignore
@@ -1,3 +1,4 @@
*.py[co]
build
dist
*.egg-info
*.egg-info
175 changes: 175 additions & 0 deletions OpenSSL/SSL.py
Expand Up @@ -122,6 +122,161 @@ class _memoryview(object):
SSL_CB_HANDSHAKE_DONE = _lib.SSL_CB_HANDSHAKE_DONE


NID_X9_62_c2pnb163v1 = _lib.NID_X9_62_c2pnb163v1
SN_X9_62_c2pnb163v1 = _ffi.string(_lib.SN_X9_62_c2pnb163v1)
NID_X9_62_c2pnb163v2 = _lib.NID_X9_62_c2pnb163v2
SN_X9_62_c2pnb163v2 = _ffi.string(_lib.SN_X9_62_c2pnb163v2)
NID_X9_62_c2pnb163v3 = _lib.NID_X9_62_c2pnb163v3
SN_X9_62_c2pnb163v3 = _ffi.string(_lib.SN_X9_62_c2pnb163v3)
NID_X9_62_c2pnb176v1 = _lib.NID_X9_62_c2pnb176v1
SN_X9_62_c2pnb176v1 = _ffi.string(_lib.SN_X9_62_c2pnb176v1)
NID_X9_62_c2tnb191v1 = _lib.NID_X9_62_c2tnb191v1
SN_X9_62_c2tnb191v1 = _ffi.string(_lib.SN_X9_62_c2tnb191v1)
NID_X9_62_c2tnb191v2 = _lib.NID_X9_62_c2tnb191v2
SN_X9_62_c2tnb191v2 = _ffi.string(_lib.SN_X9_62_c2tnb191v2)
NID_X9_62_c2tnb191v3 = _lib.NID_X9_62_c2tnb191v3
SN_X9_62_c2tnb191v3 = _ffi.string(_lib.SN_X9_62_c2tnb191v3)
NID_X9_62_c2onb191v4 = _lib.NID_X9_62_c2onb191v4
SN_X9_62_c2onb191v4 = _ffi.string(_lib.SN_X9_62_c2onb191v4)
NID_X9_62_c2onb191v5 = _lib.NID_X9_62_c2onb191v5
SN_X9_62_c2onb191v5 = _ffi.string(_lib.SN_X9_62_c2onb191v5)
NID_X9_62_c2pnb208w1 = _lib.NID_X9_62_c2pnb208w1
SN_X9_62_c2pnb208w1 = _ffi.string(_lib.SN_X9_62_c2pnb208w1)
NID_X9_62_c2tnb239v1 = _lib.NID_X9_62_c2tnb239v1
SN_X9_62_c2tnb239v1 = _ffi.string(_lib.SN_X9_62_c2tnb239v1)
NID_X9_62_c2tnb239v2 = _lib.NID_X9_62_c2tnb239v2
SN_X9_62_c2tnb239v2 = _ffi.string(_lib.SN_X9_62_c2tnb239v2)
NID_X9_62_c2tnb239v3 = _lib.NID_X9_62_c2tnb239v3
SN_X9_62_c2tnb239v3 = _ffi.string(_lib.SN_X9_62_c2tnb239v3)
NID_X9_62_c2onb239v4 = _lib.NID_X9_62_c2onb239v4
SN_X9_62_c2onb239v4 = _ffi.string(_lib.SN_X9_62_c2onb239v4)
NID_X9_62_c2onb239v5 = _lib.NID_X9_62_c2onb239v5
SN_X9_62_c2onb239v5 = _ffi.string(_lib.SN_X9_62_c2onb239v5)
NID_X9_62_c2pnb272w1 = _lib.NID_X9_62_c2pnb272w1
SN_X9_62_c2pnb272w1 = _ffi.string(_lib.SN_X9_62_c2pnb272w1)
NID_X9_62_c2pnb304w1 = _lib.NID_X9_62_c2pnb304w1
SN_X9_62_c2pnb304w1 = _ffi.string(_lib.SN_X9_62_c2pnb304w1)
NID_X9_62_c2tnb359v1 = _lib.NID_X9_62_c2tnb359v1
SN_X9_62_c2tnb359v1 = _ffi.string(_lib.SN_X9_62_c2tnb359v1)
NID_X9_62_c2pnb368w1 = _lib.NID_X9_62_c2pnb368w1
SN_X9_62_c2pnb368w1 = _ffi.string(_lib.SN_X9_62_c2pnb368w1)
NID_X9_62_c2tnb431r1 = _lib.NID_X9_62_c2tnb431r1
SN_X9_62_c2tnb431r1 = _ffi.string(_lib.SN_X9_62_c2tnb431r1)
NID_X9_62_prime192v1 = _lib.NID_X9_62_prime192v1
SN_X9_62_prime192v1 = _ffi.string(_lib.SN_X9_62_prime192v1)
NID_X9_62_prime192v2 = _lib.NID_X9_62_prime192v2
SN_X9_62_prime192v2 = _ffi.string(_lib.SN_X9_62_prime192v2)
NID_X9_62_prime192v3 = _lib.NID_X9_62_prime192v3
SN_X9_62_prime192v3 = _ffi.string(_lib.SN_X9_62_prime192v3)
NID_X9_62_prime239v1 = _lib.NID_X9_62_prime239v1
SN_X9_62_prime239v1 = _ffi.string(_lib.SN_X9_62_prime239v1)
NID_X9_62_prime239v2 = _lib.NID_X9_62_prime239v2
SN_X9_62_prime239v2 = _ffi.string(_lib.SN_X9_62_prime239v2)
NID_X9_62_prime239v3 = _lib.NID_X9_62_prime239v3
SN_X9_62_prime239v3 = _ffi.string(_lib.SN_X9_62_prime239v3)
NID_X9_62_prime256v1 = _lib.NID_X9_62_prime256v1
SN_X9_62_prime256v1 = _ffi.string(_lib.SN_X9_62_prime256v1)
NID_secp112r1 = _lib.NID_secp112r1
SN_secp112r1 = _ffi.string(_lib.SN_secp112r1)
NID_secp112r2 = _lib.NID_secp112r2
SN_secp112r2 = _ffi.string(_lib.SN_secp112r2)
NID_secp128r1 = _lib.NID_secp128r1
SN_secp128r1 = _ffi.string(_lib.SN_secp128r1)
NID_secp128r2 = _lib.NID_secp128r2
SN_secp128r2 = _ffi.string(_lib.SN_secp128r2)
NID_secp160k1 = _lib.NID_secp160k1
SN_secp160k1 = _ffi.string(_lib.SN_secp160k1)
NID_secp160r1 = _lib.NID_secp160r1
SN_secp160r1 = _ffi.string(_lib.SN_secp160r1)
NID_secp160r2 = _lib.NID_secp160r2
SN_secp160r2 = _ffi.string(_lib.SN_secp160r2)
NID_sect163k1 = _lib.NID_sect163k1
SN_sect163k1 = _ffi.string(_lib.SN_sect163k1)
NID_sect163r1 = _lib.NID_sect163r1
SN_sect163r1 = _ffi.string(_lib.SN_sect163r1)
NID_sect163r2 = _lib.NID_sect163r2
SN_sect163r2 = _ffi.string(_lib.SN_sect163r2)
NID_secp192k1 = _lib.NID_secp192k1
SN_secp192k1 = _ffi.string(_lib.SN_secp192k1)
NID_secp224k1 = _lib.NID_secp224k1
SN_secp224k1 = _ffi.string(_lib.SN_secp224k1)
NID_secp224r1 = _lib.NID_secp224r1
SN_secp224r1 = _ffi.string(_lib.SN_secp224r1)
NID_secp256k1 = _lib.NID_secp256k1
SN_secp256k1 = _ffi.string(_lib.SN_secp256k1)
NID_secp384r1 = _lib.NID_secp384r1
SN_secp384r1 = _ffi.string(_lib.SN_secp384r1)
NID_secp521r1 = _lib.NID_secp521r1
SN_secp521r1 = _ffi.string(_lib.SN_secp521r1)
NID_sect113r1 = _lib.NID_sect113r1
SN_sect113r1 = _ffi.string(_lib.SN_sect113r1)
NID_sect113r2 = _lib.NID_sect113r2
SN_sect113r2 = _ffi.string(_lib.SN_sect113r2)
NID_sect131r1 = _lib.NID_sect131r1
SN_sect131r1 = _ffi.string(_lib.SN_sect131r1)
NID_sect131r2 = _lib.NID_sect131r2
SN_sect131r2 = _ffi.string(_lib.SN_sect131r2)
NID_sect193r1 = _lib.NID_sect193r1
SN_sect193r1 = _ffi.string(_lib.SN_sect193r1)
NID_sect193r2 = _lib.NID_sect193r2
SN_sect193r2 = _ffi.string(_lib.SN_sect193r2)
NID_sect233k1 = _lib.NID_sect233k1
SN_sect233k1 = _ffi.string(_lib.SN_sect233k1)
NID_sect233r1 = _lib.NID_sect233r1
SN_sect233r1 = _ffi.string(_lib.SN_sect233r1)
NID_sect239k1 = _lib.NID_sect239k1
SN_sect239k1 = _ffi.string(_lib.SN_sect239k1)
NID_sect283k1 = _lib.NID_sect283k1
SN_sect283k1 = _ffi.string(_lib.SN_sect283k1)
NID_sect283r1 = _lib.NID_sect283r1
SN_sect283r1 = _ffi.string(_lib.SN_sect283r1)
NID_sect409k1 = _lib.NID_sect409k1
SN_sect409k1 = _ffi.string(_lib.SN_sect409k1)
NID_sect409r1 = _lib.NID_sect409r1
SN_sect409r1 = _ffi.string(_lib.SN_sect409r1)
NID_sect571k1 = _lib.NID_sect571k1
SN_sect571k1 = _ffi.string(_lib.SN_sect571k1)
NID_sect571r1 = _lib.NID_sect571r1
SN_sect571r1 = _ffi.string(_lib.SN_sect571r1)
NID_wap_wsg_idm_ecid_wtls1 = _lib.NID_wap_wsg_idm_ecid_wtls1
SN_wap_wsg_idm_ecid_wtls1 = _ffi.string(_lib.SN_wap_wsg_idm_ecid_wtls1)
NID_wap_wsg_idm_ecid_wtls3 = _lib.NID_wap_wsg_idm_ecid_wtls3
SN_wap_wsg_idm_ecid_wtls3 = _ffi.string(_lib.SN_wap_wsg_idm_ecid_wtls3)
NID_wap_wsg_idm_ecid_wtls4 = _lib.NID_wap_wsg_idm_ecid_wtls4
SN_wap_wsg_idm_ecid_wtls4 = _ffi.string(_lib.SN_wap_wsg_idm_ecid_wtls4)
NID_wap_wsg_idm_ecid_wtls5 = _lib.NID_wap_wsg_idm_ecid_wtls5
SN_wap_wsg_idm_ecid_wtls5 = _ffi.string(_lib.SN_wap_wsg_idm_ecid_wtls5)
NID_wap_wsg_idm_ecid_wtls6 = _lib.NID_wap_wsg_idm_ecid_wtls6
SN_wap_wsg_idm_ecid_wtls6 = _ffi.string(_lib.SN_wap_wsg_idm_ecid_wtls6)
NID_wap_wsg_idm_ecid_wtls7 = _lib.NID_wap_wsg_idm_ecid_wtls7
SN_wap_wsg_idm_ecid_wtls7 = _ffi.string(_lib.SN_wap_wsg_idm_ecid_wtls7)
NID_wap_wsg_idm_ecid_wtls8 = _lib.NID_wap_wsg_idm_ecid_wtls8
SN_wap_wsg_idm_ecid_wtls8 = _ffi.string(_lib.SN_wap_wsg_idm_ecid_wtls8)
NID_wap_wsg_idm_ecid_wtls9 = _lib.NID_wap_wsg_idm_ecid_wtls9
SN_wap_wsg_idm_ecid_wtls9 = _ffi.string(_lib.SN_wap_wsg_idm_ecid_wtls9)
NID_wap_wsg_idm_ecid_wtls10 = _lib.NID_wap_wsg_idm_ecid_wtls10
SN_wap_wsg_idm_ecid_wtls10 = _ffi.string(_lib.SN_wap_wsg_idm_ecid_wtls10)
NID_wap_wsg_idm_ecid_wtls11 = _lib.NID_wap_wsg_idm_ecid_wtls11
SN_wap_wsg_idm_ecid_wtls11 = _ffi.string(_lib.SN_wap_wsg_idm_ecid_wtls11)
NID_wap_wsg_idm_ecid_wtls12 = _lib.NID_wap_wsg_idm_ecid_wtls12
SN_wap_wsg_idm_ecid_wtls12 = _ffi.string(_lib.SN_wap_wsg_idm_ecid_wtls12)
NID_ipsec3 = _lib.NID_ipsec3
SN_ipsec3 = _ffi.string(_lib.SN_ipsec3)
NID_ipsec4 = _lib.NID_ipsec4
SN_ipsec4 = _ffi.string(_lib.SN_ipsec4)

_Cryptography_HAS_EC = _lib.Cryptography_HAS_EC
ELLIPTIC_CURVE_DESCRIPTIONS = {} # In case there's no EC support
if _Cryptography_HAS_EC:
_num_curves = _lib.EC_get_builtin_curves(_ffi.NULL, 0)
_curves = _ffi.new('EC_builtin_curve[]', _num_curves)
if _lib.EC_get_builtin_curves(_curves, _num_curves) == _num_curves:
ELLIPTIC_CURVE_DESCRIPTIONS = {c.nid : _ffi.string(c.comment)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dict comprehension are Python 2.7+. Try dict((key, value) for (key, value) in sequence) instead.

for c in _curves}
del _num_curves
del _curves


class Error(Exception):
"""
An error occurred in an `OpenSSL.SSL` API.
Expand Down Expand Up @@ -594,6 +749,26 @@ def load_tmp_dh(self, dhfile):
_lib.SSL_CTX_set_tmp_dh(self._context, dh)


def set_tmp_ecdh_by_curve_name(self, curve_name):
"""
Configure this connection to people to use Elliptical Curve
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This neither about connections (it’s a context) nor about people. :) How about just “Configure curve for ECDHE key exchanges.”?

Diffie-Hellman key exchanges.

:param curve_name: One of the named curve constants.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs a :type curve_name:

:return: None
"""
if _lib.Cryptography_HAS_EC:
ecdh = _lib.EC_KEY_new_by_curve_name(curve_name)
if ecdh == _ffi.NULL:
raise ValueError(
"OpenSSL could not load the requested elliptic curve"
)
_lib.SSL_CTX_set_tmp_ecdh(self._context, ecdh)
_lib.EC_KEY_free(ecdh)
else:
raise ValueError("OpenSSL is compiled without ECDH support")


def set_cipher_list(self, cipher_list):
"""
Change the cipher list
Expand Down
12 changes: 12 additions & 0 deletions OpenSSL/test/test_ssl.py
Expand Up @@ -35,6 +35,7 @@
SESS_CACHE_OFF, SESS_CACHE_CLIENT, SESS_CACHE_SERVER, SESS_CACHE_BOTH,
SESS_CACHE_NO_AUTO_CLEAR, SESS_CACHE_NO_INTERNAL_LOOKUP,
SESS_CACHE_NO_INTERNAL_STORE, SESS_CACHE_NO_INTERNAL)
from OpenSSL.SSL import NID_X9_62_prime256v1, _Cryptography_HAS_EC

from OpenSSL.SSL import (
Error, SysCallError, WantReadError, WantWriteError, ZeroReturnError)
Expand Down Expand Up @@ -1172,6 +1173,17 @@ def test_load_tmp_dh(self):
# XXX What should I assert here? -exarkun


if _Cryptography_HAS_EC:
def test_set_tmp_ecdh_by_curve_name(self):
"""
:py:obj:`Context.set_tmp_ecdh_by_curve_name` sets the Eliptical
Curve for Diffie-Hellman by the named curve.
"""
context = Context(TLSv1_METHOD)
context.set_tmp_ecdh_by_curve_name(NID_X9_62_prime256v1)
# XXX What should I assert here? -alex


def test_set_cipher_list_bytes(self):
"""
:py:obj:`Context.set_cipher_list` accepts a :py:obj:`bytes` naming the
Expand Down
22 changes: 22 additions & 0 deletions doc/api/ssl.rst
Expand Up @@ -116,6 +116,18 @@ Context, Connection.
.. versionadded:: 0.14


.. py:data:: NID_X9_62_prime192v1
NID_X9_62_prime192v2
NID_X9_62_prime192v3
NID_X9_62_prime239v1
NID_X9_62_prime239v2
NID_X9_62_prime239v3
NID_X9_62_prime256v1

Constants used with :py:meth:`Context.set_tmp_ecdh_by_curve_name` to
specify which elliptical curve should be used.


.. py:data:: OPENSSL_VERSION_NUMBER

An integer giving the version number of the OpenSSL library used to build this
Expand Down Expand Up @@ -322,6 +334,16 @@ Context objects have the following methods:

Load parameters for Ephemeral Diffie-Hellman from *dhfile*.

.. py:method:: Context.set_tmp_ecdh_by_curve_name(curve_name)

Configure this connection to people to use Elliptical Curve Diffie-Hellman
key exchanges.

``curve_name`` should be one of the named curve constants, such as
:py:data:`NID_X9_62_prime256v1`.

Raises a ``ValueError`` if the linked OpenSSL was not compiled with
elliptical curve support, or the specified curve is not available.

.. py:method:: Context.set_app_data(data)

Expand Down