aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2014-09-09 21:13:39 -0500
committerPaul Kehrer <paul.l.kehrer@gmail.com>2014-09-09 21:13:39 -0500
commitb8599c085d3e295f460f0117f7df9288a4841d7f (patch)
tree6b6e8d52a3167b4f7540ada271fd3b6dd0d4f70c
parent86dd8345a9bd8f826b950b4574072427676f43b3 (diff)
parent4e5d1eeb574b3abfe93f81975984d5d4ef688006 (diff)
downloadcryptography-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.py15
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py30
-rw-r--r--cryptography/hazmat/primitives/serialization.py22
-rw-r--r--cryptography/utils.py1
-rw-r--r--docs/hazmat/primitives/asymmetric/serialization.rst46
-rw-r--r--pytest.ini1
-rw-r--r--tests/conftest.py4
-rw-r--r--tests/hazmat/backends/test_multibackend.py18
-rw-r--r--tests/hazmat/primitives/test_serialization.py24
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
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/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"),
[