Repository: pyca/cryptography

Issue:
MultiBackend doesn't actually provide RSABackend.
We've been kind of haphazardly adding things to the interface as we add features and it's resulted in an incompletely implementation of MultiBackend.



Discussion:

Resolving patch:
diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py
--- a/cryptography/hazmat/backends/multibackend.py
+++ b/cryptography/hazmat/backends/multibackend.py
@@ -146,6 +146,24 @@ def create_rsa_verification_ctx(self, public_key, signature, padding,
         raise UnsupportedAlgorithm("RSA is not supported by the backend",
                                    _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
 
+    def mgf1_hash_supported(self, algorithm):
+        for b in self._filtered_backends(RSABackend):
+            return b.mgf1_hash_supported(algorithm)
+        raise UnsupportedAlgorithm("RSA is not supported by the backend",
+                                   _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+    def decrypt_rsa(self, private_key, ciphertext, padding):
+        for b in self._filtered_backends(RSABackend):
+            return b.decrypt_rsa(private_key, ciphertext, padding)
+        raise UnsupportedAlgorithm("RSA is not supported by the backend",
+                                   _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+    def encrypt_rsa(self, public_key, plaintext, padding):
+        for b in self._filtered_backends(RSABackend):
+            return b.encrypt_rsa(public_key, plaintext, 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)


Test patch:
diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py
--- a/tests/hazmat/backends/test_multibackend.py
+++ b/tests/hazmat/backends/test_multibackend.py
@@ -98,6 +98,15 @@ def create_rsa_verification_ctx(self, public_key, signature, padding,
                                     algorithm):
         pass
 
+    def mgf1_hash_supported(self, algorithm):
+        pass
+
+    def decrypt_rsa(self, private_key, ciphertext, padding):
+        pass
+
+    def encrypt_rsa(self, public_key, plaintext, padding):
+        pass
+
 
 @utils.register_interface(DSABackend)
 class DummyDSABackend(object):
@@ -211,6 +220,12 @@ def test_rsa(self):
         backend.create_rsa_verification_ctx("public_key", "sig",
                                             padding.PKCS1v15(), hashes.MD5())
 
+        backend.mgf1_hash_supported(hashes.MD5())
+
+        backend.encrypt_rsa("public_key", "encryptme", padding.PKCS1v15())
+
+        backend.decrypt_rsa("private_key", "encrypted", padding.PKCS1v15())
+
         backend = MultiBackend([])
         with raises_unsupported_algorithm(
             _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
@@ -229,6 +244,21 @@ def test_rsa(self):
             backend.create_rsa_verification_ctx(
                 "public_key", "sig", padding.PKCS1v15(), hashes.MD5())
 
+        with raises_unsupported_algorithm(
+            _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+        ):
+            backend.mgf1_hash_supported(hashes.MD5())
+
+        with raises_unsupported_algorithm(
+            _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+        ):
+            backend.encrypt_rsa("public_key", "encryptme", padding.PKCS1v15())
+
+        with raises_unsupported_algorithm(
+            _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+        ):
+            backend.decrypt_rsa("private_key", "encrypted", padding.PKCS1v15())
+
     def test_dsa(self):
         backend = MultiBackend([
             DummyDSABackend()