diff options
-rw-r--r-- | cryptography/hazmat/backends/interfaces.py | 12 | ||||
-rw-r--r-- | cryptography/hazmat/backends/multibackend.py | 14 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/backend.py | 18 | ||||
-rw-r--r-- | docs/hazmat/backends/interfaces.rst | 31 | ||||
-rw-r--r-- | tests/hazmat/backends/test_multibackend.py | 20 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_rsa.py | 248 |
6 files changed, 343 insertions, 0 deletions
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index ba02bbd2..524e0a5b 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -142,6 +142,18 @@ class RSABackend(object): generation. """ + @abc.abstractmethod + def load_rsa_private_numbers(self, numbers): + """ + Returns an RSAPrivateKey provider. + """ + + @abc.abstractmethod + def load_rsa_public_numbers(self, numbers): + """ + Returns an RSAPublicKey provider. + """ + @six.add_metaclass(abc.ABCMeta) class DSABackend(object): diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py index b4cb6889..f3c79376 100644 --- a/cryptography/hazmat/backends/multibackend.py +++ b/cryptography/hazmat/backends/multibackend.py @@ -178,6 +178,20 @@ class MultiBackend(object): raise UnsupportedAlgorithm("RSA is not supported by the backend.", _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) + def load_rsa_private_numbers(self, numbers): + for b in self._filtered_backends(RSABackend): + return b.load_rsa_private_numbers(numbers) + + raise UnsupportedAlgorithm("RSA is not supported by the backend", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) + + def load_rsa_public_numbers(self, numbers): + for b in self._filtered_backends(RSABackend): + return b.load_rsa_public_numbers(numbers) + + 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 4112f0e5..ffe09663 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -377,6 +377,24 @@ class Backend(object): return (public_exponent >= 3 and public_exponent & 1 != 0 and key_size >= 512) + def load_rsa_private_numbers(self, numbers): + return rsa.RSAPrivateKey( + p=numbers.p, + q=numbers.q, + private_exponent=numbers.d, + dmp1=numbers.dmp1, + dmq1=numbers.dmq1, + iqmp=numbers.iqmp, + public_exponent=numbers.public_numbers.e, + modulus=numbers.public_numbers.n + ) + + def load_rsa_public_numbers(self, numbers): + return rsa.RSAPublicKey( + public_exponent=numbers.e, + modulus=numbers.n + ) + def _new_evp_pkey(self): evp_pkey = self._lib.EVP_PKEY_new() assert evp_pkey != self._ffi.NULL diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst index c1ce621a..1a2603bc 100644 --- a/docs/hazmat/backends/interfaces.rst +++ b/docs/hazmat/backends/interfaces.rst @@ -322,6 +322,37 @@ A specific ``backend`` may provide one or more of these interfaces. :raises ValueError: When plaintext is too long for the key size. + .. method:: load_rsa_private_numbers(numbers): + + :param numbers: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers`. + + :returns: A provider of + :class:`~cryptography.hazmat.primitives.interfaces.RSAPrivateKey`. + + :raises ValueError: This is raised when the values of ``p``, ``q``, + ``private_exponent``, ``public_exponent``, or ``modulus`` do not + match the bounds specified in :rfc:`3447`. + + :raises cryptography.exceptions.UnsupportedAlgorithm: This raised when + any backend specific criteria are not met. + + .. method:: load_rsa_public_numbers(numbers): + + :param numbers: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers`. + + :returns: A provider of + :class:`~cryptography.hazmat.primitives.interfaces.RSAPublicKey`. + + :raises ValueError: This is raised when the values of + ``public_exponent`` or ``modulus`` do not match the bounds + specified in :rfc:`3447`. + + :raises cryptography.exceptions.UnsupportedAlgorithm: This raised when + any backend specific criteria are not met. + + .. class:: TraditionalOpenSSLSerializationBackend .. versionadded:: 0.3 diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index 3fa364e2..93d58483 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -113,6 +113,12 @@ class DummyRSABackend(object): def encrypt_rsa(self, public_key, plaintext, padding): pass + def load_rsa_private_numbers(self, numbers): + pass + + def load_rsa_public_numbers(self, numbers): + pass + @utils.register_interface(DSABackend) class DummyDSABackend(object): @@ -236,6 +242,10 @@ class TestMultiBackend(object): backend.decrypt_rsa("private_key", "encrypted", padding.PKCS1v15()) + backend.load_rsa_private_numbers("private_numbers") + + backend.load_rsa_public_numbers("public_numbers") + backend = MultiBackend([]) with raises_unsupported_algorithm( _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM @@ -279,6 +289,16 @@ class TestMultiBackend(object): ): backend.decrypt_rsa("private_key", "encrypted", padding.PKCS1v15()) + with raises_unsupported_algorithm( + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ): + backend.load_rsa_private_numbers("private_numbers") + + with raises_unsupported_algorithm( + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ): + backend.load_rsa_public_numbers("public_numbers") + def test_dsa(self): backend = MultiBackend([ DummyDSABackend() diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index ba668bff..a76c0ec2 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -1666,6 +1666,7 @@ class TestRSAEncryption(object): ) +@pytest.mark.rsa class TestRSANumbers(object): def test_rsa_public_numbers(self): public_numbers = rsa.RSAPublicNumbers(e=1, n=15) @@ -1778,3 +1779,250 @@ class TestRSANumbers(object): iqmp=2, public_numbers=None ) + + def test_invalid_public_numbers_argument_values(self, backend): + # Start with public_exponent=7, modulus=15. Then change one value at a + # time to test the bounds. + + # Test a modulus < 3. + + with pytest.raises(ValueError): + backend.load_rsa_public_numbers(rsa.RSAPublicNumbers(e=7, n=2)) + + # Test a public_exponent < 3 + with pytest.raises(ValueError): + backend.load_rsa_public_numbers(rsa.RSAPublicNumbers(e=1, n=15)) + + # Test a public_exponent > modulus + with pytest.raises(ValueError): + backend.load_rsa_public_numbers(rsa.RSAPublicNumbers(e=17, n=15)) + + # Test a public_exponent that is not odd. + with pytest.raises(ValueError): + backend.load_rsa_public_numbers(rsa.RSAPublicNumbers(e=16, n=15)) + + def test_invalid_private_numbers_argument_values(self, backend): + # Start with p=3, q=11, private_exponent=3, public_exponent=7, + # modulus=33, dmp1=1, dmq1=3, iqmp=2. Then change one value at + # a time to test the bounds. + + # Test a modulus < 3. + with pytest.raises(ValueError): + backend.load_rsa_private_numbers( + rsa.RSAPrivateNumbers( + p=3, + q=11, + d=3, + dmp1=1, + dmq1=3, + iqmp=2, + public_numbers=rsa.RSAPublicNumbers( + e=7, + n=2 + ) + ) + ) + + # Test a modulus != p * q. + with pytest.raises(ValueError): + backend.load_rsa_private_numbers( + rsa.RSAPrivateNumbers( + p=3, + q=11, + d=3, + dmp1=1, + dmq1=3, + iqmp=2, + public_numbers=rsa.RSAPublicNumbers( + e=7, + n=35 + ) + ) + ) + + # Test a p > modulus. + with pytest.raises(ValueError): + backend.load_rsa_private_numbers( + rsa.RSAPrivateNumbers( + p=37, + q=11, + d=3, + dmp1=1, + dmq1=3, + iqmp=2, + public_numbers=rsa.RSAPublicNumbers( + e=7, + n=33 + ) + ) + ) + + # Test a q > modulus. + with pytest.raises(ValueError): + backend.load_rsa_private_numbers( + rsa.RSAPrivateNumbers( + p=3, + q=37, + d=3, + dmp1=1, + dmq1=3, + iqmp=2, + public_numbers=rsa.RSAPublicNumbers( + e=7, + n=33 + ) + ) + ) + + # Test a dmp1 > modulus. + with pytest.raises(ValueError): + backend.load_rsa_private_numbers( + rsa.RSAPrivateNumbers( + p=3, + q=11, + d=3, + dmp1=35, + dmq1=3, + iqmp=2, + public_numbers=rsa.RSAPublicNumbers( + e=7, + n=33 + ) + ) + ) + + # Test a dmq1 > modulus. + with pytest.raises(ValueError): + backend.load_rsa_private_numbers( + rsa.RSAPrivateNumbers( + p=3, + q=11, + d=3, + dmp1=1, + dmq1=35, + iqmp=2, + public_numbers=rsa.RSAPublicNumbers( + e=7, + n=33 + ) + ) + ) + + # Test an iqmp > modulus. + with pytest.raises(ValueError): + backend.load_rsa_private_numbers( + rsa.RSAPrivateNumbers( + p=3, + q=11, + d=3, + dmp1=1, + dmq1=3, + iqmp=35, + public_numbers=rsa.RSAPublicNumbers( + e=7, + n=33 + ) + ) + ) + + # Test a private_exponent > modulus + with pytest.raises(ValueError): + backend.load_rsa_private_numbers( + rsa.RSAPrivateNumbers( + p=3, + q=11, + d=37, + dmp1=1, + dmq1=3, + iqmp=2, + public_numbers=rsa.RSAPublicNumbers( + e=7, + n=33 + ) + ) + ) + + # Test a public_exponent < 3 + with pytest.raises(ValueError): + backend.load_rsa_private_numbers( + rsa.RSAPrivateNumbers( + p=3, + q=11, + d=3, + dmp1=1, + dmq1=3, + iqmp=2, + public_numbers=rsa.RSAPublicNumbers( + e=1, + n=33 + ) + ) + ) + + # Test a public_exponent > modulus + with pytest.raises(ValueError): + backend.load_rsa_private_numbers( + rsa.RSAPrivateNumbers( + p=3, + q=11, + d=3, + dmp1=1, + dmq1=3, + iqmp=35, + public_numbers=rsa.RSAPublicNumbers( + e=65537, + n=33 + ) + ) + ) + + # Test a public_exponent that is not odd. + with pytest.raises(ValueError): + backend.load_rsa_private_numbers( + rsa.RSAPrivateNumbers( + p=3, + q=11, + d=3, + dmp1=1, + dmq1=3, + iqmp=2, + public_numbers=rsa.RSAPublicNumbers( + e=6, + n=33 + ) + ) + ) + + # Test a dmp1 that is not odd. + with pytest.raises(ValueError): + backend.load_rsa_private_numbers( + rsa.RSAPrivateNumbers( + p=3, + q=11, + d=3, + dmp1=2, + dmq1=3, + iqmp=2, + public_numbers=rsa.RSAPublicNumbers( + e=7, + n=33 + ) + ) + ) + + # Test a dmq1 that is not odd. + with pytest.raises(ValueError): + backend.load_rsa_private_numbers( + rsa.RSAPrivateNumbers( + p=3, + q=11, + d=3, + dmp1=1, + dmq1=4, + iqmp=2, + public_numbers=rsa.RSAPublicNumbers( + e=7, + n=33 + ) + ) + ) |