From c333dbc4bfa29a1d80c1030b41cc02facd9a8325 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 24 May 2014 18:35:02 -0500 Subject: add rsa_padding_supported interface to RSABackend and OpenSSL backend --- cryptography/hazmat/backends/interfaces.py | 6 ++++ cryptography/hazmat/backends/multibackend.py | 6 ++++ cryptography/hazmat/backends/openssl/backend.py | 10 ++++++ docs/hazmat/backends/interfaces.rst | 11 ++++++ tests/hazmat/backends/test_multibackend.py | 10 ++++++ tests/hazmat/backends/test_openssl.py | 47 +++++++++++++++++++++++++ 6 files changed, 90 insertions(+) diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index 264c5afb..11b13788 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -129,6 +129,12 @@ class RSABackend(object): Returns encrypted bytes. """ + @abc.abstractmethod + def rsa_padding_supported(self, padding): + """ + Returns True if the backend supports the given padding options. + """ + @six.add_metaclass(abc.ABCMeta) class DSABackend(object): diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py index 21d307cf..21630ba8 100644 --- a/cryptography/hazmat/backends/multibackend.py +++ b/cryptography/hazmat/backends/multibackend.py @@ -164,6 +164,12 @@ class MultiBackend(object): raise UnsupportedAlgorithm("RSA is not supported by the backend.", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) + def rsa_padding_supported(self, padding): + for b in self._filtered_backends(RSABackend): + return b.rsa_padding_supported(padding) + raise UnsupportedAlgorithm("RSA is not supported by the backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) + def generate_dsa_parameters(self, key_size): for b in self._filtered_backends(DSABackend): return b.generate_dsa_parameters(key_size) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 5d9626d0..e5d6eaa1 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -534,6 +534,16 @@ class Backend(object): else: return isinstance(algorithm, hashes.SHA1) + def rsa_padding_supported(self, padding): + if isinstance(padding, PKCS1v15): + return True + elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1): + return self.mgf1_hash_supported(padding._mgf._algorithm) + elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1): + return isinstance(padding._mgf._algorithm, hashes.SHA1) + else: + return False + def generate_dsa_parameters(self, key_size): if key_size not in (1024, 2048, 3072): raise ValueError( diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst index ff389cb5..e98b9a59 100644 --- a/docs/hazmat/backends/interfaces.rst +++ b/docs/hazmat/backends/interfaces.rst @@ -263,6 +263,17 @@ A specific ``backend`` may provide one or more of these interfaces. :returns: ``True`` if the specified ``algorithm`` is supported by this backend, otherwise ``False``. + .. method:: rsa_padding_supported(padding) + + Check if the specified ``padding`` is supported by the backend. + + :param padding: An instance of an + :class:`~cryptography.hazmat.primitives.interfaces.AsymmetricPadding` + provider. + + :returns: ``True`` if the specified ``padding`` is supported by this + backend, otherwise ``False``. + .. method:: decrypt_rsa(private_key, ciphertext, padding) :param private_key: An instance of an diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index 088465a1..63d7dd23 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -101,6 +101,9 @@ class DummyRSABackend(object): def mgf1_hash_supported(self, algorithm): pass + def rsa_padding_supported(self, padding): + pass + def decrypt_rsa(self, private_key, ciphertext, padding): pass @@ -222,6 +225,8 @@ class TestMultiBackend(object): backend.mgf1_hash_supported(hashes.MD5()) + backend.rsa_padding_supported(padding.PKCS1v15()) + backend.encrypt_rsa("public_key", "encryptme", padding.PKCS1v15()) backend.decrypt_rsa("private_key", "encrypted", padding.PKCS1v15()) @@ -249,6 +254,11 @@ class TestMultiBackend(object): ): backend.mgf1_hash_supported(hashes.MD5()) + with raises_unsupported_algorithm( + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ): + backend.rsa_padding_supported(padding.PKCS1v15()) + with raises_unsupported_algorithm( _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM ): diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 19274bf8..b3432003 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -43,11 +43,20 @@ class DummyCipher(object): name = "dummy-cipher" +@utils.register_interface(interfaces.AsymmetricPadding) +class DummyPadding(object): + name = "dummy-cipher" + + @utils.register_interface(interfaces.HashAlgorithm) class DummyHash(object): name = "dummy-hash" +class DummyMGF(object): + _salt_length = 0 + + class TestOpenSSL(object): def test_backend_exists(self): assert backend @@ -300,6 +309,44 @@ class TestOpenSSLRSA(object): def test_unsupported_mgf1_hash_algorithm(self): assert backend.mgf1_hash_supported(DummyHash()) is False + def test_rsa_padding_unsupported_pss_mgf1_hash(self): + assert backend.rsa_padding_supported( + padding.PSS(mgf=padding.MGF1(DummyHash()), salt_length=0) + ) is False + + def test_rsa_padding_unsupported(self): + assert backend.rsa_padding_supported(DummyPadding()) is False + + def test_rsa_padding_supported_pkcs1v15(self): + assert backend.rsa_padding_supported(padding.PKCS1v15()) is True + + def test_rsa_padding_supported_pss(self): + assert backend.rsa_padding_supported( + padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0) + ) is True + + def test_rsa_padding_supported_oaep(self): + assert backend.rsa_padding_supported( + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA1()), + algorithm=hashes.SHA1(), + label=None + ), + ) is True + + def test_rsa_padding_unsupported_mgf(self): + assert backend.rsa_padding_supported( + padding.OAEP( + mgf=DummyMGF(), + algorithm=hashes.SHA1(), + label=None + ), + ) is False + + assert backend.rsa_padding_supported( + padding.PSS(mgf=DummyMGF(), salt_length=0) + ) is False + def test_unsupported_mgf1_hash_algorithm_decrypt(self): private_key = rsa.RSAPrivateKey.generate( public_exponent=65537, -- cgit v1.2.3