From f0ca2e8bf0eaaba32ea0fe1a608c2a5c6348f5fa Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 8 Sep 2014 11:40:48 -0700 Subject: Start moving everything to the new API --- cryptography/hazmat/backends/openssl/backend.py | 14 +++---- cryptography/hazmat/primitives/serialization.py | 22 +++++++++++ .../hazmat/primitives/asymmetric/serialization.rst | 45 +++++++++++++++++++++- tests/hazmat/primitives/test_serialization.py | 24 ++++++++++-- 4 files changed, 93 insertions(+), 12 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 01e61283..333bef0a 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -25,7 +25,8 @@ from cryptography.exceptions import ( ) from cryptography.hazmat.backends.interfaces import ( CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend, - HashBackend, PBKDF2HMACBackend, PKCS8SerializationBackend, RSABackend, + HashBackend, PBKDF2HMACBackend, PEMSerializationBackend, + PKCS8SerializationBackend, RSABackend, TraditionalOpenSSLSerializationBackend ) from cryptography.hazmat.backends.openssl.ciphers import ( @@ -74,6 +75,7 @@ _OpenSSLError = collections.namedtuple("_OpenSSLError", @utils.register_interface(PKCS8SerializationBackend) @utils.register_interface(RSABackend) @utils.register_interface(TraditionalOpenSSLSerializationBackend) +@utils.register_interface(PEMSerializationBackend) class Backend(object): """ OpenSSL API binding interfaces. @@ -770,12 +772,7 @@ class Backend(object): def create_cmac_ctx(self, algorithm): return _CMACContext(self, algorithm) - def load_traditional_openssl_pem_private_key(self, data, password): - # OpenSSLs API for loading PKCS#8 certs can also load the traditional - # format so we just use that for both of them. - return self.load_pkcs8_pem_private_key(data, password) - - def load_pkcs8_pem_private_key(self, data, password): + def load_pem_private_key(self, data, password): return self._load_key( self._lib.PEM_read_bio_PrivateKey, self._evp_pkey_to_private_key, @@ -783,6 +780,9 @@ class Backend(object): password, ) + load_traditional_openssl_pem_private_key = load_pkcs8_pem_private_key = \ + load_pem_private_key + def _load_key(self, openssl_read_func, convert_func, data, password): mem_bio = self._bytes_to_bio(data) diff --git a/cryptography/hazmat/primitives/serialization.py b/cryptography/hazmat/primitives/serialization.py index 55b8640e..cf1ca8ec 100644 --- a/cryptography/hazmat/primitives/serialization.py +++ b/cryptography/hazmat/primitives/serialization.py @@ -13,12 +13,34 @@ from __future__ import absolute_import, division, print_function +import warnings + +from cryptography import utils + def load_pem_traditional_openssl_private_key(data, password, backend): + warnings.warn( + "load_pem_traditional_openssl_private_key is deprecated and will be " + "removed in a future version, use load_pem_private_key instead.", + utils.DeprecatedIn06, + stacklevel=2 + ) + return backend.load_traditional_openssl_pem_private_key( data, password ) def load_pem_pkcs8_private_key(data, password, backend): + warnings.warn( + "load_pem_pkcs8_private_key is deprecated and will be removed in a " + "future version, use load_pem_private_key instead.", + utils.DeprecatedIn06, + stacklevel=2 + ) + return backend.load_pkcs8_pem_private_key(data, password) + + +def load_pem_private_key(data, password, backend): + return backend.load_pem_private_key(data, password) diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index 5438c249..e18f8c83 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -45,8 +45,8 @@ methods. >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import interfaces - >>> from cryptography.hazmat.primitives.serialization import load_pem_pkcs8_private_key - >>> key = load_pem_pkcs8_private_key(pem_data, password=None, backend=default_backend()) + >>> 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, interfaces.RSAPrivateKey): ... signature = sign_with_rsa_key(key, message) ... elif isinstance(key, interfaces.DSAPrivateKey): @@ -54,6 +54,43 @@ methods. ... else: ... raise TypeError +PEM +~~~ + +PEM is an encapsulation format, meaning keys in it can actually be any one of +several formats, however these are all self-identifying, so you don't need to +worry about this detail. PEM keys are recognizable because they all begin with +``-----BEGIN {format}-----`` and end with ``-----END {format}-----``. + +.. function:: load_pem_private_key(data, password, backend): + + .. versionadded:: 0.6 + + Deserialize a private key from PEM encoded data to one of the supported + asymmetric private key types. + + :param bytes data: The PEM encoded key data. + + :param bytes password: The password to use to decrypt the data. Should + be ``None`` if the private key is not encrypted. + + :param backend: A + :class:`~cryptography.hazmat.backends.interfaces.PKCS8SerializationBackend` + provider. + + :returns: A new instance of a private key. + + :raises ValueError: If the PEM data could not be decrypted or if its + structure could not be decoded successfully. + + :raises TypeError: If a ``password`` was given and the private key was + not encrypted. Or if the key was encrypted but no + password was supplied. + + :raises UnsupportedAlgorithm: If the serialized key is of a type that + is not supported by the backend or if the key is encrypted with a + symmetric cipher that is not supported by the backend. + PKCS #8 Format ~~~~~~~~~~~~~~ @@ -72,6 +109,8 @@ with ``-----BEGIN ENCRYPTED PRIVATE KEY-----`` if they have a password. Deserialize a private key from PEM encoded data to one of the supported asymmetric private key types. + This has been deprecated in favor of :func:`load_pem_private_key`. + :param bytes data: The PEM encoded key data. :param bytes password: The password to use to decrypt the data. Should @@ -111,6 +150,8 @@ KEY-----`` or ``-----BEGIN DSA PRIVATE KEY-----``. Deserialize a private key from PEM encoded data to one of the supported asymmetric private key types. + This has been deprecated in favor of :func:`load_pem_private_key`. + :param bytes data: The PEM encoded key data. :param bytes password: The password to use to decrypt the data. Should diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 30ac4f3d..e960878b 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -22,15 +22,33 @@ import pytest from cryptography.exceptions import _Reasons from cryptography.hazmat.primitives import interfaces from cryptography.hazmat.primitives.serialization import ( - load_pem_pkcs8_private_key, load_pem_traditional_openssl_private_key + load_pem_private_key, load_pem_pkcs8_private_key, + load_pem_traditional_openssl_private_key ) from .utils import _check_rsa_private_numbers, load_vectors_from_file from ...utils import raises_unsupported_algorithm +@pytest.mark.pem_serialization +class TestPEMSerialization(object): + def test_load_pem_rsa_private_key(self, backend): + key = load_vectors_from_file( + os.path.join( + "asymmetric", "Traditional_OpenSSL_Serialization", "key1.pem"), + lambda pemfile: load_pem_private_key( + pemfile.read().encode(), b"123456", backend + ) + ) + + assert key + assert isinstance(key, interfaces.RSAPrivateKey) + if isinstance(key, interfaces.RSAPrivateKeyWithNumbers): + _check_rsa_private_numbers(key.private_numbers()) + + @pytest.mark.traditional_openssl_serialization -class TestTraditionalOpenSSLSerialisation(object): +class TestTraditionalOpenSSLSerialization(object): @pytest.mark.parametrize( ("key_file", "password"), [ @@ -252,7 +270,7 @@ class TestTraditionalOpenSSLSerialisation(object): @pytest.mark.pkcs8_serialization -class TestPKCS8Serialisation(object): +class TestPKCS8Serialization(object): @pytest.mark.parametrize( ("key_file", "password"), [ -- cgit v1.2.3 From e53677a149b646deb2be1d6ffbd3e27a960b2f8c Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 8 Sep 2014 12:43:02 -0700 Subject: fixes --- cryptography/utils.py | 1 + pytest.ini | 1 + tests/conftest.py | 4 +++- tests/hazmat/primitives/test_serialization.py | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cryptography/utils.py b/cryptography/utils.py index 9c574085..f4c2e3cb 100644 --- a/cryptography/utils.py +++ b/cryptography/utils.py @@ -17,6 +17,7 @@ import sys DeprecatedIn05 = DeprecationWarning +DeprecatedIn06 = PendingDeprecationWarning def register_interface(iface): diff --git a/pytest.ini b/pytest.ini index 00a2c7fb..77e73966 100644 --- a/pytest.ini +++ b/pytest.ini @@ -12,3 +12,4 @@ markers = pkcs8_serialization: this test requires a backend providing PKCS8SerializationBackend supported: parametrized test requiring only_if and skip_message elliptic: this test requires a backend providing EllipticCurveBackend + pem_serialization: this test requires a backend providing PEMSerializationBackend diff --git a/tests/conftest.py b/tests/conftest.py index af146386..b7981c9d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -18,7 +18,8 @@ import pytest from cryptography.hazmat.backends import _available_backends from cryptography.hazmat.backends.interfaces import ( CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend, - HashBackend, PBKDF2HMACBackend, PKCS8SerializationBackend, RSABackend, + HashBackend, PBKDF2HMACBackend, PEMSerializationBackend, + PKCS8SerializationBackend, RSABackend, TraditionalOpenSSLSerializationBackend ) from .utils import check_backend_support, check_for_iface, select_backends @@ -48,6 +49,7 @@ def pytest_runtest_setup(item): ) check_for_iface("pkcs8_serialization", PKCS8SerializationBackend, item) check_for_iface("elliptic", EllipticCurveBackend, item) + check_for_iface("pem_serialization", PEMSerializationBackend, item) check_backend_support(item) diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index e960878b..9333a6bd 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -22,7 +22,7 @@ import pytest from cryptography.exceptions import _Reasons from cryptography.hazmat.primitives import interfaces from cryptography.hazmat.primitives.serialization import ( - load_pem_private_key, load_pem_pkcs8_private_key, + load_pem_pkcs8_private_key, load_pem_private_key, load_pem_traditional_openssl_private_key ) -- cgit v1.2.3 From 38d3b358486f569d136e526d8aa45f44fc652a24 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 8 Sep 2014 12:46:59 -0700 Subject: Explicitly deprecate these as well --- cryptography/hazmat/backends/openssl/backend.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 333bef0a..ce630793 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -780,8 +780,24 @@ class Backend(object): password, ) - load_traditional_openssl_pem_private_key = load_pkcs8_pem_private_key = \ - load_pem_private_key + def load_traditional_openssl_pem_private_key(self, data, password): + warnings.warn( + "load_traditional_openssl_pem_private_key is deprecated and will " + "be removed in a future version, use load_pem_private_key " + "instead.", + utils.DeprecatedIn06, + stacklevel=2 + ) + return self.load_pem_private_key(self, data, password) + + def load_pkcs8_pem_private_key(self, data, password): + warnings.warn( + "load_pkcs8_pem_private_key is deprecated and will be removed in a" + " future version, use load_pem_private_key instead.", + utils.DeprecatedIn06, + stacklevel=2 + ) + return self.load_pem_private_key(self, data, password) def _load_key(self, openssl_read_func, convert_func, data, password): mem_bio = self._bytes_to_bio(data) -- cgit v1.2.3 From 79e51a9b9ce3969c9cc67be655a07cf515dfb1d6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 8 Sep 2014 12:54:17 -0700 Subject: remove duplicate argument --- cryptography/hazmat/backends/openssl/backend.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index ce630793..d1d18a10 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -788,7 +788,7 @@ class Backend(object): utils.DeprecatedIn06, stacklevel=2 ) - return self.load_pem_private_key(self, data, password) + return self.load_pem_private_key(data, password) def load_pkcs8_pem_private_key(self, data, password): warnings.warn( @@ -797,7 +797,7 @@ class Backend(object): utils.DeprecatedIn06, stacklevel=2 ) - return self.load_pem_private_key(self, data, password) + return self.load_pem_private_key(data, password) def _load_key(self, openssl_read_func, convert_func, data, password): mem_bio = self._bytes_to_bio(data) -- cgit v1.2.3 From a54d342197e9714ebdea32411488c147220a66f6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 8 Sep 2014 14:02:48 -0700 Subject: multibacken for docs --- cryptography/hazmat/backends/multibackend.py | 15 +++++++++++++-- tests/hazmat/backends/test_multibackend.py | 18 +++++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py index 6893cad6..221f1a1e 100644 --- a/cryptography/hazmat/backends/multibackend.py +++ b/cryptography/hazmat/backends/multibackend.py @@ -17,8 +17,9 @@ from cryptography import utils from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.backends.interfaces import ( CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend, - HashBackend, PBKDF2HMACBackend, PKCS8SerializationBackend, - RSABackend, TraditionalOpenSSLSerializationBackend + HashBackend, PBKDF2HMACBackend, PEMSerializationBackend, + PKCS8SerializationBackend, RSABackend, + TraditionalOpenSSLSerializationBackend ) @@ -32,6 +33,7 @@ from cryptography.hazmat.backends.interfaces import ( @utils.register_interface(TraditionalOpenSSLSerializationBackend) @utils.register_interface(DSABackend) @utils.register_interface(EllipticCurveBackend) +@utils.register_interface(PEMSerializationBackend) class MultiBackend(object): name = "multibackend" @@ -318,6 +320,15 @@ class MultiBackend(object): _Reasons.UNSUPPORTED_ELLIPTIC_CURVE ) + def load_pem_private_key(self, data, password): + for b in self._filtered_backends(PEMSerializationBackend): + return b.load_pem_private_key(data, password) + + raise UnsupportedAlgorithm( + "This backend does not support this key serialization.", + _Reasons.UNSUPPORTED_SERIALIZATION + ) + def load_pkcs8_pem_private_key(self, data, password): for b in self._filtered_backends(PKCS8SerializationBackend): return b.load_pkcs8_pem_private_key(data, password) diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py index 168ed688..655acc44 100644 --- a/tests/hazmat/backends/test_multibackend.py +++ b/tests/hazmat/backends/test_multibackend.py @@ -19,7 +19,8 @@ from cryptography.exceptions import ( ) from cryptography.hazmat.backends.interfaces import ( CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend, - HashBackend, PBKDF2HMACBackend, PKCS8SerializationBackend, RSABackend, + HashBackend, PBKDF2HMACBackend, PEMSerializationBackend, + PKCS8SerializationBackend, RSABackend, TraditionalOpenSSLSerializationBackend ) from cryptography.hazmat.backends.multibackend import MultiBackend @@ -211,6 +212,12 @@ class DummyTraditionalOpenSSLSerializationBackend(object): pass +@utils.register_interface(PEMSerializationBackend) +class DummyPEMSerializationBackend(object): + def load_pem_private_key(self, data, password): + pass + + class TestMultiBackend(object): def test_ciphers(self): backend = MultiBackend([ @@ -520,3 +527,12 @@ class TestMultiBackend(object): backend = MultiBackend([]) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): backend.load_traditional_openssl_pem_private_key(b"keydata", None) + + def test_pem_serialization_backend(self): + backend = MultiBackend([DummyPEMSerializationBackend()]) + + backend.load_pem_private_key(b"keydata", None) + + backend = MultiBackend([]) + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): + backend.load_pem_private_key(b"keydata", None) -- cgit v1.2.3 From ac83b394befefc8da6bf4fde75e99daf0abe9237 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 8 Sep 2014 14:04:04 -0700 Subject: Try a different phrasing --- docs/hazmat/primitives/asymmetric/serialization.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index e18f8c83..6e946b85 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -57,10 +57,11 @@ methods. PEM ~~~ -PEM is an encapsulation format, meaning keys in it can actually be any one of -several formats, however these are all self-identifying, so you don't need to -worry about this detail. PEM keys are recognizable because they all begin with -``-----BEGIN {format}-----`` and end with ``-----END {format}-----``. +PEM is an encapsulation format, meaning keys in it can actually be any of +several different key types, however these are all self-identifying, so you +don't need to worry about this detail. PEM keys are recognizable because they +all begin with ``-----BEGIN {format}-----`` and end with ``-----END +{format}-----``. .. function:: load_pem_private_key(data, password, backend): -- cgit v1.2.3 From 4e5d1eeb574b3abfe93f81975984d5d4ef688006 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 9 Sep 2014 13:14:59 -0700 Subject: Grammar from @reaperhulk --- docs/hazmat/primitives/asymmetric/serialization.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index 6e946b85..84b69fdc 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -58,7 +58,7 @@ PEM ~~~ PEM is an encapsulation format, meaning keys in it can actually be any of -several different key types, however these are all self-identifying, so you +several different key types. However these are all self-identifying, so you don't need to worry about this detail. PEM keys are recognizable because they all begin with ``-----BEGIN {format}-----`` and end with ``-----END {format}-----``. -- cgit v1.2.3