diff options
author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2014-09-09 21:13:39 -0500 |
---|---|---|
committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2014-09-09 21:13:39 -0500 |
commit | b8599c085d3e295f460f0117f7df9288a4841d7f (patch) | |
tree | 6b6e8d52a3167b4f7540ada271fd3b6dd0d4f70c | |
parent | 86dd8345a9bd8f826b950b4574072427676f43b3 (diff) | |
parent | 4e5d1eeb574b3abfe93f81975984d5d4ef688006 (diff) | |
download | cryptography-b8599c085d3e295f460f0117f7df9288a4841d7f.tar.gz cryptography-b8599c085d3e295f460f0117f7df9288a4841d7f.tar.bz2 cryptography-b8599c085d3e295f460f0117f7df9288a4841d7f.zip |
Merge pull request #1326 from alex/pem-serialization-backend
Start moving everything to the new API
-rw-r--r-- | cryptography/hazmat/backends/multibackend.py | 15 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/backend.py | 30 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/serialization.py | 22 | ||||
-rw-r--r-- | cryptography/utils.py | 1 | ||||
-rw-r--r-- | docs/hazmat/primitives/asymmetric/serialization.rst | 46 | ||||
-rw-r--r-- | pytest.ini | 1 | ||||
-rw-r--r-- | tests/conftest.py | 4 | ||||
-rw-r--r-- | tests/hazmat/backends/test_multibackend.py | 18 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_serialization.py | 24 |
9 files changed, 145 insertions, 16 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/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 01e61283..d1d18a10 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,25 @@ class Backend(object): password, ) + 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(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(data, password) + 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/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/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index 5438c249..84b69fdc 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,44 @@ methods. ... else: ... raise TypeError +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 +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 +110,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 +151,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 @@ -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/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) diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 30ac4f3d..9333a6bd 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_pkcs8_private_key, load_pem_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"), [ |