diff options
-rw-r--r-- | docs/hazmat/primitives/asymmetric/rsa.rst | 20 | ||||
-rw-r--r-- | docs/hazmat/primitives/asymmetric/serialization.rst | 60 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/rsa.py | 27 | ||||
-rw-r--r-- | src/cryptography/hazmat/primitives/asymmetric/rsa.py | 15 | ||||
-rw-r--r-- | src/cryptography/hazmat/primitives/interfaces/__init__.py | 5 | ||||
-rw-r--r-- | src/cryptography/hazmat/primitives/serialization.py | 23 | ||||
-rw-r--r-- | src/cryptography/utils.py | 1 | ||||
-rw-r--r-- | tests/hazmat/backends/test_openssl.py | 12 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_rsa.py | 51 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_serialization.py | 23 |
10 files changed, 113 insertions, 124 deletions
diff --git a/docs/hazmat/primitives/asymmetric/rsa.rst b/docs/hazmat/primitives/asymmetric/rsa.rst index 66bb37c9..ab2fe4e5 100644 --- a/docs/hazmat/primitives/asymmetric/rsa.rst +++ b/docs/hazmat/primitives/asymmetric/rsa.rst @@ -93,8 +93,9 @@ to serialize the key. >>> from cryptography.hazmat.primitives import serialization >>> pem = private_key.dump( - ... serialization.PKCS8(serialization.Encoding.PEM), - ... serialization.BestAvailable(b'passwordgoeshere') + ... encoding=serialization.Encoding.PEM, + ... fmt=serialization.Format.PKCS8, + ... encryption_type=serialization.BestAvailableEncryption(b'mypassword') ... ) >>> pem.splitlines()[0] '-----BEGIN ENCRYPTED PRIVATE KEY-----' @@ -105,8 +106,9 @@ It is also possible to serialize without encryption using .. doctest:: >>> pem = private_key.dump( - ... serialization.TraditionalOpenSSL(serialization.Encoding.PEM), - ... serialization.NoEncryption() + ... encoding=serialization.Encoding.PEM, + ... fmt=serialization.Format.PKCS8, + ... encryption_type=serialization.NoEncryption() ... ) >>> pem.splitlines()[0] '-----BEGIN RSA PRIVATE KEY-----' @@ -532,13 +534,15 @@ Key interfaces :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers` instance. - .. method:: dump(serializer, encryption_type) + .. method:: dump(encoding, fmt, encryption_type) Dump the key to PEM encoded bytes using the serializer provided. - :param serializer: An instance of - :class:`~cryptography.hazmat.primitives.serialization.TraditionalOpenSSL` - or :class:`~cryptography.hazmat.primitives.serialization.PKCS8` + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + + :param fmt: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Format` enum. :param encryption_type: An instance of an object conforming to the :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption` diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index 68eaf021..b429766d 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -75,12 +75,12 @@ methods. .. doctest:: >>> from cryptography.hazmat.backends import default_backend - >>> from cryptography.hazmat.primitives.asymmetric import dsa, rsa + >>> from cryptography.hazmat.primitives.asymmetric import rsa >>> from cryptography.hazmat.primitives.serialization import load_pem_private_key >>> key = load_pem_private_key(pem_data, password=None, backend=default_backend()) >>> if isinstance(key, rsa.RSAPrivateKey): ... signature = sign_with_rsa_key(key, message) - ... elif isinstance(key, dsa.DSAPrivateKey): + ... elif isinstance(key, interfaces.DSAPrivateKey): ... signature = sign_with_dsa_key(key, message) ... else: ... raise TypeError @@ -283,30 +283,37 @@ DSA keys look almost identical but begin with ``ssh-dss`` rather than :raises cryptography.exceptions.UnsupportedAlgorithm: If the serialized key is of a type that is not supported. -Serializers -~~~~~~~~~~~ - -Instances of these classes can be passed to methods like -:meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization.dump`. +Serialization Formats +~~~~~~~~~~~~~~~~~~~~~ -.. class:: PKCS8(encoding) +.. class:: Format .. versionadded:: 0.8 - A serializer for the PKCS #8 format. + An enumeration for key formats. + + .. attribute:: TraditionalOpenSSL + + Frequently known as PKCS#1 format. - :param encoding: A value from the - :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + .. attribute:: PKCS8 -.. class:: TraditionalOpenSSL(encoding) +Serialization Encodings +~~~~~~~~~~~~~~~~~~~~~~~ + +.. class:: Encoding .. versionadded:: 0.8 - A serializer for the traditional OpenSSL (sometimes known as PKCS #1) - format. + An enumeration for encoding types. + + .. attribute:: PEM - :param encoding: A value from the - :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + For PEM format. This is a base64 format with delimiters. + + .. attribute:: DER + + For DER format. This is a binary format. Serialization Encryption Types @@ -320,7 +327,7 @@ Serialization Encryption Types All other classes in this section represent the available choices for encryption and have this interface. -.. class:: BestAvailable +.. class:: BestAvailableEncryption(password) Encrypt using the best available encryption for a given key's backend. This is a curated encryption choice and the algorithm may change over @@ -331,22 +338,3 @@ Serialization Encryption Types .. class:: NoEncryption Do not encrypt. - - -Utility Classes -~~~~~~~~~~~~~~~ - -.. class:: Encoding - - .. versionadded:: 0.8 - - An enumeration for encoding types. Used by :class:`PKCS8` and - :class:`TraditionalOpenSSL`. - - .. attribute:: PEM - - For PEM format. This is a base64 format with delimiters. - - .. attribute:: DER - - For DER format. This is a binary format. diff --git a/src/cryptography/hazmat/backends/openssl/rsa.py b/src/cryptography/hazmat/backends/openssl/rsa.py index 1357889f..efc1a577 100644 --- a/src/cryptography/hazmat/backends/openssl/rsa.py +++ b/src/cryptography/hazmat/backends/openssl/rsa.py @@ -22,8 +22,8 @@ from cryptography.hazmat.primitives.asymmetric.rsa import ( RSAPublicKeyWithNumbers ) from cryptography.hazmat.primitives.serialization import ( - BestAvailable, Encoding, KeySerializationEncryption, NoEncryption, PKCS8, - TraditionalOpenSSL + BestAvailableEncryption, Encoding, Format, KeySerializationEncryption, + NoEncryption ) @@ -565,18 +565,23 @@ class _RSAPrivateKey(object): ) ) - def dump(self, serializer, encryption_algorithm): - if isinstance(serializer, PKCS8): + def dump(self, encoding, fmt, encryption_algorithm): + if not isinstance(encoding, Encoding): + raise TypeError("encoding must be an item from the Encoding enum") + + if not isinstance(fmt, Format): + raise TypeError("format must be an item from the Format enum") + + # This is a temporary check until we land DER serialization. + if encoding != Encoding.PEM: + raise ValueError("Only PEM encoding is supported by this backend") + + if fmt == Format.PKCS8: write_bio = self._backend._lib.PEM_write_bio_PKCS8PrivateKey key = self._evp_pkey - elif isinstance(serializer, TraditionalOpenSSL): + elif fmt == Format.TraditionalOpenSSL: write_bio = self._backend._lib.PEM_write_bio_RSAPrivateKey key = self._rsa_cdata - else: - raise TypeError("serializer must be PKCS8 or TraditionalOpenSSL") - - if serializer.encoding != Encoding.PEM: - raise ValueError("Only PEM encoding is supported by this backend") if not isinstance(encryption_algorithm, KeySerializationEncryption): raise TypeError( @@ -588,7 +593,7 @@ class _RSAPrivateKey(object): password = b"" passlen = 0 evp_cipher = self._backend._ffi.NULL - elif isinstance(encryption_algorithm, BestAvailable): + elif isinstance(encryption_algorithm, BestAvailableEncryption): # This is a curated value that we will update over time. evp_cipher = self._backend._lib.EVP_get_cipherbyname( b"aes-256-cbc" diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py index e994a9cc..918717f3 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -50,14 +50,21 @@ class RSAPrivateKeyWithSerialization(RSAPrivateKey): """ @abc.abstractmethod - def dump(self, serializer, encryption_algorithm): + def dump(self, encoding, fmt, encryption_algorithm): """ - Returns the PEM encoded key. + Returns the dumped key. """ -# DeprecatedIn08 -RSAPrivateKeyWithNumbers = RSAPrivateKeyWithSerialization +RSAPrivateKeyWithNumbers = utils.deprecated( + RSAPrivateKeyWithSerialization, + __name__, + ( + "The RSAPrivateKeyWithNumbers interface has been renamed to " + "RSAPrivateKeyWithSerialization" + ), + utils.DeprecatedIn08 +) @six.add_metaclass(abc.ABCMeta) diff --git a/src/cryptography/hazmat/primitives/interfaces/__init__.py b/src/cryptography/hazmat/primitives/interfaces/__init__.py index 6b4241bd..f9ffae06 100644 --- a/src/cryptography/hazmat/primitives/interfaces/__init__.py +++ b/src/cryptography/hazmat/primitives/interfaces/__init__.py @@ -289,11 +289,12 @@ RSAPrivateKey = utils.deprecated( ) RSAPrivateKeyWithNumbers = utils.deprecated( - rsa.RSAPrivateKeyWithNumbers, + rsa.RSAPrivateKeyWithSerialization, __name__, ( "The RSAPrivateKeyWithNumbers interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.rsa module" + "cryptography.hazmat.primitives.asymmetric.rsa module and has been " + "renamed RSAPrivateKeyWithSerialization" ), utils.DeprecatedIn08 ) diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py index 9bfbc6b7..0d564221 100644 --- a/src/cryptography/hazmat/primitives/serialization.py +++ b/src/cryptography/hazmat/primitives/serialization.py @@ -174,24 +174,9 @@ class Encoding(Enum): DER = "DER" -class PKCS8(object): - def __init__(self, encoding): - if not isinstance(encoding, Encoding): - raise TypeError( - "Encoding must be an element from the Encoding enum" - ) - - self.encoding = encoding - - -class TraditionalOpenSSL(object): - def __init__(self, encoding): - if not isinstance(encoding, Encoding): - raise TypeError( - "Encoding must be an element from the Encoding enum" - ) - - self.encoding = encoding +class Format(Enum): + PKCS8 = "PKCS8" + TraditionalOpenSSL = "TraditionalOpenSSL" @six.add_metaclass(abc.ABCMeta) @@ -200,7 +185,7 @@ class KeySerializationEncryption(object): @utils.register_interface(KeySerializationEncryption) -class BestAvailable(object): +class BestAvailableEncryption(object): def __init__(self, password): if not isinstance(password, bytes) or len(password) == 0: raise ValueError("Password must be 1 or more bytes.") diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index 77b6d253..78dcc1ca 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -12,7 +12,6 @@ import warnings # DeprecatedIn07 objects exist. This comment exists to remind developers to # look for them when it's time for the ninth release cycle deprecation dance. -# DeprecatedIn08 objects also exist. DeprecatedIn08 = PendingDeprecationWarning diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 35b7c5c3..b5de702d 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -503,18 +503,16 @@ class TestRSAPEMSerialization(object): key = RSA_KEY_2048.private_key(backend) with pytest.raises(ValueError): key.dump( - serialization.PKCS8( - serialization.Encoding.PEM - ), - serialization.BestAvailable(password) + serialization.Encoding.PEM, + serialization.Format.PKCS8, + serialization.BestAvailableEncryption(password) ) def test_unsupported_key_encoding(self): key = RSA_KEY_2048.private_key(backend) with pytest.raises(ValueError): key.dump( - serialization.PKCS8( - serialization.Encoding.DER - ), + serialization.Encoding.DER, + serialization.Format.PKCS8, serialization.NoEncryption() ) diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 72bc08ad..a0df2f26 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -1750,9 +1750,12 @@ class TestRSAPrimeFactorRecovery(object): @pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) class TestRSAPEMWriter(object): @pytest.mark.parametrize( - ("serializer", "password"), + ("fmt", "password"), itertools.product( - [serialization.TraditionalOpenSSL, serialization.PKCS8], + [ + serialization.Format.TraditionalOpenSSL, + serialization.Format.PKCS8 + ], [ b"s", b"longerpassword", @@ -1761,12 +1764,13 @@ class TestRSAPEMWriter(object): ] ) ) - def test_dump_encrypted_pem(self, backend, serializer, password): + def test_dump_encrypted_pem(self, backend, fmt, password): key = RSA_KEY_2048.private_key(backend) _skip_if_no_serialization(key, backend) serialized = key.dump( - serializer(serialization.Encoding.PEM), - serialization.BestAvailable(password) + serialization.Encoding.PEM, + fmt, + serialization.BestAvailableEncryption(password) ) loaded_key = serialization.load_pem_private_key( serialized, password, backend @@ -1776,14 +1780,15 @@ class TestRSAPEMWriter(object): assert loaded_priv_num == priv_num @pytest.mark.parametrize( - "serializer", - (serialization.TraditionalOpenSSL, serialization.PKCS8), + "fmt", + (serialization.Format.TraditionalOpenSSL, serialization.Format.PKCS8), ) - def test_dump_unencrypted_pem(self, backend, serializer): + def test_dump_unencrypted_pem(self, backend, fmt): key = RSA_KEY_2048.private_key(backend) _skip_if_no_serialization(key, backend) serialized = key.dump( - serializer(serialization.Encoding.PEM), + serialization.Encoding.PEM, + fmt, serialization.NoEncryption() ) loaded_key = serialization.load_pem_private_key( @@ -1793,20 +1798,33 @@ class TestRSAPEMWriter(object): priv_num = key.private_numbers() assert loaded_priv_num == priv_num - def test_dump_invalid_serializer(self, backend): + def test_dump_invalid_encoding(self, backend): key = RSA_KEY_2048.private_key(backend) _skip_if_no_serialization(key, backend) with pytest.raises(TypeError): - key.dump("notaserializer", serialization.NoEncryption()) + key.dump( + "notencoding", + serialization.Format.PKCS8, + serialization.NoEncryption() + ) + + def test_dump_invalid_format(self, backend): + key = RSA_KEY_2048.private_key(backend) + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.dump( + serialization.Encoding.PEM, + "invalidformat", + serialization.NoEncryption() + ) def test_dump_invalid_encryption_algorithm(self, backend): key = RSA_KEY_2048.private_key(backend) _skip_if_no_serialization(key, backend) with pytest.raises(TypeError): key.dump( - serialization.TraditionalOpenSSL( - serialization.Encoding.PEM - ), + serialization.Encoding.PEM, + serialization.Format.TraditionalOpenSSL, "notanencalg" ) @@ -1815,8 +1833,7 @@ class TestRSAPEMWriter(object): _skip_if_no_serialization(key, backend) with pytest.raises(ValueError): key.dump( - serialization.TraditionalOpenSSL( - serialization.Encoding.PEM - ), + serialization.Encoding.PEM, + serialization.Format.TraditionalOpenSSL, DummyKeyEncryption() ) diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 2a5fb21d..fc8f8664 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -18,9 +18,8 @@ from cryptography.hazmat.backends.interfaces import ( ) from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa from cryptography.hazmat.primitives.serialization import ( - BestAvailable, Encoding, PKCS8, TraditionalOpenSSL, 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 ) @@ -1162,25 +1161,11 @@ class TestECDSASSHSerialization(object): load_ssh_public_key(ssh_key, backend) -@pytest.mark.parametrize( - "serializer", - [PKCS8, TraditionalOpenSSL] -) -class TestSerializers(object): - def test_invalid_encoding(self, serializer): - with pytest.raises(TypeError): - serializer("thing") - - def test_valid_params(self, serializer): - fmt = serializer(Encoding.PEM) - assert isinstance(fmt, (PKCS8, TraditionalOpenSSL)) - - class TestKeySerializationEncryptionTypes(object): def test_non_bytes_password(self): with pytest.raises(ValueError): - BestAvailable(object()) + BestAvailableEncryption(object()) def test_encryption_with_zero_length_password(self): with pytest.raises(ValueError): - BestAvailable(b"") + BestAvailableEncryption(b"") |