aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cryptography/hazmat/backends/interfaces.py9
-rw-r--r--src/cryptography/hazmat/backends/multibackend.py13
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py66
-rw-r--r--src/cryptography/hazmat/backends/openssl/dh.py77
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/dh.py11
5 files changed, 143 insertions, 33 deletions
diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py
index c5f2951c..9ed50cc4 100644
--- a/src/cryptography/hazmat/backends/interfaces.py
+++ b/src/cryptography/hazmat/backends/interfaces.py
@@ -361,11 +361,18 @@ class DHBackend(object):
"""
@abc.abstractmethod
- def dh_parameters_supported(self, p, g):
+ def dh_parameters_supported(self, p, g, q=None):
"""
Returns whether the backend supports DH with these parameter values.
"""
+ @abc.abstractmethod
+ def dh_x942_serialization_supported(self):
+ """
+ Returns True if the backend supports the serialization of DH objects
+ with subgroup order (q).
+ """
+
@six.add_metaclass(abc.ABCMeta)
class ScryptBackend(object):
diff --git a/src/cryptography/hazmat/backends/multibackend.py b/src/cryptography/hazmat/backends/multibackend.py
index 097b4908..bb30c661 100644
--- a/src/cryptography/hazmat/backends/multibackend.py
+++ b/src/cryptography/hazmat/backends/multibackend.py
@@ -481,9 +481,18 @@ class MultiBackend(object):
_Reasons.UNSUPPORTED_DIFFIE_HELLMAN
)
- def dh_parameters_supported(self, p, g):
+ def dh_parameters_supported(self, p, g, q=None):
for b in self._filtered_backends(DHBackend):
- return b.dh_parameters_supported(p, g)
+ return b.dh_parameters_supported(p, g, q)
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support Diffie-Hellman",
+ _Reasons.UNSUPPORTED_DIFFIE_HELLMAN
+ )
+
+ def dh_x942_serialization_supported(self):
+ for b in self._filtered_backends(DHBackend):
+ return b.dh_x942_serialization_supported()
raise UnsupportedAlgorithm(
"This backend does not support Diffie-Hellman",
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 77538162..446891d3 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -23,7 +23,8 @@ from cryptography.hazmat.backends.interfaces import (
from cryptography.hazmat.backends.openssl.ciphers import _CipherContext
from cryptography.hazmat.backends.openssl.cmac import _CMACContext
from cryptography.hazmat.backends.openssl.dh import (
- _DHParameters, _DHPrivateKey, _DHPublicKey
+ _DHParameters, _DHPrivateKey, _DHPublicKey,
+ _dh_params_dup
)
from cryptography.hazmat.backends.openssl.dsa import (
_DSAParameters, _DSAPrivateKey, _DSAPublicKey
@@ -99,6 +100,9 @@ class Backend(object):
self._cipher_registry = {}
self._register_default_ciphers()
self.activate_osrandom_engine()
+ self._dh_types = [self._lib.EVP_PKEY_DH]
+ if self._lib.Cryptography_HAS_EVP_PKEY_DHX:
+ self._dh_types.append(self._lib.EVP_PKEY_DHX)
def openssl_assert(self, ok):
return binding._openssl_assert(self._lib, ok)
@@ -480,7 +484,7 @@ class Backend(object):
self.openssl_assert(ec_cdata != self._ffi.NULL)
ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey)
- elif key_type == self._lib.EVP_PKEY_DH:
+ elif key_type in self._dh_types:
dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey)
self.openssl_assert(dh_cdata != self._ffi.NULL)
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
@@ -512,7 +516,7 @@ class Backend(object):
self.openssl_assert(ec_cdata != self._ffi.NULL)
ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey)
- elif key_type == self._lib.EVP_PKEY_DH:
+ elif key_type in self._dh_types:
dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey)
self.openssl_assert(dh_cdata != self._ffi.NULL)
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
@@ -1205,6 +1209,23 @@ class Backend(object):
_Reasons.UNSUPPORTED_CIPHER
)
+ elif errors[0][1:] in (
+ (
+ self._lib.ERR_LIB_ASN1,
+ self._lib.ASN1_F_ASN1_CHECK_TLEN,
+ self._lib.ASN1_R_WRONG_TAG
+ ),
+ (
+ self._lib.ERR_LIB_PEM,
+ self._lib.PEM_F_PEM_READ_BIO,
+ self._lib.PEM_R_NO_START_LINE
+ ),
+ ):
+ raise UnsupportedAlgorithm(
+ "Unsupported public key algorithm.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ )
+
elif any(
error[1:] == (
self._lib.ERR_LIB_EVP,
@@ -1660,9 +1681,7 @@ class Backend(object):
return evp_pkey
def generate_dh_private_key(self, parameters):
- dh_key_cdata = self._lib.DHparams_dup(parameters._dh_cdata)
- self.openssl_assert(dh_key_cdata != self._ffi.NULL)
- dh_key_cdata = self._ffi.gc(dh_key_cdata, self._lib.DH_free)
+ dh_key_cdata = _dh_params_dup(parameters._dh_cdata, self)
res = self._lib.DH_generate_key(dh_key_cdata)
self.openssl_assert(res == 1)
@@ -1684,10 +1703,16 @@ class Backend(object):
p = self._int_to_bn(parameter_numbers.p)
g = self._int_to_bn(parameter_numbers.g)
+
+ if parameter_numbers.q is not None:
+ q = self._int_to_bn(parameter_numbers.q)
+ else:
+ q = self._ffi.NULL
+
pub_key = self._int_to_bn(numbers.public_numbers.y)
priv_key = self._int_to_bn(numbers.x)
- res = self._lib.DH_set0_pqg(dh_cdata, p, self._ffi.NULL, g)
+ res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
self.openssl_assert(res == 1)
res = self._lib.DH_set0_key(dh_cdata, pub_key, priv_key)
@@ -1713,9 +1738,15 @@ class Backend(object):
p = self._int_to_bn(parameter_numbers.p)
g = self._int_to_bn(parameter_numbers.g)
+
+ if parameter_numbers.q is not None:
+ q = self._int_to_bn(parameter_numbers.q)
+ else:
+ q = self._ffi.NULL
+
pub_key = self._int_to_bn(numbers.y)
- res = self._lib.DH_set0_pqg(dh_cdata, p, self._ffi.NULL, g)
+ res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
self.openssl_assert(res == 1)
res = self._lib.DH_set0_key(dh_cdata, pub_key, self._ffi.NULL)
@@ -1733,12 +1764,17 @@ class Backend(object):
p = self._int_to_bn(numbers.p)
g = self._int_to_bn(numbers.g)
- res = self._lib.DH_set0_pqg(dh_cdata, p, self._ffi.NULL, g)
+ if numbers.q is not None:
+ q = self._int_to_bn(numbers.q)
+ else:
+ q = self._ffi.NULL
+
+ res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
self.openssl_assert(res == 1)
return _DHParameters(self, dh_cdata)
- def dh_parameters_supported(self, p, g):
+ def dh_parameters_supported(self, p, g, q=None):
dh_cdata = self._lib.DH_new()
self.openssl_assert(dh_cdata != self._ffi.NULL)
dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
@@ -1746,7 +1782,12 @@ class Backend(object):
p = self._int_to_bn(p)
g = self._int_to_bn(g)
- res = self._lib.DH_set0_pqg(dh_cdata, p, self._ffi.NULL, g)
+ if q is not None:
+ q = self._int_to_bn(q)
+ else:
+ q = self._ffi.NULL
+
+ res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
self.openssl_assert(res == 1)
codes = self._ffi.new("int[]", 1)
@@ -1755,6 +1796,9 @@ class Backend(object):
return codes[0] == 0
+ def dh_x942_serialization_supported(self):
+ return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1
+
def x509_name_bytes(self, name):
x509_name = _encode_name_gc(self, name)
pp = self._ffi.new("unsigned char **")
diff --git a/src/cryptography/hazmat/backends/openssl/dh.py b/src/cryptography/hazmat/backends/openssl/dh.py
index b594d411..88c876fc 100644
--- a/src/cryptography/hazmat/backends/openssl/dh.py
+++ b/src/cryptography/hazmat/backends/openssl/dh.py
@@ -5,18 +5,31 @@
from __future__ import absolute_import, division, print_function
from cryptography import utils
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import dh
-def _dh_cdata_to_parameters(dh_cdata, backend):
+def _dh_params_dup(dh_cdata, backend):
lib = backend._lib
ffi = backend._ffi
param_cdata = lib.DHparams_dup(dh_cdata)
backend.openssl_assert(param_cdata != ffi.NULL)
param_cdata = ffi.gc(param_cdata, lib.DH_free)
+ if lib.OPENSSL_VERSION_NUMBER < 0x10002000 or lib.CRYPTOGRAPHY_IS_LIBRESSL:
+ # In OpenSSL versions < 1.0.2 or libressl DHparams_dup don't copy q
+ q = ffi.new("BIGNUM **")
+ lib.DH_get0_pqg(dh_cdata, ffi.NULL, q, ffi.NULL)
+ q_dup = lib.BN_dup(q[0])
+ res = lib.DH_set0_pqg(param_cdata, ffi.NULL, q_dup, ffi.NULL)
+ backend.openssl_assert(res == 1)
+
+ return param_cdata
+
+def _dh_cdata_to_parameters(dh_cdata, backend):
+ param_cdata = _dh_params_dup(dh_cdata, backend)
return _DHParameters(backend, param_cdata)
@@ -29,13 +42,18 @@ class _DHParameters(object):
def parameter_numbers(self):
p = self._backend._ffi.new("BIGNUM **")
g = self._backend._ffi.new("BIGNUM **")
- self._backend._lib.DH_get0_pqg(self._dh_cdata,
- p, self._backend._ffi.NULL, g)
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g)
self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
+ if q[0] == self._backend._ffi.NULL:
+ q_val = None
+ else:
+ q_val = self._backend._bn_to_int(q[0])
return dh.DHParameterNumbers(
p=self._backend._bn_to_int(p[0]),
- g=self._backend._bn_to_int(g[0])
+ g=self._backend._bn_to_int(g[0]),
+ q=q_val
)
def generate_private_key(self):
@@ -78,10 +96,14 @@ class _DHPrivateKey(object):
def private_numbers(self):
p = self._backend._ffi.new("BIGNUM **")
g = self._backend._ffi.new("BIGNUM **")
- self._backend._lib.DH_get0_pqg(self._dh_cdata,
- p, self._backend._ffi.NULL, g)
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g)
self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
+ if q[0] == self._backend._ffi.NULL:
+ q_val = None
+ else:
+ q_val = self._backend._bn_to_int(q[0])
pub_key = self._backend._ffi.new("BIGNUM **")
priv_key = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_key(self._dh_cdata, pub_key, priv_key)
@@ -91,7 +113,8 @@ class _DHPrivateKey(object):
public_numbers=dh.DHPublicNumbers(
parameter_numbers=dh.DHParameterNumbers(
p=self._backend._bn_to_int(p[0]),
- g=self._backend._bn_to_int(g[0])
+ g=self._backend._bn_to_int(g[0]),
+ q=q_val
),
y=self._backend._bn_to_int(pub_key[0])
),
@@ -126,12 +149,7 @@ class _DHPrivateKey(object):
return key
def public_key(self):
- dh_cdata = self._backend._lib.DHparams_dup(self._dh_cdata)
- self._backend.openssl_assert(dh_cdata != self._backend._ffi.NULL)
- dh_cdata = self._backend._ffi.gc(
- dh_cdata, self._backend._lib.DH_free
- )
-
+ dh_cdata = _dh_params_dup(self._dh_cdata, self._backend)
pub_key = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_key(self._dh_cdata,
pub_key, self._backend._ffi.NULL)
@@ -154,6 +172,17 @@ class _DHPrivateKey(object):
raise ValueError(
"DH private keys support only PKCS8 serialization"
)
+ if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX:
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata,
+ self._backend._ffi.NULL,
+ q,
+ self._backend._ffi.NULL)
+ if q[0] != self._backend._ffi.NULL:
+ raise UnsupportedAlgorithm(
+ "DH X9.42 serialization is not supported",
+ _Reasons.UNSUPPORTED_SERIALIZATION)
+
return self._backend._private_key_bytes(
encoding,
format,
@@ -178,10 +207,14 @@ class _DHPublicKey(object):
def public_numbers(self):
p = self._backend._ffi.new("BIGNUM **")
g = self._backend._ffi.new("BIGNUM **")
- self._backend._lib.DH_get0_pqg(self._dh_cdata,
- p, self._backend._ffi.NULL, g)
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g)
self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
+ if q[0] == self._backend._ffi.NULL:
+ q_val = None
+ else:
+ q_val = self._backend._bn_to_int(q[0])
pub_key = self._backend._ffi.new("BIGNUM **")
self._backend._lib.DH_get0_key(self._dh_cdata,
pub_key, self._backend._ffi.NULL)
@@ -189,7 +222,8 @@ class _DHPublicKey(object):
return dh.DHPublicNumbers(
parameter_numbers=dh.DHParameterNumbers(
p=self._backend._bn_to_int(p[0]),
- g=self._backend._bn_to_int(g[0])
+ g=self._backend._bn_to_int(g[0]),
+ q=q_val
),
y=self._backend._bn_to_int(pub_key[0])
)
@@ -204,6 +238,17 @@ class _DHPublicKey(object):
"SubjectPublicKeyInfo serialization"
)
+ if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX:
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata,
+ self._backend._ffi.NULL,
+ q,
+ self._backend._ffi.NULL)
+ if q[0] != self._backend._ffi.NULL:
+ raise UnsupportedAlgorithm(
+ "DH X9.42 serialization is not supported",
+ _Reasons.UNSUPPORTED_SERIALIZATION)
+
return self._backend._public_key_bytes(
encoding,
format,
diff --git a/src/cryptography/hazmat/primitives/asymmetric/dh.py b/src/cryptography/hazmat/primitives/asymmetric/dh.py
index ec044ddd..aa60a2d8 100644
--- a/src/cryptography/hazmat/primitives/asymmetric/dh.py
+++ b/src/cryptography/hazmat/primitives/asymmetric/dh.py
@@ -78,18 +78,21 @@ class DHPublicNumbers(object):
class DHParameterNumbers(object):
- def __init__(self, p, g):
+ def __init__(self, p, g, q=None):
if (
not isinstance(p, six.integer_types) or
not isinstance(g, six.integer_types)
):
raise TypeError("p and g must be integers")
+ if q is not None and not isinstance(q, six.integer_types):
+ raise TypeError("q must be integer or None")
- if g not in (2, 5):
+ if q is None and g not in (2, 5):
raise ValueError("DH generator must be 2 or 5")
self._p = p
self._g = g
+ self._q = q
def __eq__(self, other):
if not isinstance(other, DHParameterNumbers):
@@ -97,7 +100,8 @@ class DHParameterNumbers(object):
return (
self._p == other._p and
- self._g == other._g
+ self._g == other._g and
+ self._q == other._q
)
def __ne__(self, other):
@@ -108,6 +112,7 @@ class DHParameterNumbers(object):
p = utils.read_only_property("_p")
g = utils.read_only_property("_g")
+ q = utils.read_only_property("_q")
@six.add_metaclass(abc.ABCMeta)