aboutsummaryrefslogtreecommitdiffstats
path: root/cryptography/hazmat
diff options
context:
space:
mode:
Diffstat (limited to 'cryptography/hazmat')
-rw-r--r--cryptography/hazmat/backends/interfaces.py18
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py713
-rw-r--r--cryptography/hazmat/backends/openssl/ec.py175
-rw-r--r--cryptography/hazmat/backends/openssl/rsa.py491
-rw-r--r--cryptography/hazmat/bindings/commoncrypto/common_cryptor.py2
-rw-r--r--cryptography/hazmat/bindings/openssl/aes.py16
-rw-r--r--cryptography/hazmat/bindings/openssl/binding.py1
-rw-r--r--cryptography/hazmat/bindings/openssl/cms.py4
-rw-r--r--cryptography/hazmat/bindings/openssl/dh.py8
-rw-r--r--cryptography/hazmat/bindings/openssl/dsa.py10
-rw-r--r--cryptography/hazmat/bindings/openssl/err.py23
-rw-r--r--cryptography/hazmat/bindings/openssl/evp.py3
-rw-r--r--cryptography/hazmat/bindings/openssl/nid.py2
-rw-r--r--cryptography/hazmat/bindings/openssl/rsa.py2
-rw-r--r--cryptography/hazmat/bindings/openssl/ssl.py19
-rw-r--r--cryptography/hazmat/bindings/openssl/x509.py14
-rw-r--r--cryptography/hazmat/bindings/openssl/x509_vfy.py337
-rw-r--r--cryptography/hazmat/primitives/asymmetric/dsa.py71
-rw-r--r--cryptography/hazmat/primitives/asymmetric/rsa.py28
-rw-r--r--cryptography/hazmat/primitives/interfaces.py45
-rw-r--r--cryptography/hazmat/primitives/serialization.py8
21 files changed, 1279 insertions, 711 deletions
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py
index 524e0a5b..e4faf32c 100644
--- a/cryptography/hazmat/backends/interfaces.py
+++ b/cryptography/hazmat/backends/interfaces.py
@@ -196,6 +196,24 @@ class DSABackend(object):
Return True if the parameters are supported by the backend for DSA.
"""
+ @abc.abstractmethod
+ def load_dsa_private_numbers(self, numbers):
+ """
+ Returns a DSAPrivateKey provider.
+ """
+
+ @abc.abstractmethod
+ def load_dsa_public_numbers(self, numbers):
+ """
+ Returns a DSAPublicKey provider.
+ """
+
+ @abc.abstractmethod
+ def load_dsa_parameter_numbers(self, numbers):
+ """
+ Returns a DSAParameters provider.
+ """
+
@six.add_metaclass(abc.ABCMeta)
class TraditionalOpenSSLSerializationBackend(object):
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 0a7a28b4..6a2cf4db 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -15,20 +15,27 @@ from __future__ import absolute_import, division, print_function
import collections
import itertools
-import math
+import warnings
import six
from cryptography import utils
from cryptography.exceptions import (
- AlreadyFinalized, InternalError, InvalidSignature, InvalidTag,
- UnsupportedAlgorithm, _Reasons
+ InternalError, InvalidSignature, InvalidTag, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import (
CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend,
HashBackend, PBKDF2HMACBackend, PKCS8SerializationBackend, RSABackend,
TraditionalOpenSSLSerializationBackend
)
+from cryptography.hazmat.backends.openssl.ec import (
+ _ECDSASignatureContext, _ECDSAVerificationContext,
+ _EllipticCurvePrivateKey, _EllipticCurvePublicKey
+)
+from cryptography.hazmat.backends.openssl.rsa import (
+ _RSAPrivateKey, _RSAPublicKey, _RSASignatureContext,
+ _RSAVerificationContext
+)
from cryptography.hazmat.bindings.openssl.binding import Binding
from cryptography.hazmat.primitives import hashes, interfaces
from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
@@ -41,9 +48,6 @@ from cryptography.hazmat.primitives.ciphers.algorithms import (
from cryptography.hazmat.primitives.ciphers.modes import (
CBC, CFB, CFB8, CTR, ECB, GCM, OFB
)
-from cryptography.hazmat.primitives.interfaces import (
- RSAPrivateKeyWithNumbers, RSAPublicKeyWithNumbers
-)
_MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"])
@@ -533,6 +537,12 @@ class Backend(object):
return ctx
def create_rsa_signature_ctx(self, private_key, padding, algorithm):
+ warnings.warn(
+ "create_rsa_signature_ctx is deprecated and will be removed in a "
+ "future version.",
+ utils.DeprecatedIn05,
+ stacklevel=2
+ )
rsa_cdata = self._rsa_cdata_from_private_key(private_key)
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
key = _RSAPrivateKey(self, rsa_cdata)
@@ -540,6 +550,12 @@ class Backend(object):
def create_rsa_verification_ctx(self, public_key, signature, padding,
algorithm):
+ warnings.warn(
+ "create_rsa_verification_ctx is deprecated and will be removed in "
+ "a future version.",
+ utils.DeprecatedIn05,
+ stacklevel=2
+ )
rsa_cdata = self._rsa_cdata_from_public_key(public_key)
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
key = _RSAPublicKey(self, rsa_cdata)
@@ -547,6 +563,15 @@ class Backend(object):
algorithm)
def mgf1_hash_supported(self, algorithm):
+ warnings.warn(
+ "mgf1_hash_supported is deprecated and will be removed in "
+ "a future version.",
+ utils.DeprecatedIn05,
+ stacklevel=2
+ )
+ return self._mgf1_hash_supported(algorithm)
+
+ def _mgf1_hash_supported(self, algorithm):
if self._lib.Cryptography_HAS_MGF1_MD:
return self.hash_supported(algorithm)
else:
@@ -556,7 +581,7 @@ class Backend(object):
if isinstance(padding, PKCS1v15):
return True
elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1):
- return self.mgf1_hash_supported(padding._mgf._algorithm)
+ return self._mgf1_hash_supported(padding._mgf._algorithm)
elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1):
return isinstance(padding._mgf._algorithm, hashes.SHA1)
else:
@@ -654,12 +679,24 @@ class Backend(object):
return True
def decrypt_rsa(self, private_key, ciphertext, padding):
+ warnings.warn(
+ "decrypt_rsa is deprecated and will be removed in a future "
+ "version.",
+ utils.DeprecatedIn05,
+ stacklevel=2
+ )
rsa_cdata = self._rsa_cdata_from_private_key(private_key)
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
key = _RSAPrivateKey(self, rsa_cdata)
return key.decrypt(ciphertext, padding)
def encrypt_rsa(self, public_key, plaintext, padding):
+ warnings.warn(
+ "encrypt_rsa is deprecated and will be removed in a future "
+ "version.",
+ utils.DeprecatedIn05,
+ stacklevel=2
+ )
rsa_cdata = self._rsa_cdata_from_public_key(public_key)
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
key = _RSAPublicKey(self, rsa_cdata)
@@ -896,8 +933,28 @@ class Backend(object):
if self._lib.Cryptography_HAS_EC != 1:
return False
- curves = self._supported_curves()
- return curve.name.encode("ascii") in curves
+ try:
+ curve_nid = self._elliptic_curve_to_nid(curve)
+ except UnsupportedAlgorithm:
+ curve_nid = self._lib.NID_undef
+
+ ctx = self._lib.EC_GROUP_new_by_curve_name(curve_nid)
+
+ if ctx == self._ffi.NULL:
+ errors = self._consume_errors()
+ assert (
+ curve_nid == self._lib.NID_undef or
+ errors[0][1:] == (
+ self._lib.ERR_LIB_EC,
+ self._lib.EC_F_EC_GROUP_NEW_BY_CURVE_NAME,
+ self._lib.EC_R_UNKNOWN_GROUP
+ )
+ )
+ return False
+ else:
+ assert curve_nid != self._lib.NID_undef
+ self._lib.EC_GROUP_free(ctx)
+ return True
def elliptic_curve_signature_algorithm_supported(
self, signature_algorithm, curve
@@ -918,30 +975,6 @@ class Backend(object):
return self.elliptic_curve_supported(curve)
- def _supported_curves(self):
- if self._lib.Cryptography_HAS_EC != 1:
- return []
-
- num_curves = self._lib.EC_get_builtin_curves(self._ffi.NULL, 0)
- curve_array = self._ffi.new("EC_builtin_curve[]", num_curves)
- num_curves_assigned = self._lib.EC_get_builtin_curves(
- curve_array, num_curves)
- assert num_curves == num_curves_assigned
-
- curves = [
- self._ffi.string(self._lib.OBJ_nid2sn(curve.nid)).decode()
- for curve in curve_array
- ]
-
- curve_aliases = {
- "prime192v1": "secp192r1",
- "prime256v1": "secp256r1"
- }
- return [
- curve_aliases.get(curve, curve)
- for curve in curves
- ]
-
def _create_ecdsa_signature_ctx(self, private_key, ecdsa):
return _ECDSASignatureContext(self, private_key, ecdsa.algorithm)
@@ -1443,384 +1476,6 @@ class _HMACContext(object):
return self._backend._ffi.buffer(buf)[:outlen[0]]
-def _get_rsa_pss_salt_length(pss, key_size, digest_size):
- if pss._mgf._salt_length is not None:
- salt = pss._mgf._salt_length
- else:
- salt = pss._salt_length
-
- if salt is MGF1.MAX_LENGTH or salt is PSS.MAX_LENGTH:
- # bit length - 1 per RFC 3447
- emlen = int(math.ceil((key_size - 1) / 8.0))
- salt_length = emlen - digest_size - 2
- assert salt_length >= 0
- return salt_length
- else:
- return salt
-
-
-@utils.register_interface(interfaces.AsymmetricSignatureContext)
-class _RSASignatureContext(object):
- def __init__(self, backend, private_key, padding, algorithm):
- self._backend = backend
- self._private_key = private_key
-
- if not isinstance(padding, interfaces.AsymmetricPadding):
- raise TypeError(
- "Expected provider of interfaces.AsymmetricPadding.")
-
- self._pkey_size = self._backend._lib.EVP_PKEY_size(
- self._private_key._evp_pkey
- )
-
- if isinstance(padding, PKCS1v15):
- if self._backend._lib.Cryptography_HAS_PKEY_CTX:
- self._finalize_method = self._finalize_pkey_ctx
- self._padding_enum = self._backend._lib.RSA_PKCS1_PADDING
- else:
- self._finalize_method = self._finalize_pkcs1
- elif isinstance(padding, PSS):
- if not isinstance(padding._mgf, MGF1):
- raise UnsupportedAlgorithm(
- "Only MGF1 is supported by this backend.",
- _Reasons.UNSUPPORTED_MGF
- )
-
- # Size of key in bytes - 2 is the maximum
- # PSS signature length (salt length is checked later)
- assert self._pkey_size > 0
- if self._pkey_size - algorithm.digest_size - 2 < 0:
- raise ValueError("Digest too large for key size. Use a larger "
- "key.")
-
- if not self._backend.mgf1_hash_supported(padding._mgf._algorithm):
- raise UnsupportedAlgorithm(
- "When OpenSSL is older than 1.0.1 then only SHA1 is "
- "supported with MGF1.",
- _Reasons.UNSUPPORTED_HASH
- )
-
- if self._backend._lib.Cryptography_HAS_PKEY_CTX:
- self._finalize_method = self._finalize_pkey_ctx
- self._padding_enum = self._backend._lib.RSA_PKCS1_PSS_PADDING
- else:
- self._finalize_method = self._finalize_pss
- else:
- raise UnsupportedAlgorithm(
- "{0} is not supported by this backend.".format(padding.name),
- _Reasons.UNSUPPORTED_PADDING
- )
-
- self._padding = padding
- self._algorithm = algorithm
- self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
-
- def update(self, data):
- self._hash_ctx.update(data)
-
- def finalize(self):
- evp_md = self._backend._lib.EVP_get_digestbyname(
- self._algorithm.name.encode("ascii"))
- assert evp_md != self._backend._ffi.NULL
-
- return self._finalize_method(evp_md)
-
- def _finalize_pkey_ctx(self, evp_md):
- pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new(
- self._private_key._evp_pkey, self._backend._ffi.NULL
- )
- assert pkey_ctx != self._backend._ffi.NULL
- pkey_ctx = self._backend._ffi.gc(pkey_ctx,
- self._backend._lib.EVP_PKEY_CTX_free)
- res = self._backend._lib.EVP_PKEY_sign_init(pkey_ctx)
- assert res == 1
- res = self._backend._lib.EVP_PKEY_CTX_set_signature_md(
- pkey_ctx, evp_md)
- assert res > 0
-
- res = self._backend._lib.EVP_PKEY_CTX_set_rsa_padding(
- pkey_ctx, self._padding_enum)
- assert res > 0
- if isinstance(self._padding, PSS):
- res = self._backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen(
- pkey_ctx,
- _get_rsa_pss_salt_length(
- self._padding,
- self._private_key.key_size,
- self._hash_ctx.algorithm.digest_size
- )
- )
- assert res > 0
-
- if self._backend._lib.Cryptography_HAS_MGF1_MD:
- # MGF1 MD is configurable in OpenSSL 1.0.1+
- mgf1_md = self._backend._lib.EVP_get_digestbyname(
- self._padding._mgf._algorithm.name.encode("ascii"))
- assert mgf1_md != self._backend._ffi.NULL
- res = self._backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(
- pkey_ctx, mgf1_md
- )
- assert res > 0
- data_to_sign = self._hash_ctx.finalize()
- buflen = self._backend._ffi.new("size_t *")
- res = self._backend._lib.EVP_PKEY_sign(
- pkey_ctx,
- self._backend._ffi.NULL,
- buflen,
- data_to_sign,
- len(data_to_sign)
- )
- assert res == 1
- buf = self._backend._ffi.new("unsigned char[]", buflen[0])
- res = self._backend._lib.EVP_PKEY_sign(
- pkey_ctx, buf, buflen, data_to_sign, len(data_to_sign))
- if res != 1:
- errors = self._backend._consume_errors()
- assert errors[0].lib == self._backend._lib.ERR_LIB_RSA
- reason = None
- if (errors[0].reason ==
- self._backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE):
- reason = ("Salt length too long for key size. Try using "
- "MAX_LENGTH instead.")
- elif (errors[0].reason ==
- self._backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY):
- reason = "Digest too large for key size. Use a larger key."
- assert reason is not None
- raise ValueError(reason)
-
- return self._backend._ffi.buffer(buf)[:]
-
- def _finalize_pkcs1(self, evp_md):
- if self._hash_ctx._ctx is None:
- raise AlreadyFinalized("Context has already been finalized.")
-
- sig_buf = self._backend._ffi.new("char[]", self._pkey_size)
- sig_len = self._backend._ffi.new("unsigned int *")
- res = self._backend._lib.EVP_SignFinal(
- self._hash_ctx._ctx._ctx,
- sig_buf,
- sig_len,
- self._private_key._evp_pkey
- )
- self._hash_ctx.finalize()
- if res == 0:
- errors = self._backend._consume_errors()
- assert errors[0].lib == self._backend._lib.ERR_LIB_RSA
- assert (errors[0].reason ==
- self._backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY)
- raise ValueError("Digest too large for key size. Use a larger "
- "key.")
-
- return self._backend._ffi.buffer(sig_buf)[:sig_len[0]]
-
- def _finalize_pss(self, evp_md):
- data_to_sign = self._hash_ctx.finalize()
- padded = self._backend._ffi.new("unsigned char[]", self._pkey_size)
- res = self._backend._lib.RSA_padding_add_PKCS1_PSS(
- self._private_key._rsa_cdata,
- padded,
- data_to_sign,
- evp_md,
- _get_rsa_pss_salt_length(
- self._padding,
- self._private_key.key_size,
- len(data_to_sign)
- )
- )
- if res != 1:
- errors = self._backend._consume_errors()
- assert errors[0].lib == self._backend._lib.ERR_LIB_RSA
- assert (errors[0].reason ==
- self._backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE)
- raise ValueError("Salt length too long for key size. Try using "
- "MAX_LENGTH instead.")
-
- sig_buf = self._backend._ffi.new("char[]", self._pkey_size)
- sig_len = self._backend._lib.RSA_private_encrypt(
- self._pkey_size,
- padded,
- sig_buf,
- self._private_key._rsa_cdata,
- self._backend._lib.RSA_NO_PADDING
- )
- assert sig_len != -1
- return self._backend._ffi.buffer(sig_buf)[:sig_len]
-
-
-@utils.register_interface(interfaces.AsymmetricVerificationContext)
-class _RSAVerificationContext(object):
- def __init__(self, backend, public_key, signature, padding, algorithm):
- self._backend = backend
- self._public_key = public_key
- self._signature = signature
-
- if not isinstance(padding, interfaces.AsymmetricPadding):
- raise TypeError(
- "Expected provider of interfaces.AsymmetricPadding.")
-
- self._pkey_size = self._backend._lib.EVP_PKEY_size(
- self._public_key._evp_pkey
- )
-
- if isinstance(padding, PKCS1v15):
- if self._backend._lib.Cryptography_HAS_PKEY_CTX:
- self._verify_method = self._verify_pkey_ctx
- self._padding_enum = self._backend._lib.RSA_PKCS1_PADDING
- else:
- self._verify_method = self._verify_pkcs1
- elif isinstance(padding, PSS):
- if not isinstance(padding._mgf, MGF1):
- raise UnsupportedAlgorithm(
- "Only MGF1 is supported by this backend.",
- _Reasons.UNSUPPORTED_MGF
- )
-
- # Size of key in bytes - 2 is the maximum
- # PSS signature length (salt length is checked later)
- assert self._pkey_size > 0
- if self._pkey_size - algorithm.digest_size - 2 < 0:
- raise ValueError(
- "Digest too large for key size. Check that you have the "
- "correct key and digest algorithm."
- )
-
- if not self._backend.mgf1_hash_supported(padding._mgf._algorithm):
- raise UnsupportedAlgorithm(
- "When OpenSSL is older than 1.0.1 then only SHA1 is "
- "supported with MGF1.",
- _Reasons.UNSUPPORTED_HASH
- )
-
- if self._backend._lib.Cryptography_HAS_PKEY_CTX:
- self._verify_method = self._verify_pkey_ctx
- self._padding_enum = self._backend._lib.RSA_PKCS1_PSS_PADDING
- else:
- self._verify_method = self._verify_pss
- else:
- raise UnsupportedAlgorithm(
- "{0} is not supported by this backend.".format(padding.name),
- _Reasons.UNSUPPORTED_PADDING
- )
-
- self._padding = padding
- self._algorithm = algorithm
- self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
-
- def update(self, data):
- self._hash_ctx.update(data)
-
- def verify(self):
- evp_md = self._backend._lib.EVP_get_digestbyname(
- self._algorithm.name.encode("ascii"))
- assert evp_md != self._backend._ffi.NULL
-
- self._verify_method(evp_md)
-
- def _verify_pkey_ctx(self, evp_md):
- pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new(
- self._public_key._evp_pkey, self._backend._ffi.NULL
- )
- assert pkey_ctx != self._backend._ffi.NULL
- pkey_ctx = self._backend._ffi.gc(pkey_ctx,
- self._backend._lib.EVP_PKEY_CTX_free)
- res = self._backend._lib.EVP_PKEY_verify_init(pkey_ctx)
- assert res == 1
- res = self._backend._lib.EVP_PKEY_CTX_set_signature_md(
- pkey_ctx, evp_md)
- assert res > 0
-
- res = self._backend._lib.EVP_PKEY_CTX_set_rsa_padding(
- pkey_ctx, self._padding_enum)
- assert res > 0
- if isinstance(self._padding, PSS):
- res = self._backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen(
- pkey_ctx,
- _get_rsa_pss_salt_length(
- self._padding,
- self._public_key.key_size,
- self._hash_ctx.algorithm.digest_size
- )
- )
- assert res > 0
- if self._backend._lib.Cryptography_HAS_MGF1_MD:
- # MGF1 MD is configurable in OpenSSL 1.0.1+
- mgf1_md = self._backend._lib.EVP_get_digestbyname(
- self._padding._mgf._algorithm.name.encode("ascii"))
- assert mgf1_md != self._backend._ffi.NULL
- res = self._backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(
- pkey_ctx, mgf1_md
- )
- assert res > 0
-
- data_to_verify = self._hash_ctx.finalize()
- res = self._backend._lib.EVP_PKEY_verify(
- pkey_ctx,
- self._signature,
- len(self._signature),
- data_to_verify,
- len(data_to_verify)
- )
- # The previous call can return negative numbers in the event of an
- # error. This is not a signature failure but we need to fail if it
- # occurs.
- assert res >= 0
- if res == 0:
- errors = self._backend._consume_errors()
- assert errors
- raise InvalidSignature
-
- def _verify_pkcs1(self, evp_md):
- if self._hash_ctx._ctx is None:
- raise AlreadyFinalized("Context has already been finalized.")
-
- res = self._backend._lib.EVP_VerifyFinal(
- self._hash_ctx._ctx._ctx,
- self._signature,
- len(self._signature),
- self._public_key._evp_pkey
- )
- self._hash_ctx.finalize()
- # The previous call can return negative numbers in the event of an
- # error. This is not a signature failure but we need to fail if it
- # occurs.
- assert res >= 0
- if res == 0:
- errors = self._backend._consume_errors()
- assert errors
- raise InvalidSignature
-
- def _verify_pss(self, evp_md):
- buf = self._backend._ffi.new("unsigned char[]", self._pkey_size)
- res = self._backend._lib.RSA_public_decrypt(
- len(self._signature),
- self._signature,
- buf,
- self._public_key._rsa_cdata,
- self._backend._lib.RSA_NO_PADDING
- )
- if res != self._pkey_size:
- errors = self._backend._consume_errors()
- assert errors
- raise InvalidSignature
-
- data_to_verify = self._hash_ctx.finalize()
- res = self._backend._lib.RSA_verify_PKCS1_PSS(
- self._public_key._rsa_cdata,
- data_to_verify,
- evp_md,
- buf,
- _get_rsa_pss_salt_length(
- self._padding,
- self._public_key.key_size,
- len(data_to_verify)
- )
- )
- if res != 1:
- errors = self._backend._consume_errors()
- assert errors
- raise InvalidSignature
-
-
@utils.register_interface(interfaces.AsymmetricVerificationContext)
class _DSAVerificationContext(object):
def __init__(self, backend, public_key, signature, algorithm):
@@ -1949,240 +1604,4 @@ class _CMACContext(object):
)
-def _truncate_digest_for_ecdsa(ec_key_cdata, digest, backend):
- _lib = backend._lib
- _ffi = backend._ffi
-
- digest_len = len(digest)
-
- group = _lib.EC_KEY_get0_group(ec_key_cdata)
-
- bn_ctx = _lib.BN_CTX_new()
- assert bn_ctx != _ffi.NULL
- bn_ctx = _ffi.gc(bn_ctx, _lib.BN_CTX_free)
-
- order = _lib.BN_CTX_get(bn_ctx)
- assert order != _ffi.NULL
-
- res = _lib.EC_GROUP_get_order(group, order, bn_ctx)
- assert res == 1
-
- order_bits = _lib.BN_num_bits(order)
-
- if 8 * digest_len > order_bits:
- digest_len = (order_bits + 7) // 8
- digest = digest[:digest_len]
-
- if 8 * digest_len > order_bits:
- rshift = 8 - (order_bits & 0x7)
- assert rshift > 0 and rshift < 8
-
- mask = 0xFF >> rshift << rshift
-
- # Set the bottom rshift bits to 0
- digest = digest[:-1] + six.int2byte(six.byte2int(digest[-1]) & mask)
-
- return digest
-
-
-@utils.register_interface(interfaces.AsymmetricSignatureContext)
-class _ECDSASignatureContext(object):
- def __init__(self, backend, private_key, algorithm):
- self._backend = backend
- self._private_key = private_key
- self._digest = hashes.Hash(algorithm, backend)
-
- def update(self, data):
- self._digest.update(data)
-
- def finalize(self):
- ec_key = self._private_key._ec_key
-
- digest = self._digest.finalize()
-
- digest = _truncate_digest_for_ecdsa(ec_key, digest, self._backend)
-
- max_size = self._backend._lib.ECDSA_size(ec_key)
- assert max_size > 0
-
- sigbuf = self._backend._ffi.new("char[]", max_size)
- siglen_ptr = self._backend._ffi.new("unsigned int[]", 1)
- res = self._backend._lib.ECDSA_sign(
- 0,
- digest,
- len(digest),
- sigbuf,
- siglen_ptr,
- ec_key
- )
- assert res == 1
- return self._backend._ffi.buffer(sigbuf)[:siglen_ptr[0]]
-
-
-@utils.register_interface(interfaces.AsymmetricVerificationContext)
-class _ECDSAVerificationContext(object):
- def __init__(self, backend, public_key, signature, algorithm):
- self._backend = backend
- self._public_key = public_key
- self._signature = signature
- self._digest = hashes.Hash(algorithm, backend)
-
- def update(self, data):
- self._digest.update(data)
-
- def verify(self):
- ec_key = self._public_key._ec_key
-
- digest = self._digest.finalize()
-
- digest = _truncate_digest_for_ecdsa(ec_key, digest, self._backend)
-
- res = self._backend._lib.ECDSA_verify(
- 0,
- digest,
- len(digest),
- self._signature,
- len(self._signature),
- ec_key
- )
- if res != 1:
- self._backend._consume_errors()
- raise InvalidSignature
- return True
-
-
-@utils.register_interface(interfaces.EllipticCurvePrivateKey)
-class _EllipticCurvePrivateKey(object):
- def __init__(self, backend, ec_key_cdata, curve):
- self._backend = backend
- self._ec_key = ec_key_cdata
- self._curve = curve
-
- @property
- def curve(self):
- return self._curve
-
- def signer(self, signature_algorithm):
- if isinstance(signature_algorithm, ec.ECDSA):
- return self._backend._create_ecdsa_signature_ctx(
- self, signature_algorithm)
- else:
- raise UnsupportedAlgorithm(
- "Unsupported elliptic curve signature algorithm.",
- _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
-
- def public_key(self):
- public_ec_key = self._backend._public_ec_key_from_private_ec_key(
- self._ec_key
- )
-
- return _EllipticCurvePublicKey(
- self._backend, public_ec_key, self._curve)
-
-
-@utils.register_interface(interfaces.EllipticCurvePublicKey)
-class _EllipticCurvePublicKey(object):
- def __init__(self, backend, ec_key_cdata, curve):
- self._backend = backend
- self._ec_key = ec_key_cdata
- self._curve = curve
-
- @property
- def curve(self):
- return self._curve
-
- def verifier(self, signature, signature_algorithm):
- if isinstance(signature_algorithm, ec.ECDSA):
- return self._backend._create_ecdsa_verification_ctx(
- self, signature, signature_algorithm)
- else:
- raise UnsupportedAlgorithm(
- "Unsupported elliptic curve signature algorithm.",
- _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
-
-
-@utils.register_interface(RSAPrivateKeyWithNumbers)
-class _RSAPrivateKey(object):
- def __init__(self, backend, rsa_cdata):
- self._backend = backend
- self._rsa_cdata = rsa_cdata
-
- evp_pkey = self._backend._lib.EVP_PKEY_new()
- assert evp_pkey != self._backend._ffi.NULL
- evp_pkey = self._backend._ffi.gc(
- evp_pkey, self._backend._lib.EVP_PKEY_free
- )
- res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata)
- assert res == 1
- self._evp_pkey = evp_pkey
-
- self.key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
-
- def signer(self, padding, algorithm):
- return _RSASignatureContext(self._backend, self, padding, algorithm)
-
- def decrypt(self, ciphertext, padding):
- key_size_bytes = int(math.ceil(self.key_size / 8.0))
- if key_size_bytes != len(ciphertext):
- raise ValueError("Ciphertext length must be equal to key size.")
-
- return self._backend._enc_dec_rsa(self, ciphertext, padding)
-
- def public_key(self):
- ctx = self._backend._lib.RSA_new()
- assert ctx != self._backend._ffi.NULL
- ctx = self._backend._ffi.gc(ctx, self._backend._lib.RSA_free)
- ctx.e = self._backend._lib.BN_dup(self._rsa_cdata.e)
- ctx.n = self._backend._lib.BN_dup(self._rsa_cdata.n)
- res = self._backend._lib.RSA_blinding_on(ctx, self._backend._ffi.NULL)
- assert res == 1
- return _RSAPublicKey(self._backend, ctx)
-
- def private_numbers(self):
- return rsa.RSAPrivateNumbers(
- p=self._backend._bn_to_int(self._rsa_cdata.p),
- q=self._backend._bn_to_int(self._rsa_cdata.q),
- d=self._backend._bn_to_int(self._rsa_cdata.d),
- dmp1=self._backend._bn_to_int(self._rsa_cdata.dmp1),
- dmq1=self._backend._bn_to_int(self._rsa_cdata.dmq1),
- iqmp=self._backend._bn_to_int(self._rsa_cdata.iqmp),
- public_numbers=rsa.RSAPublicNumbers(
- e=self._backend._bn_to_int(self._rsa_cdata.e),
- n=self._backend._bn_to_int(self._rsa_cdata.n),
- )
- )
-
-
-@utils.register_interface(RSAPublicKeyWithNumbers)
-class _RSAPublicKey(object):
- def __init__(self, backend, rsa_cdata):
- self._backend = backend
- self._rsa_cdata = rsa_cdata
-
- evp_pkey = self._backend._lib.EVP_PKEY_new()
- assert evp_pkey != self._backend._ffi.NULL
- evp_pkey = self._backend._ffi.gc(
- evp_pkey, self._backend._lib.EVP_PKEY_free
- )
- res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata)
- assert res == 1
- self._evp_pkey = evp_pkey
-
- self.key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
-
- def verifier(self, signature, padding, algorithm):
- return _RSAVerificationContext(
- self._backend, self, signature, padding, algorithm
- )
-
- def encrypt(self, plaintext, padding):
- return self._backend._enc_dec_rsa(self, plaintext, padding)
-
- def public_numbers(self):
- return rsa.RSAPublicNumbers(
- e=self._backend._bn_to_int(self._rsa_cdata.e),
- n=self._backend._bn_to_int(self._rsa_cdata.n),
- )
-
-
backend = Backend()
diff --git a/cryptography/hazmat/backends/openssl/ec.py b/cryptography/hazmat/backends/openssl/ec.py
new file mode 100644
index 00000000..892d20ea
--- /dev/null
+++ b/cryptography/hazmat/backends/openssl/ec.py
@@ -0,0 +1,175 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import absolute_import, division, print_function
+
+import six
+
+from cryptography import utils
+from cryptography.exceptions import (
+ InvalidSignature, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.primitives import hashes, interfaces
+from cryptography.hazmat.primitives.asymmetric import ec
+
+
+def _truncate_digest_for_ecdsa(ec_key_cdata, digest, backend):
+ _lib = backend._lib
+ _ffi = backend._ffi
+
+ digest_len = len(digest)
+
+ group = _lib.EC_KEY_get0_group(ec_key_cdata)
+
+ bn_ctx = _lib.BN_CTX_new()
+ assert bn_ctx != _ffi.NULL
+ bn_ctx = _ffi.gc(bn_ctx, _lib.BN_CTX_free)
+
+ order = _lib.BN_CTX_get(bn_ctx)
+ assert order != _ffi.NULL
+
+ res = _lib.EC_GROUP_get_order(group, order, bn_ctx)
+ assert res == 1
+
+ order_bits = _lib.BN_num_bits(order)
+
+ if 8 * digest_len > order_bits:
+ digest_len = (order_bits + 7) // 8
+ digest = digest[:digest_len]
+
+ if 8 * digest_len > order_bits:
+ rshift = 8 - (order_bits & 0x7)
+ assert rshift > 0 and rshift < 8
+
+ mask = 0xFF >> rshift << rshift
+
+ # Set the bottom rshift bits to 0
+ digest = digest[:-1] + six.int2byte(six.indexbytes(digest, -1) & mask)
+
+ return digest
+
+
+@utils.register_interface(interfaces.AsymmetricSignatureContext)
+class _ECDSASignatureContext(object):
+ def __init__(self, backend, private_key, algorithm):
+ self._backend = backend
+ self._private_key = private_key
+ self._digest = hashes.Hash(algorithm, backend)
+
+ def update(self, data):
+ self._digest.update(data)
+
+ def finalize(self):
+ ec_key = self._private_key._ec_key
+
+ digest = self._digest.finalize()
+
+ digest = _truncate_digest_for_ecdsa(ec_key, digest, self._backend)
+
+ max_size = self._backend._lib.ECDSA_size(ec_key)
+ assert max_size > 0
+
+ sigbuf = self._backend._ffi.new("char[]", max_size)
+ siglen_ptr = self._backend._ffi.new("unsigned int[]", 1)
+ res = self._backend._lib.ECDSA_sign(
+ 0,
+ digest,
+ len(digest),
+ sigbuf,
+ siglen_ptr,
+ ec_key
+ )
+ assert res == 1
+ return self._backend._ffi.buffer(sigbuf)[:siglen_ptr[0]]
+
+
+@utils.register_interface(interfaces.AsymmetricVerificationContext)
+class _ECDSAVerificationContext(object):
+ def __init__(self, backend, public_key, signature, algorithm):
+ self._backend = backend
+ self._public_key = public_key
+ self._signature = signature
+ self._digest = hashes.Hash(algorithm, backend)
+
+ def update(self, data):
+ self._digest.update(data)
+
+ def verify(self):
+ ec_key = self._public_key._ec_key
+
+ digest = self._digest.finalize()
+
+ digest = _truncate_digest_for_ecdsa(ec_key, digest, self._backend)
+
+ res = self._backend._lib.ECDSA_verify(
+ 0,
+ digest,
+ len(digest),
+ self._signature,
+ len(self._signature),
+ ec_key
+ )
+ if res != 1:
+ self._backend._consume_errors()
+ raise InvalidSignature
+ return True
+
+
+@utils.register_interface(interfaces.EllipticCurvePrivateKey)
+class _EllipticCurvePrivateKey(object):
+ def __init__(self, backend, ec_key_cdata, curve):
+ self._backend = backend
+ self._ec_key = ec_key_cdata
+ self._curve = curve
+
+ @property
+ def curve(self):
+ return self._curve
+
+ def signer(self, signature_algorithm):
+ if isinstance(signature_algorithm, ec.ECDSA):
+ return self._backend._create_ecdsa_signature_ctx(
+ self, signature_algorithm)
+ else:
+ raise UnsupportedAlgorithm(
+ "Unsupported elliptic curve signature algorithm.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def public_key(self):
+ public_ec_key = self._backend._public_ec_key_from_private_ec_key(
+ self._ec_key
+ )
+
+ return _EllipticCurvePublicKey(
+ self._backend, public_ec_key, self._curve)
+
+
+@utils.register_interface(interfaces.EllipticCurvePublicKey)
+class _EllipticCurvePublicKey(object):
+ def __init__(self, backend, ec_key_cdata, curve):
+ self._backend = backend
+ self._ec_key = ec_key_cdata
+ self._curve = curve
+
+ @property
+ def curve(self):
+ return self._curve
+
+ def verifier(self, signature, signature_algorithm):
+ if isinstance(signature_algorithm, ec.ECDSA):
+ return self._backend._create_ecdsa_verification_ctx(
+ self, signature, signature_algorithm)
+ else:
+ raise UnsupportedAlgorithm(
+ "Unsupported elliptic curve signature algorithm.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
diff --git a/cryptography/hazmat/backends/openssl/rsa.py b/cryptography/hazmat/backends/openssl/rsa.py
new file mode 100644
index 00000000..2fada1b9
--- /dev/null
+++ b/cryptography/hazmat/backends/openssl/rsa.py
@@ -0,0 +1,491 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import absolute_import, division, print_function
+
+import math
+
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, InvalidSignature, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.primitives import hashes, interfaces
+from cryptography.hazmat.primitives.asymmetric import rsa
+from cryptography.hazmat.primitives.asymmetric.padding import (
+ MGF1, PKCS1v15, PSS
+)
+from cryptography.hazmat.primitives.interfaces import (
+ RSAPrivateKeyWithNumbers, RSAPublicKeyWithNumbers
+)
+
+
+def _get_rsa_pss_salt_length(pss, key_size, digest_size):
+ if pss._mgf._salt_length is not None:
+ salt = pss._mgf._salt_length
+ else:
+ salt = pss._salt_length
+
+ if salt is MGF1.MAX_LENGTH or salt is PSS.MAX_LENGTH:
+ # bit length - 1 per RFC 3447
+ emlen = int(math.ceil((key_size - 1) / 8.0))
+ salt_length = emlen - digest_size - 2
+ assert salt_length >= 0
+ return salt_length
+ else:
+ return salt
+
+
+@utils.register_interface(interfaces.AsymmetricSignatureContext)
+class _RSASignatureContext(object):
+ def __init__(self, backend, private_key, padding, algorithm):
+ self._backend = backend
+ self._private_key = private_key
+
+ if not isinstance(padding, interfaces.AsymmetricPadding):
+ raise TypeError(
+ "Expected provider of interfaces.AsymmetricPadding.")
+
+ self._pkey_size = self._backend._lib.EVP_PKEY_size(
+ self._private_key._evp_pkey
+ )
+
+ if isinstance(padding, PKCS1v15):
+ if self._backend._lib.Cryptography_HAS_PKEY_CTX:
+ self._finalize_method = self._finalize_pkey_ctx
+ self._padding_enum = self._backend._lib.RSA_PKCS1_PADDING
+ else:
+ self._finalize_method = self._finalize_pkcs1
+ elif isinstance(padding, PSS):
+ if not isinstance(padding._mgf, MGF1):
+ raise UnsupportedAlgorithm(
+ "Only MGF1 is supported by this backend.",
+ _Reasons.UNSUPPORTED_MGF
+ )
+
+ # Size of key in bytes - 2 is the maximum
+ # PSS signature length (salt length is checked later)
+ assert self._pkey_size > 0
+ if self._pkey_size - algorithm.digest_size - 2 < 0:
+ raise ValueError("Digest too large for key size. Use a larger "
+ "key.")
+
+ if not self._backend._mgf1_hash_supported(padding._mgf._algorithm):
+ raise UnsupportedAlgorithm(
+ "When OpenSSL is older than 1.0.1 then only SHA1 is "
+ "supported with MGF1.",
+ _Reasons.UNSUPPORTED_HASH
+ )
+
+ if self._backend._lib.Cryptography_HAS_PKEY_CTX:
+ self._finalize_method = self._finalize_pkey_ctx
+ self._padding_enum = self._backend._lib.RSA_PKCS1_PSS_PADDING
+ else:
+ self._finalize_method = self._finalize_pss
+ else:
+ raise UnsupportedAlgorithm(
+ "{0} is not supported by this backend.".format(padding.name),
+ _Reasons.UNSUPPORTED_PADDING
+ )
+
+ self._padding = padding
+ self._algorithm = algorithm
+ self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
+
+ def update(self, data):
+ self._hash_ctx.update(data)
+
+ def finalize(self):
+ evp_md = self._backend._lib.EVP_get_digestbyname(
+ self._algorithm.name.encode("ascii"))
+ assert evp_md != self._backend._ffi.NULL
+
+ return self._finalize_method(evp_md)
+
+ def _finalize_pkey_ctx(self, evp_md):
+ pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new(
+ self._private_key._evp_pkey, self._backend._ffi.NULL
+ )
+ assert pkey_ctx != self._backend._ffi.NULL
+ pkey_ctx = self._backend._ffi.gc(pkey_ctx,
+ self._backend._lib.EVP_PKEY_CTX_free)
+ res = self._backend._lib.EVP_PKEY_sign_init(pkey_ctx)
+ assert res == 1
+ res = self._backend._lib.EVP_PKEY_CTX_set_signature_md(
+ pkey_ctx, evp_md)
+ assert res > 0
+
+ res = self._backend._lib.EVP_PKEY_CTX_set_rsa_padding(
+ pkey_ctx, self._padding_enum)
+ assert res > 0
+ if isinstance(self._padding, PSS):
+ res = self._backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen(
+ pkey_ctx,
+ _get_rsa_pss_salt_length(
+ self._padding,
+ self._private_key.key_size,
+ self._hash_ctx.algorithm.digest_size
+ )
+ )
+ assert res > 0
+
+ if self._backend._lib.Cryptography_HAS_MGF1_MD:
+ # MGF1 MD is configurable in OpenSSL 1.0.1+
+ mgf1_md = self._backend._lib.EVP_get_digestbyname(
+ self._padding._mgf._algorithm.name.encode("ascii"))
+ assert mgf1_md != self._backend._ffi.NULL
+ res = self._backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(
+ pkey_ctx, mgf1_md
+ )
+ assert res > 0
+ data_to_sign = self._hash_ctx.finalize()
+ buflen = self._backend._ffi.new("size_t *")
+ res = self._backend._lib.EVP_PKEY_sign(
+ pkey_ctx,
+ self._backend._ffi.NULL,
+ buflen,
+ data_to_sign,
+ len(data_to_sign)
+ )
+ assert res == 1
+ buf = self._backend._ffi.new("unsigned char[]", buflen[0])
+ res = self._backend._lib.EVP_PKEY_sign(
+ pkey_ctx, buf, buflen, data_to_sign, len(data_to_sign))
+ if res != 1:
+ errors = self._backend._consume_errors()
+ assert errors[0].lib == self._backend._lib.ERR_LIB_RSA
+ reason = None
+ if (errors[0].reason ==
+ self._backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE):
+ reason = ("Salt length too long for key size. Try using "
+ "MAX_LENGTH instead.")
+ elif (errors[0].reason ==
+ self._backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY):
+ reason = "Digest too large for key size. Use a larger key."
+ assert reason is not None
+ raise ValueError(reason)
+
+ return self._backend._ffi.buffer(buf)[:]
+
+ def _finalize_pkcs1(self, evp_md):
+ if self._hash_ctx._ctx is None:
+ raise AlreadyFinalized("Context has already been finalized.")
+
+ sig_buf = self._backend._ffi.new("char[]", self._pkey_size)
+ sig_len = self._backend._ffi.new("unsigned int *")
+ res = self._backend._lib.EVP_SignFinal(
+ self._hash_ctx._ctx._ctx,
+ sig_buf,
+ sig_len,
+ self._private_key._evp_pkey
+ )
+ self._hash_ctx.finalize()
+ if res == 0:
+ errors = self._backend._consume_errors()
+ assert errors[0].lib == self._backend._lib.ERR_LIB_RSA
+ assert (errors[0].reason ==
+ self._backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY)
+ raise ValueError("Digest too large for key size. Use a larger "
+ "key.")
+
+ return self._backend._ffi.buffer(sig_buf)[:sig_len[0]]
+
+ def _finalize_pss(self, evp_md):
+ data_to_sign = self._hash_ctx.finalize()
+ padded = self._backend._ffi.new("unsigned char[]", self._pkey_size)
+ res = self._backend._lib.RSA_padding_add_PKCS1_PSS(
+ self._private_key._rsa_cdata,
+ padded,
+ data_to_sign,
+ evp_md,
+ _get_rsa_pss_salt_length(
+ self._padding,
+ self._private_key.key_size,
+ len(data_to_sign)
+ )
+ )
+ if res != 1:
+ errors = self._backend._consume_errors()
+ assert errors[0].lib == self._backend._lib.ERR_LIB_RSA
+ assert (errors[0].reason ==
+ self._backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE)
+ raise ValueError("Salt length too long for key size. Try using "
+ "MAX_LENGTH instead.")
+
+ sig_buf = self._backend._ffi.new("char[]", self._pkey_size)
+ sig_len = self._backend._lib.RSA_private_encrypt(
+ self._pkey_size,
+ padded,
+ sig_buf,
+ self._private_key._rsa_cdata,
+ self._backend._lib.RSA_NO_PADDING
+ )
+ assert sig_len != -1
+ return self._backend._ffi.buffer(sig_buf)[:sig_len]
+
+
+@utils.register_interface(interfaces.AsymmetricVerificationContext)
+class _RSAVerificationContext(object):
+ def __init__(self, backend, public_key, signature, padding, algorithm):
+ self._backend = backend
+ self._public_key = public_key
+ self._signature = signature
+
+ if not isinstance(padding, interfaces.AsymmetricPadding):
+ raise TypeError(
+ "Expected provider of interfaces.AsymmetricPadding.")
+
+ self._pkey_size = self._backend._lib.EVP_PKEY_size(
+ self._public_key._evp_pkey
+ )
+
+ if isinstance(padding, PKCS1v15):
+ if self._backend._lib.Cryptography_HAS_PKEY_CTX:
+ self._verify_method = self._verify_pkey_ctx
+ self._padding_enum = self._backend._lib.RSA_PKCS1_PADDING
+ else:
+ self._verify_method = self._verify_pkcs1
+ elif isinstance(padding, PSS):
+ if not isinstance(padding._mgf, MGF1):
+ raise UnsupportedAlgorithm(
+ "Only MGF1 is supported by this backend.",
+ _Reasons.UNSUPPORTED_MGF
+ )
+
+ # Size of key in bytes - 2 is the maximum
+ # PSS signature length (salt length is checked later)
+ assert self._pkey_size > 0
+ if self._pkey_size - algorithm.digest_size - 2 < 0:
+ raise ValueError(
+ "Digest too large for key size. Check that you have the "
+ "correct key and digest algorithm."
+ )
+
+ if not self._backend._mgf1_hash_supported(padding._mgf._algorithm):
+ raise UnsupportedAlgorithm(
+ "When OpenSSL is older than 1.0.1 then only SHA1 is "
+ "supported with MGF1.",
+ _Reasons.UNSUPPORTED_HASH
+ )
+
+ if self._backend._lib.Cryptography_HAS_PKEY_CTX:
+ self._verify_method = self._verify_pkey_ctx
+ self._padding_enum = self._backend._lib.RSA_PKCS1_PSS_PADDING
+ else:
+ self._verify_method = self._verify_pss
+ else:
+ raise UnsupportedAlgorithm(
+ "{0} is not supported by this backend.".format(padding.name),
+ _Reasons.UNSUPPORTED_PADDING
+ )
+
+ self._padding = padding
+ self._algorithm = algorithm
+ self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
+
+ def update(self, data):
+ self._hash_ctx.update(data)
+
+ def verify(self):
+ evp_md = self._backend._lib.EVP_get_digestbyname(
+ self._algorithm.name.encode("ascii"))
+ assert evp_md != self._backend._ffi.NULL
+
+ self._verify_method(evp_md)
+
+ def _verify_pkey_ctx(self, evp_md):
+ pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new(
+ self._public_key._evp_pkey, self._backend._ffi.NULL
+ )
+ assert pkey_ctx != self._backend._ffi.NULL
+ pkey_ctx = self._backend._ffi.gc(pkey_ctx,
+ self._backend._lib.EVP_PKEY_CTX_free)
+ res = self._backend._lib.EVP_PKEY_verify_init(pkey_ctx)
+ assert res == 1
+ res = self._backend._lib.EVP_PKEY_CTX_set_signature_md(
+ pkey_ctx, evp_md)
+ assert res > 0
+
+ res = self._backend._lib.EVP_PKEY_CTX_set_rsa_padding(
+ pkey_ctx, self._padding_enum)
+ assert res > 0
+ if isinstance(self._padding, PSS):
+ res = self._backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen(
+ pkey_ctx,
+ _get_rsa_pss_salt_length(
+ self._padding,
+ self._public_key.key_size,
+ self._hash_ctx.algorithm.digest_size
+ )
+ )
+ assert res > 0
+ if self._backend._lib.Cryptography_HAS_MGF1_MD:
+ # MGF1 MD is configurable in OpenSSL 1.0.1+
+ mgf1_md = self._backend._lib.EVP_get_digestbyname(
+ self._padding._mgf._algorithm.name.encode("ascii"))
+ assert mgf1_md != self._backend._ffi.NULL
+ res = self._backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(
+ pkey_ctx, mgf1_md
+ )
+ assert res > 0
+
+ data_to_verify = self._hash_ctx.finalize()
+ res = self._backend._lib.EVP_PKEY_verify(
+ pkey_ctx,
+ self._signature,
+ len(self._signature),
+ data_to_verify,
+ len(data_to_verify)
+ )
+ # The previous call can return negative numbers in the event of an
+ # error. This is not a signature failure but we need to fail if it
+ # occurs.
+ assert res >= 0
+ if res == 0:
+ errors = self._backend._consume_errors()
+ assert errors
+ raise InvalidSignature
+
+ def _verify_pkcs1(self, evp_md):
+ if self._hash_ctx._ctx is None:
+ raise AlreadyFinalized("Context has already been finalized.")
+
+ res = self._backend._lib.EVP_VerifyFinal(
+ self._hash_ctx._ctx._ctx,
+ self._signature,
+ len(self._signature),
+ self._public_key._evp_pkey
+ )
+ self._hash_ctx.finalize()
+ # The previous call can return negative numbers in the event of an
+ # error. This is not a signature failure but we need to fail if it
+ # occurs.
+ assert res >= 0
+ if res == 0:
+ errors = self._backend._consume_errors()
+ assert errors
+ raise InvalidSignature
+
+ def _verify_pss(self, evp_md):
+ buf = self._backend._ffi.new("unsigned char[]", self._pkey_size)
+ res = self._backend._lib.RSA_public_decrypt(
+ len(self._signature),
+ self._signature,
+ buf,
+ self._public_key._rsa_cdata,
+ self._backend._lib.RSA_NO_PADDING
+ )
+ if res != self._pkey_size:
+ errors = self._backend._consume_errors()
+ assert errors
+ raise InvalidSignature
+
+ data_to_verify = self._hash_ctx.finalize()
+ res = self._backend._lib.RSA_verify_PKCS1_PSS(
+ self._public_key._rsa_cdata,
+ data_to_verify,
+ evp_md,
+ buf,
+ _get_rsa_pss_salt_length(
+ self._padding,
+ self._public_key.key_size,
+ len(data_to_verify)
+ )
+ )
+ if res != 1:
+ errors = self._backend._consume_errors()
+ assert errors
+ raise InvalidSignature
+
+
+@utils.register_interface(RSAPrivateKeyWithNumbers)
+class _RSAPrivateKey(object):
+ def __init__(self, backend, rsa_cdata):
+ self._backend = backend
+ self._rsa_cdata = rsa_cdata
+
+ evp_pkey = self._backend._lib.EVP_PKEY_new()
+ assert evp_pkey != self._backend._ffi.NULL
+ evp_pkey = self._backend._ffi.gc(
+ evp_pkey, self._backend._lib.EVP_PKEY_free
+ )
+ res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata)
+ assert res == 1
+ self._evp_pkey = evp_pkey
+
+ self.key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
+
+ def signer(self, padding, algorithm):
+ return _RSASignatureContext(self._backend, self, padding, algorithm)
+
+ def decrypt(self, ciphertext, padding):
+ key_size_bytes = int(math.ceil(self.key_size / 8.0))
+ if key_size_bytes != len(ciphertext):
+ raise ValueError("Ciphertext length must be equal to key size.")
+
+ return self._backend._enc_dec_rsa(self, ciphertext, padding)
+
+ def public_key(self):
+ ctx = self._backend._lib.RSA_new()
+ assert ctx != self._backend._ffi.NULL
+ ctx = self._backend._ffi.gc(ctx, self._backend._lib.RSA_free)
+ ctx.e = self._backend._lib.BN_dup(self._rsa_cdata.e)
+ ctx.n = self._backend._lib.BN_dup(self._rsa_cdata.n)
+ res = self._backend._lib.RSA_blinding_on(ctx, self._backend._ffi.NULL)
+ assert res == 1
+ return _RSAPublicKey(self._backend, ctx)
+
+ def private_numbers(self):
+ return rsa.RSAPrivateNumbers(
+ p=self._backend._bn_to_int(self._rsa_cdata.p),
+ q=self._backend._bn_to_int(self._rsa_cdata.q),
+ d=self._backend._bn_to_int(self._rsa_cdata.d),
+ dmp1=self._backend._bn_to_int(self._rsa_cdata.dmp1),
+ dmq1=self._backend._bn_to_int(self._rsa_cdata.dmq1),
+ iqmp=self._backend._bn_to_int(self._rsa_cdata.iqmp),
+ public_numbers=rsa.RSAPublicNumbers(
+ e=self._backend._bn_to_int(self._rsa_cdata.e),
+ n=self._backend._bn_to_int(self._rsa_cdata.n),
+ )
+ )
+
+
+@utils.register_interface(RSAPublicKeyWithNumbers)
+class _RSAPublicKey(object):
+ def __init__(self, backend, rsa_cdata):
+ self._backend = backend
+ self._rsa_cdata = rsa_cdata
+
+ evp_pkey = self._backend._lib.EVP_PKEY_new()
+ assert evp_pkey != self._backend._ffi.NULL
+ evp_pkey = self._backend._ffi.gc(
+ evp_pkey, self._backend._lib.EVP_PKEY_free
+ )
+ res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata)
+ assert res == 1
+ self._evp_pkey = evp_pkey
+
+ self.key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
+
+ def verifier(self, signature, padding, algorithm):
+ return _RSAVerificationContext(
+ self._backend, self, signature, padding, algorithm
+ )
+
+ def encrypt(self, plaintext, padding):
+ return self._backend._enc_dec_rsa(self, plaintext, padding)
+
+ def public_numbers(self):
+ return rsa.RSAPublicNumbers(
+ e=self._backend._bn_to_int(self._rsa_cdata.e),
+ n=self._backend._bn_to_int(self._rsa_cdata.n),
+ )
diff --git a/cryptography/hazmat/bindings/commoncrypto/common_cryptor.py b/cryptography/hazmat/bindings/commoncrypto/common_cryptor.py
index 9bd03a7c..713bc566 100644
--- a/cryptography/hazmat/bindings/commoncrypto/common_cryptor.py
+++ b/cryptography/hazmat/bindings/commoncrypto/common_cryptor.py
@@ -101,7 +101,7 @@ MACROS = """
"""
CUSTOMIZATIONS = """
-// Not defined in the public header
+/* Not defined in the public header */
enum {
kCCModeGCM = 11
};
diff --git a/cryptography/hazmat/bindings/openssl/aes.py b/cryptography/hazmat/bindings/openssl/aes.py
index b0e00721..e4071523 100644
--- a/cryptography/hazmat/bindings/openssl/aes.py
+++ b/cryptography/hazmat/bindings/openssl/aes.py
@@ -29,12 +29,6 @@ typedef struct aes_key_st AES_KEY;
FUNCTIONS = """
int AES_set_encrypt_key(const unsigned char *, const int, AES_KEY *);
int AES_set_decrypt_key(const unsigned char *, const int, AES_KEY *);
-/* The ctr128_encrypt function is only useful in 0.9.8. You should use EVP for
- this in 1.0.0+. */
-void AES_ctr128_encrypt(const unsigned char *, unsigned char *,
- const unsigned long, const AES_KEY *,
- unsigned char[], unsigned char[], unsigned int *);
-
"""
MACROS = """
@@ -44,10 +38,18 @@ int AES_wrap_key(AES_KEY *, const unsigned char *, unsigned char *,
const unsigned char *, unsigned int);
int AES_unwrap_key(AES_KEY *, const unsigned char *, unsigned char *,
const unsigned char *, unsigned int);
+
+/* The ctr128_encrypt function is only useful in 0.9.8. You should use EVP for
+ this in 1.0.0+. It is defined in macros because the function signature
+ changed after 0.9.8 */
+void AES_ctr128_encrypt(const unsigned char *, unsigned char *,
+ const size_t, const AES_KEY *,
+ unsigned char[], unsigned char[], unsigned int *);
+
"""
CUSTOMIZATIONS = """
-// OpenSSL 0.9.8h+
+/* OpenSSL 0.9.8h+ */
#if OPENSSL_VERSION_NUMBER >= 0x0090808fL
static const long Cryptography_HAS_AES_WRAP = 1;
#else
diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py
index 464081b0..554c3c3e 100644
--- a/cryptography/hazmat/bindings/openssl/binding.py
+++ b/cryptography/hazmat/bindings/openssl/binding.py
@@ -74,6 +74,7 @@ class Binding(object):
"x509",
"x509name",
"x509v3",
+ "x509_vfy"
]
_locks = None
diff --git a/cryptography/hazmat/bindings/openssl/cms.py b/cryptography/hazmat/bindings/openssl/cms.py
index a3760f2c..cbf4b283 100644
--- a/cryptography/hazmat/bindings/openssl/cms.py
+++ b/cryptography/hazmat/bindings/openssl/cms.py
@@ -15,8 +15,8 @@ from __future__ import absolute_import, division, print_function
INCLUDES = """
#if !defined(OPENSSL_NO_CMS) && OPENSSL_VERSION_NUMBER >= 0x0090808fL
-// The next define should really be in the OpenSSL header, but it is missing.
-// Failing to include this on Windows causes compilation failures.
+/* The next define should really be in the OpenSSL header, but it is missing.
+ Failing to include this on Windows causes compilation failures. */
#if defined(OPENSSL_SYS_WINDOWS)
#include <windows.h>
#endif
diff --git a/cryptography/hazmat/bindings/openssl/dh.py b/cryptography/hazmat/bindings/openssl/dh.py
index a0f99479..e2e8976e 100644
--- a/cryptography/hazmat/bindings/openssl/dh.py
+++ b/cryptography/hazmat/bindings/openssl/dh.py
@@ -19,13 +19,13 @@ INCLUDES = """
TYPES = """
typedef struct dh_st {
- // prime number (shared)
+ /* Prime number (shared) */
BIGNUM *p;
- // generator of Z_p (shared)
+ /* Generator of Z_p (shared) */
BIGNUM *g;
- // private DH value x
+ /* Private DH value x */
BIGNUM *priv_key;
- // public DH value g^x
+ /* Public DH value g^x */
BIGNUM *pub_key;
...;
} DH;
diff --git a/cryptography/hazmat/bindings/openssl/dsa.py b/cryptography/hazmat/bindings/openssl/dsa.py
index 7db03326..c9aa8882 100644
--- a/cryptography/hazmat/bindings/openssl/dsa.py
+++ b/cryptography/hazmat/bindings/openssl/dsa.py
@@ -19,15 +19,15 @@ INCLUDES = """
TYPES = """
typedef struct dsa_st {
- // prime number (public)
+ /* Prime number (public) */
BIGNUM *p;
- // 160-bit subprime, q | p-1 (public)
+ /* Subprime (160-bit, q | p-1, public) */
BIGNUM *q;
- // generator of subgroup (public)
+ /* Generator of subgroup (public) */
BIGNUM *g;
- // private key x
+ /* Private key x */
BIGNUM *priv_key;
- // public key y = g^x
+ /* Public key y = g^x */
BIGNUM *pub_key;
...;
} DSA;
diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py
index f685e494..232060a2 100644
--- a/cryptography/hazmat/bindings/openssl/err.py
+++ b/cryptography/hazmat/bindings/openssl/err.py
@@ -21,6 +21,7 @@ TYPES = """
static const int Cryptography_HAS_REMOVE_THREAD_STATE;
static const int Cryptography_HAS_098H_ERROR_CODES;
static const int Cryptography_HAS_098C_CAMELLIA_CODES;
+static const int Cryptography_HAS_EC_CODES;
struct ERR_string_data_st {
unsigned long error;
@@ -28,8 +29,8 @@ struct ERR_string_data_st {
};
typedef struct ERR_string_data_st ERR_STRING_DATA;
-
static const int ERR_LIB_EVP;
+static const int ERR_LIB_EC;
static const int ERR_LIB_PEM;
static const int ERR_LIB_ASN1;
static const int ERR_LIB_RSA;
@@ -173,6 +174,10 @@ static const int EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM;
static const int EVP_R_WRONG_FINAL_BLOCK_LENGTH;
static const int EVP_R_WRONG_PUBLIC_KEY_TYPE;
+static const int EC_F_EC_GROUP_NEW_BY_CURVE_NAME;
+
+static const int EC_R_UNKNOWN_GROUP;
+
static const int PEM_F_D2I_PKCS8PRIVATEKEY_BIO;
static const int PEM_F_D2I_PKCS8PRIVATEKEY_FP;
static const int PEM_F_DO_PK8PKEY;
@@ -285,7 +290,7 @@ typedef uint32_t CRYPTO_THREADID;
void (*ERR_remove_thread_state)(const CRYPTO_THREADID *) = NULL;
#endif
-// OpenSSL 0.9.8h+
+/* OpenSSL 0.9.8h+ */
#if OPENSSL_VERSION_NUMBER >= 0x0090808fL
static const long Cryptography_HAS_098H_ERROR_CODES = 1;
#else
@@ -299,7 +304,7 @@ static const int ASN1_R_NO_MULTIPART_BODY_FAILURE = 0;
static const int ASN1_R_NO_MULTIPART_BOUNDARY = 0;
#endif
-// OpenSSL 0.9.8c+
+/* OpenSSL 0.9.8c+ */
#ifdef EVP_F_CAMELLIA_INIT_KEY
static const long Cryptography_HAS_098C_CAMELLIA_CODES = 1;
#else
@@ -308,6 +313,14 @@ static const int EVP_F_CAMELLIA_INIT_KEY = 0;
static const int EVP_R_CAMELLIA_KEY_SETUP_FAILED = 0;
#endif
+// OpenSSL without EC. e.g. RHEL
+#ifndef OPENSSL_NO_EC
+static const long Cryptography_HAS_EC_CODES = 1;
+#else
+static const long Cryptography_HAS_EC_CODES = 0;
+static const int EC_R_UNKNOWN_GROUP = 0;
+static const int EC_F_EC_GROUP_NEW_BY_CURVE_NAME = 0;
+#endif
"""
CONDITIONAL_NAMES = {
@@ -326,5 +339,9 @@ CONDITIONAL_NAMES = {
"Cryptography_HAS_098C_CAMELLIA_CODES": [
"EVP_F_CAMELLIA_INIT_KEY",
"EVP_R_CAMELLIA_KEY_SETUP_FAILED"
+ ],
+ "Cryptography_HAS_EC_CODES": [
+ "EC_R_UNKNOWN_GROUP",
+ "EC_F_EC_GROUP_NEW_BY_CURVE_NAME"
]
}
diff --git a/cryptography/hazmat/bindings/openssl/evp.py b/cryptography/hazmat/bindings/openssl/evp.py
index b3d958e6..11834509 100644
--- a/cryptography/hazmat/bindings/openssl/evp.py
+++ b/cryptography/hazmat/bindings/openssl/evp.py
@@ -139,7 +139,8 @@ int PKCS5_PBKDF2_HMAC(const char *, int, const unsigned char *, int, int,
int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *, const EVP_MD *);
-// not macros but must be in this section since they're not available in 0.9.8
+/* These aren't macros, but must be in this section because they're not
+ available in 0.9.8. */
EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *, ENGINE *);
EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int, ENGINE *);
EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *);
diff --git a/cryptography/hazmat/bindings/openssl/nid.py b/cryptography/hazmat/bindings/openssl/nid.py
index ea6fd4d6..7fa08660 100644
--- a/cryptography/hazmat/bindings/openssl/nid.py
+++ b/cryptography/hazmat/bindings/openssl/nid.py
@@ -193,7 +193,7 @@ MACROS = """
"""
CUSTOMIZATIONS = """
-// OpenSSL 0.9.8g+
+/* OpenSSL 0.9.8g+ */
#if OPENSSL_VERSION_NUMBER >= 0x0090807fL
static const long Cryptography_HAS_ECDSA_SHA2_NIDS = 1;
#else
diff --git a/cryptography/hazmat/bindings/openssl/rsa.py b/cryptography/hazmat/bindings/openssl/rsa.py
index c6356101..cb8e701e 100644
--- a/cryptography/hazmat/bindings/openssl/rsa.py
+++ b/cryptography/hazmat/bindings/openssl/rsa.py
@@ -80,7 +80,7 @@ CUSTOMIZATIONS = """
#if OPENSSL_VERSION_NUMBER >= 0x10000000
static const long Cryptography_HAS_PSS_PADDING = 1;
#else
-// see evp.py for the definition of Cryptography_HAS_PKEY_CTX
+/* see evp.py for the definition of Cryptography_HAS_PKEY_CTX */
static const long Cryptography_HAS_PSS_PADDING = 0;
int (*EVP_PKEY_CTX_set_rsa_padding)(EVP_PKEY_CTX *, int) = NULL;
int (*EVP_PKEY_CTX_set_rsa_pss_saltlen)(EVP_PKEY_CTX *, int) = NULL;
diff --git a/cryptography/hazmat/bindings/openssl/ssl.py b/cryptography/hazmat/bindings/openssl/ssl.py
index 165bc7a1..7d805e78 100644
--- a/cryptography/hazmat/bindings/openssl/ssl.py
+++ b/cryptography/hazmat/bindings/openssl/ssl.py
@@ -127,9 +127,6 @@ static const long SSL_MODE_ENABLE_PARTIAL_WRITE;
static const long SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER;
static const long SSL_MODE_AUTO_RETRY;
static const long SSL3_RANDOM_SIZE;
-typedef ... X509_STORE_CTX;
-static const long X509_V_OK;
-static const long X509_V_ERR_APPLICATION_VERIFICATION;
typedef ... SSL_METHOD;
typedef struct ssl_st {
int version;
@@ -228,16 +225,6 @@ int SSL_CTX_add_client_CA(SSL_CTX *, X509 *);
void SSL_CTX_set_client_CA_list(SSL_CTX *, Cryptography_STACK_OF_X509_NAME *);
-
-/* X509_STORE_CTX */
-int X509_STORE_CTX_get_error(X509_STORE_CTX *);
-void X509_STORE_CTX_set_error(X509_STORE_CTX *, int);
-int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *);
-X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *);
-int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *, int, void *);
-void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *, int);
-
-
/* SSL_SESSION */
void SSL_SESSION_free(SSL_SESSION *);
@@ -469,7 +456,7 @@ static const long Cryptography_HAS_SSL_OP_NO_TICKET = 0;
const long SSL_OP_NO_TICKET = 0;
#endif
-// OpenSSL 0.9.8f+
+/* OpenSSL 0.9.8f+ */
#if OPENSSL_VERSION_NUMBER >= 0x00908070L
static const long Cryptography_HAS_SSL_SET_SSL_CTX = 1;
#else
@@ -496,7 +483,7 @@ static const long Cryptography_HAS_NETBSD_D1_METH = 1;
static const long Cryptography_HAS_NETBSD_D1_METH = 1;
#endif
-// Workaround for #794 caused by cffi const** bug.
+/* Workaround for #794 caused by cffi const** bug. */
const SSL_METHOD* Cryptography_SSL_CTX_get_method(const SSL_CTX* ctx) {
return ctx->method;
}
@@ -532,7 +519,7 @@ void (*SSL_get0_next_proto_negotiated)(const SSL *,
static const long Cryptography_HAS_NEXTPROTONEG = 1;
#endif
-// ALPN was added in OpenSSL 1.0.2.
+/* ALPN was added in OpenSSL 1.0.2. */
#if OPENSSL_VERSION_NUMBER < 0x10002001L
int (*SSL_CTX_set_alpn_protos)(SSL_CTX *,
const unsigned char*,
diff --git a/cryptography/hazmat/bindings/openssl/x509.py b/cryptography/hazmat/bindings/openssl/x509.py
index 36a15e4a..b74c118b 100644
--- a/cryptography/hazmat/bindings/openssl/x509.py
+++ b/cryptography/hazmat/bindings/openssl/x509.py
@@ -24,11 +24,13 @@ INCLUDES = """
* Note that the result is an opaque type.
*/
typedef STACK_OF(X509) Cryptography_STACK_OF_X509;
+typedef STACK_OF(X509_CRL) Cryptography_STACK_OF_X509_CRL;
typedef STACK_OF(X509_REVOKED) Cryptography_STACK_OF_X509_REVOKED;
"""
TYPES = """
typedef ... Cryptography_STACK_OF_X509;
+typedef ... Cryptography_STACK_OF_X509_CRL;
typedef ... Cryptography_STACK_OF_X509_REVOKED;
typedef struct {
@@ -76,7 +78,6 @@ typedef struct {
...;
} X509;
-typedef ... X509_STORE;
typedef ... NETSCAPE_SPKI;
"""
@@ -166,12 +167,6 @@ EVP_PKEY *d2i_PUBKEY_bio(BIO *, EVP_PKEY **);
ASN1_INTEGER *X509_get_serialNumber(X509 *);
int X509_set_serialNumber(X509 *, ASN1_INTEGER *);
-/* X509_STORE */
-X509_STORE *X509_STORE_new(void);
-void X509_STORE_free(X509_STORE *);
-int X509_STORE_add_cert(X509_STORE *, X509 *);
-int X509_verify_cert(X509_STORE_CTX *);
-
const char *X509_verify_cert_error_string(long);
const char *X509_get_default_cert_area(void);
@@ -190,7 +185,6 @@ DSA *d2i_DSA_PUBKEY(DSA **, const unsigned char **, long);
DSA *d2i_DSAPublicKey(DSA **, const unsigned char **, long);
DSA *d2i_DSAPrivateKey(DSA **, const unsigned char **, long);
-
RSA *d2i_RSAPrivateKey_bio(BIO *, RSA **);
int i2d_RSAPrivateKey_bio(BIO *, RSA *);
RSA *d2i_RSAPublicKey_bio(BIO *, RSA **);
@@ -237,7 +231,7 @@ int i2d_DSAPrivateKey(DSA *, unsigned char **);
int X509_CRL_set_lastUpdate(X509_CRL *, ASN1_TIME *);
int X509_CRL_set_nextUpdate(X509_CRL *, ASN1_TIME *);
-/* these use STACK_OF(X509_EXTENSION) in 0.9.8e. Once we drop support for
+/* These use STACK_OF(X509_EXTENSION) in 0.9.8e. Once we drop support for
RHEL/CentOS 5 we should move these back to FUNCTIONS. */
int X509_REQ_add_extensions(X509_REQ *, X509_EXTENSIONS *);
X509_EXTENSIONS *X509_REQ_get_extensions(X509_REQ *);
@@ -251,7 +245,7 @@ int i2d_ECPrivateKey_bio(BIO *, EC_KEY *);
"""
CUSTOMIZATIONS = """
-// OpenSSL 0.9.8e does not have this definition
+/* OpenSSL 0.9.8e does not have this definition. */
#if OPENSSL_VERSION_NUMBER <= 0x0090805fL
typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS;
#endif
diff --git a/cryptography/hazmat/bindings/openssl/x509_vfy.py b/cryptography/hazmat/bindings/openssl/x509_vfy.py
new file mode 100644
index 00000000..a53716b0
--- /dev/null
+++ b/cryptography/hazmat/bindings/openssl/x509_vfy.py
@@ -0,0 +1,337 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import absolute_import, division, print_function
+
+INCLUDES = """
+#include <openssl/x509_vfy.h>
+
+/*
+ * This is part of a work-around for the difficulty cffi has in dealing with
+ * `STACK_OF(foo)` as the name of a type. We invent a new, simpler name that
+ * will be an alias for this type and use the alias throughout. This works
+ * together with another opaque typedef for the same name in the TYPES section.
+ * Note that the result is an opaque type.
+ */
+typedef STACK_OF(ASN1_OBJECT) Cryptography_STACK_OF_ASN1_OBJECT;
+"""
+
+TYPES = """
+static const long Cryptography_HAS_X509_VERIFY_PARAM_SET_HOSTFLAGS;
+static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES;
+static const long Cryptography_HAS_102_VERIFICATION_PARAMS;
+static const long Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST;
+static const long Cryptography_HAS_100_VERIFICATION_ERROR_CODES;
+static const long Cryptography_HAS_100_VERIFICATION_PARAMS;
+static const long Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE;
+
+typedef ... Cryptography_STACK_OF_ASN1_OBJECT;
+
+typedef ... X509_STORE;
+typedef ... X509_STORE_CTX;
+typedef ... X509_VERIFY_PARAM;
+
+/* While these are defined in the source as ints, they're tagged here
+ as longs, just in case they ever grow to large, such as what we saw
+ with OP_ALL. */
+
+/* Verification error codes */
+static const int X509_V_OK;
+static const int X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
+static const int X509_V_ERR_UNABLE_TO_GET_CRL;
+static const int X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE;
+static const int X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE;
+static const int X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
+static const int X509_V_ERR_CERT_SIGNATURE_FAILURE;
+static const int X509_V_ERR_CRL_SIGNATURE_FAILURE;
+static const int X509_V_ERR_CERT_NOT_YET_VALID;
+static const int X509_V_ERR_CERT_HAS_EXPIRED;
+static const int X509_V_ERR_CRL_NOT_YET_VALID;
+static const int X509_V_ERR_CRL_HAS_EXPIRED;
+static const int X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD;
+static const int X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD;
+static const int X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD;
+static const int X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD;
+static const int X509_V_ERR_OUT_OF_MEM;
+static const int X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
+static const int X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
+static const int X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
+static const int X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE;
+static const int X509_V_ERR_CERT_CHAIN_TOO_LONG;
+static const int X509_V_ERR_CERT_REVOKED;
+static const int X509_V_ERR_INVALID_CA;
+static const int X509_V_ERR_PATH_LENGTH_EXCEEDED;
+static const int X509_V_ERR_INVALID_PURPOSE;
+static const int X509_V_ERR_CERT_UNTRUSTED;
+static const int X509_V_ERR_CERT_REJECTED;
+static const int X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
+static const int X509_V_ERR_AKID_SKID_MISMATCH;
+static const int X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
+static const int X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
+static const int X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER;
+static const int X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION;
+static const int X509_V_ERR_KEYUSAGE_NO_CRL_SIGN;
+static const int X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION;
+static const int X509_V_ERR_INVALID_NON_CA;
+static const int X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED;
+static const int X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
+static const int X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED;
+static const int X509_V_ERR_INVALID_EXTENSION;
+static const int X509_V_ERR_INVALID_POLICY_EXTENSION;
+static const int X509_V_ERR_NO_EXPLICIT_POLICY;
+static const int X509_V_ERR_DIFFERENT_CRL_SCOPE;
+static const int X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE;
+static const int X509_V_ERR_UNNESTED_RESOURCE;
+static const int X509_V_ERR_PERMITTED_VIOLATION;
+static const int X509_V_ERR_EXCLUDED_VIOLATION;
+static const int X509_V_ERR_SUBTREE_MINMAX;
+static const int X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE;
+static const int X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX;
+static const int X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+static const int X509_V_ERR_CRL_PATH_VALIDATION_ERROR;
+static const int X509_V_ERR_SUITE_B_INVALID_VERSION;
+static const int X509_V_ERR_SUITE_B_INVALID_ALGORITHM;
+static const int X509_V_ERR_SUITE_B_INVALID_CURVE;
+static const int X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM;
+static const int X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED;
+static const int X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256;
+static const int X509_V_ERR_HOSTNAME_MISMATCH;
+static const int X509_V_ERR_EMAIL_MISMATCH;
+static const int X509_V_ERR_IP_ADDRESS_MISMATCH;
+static const int X509_V_ERR_APPLICATION_VERIFICATION;
+
+/* Verification parameters */
+static const long X509_V_FLAG_CB_ISSUER_CHECK;
+static const long X509_V_FLAG_USE_CHECK_TIME;
+static const long X509_V_FLAG_CRL_CHECK;
+static const long X509_V_FLAG_CRL_CHECK_ALL;
+static const long X509_V_FLAG_IGNORE_CRITICAL;
+static const long X509_V_FLAG_X509_STRICT;
+static const long X509_V_FLAG_ALLOW_PROXY_CERTS;
+static const long X509_V_FLAG_POLICY_CHECK;
+static const long X509_V_FLAG_EXPLICIT_POLICY;
+static const long X509_V_FLAG_INHIBIT_ANY;
+static const long X509_V_FLAG_INHIBIT_MAP;
+static const long X509_V_FLAG_NOTIFY_POLICY;
+static const long X509_V_FLAG_EXTENDED_CRL_SUPPORT;
+static const long X509_V_FLAG_USE_DELTAS;
+static const long X509_V_FLAG_CHECK_SS_SIGNATURE;
+static const long X509_V_FLAG_TRUSTED_FIRST;
+static const long X509_V_FLAG_SUITEB_128_LOS_ONLY;
+static const long X509_V_FLAG_SUITEB_192_LOS;
+static const long X509_V_FLAG_SUITEB_128_LOS;
+static const long X509_V_FLAG_PARTIAL_CHAIN;
+"""
+
+FUNCTIONS = """
+int X509_verify_cert(X509_STORE_CTX *);
+
+/* X509_STORE */
+X509_STORE *X509_STORE_new(void);
+void X509_STORE_free(X509_STORE *);
+int X509_STORE_add_cert(X509_STORE *, X509 *);
+
+/* X509_STORE_CTX */
+X509_STORE_CTX *X509_STORE_CTX_new(void);
+void X509_STORE_CTX_cleanup(X509_STORE_CTX *);
+void X509_STORE_CTX_free(X509_STORE_CTX *);
+int X509_STORE_CTX_init(X509_STORE_CTX *, X509_STORE *, X509 *,
+ Cryptography_STACK_OF_X509 *);
+void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *,
+ Cryptography_STACK_OF_X509 *);
+void X509_STORE_CTX_set_cert(X509_STORE_CTX *, X509 *);
+void X509_STORE_CTX_set_chain(X509_STORE_CTX *,Cryptography_STACK_OF_X509 *);
+X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *);
+void X509_STORE_CTX_set0_param(X509_STORE_CTX *, X509_VERIFY_PARAM *);
+int X509_STORE_CTX_set_default(X509_STORE_CTX *, const char *);
+void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *,
+ int (*)(int, X509_STORE_CTX *));
+Cryptography_STACK_OF_X509 *X509_STORE_CTX_get_chain(X509_STORE_CTX *);
+Cryptography_STACK_OF_X509 *X509_STORE_CTX_get1_chain(X509_STORE_CTX *);
+int X509_STORE_CTX_get_error(X509_STORE_CTX *);
+void X509_STORE_CTX_set_error(X509_STORE_CTX *, int);
+int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *);
+X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *);
+int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *, int, void *);
+void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *, int);
+
+/* X509_VERIFY_PARAM */
+X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void);
+int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *, unsigned long);
+int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *, unsigned long);
+unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *);
+int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *, int);
+int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *, int);
+void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *, time_t);
+int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *, ASN1_OBJECT *);
+int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *,
+ Cryptography_STACK_OF_ASN1_OBJECT *);
+void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *, int);
+int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *);
+"""
+
+MACROS = """
+/* X509_STORE_CTX */
+void X509_STORE_CTX_set0_crls(X509_STORE_CTX *,
+ Cryptography_STACK_OF_X509_CRL *);
+
+/* X509_VERIFY_PARAM */
+int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *, const unsigned char *,
+ size_t);
+void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *, unsigned int);
+int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *, const unsigned char *,
+ size_t);
+int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *, const unsigned char *,
+ size_t);
+int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *, const char *);
+"""
+
+CUSTOMIZATIONS = """
+/* OpenSSL 1.0.2+, but only some very new releases */
+#ifdef X509_VERIFY_PARAM_set_hostflags
+static const long Cryptography_HAS_X509_VERIFY_PARAM_SET_HOSTFLAGS = 1;
+#else
+static const long Cryptography_HAS_X509_VERIFY_PARAM_SET_HOSTFLAGS = 0;
+void (*X509_VERIFY_PARAM_set_hostflags)(X509_VERIFY_PARAM *,
+ unsigned int) = NULL;
+#endif
+
+/* OpenSSL 1.0.2+ verification error codes */
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES = 1;
+#else
+static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES = 0;
+static const long X509_V_ERR_SUITE_B_INVALID_VERSION = 0;
+static const long X509_V_ERR_SUITE_B_INVALID_ALGORITHM = 0;
+static const long X509_V_ERR_SUITE_B_INVALID_CURVE = 0;
+static const long X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM = 0;
+static const long X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED = 0;
+static const long X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 = 0;
+static const long X509_V_ERR_HOSTNAME_MISMATCH = 0;
+static const long X509_V_ERR_EMAIL_MISMATCH = 0;
+static const long X509_V_ERR_IP_ADDRESS_MISMATCH = 0;
+#endif
+
+/* OpenSSL 1.0.2+ verification parameters */
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+static const long Cryptography_HAS_102_VERIFICATION_PARAMS = 1;
+#else
+static const long Cryptography_HAS_102_VERIFICATION_PARAMS = 0;
+/* X509_V_FLAG_TRUSTED_FIRST is also new in 1.0.2+, but it is added separately
+ below because it shows up in some earlier 3rd party OpenSSL packages. */
+static const long X509_V_FLAG_SUITEB_128_LOS_ONLY = 0;
+static const long X509_V_FLAG_SUITEB_192_LOS = 0;
+static const long X509_V_FLAG_SUITEB_128_LOS = 0;
+static const long X509_V_FLAG_PARTIAL_CHAIN = 0;
+
+int (*X509_VERIFY_PARAM_set1_host)(X509_VERIFY_PARAM *, const unsigned char *,
+ size_t) = NULL;
+int (*X509_VERIFY_PARAM_set1_email)(X509_VERIFY_PARAM *, const unsigned char *,
+ size_t) = NULL;
+int (*X509_VERIFY_PARAM_set1_ip)(X509_VERIFY_PARAM *, const unsigned char *,
+ size_t) = NULL;
+int (*X509_VERIFY_PARAM_set1_ip_asc)(X509_VERIFY_PARAM *, const char *) = NULL;
+#endif
+
+/* OpenSSL 1.0.2+, *or* Fedora 20's flavor of OpenSSL 1.0.1e... */
+#ifdef X509_V_FLAG_TRUSTED_FIRST
+static const long Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST = 1;
+#else
+static const long Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST = 0;
+static const long X509_V_FLAG_TRUSTED_FIRST = 0;
+#endif
+
+/* OpenSSL 1.0.0+ verification error codes */
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+static const long Cryptography_HAS_100_VERIFICATION_ERROR_CODES = 1;
+#else
+static const long Cryptography_HAS_100_VERIFICATION_ERROR_CODES = 0;
+static const long X509_V_ERR_DIFFERENT_CRL_SCOPE = 0;
+static const long X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE = 0;
+static const long X509_V_ERR_PERMITTED_VIOLATION = 0;
+static const long X509_V_ERR_EXCLUDED_VIOLATION = 0;
+static const long X509_V_ERR_SUBTREE_MINMAX = 0;
+static const long X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE = 0;
+static const long X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX = 0;
+static const long X509_V_ERR_UNSUPPORTED_NAME_SYNTAX = 0;
+static const long X509_V_ERR_CRL_PATH_VALIDATION_ERROR = 0;
+#endif
+
+/* OpenSSL 1.0.0+ verification parameters */
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+static const long Cryptography_HAS_100_VERIFICATION_PARAMS = 1;
+#else
+static const long Cryptography_HAS_100_VERIFICATION_PARAMS = 0;
+static const long X509_V_FLAG_EXTENDED_CRL_SUPPORT = 0;
+static const long X509_V_FLAG_USE_DELTAS = 0;
+#endif
+
+/* OpenSSL 0.9.8recent+ */
+#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE
+static const long Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE = 1;
+#else
+static const long Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE = 0;
+static const long X509_V_FLAG_CHECK_SS_SIGNATURE = 0;
+#endif
+"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_X509_VERIFY_PARAM_SET_HOSTFLAGS": [
+ "X509_VERIFY_PARAM_set_hostflags",
+ ],
+ "Cryptography_HAS_102_VERIFICATION_ERROR_CODES": [
+ 'X509_V_ERR_SUITE_B_INVALID_VERSION',
+ 'X509_V_ERR_SUITE_B_INVALID_ALGORITHM',
+ 'X509_V_ERR_SUITE_B_INVALID_CURVE',
+ 'X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM',
+ 'X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED',
+ 'X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256',
+ 'X509_V_ERR_HOSTNAME_MISMATCH',
+ 'X509_V_ERR_EMAIL_MISMATCH',
+ 'X509_V_ERR_IP_ADDRESS_MISMATCH'
+ ],
+ "Cryptography_HAS_102_VERIFICATION_PARAMS": [
+ "X509_V_FLAG_SUITEB_128_LOS_ONLY",
+ "X509_V_FLAG_SUITEB_192_LOS",
+ "X509_V_FLAG_SUITEB_128_LOS",
+ "X509_V_FLAG_PARTIAL_CHAIN",
+
+ "X509_VERIFY_PARAM_set1_host",
+ "X509_VERIFY_PARAM_set1_email",
+ "X509_VERIFY_PARAM_set1_ip",
+ "X509_VERIFY_PARAM_set1_ip_asc",
+ ],
+ "Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST": [
+ "X509_V_FLAG_TRUSTED_FIRST",
+ ],
+ "Cryptography_HAS_100_VERIFICATION_ERROR_CODES": [
+ 'X509_V_ERR_DIFFERENT_CRL_SCOPE',
+ 'X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE',
+ 'X509_V_ERR_UNNESTED_RESOURCE',
+ 'X509_V_ERR_PERMITTED_VIOLATION',
+ 'X509_V_ERR_EXCLUDED_VIOLATION',
+ 'X509_V_ERR_SUBTREE_MINMAX',
+ 'X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE',
+ 'X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX',
+ 'X509_V_ERR_UNSUPPORTED_NAME_SYNTAX',
+ 'X509_V_ERR_CRL_PATH_VALIDATION_ERROR',
+ ],
+ "Cryptography_HAS_100_VERIFICATION_PARAMS": [
+ "Cryptography_HAS_100_VERIFICATION_PARAMS",
+ "X509_V_FLAG_EXTENDED_CRL_SUPPORT",
+ "X509_V_FLAG_USE_DELTAS",
+ ],
+ "Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE": [
+ "X509_V_FLAG_CHECK_SS_SIGNATURE",
+ ]
+}
diff --git a/cryptography/hazmat/primitives/asymmetric/dsa.py b/cryptography/hazmat/primitives/asymmetric/dsa.py
index a9ae9ecb..4d78679e 100644
--- a/cryptography/hazmat/primitives/asymmetric/dsa.py
+++ b/cryptography/hazmat/primitives/asymmetric/dsa.py
@@ -181,3 +181,74 @@ class DSAPublicKey(object):
def parameters(self):
return DSAParameters(self._modulus, self._subgroup_order,
self._generator)
+
+
+class DSAParameterNumbers(object):
+ def __init__(self, p, q, g):
+ if (
+ not isinstance(p, six.integer_types) or
+ not isinstance(q, six.integer_types) or
+ not isinstance(g, six.integer_types)
+ ):
+ raise TypeError(
+ "DSAParameterNumbers p, q, and g arguments must be integers."
+ )
+
+ self._p = p
+ self._q = q
+ self._g = g
+
+ @property
+ def p(self):
+ return self._p
+
+ @property
+ def q(self):
+ return self._q
+
+ @property
+ def g(self):
+ return self._g
+
+
+class DSAPublicNumbers(object):
+ def __init__(self, y, parameter_numbers):
+ if not isinstance(y, six.integer_types):
+ raise TypeError("DSAPublicNumbers y argument must be an integer.")
+
+ if not isinstance(parameter_numbers, DSAParameterNumbers):
+ raise TypeError(
+ "parameter_numbers must be a DSAParameterNumbers instance."
+ )
+
+ self._y = y
+ self._parameter_numbers = parameter_numbers
+
+ @property
+ def y(self):
+ return self._y
+
+ @property
+ def parameter_numbers(self):
+ return self._parameter_numbers
+
+
+class DSAPrivateNumbers(object):
+ def __init__(self, x, public_numbers):
+ if not isinstance(x, six.integer_types):
+ raise TypeError("DSAPrivateNumbers x argument must be an integer.")
+
+ if not isinstance(public_numbers, DSAPublicNumbers):
+ raise TypeError(
+ "public_numbers must be a DSAPublicNumbers instance."
+ )
+ self._public_numbers = public_numbers
+ self._x = x
+
+ @property
+ def x(self):
+ return self._x
+
+ @property
+ def public_numbers(self):
+ return self._public_numbers
diff --git a/cryptography/hazmat/primitives/asymmetric/rsa.py b/cryptography/hazmat/primitives/asymmetric/rsa.py
index 18ca0db2..15ec52ac 100644
--- a/cryptography/hazmat/primitives/asymmetric/rsa.py
+++ b/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -13,12 +13,13 @@
from __future__ import absolute_import, division, print_function
+import warnings
+
import six
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.backends.interfaces import RSABackend
-from cryptography.hazmat.primitives import interfaces
def generate_private_key(public_exponent, key_size, backend):
@@ -93,9 +94,14 @@ def _check_public_key_components(e, n):
raise ValueError("e must be odd.")
-@utils.register_interface(interfaces.RSAPublicKey)
class RSAPublicKey(object):
def __init__(self, public_exponent, modulus):
+ warnings.warn(
+ "The RSAPublicKey class is deprecated and will be removed in a "
+ "future version.",
+ utils.DeprecatedIn05,
+ stacklevel=2
+ )
if (
not isinstance(public_exponent, six.integer_types) or
not isinstance(modulus, six.integer_types)
@@ -183,10 +189,15 @@ def rsa_crt_dmq1(private_exponent, q):
return private_exponent % (q - 1)
-@utils.register_interface(interfaces.RSAPrivateKey)
class RSAPrivateKey(object):
def __init__(self, p, q, private_exponent, dmp1, dmq1, iqmp,
public_exponent, modulus):
+ warnings.warn(
+ "The RSAPrivateKey class is deprecated and will be removed in a "
+ "future version.",
+ utils.DeprecatedIn05,
+ stacklevel=2
+ )
if (
not isinstance(p, six.integer_types) or
not isinstance(q, six.integer_types) or
@@ -213,6 +224,11 @@ class RSAPrivateKey(object):
@classmethod
def generate(cls, public_exponent, key_size, backend):
+ warnings.warn(
+ "generate is deprecated and will be removed in a future version.",
+ utils.DeprecatedIn05,
+ stacklevel=2
+ )
if not isinstance(backend, RSABackend):
raise UnsupportedAlgorithm(
"Backend object does not implement RSABackend.",
@@ -361,6 +377,9 @@ class RSAPrivateNumbers(object):
def public_numbers(self):
return self._public_numbers
+ def private_key(self, backend):
+ return backend.load_rsa_private_numbers(self)
+
class RSAPublicNumbers(object):
def __init__(self, e, n):
@@ -380,3 +399,6 @@ class RSAPublicNumbers(object):
@property
def n(self):
return self._n
+
+ def public_key(self, backend):
+ return backend.load_rsa_public_numbers(self)
diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py
index c6dc1251..ef8640c2 100644
--- a/cryptography/hazmat/primitives/interfaces.py
+++ b/cryptography/hazmat/primitives/interfaces.py
@@ -186,11 +186,17 @@ class HashContext(object):
@six.add_metaclass(abc.ABCMeta)
class RSAPrivateKey(object):
@abc.abstractmethod
- def signer(self, padding, algorithm, backend):
+ def signer(self, padding, algorithm):
"""
Returns an AsymmetricSignatureContext used for signing data.
"""
+ @abc.abstractmethod
+ def decrypt(self, ciphertext, padding):
+ """
+ Decrypts the provided ciphertext.
+ """
+
@abc.abstractproperty
def key_size(self):
"""
@@ -206,6 +212,7 @@ class RSAPrivateKey(object):
@six.add_metaclass(abc.ABCMeta)
class RSAPrivateKeyWithNumbers(RSAPrivateKey):
+ @abc.abstractmethod
def private_numbers(self):
"""
Returns an RSAPrivateNumbers.
@@ -215,11 +222,17 @@ class RSAPrivateKeyWithNumbers(RSAPrivateKey):
@six.add_metaclass(abc.ABCMeta)
class RSAPublicKey(object):
@abc.abstractmethod
- def verifier(self, signature, padding, algorithm, backend):
+ def verifier(self, signature, padding, algorithm):
"""
Returns an AsymmetricVerificationContext used for verifying signatures.
"""
+ @abc.abstractmethod
+ def encrypt(self, plaintext, padding):
+ """
+ Encrypts the given plaintext.
+ """
+
@abc.abstractproperty
def key_size(self):
"""
@@ -229,6 +242,7 @@ class RSAPublicKey(object):
@six.add_metaclass(abc.ABCMeta)
class RSAPublicKeyWithNumbers(RSAPublicKey):
+ @abc.abstractmethod
def public_numbers(self):
"""
Returns an RSAPublicNumbers
@@ -241,6 +255,15 @@ class DSAParameters(object):
@six.add_metaclass(abc.ABCMeta)
+class DSAParametersWithNumbers(DSAParameters):
+ @abc.abstractmethod
+ def parameter_numbers(self):
+ """
+ Returns a DSAParameterNumbers.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
class DSAPrivateKey(object):
@abc.abstractproperty
def key_size(self):
@@ -262,6 +285,15 @@ class DSAPrivateKey(object):
@six.add_metaclass(abc.ABCMeta)
+class DSAPrivateKeyWithNumbers(DSAPrivateKey):
+ @abc.abstractmethod
+ def private_numbers(self):
+ """
+ Returns a DSAPrivateNumbers.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
class DSAPublicKey(object):
@abc.abstractproperty
def key_size(self):
@@ -277,6 +309,15 @@ class DSAPublicKey(object):
@six.add_metaclass(abc.ABCMeta)
+class DSAPublicKeyWithNumbers(DSAPublicKey):
+ @abc.abstractmethod
+ def public_numbers(self):
+ """
+ Returns a DSAPublicNumbers.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
class AsymmetricSignatureContext(object):
@abc.abstractmethod
def update(self, data):
diff --git a/cryptography/hazmat/primitives/serialization.py b/cryptography/hazmat/primitives/serialization.py
index 056d4a06..ed73c4c4 100644
--- a/cryptography/hazmat/primitives/serialization.py
+++ b/cryptography/hazmat/primitives/serialization.py
@@ -24,11 +24,3 @@ def load_pem_pkcs8_private_key(data, password, backend):
return backend.load_pkcs8_pem_private_key(
data, password
)
-
-
-def load_rsa_private_numbers(numbers, backend):
- return backend.load_rsa_private_numbers(numbers)
-
-
-def load_rsa_public_numbers(numbers, backend):
- return backend.load_rsa_public_numbers(numbers)