aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Stapleton <alexs@prol.etari.at>2015-03-01 16:02:23 +0000
committerAlex Stapleton <alexs@prol.etari.at>2015-03-01 16:02:23 +0000
commit6bb9624186f3546dd203e3a20e7785dad71c6256 (patch)
treece9d0ea0d2e821557aac3abf0f01966a125a801e
parente8f12f833f14c55b18919a55db52d24cc8880ae9 (diff)
parent223a8f02a37a87b3c7366441647013cf9a18b061 (diff)
downloadcryptography-6bb9624186f3546dd203e3a20e7785dad71c6256.tar.gz
cryptography-6bb9624186f3546dd203e3a20e7785dad71c6256.tar.bz2
cryptography-6bb9624186f3546dd203e3a20e7785dad71c6256.zip
Merge pull request #1503 from reaperhulk/serialize-some-keys
Support for traditional OpenSSL and PKCS8 RSA private key serialization
-rw-r--r--CHANGELOG.rst8
-rw-r--r--docs/hazmat/primitives/asymmetric/rsa.rst76
-rw-r--r--docs/hazmat/primitives/asymmetric/serialization.rst66
-rw-r--r--docs/spelling_wordlist.txt2
-rw-r--r--src/cryptography/hazmat/backends/openssl/rsa.py66
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/rsa.py19
-rw-r--r--src/cryptography/hazmat/primitives/interfaces/__init__.py5
-rw-r--r--src/cryptography/hazmat/primitives/serialization.py32
-rw-r--r--tests/hazmat/backends/test_openssl.py27
-rw-r--r--tests/hazmat/primitives/test_rsa.py133
-rw-r--r--tests/hazmat/primitives/test_serialization.py14
11 files changed, 436 insertions, 12 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index da529f68..f0e373be 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -78,6 +78,14 @@ Changelog
support loading DER encoded public keys.
* Fixed building against LibreSSL, a compile-time substitute for OpenSSL.
* FreeBSD 9.2 was removed from the continuous integration system.
+* Added
+ :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization`
+ and deprecated
+ :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithNumbers`.
+* Added
+ :meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization.private_bytes`
+ to
+ :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization`.
0.7.2 - 2015-01-16
~~~~~~~~~~~~~~~~~~
diff --git a/docs/hazmat/primitives/asymmetric/rsa.rst b/docs/hazmat/primitives/asymmetric/rsa.rst
index fd97d75b..924696db 100644
--- a/docs/hazmat/primitives/asymmetric/rsa.rst
+++ b/docs/hazmat/primitives/asymmetric/rsa.rst
@@ -80,6 +80,39 @@ password. If the key is encrypted we can pass a ``bytes`` object as the
There is also support for :func:`loading public keys in the SSH format
<cryptography.hazmat.primitives.serialization.load_ssh_public_key>`.
+Key serialization
+~~~~~~~~~~~~~~~~~
+
+If you have a key that you've loaded or generated which implements the
+:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization`
+interface you can use
+:meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization.private_bytes`
+to serialize the key.
+
+.. doctest::
+
+ >>> from cryptography.hazmat.primitives import serialization
+ >>> pem = private_key.private_bytes(
+ ... encoding=serialization.Encoding.PEM,
+ ... format=serialization.Format.PKCS8,
+ ... encryption_algorithm=serialization.BestAvailableEncryption(b'mypassword')
+ ... )
+ >>> pem.splitlines()[0]
+ '-----BEGIN ENCRYPTED PRIVATE KEY-----'
+
+It is also possible to serialize without encryption using
+:class:`~cryptography.hazmat.primitives.serialization.NoEncryption`.
+
+.. doctest::
+
+ >>> pem = private_key.private_bytes(
+ ... encoding=serialization.Encoding.PEM,
+ ... format=serialization.Format.TraditionalOpenSSL,
+ ... encryption_algorithm=serialization.NoEncryption()
+ ... )
+ >>> pem.splitlines()[0]
+ '-----BEGIN RSA PRIVATE KEY-----'
+
Signing
~~~~~~~
@@ -485,6 +518,49 @@ Key interfaces
instance.
+.. class:: RSAPrivateKeyWithSerialization
+
+ .. versionadded:: 0.8
+
+ Extends :class:`RSAPrivateKey`.
+
+ .. method:: private_numbers()
+
+ Create a
+ :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers`
+ object.
+
+ :returns: An
+ :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers`
+ instance.
+
+ .. method:: private_bytes(encoding, format, encryption_algorithm)
+
+ Allows serialization of the key to bytes. Encoding (
+ :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM` or
+ :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`),
+ format (
+ :attr:`~cryptography.hazmat.primitives.serialization.Format.TraditionalOpenSSL`
+ or
+ :attr:`~cryptography.hazmat.primitives.serialization.Format.PKCS8`) and
+ encryption algorithm (such as
+ :class:`~cryptography.hazmat.primitives.serialization.BestAvailableEncryption`
+ or :class:`~cryptography.hazmat.primitives.serialization.NoEncryption`)
+ are chosen to define the exact serialization.
+
+ :param encoding: A value from the
+ :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum.
+
+ :param format: A value from the
+ :class:`~cryptography.hazmat.primitives.serialization.Format` enum.
+
+ :param encryption_algorithm: An instance of an object conforming to the
+ :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption`
+ interface.
+
+ :return bytes: Serialized key.
+
+
.. class:: RSAPublicKey
.. versionadded:: 0.2
diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst
index 87f3c0b0..4940ebd4 100644
--- a/docs/hazmat/primitives/asymmetric/serialization.rst
+++ b/docs/hazmat/primitives/asymmetric/serialization.rst
@@ -3,7 +3,7 @@
Key Serialization
=================
-.. currentmodule:: cryptography.hazmat.primitives.serialization
+.. module:: cryptography.hazmat.primitives.serialization
.. testsetup::
@@ -282,3 +282,67 @@ 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.
+
+Serialization Formats
+~~~~~~~~~~~~~~~~~~~~~
+
+.. class:: Format
+
+ .. versionadded:: 0.8
+
+ An enumeration for key formats. Used with
+ :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization.private_bytes`.
+
+ .. attribute:: TraditionalOpenSSL
+
+ Frequently known as PKCS#1 format. Still a widely used format, but
+ generally considered legacy.
+
+ .. attribute:: PKCS8
+
+ A more modern format for serializing keys which allows for better
+ encryption. Choose this unless you have explicit legacy compatibility
+ requirements.
+
+Serialization Encodings
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. class:: Encoding
+
+ .. versionadded:: 0.8
+
+ An enumeration for encoding types. Used with
+ :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization.private_bytes`.
+
+ .. attribute:: PEM
+
+ For PEM format. This is a base64 format with delimiters.
+
+ .. attribute:: DER
+
+ For DER format. This is a binary format.
+
+
+Serialization Encryption Types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. class:: KeySerializationEncryption
+
+ Objects with this interface are usable as encryption types with methods
+ like
+ :meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization.private_bytes`.
+ All other classes in this section represent the available choices for
+ encryption and have this interface. They are used with
+ :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization.private_bytes`.
+
+.. 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
+ time.
+
+ :param bytes password: The password to use for encryption.
+
+.. class:: NoEncryption
+
+ Do not encrypt.
diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt
index 9434a0b7..81310d2d 100644
--- a/docs/spelling_wordlist.txt
+++ b/docs/spelling_wordlist.txt
@@ -45,6 +45,8 @@ pseudorandom
pyOpenSSL
Schneier
scrypt
+Serializers
+serializer
Solaris
Tanja
testability
diff --git a/src/cryptography/hazmat/backends/openssl/rsa.py b/src/cryptography/hazmat/backends/openssl/rsa.py
index 00ddcda3..e7365c11 100644
--- a/src/cryptography/hazmat/backends/openssl/rsa.py
+++ b/src/cryptography/hazmat/backends/openssl/rsa.py
@@ -17,8 +17,13 @@ from cryptography.hazmat.primitives.asymmetric import (
from cryptography.hazmat.primitives.asymmetric.padding import (
AsymmetricPadding, MGF1, OAEP, PKCS1v15, PSS
)
-from cryptography.hazmat.primitives.interfaces import (
- RSAPrivateKeyWithNumbers, RSAPublicKeyWithNumbers
+from cryptography.hazmat.primitives.asymmetric.rsa import (
+ RSAPrivateKeyWithNumbers, RSAPrivateKeyWithSerialization,
+ RSAPublicKeyWithNumbers
+)
+from cryptography.hazmat.primitives.serialization import (
+ BestAvailableEncryption, Encoding, Format, KeySerializationEncryption,
+ NoEncryption
)
@@ -507,6 +512,7 @@ class _RSAVerificationContext(object):
@utils.register_interface(RSAPrivateKeyWithNumbers)
+@utils.register_interface(RSAPrivateKeyWithSerialization)
class _RSAPrivateKey(object):
def __init__(self, backend, rsa_cdata):
self._backend = backend
@@ -559,6 +565,62 @@ class _RSAPrivateKey(object):
)
)
+ def private_bytes(self, encoding, format, encryption_algorithm):
+ if not isinstance(encoding, Encoding):
+ raise TypeError("encoding must be an item from the Encoding enum")
+
+ if not isinstance(format, Format):
+ raise TypeError("format must be an item from the Format enum")
+
+ # This is a temporary check until we land DER serialization.
+ if encoding is not Encoding.PEM:
+ raise ValueError("Only PEM encoding is supported by this backend")
+
+ if format is Format.PKCS8:
+ write_bio = self._backend._lib.PEM_write_bio_PKCS8PrivateKey
+ key = self._evp_pkey
+ elif format is Format.TraditionalOpenSSL:
+ write_bio = self._backend._lib.PEM_write_bio_RSAPrivateKey
+ key = self._rsa_cdata
+
+ if not isinstance(encryption_algorithm, KeySerializationEncryption):
+ raise TypeError(
+ "Encryption algorithm must be a KeySerializationEncryption "
+ "instance"
+ )
+
+ if isinstance(encryption_algorithm, NoEncryption):
+ password = b""
+ passlen = 0
+ evp_cipher = self._backend._ffi.NULL
+ 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"
+ )
+ password = encryption_algorithm.password
+ passlen = len(password)
+ if passlen > 1023:
+ raise ValueError(
+ "Passwords longer than 1023 bytes are not supported by "
+ "this backend"
+ )
+ else:
+ raise ValueError("Unsupported encryption type")
+
+ bio = self._backend._create_mem_bio()
+ res = write_bio(
+ bio,
+ key,
+ evp_cipher,
+ password,
+ passlen,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL
+ )
+ assert res == 1
+ return self._backend._read_mem_bio(bio)
+
@utils.register_interface(RSAPublicKeyWithNumbers)
class _RSAPublicKey(object):
diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py
index 332ad2c3..4963d85c 100644
--- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py
+++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -42,13 +42,30 @@ class RSAPrivateKey(object):
@six.add_metaclass(abc.ABCMeta)
-class RSAPrivateKeyWithNumbers(RSAPrivateKey):
+class RSAPrivateKeyWithSerialization(RSAPrivateKey):
@abc.abstractmethod
def private_numbers(self):
"""
Returns an RSAPrivateNumbers.
"""
+ @abc.abstractmethod
+ def private_bytes(self, encoding, format, encryption_algorithm):
+ """
+ Returns the key serialized as bytes.
+ """
+
+
+RSAPrivateKeyWithNumbers = utils.deprecated(
+ RSAPrivateKeyWithSerialization,
+ __name__,
+ (
+ "The RSAPrivateKeyWithNumbers interface has been renamed to "
+ "RSAPrivateKeyWithSerialization"
+ ),
+ utils.DeprecatedIn08
+)
+
@six.add_metaclass(abc.ABCMeta)
class RSAPublicKey(object):
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 0f9506e1..0d564221 100644
--- a/src/cryptography/hazmat/primitives/serialization.py
+++ b/src/cryptography/hazmat/primitives/serialization.py
@@ -4,11 +4,14 @@
from __future__ import absolute_import, division, print_function
+import abc
import base64
import struct
+from enum import Enum
import six
+from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
@@ -164,3 +167,32 @@ else:
data = data[4:]
return result
+
+
+class Encoding(Enum):
+ PEM = "PEM"
+ DER = "DER"
+
+
+class Format(Enum):
+ PKCS8 = "PKCS8"
+ TraditionalOpenSSL = "TraditionalOpenSSL"
+
+
+@six.add_metaclass(abc.ABCMeta)
+class KeySerializationEncryption(object):
+ pass
+
+
+@utils.register_interface(KeySerializationEncryption)
+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.")
+
+ self.password = password
+
+
+@utils.register_interface(KeySerializationEncryption)
+class NoEncryption(object):
+ pass
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 0e4d75ed..4f44f686 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,25 @@ 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.Format.PKCS8,
+ serialization.BestAvailableEncryption(password)
+ )
+
+ def test_unsupported_key_encoding(self):
+ key = RSA_KEY_2048.private_key(backend)
+ with pytest.raises(ValueError):
+ key.private_bytes(
+ 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 74183010..0cf94afe 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
+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,18 @@ def test_modular_inverse():
)
+def _skip_if_no_serialization(key, backend):
+ if not isinstance(key, rsa.RSAPrivateKeyWithSerialization):
+ 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(
@@ -1725,3 +1744,113 @@ 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 TestRSAPEMWriter(object):
+ @pytest.mark.parametrize(
+ ("fmt", "password"),
+ itertools.product(
+ [
+ serialization.Format.TraditionalOpenSSL,
+ serialization.Format.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.Format.TraditionalOpenSSL, serialization.Format.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.Format.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.Format.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.Format.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.Format.TraditionalOpenSSL,
+ DummyKeyEncryption()
+ )
diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py
index a17aac4b..fc8f8664 100644
--- a/tests/hazmat/primitives/test_serialization.py
+++ b/tests/hazmat/primitives/test_serialization.py
@@ -18,8 +18,8 @@ from cryptography.hazmat.backends.interfaces import (
)
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
)
@@ -1159,3 +1159,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"")