diff options
Diffstat (limited to 'cryptography/hazmat')
63 files changed, 1674 insertions, 260 deletions
diff --git a/cryptography/hazmat/__init__.py b/cryptography/hazmat/__init__.py index 55c925c6..2f420574 100644 --- a/cryptography/hazmat/__init__.py +++ b/cryptography/hazmat/__init__.py @@ -10,3 +10,5 @@ # implied. # See the License for the specific language governing permissions and # limitations under the License. + +from __future__ import absolute_import, division, print_function diff --git a/cryptography/hazmat/backends/__init__.py b/cryptography/hazmat/backends/__init__.py index 41d260a8..ae78822c 100644 --- a/cryptography/hazmat/backends/__init__.py +++ b/cryptography/hazmat/backends/__init__.py @@ -11,21 +11,44 @@ # See the License for the specific language governing permissions and # limitations under the License. -from cryptography.hazmat.backends import openssl +from __future__ import absolute_import, division, print_function + from cryptography.hazmat.backends.multibackend import MultiBackend from cryptography.hazmat.bindings.commoncrypto.binding import ( Binding as CommonCryptoBinding ) +from cryptography.hazmat.bindings.openssl.binding import ( + Binding as OpenSSLBinding +) + + +_available_backends_list = None + -_ALL_BACKENDS = [openssl.backend] +def _available_backends(): + global _available_backends_list -if CommonCryptoBinding.is_available(): - from cryptography.hazmat.backends import commoncrypto - _ALL_BACKENDS.append(commoncrypto.backend) + if _available_backends_list is None: + _available_backends_list = [] + if CommonCryptoBinding.is_available(): + from cryptography.hazmat.backends import commoncrypto + _available_backends_list.append(commoncrypto.backend) -_default_backend = MultiBackend(_ALL_BACKENDS) + if OpenSSLBinding.is_available(): + from cryptography.hazmat.backends import openssl + _available_backends_list.append(openssl.backend) + + return _available_backends_list + + +_default_backend = None def default_backend(): + global _default_backend + + if _default_backend is None: + _default_backend = MultiBackend(_available_backends()) + return _default_backend diff --git a/cryptography/hazmat/backends/commoncrypto/__init__.py b/cryptography/hazmat/backends/commoncrypto/__init__.py index 64a1c01c..f080394f 100644 --- a/cryptography/hazmat/backends/commoncrypto/__init__.py +++ b/cryptography/hazmat/backends/commoncrypto/__init__.py @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import absolute_import, division, print_function + from cryptography.hazmat.backends.commoncrypto.backend import backend diff --git a/cryptography/hazmat/backends/commoncrypto/backend.py b/cryptography/hazmat/backends/commoncrypto/backend.py index 4a451d34..4faca73e 100644 --- a/cryptography/hazmat/backends/commoncrypto/backend.py +++ b/cryptography/hazmat/backends/commoncrypto/backend.py @@ -17,18 +17,18 @@ from collections import namedtuple from cryptography import utils from cryptography.exceptions import ( - UnsupportedAlgorithm, InvalidTag, InternalError + InternalError, InvalidTag, UnsupportedAlgorithm, _Reasons ) from cryptography.hazmat.backends.interfaces import ( - HashBackend, HMACBackend, CipherBackend, PBKDF2HMACBackend + CipherBackend, HMACBackend, HashBackend, PBKDF2HMACBackend ) from cryptography.hazmat.bindings.commoncrypto.binding import Binding -from cryptography.hazmat.primitives import interfaces, constant_time +from cryptography.hazmat.primitives import constant_time, interfaces from cryptography.hazmat.primitives.ciphers.algorithms import ( - AES, Blowfish, TripleDES, ARC4, CAST5 + AES, ARC4, Blowfish, CAST5, TripleDES ) from cryptography.hazmat.primitives.ciphers.modes import ( - CBC, CTR, ECB, OFB, CFB, GCM + CBC, CFB, CTR, ECB, GCM, OFB ) @@ -276,7 +276,8 @@ class _CipherContext(object): raise UnsupportedAlgorithm( "cipher {0} in {1} mode is not supported " "by this backend".format( - cipher.name, mode.name if mode else mode) + cipher.name, mode.name if mode else mode), + _Reasons.UNSUPPORTED_CIPHER ) ctx = self._backend._ffi.new("CCCryptorRef *") @@ -349,7 +350,8 @@ class _GCMCipherContext(object): raise UnsupportedAlgorithm( "cipher {0} in {1} mode is not supported " "by this backend".format( - cipher.name, mode.name if mode else mode) + cipher.name, mode.name if mode else mode), + _Reasons.UNSUPPORTED_CIPHER ) ctx = self._backend._ffi.new("CCCryptorRef *") @@ -422,7 +424,8 @@ class _HashContext(object): except KeyError: raise UnsupportedAlgorithm( "{0} is not a supported hash on this backend".format( - algorithm.name) + algorithm.name), + _Reasons.UNSUPPORTED_HASH ) ctx = self._backend._ffi.new(methods.ctx) res = methods.hash_init(ctx) @@ -465,7 +468,8 @@ class _HMACContext(object): except KeyError: raise UnsupportedAlgorithm( "{0} is not a supported HMAC hash on this backend".format( - algorithm.name) + algorithm.name), + _Reasons.UNSUPPORTED_HASH ) self._backend._lib.CCHmacInit(ctx, alg, key, len(key)) diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index da41532d..27b609ed 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -106,6 +106,12 @@ class RSABackend(six.with_metaclass(abc.ABCMeta)): interface. """ + @abc.abstractmethod + def mgf1_hash_supported(self, algorithm): + """ + Return True if the hash algorithm is supported for MGF1 in PSS. + """ + class OpenSSLSerializationBackend(six.with_metaclass(abc.ABCMeta)): @abc.abstractmethod diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py index de1fff7c..aa649dd3 100644 --- a/cryptography/hazmat/backends/multibackend.py +++ b/cryptography/hazmat/backends/multibackend.py @@ -14,9 +14,9 @@ from __future__ import absolute_import, division, print_function from cryptography import utils -from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.backends.interfaces import ( - CipherBackend, HashBackend, HMACBackend, PBKDF2HMACBackend, RSABackend + CipherBackend, HMACBackend, HashBackend, PBKDF2HMACBackend, RSABackend ) @@ -48,7 +48,11 @@ class MultiBackend(object): return b.create_symmetric_encryption_ctx(algorithm, mode) except UnsupportedAlgorithm: pass - raise UnsupportedAlgorithm + raise UnsupportedAlgorithm( + "cipher {0} in {1} mode is not supported by this backend".format( + algorithm.name, mode.name if mode else mode), + _Reasons.UNSUPPORTED_CIPHER + ) def create_symmetric_decryption_ctx(self, algorithm, mode): for b in self._filtered_backends(CipherBackend): @@ -56,7 +60,11 @@ class MultiBackend(object): return b.create_symmetric_decryption_ctx(algorithm, mode) except UnsupportedAlgorithm: pass - raise UnsupportedAlgorithm + raise UnsupportedAlgorithm( + "cipher {0} in {1} mode is not supported by this backend".format( + algorithm.name, mode.name if mode else mode), + _Reasons.UNSUPPORTED_CIPHER + ) def hash_supported(self, algorithm): return any( @@ -70,7 +78,11 @@ class MultiBackend(object): return b.create_hash_ctx(algorithm) except UnsupportedAlgorithm: pass - raise UnsupportedAlgorithm + raise UnsupportedAlgorithm( + "{0} is not a supported hash on this backend".format( + algorithm.name), + _Reasons.UNSUPPORTED_HASH + ) def hmac_supported(self, algorithm): return any( @@ -84,7 +96,11 @@ class MultiBackend(object): return b.create_hmac_ctx(key, algorithm) except UnsupportedAlgorithm: pass - raise UnsupportedAlgorithm + raise UnsupportedAlgorithm( + "{0} is not a supported hash on this backend".format( + algorithm.name), + _Reasons.UNSUPPORTED_HASH + ) def pbkdf2_hmac_supported(self, algorithm): return any( @@ -101,21 +117,28 @@ class MultiBackend(object): ) except UnsupportedAlgorithm: pass - raise UnsupportedAlgorithm + raise UnsupportedAlgorithm( + "{0} is not a supported hash on this backend".format( + algorithm.name), + _Reasons.UNSUPPORTED_HASH + ) def generate_rsa_private_key(self, public_exponent, key_size): for b in self._filtered_backends(RSABackend): return b.generate_rsa_private_key(public_exponent, key_size) - raise UnsupportedAlgorithm + raise UnsupportedAlgorithm("RSA is not supported by the backend", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) def create_rsa_signature_ctx(self, private_key, padding, algorithm): for b in self._filtered_backends(RSABackend): return b.create_rsa_signature_ctx(private_key, padding, algorithm) - raise UnsupportedAlgorithm + raise UnsupportedAlgorithm("RSA is not supported by the backend", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) def create_rsa_verification_ctx(self, public_key, signature, padding, algorithm): for b in self._filtered_backends(RSABackend): return b.create_rsa_verification_ctx(public_key, signature, padding, algorithm) - raise UnsupportedAlgorithm + raise UnsupportedAlgorithm("RSA is not supported by the backend", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) diff --git a/cryptography/hazmat/backends/openssl/__init__.py b/cryptography/hazmat/backends/openssl/__init__.py index a8dfad06..25885e18 100644 --- a/cryptography/hazmat/backends/openssl/__init__.py +++ b/cryptography/hazmat/backends/openssl/__init__.py @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import absolute_import, division, print_function + from cryptography.hazmat.backends.openssl.backend import backend diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index f05ee3d6..3293741c 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -15,23 +15,29 @@ from __future__ import absolute_import, division, print_function import collections import itertools +import math + +import six from cryptography import utils from cryptography.exceptions import ( - UnsupportedAlgorithm, InvalidTag, InternalError, AlreadyFinalized, - UnsupportedPadding, InvalidSignature + AlreadyFinalized, InternalError, InvalidSignature, InvalidTag, + UnsupportedAlgorithm, _Reasons ) from cryptography.hazmat.backends.interfaces import ( - CipherBackend, HashBackend, HMACBackend, PBKDF2HMACBackend, RSABackend + CipherBackend, HMACBackend, HashBackend, PBKDF2HMACBackend, RSABackend ) from cryptography.hazmat.bindings.openssl.binding import Binding -from cryptography.hazmat.primitives import interfaces, hashes +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.ciphers.algorithms import ( - AES, Blowfish, Camellia, TripleDES, ARC4, CAST5 + AES, ARC4, Blowfish, CAST5, Camellia, IDEA, TripleDES ) from cryptography.hazmat.primitives.ciphers.modes import ( - CBC, CTR, ECB, OFB, CFB, GCM, + CBC, CFB, CTR, ECB, GCM, OFB ) @@ -159,11 +165,14 @@ class Backend(object): mode_cls, GetCipherByName("bf-{mode.name}") ) - for mode_cls in [CBC, CFB, OFB, ECB]: + for cipher_cls, mode_cls in itertools.product( + [CAST5, IDEA], + [CBC, OFB, CFB, ECB], + ): self.register_cipher_adapter( - CAST5, + cipher_cls, mode_cls, - GetCipherByName("cast5-{mode.name}") + GetCipherByName("{cipher.name}-{mode.name}") ) self.register_cipher_adapter( ARC4, @@ -213,7 +222,8 @@ class Backend(object): if not isinstance(algorithm, hashes.SHA1): raise UnsupportedAlgorithm( "This version of OpenSSL only supports PBKDF2HMAC with " - "SHA1" + "SHA1", + _Reasons.UNSUPPORTED_HASH ) res = self._lib.PKCS5_PBKDF2_HMAC_SHA1( key_material, @@ -256,11 +266,24 @@ class Backend(object): ) def _bn_to_int(self, bn): - hex_cdata = self._lib.BN_bn2hex(bn) - assert hex_cdata != self._ffi.NULL - hex_str = self._ffi.string(hex_cdata) - self._lib.OPENSSL_free(hex_cdata) - return int(hex_str, 16) + if six.PY3: + # Python 3 has constant time from_bytes, so use that. + + bn_num_bytes = (self._lib.BN_num_bits(bn) + 7) // 8 + bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes) + bin_len = self._lib.BN_bn2bin(bn, bin_ptr) + assert bin_len > 0 + assert bin_ptr != self._ffi.NULL + return int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big") + + else: + # Under Python 2 the best we can do is hex() + + hex_cdata = self._lib.BN_bn2hex(bn) + assert hex_cdata != self._ffi.NULL + hex_str = self._ffi.string(hex_cdata) + self._lib.OPENSSL_free(hex_cdata) + return int(hex_str, 16) def _int_to_bn(self, num): """ @@ -269,12 +292,24 @@ class Backend(object): ownership of the object). Be sure to register it for GC if it will be discarded after use. """ - hex_num = hex(num).rstrip("L").lstrip("0x").encode("ascii") or b"0" - bn_ptr = self._ffi.new("BIGNUM **") - res = self._lib.BN_hex2bn(bn_ptr, hex_num) - assert res != 0 - assert bn_ptr[0] != self._ffi.NULL - return bn_ptr[0] + + if six.PY3: + # Python 3 has constant time to_bytes, so use that. + + binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big") + bn_ptr = self._lib.BN_bin2bn(binary, len(binary), self._ffi.NULL) + assert bn_ptr != self._ffi.NULL + return bn_ptr + + else: + # Under Python 2 the best we can do is hex() + + hex_num = hex(num).rstrip("L").lstrip("0x").encode("ascii") or b"0" + bn_ptr = self._ffi.new("BIGNUM **") + res = self._lib.BN_hex2bn(bn_ptr, hex_num) + assert res != 0 + assert bn_ptr[0] != self._ffi.NULL + return bn_ptr[0] def generate_rsa_private_key(self, public_exponent, key_size): if public_exponent < 3: @@ -298,21 +333,54 @@ class Backend(object): ) assert res == 1 + return self._rsa_cdata_to_private_key(ctx) + + def _new_evp_pkey(self): + evp_pkey = self._lib.EVP_PKEY_new() + assert evp_pkey != self._ffi.NULL + return self._ffi.gc(evp_pkey, backend._lib.EVP_PKEY_free) + + def _rsa_private_key_to_evp_pkey(self, private_key): + evp_pkey = self._new_evp_pkey() + rsa_cdata = self._rsa_cdata_from_private_key(private_key) + + res = self._lib.RSA_blinding_on(rsa_cdata, self._ffi.NULL) + assert res == 1 + + res = self._lib.EVP_PKEY_assign_RSA(evp_pkey, rsa_cdata) + assert res == 1 + + return evp_pkey + + def _rsa_public_key_to_evp_pkey(self, public_key): + evp_pkey = self._new_evp_pkey() + rsa_cdata = self._rsa_cdata_from_public_key(public_key) + + res = self._lib.RSA_blinding_on(rsa_cdata, self._ffi.NULL) + assert res == 1 + + res = self._lib.EVP_PKEY_assign_RSA(evp_pkey, rsa_cdata) + assert res == 1 + + return evp_pkey + + def _rsa_cdata_to_private_key(self, cdata): return rsa.RSAPrivateKey( - p=self._bn_to_int(ctx.p), - q=self._bn_to_int(ctx.q), - dmp1=self._bn_to_int(ctx.dmp1), - dmq1=self._bn_to_int(ctx.dmq1), - iqmp=self._bn_to_int(ctx.iqmp), - private_exponent=self._bn_to_int(ctx.d), - public_exponent=self._bn_to_int(ctx.e), - modulus=self._bn_to_int(ctx.n), + p=self._bn_to_int(cdata.p), + q=self._bn_to_int(cdata.q), + dmp1=self._bn_to_int(cdata.dmp1), + dmq1=self._bn_to_int(cdata.dmq1), + iqmp=self._bn_to_int(cdata.iqmp), + private_exponent=self._bn_to_int(cdata.d), + public_exponent=self._bn_to_int(cdata.e), + modulus=self._bn_to_int(cdata.n), ) def _rsa_cdata_from_private_key(self, private_key): + # Does not GC the RSA cdata. You *must* make sure it's freed + # correctly yourself! ctx = self._lib.RSA_new() assert ctx != self._ffi.NULL - ctx = self._ffi.gc(ctx, self._lib.RSA_free) ctx.p = self._int_to_bn(private_key.p) ctx.q = self._int_to_bn(private_key.q) ctx.d = self._int_to_bn(private_key.d) @@ -324,9 +392,11 @@ class Backend(object): return ctx def _rsa_cdata_from_public_key(self, public_key): + # Does not GC the RSA cdata. You *must* make sure it's freed + # correctly yourself! + ctx = self._lib.RSA_new() assert ctx != self._ffi.NULL - ctx = self._ffi.gc(ctx, self._lib.RSA_free) ctx.e = self._int_to_bn(public_key.e) ctx.n = self._int_to_bn(public_key.n) return ctx @@ -339,6 +409,12 @@ class Backend(object): return _RSAVerificationContext(self, public_key, signature, padding, algorithm) + def mgf1_hash_supported(self, algorithm): + if self._lib.Cryptography_HAS_MGF1_MD: + return self.hash_supported(algorithm) + else: + return isinstance(algorithm, hashes.SHA1) + class GetCipherByName(object): def __init__(self, fmt): @@ -380,7 +456,8 @@ class _CipherContext(object): raise UnsupportedAlgorithm( "cipher {0} in {1} mode is not supported " "by this backend".format( - cipher.name, mode.name if mode else mode) + cipher.name, mode.name if mode else mode), + _Reasons.UNSUPPORTED_CIPHER ) evp_cipher = adapter(self._backend, cipher, mode) @@ -388,7 +465,8 @@ class _CipherContext(object): raise UnsupportedAlgorithm( "cipher {0} in {1} mode is not supported " "by this backend".format( - cipher.name, mode.name if mode else mode) + cipher.name, mode.name if mode else mode), + _Reasons.UNSUPPORTED_CIPHER ) if isinstance(mode, interfaces.ModeWithInitializationVector): @@ -438,6 +516,15 @@ class _CipherContext(object): self._ctx = ctx def update(self, data): + # OpenSSL 0.9.8e has an assertion in its EVP code that causes it + # to SIGABRT if you call update with an empty byte string. This can be + # removed when we drop support for 0.9.8e (CentOS/RHEL 5). This branch + # should be taken only when length is zero and mode is not GCM because + # AES GCM can return improper tag values if you don't call update + # with empty plaintext when authenticating AAD for ...reasons. + if len(data) == 0 and not isinstance(self._mode, GCM): + return b"" + buf = self._backend._ffi.new("unsigned char[]", len(data) + self._block_size - 1) outlen = self._backend._ffi.new("int *") @@ -519,7 +606,8 @@ class _HashContext(object): if evp_md == self._backend._ffi.NULL: raise UnsupportedAlgorithm( "{0} is not a supported hash on this backend".format( - algorithm.name) + algorithm.name), + _Reasons.UNSUPPORTED_HASH ) res = self._backend._lib.EVP_DigestInit_ex(ctx, evp_md, self._backend._ffi.NULL) @@ -569,7 +657,8 @@ class _HMACContext(object): if evp_md == self._backend._ffi.NULL: raise UnsupportedAlgorithm( "{0} is not a supported hash on this backend".format( - algorithm.name) + algorithm.name), + _Reasons.UNSUPPORTED_HASH ) res = self._backend._lib.Cryptography_HMAC_Init_ex( ctx, key, len(key), evp_md, self._backend._ffi.NULL @@ -612,24 +701,63 @@ class _HMACContext(object): return self._backend._ffi.buffer(buf)[:outlen[0]] +def _get_rsa_pss_salt_length(mgf, key_size, digest_size): + if mgf._salt_length is MGF1.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 mgf._salt_length + + @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") - if padding.name == "EMSA-PKCS1-v1_5": + 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) + key_size_bytes = int(math.ceil(private_key.key_size / 8.0)) + if key_size_bytes - 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 UnsupportedPadding( - "{0} is not supported by this backend".format(padding.name) + raise UnsupportedAlgorithm( + "{0} is not supported by this backend".format(padding.name), + _Reasons.UNSUPPORTED_PADDING ) self._padding = padding @@ -645,24 +773,19 @@ class _RSASignatureContext(object): def finalize(self): if self._hash_ctx is None: raise AlreadyFinalized("Context has already been finalized") - evp_pkey = self._backend._lib.EVP_PKEY_new() - assert evp_pkey != self._backend._ffi.NULL - evp_pkey = backend._ffi.gc(evp_pkey, backend._lib.EVP_PKEY_free) - rsa_cdata = backend._rsa_cdata_from_private_key(self._private_key) - res = self._backend._lib.RSA_blinding_on( - rsa_cdata, self._backend._ffi.NULL) - assert res == 1 - res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata) - assert res == 1 + + evp_pkey = self._backend._rsa_private_key_to_evp_pkey( + self._private_key) + evp_md = self._backend._lib.EVP_get_digestbyname( self._algorithm.name.encode("ascii")) assert evp_md != self._backend._ffi.NULL pkey_size = self._backend._lib.EVP_PKEY_size(evp_pkey) assert pkey_size > 0 - return self._finalize_method(evp_pkey, pkey_size, rsa_cdata, evp_md) + return self._finalize_method(evp_pkey, pkey_size, evp_md) - def _finalize_pkey_ctx(self, evp_pkey, pkey_size, rsa_cdata, evp_md): + def _finalize_pkey_ctx(self, evp_pkey, pkey_size, evp_md): pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new( evp_pkey, self._backend._ffi.NULL ) @@ -676,6 +799,26 @@ class _RSASignatureContext(object): 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._mgf, + 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() self._hash_ctx = None buflen = self._backend._ffi.new("size_t *") @@ -690,10 +833,17 @@ class _RSASignatureContext(object): 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)) - assert res == 1 + 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.") + return self._backend._ffi.buffer(buf)[:] - def _finalize_pkcs1(self, evp_pkey, pkey_size, rsa_cdata, evp_md): + def _finalize_pkcs1(self, evp_pkey, pkey_size, evp_md): sig_buf = self._backend._ffi.new("char[]", pkey_size) sig_len = self._backend._ffi.new("unsigned int *") res = self._backend._lib.EVP_SignFinal( @@ -707,6 +857,44 @@ class _RSASignatureContext(object): assert res == 1 return self._backend._ffi.buffer(sig_buf)[:sig_len[0]] + def _finalize_pss(self, evp_pkey, pkey_size, evp_md): + data_to_sign = self._hash_ctx.finalize() + self._hash_ctx = None + padded = self._backend._ffi.new("unsigned char[]", pkey_size) + rsa_cdata = self._backend._lib.EVP_PKEY_get1_RSA(evp_pkey) + assert rsa_cdata != self._backend._ffi.NULL + rsa_cdata = self._backend._ffi.gc(rsa_cdata, + self._backend._lib.RSA_free) + res = self._backend._lib.RSA_padding_add_PKCS1_PSS( + rsa_cdata, + padded, + data_to_sign, + evp_md, + _get_rsa_pss_salt_length( + self._padding._mgf, + 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[]", pkey_size) + sig_len = self._backend._lib.RSA_private_encrypt( + pkey_size, + padded, + sig_buf, + 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): @@ -714,18 +902,50 @@ class _RSAVerificationContext(object): self._backend = backend self._public_key = public_key self._signature = signature + if not isinstance(padding, interfaces.AsymmetricPadding): raise TypeError( "Expected provider of interfaces.AsymmetricPadding") - if padding.name == "EMSA-PKCS1-v1_5": + 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) + key_size_bytes = int(math.ceil(public_key.key_size / 8.0)) + if key_size_bytes - 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 UnsupportedPadding + raise UnsupportedAlgorithm( + "{0} is not supported by this backend".format(padding.name), + _Reasons.UNSUPPORTED_PADDING + ) self._padding = padding self._algorithm = algorithm @@ -741,22 +961,16 @@ class _RSAVerificationContext(object): if self._hash_ctx is None: raise AlreadyFinalized("Context has already been finalized") - evp_pkey = self._backend._lib.EVP_PKEY_new() - assert evp_pkey != self._backend._ffi.NULL - evp_pkey = backend._ffi.gc(evp_pkey, backend._lib.EVP_PKEY_free) - rsa_cdata = backend._rsa_cdata_from_public_key(self._public_key) - res = self._backend._lib.RSA_blinding_on( - rsa_cdata, self._backend._ffi.NULL) - assert res == 1 - res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata) - assert res == 1 + evp_pkey = self._backend._rsa_public_key_to_evp_pkey( + self._public_key) + evp_md = self._backend._lib.EVP_get_digestbyname( self._algorithm.name.encode("ascii")) assert evp_md != self._backend._ffi.NULL - self._verify_method(rsa_cdata, evp_pkey, evp_md) + self._verify_method(evp_pkey, evp_md) - def _verify_pkey_ctx(self, rsa_cdata, evp_pkey, evp_md): + def _verify_pkey_ctx(self, evp_pkey, evp_md): pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new( evp_pkey, self._backend._ffi.NULL ) @@ -770,6 +984,26 @@ class _RSAVerificationContext(object): 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._mgf, + 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() self._hash_ctx = None res = self._backend._lib.EVP_PKEY_verify( @@ -784,10 +1018,11 @@ class _RSAVerificationContext(object): # occurs. assert res >= 0 if res == 0: - assert self._backend._consume_errors() + errors = self._backend._consume_errors() + assert errors raise InvalidSignature - def _verify_pkcs1(self, rsa_cdata, evp_pkey, evp_md): + def _verify_pkcs1(self, evp_pkey, evp_md): res = self._backend._lib.EVP_VerifyFinal( self._hash_ctx._ctx, self._signature, @@ -801,7 +1036,46 @@ class _RSAVerificationContext(object): # occurs. assert res >= 0 if res == 0: - assert self._backend._consume_errors() + errors = self._backend._consume_errors() + assert errors + raise InvalidSignature + + def _verify_pss(self, evp_pkey, evp_md): + pkey_size = self._backend._lib.EVP_PKEY_size(evp_pkey) + assert pkey_size > 0 + rsa_cdata = self._backend._lib.EVP_PKEY_get1_RSA(evp_pkey) + assert rsa_cdata != self._backend._ffi.NULL + rsa_cdata = self._backend._ffi.gc(rsa_cdata, + self._backend._lib.RSA_free) + buf = self._backend._ffi.new("unsigned char[]", pkey_size) + res = self._backend._lib.RSA_public_decrypt( + len(self._signature), + self._signature, + buf, + rsa_cdata, + self._backend._lib.RSA_NO_PADDING + ) + if res != pkey_size: + errors = self._backend._consume_errors() + assert errors + raise InvalidSignature + + data_to_verify = self._hash_ctx.finalize() + self._hash_ctx = None + res = self._backend._lib.RSA_verify_PKCS1_PSS( + rsa_cdata, + data_to_verify, + evp_md, + buf, + _get_rsa_pss_salt_length( + self._padding._mgf, + self._public_key.key_size, + len(data_to_verify) + ) + ) + if res != 1: + errors = self._backend._consume_errors() + assert errors raise InvalidSignature diff --git a/cryptography/hazmat/bindings/__init__.py b/cryptography/hazmat/bindings/__init__.py index 55c925c6..2f420574 100644 --- a/cryptography/hazmat/bindings/__init__.py +++ b/cryptography/hazmat/bindings/__init__.py @@ -10,3 +10,5 @@ # implied. # See the License for the specific language governing permissions and # limitations under the License. + +from __future__ import absolute_import, division, print_function diff --git a/cryptography/hazmat/bindings/commoncrypto/__init__.py b/cryptography/hazmat/bindings/commoncrypto/__init__.py index 55c925c6..2f420574 100644 --- a/cryptography/hazmat/bindings/commoncrypto/__init__.py +++ b/cryptography/hazmat/bindings/commoncrypto/__init__.py @@ -10,3 +10,5 @@ # implied. # See the License for the specific language governing permissions and # limitations under the License. + +from __future__ import absolute_import, division, print_function diff --git a/cryptography/hazmat/bindings/commoncrypto/binding.py b/cryptography/hazmat/bindings/commoncrypto/binding.py index 45c0eaad..3673ea36 100644 --- a/cryptography/hazmat/bindings/commoncrypto/binding.py +++ b/cryptography/hazmat/bindings/commoncrypto/binding.py @@ -13,6 +13,7 @@ from __future__ import absolute_import, division, print_function +import platform import sys from cryptography.hazmat.bindings.utils import build_ffi @@ -46,4 +47,5 @@ class Binding(object): @classmethod def is_available(cls): - return sys.platform == "darwin" + return sys.platform == "darwin" and list(map( + int, platform.mac_ver()[0].split("."))) >= [10, 8, 0] diff --git a/cryptography/hazmat/bindings/commoncrypto/common_cryptor.py b/cryptography/hazmat/bindings/commoncrypto/common_cryptor.py index 8f03bc3f..9bd03a7c 100644 --- a/cryptography/hazmat/bindings/commoncrypto/common_cryptor.py +++ b/cryptography/hazmat/bindings/commoncrypto/common_cryptor.py @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import absolute_import, division, print_function + INCLUDES = """ #include <CommonCrypto/CommonCryptor.h> """ diff --git a/cryptography/hazmat/bindings/commoncrypto/common_digest.py b/cryptography/hazmat/bindings/commoncrypto/common_digest.py index ec0fcc92..c59200cb 100644 --- a/cryptography/hazmat/bindings/commoncrypto/common_digest.py +++ b/cryptography/hazmat/bindings/commoncrypto/common_digest.py @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import absolute_import, division, print_function + INCLUDES = """ #include <CommonCrypto/CommonDigest.h> """ diff --git a/cryptography/hazmat/bindings/commoncrypto/common_hmac.py b/cryptography/hazmat/bindings/commoncrypto/common_hmac.py index a4bf9009..4f54b62b 100644 --- a/cryptography/hazmat/bindings/commoncrypto/common_hmac.py +++ b/cryptography/hazmat/bindings/commoncrypto/common_hmac.py @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import absolute_import, division, print_function + INCLUDES = """ #include <CommonCrypto/CommonHMAC.h> """ diff --git a/cryptography/hazmat/bindings/commoncrypto/common_key_derivation.py b/cryptography/hazmat/bindings/commoncrypto/common_key_derivation.py index 85def1e9..e8cc03ef 100644 --- a/cryptography/hazmat/bindings/commoncrypto/common_key_derivation.py +++ b/cryptography/hazmat/bindings/commoncrypto/common_key_derivation.py @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import absolute_import, division, print_function + INCLUDES = """ #include <CommonCrypto/CommonKeyDerivation.h> """ diff --git a/cryptography/hazmat/bindings/openssl/__init__.py b/cryptography/hazmat/bindings/openssl/__init__.py index 55c925c6..2f420574 100644 --- a/cryptography/hazmat/bindings/openssl/__init__.py +++ b/cryptography/hazmat/bindings/openssl/__init__.py @@ -10,3 +10,5 @@ # implied. # See the License for the specific language governing permissions and # limitations under the License. + +from __future__ import absolute_import, division, print_function diff --git a/cryptography/hazmat/bindings/openssl/aes.py b/cryptography/hazmat/bindings/openssl/aes.py index 6cbcd577..17c154cf 100644 --- a/cryptography/hazmat/bindings/openssl/aes.py +++ b/cryptography/hazmat/bindings/openssl/aes.py @@ -11,11 +11,15 @@ # 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/aes.h> """ TYPES = """ +static const int Cryptography_HAS_AES_WRAP; + struct aes_key_st { ...; }; @@ -25,16 +29,34 @@ 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 *); +""" + +MACROS = """ +/* these can be moved back to FUNCTIONS once we drop support for 0.9.8h. + This should be when we drop RHEL/CentOS 5, which is on 0.9.8e. */ 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); """ -MACROS = """ -""" - CUSTOMIZATIONS = """ +// OpenSSL 0.9.8h+ +#if OPENSSL_VERSION_NUMBER >= 0x0090808fL +static const long Cryptography_HAS_AES_WRAP = 1; +#else +static const long Cryptography_HAS_AES_WRAP = 0; +int (*AES_wrap_key)(AES_KEY *, const unsigned char *, unsigned char *, + const unsigned char *, unsigned int) = NULL; +int (*AES_unwrap_key)(AES_KEY *, const unsigned char *, unsigned char *, + const unsigned char *, unsigned int) = NULL; +#endif + """ -CONDITIONAL_NAMES = {} +CONDITIONAL_NAMES = { + "Cryptography_HAS_AES_WRAP": [ + "AES_wrap_key", + "AES_unwrap_key", + ], +} diff --git a/cryptography/hazmat/bindings/openssl/asn1.py b/cryptography/hazmat/bindings/openssl/asn1.py index aeaf316e..dfdf1bf5 100644 --- a/cryptography/hazmat/bindings/openssl/asn1.py +++ b/cryptography/hazmat/bindings/openssl/asn1.py @@ -11,6 +11,8 @@ # 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/asn1.h> """ @@ -97,6 +99,7 @@ int i2a_ASN1_INTEGER(BIO *, ASN1_INTEGER *); /* ASN1 TIME */ ASN1_TIME *ASN1_TIME_new(void); +void ASN1_TIME_free(ASN1_TIME *); ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *, ASN1_GENERALIZEDTIME **); @@ -106,7 +109,6 @@ int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *, time_t); /* ASN1 GENERALIZEDTIME */ int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *, const char *); void ASN1_GENERALIZEDTIME_free(ASN1_GENERALIZEDTIME *); -int ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *); /* ASN1 ENUMERATED */ ASN1_ENUMERATED *ASN1_ENUMERATED_new(void); @@ -136,6 +138,9 @@ long ASN1_INTEGER_get(ASN1_INTEGER *); BIGNUM *ASN1_INTEGER_to_BN(ASN1_INTEGER *, BIGNUM *); ASN1_INTEGER *BN_to_ASN1_INTEGER(BIGNUM *, ASN1_INTEGER *); + +/* These isn't a macro the arg is const on openssl 1.0.2+ */ +int ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *); """ CUSTOMIZATIONS = """ diff --git a/cryptography/hazmat/bindings/openssl/bignum.py b/cryptography/hazmat/bindings/openssl/bignum.py index e843099e..a40397db 100644 --- a/cryptography/hazmat/bindings/openssl/bignum.py +++ b/cryptography/hazmat/bindings/openssl/bignum.py @@ -11,6 +11,8 @@ # 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/bn.h> """ diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py index 0469a1ea..927406c6 100644 --- a/cryptography/hazmat/bindings/openssl/binding.py +++ b/cryptography/hazmat/bindings/openssl/binding.py @@ -53,6 +53,7 @@ class Binding(object): "dh", "dsa", "ec", + "ecdsa", "engine", "err", "evp", diff --git a/cryptography/hazmat/bindings/openssl/bio.py b/cryptography/hazmat/bindings/openssl/bio.py index 279ad223..0c521b4d 100644 --- a/cryptography/hazmat/bindings/openssl/bio.py +++ b/cryptography/hazmat/bindings/openssl/bio.py @@ -11,6 +11,8 @@ # 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/bio.h> """ @@ -105,7 +107,6 @@ BIO *BIO_push(BIO *, BIO *); BIO *BIO_pop(BIO *); BIO *BIO_next(BIO *); BIO *BIO_find_type(BIO *, int); -int BIO_method_type(const BIO *); BIO_METHOD *BIO_s_mem(void); BIO *BIO_new_mem_buf(void *, int); BIO_METHOD *BIO_s_file(void); @@ -168,6 +169,10 @@ long BIO_set_read_buffer_size(BIO *, long); long BIO_set_write_buffer_size(BIO *, long); long BIO_set_buffer_size(BIO *, long); long BIO_set_buffer_read_data(BIO *, void *, long); + +/* The following was a macro in 0.9.8e. Once we drop support for RHEL/CentOS 5 + we should move this back to FUNCTIONS. */ +int BIO_method_type(const BIO *); """ CUSTOMIZATIONS = """ diff --git a/cryptography/hazmat/bindings/openssl/conf.py b/cryptography/hazmat/bindings/openssl/conf.py index 6d818cf1..dda35e86 100644 --- a/cryptography/hazmat/bindings/openssl/conf.py +++ b/cryptography/hazmat/bindings/openssl/conf.py @@ -11,6 +11,8 @@ # 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/conf.h> """ diff --git a/cryptography/hazmat/bindings/openssl/crypto.py b/cryptography/hazmat/bindings/openssl/crypto.py index 81d13b73..99e1a61d 100644 --- a/cryptography/hazmat/bindings/openssl/crypto.py +++ b/cryptography/hazmat/bindings/openssl/crypto.py @@ -11,6 +11,8 @@ # 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/crypto.h> """ diff --git a/cryptography/hazmat/bindings/openssl/dh.py b/cryptography/hazmat/bindings/openssl/dh.py index ecc62e98..1791a670 100644 --- a/cryptography/hazmat/bindings/openssl/dh.py +++ b/cryptography/hazmat/bindings/openssl/dh.py @@ -11,6 +11,8 @@ # 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/dh.h> """ diff --git a/cryptography/hazmat/bindings/openssl/dsa.py b/cryptography/hazmat/bindings/openssl/dsa.py index 609a33bf..40d3b8ee 100644 --- a/cryptography/hazmat/bindings/openssl/dsa.py +++ b/cryptography/hazmat/bindings/openssl/dsa.py @@ -11,6 +11,8 @@ # 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/dsa.h> """ @@ -35,10 +37,13 @@ FUNCTIONS = """ DSA *DSA_generate_parameters(int, unsigned char *, int, int *, unsigned long *, void (*)(int, int, void *), void *); int DSA_generate_key(DSA *); +DSA *DSA_new(void); void DSA_free(DSA *); """ MACROS = """ +int DSA_generate_parameters_ex(DSA *, int, unsigned char *, int, + int *, unsigned long *, BN_GENCB *); """ CUSTOMIZATIONS = """ diff --git a/cryptography/hazmat/bindings/openssl/ec.py b/cryptography/hazmat/bindings/openssl/ec.py index 39403ff2..2617fe2a 100644 --- a/cryptography/hazmat/bindings/openssl/ec.py +++ b/cryptography/hazmat/bindings/openssl/ec.py @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import absolute_import, division, print_function + INCLUDES = """ #ifndef OPENSSL_NO_EC #include <openssl/ec.h> @@ -23,14 +25,10 @@ TYPES = """ static const int Cryptography_HAS_EC; typedef ... EC_KEY; - -static const int NID_X9_62_prime192v1; -static const int NID_X9_62_prime192v2; -static const int NID_X9_62_prime192v3; -static const int NID_X9_62_prime239v1; -static const int NID_X9_62_prime239v2; -static const int NID_X9_62_prime239v3; -static const int NID_X9_62_prime256v1; +typedef struct { + int nid; + const char *comment; +} EC_builtin_curve; """ FUNCTIONS = """ @@ -39,14 +37,22 @@ FUNCTIONS = """ MACROS = """ EC_KEY *EC_KEY_new_by_curve_name(int); void EC_KEY_free(EC_KEY *); + +size_t EC_get_builtin_curves(EC_builtin_curve *, size_t); + """ CUSTOMIZATIONS = """ #ifdef OPENSSL_NO_EC static const long Cryptography_HAS_EC = 0; typedef void EC_KEY; +typedef struct { + int nid; + const char *comment; +} EC_builtin_curve; EC_KEY* (*EC_KEY_new_by_curve_name)(int) = NULL; void (*EC_KEY_free)(EC_KEY *) = NULL; +size_t (*EC_get_builtin_curves)(EC_builtin_curve *, size_t) = NULL; #else static const long Cryptography_HAS_EC = 1; #endif @@ -56,5 +62,6 @@ CONDITIONAL_NAMES = { "Cryptography_HAS_EC": [ "EC_KEY_new_by_curve_name", "EC_KEY_free", + "EC_get_builtin_curves", ], } diff --git a/cryptography/hazmat/bindings/openssl/ecdsa.py b/cryptography/hazmat/bindings/openssl/ecdsa.py new file mode 100644 index 00000000..bfa67206 --- /dev/null +++ b/cryptography/hazmat/bindings/openssl/ecdsa.py @@ -0,0 +1,130 @@ +# 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 = """ +#ifndef OPENSSL_NO_ECDSA +#include <openssl/ecdsa.h> +#endif +""" + +TYPES = """ +static const int Cryptography_HAS_ECDSA; + +typedef struct { + BIGNUM *r; + BIGNUM *s; +} ECDSA_SIG; + +typedef ... CRYPTO_EX_new; +typedef ... CRYPTO_EX_dup; +typedef ... CRYPTO_EX_free; +""" + +FUNCTIONS = """ +""" + +MACROS = """ +ECDSA_SIG *ECDSA_SIG_new(); +void ECDSA_SIG_free(ECDSA_SIG *); +int i2d_ECDSA_SIG(const ECDSA_SIG *, unsigned char **); +ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **s, const unsigned char **, long); +ECDSA_SIG *ECDSA_do_sign(const unsigned char *, int, EC_KEY *); +ECDSA_SIG *ECDSA_do_sign_ex(const unsigned char *, int, const BIGNUM *, + const BIGNUM *, EC_KEY *); +int ECDSA_do_verify(const unsigned char *, int, const ECDSA_SIG *, EC_KEY*); +int ECDSA_sign_setup(EC_KEY *, BN_CTX *, BIGNUM **, BIGNUM **); +int ECDSA_sign(int, const unsigned char *, int, unsigned char *, + unsigned int *, EC_KEY *); +int ECDSA_sign_ex(int, const unsigned char *, int dgstlen, unsigned char *, + unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *); +int ECDSA_verify(int, const unsigned char *, int, const unsigned char *, int, + EC_KEY *); +int ECDSA_size(const EC_KEY *); + +const ECDSA_METHOD* ECDSA_OpenSSL(); +void ECDSA_set_default_method(const ECDSA_METHOD *); +const ECDSA_METHOD* ECDSA_get_default_method(); +int ECDSA_get_ex_new_index(long, void *, CRYPTO_EX_new *, + CRYPTO_EX_dup *, CRYPTO_EX_free *); +int ECDSA_set_method(EC_KEY *, const ECDSA_METHOD *); +int ECDSA_set_ex_data(EC_KEY *, int, void *); +void *ECDSA_get_ex_data(EC_KEY *, int); +""" + +CUSTOMIZATIONS = """ +#ifdef OPENSSL_NO_ECDSA +static const long Cryptography_HAS_ECDSA = 0; + +typedef struct { + BIGNUM *r; + BIGNUM *s; +} ECDSA_SIG; + +ECDSA_SIG* (*ECDSA_SIG_new)() = NULL; +void (*ECDSA_SIG_free)(ECDSA_SIG *) = NULL; +int (*i2d_ECDSA_SIG)(const ECDSA_SIG *, unsigned char **) = NULL; +ECDSA_SIG* (*d2i_ECDSA_SIG)(ECDSA_SIG **s, const unsigned char **, + long) = NULL; +ECDSA_SIG* (*ECDSA_do_sign)(const unsigned char *, int, EC_KEY *eckey) = NULL; +ECDSA_SIG* (*ECDSA_do_sign_ex)(const unsigned char *, int, const BIGNUM *, + const BIGNUM *, EC_KEY *) = NULL; +int (*ECDSA_do_verify)(const unsigned char *, int, const ECDSA_SIG *, + EC_KEY*) = NULL; +int (*ECDSA_sign_setup)(EC_KEY *, BN_CTX *, BIGNUM **, BIGNUM **) = NULL; +int (*ECDSA_sign)(int, const unsigned char *, int, unsigned char *, + unsigned int *, EC_KEY *) = NULL; +int (*ECDSA_sign_ex)(int, const unsigned char *, int dgstlen, unsigned char *, + unsigned int *, const BIGNUM *, const BIGNUM *, + EC_KEY *) = NULL; +int (*ECDSA_verify)(int, const unsigned char *, int, const unsigned char *, + int, EC_KEY *) = NULL; +int (*ECDSA_size)(const EC_KEY *) = NULL; + +const ECDSA_METHOD* (*ECDSA_OpenSSL)() = NULL; +void (*ECDSA_set_default_method)(const ECDSA_METHOD *) = NULL; +const ECDSA_METHOD* (*ECDSA_get_default_method)() = NULL; +int (*ECDSA_set_method)(EC_KEY *, const ECDSA_METHOD *) = NULL; +int (*ECDSA_get_ex_new_index)(long, void *, CRYPTO_EX_new *, + CRYPTO_EX_dup *, CRYPTO_EX_free *) = NULL; +int (*ECDSA_set_ex_data)(EC_KEY *, int, void *) = NULL; +void* (*ECDSA_get_ex_data)(EC_KEY *, int) = NULL; +#else +static const long Cryptography_HAS_ECDSA = 1; +#endif +""" + +CONDITIONAL_NAMES = { + "Cryptography_HAS_ECDSA": [ + "ECDSA_SIG_new", + "ECDSA_SIG_free", + "i2d_ECDSA_SIG", + "d2i_ECDSA_SIG", + "ECDSA_do_sign", + "ECDSA_do_sign_ex", + "ECDSA_do_verify", + "ECDSA_sign_setup", + "ECDSA_sign", + "ECDSA_sign_ex", + "ECDSA_verify", + "ECDSA_size", + "ECDSA_OpenSSL", + "ECDSA_set_default_method", + "ECDSA_get_default_method", + "ECDSA_set_method", + "ECDSA_get_ex_new_index", + "ECDSA_set_ex_data", + "ECDSA_get_ex_data", + ], +} diff --git a/cryptography/hazmat/bindings/openssl/engine.py b/cryptography/hazmat/bindings/openssl/engine.py index 77118e81..364232e0 100644 --- a/cryptography/hazmat/bindings/openssl/engine.py +++ b/cryptography/hazmat/bindings/openssl/engine.py @@ -11,6 +11,8 @@ # 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/engine.h> """ diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py index ddb60ef7..551d8217 100644 --- a/cryptography/hazmat/bindings/openssl/err.py +++ b/cryptography/hazmat/bindings/openssl/err.py @@ -11,12 +11,16 @@ # 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/err.h> """ 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; struct ERR_string_data_st { unsigned long error; @@ -28,6 +32,7 @@ typedef struct ERR_string_data_st ERR_STRING_DATA; static const int ERR_LIB_EVP; static const int ERR_LIB_PEM; static const int ERR_LIB_ASN1; +static const int ERR_LIB_RSA; static const int ASN1_F_ASN1_ENUMERATED_TO_BN; static const int ASN1_F_ASN1_EX_C2I; @@ -50,8 +55,6 @@ static const int ASN1_F_ASN1_TYPE_GET_OCTETSTRING; static const int ASN1_F_ASN1_UNPACK_STRING; static const int ASN1_F_ASN1_UTCTIME_SET; static const int ASN1_F_ASN1_VERIFY; -static const int ASN1_F_B64_READ_ASN1; -static const int ASN1_F_B64_WRITE_ASN1; static const int ASN1_F_BITSTR_CB; static const int ASN1_F_BN_TO_ASN1_ENUMERATED; static const int ASN1_F_BN_TO_ASN1_INTEGER; @@ -71,8 +74,6 @@ static const int ASN1_F_LONG_C2I; static const int ASN1_F_OID_MODULE_INIT; static const int ASN1_F_PARSE_TAGGING; static const int ASN1_F_PKCS5_PBE_SET; -static const int ASN1_F_SMIME_READ_ASN1; -static const int ASN1_F_SMIME_TEXT; static const int ASN1_F_X509_CINF_NEW; static const int ASN1_R_BOOLEAN_IS_WRONG_LENGTH; static const int ASN1_R_BUFFER_TOO_SMALL; @@ -86,10 +87,7 @@ static const int ASN1_R_ERROR_GETTING_TIME; static const int ASN1_R_ERROR_LOADING_SECTION; static const int ASN1_R_MSTRING_WRONG_TAG; static const int ASN1_R_NESTED_ASN1_STRING; -static const int ASN1_R_NO_CONTENT_TYPE; static const int ASN1_R_NO_MATCHING_CHOICE_TYPE; -static const int ASN1_R_NO_MULTIPART_BODY_FAILURE; -static const int ASN1_R_NO_MULTIPART_BOUNDARY; static const int ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM; static const int ASN1_R_UNKNOWN_OBJECT_TYPE; static const int ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE; @@ -103,7 +101,6 @@ static const int ASN1_R_WRONG_TAG; static const int ASN1_R_WRONG_TYPE; static const int EVP_F_AES_INIT_KEY; -static const int EVP_F_CAMELLIA_INIT_KEY; static const int EVP_F_D2I_PKEY; static const int EVP_F_DSA_PKEY2PKCS8; static const int EVP_F_DSAPKEY2PKCS8; @@ -144,14 +141,12 @@ static const int EVP_R_BAD_BLOCK_LENGTH; static const int EVP_R_BAD_KEY_LENGTH; static const int EVP_R_BN_DECODE_ERROR; static const int EVP_R_BN_PUBKEY_ERROR; -static const int EVP_R_CAMELLIA_KEY_SETUP_FAILED; static const int EVP_R_CIPHER_PARAMETER_ERROR; static const int EVP_R_CTRL_NOT_IMPLEMENTED; static const int EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED; static const int EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH; static const int EVP_R_DECODE_ERROR; static const int EVP_R_DIFFERENT_KEY_TYPES; -static const int EVP_R_DISABLED_FOR_FIPS; static const int EVP_R_ENCODE_ERROR; static const int EVP_R_INITIALIZATION_ERROR; static const int EVP_R_INPUT_NOT_INITIALIZED; @@ -218,6 +213,8 @@ static const int PEM_R_READ_KEY; static const int PEM_R_SHORT_HEADER; static const int PEM_R_UNSUPPORTED_CIPHER; static const int PEM_R_UNSUPPORTED_ENCRYPTION; + +static const int RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE; """ FUNCTIONS = """ @@ -258,6 +255,19 @@ int ERR_FATAL_ERROR(unsigned long); * supporting 0.9.8 */ void ERR_remove_thread_state(const CRYPTO_THREADID *); + +/* These were added in OpenSSL 0.9.8h. When we drop support for RHEL/CentOS 5 + we should be able to move these back to TYPES. */ +static const int ASN1_F_B64_READ_ASN1; +static const int ASN1_F_B64_WRITE_ASN1; +static const int ASN1_F_SMIME_READ_ASN1; +static const int ASN1_F_SMIME_TEXT; +static const int ASN1_R_NO_CONTENT_TYPE; +static const int ASN1_R_NO_MULTIPART_BODY_FAILURE; +static const int ASN1_R_NO_MULTIPART_BOUNDARY; +/* These were added in OpenSSL 0.9.8c. */ +static const int EVP_F_CAMELLIA_INIT_KEY; +static const int EVP_R_CAMELLIA_KEY_SETUP_FAILED; """ CUSTOMIZATIONS = """ @@ -266,12 +276,49 @@ static const long Cryptography_HAS_REMOVE_THREAD_STATE = 1; #else static const long Cryptography_HAS_REMOVE_THREAD_STATE = 0; typedef uint32_t CRYPTO_THREADID; -void (*ERR_remove_thread_state)(const CRYPTO_THREADID *); +void (*ERR_remove_thread_state)(const CRYPTO_THREADID *) = NULL; +#endif + +// OpenSSL 0.9.8h+ +#if OPENSSL_VERSION_NUMBER >= 0x0090808fL +static const long Cryptography_HAS_098H_ERROR_CODES = 1; +#else +static const long Cryptography_HAS_098H_ERROR_CODES = 0; +static const int ASN1_F_B64_READ_ASN1 = 0; +static const int ASN1_F_B64_WRITE_ASN1 = 0; +static const int ASN1_F_SMIME_READ_ASN1 = 0; +static const int ASN1_F_SMIME_TEXT = 0; +static const int ASN1_R_NO_CONTENT_TYPE = 0; +static const int ASN1_R_NO_MULTIPART_BODY_FAILURE = 0; +static const int ASN1_R_NO_MULTIPART_BOUNDARY = 0; #endif + +// OpenSSL 0.9.8c+ +#ifdef EVP_F_CAMELLIA_INIT_KEY +static const long Cryptography_HAS_098C_CAMELLIA_CODES = 1; +#else +static const long Cryptography_HAS_098C_CAMELLIA_CODES = 0; +static const int EVP_F_CAMELLIA_INIT_KEY = 0; +static const int EVP_R_CAMELLIA_KEY_SETUP_FAILED = 0; +#endif + """ CONDITIONAL_NAMES = { "Cryptography_HAS_REMOVE_THREAD_STATE": [ "ERR_remove_thread_state" ], + "Cryptography_HAS_098H_ERROR_CODES": [ + "ASN1_F_B64_READ_ASN1", + "ASN1_F_B64_WRITE_ASN1", + "ASN1_F_SMIME_READ_ASN1", + "ASN1_F_SMIME_TEXT", + "ASN1_R_NO_CONTENT_TYPE", + "ASN1_R_NO_MULTIPART_BODY_FAILURE", + "ASN1_R_NO_MULTIPART_BOUNDARY", + ], + "Cryptography_HAS_098C_CAMELLIA_CODES": [ + "EVP_F_CAMELLIA_INIT_KEY", + "EVP_R_CAMELLIA_KEY_SETUP_FAILED" + ] } diff --git a/cryptography/hazmat/bindings/openssl/evp.py b/cryptography/hazmat/bindings/openssl/evp.py index a5e19c3a..88cf5c34 100644 --- a/cryptography/hazmat/bindings/openssl/evp.py +++ b/cryptography/hazmat/bindings/openssl/evp.py @@ -11,6 +11,8 @@ # 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/evp.h> """ @@ -64,8 +66,6 @@ int EVP_CipherUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, const unsigned char *, int); int EVP_CipherFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *); -const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *); -int EVP_CIPHER_block_size(const EVP_CIPHER *); void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *); EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void); void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *); @@ -79,8 +79,6 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *, unsigned char *, unsigned int *); int EVP_MD_CTX_cleanup(EVP_MD_CTX *); void EVP_MD_CTX_destroy(EVP_MD_CTX *); const EVP_MD *EVP_get_digestbyname(const char *); -const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *); -int EVP_MD_size(const EVP_MD *); EVP_PKEY *EVP_PKEY_new(void); void EVP_PKEY_free(EVP_PKEY *); @@ -143,6 +141,23 @@ int EVP_PKEY_sign(EVP_PKEY_CTX *, unsigned char *, size_t *, int EVP_PKEY_verify_init(EVP_PKEY_CTX *); int EVP_PKEY_verify(EVP_PKEY_CTX *, const unsigned char *, size_t, const unsigned char *, size_t); +int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *); +int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *); + +/* The following were macros in 0.9.8e. Once we drop support for RHEL/CentOS 5 + we should move these back to FUNCTIONS. */ +const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *); +int EVP_CIPHER_block_size(const EVP_CIPHER *); +const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *); +int EVP_MD_size(const EVP_MD *); + +/* Must be in macros because EVP_PKEY_CTX is undefined in 0.9.8 */ +int Cryptography_EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, + size_t *outlen, const unsigned char *in, + size_t inlen); +int Cryptography_EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out, + size_t *outlen, const unsigned char *in, + size_t inlen); """ CUSTOMIZATIONS = """ @@ -154,9 +169,24 @@ const long EVP_CTRL_GCM_GET_TAG = -1; const long EVP_CTRL_GCM_SET_TAG = -1; const long EVP_CTRL_GCM_SET_IVLEN = -1; #endif -#if OPENSSL_VERSION_NUMBER >= 0x10000000 +#if OPENSSL_VERSION_NUMBER >= 0x10000000L const long Cryptography_HAS_PBKDF2_HMAC = 1; const long Cryptography_HAS_PKEY_CTX = 1; + +/* OpenSSL 0.9.8 defines EVP_PKEY_encrypt and EVP_PKEY_decrypt functions, + but they are a completely different signature from the ones in 1.0.0+. + These wrapper functions allows us to safely declare them on any version and + conditionally remove them on 0.9.8. */ +int Cryptography_EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, + size_t *outlen, const unsigned char *in, + size_t inlen) { + return EVP_PKEY_encrypt(ctx, out, outlen, in, inlen); +} +int Cryptography_EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out, + size_t *outlen, const unsigned char *in, + size_t inlen) { + return EVP_PKEY_decrypt(ctx, out, outlen, in, inlen); +} #else const long Cryptography_HAS_PBKDF2_HMAC = 0; int (*PKCS5_PBKDF2_HMAC)(const char *, int, const unsigned char *, int, int, @@ -174,6 +204,12 @@ EVP_PKEY_CTX *(*EVP_PKEY_CTX_new)(EVP_PKEY *, ENGINE *) = NULL; EVP_PKEY_CTX *(*EVP_PKEY_CTX_new_id)(int, ENGINE *) = NULL; EVP_PKEY_CTX *(*EVP_PKEY_CTX_dup)(EVP_PKEY_CTX *) = NULL; void (*EVP_PKEY_CTX_free)(EVP_PKEY_CTX *) = NULL; +int (*EVP_PKEY_encrypt_init)(EVP_PKEY_CTX *) = NULL; +int (*EVP_PKEY_decrypt_init)(EVP_PKEY_CTX *) = NULL; +int (*Cryptography_EVP_PKEY_encrypt)(EVP_PKEY_CTX *, unsigned char *, size_t *, + const unsigned char *, size_t) = NULL; +int (*Cryptography_EVP_PKEY_decrypt)(EVP_PKEY_CTX *, unsigned char *, size_t *, + const unsigned char *, size_t) = NULL; #endif """ @@ -195,6 +231,10 @@ CONDITIONAL_NAMES = { "EVP_PKEY_sign_init", "EVP_PKEY_verify", "EVP_PKEY_verify_init", + "Cryptography_EVP_PKEY_encrypt", + "EVP_PKEY_encrypt_init", + "Cryptography_EVP_PKEY_decrypt", + "EVP_PKEY_decrypt_init", "EVP_PKEY_CTX_set_signature_md", ] } diff --git a/cryptography/hazmat/bindings/openssl/hmac.py b/cryptography/hazmat/bindings/openssl/hmac.py index 4b81c9df..6a64b92c 100644 --- a/cryptography/hazmat/bindings/openssl/hmac.py +++ b/cryptography/hazmat/bindings/openssl/hmac.py @@ -11,6 +11,8 @@ # 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/hmac.h> """ diff --git a/cryptography/hazmat/bindings/openssl/nid.py b/cryptography/hazmat/bindings/openssl/nid.py index 40aed19f..ea6fd4d6 100644 --- a/cryptography/hazmat/bindings/openssl/nid.py +++ b/cryptography/hazmat/bindings/openssl/nid.py @@ -11,9 +11,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import absolute_import, division, print_function + INCLUDES = "" TYPES = """ +static const int Cryptography_HAS_ECDSA_SHA2_NIDS; + static const int NID_undef; static const int NID_dsa; static const int NID_dsaWithSHA; @@ -38,6 +42,148 @@ static const int NID_ecdsa_with_SHA512; static const int NID_crl_reason; static const int NID_pbe_WithSHA1And3_Key_TripleDES_CBC; static const int NID_subject_alt_name; +static const int NID_X9_62_c2pnb163v1; +static const int NID_X9_62_c2pnb163v2; +static const int NID_X9_62_c2pnb163v3; +static const int NID_X9_62_c2pnb176v1; +static const int NID_X9_62_c2tnb191v1; +static const int NID_X9_62_c2tnb191v2; +static const int NID_X9_62_c2tnb191v3; +static const int NID_X9_62_c2onb191v4; +static const int NID_X9_62_c2onb191v5; +static const int NID_X9_62_c2pnb208w1; +static const int NID_X9_62_c2tnb239v1; +static const int NID_X9_62_c2tnb239v2; +static const int NID_X9_62_c2tnb239v3; +static const int NID_X9_62_c2onb239v4; +static const int NID_X9_62_c2onb239v5; +static const int NID_X9_62_c2pnb272w1; +static const int NID_X9_62_c2pnb304w1; +static const int NID_X9_62_c2tnb359v1; +static const int NID_X9_62_c2pnb368w1; +static const int NID_X9_62_c2tnb431r1; +static const int NID_X9_62_prime192v1; +static const int NID_X9_62_prime192v2; +static const int NID_X9_62_prime192v3; +static const int NID_X9_62_prime239v1; +static const int NID_X9_62_prime239v2; +static const int NID_X9_62_prime239v3; +static const int NID_X9_62_prime256v1; +static const int NID_secp112r1; +static const int NID_secp112r2; +static const int NID_secp128r1; +static const int NID_secp128r2; +static const int NID_secp160k1; +static const int NID_secp160r1; +static const int NID_secp160r2; +static const int NID_sect163k1; +static const int NID_sect163r1; +static const int NID_sect163r2; +static const int NID_secp192k1; +static const int NID_secp224k1; +static const int NID_secp224r1; +static const int NID_secp256k1; +static const int NID_secp384r1; +static const int NID_secp521r1; +static const int NID_sect113r1; +static const int NID_sect113r2; +static const int NID_sect131r1; +static const int NID_sect131r2; +static const int NID_sect193r1; +static const int NID_sect193r2; +static const int NID_sect233k1; +static const int NID_sect233r1; +static const int NID_sect239k1; +static const int NID_sect283k1; +static const int NID_sect283r1; +static const int NID_sect409k1; +static const int NID_sect409r1; +static const int NID_sect571k1; +static const int NID_sect571r1; +static const int NID_wap_wsg_idm_ecid_wtls1; +static const int NID_wap_wsg_idm_ecid_wtls3; +static const int NID_wap_wsg_idm_ecid_wtls4; +static const int NID_wap_wsg_idm_ecid_wtls5; +static const int NID_wap_wsg_idm_ecid_wtls6; +static const int NID_wap_wsg_idm_ecid_wtls7; +static const int NID_wap_wsg_idm_ecid_wtls8; +static const int NID_wap_wsg_idm_ecid_wtls9; +static const int NID_wap_wsg_idm_ecid_wtls10; +static const int NID_wap_wsg_idm_ecid_wtls11; +static const int NID_wap_wsg_idm_ecid_wtls12; +static const int NID_ipsec3; +static const int NID_ipsec4; +static const char *const SN_X9_62_c2pnb163v1; +static const char *const SN_X9_62_c2pnb163v2; +static const char *const SN_X9_62_c2pnb163v3; +static const char *const SN_X9_62_c2pnb176v1; +static const char *const SN_X9_62_c2tnb191v1; +static const char *const SN_X9_62_c2tnb191v2; +static const char *const SN_X9_62_c2tnb191v3; +static const char *const SN_X9_62_c2onb191v4; +static const char *const SN_X9_62_c2onb191v5; +static const char *const SN_X9_62_c2pnb208w1; +static const char *const SN_X9_62_c2tnb239v1; +static const char *const SN_X9_62_c2tnb239v2; +static const char *const SN_X9_62_c2tnb239v3; +static const char *const SN_X9_62_c2onb239v4; +static const char *const SN_X9_62_c2onb239v5; +static const char *const SN_X9_62_c2pnb272w1; +static const char *const SN_X9_62_c2pnb304w1; +static const char *const SN_X9_62_c2tnb359v1; +static const char *const SN_X9_62_c2pnb368w1; +static const char *const SN_X9_62_c2tnb431r1; +static const char *const SN_X9_62_prime192v1; +static const char *const SN_X9_62_prime192v2; +static const char *const SN_X9_62_prime192v3; +static const char *const SN_X9_62_prime239v1; +static const char *const SN_X9_62_prime239v2; +static const char *const SN_X9_62_prime239v3; +static const char *const SN_X9_62_prime256v1; +static const char *const SN_secp112r1; +static const char *const SN_secp112r2; +static const char *const SN_secp128r1; +static const char *const SN_secp128r2; +static const char *const SN_secp160k1; +static const char *const SN_secp160r1; +static const char *const SN_secp160r2; +static const char *const SN_sect163k1; +static const char *const SN_sect163r1; +static const char *const SN_sect163r2; +static const char *const SN_secp192k1; +static const char *const SN_secp224k1; +static const char *const SN_secp224r1; +static const char *const SN_secp256k1; +static const char *const SN_secp384r1; +static const char *const SN_secp521r1; +static const char *const SN_sect113r1; +static const char *const SN_sect113r2; +static const char *const SN_sect131r1; +static const char *const SN_sect131r2; +static const char *const SN_sect193r1; +static const char *const SN_sect193r2; +static const char *const SN_sect233k1; +static const char *const SN_sect233r1; +static const char *const SN_sect239k1; +static const char *const SN_sect283k1; +static const char *const SN_sect283r1; +static const char *const SN_sect409k1; +static const char *const SN_sect409r1; +static const char *const SN_sect571k1; +static const char *const SN_sect571r1; +static const char *const SN_wap_wsg_idm_ecid_wtls1; +static const char *const SN_wap_wsg_idm_ecid_wtls3; +static const char *const SN_wap_wsg_idm_ecid_wtls4; +static const char *const SN_wap_wsg_idm_ecid_wtls5; +static const char *const SN_wap_wsg_idm_ecid_wtls6; +static const char *const SN_wap_wsg_idm_ecid_wtls7; +static const char *const SN_wap_wsg_idm_ecid_wtls8; +static const char *const SN_wap_wsg_idm_ecid_wtls9; +static const char *const SN_wap_wsg_idm_ecid_wtls10; +static const char *const SN_wap_wsg_idm_ecid_wtls11; +static const char *const SN_wap_wsg_idm_ecid_wtls12; +static const char *const SN_ipsec3; +static const char *const SN_ipsec4; """ FUNCTIONS = """ @@ -47,6 +193,23 @@ MACROS = """ """ CUSTOMIZATIONS = """ +// OpenSSL 0.9.8g+ +#if OPENSSL_VERSION_NUMBER >= 0x0090807fL +static const long Cryptography_HAS_ECDSA_SHA2_NIDS = 1; +#else +static const long Cryptography_HAS_ECDSA_SHA2_NIDS = 0; +static const int NID_ecdsa_with_SHA224 = 0; +static const int NID_ecdsa_with_SHA256 = 0; +static const int NID_ecdsa_with_SHA384 = 0; +static const int NID_ecdsa_with_SHA512 = 0; +#endif """ -CONDITIONAL_NAMES = {} +CONDITIONAL_NAMES = { + "Cryptography_HAS_ECDSA_SHA2_NIDS": [ + "NID_ecdsa_with_SHA224", + "NID_ecdsa_with_SHA256", + "NID_ecdsa_with_SHA384", + "NID_ecdsa_with_SHA512", + ], +} diff --git a/cryptography/hazmat/bindings/openssl/objects.py b/cryptography/hazmat/bindings/openssl/objects.py index 0abc42d6..557c0158 100644 --- a/cryptography/hazmat/bindings/openssl/objects.py +++ b/cryptography/hazmat/bindings/openssl/objects.py @@ -11,6 +11,8 @@ # 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/objects.h> """ diff --git a/cryptography/hazmat/bindings/openssl/opensslv.py b/cryptography/hazmat/bindings/openssl/opensslv.py index 397f4ca2..e4aa6212 100644 --- a/cryptography/hazmat/bindings/openssl/opensslv.py +++ b/cryptography/hazmat/bindings/openssl/opensslv.py @@ -11,6 +11,8 @@ # 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/opensslv.h> """ diff --git a/cryptography/hazmat/bindings/openssl/osrandom_engine.py b/cryptography/hazmat/bindings/openssl/osrandom_engine.py index 0903a4bf..462997cc 100644 --- a/cryptography/hazmat/bindings/openssl/osrandom_engine.py +++ b/cryptography/hazmat/bindings/openssl/osrandom_engine.py @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import absolute_import, division, print_function + INCLUDES = """ #ifdef _WIN32 #include <Wincrypt.h> diff --git a/cryptography/hazmat/bindings/openssl/pem.py b/cryptography/hazmat/bindings/openssl/pem.py index 942cba34..e42fc6fe 100644 --- a/cryptography/hazmat/bindings/openssl/pem.py +++ b/cryptography/hazmat/bindings/openssl/pem.py @@ -11,6 +11,8 @@ # 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/pem.h> """ diff --git a/cryptography/hazmat/bindings/openssl/pkcs12.py b/cryptography/hazmat/bindings/openssl/pkcs12.py index bd01e756..a8f106f6 100644 --- a/cryptography/hazmat/bindings/openssl/pkcs12.py +++ b/cryptography/hazmat/bindings/openssl/pkcs12.py @@ -11,6 +11,8 @@ # 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/pkcs12.h> """ diff --git a/cryptography/hazmat/bindings/openssl/pkcs7.py b/cryptography/hazmat/bindings/openssl/pkcs7.py index 43f9540b..1343e566 100644 --- a/cryptography/hazmat/bindings/openssl/pkcs7.py +++ b/cryptography/hazmat/bindings/openssl/pkcs7.py @@ -11,6 +11,8 @@ # 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/pkcs7.h> """ diff --git a/cryptography/hazmat/bindings/openssl/rand.py b/cryptography/hazmat/bindings/openssl/rand.py index 0e645fbc..7b1be9df 100644 --- a/cryptography/hazmat/bindings/openssl/rand.py +++ b/cryptography/hazmat/bindings/openssl/rand.py @@ -11,6 +11,8 @@ # 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/rand.h> """ diff --git a/cryptography/hazmat/bindings/openssl/rsa.py b/cryptography/hazmat/bindings/openssl/rsa.py index 359305c6..c6356101 100644 --- a/cryptography/hazmat/bindings/openssl/rsa.py +++ b/cryptography/hazmat/bindings/openssl/rsa.py @@ -11,6 +11,8 @@ # 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/rsa.h> """ @@ -37,6 +39,7 @@ static const int RSA_PKCS1_PSS_PADDING; static const int RSA_F4; static const int Cryptography_HAS_PSS_PADDING; +static const int Cryptography_HAS_MGF1_MD; """ FUNCTIONS = """ @@ -70,6 +73,7 @@ int RSA_padding_check_PKCS1_OAEP(unsigned char *, int, const unsigned char *, MACROS = """ int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *, int); int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *, int); +int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *, EVP_MD *); """ CUSTOMIZATIONS = """ @@ -82,6 +86,12 @@ 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; static const long RSA_PKCS1_PSS_PADDING = 0; #endif +#if OPENSSL_VERSION_NUMBER >= 0x1000100f +static const long Cryptography_HAS_MGF1_MD = 1; +#else +static const long Cryptography_HAS_MGF1_MD = 0; +int (*EVP_PKEY_CTX_set_rsa_mgf1_md)(EVP_PKEY_CTX *, EVP_MD *) = NULL; +#endif """ CONDITIONAL_NAMES = { @@ -92,4 +102,7 @@ CONDITIONAL_NAMES = { "Cryptography_HAS_PSS_PADDING": [ "RSA_PKCS1_PSS_PADDING", ], + "Cryptography_HAS_MGF1_MD": [ + "EVP_PKEY_CTX_set_rsa_mgf1_md", + ], } diff --git a/cryptography/hazmat/bindings/openssl/ssl.py b/cryptography/hazmat/bindings/openssl/ssl.py index c0a6f016..094310f3 100644 --- a/cryptography/hazmat/bindings/openssl/ssl.py +++ b/cryptography/hazmat/bindings/openssl/ssl.py @@ -11,6 +11,8 @@ # 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/ssl.h> """ @@ -19,107 +21,115 @@ TYPES = """ /* * Internally invented symbols to tell which versions of SSL/TLS are supported. */ -static const int Cryptography_HAS_SSL2; -static const int Cryptography_HAS_TLSv1_1; -static const int Cryptography_HAS_TLSv1_2; +static const long Cryptography_HAS_SSL2; +static const long Cryptography_HAS_TLSv1_1; +static const long Cryptography_HAS_TLSv1_2; /* Internally invented symbol to tell us if SNI is supported */ -static const int Cryptography_HAS_TLSEXT_HOSTNAME; +static const long Cryptography_HAS_TLSEXT_HOSTNAME; /* Internally invented symbol to tell us if SSL_MODE_RELEASE_BUFFERS is * supported */ -static const int Cryptography_HAS_RELEASE_BUFFERS; +static const long Cryptography_HAS_RELEASE_BUFFERS; /* Internally invented symbol to tell us if SSL_OP_NO_COMPRESSION is * supported */ -static const int Cryptography_HAS_OP_NO_COMPRESSION; - -static const int Cryptography_HAS_SSL_OP_MSIE_SSLV2_RSA_PADDING; - -static const int SSL_FILETYPE_PEM; -static const int SSL_FILETYPE_ASN1; -static const int SSL_ERROR_NONE; -static const int SSL_ERROR_ZERO_RETURN; -static const int SSL_ERROR_WANT_READ; -static const int SSL_ERROR_WANT_WRITE; -static const int SSL_ERROR_WANT_X509_LOOKUP; -static const int SSL_ERROR_SYSCALL; -static const int SSL_ERROR_SSL; -static const int SSL_SENT_SHUTDOWN; -static const int SSL_RECEIVED_SHUTDOWN; -static const int SSL_OP_NO_SSLv2; -static const int SSL_OP_NO_SSLv3; -static const int SSL_OP_NO_TLSv1; -static const int SSL_OP_NO_TLSv1_1; -static const int SSL_OP_NO_TLSv1_2; -static const int SSL_OP_NO_COMPRESSION; -static const int SSL_OP_SINGLE_DH_USE; -static const int SSL_OP_EPHEMERAL_RSA; -static const int SSL_OP_MICROSOFT_SESS_ID_BUG; -static const int SSL_OP_NETSCAPE_CHALLENGE_BUG; -static const int SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; -static const int SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG; -static const int SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER; -static const int SSL_OP_MSIE_SSLV2_RSA_PADDING; -static const int SSL_OP_SSLEAY_080_CLIENT_DH_BUG; -static const int SSL_OP_TLS_D5_BUG; -static const int SSL_OP_TLS_BLOCK_PADDING_BUG; -static const int SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; -static const int SSL_OP_CIPHER_SERVER_PREFERENCE; -static const int SSL_OP_TLS_ROLLBACK_BUG; -static const int SSL_OP_PKCS1_CHECK_1; -static const int SSL_OP_PKCS1_CHECK_2; -static const int SSL_OP_NETSCAPE_CA_DN_BUG; -static const int SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG; -static const int SSL_OP_NO_QUERY_MTU; -static const int SSL_OP_COOKIE_EXCHANGE; -static const int SSL_OP_NO_TICKET; -static const int SSL_OP_ALL; -static const int SSL_OP_SINGLE_ECDH_USE; -static const int SSL_VERIFY_PEER; -static const int SSL_VERIFY_FAIL_IF_NO_PEER_CERT; -static const int SSL_VERIFY_CLIENT_ONCE; -static const int SSL_VERIFY_NONE; -static const int SSL_SESS_CACHE_OFF; -static const int SSL_SESS_CACHE_CLIENT; -static const int SSL_SESS_CACHE_SERVER; -static const int SSL_SESS_CACHE_BOTH; -static const int SSL_SESS_CACHE_NO_AUTO_CLEAR; -static const int SSL_SESS_CACHE_NO_INTERNAL_LOOKUP; -static const int SSL_SESS_CACHE_NO_INTERNAL_STORE; -static const int SSL_SESS_CACHE_NO_INTERNAL; -static const int SSL_ST_CONNECT; -static const int SSL_ST_ACCEPT; -static const int SSL_ST_MASK; -static const int SSL_ST_INIT; -static const int SSL_ST_BEFORE; -static const int SSL_ST_OK; -static const int SSL_ST_RENEGOTIATE; -static const int SSL_CB_LOOP; -static const int SSL_CB_EXIT; -static const int SSL_CB_READ; -static const int SSL_CB_WRITE; -static const int SSL_CB_ALERT; -static const int SSL_CB_READ_ALERT; -static const int SSL_CB_WRITE_ALERT; -static const int SSL_CB_ACCEPT_LOOP; -static const int SSL_CB_ACCEPT_EXIT; -static const int SSL_CB_CONNECT_LOOP; -static const int SSL_CB_CONNECT_EXIT; -static const int SSL_CB_HANDSHAKE_START; -static const int SSL_CB_HANDSHAKE_DONE; -static const int SSL_MODE_RELEASE_BUFFERS; -static const int SSL_MODE_ENABLE_PARTIAL_WRITE; -static const int SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; -static const int SSL_MODE_AUTO_RETRY; -static const int SSL3_RANDOM_SIZE; +static const long Cryptography_HAS_OP_NO_COMPRESSION; + +static const long Cryptography_HAS_SSL_OP_MSIE_SSLV2_RSA_PADDING; +static const long Cryptography_HAS_SSL_SET_SSL_CTX; +static const long Cryptography_HAS_SSL_OP_NO_TICKET; +static const long Cryptography_HAS_NETBSD_D1_METH; +static const long Cryptography_HAS_NEXTPROTONEG; + +static const long SSL_FILETYPE_PEM; +static const long SSL_FILETYPE_ASN1; +static const long SSL_ERROR_NONE; +static const long SSL_ERROR_ZERO_RETURN; +static const long SSL_ERROR_WANT_READ; +static const long SSL_ERROR_WANT_WRITE; +static const long SSL_ERROR_WANT_X509_LOOKUP; +static const long SSL_ERROR_SYSCALL; +static const long SSL_ERROR_SSL; +static const long SSL_SENT_SHUTDOWN; +static const long SSL_RECEIVED_SHUTDOWN; +static const long SSL_OP_NO_SSLv2; +static const long SSL_OP_NO_SSLv3; +static const long SSL_OP_NO_TLSv1; +static const long SSL_OP_NO_TLSv1_1; +static const long SSL_OP_NO_TLSv1_2; +static const long SSL_OP_NO_COMPRESSION; +static const long SSL_OP_SINGLE_DH_USE; +static const long SSL_OP_EPHEMERAL_RSA; +static const long SSL_OP_MICROSOFT_SESS_ID_BUG; +static const long SSL_OP_NETSCAPE_CHALLENGE_BUG; +static const long SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; +static const long SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG; +static const long SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER; +static const long SSL_OP_MSIE_SSLV2_RSA_PADDING; +static const long SSL_OP_SSLEAY_080_CLIENT_DH_BUG; +static const long SSL_OP_TLS_D5_BUG; +static const long SSL_OP_TLS_BLOCK_PADDING_BUG; +static const long SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; +static const long SSL_OP_CIPHER_SERVER_PREFERENCE; +static const long SSL_OP_TLS_ROLLBACK_BUG; +static const long SSL_OP_PKCS1_CHECK_1; +static const long SSL_OP_PKCS1_CHECK_2; +static const long SSL_OP_NETSCAPE_CA_DN_BUG; +static const long SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG; +static const long SSL_OP_NO_QUERY_MTU; +static const long SSL_OP_COOKIE_EXCHANGE; +static const long SSL_OP_NO_TICKET; +static const long SSL_OP_ALL; +static const long SSL_OP_SINGLE_ECDH_USE; +static const long SSL_VERIFY_PEER; +static const long SSL_VERIFY_FAIL_IF_NO_PEER_CERT; +static const long SSL_VERIFY_CLIENT_ONCE; +static const long SSL_VERIFY_NONE; +static const long SSL_SESS_CACHE_OFF; +static const long SSL_SESS_CACHE_CLIENT; +static const long SSL_SESS_CACHE_SERVER; +static const long SSL_SESS_CACHE_BOTH; +static const long SSL_SESS_CACHE_NO_AUTO_CLEAR; +static const long SSL_SESS_CACHE_NO_INTERNAL_LOOKUP; +static const long SSL_SESS_CACHE_NO_INTERNAL_STORE; +static const long SSL_SESS_CACHE_NO_INTERNAL; +static const long SSL_ST_CONNECT; +static const long SSL_ST_ACCEPT; +static const long SSL_ST_MASK; +static const long SSL_ST_INIT; +static const long SSL_ST_BEFORE; +static const long SSL_ST_OK; +static const long SSL_ST_RENEGOTIATE; +static const long SSL_CB_LOOP; +static const long SSL_CB_EXIT; +static const long SSL_CB_READ; +static const long SSL_CB_WRITE; +static const long SSL_CB_ALERT; +static const long SSL_CB_READ_ALERT; +static const long SSL_CB_WRITE_ALERT; +static const long SSL_CB_ACCEPT_LOOP; +static const long SSL_CB_ACCEPT_EXIT; +static const long SSL_CB_CONNECT_LOOP; +static const long SSL_CB_CONNECT_EXIT; +static const long SSL_CB_HANDSHAKE_START; +static const long SSL_CB_HANDSHAKE_DONE; +static const long SSL_MODE_RELEASE_BUFFERS; +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 int X509_V_OK; -static const int X509_V_ERR_APPLICATION_VERIFICATION; +static const long X509_V_OK; +static const long X509_V_ERR_APPLICATION_VERIFICATION; typedef ... SSL_METHOD; -typedef ... SSL_CTX; +typedef struct ssl_st { + int version; + int type; + ...; +} SSL_CTX; typedef struct { int master_key_length; @@ -140,7 +150,7 @@ typedef struct { ...; } SSL; -static const int TLSEXT_NAMETYPE_host_name; +static const long TLSEXT_NAMETYPE_host_name; typedef ... SSL_CIPHER; """ @@ -150,7 +160,6 @@ void SSL_load_error_strings(void); int SSL_library_init(void); /* SSL */ -SSL_CTX *SSL_set_SSL_CTX(SSL *, SSL_CTX *); SSL_SESSION *SSL_get1_session(SSL *); int SSL_set_session(SSL *, SSL_SESSION *); int SSL_get_verify_mode(const SSL *); @@ -188,8 +197,6 @@ int SSL_CTX_set_default_verify_paths(SSL_CTX *); void SSL_CTX_set_verify(SSL_CTX *, int, int (*)(int, X509_STORE_CTX *)); void SSL_CTX_set_verify_depth(SSL_CTX *, int); int (*SSL_CTX_get_verify_callback(const SSL_CTX *))(int, X509_STORE_CTX *); -void SSL_CTX_set_info_callback(SSL_CTX *, void (*)(const SSL *, int, int)); -void (*SSL_CTX_get_info_callback(SSL_CTX *))(const SSL *, int, int); int SSL_CTX_get_verify_mode(const SSL_CTX *); int SSL_CTX_get_verify_depth(const SSL_CTX *); int SSL_CTX_set_cipher_list(SSL_CTX *, const char *); @@ -308,6 +315,39 @@ void SSL_CTX_set_tlsext_servername_callback( int (*)(const SSL *, int *, void *)); long SSL_session_reused(SSL *); + +/* The following were macros in 0.9.8e. Once we drop support for RHEL/CentOS 5 + we should move these back to FUNCTIONS. */ +void SSL_CTX_set_info_callback(SSL_CTX *, void (*)(const SSL *, int, int)); +void (*SSL_CTX_get_info_callback(SSL_CTX *))(const SSL *, int, int); +/* This function does not exist in 0.9.8e. Once we drop support for + RHEL/CentOS 5 this can be moved back to FUNCTIONS. */ +SSL_CTX *SSL_set_SSL_CTX(SSL *, SSL_CTX *); + +const SSL_METHOD* Cryptography_SSL_CTX_get_method(const SSL_CTX*); + +/* NPN APIs were introduced in OpenSSL 1.0.1. To continue to support earlier + * versions some special handling of these is necessary. + */ +void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *, + int (*)(SSL *, + const unsigned char **, + unsigned int *, + void *), + void *); +void SSL_CTX_set_next_proto_select_cb(SSL_CTX *, + int (*)(SSL *, + unsigned char **, + unsigned char *, + const unsigned char *, + unsigned int, + void *), + void *); +int SSL_select_next_proto(unsigned char **, unsigned char *, + const unsigned char *, unsigned int, + const unsigned char *, unsigned int); +void SSL_get0_next_proto_negotiated(const SSL *, + const unsigned char **, unsigned *); """ CUSTOMIZATIONS = """ @@ -375,6 +415,76 @@ const long SSL_OP_MSIE_SSLV2_RSA_PADDING = 0; #ifdef OPENSSL_NO_EC long (*SSL_CTX_set_tmp_ecdh)(SSL_CTX *, EC_KEY *) = NULL; #endif + +#ifdef SSL_OP_NO_TICKET +static const long Cryptography_HAS_SSL_OP_NO_TICKET = 1; +#else +static const long Cryptography_HAS_SSL_OP_NO_TICKET = 0; +const long SSL_OP_NO_TICKET = 0; +#endif + +// OpenSSL 0.9.8f+ +#if OPENSSL_VERSION_NUMBER >= 0x00908070L +static const long Cryptography_HAS_SSL_SET_SSL_CTX = 1; +#else +static const long Cryptography_HAS_SSL_SET_SSL_CTX = 0; +static const long TLSEXT_NAMETYPE_host_name = 0; +SSL_CTX *(*SSL_set_SSL_CTX)(SSL *, SSL_CTX *) = NULL; +#endif + +/* NetBSD shipped without including d1_meth.c. This workaround checks to see + if the version of NetBSD we're currently running on is old enough to + have the bug and provides an empty implementation so we can link and + then remove the function from the ffi object. */ +#ifdef __NetBSD__ +# include <sys/param.h> +# if (__NetBSD_Version__ < 699003800) +static const long Cryptography_HAS_NETBSD_D1_METH = 0; +const SSL_METHOD *DTLSv1_method(void) { + return NULL; +} +# else +static const long Cryptography_HAS_NETBSD_D1_METH = 1; +# endif +#else +static const long Cryptography_HAS_NETBSD_D1_METH = 1; +#endif + +// Workaround for #794 caused by cffi const** bug. +const SSL_METHOD* Cryptography_SSL_CTX_get_method(const SSL_CTX* ctx) { + return ctx->method; +} + +/* Because OPENSSL defines macros that claim lack of support for things, rather + * than macros that claim support for things, we need to do a version check in + * addition to a definition check. NPN was added in 1.0.1: for any version + * before that, there is no compatibility. + */ +#if defined(OPENSSL_NO_NEXTPROTONEG) || OPENSSL_VERSION_NUMBER < 0x1000100fL +static const long Cryptography_HAS_NEXTPROTONEG = 0; +void (*SSL_CTX_set_next_protos_advertised_cb)(SSL_CTX *, + int (*)(SSL *, + const unsigned char **, + unsigned int *, + void *), + void *) = NULL; +void (*SSL_CTX_set_next_proto_select_cb)(SSL_CTX *, + int (*)(SSL *, + unsigned char **, + unsigned char *, + const unsigned char *, + unsigned int, + void *), + void *) = NULL; +int (*SSL_select_next_proto)(unsigned char **, unsigned char *, + const unsigned char *, unsigned int, + const unsigned char *, unsigned int) = NULL; +void (*SSL_get0_next_proto_negotiated)(const SSL *, + const unsigned char **, + unsigned *) = NULL; +#else +static const long Cryptography_HAS_NEXTPROTONEG = 1; +#endif """ CONDITIONAL_NAMES = { @@ -418,5 +528,25 @@ CONDITIONAL_NAMES = { "Cryptography_HAS_EC": [ "SSL_CTX_set_tmp_ecdh", + ], + + "Cryptography_HAS_SSL_OP_NO_TICKET": [ + "SSL_OP_NO_TICKET", + ], + + "Cryptography_HAS_SSL_SET_SSL_CTX": [ + "SSL_set_SSL_CTX", + "TLSEXT_NAMETYPE_host_name", + ], + + "Cryptography_HAS_NETBSD_D1_METH": [ + "DTLSv1_method", + ], + + "Cryptography_HAS_NEXTPROTONEG": [ + "SSL_CTX_set_next_protos_advertised_cb", + "SSL_CTX_set_next_proto_select_cb", + "SSL_select_next_proto", + "SSL_get0_next_proto_negotiated", ] } diff --git a/cryptography/hazmat/bindings/openssl/x509.py b/cryptography/hazmat/bindings/openssl/x509.py index 95c88b3a..e800d272 100644 --- a/cryptography/hazmat/bindings/openssl/x509.py +++ b/cryptography/hazmat/bindings/openssl/x509.py @@ -11,6 +11,8 @@ # 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/ssl.h> @@ -120,8 +122,6 @@ int X509_REQ_set_pubkey(X509_REQ *, EVP_PKEY *); int X509_REQ_sign(X509_REQ *, EVP_PKEY *, const EVP_MD *); int X509_REQ_verify(X509_REQ *, EVP_PKEY *); EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *); -int X509_REQ_add_extensions(X509_REQ *, X509_EXTENSIONS *); -X509_EXTENSIONS *X509_REQ_get_extensions(X509_REQ *); int X509_REQ_print_ex(BIO *, X509_REQ *, unsigned long, unsigned long); int X509V3_EXT_print(BIO *, X509_EXTENSION *, unsigned long, int); @@ -208,9 +208,18 @@ X509_REVOKED *sk_X509_REVOKED_value(Cryptography_STACK_OF_X509_REVOKED *, int); /* These aren't macros these arguments are all const X on openssl > 1.0.x */ 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 + 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 *); """ CUSTOMIZATIONS = """ +// OpenSSL 0.9.8e does not have this definition +#if OPENSSL_VERSION_NUMBER <= 0x0090805fL +typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS; +#endif """ CONDITIONAL_NAMES = {} diff --git a/cryptography/hazmat/bindings/openssl/x509name.py b/cryptography/hazmat/bindings/openssl/x509name.py index bf627d61..50abee2a 100644 --- a/cryptography/hazmat/bindings/openssl/x509name.py +++ b/cryptography/hazmat/bindings/openssl/x509name.py @@ -11,6 +11,8 @@ # 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.h> diff --git a/cryptography/hazmat/bindings/openssl/x509v3.py b/cryptography/hazmat/bindings/openssl/x509v3.py index 6d2d2361..02ec250a 100644 --- a/cryptography/hazmat/bindings/openssl/x509v3.py +++ b/cryptography/hazmat/bindings/openssl/x509v3.py @@ -11,6 +11,8 @@ # 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/x509v3.h> """ diff --git a/cryptography/hazmat/bindings/utils.py b/cryptography/hazmat/bindings/utils.py index b8253483..318b82bb 100644 --- a/cryptography/hazmat/bindings/utils.py +++ b/cryptography/hazmat/bindings/utils.py @@ -13,6 +13,8 @@ from __future__ import absolute_import, division, print_function +import binascii + import sys import cffi @@ -50,7 +52,8 @@ def build_ffi(module_prefix, modules, pre_include, post_include, libraries): includes.append(module.INCLUDES) customizations.append(module.CUSTOMIZATIONS) - ffi.cdef("\n".join(types + functions + macros)) + cdef_sources = types + functions + macros + ffi.cdef("\n".join(cdef_sources)) # We include functions here so that if we got any of their definitions # wrong, the underlying C compiler will explode. In C you are allowed @@ -60,14 +63,16 @@ def build_ffi(module_prefix, modules, pre_include, post_include, libraries): # is legal, but the following will fail to compile: # int foo(int); # int foo(short); + source = "\n".join( + [pre_include] + + includes + + [post_include] + + functions + + customizations + ) lib = ffi.verify( - source="\n".join( - [pre_include] + - includes + - [post_include] + - functions + - customizations - ), + source=source, + modulename=_create_modulename(cdef_sources, source, sys.version), libraries=libraries, ext_package="cryptography", ) @@ -81,3 +86,20 @@ def build_ffi(module_prefix, modules, pre_include, post_include, libraries): delattr(lib, name) return ffi, lib + + +def _create_modulename(cdef_sources, source, sys_version): + """ + cffi creates a modulename internally that incorporates the cffi version. + This will cause cryptography's wheels to break when the version of cffi + the user has does not match what was used when building the wheel. To + resolve this we build our own modulename that uses most of the same code + from cffi but elides the version key. + """ + key = '\x00'.join([sys_version[:3], source] + cdef_sources) + key = key.encode('utf-8') + k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff) + k1 = k1.lstrip('0x').rstrip('L') + k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff) + k2 = k2.lstrip('0').rstrip('L') + return '_Cryptography_cffi_{0}{1}'.format(k1, k2) diff --git a/cryptography/hazmat/primitives/__init__.py b/cryptography/hazmat/primitives/__init__.py index e69de29b..2f420574 100644 --- a/cryptography/hazmat/primitives/__init__.py +++ b/cryptography/hazmat/primitives/__init__.py @@ -0,0 +1,14 @@ +# 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 diff --git a/cryptography/hazmat/primitives/asymmetric/__init__.py b/cryptography/hazmat/primitives/asymmetric/__init__.py index e69de29b..2f420574 100644 --- a/cryptography/hazmat/primitives/asymmetric/__init__.py +++ b/cryptography/hazmat/primitives/asymmetric/__init__.py @@ -0,0 +1,14 @@ +# 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 diff --git a/cryptography/hazmat/primitives/asymmetric/dsa.py b/cryptography/hazmat/primitives/asymmetric/dsa.py new file mode 100644 index 00000000..974db0a6 --- /dev/null +++ b/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -0,0 +1,142 @@ +# 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.hazmat.primitives import interfaces + + +def _check_dsa_parameters(modulus, subgroup_order, generator): + if ( + not isinstance(modulus, six.integer_types) or + not isinstance(subgroup_order, six.integer_types) or + not isinstance(generator, six.integer_types) + ): + raise TypeError("DSA parameters must be integers") + + if (utils.bit_length(modulus), + utils.bit_length(subgroup_order)) not in ( + (1024, 160), + (2048, 256), + (3072, 256)): + raise ValueError("modulus and subgroup_order lengths must be " + "one of these pairs (1024, 160) or (2048, 256) " + "or (3072, 256)") + + if generator <= 1 or generator >= modulus: + raise ValueError("generator must be > 1 and < modulus") + + +@utils.register_interface(interfaces.DSAParameters) +class DSAParameters(object): + def __init__(self, modulus, subgroup_order, generator): + _check_dsa_parameters(modulus, subgroup_order, generator) + + self._modulus = modulus + self._subgroup_order = subgroup_order + self._generator = generator + + @property + def modulus(self): + return self._modulus + + @property + def subgroup_order(self): + return self._subgroup_order + + @property + def generator(self): + return self._generator + + @property + def p(self): + return self.modulus + + @property + def q(self): + return self.subgroup_order + + @property + def g(self): + return self.generator + + +@utils.register_interface(interfaces.DSAPrivateKey) +class DSAPrivateKey(object): + def __init__(self, modulus, subgroup_order, generator, x, y): + _check_dsa_parameters(modulus, subgroup_order, generator) + if ( + not isinstance(x, six.integer_types) or + not isinstance(y, six.integer_types) + ): + raise TypeError("DSAPrivateKey arguments must be integers") + + if x <= 0 or x >= subgroup_order: + raise ValueError("x must be > 0 and < subgroup_order") + + if y != pow(generator, x, modulus): + raise ValueError("y must be equal to (generator ** x % modulus)") + + self._modulus = modulus + self._subgroup_order = subgroup_order + self._generator = generator + self._x = x + self._y = y + + @property + def key_size(self): + return utils.bit_length(self._modulus) + + def public_key(self): + return DSAPublicKey(self._modulus, self._subgroup_order, + self._generator, self.y) + + @property + def x(self): + return self._x + + @property + def y(self): + return self._y + + def parameters(self): + return DSAParameters(self._modulus, self._subgroup_order, + self._generator) + + +@utils.register_interface(interfaces.DSAPublicKey) +class DSAPublicKey(object): + def __init__(self, modulus, subgroup_order, generator, y): + _check_dsa_parameters(modulus, subgroup_order, generator) + if not isinstance(y, six.integer_types): + raise TypeError("y must be an integer") + + self._modulus = modulus + self._subgroup_order = subgroup_order + self._generator = generator + self._y = y + + @property + def key_size(self): + return utils.bit_length(self._modulus) + + @property + def y(self): + return self._y + + def parameters(self): + return DSAParameters(self._modulus, self._subgroup_order, + self._generator) diff --git a/cryptography/hazmat/primitives/asymmetric/padding.py b/cryptography/hazmat/primitives/asymmetric/padding.py index 6bafe314..02aff280 100644 --- a/cryptography/hazmat/primitives/asymmetric/padding.py +++ b/cryptography/hazmat/primitives/asymmetric/padding.py @@ -13,6 +13,8 @@ from __future__ import absolute_import, division, print_function +import six + from cryptography import utils from cryptography.hazmat.primitives import interfaces @@ -20,3 +22,30 @@ from cryptography.hazmat.primitives import interfaces @utils.register_interface(interfaces.AsymmetricPadding) class PKCS1v15(object): name = "EMSA-PKCS1-v1_5" + + +@utils.register_interface(interfaces.AsymmetricPadding) +class PSS(object): + name = "EMSA-PSS" + + def __init__(self, mgf): + self._mgf = mgf + + +class MGF1(object): + MAX_LENGTH = object() + + def __init__(self, algorithm, salt_length): + if not isinstance(algorithm, interfaces.HashAlgorithm): + raise TypeError("Expected instance of interfaces.HashAlgorithm.") + + self._algorithm = algorithm + + if (not isinstance(salt_length, six.integer_types) and + salt_length is not self.MAX_LENGTH): + raise TypeError("salt_length must be an integer") + + if salt_length is not self.MAX_LENGTH and salt_length < 0: + raise ValueError("salt_length must be zero or greater") + + self._salt_length = salt_length diff --git a/cryptography/hazmat/primitives/asymmetric/rsa.py b/cryptography/hazmat/primitives/asymmetric/rsa.py index d8254046..94cc4645 100644 --- a/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -13,21 +13,14 @@ from __future__ import absolute_import, division, print_function -import sys - 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 _bit_length(x): - if sys.version_info >= (2, 7): - return x.bit_length() - else: - return len(bin(x)) - (2 + (x <= 0)) - - @utils.register_interface(interfaces.RSAPublicKey) class RSAPublicKey(object): def __init__(self, public_exponent, modulus): @@ -50,12 +43,18 @@ class RSAPublicKey(object): self._modulus = modulus def verifier(self, signature, padding, algorithm, backend): + if not isinstance(backend, RSABackend): + raise UnsupportedAlgorithm( + "Backend object does not implement RSABackend", + _Reasons.BACKEND_MISSING_INTERFACE + ) + return backend.create_rsa_verification_ctx(self, signature, padding, algorithm) @property def key_size(self): - return _bit_length(self.modulus) + return utils.bit_length(self.modulus) @property def public_exponent(self): @@ -137,14 +136,26 @@ class RSAPrivateKey(object): @classmethod def generate(cls, public_exponent, key_size, backend): + if not isinstance(backend, RSABackend): + raise UnsupportedAlgorithm( + "Backend object does not implement RSABackend", + _Reasons.BACKEND_MISSING_INTERFACE + ) + return backend.generate_rsa_private_key(public_exponent, key_size) def signer(self, padding, algorithm, backend): + if not isinstance(backend, RSABackend): + raise UnsupportedAlgorithm( + "Backend object does not implement RSABackend", + _Reasons.BACKEND_MISSING_INTERFACE + ) + return backend.create_rsa_signature_ctx(self, padding, algorithm) @property def key_size(self): - return _bit_length(self.modulus) + return utils.bit_length(self.modulus) def public_key(self): return RSAPublicKey(self.public_exponent, self.modulus) diff --git a/cryptography/hazmat/primitives/ciphers/algorithms.py b/cryptography/hazmat/primitives/ciphers/algorithms.py index a5cfce92..2d37e0cf 100644 --- a/cryptography/hazmat/primitives/ciphers/algorithms.py +++ b/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -116,3 +116,17 @@ class ARC4(object): @property def key_size(self): return len(self.key) * 8 + + +@utils.register_interface(interfaces.CipherAlgorithm) +class IDEA(object): + name = "IDEA" + block_size = 64 + key_sizes = frozenset([128]) + + def __init__(self, key): + self.key = _verify_key_size(self, key) + + @property + def key_size(self): + return len(self.key) * 8 diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index d366e4cf..2274e945 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -15,13 +15,21 @@ from __future__ import absolute_import, division, print_function from cryptography import utils from cryptography.exceptions import ( - AlreadyFinalized, NotYetFinalized, AlreadyUpdated, + AlreadyFinalized, AlreadyUpdated, NotYetFinalized, UnsupportedAlgorithm, + _Reasons ) +from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives import interfaces class Cipher(object): def __init__(self, algorithm, mode, backend): + if not isinstance(backend, CipherBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement CipherBackend", + _Reasons.BACKEND_MISSING_INTERFACE + ) + if not isinstance(algorithm, interfaces.CipherAlgorithm): raise TypeError("Expected interface of interfaces.CipherAlgorithm") diff --git a/cryptography/hazmat/primitives/constant_time.py b/cryptography/hazmat/primitives/constant_time.py index e88a0d95..e0e9aa37 100644 --- a/cryptography/hazmat/primitives/constant_time.py +++ b/cryptography/hazmat/primitives/constant_time.py @@ -13,18 +13,20 @@ from __future__ import absolute_import, division, print_function +import sys + import cffi import six +from cryptography.hazmat.bindings.utils import _create_modulename -_ffi = cffi.FFI() -_ffi.cdef(""" +TYPES = """ uint8_t Cryptography_constant_time_bytes_eq(uint8_t *, size_t, uint8_t *, size_t); -""") -_lib = _ffi.verify( - """ +""" + +FUNCTIONS = """ uint8_t Cryptography_constant_time_bytes_eq(uint8_t *a, size_t len_a, uint8_t *b, size_t len_b) { size_t i = 0; @@ -43,7 +45,13 @@ uint8_t Cryptography_constant_time_bytes_eq(uint8_t *a, size_t len_a, /* Now check the low bit to see if it's set */ return (mismatch & 1) == 0; } -""", +""" + +_ffi = cffi.FFI() +_ffi.cdef(TYPES) +_lib = _ffi.verify( + source=FUNCTIONS, + modulename=_create_modulename([TYPES], FUNCTIONS, sys.version), ext_package="cryptography", ) diff --git a/cryptography/hazmat/primitives/hashes.py b/cryptography/hazmat/primitives/hashes.py index bee188b3..35b677b0 100644 --- a/cryptography/hazmat/primitives/hashes.py +++ b/cryptography/hazmat/primitives/hashes.py @@ -16,13 +16,22 @@ from __future__ import absolute_import, division, print_function import six from cryptography import utils -from cryptography.exceptions import AlreadyFinalized +from cryptography.exceptions import ( + AlreadyFinalized, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import HashBackend from cryptography.hazmat.primitives import interfaces @utils.register_interface(interfaces.HashContext) class Hash(object): def __init__(self, algorithm, backend, ctx=None): + if not isinstance(backend, HashBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HashBackend", + _Reasons.BACKEND_MISSING_INTERFACE + ) + if not isinstance(algorithm, interfaces.HashAlgorithm): raise TypeError("Expected instance of interfaces.HashAlgorithm.") self.algorithm = algorithm diff --git a/cryptography/hazmat/primitives/hmac.py b/cryptography/hazmat/primitives/hmac.py index 76d658aa..afbb2f75 100644 --- a/cryptography/hazmat/primitives/hmac.py +++ b/cryptography/hazmat/primitives/hmac.py @@ -16,13 +16,22 @@ from __future__ import absolute_import, division, print_function import six from cryptography import utils -from cryptography.exceptions import AlreadyFinalized, InvalidSignature +from cryptography.exceptions import ( + AlreadyFinalized, InvalidSignature, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import constant_time, interfaces @utils.register_interface(interfaces.HashContext) class HMAC(object): def __init__(self, key, algorithm, backend, ctx=None): + if not isinstance(backend, HMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HMACBackend", + _Reasons.BACKEND_MISSING_INTERFACE + ) + if not isinstance(algorithm, interfaces.HashAlgorithm): raise TypeError("Expected instance of interfaces.HashAlgorithm.") self.algorithm = algorithm diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index 11696160..eab48b4d 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -287,6 +287,104 @@ class RSAPublicKey(six.with_metaclass(abc.ABCMeta)): """ +class DSAParameters(six.with_metaclass(abc.ABCMeta)): + @abc.abstractproperty + def modulus(self): + """ + The prime modulus that's used in generating the DSA keypair and used + in the DSA signing and verification processes. + """ + + @abc.abstractproperty + def subgroup_order(self): + """ + The subgroup order that's used in generating the DSA keypair + by the generator and used in the DSA signing and verification + processes. + """ + + @abc.abstractproperty + def generator(self): + """ + The generator that is used in generating the DSA keypair and used + in the DSA signing and verification processes. + """ + + @abc.abstractproperty + def p(self): + """ + The prime modulus that's used in generating the DSA keypair and used + in the DSA signing and verification processes. Alias for modulus. + """ + + @abc.abstractproperty + def q(self): + """ + The subgroup order that's used in generating the DSA keypair + by the generator and used in the DSA signing and verification + processes. Alias for subgroup_order. + """ + + @abc.abstractproperty + def g(self): + """ + The generator that is used in generating the DSA keypair and used + in the DSA signing and verification processes. Alias for generator. + """ + + +class DSAPrivateKey(six.with_metaclass(abc.ABCMeta)): + @abc.abstractproperty + def key_size(self): + """ + The bit length of the prime modulus. + """ + + @abc.abstractmethod + def public_key(self): + """ + The DSAPublicKey associated with this private key. + """ + + @abc.abstractproperty + def x(self): + """ + The private key "x" in the DSA structure. + """ + + @abc.abstractproperty + def y(self): + """ + The public key. + """ + + @abc.abstractmethod + def parameters(self): + """ + The DSAParameters object associated with this private key. + """ + + +class DSAPublicKey(six.with_metaclass(abc.ABCMeta)): + @abc.abstractproperty + def key_size(self): + """ + The bit length of the prime modulus. + """ + + @abc.abstractproperty + def y(self): + """ + The public key. + """ + + @abc.abstractmethod + def parameters(self): + """ + The DSAParameters object associated with this public key. + """ + + class AsymmetricSignatureContext(six.with_metaclass(abc.ABCMeta)): @abc.abstractmethod def update(self, data): diff --git a/cryptography/hazmat/primitives/kdf/__init__.py b/cryptography/hazmat/primitives/kdf/__init__.py index e69de29b..2f420574 100644 --- a/cryptography/hazmat/primitives/kdf/__init__.py +++ b/cryptography/hazmat/primitives/kdf/__init__.py @@ -0,0 +1,14 @@ +# 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 diff --git a/cryptography/hazmat/primitives/kdf/hkdf.py b/cryptography/hazmat/primitives/kdf/hkdf.py index af15b64d..03500aaa 100644 --- a/cryptography/hazmat/primitives/kdf/hkdf.py +++ b/cryptography/hazmat/primitives/kdf/hkdf.py @@ -11,16 +11,27 @@ # 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 AlreadyFinalized, InvalidKey +from cryptography.exceptions import ( + AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import constant_time, hmac, interfaces @utils.register_interface(interfaces.KeyDerivationFunction) class HKDF(object): def __init__(self, algorithm, length, salt, info, backend): + if not isinstance(backend, HMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HMACBackend", + _Reasons.BACKEND_MISSING_INTERFACE + ) + self._algorithm = algorithm max_length = 255 * (algorithm.digest_size // 8) diff --git a/cryptography/hazmat/primitives/kdf/pbkdf2.py b/cryptography/hazmat/primitives/kdf/pbkdf2.py index 71b88211..bec35bb2 100644 --- a/cryptography/hazmat/primitives/kdf/pbkdf2.py +++ b/cryptography/hazmat/primitives/kdf/pbkdf2.py @@ -17,18 +17,26 @@ import six from cryptography import utils from cryptography.exceptions import ( - InvalidKey, UnsupportedAlgorithm, AlreadyFinalized + AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons ) +from cryptography.hazmat.backends.interfaces import PBKDF2HMACBackend from cryptography.hazmat.primitives import constant_time, interfaces @utils.register_interface(interfaces.KeyDerivationFunction) class PBKDF2HMAC(object): def __init__(self, algorithm, length, salt, iterations, backend): + if not isinstance(backend, PBKDF2HMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement PBKDF2HMACBackend", + _Reasons.BACKEND_MISSING_INTERFACE + ) + if not backend.pbkdf2_hmac_supported(algorithm): raise UnsupportedAlgorithm( "{0} is not supported for PBKDF2 by this backend".format( - algorithm.name) + algorithm.name), + _Reasons.UNSUPPORTED_HASH ) self._used = False self._algorithm = algorithm diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py index 1717262c..d78c6a5b 100644 --- a/cryptography/hazmat/primitives/padding.py +++ b/cryptography/hazmat/primitives/padding.py @@ -11,20 +11,24 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import absolute_import, division, print_function + +import sys + import cffi import six from cryptography import utils +from cryptography.hazmat.bindings.utils import _create_modulename from cryptography.hazmat.primitives import interfaces -_ffi = cffi.FFI() -_ffi.cdef(""" +TYPES = """ uint8_t Cryptography_check_pkcs7_padding(const uint8_t *, uint8_t); -""") -_lib = _ffi.verify( - """ +""" + +FUNCTIONS = """ /* Returns the value of the input with the most-significant-bit copied to all of the bits. */ static uint8_t Cryptography_DUPLICATE_MSB_TO_ALL(uint8_t a) { @@ -60,7 +64,13 @@ uint8_t Cryptography_check_pkcs7_padding(const uint8_t *data, /* Now check the low bit to see if it's set */ return (mismatch & 1) == 0; } -""", +""" + +_ffi = cffi.FFI() +_ffi.cdef(TYPES) +_lib = _ffi.verify( + source=FUNCTIONS, + modulename=_create_modulename([TYPES], FUNCTIONS, sys.version), ext_package="cryptography", ) diff --git a/cryptography/hazmat/primitives/twofactor/__init__.py b/cryptography/hazmat/primitives/twofactor/__init__.py index e69de29b..2f420574 100644 --- a/cryptography/hazmat/primitives/twofactor/__init__.py +++ b/cryptography/hazmat/primitives/twofactor/__init__.py @@ -0,0 +1,14 @@ +# 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 diff --git a/cryptography/hazmat/primitives/twofactor/hotp.py b/cryptography/hazmat/primitives/twofactor/hotp.py index 24f5f465..41c467c8 100644 --- a/cryptography/hazmat/primitives/twofactor/hotp.py +++ b/cryptography/hazmat/primitives/twofactor/hotp.py @@ -17,22 +17,33 @@ import struct import six -from cryptography.exceptions import InvalidToken, UnsupportedAlgorithm +from cryptography.exceptions import ( + InvalidToken, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import constant_time, hmac from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512 class HOTP(object): def __init__(self, key, length, algorithm, backend): + if not isinstance(backend, HMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HMACBackend", + _Reasons.BACKEND_MISSING_INTERFACE + ) + if len(key) < 16: raise ValueError("Key length has to be at least 128 bits.") + if not isinstance(length, six.integer_types): + raise TypeError("Length parameter must be an integer type") + if length < 6 or length > 8: raise ValueError("Length of HOTP has to be between 6 to 8.") if not isinstance(algorithm, (SHA1, SHA256, SHA512)): - raise UnsupportedAlgorithm( - "Algorithm must be SHA1, SHA256 or SHA512") + raise TypeError("Algorithm must be SHA1, SHA256 or SHA512") self._key = key self._length = length diff --git a/cryptography/hazmat/primitives/twofactor/totp.py b/cryptography/hazmat/primitives/twofactor/totp.py index 0630de69..e55ba00d 100644 --- a/cryptography/hazmat/primitives/twofactor/totp.py +++ b/cryptography/hazmat/primitives/twofactor/totp.py @@ -13,13 +13,22 @@ from __future__ import absolute_import, division, print_function -from cryptography.exceptions import InvalidToken +from cryptography.exceptions import ( + InvalidToken, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import constant_time from cryptography.hazmat.primitives.twofactor.hotp import HOTP class TOTP(object): def __init__(self, key, length, algorithm, time_step, backend): + if not isinstance(backend, HMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HMACBackend", + _Reasons.BACKEND_MISSING_INTERFACE + ) + self._time_step = time_step self._hotp = HOTP(key, length, algorithm, backend) |