From 9626b5a50460d2f90baa1f1b8c6a09ccc900c178 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 19 Nov 2013 16:49:26 -0800 Subject: Validate the IV/nonce length for a given algorithm. Fixes #159 --- cryptography/hazmat/primitives/ciphers/base.py | 3 +++ cryptography/hazmat/primitives/ciphers/modes.py | 21 +++++++++++++++++++++ cryptography/hazmat/primitives/interfaces.py | 7 +++++++ docs/hazmat/primitives/interfaces.rst | 12 ++++++++++++ tests/hazmat/bindings/test_openssl.py | 3 ++- tests/hazmat/primitives/test_block.py | 17 ++++++++++++++++- 6 files changed, 61 insertions(+), 2 deletions(-) diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py index 3d733afc..d046a012 100644 --- a/cryptography/hazmat/primitives/ciphers/base.py +++ b/cryptography/hazmat/primitives/ciphers/base.py @@ -28,6 +28,9 @@ class Cipher(object): if not isinstance(algorithm, interfaces.CipherAlgorithm): raise TypeError("Expected interface of interfaces.CipherAlgorithm") + if mode is not None: + mode.validate_for_algorithm(algorithm) + self.algorithm = algorithm self.mode = mode self._backend = backend diff --git a/cryptography/hazmat/primitives/ciphers/modes.py b/cryptography/hazmat/primitives/ciphers/modes.py index 1d0de689..597b4e3e 100644 --- a/cryptography/hazmat/primitives/ciphers/modes.py +++ b/cryptography/hazmat/primitives/ciphers/modes.py @@ -25,11 +25,20 @@ class CBC(object): def __init__(self, initialization_vector): self.initialization_vector = initialization_vector + def validate_for_algorithm(self, algorithm): + if len(self.initialization_vector) * 8 != algorithm.block_size: + raise ValueError("Invalid iv size ({0}) for {1}".format( + len(self.initialization_vector), self.name + )) + @utils.register_interface(interfaces.Mode) class ECB(object): name = "ECB" + def validate_for_algorithm(self, algorithm): + pass + @utils.register_interface(interfaces.Mode) @utils.register_interface(interfaces.ModeWithInitializationVector) @@ -39,6 +48,12 @@ class OFB(object): def __init__(self, initialization_vector): self.initialization_vector = initialization_vector + def validate_for_algorithm(self, algorithm): + if len(self.initialization_vector) * 8 != algorithm.block_size: + raise ValueError("Invalid iv size ({0}) for {1}".format( + len(self.initialization_vector), self.name + )) + @utils.register_interface(interfaces.Mode) @utils.register_interface(interfaces.ModeWithInitializationVector) @@ -48,6 +63,12 @@ class CFB(object): def __init__(self, initialization_vector): self.initialization_vector = initialization_vector + def validate_for_algorithm(self, algorithm): + if len(self.initialization_vector) * 8 != algorithm.block_size: + raise ValueError("Invalid iv size ({0}) for {1}".format( + len(self.initialization_vector), self.name + )) + @utils.register_interface(interfaces.Mode) @utils.register_interface(interfaces.ModeWithNonce) diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py index 8cc9d42c..672ac96a 100644 --- a/cryptography/hazmat/primitives/interfaces.py +++ b/cryptography/hazmat/primitives/interfaces.py @@ -39,6 +39,13 @@ class Mode(six.with_metaclass(abc.ABCMeta)): A string naming this mode. (e.g. ECB, CBC) """ + @abc.abstractmethod + def validate_for_algorithm(self, algorithm): + """ + Checks that all the necessary invariants of this (mode, algorithm) + combination are met. + """ + class ModeWithInitializationVector(six.with_metaclass(abc.ABCMeta)): @abc.abstractproperty diff --git a/docs/hazmat/primitives/interfaces.rst b/docs/hazmat/primitives/interfaces.rst index 11cff51a..e798c0e6 100644 --- a/docs/hazmat/primitives/interfaces.rst +++ b/docs/hazmat/primitives/interfaces.rst @@ -56,6 +56,18 @@ Interfaces used by the symmetric cipher modes described in The name may be used by a backend to influence the operation of a cipher in conjunction with the algorithm's name. + .. method:: validate_for_algorithm(algorithm) + + :param CipherAlgorithm algorithm: + + Checks that the combination of this mode with the provided algorithm + meets any necessary invariants. This should raise an exception if they + are not met. + + For example, the :class:`~cryptography.hazmat.primitives.modes.CBC` + mode uses this method to check that the provided initialization + vector's length matches the block size of the algorithm. + .. class:: ModeWithInitializationVector diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py index 9f27aab7..1cadc75c 100644 --- a/tests/hazmat/bindings/test_openssl.py +++ b/tests/hazmat/bindings/test_openssl.py @@ -23,7 +23,8 @@ from cryptography.hazmat.primitives.ciphers.modes import CBC class DummyMode(object): - pass + def validate_for_algorithm(self, algorithm): + pass @utils.register_interface(interfaces.CipherAlgorithm) diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py index 9460c53d..b41f8922 100644 --- a/tests/hazmat/primitives/test_block.py +++ b/tests/hazmat/primitives/test_block.py @@ -30,6 +30,11 @@ class DummyCipher(object): pass +class DummyMode(object): + def validate_for_algorithm(self, algorithm): + pass + + class TestCipher(object): def test_instantiate_without_backend(self): Cipher( @@ -101,10 +106,20 @@ class TestCipherContext(object): def test_nonexistent_cipher(self, backend): cipher = Cipher( - DummyCipher(), object(), backend + DummyCipher(), DummyMode(), backend ) with pytest.raises(UnsupportedAlgorithm): cipher.encryptor() with pytest.raises(UnsupportedAlgorithm): cipher.decryptor() + + +class TestModeValidation(object): + def test_cbc(self, backend): + with pytest.raises(ValueError): + Cipher( + algorithms.AES(b"\x00" * 16), + modes.CBC(b"abc"), + backend, + ) -- cgit v1.2.3 From 707253283ec2921bf76e2c8049eb47388d9da580 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 19 Nov 2013 16:52:32 -0800 Subject: Implement this for CTR --- cryptography/hazmat/primitives/ciphers/modes.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cryptography/hazmat/primitives/ciphers/modes.py b/cryptography/hazmat/primitives/ciphers/modes.py index 597b4e3e..f357dcf7 100644 --- a/cryptography/hazmat/primitives/ciphers/modes.py +++ b/cryptography/hazmat/primitives/ciphers/modes.py @@ -77,3 +77,10 @@ class CTR(object): def __init__(self, nonce): self.nonce = nonce + + + def validate_for_algorithm(self, algorithm): + if len(self.nonce) * 8 != algorithm.block_size: + raise ValueError("Invalid nonce size ({0}) for {1}".format( + len(self.nonce), self.name + )) -- cgit v1.2.3 From 26ebea2c5bde18aaecee5f03291606cc5799d0cc Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 19 Nov 2013 16:53:36 -0800 Subject: Tests for OFB and CFB --- tests/hazmat/primitives/test_block.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py index b41f8922..ad56f77e 100644 --- a/tests/hazmat/primitives/test_block.py +++ b/tests/hazmat/primitives/test_block.py @@ -123,3 +123,19 @@ class TestModeValidation(object): modes.CBC(b"abc"), backend, ) + + def test_ofb(self, backend): + with pytest.raises(ValueError): + Cipher( + algorithms.AES(b"\x00" * 16), + modes.OFB(b"abc"), + backend, + ) + + def test_cfb(self, backend): + with pytest.raises(ValueError): + Cipher( + algorithms.AES(b"\x00" * 16), + modes.CFB(b"abc"), + backend, + ) -- cgit v1.2.3 From 18f2c8f5da97e430387a78d6e7fe20de1c1e6ada Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 19 Nov 2013 16:57:08 -0800 Subject: test for ctr --- tests/hazmat/primitives/test_block.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py index ad56f77e..52221cb6 100644 --- a/tests/hazmat/primitives/test_block.py +++ b/tests/hazmat/primitives/test_block.py @@ -139,3 +139,11 @@ class TestModeValidation(object): modes.CFB(b"abc"), backend, ) + + def test_ctr(self, backend): + with pytest.raises(ValueError): + Cipher( + algorithms.AES(b"\x00" * 16), + modes.CFB(b"abc"), + backend, + ) -- cgit v1.2.3 From 51cd5a1534fe4d9f84563f09cf95fb4a547cf143 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 19 Nov 2013 17:03:35 -0800 Subject: flake8 --- cryptography/hazmat/primitives/ciphers/modes.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cryptography/hazmat/primitives/ciphers/modes.py b/cryptography/hazmat/primitives/ciphers/modes.py index f357dcf7..63fa163c 100644 --- a/cryptography/hazmat/primitives/ciphers/modes.py +++ b/cryptography/hazmat/primitives/ciphers/modes.py @@ -78,7 +78,6 @@ class CTR(object): def __init__(self, nonce): self.nonce = nonce - def validate_for_algorithm(self, algorithm): if len(self.nonce) * 8 != algorithm.block_size: raise ValueError("Invalid nonce size ({0}) for {1}".format( -- cgit v1.2.3 From 3c25f61c18c6f8f9a2210fb2124654023bcec775 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 19 Nov 2013 17:10:14 -0800 Subject: fixed typo --- tests/hazmat/primitives/test_block.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py index 52221cb6..e0deb36b 100644 --- a/tests/hazmat/primitives/test_block.py +++ b/tests/hazmat/primitives/test_block.py @@ -144,6 +144,6 @@ class TestModeValidation(object): with pytest.raises(ValueError): Cipher( algorithms.AES(b"\x00" * 16), - modes.CFB(b"abc"), + modes.CTR(b"abc"), backend, ) -- cgit v1.2.3 From 62aefffb1396190930074bf04c91459d1536bd0e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 16 Dec 2013 09:15:13 -0800 Subject: So the tests don't all explode --- cryptography/hazmat/primitives/ciphers/modes.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cryptography/hazmat/primitives/ciphers/modes.py b/cryptography/hazmat/primitives/ciphers/modes.py index 63a69ac4..51a1047c 100644 --- a/cryptography/hazmat/primitives/ciphers/modes.py +++ b/cryptography/hazmat/primitives/ciphers/modes.py @@ -94,3 +94,7 @@ class GCM(object): def __init__(self, initialization_vector, tag=None): self.initialization_vector = initialization_vector self.tag = tag + + def validate_for_algorithm(self, algorithm): + # TODO: figure out what this should do + pass -- cgit v1.2.3 From 71e8ca0d79d8599f1f00d6ec18cb19a2ffabfc8d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 1 Jan 2014 12:19:47 -0800 Subject: Explanatory comment --- cryptography/hazmat/primitives/ciphers/modes.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cryptography/hazmat/primitives/ciphers/modes.py b/cryptography/hazmat/primitives/ciphers/modes.py index 51a1047c..31af5d6e 100644 --- a/cryptography/hazmat/primitives/ciphers/modes.py +++ b/cryptography/hazmat/primitives/ciphers/modes.py @@ -92,9 +92,11 @@ class GCM(object): name = "GCM" def __init__(self, initialization_vector, tag=None): + # len(initialization_vector) must in [1, 2 ** 64), but it's impossible + # to actually construct a bytes object that large, so we don't check + # for it self.initialization_vector = initialization_vector self.tag = tag def validate_for_algorithm(self, algorithm): - # TODO: figure out what this should do pass -- cgit v1.2.3 From 8d3857221ba0055e625e78783a98c27fcb192199 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 4 Jan 2014 11:45:18 -0600 Subject: Instantiate our hash objects used for supported checks --- tests/hazmat/primitives/test_hash_vectors.py | 16 ++++++++-------- tests/hazmat/primitives/test_hashes.py | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/hazmat/primitives/test_hash_vectors.py b/tests/hazmat/primitives/test_hash_vectors.py index 13ffc3fd..ca97fc11 100644 --- a/tests/hazmat/primitives/test_hash_vectors.py +++ b/tests/hazmat/primitives/test_hash_vectors.py @@ -24,7 +24,7 @@ from ...utils import load_hash_vectors @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.SHA1), + only_if=lambda backend: backend.hash_supported(hashes.SHA1()), skip_message="Does not support SHA1", ) @pytest.mark.hash @@ -41,7 +41,7 @@ class TestSHA1(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.SHA224), + only_if=lambda backend: backend.hash_supported(hashes.SHA224()), skip_message="Does not support SHA224", ) @pytest.mark.hash @@ -58,7 +58,7 @@ class TestSHA224(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.SHA256), + only_if=lambda backend: backend.hash_supported(hashes.SHA256()), skip_message="Does not support SHA256", ) @pytest.mark.hash @@ -75,7 +75,7 @@ class TestSHA256(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.SHA384), + only_if=lambda backend: backend.hash_supported(hashes.SHA384()), skip_message="Does not support SHA384", ) @pytest.mark.hash @@ -92,7 +92,7 @@ class TestSHA384(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.SHA512), + only_if=lambda backend: backend.hash_supported(hashes.SHA512()), skip_message="Does not support SHA512", ) @pytest.mark.hash @@ -109,7 +109,7 @@ class TestSHA512(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.RIPEMD160), + only_if=lambda backend: backend.hash_supported(hashes.RIPEMD160()), skip_message="Does not support RIPEMD160", ) @pytest.mark.hash @@ -130,7 +130,7 @@ class TestRIPEMD160(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.Whirlpool), + only_if=lambda backend: backend.hash_supported(hashes.Whirlpool()), skip_message="Does not support Whirlpool", ) @pytest.mark.hash @@ -153,7 +153,7 @@ class TestWhirlpool(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.MD5), + only_if=lambda backend: backend.hash_supported(hashes.MD5()), skip_message="Does not support MD5", ) @pytest.mark.hash diff --git a/tests/hazmat/primitives/test_hashes.py b/tests/hazmat/primitives/test_hashes.py index c907ef61..9ca2feee 100644 --- a/tests/hazmat/primitives/test_hashes.py +++ b/tests/hazmat/primitives/test_hashes.py @@ -70,7 +70,7 @@ class TestHashContext(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.SHA1), + only_if=lambda backend: backend.hash_supported(hashes.SHA1()), skip_message="Does not support SHA1", ) @pytest.mark.hash @@ -83,7 +83,7 @@ class TestSHA1(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.SHA224), + only_if=lambda backend: backend.hash_supported(hashes.SHA224()), skip_message="Does not support SHA224", ) @pytest.mark.hash @@ -96,7 +96,7 @@ class TestSHA224(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.SHA256), + only_if=lambda backend: backend.hash_supported(hashes.SHA256()), skip_message="Does not support SHA256", ) @pytest.mark.hash @@ -109,7 +109,7 @@ class TestSHA256(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.SHA384), + only_if=lambda backend: backend.hash_supported(hashes.SHA384()), skip_message="Does not support SHA384", ) @pytest.mark.hash @@ -122,7 +122,7 @@ class TestSHA384(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.SHA512), + only_if=lambda backend: backend.hash_supported(hashes.SHA512()), skip_message="Does not support SHA512", ) @pytest.mark.hash @@ -135,7 +135,7 @@ class TestSHA512(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.RIPEMD160), + only_if=lambda backend: backend.hash_supported(hashes.RIPEMD160()), skip_message="Does not support RIPEMD160", ) @pytest.mark.hash @@ -148,7 +148,7 @@ class TestRIPEMD160(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.Whirlpool), + only_if=lambda backend: backend.hash_supported(hashes.Whirlpool()), skip_message="Does not support Whirlpool", ) @pytest.mark.hash @@ -161,7 +161,7 @@ class TestWhirlpool(object): @pytest.mark.supported( - only_if=lambda backend: backend.hash_supported(hashes.MD5), + only_if=lambda backend: backend.hash_supported(hashes.MD5()), skip_message="Does not support MD5", ) @pytest.mark.hash -- cgit v1.2.3 From 24684cababdd46dbc715087ff6a6fdb7f1cec8ec Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 4 Jan 2014 11:51:40 -0600 Subject: instantiate hash objects for hmac checks too --- tests/hazmat/primitives/test_hmac.py | 2 +- tests/hazmat/primitives/test_hmac_vectors.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/hazmat/primitives/test_hmac.py b/tests/hazmat/primitives/test_hmac.py index 04913af6..dd9cdaab 100644 --- a/tests/hazmat/primitives/test_hmac.py +++ b/tests/hazmat/primitives/test_hmac.py @@ -34,7 +34,7 @@ class UnsupportedDummyHash(object): @pytest.mark.supported( - only_if=lambda backend: backend.hmac_supported(hashes.MD5), + only_if=lambda backend: backend.hmac_supported(hashes.MD5()), skip_message="Does not support MD5", ) @pytest.mark.hmac diff --git a/tests/hazmat/primitives/test_hmac_vectors.py b/tests/hazmat/primitives/test_hmac_vectors.py index c5644459..0792080b 100644 --- a/tests/hazmat/primitives/test_hmac_vectors.py +++ b/tests/hazmat/primitives/test_hmac_vectors.py @@ -22,7 +22,7 @@ from ...utils import load_hash_vectors @pytest.mark.supported( - only_if=lambda backend: backend.hmac_supported(hashes.MD5), + only_if=lambda backend: backend.hmac_supported(hashes.MD5()), skip_message="Does not support MD5", ) @pytest.mark.hmac @@ -38,7 +38,7 @@ class TestHMAC_MD5(object): @pytest.mark.supported( - only_if=lambda backend: backend.hmac_supported(hashes.SHA1), + only_if=lambda backend: backend.hmac_supported(hashes.SHA1()), skip_message="Does not support SHA1", ) @pytest.mark.hmac @@ -54,7 +54,7 @@ class TestHMAC_SHA1(object): @pytest.mark.supported( - only_if=lambda backend: backend.hmac_supported(hashes.SHA224), + only_if=lambda backend: backend.hmac_supported(hashes.SHA224()), skip_message="Does not support SHA224", ) @pytest.mark.hmac @@ -70,7 +70,7 @@ class TestHMAC_SHA224(object): @pytest.mark.supported( - only_if=lambda backend: backend.hmac_supported(hashes.SHA256), + only_if=lambda backend: backend.hmac_supported(hashes.SHA256()), skip_message="Does not support SHA256", ) @pytest.mark.hmac @@ -86,7 +86,7 @@ class TestHMAC_SHA256(object): @pytest.mark.supported( - only_if=lambda backend: backend.hmac_supported(hashes.SHA384), + only_if=lambda backend: backend.hmac_supported(hashes.SHA384()), skip_message="Does not support SHA384", ) @pytest.mark.hmac @@ -102,7 +102,7 @@ class TestHMAC_SHA384(object): @pytest.mark.supported( - only_if=lambda backend: backend.hmac_supported(hashes.SHA512), + only_if=lambda backend: backend.hmac_supported(hashes.SHA512()), skip_message="Does not support SHA512", ) @pytest.mark.hmac @@ -118,7 +118,7 @@ class TestHMAC_SHA512(object): @pytest.mark.supported( - only_if=lambda backend: backend.hmac_supported(hashes.RIPEMD160), + only_if=lambda backend: backend.hmac_supported(hashes.RIPEMD160()), skip_message="Does not support RIPEMD160", ) @pytest.mark.hmac -- cgit v1.2.3 From f38074703c6fddabbd8cc76bec91d976d029e5ec Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 4 Jan 2014 12:28:02 -0600 Subject: refactor bindings to reduce code duplication with multiple backends --- cryptography/hazmat/bindings/openssl/binding.py | 74 ++++++------------------- cryptography/hazmat/bindings/utils.py | 65 ++++++++++++++++++++++ 2 files changed, 81 insertions(+), 58 deletions(-) create mode 100644 cryptography/hazmat/bindings/utils.py diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py index 8b5e3449..208bbdca 100644 --- a/cryptography/hazmat/bindings/openssl/binding.py +++ b/cryptography/hazmat/bindings/openssl/binding.py @@ -13,9 +13,7 @@ from __future__ import absolute_import, division, print_function -import sys - -import cffi +from cryptography.hazmat.bindings import utils _OSX_PRE_INCLUDE = """ #ifdef __APPLE__ @@ -36,6 +34,19 @@ _OSX_POST_INCLUDE = """ """ +def verify_kwargs(includes, functions, customizations): + return { + "source": "\n".join( + [_OSX_PRE_INCLUDE] + + includes + + [_OSX_POST_INCLUDE] + + functions + + customizations + ), + "libraries": ["crypto", "ssl"], + } + + class Binding(object): """ OpenSSL API wrapper. @@ -92,58 +103,5 @@ class Binding(object): if cls.ffi is not None and cls.lib is not None: return - ffi = cffi.FFI() - includes = [] - functions = [] - macros = [] - customizations = [] - for name in cls._modules: - module_name = cls._module_prefix + name - __import__(module_name) - module = sys.modules[module_name] - - ffi.cdef(module.TYPES) - - macros.append(module.MACROS) - functions.append(module.FUNCTIONS) - includes.append(module.INCLUDES) - customizations.append(module.CUSTOMIZATIONS) - - # loop over the functions & macros after declaring all the types - # so we can set interdependent types in different files and still - # have them all defined before we parse the funcs & macros - for func in functions: - ffi.cdef(func) - for macro in macros: - ffi.cdef(macro) - - # 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 - # to re-declare a function if it has the same signature. That is: - # int foo(int); - # int foo(int); - # is legal, but the following will fail to compile: - # int foo(int); - # int foo(short); - - lib = ffi.verify( - source="\n".join( - [_OSX_PRE_INCLUDE] + - includes + - [_OSX_POST_INCLUDE] + - functions + - customizations - ), - libraries=["crypto", "ssl"], - ) - - for name in cls._modules: - module_name = cls._module_prefix + name - module = sys.modules[module_name] - for condition, names in module.CONDITIONAL_NAMES.items(): - if not getattr(lib, condition): - for name in names: - delattr(lib, name) - - cls.ffi = ffi - cls.lib = lib + cls.ffi, cls.lib = utils.build_ffi(cls._modules, cls._module_prefix, + verify_kwargs) diff --git a/cryptography/hazmat/bindings/utils.py b/cryptography/hazmat/bindings/utils.py new file mode 100644 index 00000000..02ba1f26 --- /dev/null +++ b/cryptography/hazmat/bindings/utils.py @@ -0,0 +1,65 @@ +# 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 sys + +import cffi + + +def build_ffi(modules, module_prefix, verify_kwargs): + ffi = cffi.FFI() + includes = [] + functions = [] + macros = [] + customizations = [] + for name in modules: + module_name = module_prefix + name + __import__(module_name) + module = sys.modules[module_name] + + ffi.cdef(module.TYPES) + + macros.append(module.MACROS) + functions.append(module.FUNCTIONS) + includes.append(module.INCLUDES) + customizations.append(module.CUSTOMIZATIONS) + + # loop over the functions & macros after declaring all the types + # so we can set interdependent types in different files and still + # have them all defined before we parse the funcs & macros + for func in functions: + ffi.cdef(func) + for macro in macros: + ffi.cdef(macro) + + # 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 + # to re-declare a function if it has the same signature. That is: + # int foo(int); + # int foo(int); + # is legal, but the following will fail to compile: + # int foo(int); + # int foo(short); + lib = ffi.verify(**verify_kwargs(includes, functions, customizations)) + + for name in modules: + module_name = module_prefix + name + module = sys.modules[module_name] + for condition, names in module.CONDITIONAL_NAMES.items(): + if not getattr(lib, condition): + for name in names: + delattr(lib, name) + + return ffi, lib -- cgit v1.2.3 From 24ff720b4e9b4d6299a8c7c4d5a0bbc3f377fea0 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 4 Jan 2014 12:52:20 -0600 Subject: remove verify_kwargs and replace with pre_include/post_include/libraries --- cryptography/hazmat/bindings/openssl/binding.py | 32 +++---------------------- cryptography/hazmat/bindings/utils.py | 28 ++++++++++++++++++++-- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py index 208bbdca..3fb3dc8b 100644 --- a/cryptography/hazmat/bindings/openssl/binding.py +++ b/cryptography/hazmat/bindings/openssl/binding.py @@ -34,36 +34,9 @@ _OSX_POST_INCLUDE = """ """ -def verify_kwargs(includes, functions, customizations): - return { - "source": "\n".join( - [_OSX_PRE_INCLUDE] + - includes + - [_OSX_POST_INCLUDE] + - functions + - customizations - ), - "libraries": ["crypto", "ssl"], - } - - class Binding(object): """ OpenSSL API wrapper. - - Modules listed in the ``_modules`` listed should have the following - attributes: - - * ``INCLUDES``: A string containg C includes. - * ``TYPES``: A string containing C declarations for types. - * ``FUNCTIONS``: A string containing C declarations for functions. - * ``MACROS``: A string containing C declarations for any macros. - * ``CUSTOMIZATIONS``: A string containing arbitrary top-level C code, this - can be used to do things like test for a define and provide an - alternate implementation based on that. - * ``CONDITIONAL_NAMES``: A dict mapping strings of condition names from the - library to a list of names which will not be present without the - condition. """ _module_prefix = "cryptography.hazmat.bindings.openssl." _modules = [ @@ -103,5 +76,6 @@ class Binding(object): if cls.ffi is not None and cls.lib is not None: return - cls.ffi, cls.lib = utils.build_ffi(cls._modules, cls._module_prefix, - verify_kwargs) + cls.ffi, cls.lib = utils.build_ffi(cls._module_prefix, cls._modules, + _OSX_PRE_INCLUDE, _OSX_POST_INCLUDE, + ["crypto", "ssl"]) diff --git a/cryptography/hazmat/bindings/utils.py b/cryptography/hazmat/bindings/utils.py index 02ba1f26..67f58795 100644 --- a/cryptography/hazmat/bindings/utils.py +++ b/cryptography/hazmat/bindings/utils.py @@ -18,7 +18,22 @@ import sys import cffi -def build_ffi(modules, module_prefix, verify_kwargs): +def build_ffi(module_prefix, modules, pre_include, post_include, libraries): + """ + Modules listed in the ``modules`` listed should have the following + attributes: + + * ``INCLUDES``: A string containing C includes. + * ``TYPES``: A string containing C declarations for types. + * ``FUNCTIONS``: A string containing C declarations for functions. + * ``MACROS``: A string containing C declarations for any macros. + * ``CUSTOMIZATIONS``: A string containing arbitrary top-level C code, this + can be used to do things like test for a define and provide an + alternate implementation based on that. + * ``CONDITIONAL_NAMES``: A dict mapping strings of condition names from the + library to a list of names which will not be present without the + condition. + """ ffi = cffi.FFI() includes = [] functions = [] @@ -52,7 +67,16 @@ def build_ffi(modules, module_prefix, verify_kwargs): # is legal, but the following will fail to compile: # int foo(int); # int foo(short); - lib = ffi.verify(**verify_kwargs(includes, functions, customizations)) + lib = ffi.verify( + source="\n".join( + [pre_include] + + includes + + [post_include] + + functions + + customizations + ), + libraries=libraries + ) for name in modules: module_name = module_prefix + name -- cgit v1.2.3 From ac4209a01e380abf5b0f985efdb9cb7524b512b7 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 4 Jan 2014 12:52:28 -0600 Subject: import build_ffi directly --- cryptography/hazmat/bindings/openssl/binding.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py index 3fb3dc8b..e6dde954 100644 --- a/cryptography/hazmat/bindings/openssl/binding.py +++ b/cryptography/hazmat/bindings/openssl/binding.py @@ -13,7 +13,7 @@ from __future__ import absolute_import, division, print_function -from cryptography.hazmat.bindings import utils +from cryptography.hazmat.bindings.utils import build_ffi _OSX_PRE_INCLUDE = """ #ifdef __APPLE__ @@ -76,6 +76,6 @@ class Binding(object): if cls.ffi is not None and cls.lib is not None: return - cls.ffi, cls.lib = utils.build_ffi(cls._module_prefix, cls._modules, - _OSX_PRE_INCLUDE, _OSX_POST_INCLUDE, - ["crypto", "ssl"]) + cls.ffi, cls.lib = build_ffi(cls._module_prefix, cls._modules, + _OSX_PRE_INCLUDE, _OSX_POST_INCLUDE, + ["crypto", "ssl"]) -- cgit v1.2.3 From 982d8a5f3c617106d8db767863d7da46143487d9 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 4 Jan 2014 12:54:39 -0600 Subject: fix indentation mistake --- cryptography/hazmat/bindings/openssl/binding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py index e6dde954..4f6b99ae 100644 --- a/cryptography/hazmat/bindings/openssl/binding.py +++ b/cryptography/hazmat/bindings/openssl/binding.py @@ -78,4 +78,4 @@ class Binding(object): cls.ffi, cls.lib = build_ffi(cls._module_prefix, cls._modules, _OSX_PRE_INCLUDE, _OSX_POST_INCLUDE, - ["crypto", "ssl"]) + ["crypto", "ssl"]) -- cgit v1.2.3 From 3366d8bab493386c2d10fdc6c7eca5f82ea5b515 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 4 Jan 2014 12:55:28 -0600 Subject: improve docstring --- cryptography/hazmat/bindings/utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cryptography/hazmat/bindings/utils.py b/cryptography/hazmat/bindings/utils.py index 67f58795..9e1d3937 100644 --- a/cryptography/hazmat/bindings/utils.py +++ b/cryptography/hazmat/bindings/utils.py @@ -20,8 +20,7 @@ import cffi def build_ffi(module_prefix, modules, pre_include, post_include, libraries): """ - Modules listed in the ``modules`` listed should have the following - attributes: + Modules listed in ``modules`` should have the following attributes: * ``INCLUDES``: A string containing C includes. * ``TYPES``: A string containing C declarations for types. -- cgit v1.2.3