aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2015-03-13 13:48:02 -0400
committerAlex Gaynor <alex.gaynor@gmail.com>2015-03-13 13:48:02 -0400
commit7905fcec68fd633d0b28d371660123b7b22cca53 (patch)
tree991f2f68d82d91ea066bebc3e60b636fc0bc1713
parent710877611effc64cbdebe41c1cd91f52e9f2513c (diff)
parent22d25d5674faba9170f64e6a4714dfa0c62cc5d7 (diff)
downloadcryptography-7905fcec68fd633d0b28d371660123b7b22cca53.tar.gz
cryptography-7905fcec68fd633d0b28d371660123b7b22cca53.tar.bz2
cryptography-7905fcec68fd633d0b28d371660123b7b22cca53.zip
Merge pull request #1754 from reaperhulk/serialize-der-part-un
support RSA DER private key serialization
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py62
-rw-r--r--tests/hazmat/backends/test_openssl.py15
-rw-r--r--tests/hazmat/primitives/test_rsa.py103
3 files changed, 139 insertions, 41 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 6b5c1a0c..150dbfc0 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -1133,24 +1133,6 @@ class Backend(object):
"format must be an item from the PrivateFormat enum"
)
- # This is a temporary check until we land DER serialization.
- if encoding is not serialization.Encoding.PEM:
- raise ValueError("Only PEM encoding is supported by this backend")
-
- if format is serialization.PrivateFormat.PKCS8:
- write_bio = self._lib.PEM_write_bio_PKCS8PrivateKey
- key = evp_pkey
- elif format is serialization.PrivateFormat.TraditionalOpenSSL:
- if evp_pkey.type == self._lib.EVP_PKEY_RSA:
- write_bio = self._lib.PEM_write_bio_RSAPrivateKey
- elif evp_pkey.type == self._lib.EVP_PKEY_DSA:
- write_bio = self._lib.PEM_write_bio_DSAPrivateKey
- elif (self._lib.Cryptography_HAS_EC == 1 and
- evp_pkey.type == self._lib.EVP_PKEY_EC):
- write_bio = self._lib.PEM_write_bio_ECPrivateKey
-
- key = cdata
-
if not isinstance(encryption_algorithm,
serialization.KeySerializationEncryption):
raise TypeError(
@@ -1178,6 +1160,37 @@ class Backend(object):
else:
raise ValueError("Unsupported encryption type")
+ if encoding is serialization.Encoding.PEM:
+ if format is serialization.PrivateFormat.PKCS8:
+ write_bio = self._lib.PEM_write_bio_PKCS8PrivateKey
+ key = evp_pkey
+ elif format is serialization.PrivateFormat.TraditionalOpenSSL:
+ if evp_pkey.type == self._lib.EVP_PKEY_RSA:
+ write_bio = self._lib.PEM_write_bio_RSAPrivateKey
+ elif evp_pkey.type == self._lib.EVP_PKEY_DSA:
+ write_bio = self._lib.PEM_write_bio_DSAPrivateKey
+ elif (self._lib.Cryptography_HAS_EC == 1 and
+ evp_pkey.type == self._lib.EVP_PKEY_EC):
+ write_bio = self._lib.PEM_write_bio_ECPrivateKey
+
+ key = cdata
+ elif encoding is serialization.Encoding.DER:
+ if format is serialization.PrivateFormat.TraditionalOpenSSL:
+ if not isinstance(
+ encryption_algorithm, serialization.NoEncryption
+ ):
+ raise ValueError(
+ "Encryption is not supported for DER encoded "
+ "traditional OpenSSL keys"
+ )
+
+ return self._private_key_bytes_traditional_der(
+ evp_pkey.type, cdata
+ )
+ elif format is serialization.PrivateFormat.PKCS8:
+ write_bio = self._lib.i2d_PKCS8PrivateKey_bio
+ key = evp_pkey
+
bio = self._create_mem_bio()
res = write_bio(
bio,
@@ -1191,6 +1204,19 @@ class Backend(object):
assert res == 1
return self._read_mem_bio(bio)
+ def _private_key_bytes_traditional_der(self, type, cdata):
+ if type == self._lib.EVP_PKEY_RSA:
+ write_bio = self._lib.i2d_RSAPrivateKey_bio
+ else:
+ raise TypeError(
+ "Only RSA keys are supported for DER serialization"
+ )
+
+ bio = self._create_mem_bio()
+ res = write_bio(bio, cdata)
+ assert res == 1
+ return self._read_mem_bio(bio)
+
def _public_key_bytes(self, encoding, format, evp_pkey, cdata):
if not isinstance(encoding, serialization.Encoding):
raise TypeError("encoding must be an item from the Encoding enum")
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index cfdc06b4..410d3d2a 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -15,7 +15,7 @@ import pytest
from cryptography import utils
from cryptography.exceptions import InternalError, _Reasons
-from cryptography.hazmat.backends.interfaces import RSABackend
+from cryptography.hazmat.backends.interfaces import DSABackend, RSABackend
from cryptography.hazmat.backends.openssl.backend import (
Backend, backend
)
@@ -508,11 +508,18 @@ class TestRSAPEMSerialization(object):
serialization.BestAvailableEncryption(password)
)
+
+@pytest.mark.requires_backend_interface(interface=DSABackend)
+class TestDSADERSerialization(object):
def test_unsupported_private_key_encoding(self):
- key = RSA_KEY_2048.private_key(backend)
- with pytest.raises(ValueError):
+ key_bytes = load_vectors_from_file(
+ os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"),
+ lambda pemfile: pemfile.read().encode()
+ )
+ key = serialization.load_pem_private_key(key_bytes, None, backend)
+ with pytest.raises(TypeError):
key.private_bytes(
serialization.Encoding.DER,
- serialization.PrivateFormat.PKCS8,
+ serialization.PrivateFormat.TraditionalOpenSSL,
serialization.NoEncryption()
)
diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py
index ab7cc3ad..eb12df8d 100644
--- a/tests/hazmat/primitives/test_rsa.py
+++ b/tests/hazmat/primitives/test_rsa.py
@@ -1751,7 +1751,7 @@ class TestRSAPrimeFactorRecovery(object):
@pytest.mark.requires_backend_interface(interface=RSABackend)
@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend)
-class TestRSAPEMPrivateKeySerialization(object):
+class TestRSAPrivateKeySerialization(object):
@pytest.mark.parametrize(
("fmt", "password"),
itertools.product(
@@ -1783,44 +1783,109 @@ class TestRSAPEMPrivateKeySerialization(object):
assert loaded_priv_num == priv_num
@pytest.mark.parametrize(
- "fmt",
+ ("fmt", "password"),
[
- serialization.PrivateFormat.TraditionalOpenSSL,
- serialization.PrivateFormat.PKCS8
- ],
+ [serialization.PrivateFormat.PKCS8, b"s"],
+ [serialization.PrivateFormat.PKCS8, b"longerpassword"],
+ [serialization.PrivateFormat.PKCS8, b"!*$&(@#$*&($T@%_somesymbol"],
+ [serialization.PrivateFormat.PKCS8, b"\x01" * 1000]
+ ]
)
- def test_private_bytes_unencrypted_pem(self, backend, fmt):
+ def test_private_bytes_encrypted_der(self, backend, fmt, password):
key = RSA_KEY_2048.private_key(backend)
_skip_if_no_serialization(key, backend)
serialized = key.private_bytes(
- serialization.Encoding.PEM,
+ serialization.Encoding.DER,
fmt,
- serialization.NoEncryption()
+ serialization.BestAvailableEncryption(password)
)
- loaded_key = serialization.load_pem_private_key(
- serialized, None, backend
+ loaded_key = serialization.load_der_private_key(
+ serialized, password, 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):
+ @pytest.mark.parametrize(
+ ("encoding", "fmt", "loader_func"),
+ [
+ [
+ serialization.Encoding.PEM,
+ serialization.PrivateFormat.TraditionalOpenSSL,
+ serialization.load_pem_private_key
+ ],
+ [
+ serialization.Encoding.DER,
+ serialization.PrivateFormat.TraditionalOpenSSL,
+ serialization.load_der_private_key
+ ],
+ [
+ serialization.Encoding.PEM,
+ serialization.PrivateFormat.PKCS8,
+ serialization.load_pem_private_key
+ ],
+ [
+ serialization.Encoding.DER,
+ serialization.PrivateFormat.PKCS8,
+ serialization.load_der_private_key
+ ],
+ ]
+ )
+ def test_private_bytes_unencrypted(self, backend, encoding, fmt,
+ loader_func):
+ key = RSA_KEY_2048.private_key(backend)
+ _skip_if_no_serialization(key, backend)
+ serialized = key.private_bytes(
+ encoding, fmt, serialization.NoEncryption()
+ )
+ loaded_key = loader_func(serialized, None, backend)
+ loaded_priv_num = loaded_key.private_numbers()
+ priv_num = key.private_numbers()
+ assert loaded_priv_num == priv_num
+
+ @pytest.mark.parametrize(
+ ("key_path", "encoding", "loader_func"),
+ [
+ [
+ os.path.join(
+ "asymmetric",
+ "Traditional_OpenSSL_Serialization",
+ "testrsa.pem"
+ ),
+ serialization.Encoding.PEM,
+ serialization.load_pem_private_key
+ ],
+ [
+ os.path.join("asymmetric", "DER_Serialization", "testrsa.der"),
+ serialization.Encoding.DER,
+ serialization.load_der_private_key
+ ],
+ ]
+ )
+ def test_private_bytes_traditional_openssl_unencrypted(
+ self, backend, key_path, encoding, loader_func
+ ):
key_bytes = load_vectors_from_file(
- os.path.join(
- "asymmetric",
- "Traditional_OpenSSL_Serialization",
- "testrsa.pem"
- ),
- lambda pemfile: pemfile.read().encode()
+ key_path, lambda pemfile: pemfile.read(), mode="rb"
)
- key = serialization.load_pem_private_key(key_bytes, None, backend)
+ key = loader_func(key_bytes, None, backend)
serialized = key.private_bytes(
- serialization.Encoding.PEM,
+ encoding,
serialization.PrivateFormat.TraditionalOpenSSL,
serialization.NoEncryption()
)
assert serialized == key_bytes
+ def test_private_bytes_traditional_der_encrypted_invalid(self, backend):
+ key = RSA_KEY_2048.private_key(backend)
+ _skip_if_no_serialization(key, backend)
+ with pytest.raises(ValueError):
+ key.private_bytes(
+ serialization.Encoding.DER,
+ serialization.PrivateFormat.TraditionalOpenSSL,
+ serialization.BestAvailableEncryption(b"password")
+ )
+
def test_private_bytes_invalid_encoding(self, backend):
key = RSA_KEY_2048.private_key(backend)
_skip_if_no_serialization(key, backend)