diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/hazmat/backends/test_openssl.py | 35 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_dh.py | 113 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_dsa.py | 177 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_ec.py | 246 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_rsa.py | 183 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_serialization.py | 85 |
6 files changed, 791 insertions, 48 deletions
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 0e4d75ed..ba0a2ba3 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -15,11 +15,12 @@ import pytest from cryptography import utils from cryptography.exceptions import InternalError, _Reasons +from cryptography.hazmat.backends.interfaces import RSABackend from cryptography.hazmat.backends.openssl.backend import ( Backend, backend ) from cryptography.hazmat.backends.openssl.ec import _sn_to_elliptic_curve -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import dsa, padding from cryptography.hazmat.primitives.ciphers import ( BlockCipherAlgorithm, Cipher, CipherAlgorithm @@ -27,7 +28,7 @@ from cryptography.hazmat.primitives.ciphers import ( from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import CBC, CTR, Mode -from ..primitives.fixtures_rsa import RSA_KEY_512 +from ..primitives.fixtures_rsa import RSA_KEY_2048, RSA_KEY_512 from ...utils import load_vectors_from_file, raises_unsupported_algorithm @@ -493,3 +494,33 @@ class TestOpenSSLEllipticCurve(object): def test_sn_to_elliptic_curve_not_supported(self): with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_ELLIPTIC_CURVE): _sn_to_elliptic_curve(backend, b"fake") + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +class TestRSAPEMSerialization(object): + def test_password_length_limit(self): + password = b"x" * 1024 + key = RSA_KEY_2048.private_key(backend) + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.PKCS8, + serialization.BestAvailableEncryption(password) + ) + + def test_unsupported_private_key_encoding(self): + key = RSA_KEY_2048.private_key(backend) + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.DER, + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption() + ) + + def test_unsupported_public_key_encoding(self): + key = RSA_KEY_2048.private_key(backend).public_key() + with pytest.raises(ValueError): + key.public_bytes( + serialization.Encoding.DER, + serialization.PublicFormat.SubjectPublicKeyInfo + ) diff --git a/tests/hazmat/primitives/test_dh.py b/tests/hazmat/primitives/test_dh.py new file mode 100644 index 00000000..115f3d8c --- /dev/null +++ b/tests/hazmat/primitives/test_dh.py @@ -0,0 +1,113 @@ +# 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 pytest + +from cryptography.hazmat.primitives.asymmetric import dh + + +def test_dh_parameternumbers(): + params = dh.DHParameterNumbers( + 65537, 3 + ) + + assert params.p == 65537 + assert params.g == 3 + + with pytest.raises(TypeError): + dh.DHParameterNumbers( + None, 3 + ) + + with pytest.raises(TypeError): + dh.DHParameterNumbers( + 65537, None + ) + + with pytest.raises(TypeError): + dh.DHParameterNumbers( + None, None + ) + + +def test_dh_numbers(): + params = dh.DHParameterNumbers( + 65537, 3 + ) + + public = dh.DHPublicNumbers( + 1, params + ) + + assert public.parameter_numbers is params + assert public.y == 1 + + with pytest.raises(TypeError): + dh.DHPublicNumbers( + 1, None + ) + + with pytest.raises(TypeError): + dh.DHPublicNumbers( + None, params + ) + + private = dh.DHPrivateNumbers( + 1, public + ) + + assert private.public_numbers is public + assert private.x == 1 + + with pytest.raises(TypeError): + dh.DHPrivateNumbers( + 1, None + ) + + with pytest.raises(TypeError): + dh.DHPrivateNumbers( + None, public + ) + + +def test_dh_parameter_numbers_equality(): + assert dh.DHParameterNumbers(65537, 3) == dh.DHParameterNumbers(65537, 3) + assert dh.DHParameterNumbers(6, 3) != dh.DHParameterNumbers(65537, 3) + assert dh.DHParameterNumbers(65537, 0) != dh.DHParameterNumbers(65537, 3) + assert dh.DHParameterNumbers(65537, 0) != object() + + +def test_dh_private_numbers_equality(): + params = dh.DHParameterNumbers(65537, 3) + public = dh.DHPublicNumbers(1, params) + private = dh.DHPrivateNumbers(2, public) + + assert private == dh.DHPrivateNumbers(2, public) + assert private != dh.DHPrivateNumbers(0, public) + assert private != dh.DHPrivateNumbers(2, dh.DHPublicNumbers(0, params)) + assert private != dh.DHPrivateNumbers( + 2, dh.DHPublicNumbers(1, dh.DHParameterNumbers(65537, 0)) + ) + assert private != object() + + +def test_dh_public_numbers_equality(): + params = dh.DHParameterNumbers(65537, 3) + public = dh.DHPublicNumbers(1, params) + + assert public == dh.DHPublicNumbers(1, params) + assert public != dh.DHPublicNumbers(0, params) + assert public != dh.DHPublicNumbers(1, dh.DHParameterNumbers(65537, 0)) + assert public != object() diff --git a/tests/hazmat/primitives/test_dsa.py b/tests/hazmat/primitives/test_dsa.py index 8c0fb80c..19ca0794 100644 --- a/tests/hazmat/primitives/test_dsa.py +++ b/tests/hazmat/primitives/test_dsa.py @@ -4,13 +4,17 @@ from __future__ import absolute_import, division, print_function +import itertools import os import pytest +from cryptography import utils from cryptography.exceptions import AlreadyFinalized, InvalidSignature -from cryptography.hazmat.backends.interfaces import DSABackend -from cryptography.hazmat.primitives import hashes, interfaces +from cryptography.hazmat.backends.interfaces import ( + DSABackend, PEMSerializationBackend +) +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import dsa from cryptography.hazmat.primitives.asymmetric.utils import ( encode_rfc6979_signature @@ -26,11 +30,28 @@ from ...utils import ( ) +def _skip_if_no_serialization(key, backend): + if not isinstance(key, dsa.DSAPrivateKeyWithSerialization): + pytest.skip( + "{0} does not support DSA key serialization".format(backend) + ) + + +def test_skip_if_no_serialization(): + with pytest.raises(pytest.skip.Exception): + _skip_if_no_serialization("notakeywithserialization", "backend") + + +@utils.register_interface(serialization.KeySerializationEncryption) +class DummyKeyEncryption(object): + pass + + @pytest.mark.requires_backend_interface(interface=DSABackend) class TestDSA(object): def test_generate_dsa_parameters(self, backend): parameters = dsa.generate_parameters(1024, backend) - assert isinstance(parameters, interfaces.DSAParameters) + assert isinstance(parameters, dsa.DSAParameters) def test_generate_invalid_dsa_parameters(self, backend): with pytest.raises(ValueError): @@ -51,7 +72,7 @@ class TestDSA(object): g=vector['g'] ).parameters(backend) skey = parameters.generate_private_key() - if isinstance(skey, interfaces.DSAPrivateKeyWithNumbers): + if isinstance(skey, dsa.DSAPrivateKeyWithNumbers): numbers = skey.private_numbers() skey_parameters = numbers.public_numbers.parameter_numbers pkey = skey.public_key() @@ -74,7 +95,7 @@ class TestDSA(object): def test_generate_dsa_private_key_and_parameters(self, backend): skey = dsa.generate_private_key(1024, backend) assert skey - if isinstance(skey, interfaces.DSAPrivateKeyWithNumbers): + if isinstance(skey, dsa.DSAPrivateKeyWithNumbers): numbers = skey.private_numbers() skey_parameters = numbers.public_numbers.parameter_numbers assert numbers.public_numbers.y == pow( @@ -769,3 +790,149 @@ class TestDSANumberEquality(object): ) ) assert priv != object() + + +@pytest.mark.requires_backend_interface(interface=DSABackend) +@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) +class TestDSASerialization(object): + @pytest.mark.parametrize( + ("fmt", "password"), + itertools.product( + [ + serialization.PrivateFormat.TraditionalOpenSSL, + serialization.PrivateFormat.PKCS8 + ], + [ + b"s", + b"longerpassword", + b"!*$&(@#$*&($T@%_somesymbols", + b"\x01" * 1000, + ] + ) + ) + def test_private_bytes_encrypted_pem(self, backend, fmt, password): + key_bytes = load_vectors_from_file( + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"), + lambda pemfile: pemfile.read().encode() + ) + key = serialization.load_pem_private_key(key_bytes, None, backend) + _skip_if_no_serialization(key, backend) + serialized = key.private_bytes( + serialization.Encoding.PEM, + fmt, + serialization.BestAvailableEncryption(password) + ) + loaded_key = serialization.load_pem_private_key( + serialized, password, backend + ) + loaded_priv_num = loaded_key.private_numbers() + priv_num = key.private_numbers() + assert loaded_priv_num == priv_num + + @pytest.mark.parametrize( + "fmt", + [ + serialization.PrivateFormat.TraditionalOpenSSL, + serialization.PrivateFormat.PKCS8 + ], + ) + def test_private_bytes_unencrypted_pem(self, backend, fmt): + key_bytes = load_vectors_from_file( + os.path.join( + "asymmetric", + "Traditional_OpenSSL_Serialization", + "dsa.1024.pem" + ), + lambda pemfile: pemfile.read().encode() + ) + key = serialization.load_pem_private_key(key_bytes, None, backend) + _skip_if_no_serialization(key, backend) + serialized = key.private_bytes( + serialization.Encoding.PEM, + fmt, + serialization.NoEncryption() + ) + loaded_key = serialization.load_pem_private_key( + serialized, None, backend + ) + loaded_priv_num = loaded_key.private_numbers() + priv_num = key.private_numbers() + assert loaded_priv_num == priv_num + + def test_private_bytes_traditional_openssl_unencrypted_pem(self, backend): + key_bytes = load_vectors_from_file( + os.path.join( + "asymmetric", + "Traditional_OpenSSL_Serialization", + "dsa.1024.pem" + ), + lambda pemfile: pemfile.read().encode() + ) + key = serialization.load_pem_private_key(key_bytes, None, backend) + _skip_if_no_serialization(key, backend) + serialized = key.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.TraditionalOpenSSL, + serialization.NoEncryption() + ) + assert serialized == key_bytes + + def test_private_bytes_invalid_encoding(self, backend): + key = load_vectors_from_file( + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"), + lambda pemfile: serialization.load_pem_private_key( + pemfile.read().encode(), None, backend + ) + ) + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.private_bytes( + "notencoding", + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption() + ) + + def test_private_bytes_invalid_format(self, backend): + key = load_vectors_from_file( + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"), + lambda pemfile: serialization.load_pem_private_key( + pemfile.read().encode(), None, backend + ) + ) + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.private_bytes( + serialization.Encoding.PEM, + "invalidformat", + serialization.NoEncryption() + ) + + def test_private_bytes_invalid_encryption_algorithm(self, backend): + key = load_vectors_from_file( + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"), + lambda pemfile: serialization.load_pem_private_key( + pemfile.read().encode(), None, backend + ) + ) + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.TraditionalOpenSSL, + "notanencalg" + ) + + def test_private_bytes_unsupported_encryption_type(self, backend): + key = load_vectors_from_file( + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"), + lambda pemfile: serialization.load_pem_private_key( + pemfile.read().encode(), None, backend + ) + ) + _skip_if_no_serialization(key, backend) + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.TraditionalOpenSSL, + DummyKeyEncryption() + ) diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py index ea621ad6..40b1741c 100644 --- a/tests/hazmat/primitives/test_ec.py +++ b/tests/hazmat/primitives/test_ec.py @@ -10,8 +10,10 @@ import os import pytest from cryptography import exceptions, utils -from cryptography.hazmat.backends.interfaces import EllipticCurveBackend -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.backends.interfaces import ( + EllipticCurveBackend, PEMSerializationBackend +) +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.asymmetric.utils import ( encode_rfc6979_signature @@ -31,6 +33,18 @@ _HASH_TYPES = { } +def _skip_if_no_serialization(key, backend): + if not isinstance( + key, ( + ec.EllipticCurvePrivateKeyWithSerialization, + ec.EllipticCurvePublicKeyWithSerialization + ) + ): + pytest.skip( + "{0} does not support EC key serialization".format(backend) + ) + + def _skip_ecdsa_vector(backend, curve_type, hash_type): if not backend.elliptic_curve_signature_algorithm_supported( ec.ECDSA(hash_type()), @@ -63,12 +77,22 @@ class DummySignatureAlgorithm(object): algorithm = None +@utils.register_interface(serialization.KeySerializationEncryption) +class DummyKeyEncryption(object): + pass + + @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_skip_curve_unsupported(backend): with pytest.raises(pytest.skip.Exception): _skip_curve_unsupported(backend, DummyCurve()) +def test_skip_no_serialization(): + with pytest.raises(pytest.skip.Exception): + _skip_if_no_serialization("fakebackend", "fakekey") + + def test_ec_numbers(): numbers = ec.EllipticCurvePrivateNumbers( 1, @@ -378,3 +402,221 @@ class TestECNumbersEquality(object): 1, ec.EllipticCurvePublicNumbers(1, 2, ec.SECP521R1()) ) assert priv != object() + + +@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) +@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) +class TestECSerialization(object): + @pytest.mark.parametrize( + ("fmt", "password"), + itertools.product( + [ + serialization.PrivateFormat.TraditionalOpenSSL, + serialization.PrivateFormat.PKCS8 + ], + [ + b"s", + b"longerpassword", + b"!*$&(@#$*&($T@%_somesymbols", + b"\x01" * 1000, + ] + ) + ) + def test_private_bytes_encrypted_pem(self, backend, fmt, password): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key_bytes = load_vectors_from_file( + os.path.join( + "asymmetric", "PKCS8", "ec_private_key.pem"), + lambda pemfile: pemfile.read().encode() + ) + key = serialization.load_pem_private_key(key_bytes, None, backend) + _skip_if_no_serialization(key, backend) + serialized = key.private_bytes( + serialization.Encoding.PEM, + fmt, + serialization.BestAvailableEncryption(password) + ) + loaded_key = serialization.load_pem_private_key( + serialized, password, backend + ) + loaded_priv_num = loaded_key.private_numbers() + priv_num = key.private_numbers() + assert loaded_priv_num == priv_num + + @pytest.mark.parametrize( + "fmt", + [ + serialization.PrivateFormat.TraditionalOpenSSL, + serialization.PrivateFormat.PKCS8 + ], + ) + def test_private_bytes_unencrypted_pem(self, backend, fmt): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key_bytes = load_vectors_from_file( + os.path.join( + "asymmetric", "PKCS8", "ec_private_key.pem"), + lambda pemfile: pemfile.read().encode() + ) + key = serialization.load_pem_private_key(key_bytes, None, backend) + _skip_if_no_serialization(key, backend) + serialized = key.private_bytes( + serialization.Encoding.PEM, + fmt, + serialization.NoEncryption() + ) + loaded_key = serialization.load_pem_private_key( + serialized, None, backend + ) + loaded_priv_num = loaded_key.private_numbers() + priv_num = key.private_numbers() + assert loaded_priv_num == priv_num + + def test_private_bytes_traditional_openssl_unencrypted_pem(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key_bytes = load_vectors_from_file( + os.path.join( + "asymmetric", "PEM_Serialization", "ec_private_key.pem"), + lambda pemfile: pemfile.read().encode() + ) + key = serialization.load_pem_private_key(key_bytes, None, backend) + serialized = key.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.TraditionalOpenSSL, + serialization.NoEncryption() + ) + assert serialized == key_bytes + + def test_private_bytes_invalid_encoding(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PKCS8", "ec_private_key.pem"), + lambda pemfile: serialization.load_pem_private_key( + pemfile.read().encode(), None, backend + ) + ) + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.private_bytes( + "notencoding", + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption() + ) + + def test_private_bytes_invalid_format(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PKCS8", "ec_private_key.pem"), + lambda pemfile: serialization.load_pem_private_key( + pemfile.read().encode(), None, backend + ) + ) + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.private_bytes( + serialization.Encoding.PEM, + "invalidformat", + serialization.NoEncryption() + ) + + def test_private_bytes_invalid_encryption_algorithm(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PKCS8", "ec_private_key.pem"), + lambda pemfile: serialization.load_pem_private_key( + pemfile.read().encode(), None, backend + ) + ) + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.TraditionalOpenSSL, + "notanencalg" + ) + + def test_private_bytes_unsupported_encryption_type(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PKCS8", "ec_private_key.pem"), + lambda pemfile: serialization.load_pem_private_key( + pemfile.read().encode(), None, backend + ) + ) + _skip_if_no_serialization(key, backend) + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.TraditionalOpenSSL, + DummyKeyEncryption() + ) + + +@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) +@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) +class TestEllipticCurvePEMPublicKeySerialization(object): + def test_public_bytes_unencrypted_pem(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key_bytes = load_vectors_from_file( + os.path.join( + "asymmetric", "PEM_Serialization", "ec_public_key.pem" + ), + lambda pemfile: pemfile.read().encode() + ) + key = serialization.load_pem_public_key(key_bytes, backend) + _skip_if_no_serialization(key, backend) + serialized = key.public_bytes( + serialization.Encoding.PEM, + serialization.PublicFormat.SubjectPublicKeyInfo, + ) + assert serialized == key_bytes + + def test_public_bytes_invalid_encoding(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PEM_Serialization", "ec_public_key.pem" + ), + lambda pemfile: serialization.load_pem_public_key( + pemfile.read().encode(), backend + ) + ) + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.public_bytes( + "notencoding", + serialization.PublicFormat.SubjectPublicKeyInfo + ) + + def test_public_bytes_invalid_format(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PEM_Serialization", "ec_public_key.pem" + ), + lambda pemfile: serialization.load_pem_public_key( + pemfile.read().encode(), backend + ) + ) + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.public_bytes(serialization.Encoding.PEM, "invalidformat") + + def test_public_bytes_pkcs1_unsupported(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key = load_vectors_from_file( + os.path.join( + "asymmetric", "PEM_Serialization", "ec_public_key.pem" + ), + lambda pemfile: serialization.load_pem_public_key( + pemfile.read().encode(), backend + ) + ) + _skip_if_no_serialization(key, backend) + with pytest.raises(ValueError): + key.public_bytes( + serialization.Encoding.PEM, serialization.PublicFormat.PKCS1 + ) diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 6d8e6874..e6d0ac28 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -15,8 +15,10 @@ from cryptography import utils from cryptography.exceptions import ( AlreadyFinalized, InvalidSignature, _Reasons ) -from cryptography.hazmat.backends.interfaces import RSABackend -from cryptography.hazmat.primitives import hashes, interfaces +from cryptography.hazmat.backends.interfaces import ( + PEMSerializationBackend, RSABackend +) +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding, rsa from cryptography.hazmat.primitives.asymmetric.rsa import ( RSAPrivateNumbers, RSAPublicNumbers @@ -46,6 +48,11 @@ class DummyMGF(object): _salt_length = 0 +@utils.register_interface(serialization.KeySerializationEncryption) +class DummyKeyEncryption(object): + pass + + def _flatten_pkcs1_examples(vectors): flattened_vectors = [] for vector in vectors: @@ -78,6 +85,21 @@ def test_modular_inverse(): ) +def _skip_if_no_serialization(key, backend): + if not isinstance( + key, + (rsa.RSAPrivateKeyWithSerialization, rsa.RSAPublicKeyWithSerialization) + ): + pytest.skip( + "{0} does not support RSA key serialization".format(backend) + ) + + +def test_skip_if_no_serialization(): + with pytest.raises(pytest.skip.Exception): + _skip_if_no_serialization("notakeywithserialization", "backend") + + @pytest.mark.requires_backend_interface(interface=RSABackend) class TestRSA(object): @pytest.mark.parametrize( @@ -91,7 +113,7 @@ class TestRSA(object): skey = rsa.generate_private_key(public_exponent, key_size, backend) assert skey.key_size == key_size - if isinstance(skey, interfaces.RSAPrivateKeyWithNumbers): + if isinstance(skey, rsa.RSAPrivateKeyWithNumbers): _check_rsa_private_numbers(skey.private_numbers()) pkey = skey.public_key() assert isinstance(pkey.public_numbers(), rsa.RSAPublicNumbers) @@ -1725,3 +1747,158 @@ class TestRSAPrimeFactorRecovery(object): def test_invalid_recover_prime_factors(self): with pytest.raises(ValueError): rsa.rsa_recover_prime_factors(34, 3, 7) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) +class TestRSAPEMPrivateKeySerialization(object): + @pytest.mark.parametrize( + ("fmt", "password"), + itertools.product( + [ + serialization.PrivateFormat.TraditionalOpenSSL, + serialization.PrivateFormat.PKCS8 + ], + [ + b"s", + b"longerpassword", + b"!*$&(@#$*&($T@%_somesymbols", + b"\x01" * 1000, + ] + ) + ) + def test_private_bytes_encrypted_pem(self, backend, fmt, password): + key = RSA_KEY_2048.private_key(backend) + _skip_if_no_serialization(key, backend) + serialized = key.private_bytes( + serialization.Encoding.PEM, + fmt, + serialization.BestAvailableEncryption(password) + ) + loaded_key = serialization.load_pem_private_key( + serialized, password, backend + ) + loaded_priv_num = loaded_key.private_numbers() + priv_num = key.private_numbers() + assert loaded_priv_num == priv_num + + @pytest.mark.parametrize( + "fmt", + [ + serialization.PrivateFormat.TraditionalOpenSSL, + serialization.PrivateFormat.PKCS8 + ], + ) + def test_private_bytes_unencrypted_pem(self, backend, fmt): + key = RSA_KEY_2048.private_key(backend) + _skip_if_no_serialization(key, backend) + serialized = key.private_bytes( + serialization.Encoding.PEM, + fmt, + serialization.NoEncryption() + ) + loaded_key = serialization.load_pem_private_key( + serialized, None, backend + ) + loaded_priv_num = loaded_key.private_numbers() + priv_num = key.private_numbers() + assert loaded_priv_num == priv_num + + def test_private_bytes_traditional_openssl_unencrypted_pem(self, backend): + key_bytes = load_vectors_from_file( + os.path.join( + "asymmetric", + "Traditional_OpenSSL_Serialization", + "testrsa.pem" + ), + lambda pemfile: pemfile.read().encode() + ) + key = serialization.load_pem_private_key(key_bytes, None, backend) + serialized = key.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.TraditionalOpenSSL, + serialization.NoEncryption() + ) + assert serialized == key_bytes + + def test_private_bytes_invalid_encoding(self, backend): + key = RSA_KEY_2048.private_key(backend) + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.private_bytes( + "notencoding", + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption() + ) + + def test_private_bytes_invalid_format(self, backend): + key = RSA_KEY_2048.private_key(backend) + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.private_bytes( + serialization.Encoding.PEM, + "invalidformat", + serialization.NoEncryption() + ) + + def test_private_bytes_invalid_encryption_algorithm(self, backend): + key = RSA_KEY_2048.private_key(backend) + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.TraditionalOpenSSL, + "notanencalg" + ) + + def test_private_bytes_unsupported_encryption_type(self, backend): + key = RSA_KEY_2048.private_key(backend) + _skip_if_no_serialization(key, backend) + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.TraditionalOpenSSL, + DummyKeyEncryption() + ) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) +class TestRSAPEMPublicKeySerialization(object): + def test_public_bytes_unencrypted_pem(self, backend): + key_bytes = load_vectors_from_file( + os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), + lambda pemfile: pemfile.read().encode() + ) + key = serialization.load_pem_public_key(key_bytes, backend) + _skip_if_no_serialization(key, backend) + serialized = key.public_bytes( + serialization.Encoding.PEM, + serialization.PublicFormat.SubjectPublicKeyInfo, + ) + assert serialized == key_bytes + + def test_public_bytes_pkcs1_unencrypted_pem(self, backend): + key_bytes = load_vectors_from_file( + os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.pem"), + lambda pemfile: pemfile.read().encode() + ) + key = serialization.load_pem_public_key(key_bytes, backend) + _skip_if_no_serialization(key, backend) + serialized = key.public_bytes( + serialization.Encoding.PEM, + serialization.PublicFormat.PKCS1, + ) + assert serialized == key_bytes + + def test_public_bytes_invalid_encoding(self, backend): + key = RSA_KEY_2048.private_key(backend).public_key() + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.public_bytes("notencoding", serialization.PublicFormat.PKCS1) + + def test_public_bytes_invalid_format(self, backend): + key = RSA_KEY_2048.private_key(backend).public_key() + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.public_bytes(serialization.Encoding.PEM, "invalidformat") diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index a4a91430..07a8f02e 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -16,15 +16,10 @@ from cryptography.hazmat.backends.interfaces import ( DERSerializationBackend, DSABackend, EllipticCurveBackend, PEMSerializationBackend, RSABackend ) -from cryptography.hazmat.primitives import interfaces -from cryptography.hazmat.primitives.asymmetric import ec -from cryptography.hazmat.primitives.asymmetric.dsa import ( - DSAParameterNumbers, DSAPublicNumbers -) -from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers +from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa from cryptography.hazmat.primitives.serialization import ( - load_der_private_key, load_der_public_key, load_pem_private_key, - load_pem_public_key, load_ssh_public_key + BestAvailableEncryption, load_der_private_key, load_der_public_key, + load_pem_private_key, load_pem_public_key, load_ssh_public_key ) @@ -57,8 +52,8 @@ class TestDERSerialization(object): mode="rb" ) assert key - assert isinstance(key, interfaces.RSAPrivateKey) - if isinstance(key, interfaces.RSAPrivateKeyWithNumbers): + assert isinstance(key, rsa.RSAPrivateKey) + if isinstance(key, rsa.RSAPrivateKeyWithNumbers): _check_rsa_private_numbers(key.private_numbers()) @pytest.mark.requires_backend_interface(interface=DSABackend) @@ -80,8 +75,8 @@ class TestDERSerialization(object): mode="rb" ) assert key - assert isinstance(key, interfaces.DSAPrivateKey) - if isinstance(key, interfaces.DSAPrivateKeyWithNumbers): + assert isinstance(key, dsa.DSAPrivateKey) + if isinstance(key, dsa.DSAPrivateKeyWithNumbers): _check_dsa_private_numbers(key.private_numbers()) @pytest.mark.parametrize( @@ -103,7 +98,7 @@ class TestDERSerialization(object): ) assert key - assert isinstance(key, interfaces.EllipticCurvePrivateKey) + assert isinstance(key, ec.EllipticCurvePrivateKey) assert key.curve.name == "secp256r1" assert key.curve.key_size == 256 @@ -238,6 +233,7 @@ class TestDERSerialization(object): "asymmetric", "DER_Serialization", "unenc-rsa-pkcs8.pub.der"), os.path.join( "asymmetric", "DER_Serialization", "rsa_public_key.der"), + os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.der"), ] ) @pytest.mark.requires_backend_interface(interface=RSABackend) @@ -250,8 +246,8 @@ class TestDERSerialization(object): mode="rb" ) assert key - assert isinstance(key, interfaces.RSAPublicKey) - if isinstance(key, interfaces.RSAPublicKeyWithNumbers): + assert isinstance(key, rsa.RSAPublicKey) + if isinstance(key, rsa.RSAPublicKeyWithNumbers): numbers = key.public_numbers() assert numbers.e == 65537 @@ -278,7 +274,7 @@ class TestDERSerialization(object): mode="rb" ) assert key - assert isinstance(key, interfaces.DSAPublicKey) + assert isinstance(key, dsa.DSAPublicKey) @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_load_ec_public_key(self, backend): @@ -293,7 +289,7 @@ class TestDERSerialization(object): mode="rb" ) assert key - assert isinstance(key, interfaces.EllipticCurvePublicKey) + assert isinstance(key, ec.EllipticCurvePublicKey) assert key.curve.name == "secp256r1" assert key.curve.key_size == 256 @@ -333,8 +329,8 @@ class TestPEMSerialization(object): ) assert key - assert isinstance(key, interfaces.RSAPrivateKey) - if isinstance(key, interfaces.RSAPrivateKeyWithNumbers): + assert isinstance(key, rsa.RSAPrivateKey) + if isinstance(key, rsa.RSAPrivateKeyWithNumbers): _check_rsa_private_numbers(key.private_numbers()) @pytest.mark.parametrize( @@ -355,8 +351,8 @@ class TestPEMSerialization(object): ) ) assert key - assert isinstance(key, interfaces.DSAPrivateKey) - if isinstance(key, interfaces.DSAPrivateKeyWithNumbers): + assert isinstance(key, dsa.DSAPrivateKey) + if isinstance(key, dsa.DSAPrivateKeyWithNumbers): _check_dsa_private_numbers(key.private_numbers()) @pytest.mark.parametrize( @@ -379,7 +375,7 @@ class TestPEMSerialization(object): ) assert key - assert isinstance(key, interfaces.EllipticCurvePrivateKey) + assert isinstance(key, ec.EllipticCurvePrivateKey) assert key.curve.name == "secp256r1" assert key.curve.key_size == 256 @@ -389,6 +385,7 @@ class TestPEMSerialization(object): os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), os.path.join( "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), + os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.pem"), ] ) def test_load_pem_rsa_public_key(self, key_file, backend): @@ -399,8 +396,8 @@ class TestPEMSerialization(object): ) ) assert key - assert isinstance(key, interfaces.RSAPublicKey) - if isinstance(key, interfaces.RSAPublicKeyWithNumbers): + assert isinstance(key, rsa.RSAPublicKey) + if isinstance(key, rsa.RSAPublicKeyWithNumbers): numbers = key.public_numbers() assert numbers.e == 65537 @@ -421,7 +418,7 @@ class TestPEMSerialization(object): ) ) assert key - assert isinstance(key, interfaces.DSAPublicKey) + assert isinstance(key, dsa.DSAPublicKey) @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_load_ec_public_key(self, backend): @@ -435,7 +432,7 @@ class TestPEMSerialization(object): ) ) assert key - assert isinstance(key, interfaces.EllipticCurvePublicKey) + assert isinstance(key, ec.EllipticCurvePublicKey) assert key.curve.name == "secp256r1" assert key.curve.key_size == 256 @@ -542,7 +539,7 @@ class TestPEMSerialization(object): ) ) - def test_wrong_format(self, backend): + def test_wrong_private_format(self, backend): key_data = b"---- NOT A KEY ----\n" with pytest.raises(ValueError): @@ -555,6 +552,12 @@ class TestPEMSerialization(object): key_data, b"this password will not be used", backend ) + def test_wrong_public_format(self, backend): + key_data = b"---- NOT A KEY ----\n" + + with pytest.raises(ValueError): + load_pem_public_key(key_data, backend) + def test_corrupt_traditional_format(self, backend): # privkey.pem with a bunch of data missing. key_data = textwrap.dedent("""\ @@ -762,12 +765,12 @@ class TestPEMSerialization(object): ) ) assert key - assert isinstance(key, interfaces.DSAPrivateKey) + assert isinstance(key, dsa.DSAPrivateKey) params = key.parameters() - assert isinstance(params, interfaces.DSAParameters) + assert isinstance(params, dsa.DSAParameters) - if isinstance(params, interfaces.DSAParametersWithNumbers): + if isinstance(params, dsa.DSAParametersWithNumbers): num = key.private_numbers() pub = num.public_numbers parameter_numbers = pub.parameter_numbers @@ -917,7 +920,7 @@ class TestRSASSHSerialization(object): key = load_ssh_public_key(ssh_key, backend) assert key is not None - assert isinstance(key, interfaces.RSAPublicKey) + assert isinstance(key, rsa.RSAPublicKey) numbers = key.public_numbers() @@ -934,7 +937,7 @@ class TestRSASSHSerialization(object): '46F8706AB88DDADBD9E8204D48B87789081E074024C8996783B31' '7076A98ABF0A2D8550EAF2097D8CCC7BE76EF', 16) - expected = RSAPublicNumbers(expected_e, expected_n) + expected = rsa.RSAPublicNumbers(expected_e, expected_n) assert numbers == expected @@ -1017,7 +1020,7 @@ class TestDSSSSHSerialization(object): key = load_ssh_public_key(ssh_key, backend) assert key is not None - assert isinstance(key, interfaces.DSAPublicKey) + assert isinstance(key, dsa.DSAPublicKey) numbers = key.public_numbers() @@ -1043,9 +1046,9 @@ class TestDSSSSHSerialization(object): "debb5982fc94d6a8c291f758feae63ad769a5621947221522a2dc31d18ede6f" "b656", 16 ) - expected = DSAPublicNumbers( + expected = dsa.DSAPublicNumbers( expected_y, - DSAParameterNumbers(expected_p, expected_q, expected_g) + dsa.DSAParameterNumbers(expected_p, expected_q, expected_g) ) assert numbers == expected @@ -1062,7 +1065,7 @@ class TestECDSASSHSerialization(object): b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01" ) key = load_ssh_public_key(ssh_key, backend) - assert isinstance(key, interfaces.EllipticCurvePublicKey) + assert isinstance(key, ec.EllipticCurvePublicKey) expected_x = int( "44196257377740326295529888716212621920056478823906609851236662550" @@ -1164,3 +1167,13 @@ class TestECDSASSHSerialization(object): ) with pytest.raises(ValueError): load_ssh_public_key(ssh_key, backend) + + +class TestKeySerializationEncryptionTypes(object): + def test_non_bytes_password(self): + with pytest.raises(ValueError): + BestAvailableEncryption(object()) + + def test_encryption_with_zero_length_password(self): + with pytest.raises(ValueError): + BestAvailableEncryption(b"") |