summaryrefslogtreecommitdiff
path: root/tests/hazmat/primitives/test_serialization.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/hazmat/primitives/test_serialization.py')
-rw-r--r--tests/hazmat/primitives/test_serialization.py1459
1 files changed, 1198 insertions, 261 deletions
diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py
index 5dd724894..32debd46c 100644
--- a/tests/hazmat/primitives/test_serialization.py
+++ b/tests/hazmat/primitives/test_serialization.py
@@ -11,27 +11,58 @@ import textwrap
import pytest
-from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+import six
+
+from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.backends.interfaces import (
- DERSerializationBackend, DSABackend, EllipticCurveBackend,
- PEMSerializationBackend, RSABackend
+ DERSerializationBackend,
+ DSABackend,
+ EllipticCurveBackend,
+ PEMSerializationBackend,
+ RSABackend,
+)
+from cryptography.hazmat.primitives.asymmetric import (
+ dsa,
+ ec,
+ ed25519,
+ ed448,
+ rsa,
+ x25519,
+ x448,
)
-from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
from cryptography.hazmat.primitives.serialization import (
- BestAvailableEncryption, Encoding, NoEncryption,
- PrivateFormat, PublicFormat,
- load_der_parameters, load_der_private_key,
- load_der_public_key, load_pem_parameters, load_pem_private_key,
- load_pem_public_key, load_ssh_public_key
+ BestAvailableEncryption,
+ Encoding,
+ NoEncryption,
+ PrivateFormat,
+ PublicFormat,
+ load_der_parameters,
+ load_der_private_key,
+ load_der_public_key,
+ load_pem_parameters,
+ load_pem_private_key,
+ load_pem_public_key,
+ load_ssh_private_key,
+ load_ssh_public_key,
+ ssh,
)
from .test_ec import _skip_curve_unsupported
from .utils import (
- _check_dsa_private_numbers, _check_rsa_private_numbers,
- load_vectors_from_file
+ _check_dsa_private_numbers,
+ _check_rsa_private_numbers,
+ load_vectors_from_file,
)
-from ...utils import raises_unsupported_algorithm
+from ...doubles import DummyKeySerializationEncryption
+
+
+def _skip_fips_format(key_path, password, backend):
+ if backend._fips_enabled:
+ if key_path[0] == "Traditional_OpenSSL_Serialization":
+ pytest.skip("Traditional OpenSSL format blocked in FIPS mode")
+ if key_path[0] == "PEM_Serialization" and password is not None:
+ pytest.skip("Encrypted PEM_Serialization blocked in FIPS mode")
class TestBufferProtocolSerialization(object):
@@ -43,12 +74,13 @@ class TestBufferProtocolSerialization(object):
(["DER_Serialization", "enc2-rsa-pkcs8.der"], bytearray(b"baz")),
(["DER_Serialization", "unenc-rsa-pkcs8.der"], None),
(["DER_Serialization", "testrsa.der"], None),
- ]
+ ],
)
def test_load_der_rsa_private_key(self, key_path, password, backend):
data = load_vectors_from_file(
os.path.join("asymmetric", *key_path),
- lambda derfile: derfile.read(), mode="rb"
+ lambda derfile: derfile.read(),
+ mode="rb",
)
key = load_der_private_key(bytearray(data), password, backend)
assert key
@@ -61,21 +93,23 @@ class TestBufferProtocolSerialization(object):
[
(
["PEM_Serialization", "rsa_private_key.pem"],
- bytearray(b"123456")
+ bytearray(b"123456"),
),
(["PKCS8", "unenc-rsa-pkcs8.pem"], None),
(["PKCS8", "enc-rsa-pkcs8.pem"], bytearray(b"foobar")),
(["PKCS8", "enc2-rsa-pkcs8.pem"], bytearray(b"baz")),
(
["Traditional_OpenSSL_Serialization", "key1.pem"],
- bytearray(b"123456")
+ bytearray(b"123456"),
),
- ]
+ ],
)
def test_load_pem_rsa_private_key(self, key_path, password, backend):
+ _skip_fips_format(key_path, password, backend)
data = load_vectors_from_file(
os.path.join("asymmetric", *key_path),
- lambda pemfile: pemfile.read(), mode="rb"
+ lambda pemfile: pemfile.read(),
+ mode="rb",
)
key = load_pem_private_key(bytearray(data), password, backend)
assert key
@@ -93,7 +127,7 @@ class TestDERSerialization(object):
(["DER_Serialization", "enc2-rsa-pkcs8.der"], b"baz"),
(["DER_Serialization", "unenc-rsa-pkcs8.der"], None),
(["DER_Serialization", "testrsa.der"], None),
- ]
+ ],
)
def test_load_der_rsa_private_key(self, key_path, password, backend):
key = load_vectors_from_file(
@@ -101,7 +135,7 @@ class TestDERSerialization(object):
lambda derfile: load_der_private_key(
derfile.read(), password, backend
),
- mode="rb"
+ mode="rb",
)
assert key
assert isinstance(key, rsa.RSAPrivateKey)
@@ -115,7 +149,7 @@ class TestDERSerialization(object):
(["DER_Serialization", "dsa.1024.der"], None),
(["DER_Serialization", "dsa.2048.der"], None),
(["DER_Serialization", "dsa.3072.der"], None),
- ]
+ ],
)
def test_load_der_dsa_private_key(self, key_path, password, backend):
key = load_vectors_from_file(
@@ -123,17 +157,14 @@ class TestDERSerialization(object):
lambda derfile: load_der_private_key(
derfile.read(), password, backend
),
- mode="rb"
+ mode="rb",
)
assert key
assert isinstance(key, dsa.DSAPrivateKey)
_check_dsa_private_numbers(key.private_numbers())
@pytest.mark.parametrize(
- "key_path",
- [
- ["DER_Serialization", "enc-rsa-pkcs8.der"],
- ]
+ "key_path", [["DER_Serialization", "enc-rsa-pkcs8.der"]]
)
@pytest.mark.requires_backend_interface(interface=RSABackend)
def test_password_not_bytes(self, key_path, backend):
@@ -146,7 +177,7 @@ class TestDERSerialization(object):
lambda derfile: load_der_private_key(
derfile.read(), password, backend
),
- mode="rb"
+ mode="rb",
)
@pytest.mark.parametrize(
@@ -154,7 +185,7 @@ class TestDERSerialization(object):
[
(["DER_Serialization", "ec_private_key.der"], None),
(["DER_Serialization", "ec_private_key_encrypted.der"], b"123456"),
- ]
+ ],
)
@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
def test_load_der_ec_private_key(self, key_path, password, backend):
@@ -164,7 +195,7 @@ class TestDERSerialization(object):
lambda derfile: load_der_private_key(
derfile.read(), password, backend
),
- mode="rb"
+ mode="rb",
)
assert key
@@ -173,10 +204,7 @@ class TestDERSerialization(object):
assert key.curve.key_size == 256
@pytest.mark.parametrize(
- "key_path",
- [
- ["DER_Serialization", "enc-rsa-pkcs8.der"],
- ]
+ "key_path", [["DER_Serialization", "enc-rsa-pkcs8.der"]]
)
@pytest.mark.requires_backend_interface(interface=RSABackend)
def test_wrong_password(self, key_path, backend):
@@ -189,14 +217,11 @@ class TestDERSerialization(object):
lambda derfile: load_der_private_key(
derfile.read(), password, backend
),
- mode="rb"
+ mode="rb",
)
@pytest.mark.parametrize(
- "key_path",
- [
- ["DER_Serialization", "unenc-rsa-pkcs8.der"]
- ]
+ "key_path", [["DER_Serialization", "unenc-rsa-pkcs8.der"]]
)
@pytest.mark.requires_backend_interface(interface=RSABackend)
def test_unused_password(self, key_path, backend):
@@ -209,17 +234,14 @@ class TestDERSerialization(object):
lambda derfile: load_der_private_key(
derfile.read(), password, backend
),
- mode="rb"
+ mode="rb",
)
@pytest.mark.parametrize(
("key_path", "password"),
itertools.product(
- [
- ["DER_Serialization", "enc-rsa-pkcs8.der"],
- ],
- [b"", None]
- )
+ [["DER_Serialization", "enc-rsa-pkcs8.der"]], [b"", None]
+ ),
)
@pytest.mark.requires_backend_interface(interface=RSABackend)
def test_missing_password(self, key_path, password, backend):
@@ -231,16 +253,14 @@ class TestDERSerialization(object):
lambda derfile: load_der_private_key(
derfile.read(), password, backend
),
- mode="rb"
+ mode="rb",
)
def test_wrong_format(self, backend):
key_data = b"---- NOT A KEY ----\n"
with pytest.raises(ValueError):
- load_der_private_key(
- key_data, None, backend
- )
+ load_der_private_key(key_data, None, backend)
with pytest.raises(ValueError):
load_der_private_key(
@@ -249,7 +269,8 @@ class TestDERSerialization(object):
def test_corrupt_der_pkcs8(self, backend):
# unenc-rsa-pkcs8 with a bunch of data missing.
- key_data = textwrap.dedent("""\
+ key_data = textwrap.dedent(
+ """\
MIICdQIBADALBgkqhkiG9w0BAQEEggJhMIICXQIBAAKBgQC7JHoJfg6yNzLMOWet
8Z49a4KD0dCspMAYvo2YAMB7/wdEycocujbhJ2n/seONi+5XqTqqFkM5VBl8rmkk
FPZk/7x0xmdsTPECSWnHK+HhoaNDFPR3j8jQhVo1laxiqcEhAHegi5cwtFosuJAv
@@ -263,13 +284,12 @@ class TestDERSerialization(object):
z+KOpdpPRR5TQmbEMEspjsFpFymMiuYPgmihQbO2cJl1qScY5OkCQQCJ6m5tcN8l
Xxg/SNpjEIv+qAyUD96XVlOJlOIeLHQ8kYE0C6ZA+MsqYIzgAreJk88Yn0lU/X0/
mu/UpE/BRZmR
- """).encode()
+ """
+ ).encode()
bad_der = base64.b64decode(b"".join(key_data.splitlines()))
with pytest.raises(ValueError):
- load_der_private_key(
- bad_der, None, backend
- )
+ load_der_private_key(bad_der, None, backend)
with pytest.raises(ValueError):
load_der_private_key(
@@ -278,14 +298,16 @@ class TestDERSerialization(object):
def test_corrupt_traditional_format_der(self, backend):
# privkey with a bunch of data missing.
- key_data = textwrap.dedent("""\
+ key_data = textwrap.dedent(
+ """\
MIIBPAIBAAJBAKrbeqkuRk8VcRmWFmtP+LviMB3+6dizWW3DwaffznyHGAFwUJ/I
Tv0XtbsCyl3QoyKGhrOAy3RvPK5M38iuXT0CAwEAAQJAZ3cnzaHXM/bxGaR5CR1R
rD1qFBAVfoQFiOH9uPJgMaoAuoQEisPHVcZDKcOv4wEg6/TInAIXBnEigtqvRzuy
mvcpHZwQJdmdHHkGKAs37Dfxi67HbkUCIQCeZGliHXFa071Fp06ZeWlR2ADonTZz
rJBhdTe0v5pCeQIhAIZfkiGgGBX4cIuuckzEm43g9WMUjxP/0GlK39vIyihxAiEA
mymehFRT0MvqW5xAKAx7Pgkt8HVKwVhc2LwGKHE0DZM=
- """).encode()
+ """
+ ).encode()
bad_der = base64.b64decode(b"".join(key_data.splitlines()))
with pytest.raises(ValueError):
@@ -300,20 +322,20 @@ class TestDERSerialization(object):
"key_file",
[
os.path.join(
- "asymmetric", "DER_Serialization", "unenc-rsa-pkcs8.pub.der"),
+ "asymmetric", "DER_Serialization", "unenc-rsa-pkcs8.pub.der"
+ ),
os.path.join(
- "asymmetric", "DER_Serialization", "rsa_public_key.der"),
+ "asymmetric", "DER_Serialization", "rsa_public_key.der"
+ ),
os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.der"),
- ]
+ ],
)
@pytest.mark.requires_backend_interface(interface=RSABackend)
def test_load_der_rsa_public_key(self, key_file, backend):
key = load_vectors_from_file(
key_file,
- lambda derfile: load_der_public_key(
- derfile.read(), backend
- ),
- mode="rb"
+ lambda derfile: load_der_public_key(derfile.read(), backend),
+ mode="rb",
)
assert key
assert isinstance(key, rsa.RSAPublicKey)
@@ -328,19 +350,19 @@ class TestDERSerialization(object):
"key_file",
[
os.path.join(
- "asymmetric", "DER_Serialization", "unenc-dsa-pkcs8.pub.der"),
+ "asymmetric", "DER_Serialization", "unenc-dsa-pkcs8.pub.der"
+ ),
os.path.join(
- "asymmetric", "DER_Serialization", "dsa_public_key.der"),
- ]
+ "asymmetric", "DER_Serialization", "dsa_public_key.der"
+ ),
+ ],
)
@pytest.mark.requires_backend_interface(interface=DSABackend)
def test_load_der_dsa_public_key(self, key_file, backend):
key = load_vectors_from_file(
key_file,
- lambda derfile: load_der_public_key(
- derfile.read(), backend
- ),
- mode="rb"
+ lambda derfile: load_der_public_key(derfile.read(), backend),
+ mode="rb",
)
assert key
assert isinstance(key, dsa.DSAPublicKey)
@@ -350,12 +372,10 @@ class TestDERSerialization(object):
_skip_curve_unsupported(backend, ec.SECP256R1())
key = load_vectors_from_file(
os.path.join(
- "asymmetric", "DER_Serialization",
- "ec_public_key.der"),
- lambda derfile: load_der_public_key(
- derfile.read(), backend
+ "asymmetric", "DER_Serialization", "ec_public_key.der"
),
- mode="rb"
+ lambda derfile: load_der_public_key(derfile.read(), backend),
+ mode="rb",
)
assert key
assert isinstance(key, ec.EllipticCurvePublicKey)
@@ -366,9 +386,7 @@ class TestDERSerialization(object):
param_data = b"---- NOT A KEY ----\n"
with pytest.raises(ValueError):
- load_der_parameters(
- param_data, backend
- )
+ load_der_parameters(param_data, backend)
@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend)
@@ -393,16 +411,19 @@ class TestPEMSerialization(object):
(["Traditional_OpenSSL_Serialization", "key1.pem"], b"123456"),
(["Traditional_OpenSSL_Serialization", "key2.pem"], b"a123456"),
(["Traditional_OpenSSL_Serialization", "testrsa.pem"], None),
- (["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"],
- b"password"),
- ]
+ (
+ ["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"],
+ b"password",
+ ),
+ ],
)
def test_load_pem_rsa_private_key(self, key_file, password, backend):
+ _skip_fips_format(key_file, password, backend)
key = load_vectors_from_file(
os.path.join("asymmetric", *key_file),
lambda pemfile: load_pem_private_key(
pemfile.read().encode(), password, backend
- )
+ ),
)
assert key
@@ -417,14 +438,15 @@ class TestPEMSerialization(object):
(["Traditional_OpenSSL_Serialization", "dsa.3072.pem"], None),
(["PKCS8", "unenc-dsa-pkcs8.pem"], None),
(["PEM_Serialization", "dsa_private_key.pem"], b"123456"),
- ]
+ ],
)
def test_load_dsa_private_key(self, key_path, password, backend):
+ _skip_fips_format(key_path, password, backend)
key = load_vectors_from_file(
os.path.join("asymmetric", *key_path),
lambda pemfile: load_pem_private_key(
pemfile.read().encode(), password, backend
- )
+ ),
)
assert key
assert isinstance(key, dsa.DSAPrivateKey)
@@ -437,16 +459,17 @@ class TestPEMSerialization(object):
(["PKCS8", "ec_private_key_encrypted.pem"], b"123456"),
(["PEM_Serialization", "ec_private_key.pem"], None),
(["PEM_Serialization", "ec_private_key_encrypted.pem"], b"123456"),
- ]
+ ],
)
@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
def test_load_pem_ec_private_key(self, key_path, password, backend):
_skip_curve_unsupported(backend, ec.SECP256R1())
+ _skip_fips_format(key_path, password, backend)
key = load_vectors_from_file(
os.path.join("asymmetric", *key_path),
lambda pemfile: load_pem_private_key(
pemfile.read().encode(), password, backend
- )
+ ),
)
assert key
@@ -459,16 +482,17 @@ class TestPEMSerialization(object):
[
os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"),
os.path.join(
- "asymmetric", "PEM_Serialization", "rsa_public_key.pem"),
+ "asymmetric", "PEM_Serialization", "rsa_public_key.pem"
+ ),
os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.pem"),
- ]
+ ],
)
def test_load_pem_rsa_public_key(self, key_file, backend):
key = load_vectors_from_file(
key_file,
lambda pemfile: load_pem_public_key(
pemfile.read().encode(), backend
- )
+ ),
)
assert key
assert isinstance(key, rsa.RSAPublicKey)
@@ -480,16 +504,16 @@ class TestPEMSerialization(object):
[
os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"),
os.path.join(
- "asymmetric", "PEM_Serialization",
- "dsa_public_key.pem"),
- ]
+ "asymmetric", "PEM_Serialization", "dsa_public_key.pem"
+ ),
+ ],
)
def test_load_pem_dsa_public_key(self, key_file, backend):
key = load_vectors_from_file(
key_file,
lambda pemfile: load_pem_public_key(
pemfile.read().encode(), backend
- )
+ ),
)
assert key
assert isinstance(key, dsa.DSAPublicKey)
@@ -499,66 +523,70 @@ class TestPEMSerialization(object):
_skip_curve_unsupported(backend, ec.SECP256R1())
key = load_vectors_from_file(
os.path.join(
- "asymmetric", "PEM_Serialization",
- "ec_public_key.pem"),
+ "asymmetric", "PEM_Serialization", "ec_public_key.pem"
+ ),
lambda pemfile: load_pem_public_key(
pemfile.read().encode(), backend
- )
+ ),
)
assert key
assert isinstance(key, ec.EllipticCurvePublicKey)
assert key.curve.name == "secp256r1"
assert key.curve.key_size == 256
+ @pytest.mark.skip_fips(
+ reason="Traditional OpenSSL format blocked in FIPS mode"
+ )
def test_rsa_traditional_encrypted_values(self, backend):
pkey = load_vectors_from_file(
os.path.join(
- "asymmetric", "Traditional_OpenSSL_Serialization", "key1.pem"),
+ "asymmetric", "Traditional_OpenSSL_Serialization", "key1.pem"
+ ),
lambda pemfile: load_pem_private_key(
pemfile.read().encode(), b"123456", backend
- )
+ ),
)
assert pkey
numbers = pkey.private_numbers()
assert numbers.p == int(
"fb7d316fc51531b36d93adaefaf52db6ad5beb793d37c4cf9dfc1ddd17cfbafb",
- 16
+ 16,
)
assert numbers.q == int(
"df98264e646de9a0fbeab094e31caad5bc7adceaaae3c800ca0275dd4bb307f5",
- 16
+ 16,
)
assert numbers.d == int(
"db4848c36f478dd5d38f35ae519643b6b810d404bcb76c00e44015e56ca1cab0"
"7bb7ae91f6b4b43fcfc82a47d7ed55b8c575152116994c2ce5325ec24313b911",
- 16
+ 16,
)
assert numbers.dmp1 == int(
"ce997f967192c2bcc3853186f1559fd355c190c58ddc15cbf5de9b6df954c727",
- 16
+ 16,
)
assert numbers.dmq1 == int(
"b018a57ab20ffaa3862435445d863369b852cf70a67c55058213e3fe10e3848d",
- 16
+ 16,
)
assert numbers.iqmp == int(
"6a8d830616924f5cf2d1bc1973f97fde6b63e052222ac7be06aa2532d10bac76",
- 16
+ 16,
)
assert numbers.public_numbers.e == 65537
assert numbers.public_numbers.n == int(
"dba786074f2f0350ce1d99f5aed5b520cfe0deb5429ec8f2a88563763f566e77"
"9814b7c310e5326edae31198eed439b845dd2db99eaa60f5c16a43f4be6bcf37",
- 16
+ 16,
)
@pytest.mark.parametrize(
"key_path",
[
["Traditional_OpenSSL_Serialization", "testrsa.pem"],
- ["PKCS8", "unenc-rsa-pkcs8.pem"]
- ]
+ ["PKCS8", "unenc-rsa-pkcs8.pem"],
+ ],
)
def test_unused_password(self, key_path, backend):
key_file = os.path.join("asymmetric", *key_path)
@@ -569,15 +597,33 @@ class TestPEMSerialization(object):
key_file,
lambda pemfile: load_pem_private_key(
pemfile.read().encode(), password, backend
- )
+ ),
)
+ def test_invalid_encoding_with_traditional(self, backend):
+ key_file = os.path.join(
+ "asymmetric", "Traditional_OpenSSL_Serialization", "testrsa.pem"
+ )
+ key = load_vectors_from_file(
+ key_file,
+ lambda pemfile: load_pem_private_key(
+ pemfile.read(), None, backend
+ ),
+ mode="rb",
+ )
+
+ for enc in (Encoding.OpenSSH, Encoding.Raw, Encoding.X962):
+ with pytest.raises(ValueError):
+ key.private_bytes(
+ enc, PrivateFormat.TraditionalOpenSSL, NoEncryption()
+ )
+
@pytest.mark.parametrize(
"key_path",
[
["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"],
- ["PKCS8", "enc-rsa-pkcs8.pem"]
- ]
+ ["PKCS8", "enc-rsa-pkcs8.pem"],
+ ],
)
def test_password_not_bytes(self, key_path, backend):
key_file = os.path.join("asymmetric", *key_path)
@@ -588,15 +634,15 @@ class TestPEMSerialization(object):
key_file,
lambda pemfile: load_pem_private_key(
pemfile.read().encode(), password, backend
- )
+ ),
)
@pytest.mark.parametrize(
"key_path",
[
["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"],
- ["PKCS8", "enc-rsa-pkcs8.pem"]
- ]
+ ["PKCS8", "enc-rsa-pkcs8.pem"],
+ ],
)
def test_wrong_password(self, key_path, backend):
key_file = os.path.join("asymmetric", *key_path)
@@ -607,19 +653,18 @@ class TestPEMSerialization(object):
key_file,
lambda pemfile: load_pem_private_key(
pemfile.read().encode(), password, backend
- )
+ ),
)
@pytest.mark.parametrize(
("key_path", "password"),
itertools.product(
[
- ["Traditional_OpenSSL_Serialization",
- "testrsa-encrypted.pem"],
+ ["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"],
["PKCS8", "enc-rsa-pkcs8.pem"],
],
- [b"", None]
- )
+ [b"", None],
+ ),
)
def test_missing_password(self, key_path, password, backend):
key_file = os.path.join("asymmetric", *key_path)
@@ -629,16 +674,14 @@ class TestPEMSerialization(object):
key_file,
lambda pemfile: load_pem_private_key(
pemfile.read().encode(), password, backend
- )
+ ),
)
def test_wrong_private_format(self, backend):
key_data = b"---- NOT A KEY ----\n"
with pytest.raises(ValueError):
- load_pem_private_key(
- key_data, None, backend
- )
+ load_pem_private_key(key_data, None, backend)
with pytest.raises(ValueError):
load_pem_private_key(
@@ -659,7 +702,8 @@ class TestPEMSerialization(object):
def test_corrupt_traditional_format(self, backend):
# privkey.pem with a bunch of data missing.
- key_data = textwrap.dedent("""\
+ key_data = textwrap.dedent(
+ """\
-----BEGIN RSA PRIVATE KEY-----
MIIBPAIBAAJBAKrbeqkuRk8VcRmWFmtP+LviMB3+6dizWW3DwaffznyHGAFwUJ/I
Tv0XtbsCyl3QoyKGhrOAy3RvPK5M38iuXT0CAwEAAQJAZ3cnzaHXM/bxGaR5CR1R
@@ -668,12 +712,11 @@ class TestPEMSerialization(object):
rJBhdTe0v5pCeQIhAIZfkiGgGBX4cIuuckzEm43g9WMUjxP/0GlK39vIyihxAiEA
mymehFRT0MvqW5xAKAx7Pgkt8HVKwVhc2LwGKHE0DZM=
-----END RSA PRIVATE KEY-----
- """).encode()
+ """
+ ).encode()
with pytest.raises(ValueError):
- load_pem_private_key(
- key_data, None, backend
- )
+ load_pem_private_key(key_data, None, backend)
with pytest.raises(ValueError):
load_pem_private_key(
@@ -682,7 +725,8 @@ class TestPEMSerialization(object):
def test_traditional_encrypted_corrupt_format(self, backend):
# privkey.pem with a single bit flipped
- key_data = textwrap.dedent("""\
+ key_data = textwrap.dedent(
+ """\
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: <,ENCRYPTED
DEK-Info: AES-128-CBC,5E22A2BD85A653FB7A3ED20DE84F54CD
@@ -695,22 +739,20 @@ class TestPEMSerialization(object):
5A295jD9BQp9CY0nNFSsy+qiXWToq2xT3y5zVNEStmN0SCGNaIlUnJzL9IHW+oMI
kPmXZMnAYBWeeCF1gf3J3aE5lZInegHNfEI0+J0LazC2aNU5Dg/BNqrmRqKWEIo/
-----END RSA PRIVATE KEY-----
- """).encode()
+ """
+ ).encode()
password = b"this password is wrong"
with pytest.raises(ValueError):
- load_pem_private_key(
- key_data, None, backend
- )
+ load_pem_private_key(key_data, None, backend)
with pytest.raises(ValueError):
- load_pem_private_key(
- key_data, password, backend
- )
+ load_pem_private_key(key_data, password, backend)
def test_unsupported_key_encryption(self, backend):
- key_data = textwrap.dedent("""\
+ key_data = textwrap.dedent(
+ """\
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: FAKE-123,5E22A2BD85A653FB7A3ED20DE84F54CD
@@ -723,18 +765,18 @@ class TestPEMSerialization(object):
5A295jD9BQp9CY0nNFSsy+qiXWToq2xT3y5zVNEStmN0SCGNaIlUnJzL9IHW+oMI
kPmXZMnAYBWeeCF1gf3J3aE5lZInegHNfEI0+J0LazC2aNU5Dg/BNqrmRqKWEIo/
-----END RSA PRIVATE KEY-----
- """).encode()
+ """
+ ).encode()
password = b"password"
- with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
- load_pem_private_key(
- key_data, password, backend
- )
+ with pytest.raises(ValueError):
+ load_pem_private_key(key_data, password, backend)
def test_corrupt_pkcs8_format(self, backend):
# unenc-rsa-pkcs8.pem with a bunch of data missing.
- key_data = textwrap.dedent("""\
+ key_data = textwrap.dedent(
+ """\
-----BEGIN PRIVATE KEY-----
MIICdQIBADALBgkqhkiG9w0BAQEEggJhMIICXQIBAAKBgQC7JHoJfg6yNzLMOWet
8Z49a4KD0dCspMAYvo2YAMB7/wdEycocujbhJ2n/seONi+5XqTqqFkM5VBl8rmkk
@@ -750,12 +792,11 @@ class TestPEMSerialization(object):
Xxg/SNpjEIv+qAyUD96XVlOJlOIeLHQ8kYE0C6ZA+MsqYIzgAreJk88Yn0lU/X0/
mu/UpE/BRZmR
-----END PRIVATE KEY-----
- """).encode()
+ """
+ ).encode()
with pytest.raises(ValueError):
- load_pem_private_key(
- key_data, None, backend
- )
+ load_pem_private_key(key_data, None, backend)
with pytest.raises(ValueError):
load_pem_private_key(
@@ -764,7 +805,8 @@ class TestPEMSerialization(object):
def test_pks8_encrypted_corrupt_format(self, backend):
# enc-rsa-pkcs8.pem with some bits flipped.
- key_data = textwrap.dedent("""\
+ key_data = textwrap.dedent(
+ """\
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIICojAcBgoqhkiG9w0BDAEDMA4ECHK0M0+QuEL9AgIBIcSCAoDRq+KRY+0XP0tO
lwBTzViiXSXoyNnKAZKt5r5K/fGNntv22g/1s/ZNCetrqsJDC5eMUPPacz06jFq/
@@ -782,27 +824,23 @@ class TestPEMSerialization(object):
6JLgl8FrvdfjHwIvmSOO1YMNmILBq000Q8WDqyErBDs4hsvtO6VQ4LeqJj6gClX3
qeJNaJFu
-----END ENCRYPTED PRIVATE KEY-----
- """).encode()
+ """
+ ).encode()
password = b"this password is wrong"
with pytest.raises(ValueError):
- load_pem_private_key(
- key_data, None, backend
- )
+ load_pem_private_key(key_data, None, backend)
with pytest.raises(ValueError):
- load_pem_private_key(
- key_data, password, backend
- )
+ load_pem_private_key(key_data, password, backend)
def test_rsa_pkcs8_encrypted_values(self, backend):
pkey = load_vectors_from_file(
- os.path.join(
- "asymmetric", "PKCS8", "enc-rsa-pkcs8.pem"),
+ os.path.join("asymmetric", "PKCS8", "enc-rsa-pkcs8.pem"),
lambda pemfile: load_pem_private_key(
pemfile.read().encode(), b"foobar", backend
- )
+ ),
)
assert pkey
@@ -813,7 +851,8 @@ class TestPEMSerialization(object):
"376a7fe5b19f95b35ca358ea5c8abd7ae051d49cd2f1e45969a1ae945460"
"3c14b278664a0e414ebc8913acb6203626985525e17a600611b028542dd0"
"562aad787fb4f1650aa318cdcff751e1b187cbf6785fbe164e9809491b95"
- "dd68480567c99b1a57", 16
+ "dd68480567c99b1a57",
+ 16,
)
assert numbers.public_numbers.e == 65537
@@ -823,37 +862,43 @@ class TestPEMSerialization(object):
"f3d9785c3a2c09e4c8090909fb3721e19a3009ec21221523a729265707a5"
"8f13063671c42a4096cad378ef2510cb59e23071489d8893ac4934dd149f"
"34f2d094bea57f1c8027c3a77248ac9b91218737d0c3c3dfa7d7829e6977"
- "cf7d995688c86c81", 16
+ "cf7d995688c86c81",
+ 16,
)
assert numbers.p == int(
"00db122ac857b2c0437d7616daa98e597bb75ca9ad3a47a70bec10c10036"
"03328794b225c8e3eee6ffd3fd6d2253d28e071fe27d629ab072faa14377"
- "ce6118cb67", 16
+ "ce6118cb67",
+ 16,
)
assert numbers.q == int(
"00df1b8aa8506fcbbbb9d00257f2975e38b33d2698fd0f37e82d7ef38c56"
"f21b6ced63c825383782a7115cfcc093300987dbd2853b518d1c8f26382a"
- "2d2586d391", 16
+ "2d2586d391",
+ 16,
)
assert numbers.dmp1 == int(
"00be18aca13e60712fdf5daa85421eb10d86d654b269e1255656194fb0c4"
"2dd01a1070ea12c19f5c39e09587af02f7b1a1030d016a9ffabf3b36d699"
- "ceaf38d9bf", 16
+ "ceaf38d9bf",
+ 16,
)
assert numbers.dmq1 == int(
"71aa8978f90a0c050744b77cf1263725b203ac9f730606d8ae1d289dce4a"
"28b8d534e9ea347aeb808c73107e583eb80c546d2bddadcdb3c82693a4c1"
- "3d863451", 16
+ "3d863451",
+ 16,
)
assert numbers.iqmp == int(
"136b7b1afac6e6279f71b24217b7083485a5e827d156024609dae39d48a6"
"bdb55af2f062cc4a3b077434e6fffad5faa29a2b5dba2bed3e4621e478c0"
- "97ccfe7f", 16
+ "97ccfe7f",
+ 16,
)
def test_load_pem_dsa_private_key(self, backend):
@@ -861,7 +906,7 @@ class TestPEMSerialization(object):
os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"),
lambda pemfile: load_pem_private_key(
pemfile.read().encode(), None, backend
- )
+ ),
)
assert key
assert isinstance(key, dsa.DSAPrivateKey)
@@ -872,15 +917,14 @@ class TestPEMSerialization(object):
num = key.private_numbers()
pub = num.public_numbers
parameter_numbers = pub.parameter_numbers
- assert num.x == int("00a535a8e1d0d91beafc8bee1d9b2a3a8de3311203",
- 16)
+ assert num.x == int("00a535a8e1d0d91beafc8bee1d9b2a3a8de3311203", 16)
assert pub.y == int(
"2b260ea97dc6a12ae932c640e7df3d8ff04a8a05a0324f8d5f1b23f15fa1"
"70ff3f42061124eff2586cb11b49a82dcdc1b90fc6a84fb10109cb67db5d"
"2da971aeaf17be5e37284563e4c64d9e5fc8480258b319f0de29d54d8350"
"70d9e287914d77df81491f4423b62da984eb3f45eb2a29fcea5dae525ac6"
"ab6bcce04bfdf5b6",
- 16
+ 16,
)
assert parameter_numbers.p == int(
@@ -889,11 +933,12 @@ class TestPEMSerialization(object):
"071d4dceb2782794ad393cc08a4d4ada7f68d6e839a5fcd34b4e402d82cb"
"8a8cb40fec31911bf9bd360b034caacb4c5e947992573c9e90099c1b0f05"
"940cabe5d2de49a167",
- 16
+ 16,
)
assert parameter_numbers.q == int(
- "00adc0e869b36f0ac013a681fdf4d4899d69820451", 16)
+ "00adc0e869b36f0ac013a681fdf4d4899d69820451", 16
+ )
assert parameter_numbers.g == int(
"008c6b4589afa53a4d1048bfc346d1f386ca75521ccf72ddaa251286880e"
@@ -901,69 +946,61 @@ class TestPEMSerialization(object):
"e71141ba324f5b93131929182c88a9fa4062836066cebe74b5c6690c7d10"
"1106c240ab7ebd54e4e3301fd086ce6adac922fb2713a2b0887cba13b9bc"
"68ce5cfff241cd3246",
- 16
+ 16,
)
@pytest.mark.parametrize(
- ("key_file", "password"),
- [
- ("bad-oid-dsa-key.pem", None),
- ]
+ ("key_file", "password"), [("bad-oid-dsa-key.pem", None)]
)
def test_load_bad_oid_key(self, key_file, password, backend):
with pytest.raises(ValueError):
load_vectors_from_file(
- os.path.join(
- "asymmetric", "PKCS8", key_file),
+ os.path.join("asymmetric", "PKCS8", key_file),
lambda pemfile: load_pem_private_key(
pemfile.read().encode(), password, backend
- )
+ ),
)
@pytest.mark.parametrize(
- ("key_file", "password"),
- [
- ("bad-encryption-oid.pem", b"password"),
- ]
+ ("key_file", "password"), [("bad-encryption-oid.pem", b"password")]
)
def test_load_bad_encryption_oid_key(self, key_file, password, backend):
- with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
+ with pytest.raises(ValueError):
load_vectors_from_file(
- os.path.join(
- "asymmetric", "PKCS8", key_file),
+ os.path.join("asymmetric", "PKCS8", key_file),
lambda pemfile: load_pem_private_key(
pemfile.read().encode(), password, backend
- )
+ ),
)
@pytest.mark.requires_backend_interface(interface=RSABackend)
class TestRSASSHSerialization(object):
def test_load_ssh_public_key_unsupported(self, backend):
- ssh_key = b'ecdsa-sha2-junk AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY='
+ ssh_key = b"ecdsa-sha2-junk AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY="
with pytest.raises(UnsupportedAlgorithm):
load_ssh_public_key(ssh_key, backend)
def test_load_ssh_public_key_bad_format(self, backend):
- ssh_key = b'ssh-rsa not-a-real-key'
+ ssh_key = b"ssh-rsa not-a-real-key"
with pytest.raises(ValueError):
load_ssh_public_key(ssh_key, backend)
def test_load_ssh_public_key_rsa_too_short(self, backend):
- ssh_key = b'ssh-rsa'
+ ssh_key = b"ssh-rsa"
with pytest.raises(ValueError):
load_ssh_public_key(ssh_key, backend)
def test_load_ssh_public_key_truncated_int(self, backend):
- ssh_key = b'ssh-rsa AAAAB3NzaC1yc2EAAAA='
+ ssh_key = b"ssh-rsa AAAAB3NzaC1yc2EAAAA="
with pytest.raises(ValueError):
load_ssh_public_key(ssh_key, backend)
- ssh_key = b'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAACKr+IHXo'
+ ssh_key = b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAACKr+IHXo"
with pytest.raises(ValueError):
load_ssh_public_key(ssh_key, backend)
@@ -1032,16 +1069,18 @@ class TestRSASSHSerialization(object):
expected_e = 0x10001
expected_n = int(
- '00C3BBF5D13F59322BA0A0B77EA0B6CF570241628AE24B5BA454D'
- '23DCA295652B3523B67752653DFFD69587FAD9578DD6406F23691'
- 'EA491C3F8B2D391D0312D9653C303B651067ADF887A5241843CEF'
- '8019680A088E092FEC305FB04EA070340BB9BD0F1635B2AD84142'
- '61B4E2D010ABD8FC6D2FB768912F78EE6B05A60857532B75B75EF'
- 'C007601A4EF58BA947B7E75E38F3443CDD87E7C138A1DAD9D9FB3'
- '19FF69DA43A9F6F6B0CD243F042CD1A5AFAEB286BD46AEB2D922B'
- 'D01385D6892167074A0907F94A2BF08A54ABB2FFFFC89920861D0'
- '46F8706AB88DDADBD9E8204D48B87789081E074024C8996783B31'
- '7076A98ABF0A2D8550EAF2097D8CCC7BE76EF', 16)
+ "00C3BBF5D13F59322BA0A0B77EA0B6CF570241628AE24B5BA454D"
+ "23DCA295652B3523B67752653DFFD69587FAD9578DD6406F23691"
+ "EA491C3F8B2D391D0312D9653C303B651067ADF887A5241843CEF"
+ "8019680A088E092FEC305FB04EA070340BB9BD0F1635B2AD84142"
+ "61B4E2D010ABD8FC6D2FB768912F78EE6B05A60857532B75B75EF"
+ "C007601A4EF58BA947B7E75E38F3443CDD87E7C138A1DAD9D9FB3"
+ "19FF69DA43A9F6F6B0CD243F042CD1A5AFAEB286BD46AEB2D922B"
+ "D01385D6892167074A0907F94A2BF08A54ABB2FFFFC89920861D0"
+ "46F8706AB88DDADBD9E8204D48B87789081E074024C8996783B31"
+ "7076A98ABF0A2D8550EAF2097D8CCC7BE76EF",
+ 16,
+ )
expected = rsa.RSAPublicNumbers(expected_e, expected_n)
@@ -1051,7 +1090,7 @@ class TestRSASSHSerialization(object):
@pytest.mark.requires_backend_interface(interface=DSABackend)
class TestDSSSSHSerialization(object):
def test_load_ssh_public_key_dss_too_short(self, backend):
- ssh_key = b'ssh-dss'
+ ssh_key = b"ssh-dss"
with pytest.raises(ValueError):
load_ssh_public_key(ssh_key, backend)
@@ -1134,14 +1173,16 @@ class TestDSSSSHSerialization(object):
"96a7032c01cdd8485b5cbfb73a46bb04708f98a18bc88d4c7812b284da8f900"
"6e473e89897f9bc9125c69bbfd8ef691c0e76c1c34e6c843b8fe240e6e5aeb3"
"13486e5fa917ab1288ff1a6ebcf9dcdeed3c5fc88474e30476f53a5ec816ef6"
- "9f4", 16
+ "9f4",
+ 16,
)
expected_p = int(
"b9b052d7f07630148d4d838b17790ef4f43437238ebebd5032ea483fd7b7902"
"5ec3dc65ebd563ab586a633b4344f6acd10af31353bcf29111fa5e3b8d5c1e8"
"7befe3c65f9b8be69c740716698c8366c8ef925b9cec1dcd69e73d926b554e2"
"b4b6ddd1453eab39ba0f846e1555adcc33c5a8637128c9ed61104a45505a748"
- "f6db", 16
+ "f6db",
+ 16,
)
expected_q = 1230879958723280233885494314531920096931919647917
expected_g = int(
@@ -1149,11 +1190,12 @@ class TestDSSSSHSerialization(object):
"7bc249b6cf8f5f5c5022afefd4df5bf9d13bbdf182df5af2a5c5d1dc7604185"
"7d5b0e4b22b856c300f850a3b00bac394b728755b8b7a56522eefc491573967"
"debb5982fc94d6a8c291f758feae63ad769a5621947221522a2dc31d18ede6f"
- "b656", 16
+ "b656",
+ 16,
)
expected = dsa.DSAPublicNumbers(
expected_y,
- dsa.DSAParameterNumbers(expected_p, expected_q, expected_g)
+ dsa.DSAParameterNumbers(expected_p, expected_q, expected_g),
)
assert numbers == expected
@@ -1174,17 +1216,32 @@ class TestECDSASSHSerialization(object):
expected_x = int(
"44196257377740326295529888716212621920056478823906609851236662550"
- "785814128027", 10
+ "785814128027",
+ 10,
)
expected_y = int(
"12257763433170736656417248739355923610241609728032203358057767672"
- "925775019611", 10
+ "925775019611",
+ 10,
)
assert key.public_numbers() == ec.EllipticCurvePublicNumbers(
expected_x, expected_y, ec.SECP256R1()
)
+ def test_load_ssh_public_key_byteslike(self, backend):
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+
+ ssh_key = (
+ b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy"
+ b"NTYAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5"
+ b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01"
+ )
+ assert load_ssh_public_key(bytearray(ssh_key), backend)
+ if six.PY3:
+ assert load_ssh_public_key(memoryview(ssh_key), backend)
+ assert load_ssh_public_key(memoryview(bytearray(ssh_key)), backend)
+
def test_load_ssh_public_key_ecdsa_nist_p384(self, backend):
_skip_curve_unsupported(backend, ec.SECP384R1())
ssh_key = (
@@ -1197,11 +1254,13 @@ class TestECDSASSHSerialization(object):
expected_x = int(
"31541830871345183397582554827482786756220448716666815789487537666"
- "592636882822352575507883817901562613492450642523901", 10
+ "592636882822352575507883817901562613492450642523901",
+ 10,
)
expected_y = int(
"15111413269431823234030344298767984698884955023183354737123929430"
- "995703524272335782455051101616329050844273733614670", 10
+ "995703524272335782455051101616329050844273733614670",
+ 10,
)
assert key.public_numbers() == ec.EllipticCurvePublicNumbers(
@@ -1222,12 +1281,14 @@ class TestECDSASSHSerialization(object):
expected_x = int(
"54124123120178189598842622575230904027376313369742467279346415219"
"77809037378785192537810367028427387173980786968395921877911964629"
- "142163122798974160187785455", 10
+ "142163122798974160187785455",
+ 10,
)
expected_y = int(
"16111775122845033200938694062381820957441843014849125660011303579"
"15284560361402515564433711416776946492019498546572162801954089916"
- "006665939539407104638103918", 10
+ "006665939539407104638103918",
+ 10,
)
assert key.public_numbers() == ec.EllipticCurvePublicNumbers(
@@ -1274,6 +1335,51 @@ class TestECDSASSHSerialization(object):
load_ssh_public_key(ssh_key, backend)
+@pytest.mark.supported(
+ only_if=lambda backend: backend.ed25519_supported(),
+ skip_message="Requires OpenSSL with Ed25519 support",
+)
+class TestEd25519SSHSerialization(object):
+ def test_load_ssh_public_key(self, backend):
+ ssh_key = (
+ b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG2fgpmpYO61qeAxGd0wgRaN/E4"
+ b"GR+xWvBmvxjxrB1vG user@chiron.local"
+ )
+ key = load_ssh_public_key(ssh_key, backend)
+ assert isinstance(key, ed25519.Ed25519PublicKey)
+ assert key.public_bytes(Encoding.Raw, PublicFormat.Raw) == (
+ b"m\x9f\x82\x99\xa9`\xee\xb5\xa9\xe01\x19\xdd0\x81\x16\x8d\xfc"
+ b"N\x06G\xecV\xbc\x19\xaf\xc6<k\x07[\xc6"
+ )
+
+ def test_public_bytes_openssh(self, backend):
+ ssh_key = (
+ b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG2fgpmpYO61qeAxGd0wgRaN/E4"
+ b"GR+xWvBmvxjxrB1vG"
+ )
+ key = load_ssh_public_key(ssh_key, backend)
+ assert isinstance(key, ed25519.Ed25519PublicKey)
+ assert (
+ key.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH) == ssh_key
+ )
+
+ def test_load_ssh_public_key_not_32_bytes(self, backend):
+ ssh_key = (
+ b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI22fgpmpYO61qeAxGd0wgRaN/E4"
+ b"GR+xWvBmvxjxrB1vGaGVs user@chiron.local"
+ )
+ with pytest.raises(ValueError):
+ load_ssh_public_key(ssh_key, backend)
+
+ def test_load_ssh_public_key_trailing_data(self, backend):
+ ssh_key = (
+ b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG2fgpmpYO61qeAxGd0wgRa"
+ b"N/E4GR+xWvBmvxjxrB1vGdHJhaWxpbmdkYXRh user@chiron.local"
+ )
+ with pytest.raises(ValueError):
+ load_ssh_public_key(ssh_key, backend)
+
+
class TestKeySerializationEncryptionTypes(object):
def test_non_bytes_password(self):
with pytest.raises(ValueError):
@@ -1285,128 +1391,959 @@ class TestKeySerializationEncryptionTypes(object):
@pytest.mark.supported(
- only_if=lambda backend: backend.x448_supported(),
- skip_message="Requires OpenSSL with X448 support"
+ only_if=lambda backend: backend.ed25519_supported(),
+ skip_message="Requires OpenSSL with Ed25519 support",
)
-class TestX448Serialization(object):
+class TestEd25519Serialization(object):
def test_load_der_private_key(self, backend):
data = load_vectors_from_file(
- os.path.join("asymmetric", "X448", "x448-pkcs8-enc.der"),
+ os.path.join("asymmetric", "Ed25519", "ed25519-pkcs8-enc.der"),
lambda derfile: derfile.read(),
- mode="rb"
+ mode="rb",
)
unencrypted = load_vectors_from_file(
- os.path.join("asymmetric", "X448", "x448-pkcs8.der"),
+ os.path.join("asymmetric", "Ed25519", "ed25519-pkcs8.der"),
lambda derfile: derfile.read(),
- mode="rb"
+ mode="rb",
)
key = load_der_private_key(data, b"password", backend)
- assert key.private_bytes(
- Encoding.DER, PrivateFormat.PKCS8, NoEncryption()
- ) == unencrypted
+ assert (
+ key.private_bytes(
+ Encoding.DER, PrivateFormat.PKCS8, NoEncryption()
+ )
+ == unencrypted
+ )
def test_load_pem_private_key(self, backend):
data = load_vectors_from_file(
- os.path.join("asymmetric", "X448", "x448-pkcs8-enc.pem"),
+ os.path.join("asymmetric", "Ed25519", "ed25519-pkcs8-enc.pem"),
lambda pemfile: pemfile.read(),
- mode="rb"
+ mode="rb",
)
unencrypted = load_vectors_from_file(
- os.path.join("asymmetric", "X448", "x448-pkcs8.pem"),
+ os.path.join("asymmetric", "Ed25519", "ed25519-pkcs8.pem"),
lambda pemfile: pemfile.read(),
- mode="rb"
+ mode="rb",
)
key = load_pem_private_key(data, b"password", backend)
- assert key.private_bytes(
- Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()
- ) == unencrypted
+ assert (
+ key.private_bytes(
+ Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()
+ )
+ == unencrypted
+ )
@pytest.mark.parametrize(
("key_path", "encoding", "loader"),
[
(
- ["X448", "x448-pub.pem"],
+ ["Ed25519", "ed25519-pub.pem"],
Encoding.PEM,
- load_pem_public_key
+ load_pem_public_key,
),
(
- ["X448", "x448-pub.der"],
+ ["Ed25519", "ed25519-pub.der"],
Encoding.DER,
- load_der_public_key
+ load_der_public_key,
),
- ]
+ ],
)
def test_load_public_key(self, key_path, encoding, loader, backend):
data = load_vectors_from_file(
os.path.join("asymmetric", *key_path),
lambda pemfile: pemfile.read(),
- mode="rb"
+ mode="rb",
)
public_key = loader(data, backend)
- assert public_key.public_bytes(
- encoding, PublicFormat.SubjectPublicKeyInfo
- ) == data
+ assert (
+ public_key.public_bytes(
+ encoding, PublicFormat.SubjectPublicKeyInfo
+ )
+ == data
+ )
+
+ def test_openssl_serialization_unsupported(self, backend):
+ key = ed25519.Ed25519PrivateKey.generate()
+ with pytest.raises(ValueError):
+ key.private_bytes(
+ Encoding.PEM,
+ PrivateFormat.TraditionalOpenSSL,
+ NoEncryption(),
+ )
+ with pytest.raises(ValueError):
+ key.private_bytes(
+ Encoding.DER,
+ PrivateFormat.TraditionalOpenSSL,
+ NoEncryption(),
+ )
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.x448_supported(),
+ skip_message="Requires OpenSSL with X448 support",
+)
+class TestX448Serialization(object):
+ def test_load_der_private_key(self, backend):
+ data = load_vectors_from_file(
+ os.path.join("asymmetric", "X448", "x448-pkcs8-enc.der"),
+ lambda derfile: derfile.read(),
+ mode="rb",
+ )
+ unencrypted = load_vectors_from_file(
+ os.path.join("asymmetric", "X448", "x448-pkcs8.der"),
+ lambda derfile: derfile.read(),
+ mode="rb",
+ )
+ key = load_der_private_key(data, b"password", backend)
+ assert (
+ key.private_bytes(
+ Encoding.DER, PrivateFormat.PKCS8, NoEncryption()
+ )
+ == unencrypted
+ )
+
+ def test_load_pem_private_key(self, backend):
+ data = load_vectors_from_file(
+ os.path.join("asymmetric", "X448", "x448-pkcs8-enc.pem"),
+ lambda pemfile: pemfile.read(),
+ mode="rb",
+ )
+ unencrypted = load_vectors_from_file(
+ os.path.join("asymmetric", "X448", "x448-pkcs8.pem"),
+ lambda pemfile: pemfile.read(),
+ mode="rb",
+ )
+ key = load_pem_private_key(data, b"password", backend)
+ assert (
+ key.private_bytes(
+ Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()
+ )
+ == unencrypted
+ )
+
+ @pytest.mark.parametrize(
+ ("key_path", "encoding", "loader"),
+ [
+ (["X448", "x448-pub.pem"], Encoding.PEM, load_pem_public_key),
+ (["X448", "x448-pub.der"], Encoding.DER, load_der_public_key),
+ ],
+ )
+ def test_load_public_key(self, key_path, encoding, loader, backend):
+ data = load_vectors_from_file(
+ os.path.join("asymmetric", *key_path),
+ lambda pemfile: pemfile.read(),
+ mode="rb",
+ )
+ public_key = loader(data, backend)
+ assert (
+ public_key.public_bytes(
+ encoding, PublicFormat.SubjectPublicKeyInfo
+ )
+ == data
+ )
+
+ def test_openssl_serialization_unsupported(self, backend):
+ key = x448.X448PrivateKey.generate()
+ with pytest.raises(ValueError):
+ key.private_bytes(
+ Encoding.PEM,
+ PrivateFormat.TraditionalOpenSSL,
+ NoEncryption(),
+ )
+ with pytest.raises(ValueError):
+ key.private_bytes(
+ Encoding.DER,
+ PrivateFormat.TraditionalOpenSSL,
+ NoEncryption(),
+ )
+
+ def test_openssh_serialization_unsupported(self, backend):
+ key = x448.X448PrivateKey.generate()
+ with pytest.raises(ValueError):
+ key.public_key().public_bytes(
+ Encoding.OpenSSH, PublicFormat.OpenSSH
+ )
+ with pytest.raises(ValueError):
+ key.private_bytes(
+ Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption()
+ )
@pytest.mark.supported(
only_if=lambda backend: backend.x25519_supported(),
- skip_message="Requires OpenSSL with X25519 support"
+ skip_message="Requires OpenSSL with X25519 support",
)
class TestX25519Serialization(object):
def test_load_der_private_key(self, backend):
data = load_vectors_from_file(
os.path.join("asymmetric", "X25519", "x25519-pkcs8-enc.der"),
lambda derfile: derfile.read(),
- mode="rb"
+ mode="rb",
)
unencrypted = load_vectors_from_file(
os.path.join("asymmetric", "X25519", "x25519-pkcs8.der"),
lambda derfile: derfile.read(),
- mode="rb"
+ mode="rb",
)
key = load_der_private_key(data, b"password", backend)
- assert key.private_bytes(
- Encoding.DER, PrivateFormat.PKCS8, NoEncryption()
- ) == unencrypted
+ assert (
+ key.private_bytes(
+ Encoding.DER, PrivateFormat.PKCS8, NoEncryption()
+ )
+ == unencrypted
+ )
def test_load_pem_private_key(self, backend):
data = load_vectors_from_file(
os.path.join("asymmetric", "X25519", "x25519-pkcs8-enc.pem"),
lambda pemfile: pemfile.read(),
- mode="rb"
+ mode="rb",
)
unencrypted = load_vectors_from_file(
os.path.join("asymmetric", "X25519", "x25519-pkcs8.pem"),
lambda pemfile: pemfile.read(),
- mode="rb"
+ mode="rb",
)
key = load_pem_private_key(data, b"password", backend)
- assert key.private_bytes(
- Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()
- ) == unencrypted
+ assert (
+ key.private_bytes(
+ Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()
+ )
+ == unencrypted
+ )
@pytest.mark.parametrize(
("key_path", "encoding", "loader"),
[
- (
- ["X25519", "x25519-pub.pem"],
+ (["X25519", "x25519-pub.pem"], Encoding.PEM, load_pem_public_key),
+ (["X25519", "x25519-pub.der"], Encoding.DER, load_der_public_key),
+ ],
+ )
+ def test_load_public_key(self, key_path, encoding, loader, backend):
+ data = load_vectors_from_file(
+ os.path.join("asymmetric", *key_path),
+ lambda pemfile: pemfile.read(),
+ mode="rb",
+ )
+ public_key = loader(data, backend)
+ assert (
+ public_key.public_bytes(
+ encoding, PublicFormat.SubjectPublicKeyInfo
+ )
+ == data
+ )
+
+ def test_openssl_serialization_unsupported(self, backend):
+ key = x25519.X25519PrivateKey.generate()
+ with pytest.raises(ValueError):
+ key.private_bytes(
Encoding.PEM,
- load_pem_public_key
- ),
- (
- ["X25519", "x25519-pub.der"],
+ PrivateFormat.TraditionalOpenSSL,
+ NoEncryption(),
+ )
+ with pytest.raises(ValueError):
+ key.private_bytes(
Encoding.DER,
- load_der_public_key
- ),
- ]
+ PrivateFormat.TraditionalOpenSSL,
+ NoEncryption(),
+ )
+
+ def test_openssh_serialization_unsupported(self, backend):
+ key = x25519.X25519PrivateKey.generate()
+ with pytest.raises(ValueError):
+ key.public_key().public_bytes(
+ Encoding.OpenSSH, PublicFormat.OpenSSH
+ )
+ with pytest.raises(ValueError):
+ key.private_bytes(
+ Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption()
+ )
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.ed448_supported(),
+ skip_message="Requires OpenSSL with Ed448 support",
+)
+class TestEd448Serialization(object):
+ def test_load_der_private_key(self, backend):
+ data = load_vectors_from_file(
+ os.path.join("asymmetric", "Ed448", "ed448-pkcs8-enc.der"),
+ lambda derfile: derfile.read(),
+ mode="rb",
+ )
+ unencrypted = load_vectors_from_file(
+ os.path.join("asymmetric", "Ed448", "ed448-pkcs8.der"),
+ lambda derfile: derfile.read(),
+ mode="rb",
+ )
+ key = load_der_private_key(data, b"password", backend)
+ assert (
+ key.private_bytes(
+ Encoding.DER, PrivateFormat.PKCS8, NoEncryption()
+ )
+ == unencrypted
+ )
+
+ def test_load_pem_private_key(self, backend):
+ data = load_vectors_from_file(
+ os.path.join("asymmetric", "Ed448", "ed448-pkcs8-enc.pem"),
+ lambda pemfile: pemfile.read(),
+ mode="rb",
+ )
+ unencrypted = load_vectors_from_file(
+ os.path.join("asymmetric", "Ed448", "ed448-pkcs8.pem"),
+ lambda pemfile: pemfile.read(),
+ mode="rb",
+ )
+ key = load_pem_private_key(data, b"password", backend)
+ assert (
+ key.private_bytes(
+ Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()
+ )
+ == unencrypted
+ )
+
+ @pytest.mark.parametrize(
+ ("key_path", "encoding", "loader"),
+ [
+ (["Ed448", "ed448-pub.pem"], Encoding.PEM, load_pem_public_key),
+ (["Ed448", "ed448-pub.der"], Encoding.DER, load_der_public_key),
+ ],
)
def test_load_public_key(self, key_path, encoding, loader, backend):
data = load_vectors_from_file(
os.path.join("asymmetric", *key_path),
lambda pemfile: pemfile.read(),
- mode="rb"
+ mode="rb",
)
public_key = loader(data, backend)
- assert public_key.public_bytes(
- encoding, PublicFormat.SubjectPublicKeyInfo
- ) == data
+ assert (
+ public_key.public_bytes(
+ encoding, PublicFormat.SubjectPublicKeyInfo
+ )
+ == data
+ )
+
+ def test_openssl_serialization_unsupported(self, backend):
+ key = ed448.Ed448PrivateKey.generate()
+ with pytest.raises(ValueError):
+ key.private_bytes(
+ Encoding.PEM,
+ PrivateFormat.TraditionalOpenSSL,
+ NoEncryption(),
+ )
+ with pytest.raises(ValueError):
+ key.private_bytes(
+ Encoding.DER,
+ PrivateFormat.TraditionalOpenSSL,
+ NoEncryption(),
+ )
+
+ def test_openssh_serialization_unsupported(self, backend):
+ key = ed448.Ed448PrivateKey.generate()
+ with pytest.raises(ValueError):
+ key.public_key().public_bytes(
+ Encoding.OpenSSH,
+ PublicFormat.OpenSSH,
+ )
+ with pytest.raises(ValueError):
+ key.private_bytes(
+ Encoding.PEM,
+ PrivateFormat.OpenSSH,
+ NoEncryption(),
+ )
+
+
+class TestDHSerialization(object):
+ """Test all options with least-supported key type."""
+
+ @pytest.mark.skip_fips(reason="non-FIPS parameters")
+ def test_dh_public_key(self, backend):
+ data = load_vectors_from_file(
+ os.path.join("asymmetric", "DH", "dhkey.pem"),
+ lambda pemfile: pemfile.read(),
+ mode="rb",
+ )
+ public_key = load_pem_private_key(data, None, backend).public_key()
+ for enc in (
+ Encoding.PEM,
+ Encoding.DER,
+ Encoding.OpenSSH,
+ Encoding.Raw,
+ Encoding.X962,
+ ):
+ for fmt in (
+ PublicFormat.SubjectPublicKeyInfo,
+ PublicFormat.PKCS1,
+ PublicFormat.OpenSSH,
+ PublicFormat.Raw,
+ PublicFormat.CompressedPoint,
+ PublicFormat.UncompressedPoint,
+ ):
+ if (
+ enc in (Encoding.PEM, Encoding.DER)
+ and fmt == PublicFormat.SubjectPublicKeyInfo
+ ):
+ # tested elsewhere
+ continue
+ with pytest.raises(ValueError):
+ public_key.public_bytes(enc, fmt)
+
+ @pytest.mark.skip_fips(reason="non-FIPS parameters")
+ def test_dh_private_key(self, backend):
+ data = load_vectors_from_file(
+ os.path.join("asymmetric", "DH", "dhkey.pem"),
+ lambda pemfile: pemfile.read(),
+ mode="rb",
+ )
+ private_key = load_pem_private_key(data, None, backend)
+ for enc in (
+ Encoding.PEM,
+ Encoding.DER,
+ Encoding.OpenSSH,
+ Encoding.Raw,
+ Encoding.X962,
+ ):
+ for fmt in (
+ PrivateFormat.PKCS8,
+ PrivateFormat.TraditionalOpenSSL,
+ PrivateFormat.Raw,
+ ):
+ if (
+ enc in (Encoding.PEM, Encoding.DER)
+ and fmt is PrivateFormat.PKCS8
+ ):
+ # tested elsewhere
+ continue
+ with pytest.raises(ValueError):
+ private_key.private_bytes(enc, fmt, NoEncryption())
+
+
+@pytest.mark.requires_backend_interface(interface=RSABackend)
+@pytest.mark.requires_backend_interface(interface=DSABackend)
+@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
+class TestOpenSSHSerialization(object):
+ @pytest.mark.parametrize(
+ ("key_file", "cert_file"),
+ [
+ ("rsa-psw.key.pub", None),
+ ("rsa-nopsw.key.pub", "rsa-nopsw.key-cert.pub"),
+ ("dsa-psw.key.pub", None),
+ ("dsa-nopsw.key.pub", "dsa-nopsw.key-cert.pub"),
+ ("ecdsa-psw.key.pub", None),
+ ("ecdsa-nopsw.key.pub", "ecdsa-nopsw.key-cert.pub"),
+ ("ed25519-psw.key.pub", None),
+ ("ed25519-nopsw.key.pub", "ed25519-nopsw.key-cert.pub"),
+ ],
+ )
+ def test_load_ssh_public_key(self, key_file, cert_file, backend):
+ if "ed25519" in key_file and not backend.ed25519_supported():
+ pytest.skip("Requires OpenSSL with Ed25519 support")
+
+ # normal public key
+ pub_data = load_vectors_from_file(
+ os.path.join("asymmetric", "OpenSSH", key_file),
+ lambda f: f.read(),
+ mode="rb",
+ )
+ public_key = load_ssh_public_key(pub_data, backend)
+ nocomment_data = b" ".join(pub_data.split()[:2])
+ assert (
+ public_key.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH)
+ == nocomment_data
+ )
+
+ self.run_partial_pubkey(pub_data, backend)
+
+ # parse public key with ssh certificate
+ if cert_file:
+ cert_data = load_vectors_from_file(
+ os.path.join("asymmetric", "OpenSSH", cert_file),
+ lambda f: f.read(),
+ mode="rb",
+ )
+ cert_key = load_ssh_public_key(cert_data, backend)
+ assert (
+ cert_key.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH)
+ == nocomment_data
+ )
+
+ # try with more spaces
+ cert_data = b" \t ".join(cert_data.split())
+ cert_key = load_ssh_public_key(cert_data, backend)
+ assert (
+ cert_key.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH)
+ == nocomment_data
+ )
+
+ self.run_partial_pubkey(cert_data, backend)
+
+ def run_partial_pubkey(self, pubdata, backend):
+ parts = pubdata.split()
+ raw = base64.b64decode(parts[1])
+ for i in range(1, len(raw)):
+ frag = base64.b64encode(raw[:i])
+ new_pub = b" ".join([parts[0], frag])
+ with pytest.raises(ValueError):
+ load_ssh_public_key(new_pub, backend)
+
+ @pytest.mark.parametrize(
+ ("key_file",),
+ [
+ ("rsa-nopsw.key",),
+ ("rsa-psw.key",),
+ ("dsa-nopsw.key",),
+ ("dsa-psw.key",),
+ ("ecdsa-nopsw.key",),
+ ("ecdsa-psw.key",),
+ ("ed25519-nopsw.key",),
+ ("ed25519-psw.key",),
+ ],
+ )
+ def test_load_ssh_private_key(self, key_file, backend):
+ if "ed25519" in key_file and not backend.ed25519_supported():
+ pytest.skip("Requires OpenSSL with Ed25519 support")
+ if "-psw" in key_file and not ssh._bcrypt_supported:
+ pytest.skip("Requires bcrypt module")
+
+ # read public and private key from ssh-keygen
+ priv_data = load_vectors_from_file(
+ os.path.join("asymmetric", "OpenSSH", key_file),
+ lambda f: f.read(),
+ mode="rb",
+ )
+ pub_data = load_vectors_from_file(
+ os.path.join("asymmetric", "OpenSSH", key_file + ".pub"),
+ lambda f: f.read(),
+ mode="rb",
+ )
+ nocomment_data = b" ".join(pub_data.split()[:2])
+
+ # load and compare
+ password = None
+ if "-psw" in key_file:
+ password = b"password"
+ private_key = load_ssh_private_key(priv_data, password, backend)
+ assert (
+ private_key.public_key().public_bytes(
+ Encoding.OpenSSH, PublicFormat.OpenSSH
+ )
+ == nocomment_data
+ )
+
+ # bytearray
+ private_key = load_ssh_private_key(
+ bytearray(priv_data), password, backend
+ )
+ assert (
+ private_key.public_key().public_bytes(
+ Encoding.OpenSSH, PublicFormat.OpenSSH
+ )
+ == nocomment_data
+ )
+
+ if six.PY3:
+ # memoryview(bytes)
+ private_key = load_ssh_private_key(
+ memoryview(priv_data), password, backend
+ )
+ assert (
+ private_key.public_key().public_bytes(
+ Encoding.OpenSSH, PublicFormat.OpenSSH
+ )
+ == nocomment_data
+ )
+
+ # memoryview(bytearray)
+ private_key = load_ssh_private_key(
+ memoryview(bytearray(priv_data)), password, backend
+ )
+ assert (
+ private_key.public_key().public_bytes(
+ Encoding.OpenSSH, PublicFormat.OpenSSH
+ )
+ == nocomment_data
+ )
+
+ # serialize with own code and reload
+ encryption = NoEncryption()
+ if password:
+ encryption = BestAvailableEncryption(password)
+ priv_data2 = private_key.private_bytes(
+ Encoding.PEM,
+ PrivateFormat.OpenSSH,
+ encryption,
+ )
+ private_key2 = load_ssh_private_key(priv_data2, password, backend)
+ assert (
+ private_key2.public_key().public_bytes(
+ Encoding.OpenSSH, PublicFormat.OpenSSH
+ )
+ == nocomment_data
+ )
+
+ # make sure multi-line base64 is used
+ maxline = max(map(len, priv_data2.split(b"\n")))
+ assert maxline < 80
+
+ @pytest.mark.supported(
+ only_if=lambda backend: ssh._bcrypt_supported,
+ skip_message="Requires that bcrypt exists",
+ )
+ def test_bcrypt_encryption(self, backend):
+ private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+ pub1 = private_key.public_key().public_bytes(
+ Encoding.OpenSSH, PublicFormat.OpenSSH
+ )
+
+ for psw in (
+ b"1",
+ b"1234",
+ b"1234" * 4,
+ b"x" * 72,
+ ):
+ # BestAvailableEncryption does not handle bytes-like?
+ best = BestAvailableEncryption(psw)
+ encdata = private_key.private_bytes(
+ Encoding.PEM, PrivateFormat.OpenSSH, best
+ )
+ decoded_key = load_ssh_private_key(encdata, psw, backend)
+ pub2 = decoded_key.public_key().public_bytes(
+ Encoding.OpenSSH, PublicFormat.OpenSSH
+ )
+ assert pub1 == pub2
+
+ # bytearray
+ decoded_key2 = load_ssh_private_key(
+ bytearray(encdata), psw, backend
+ )
+ pub2 = decoded_key2.public_key().public_bytes(
+ Encoding.OpenSSH, PublicFormat.OpenSSH
+ )
+ assert pub1 == pub2
+
+ if six.PY3:
+ # memoryview(bytes)
+ decoded_key2 = load_ssh_private_key(
+ memoryview(encdata), psw, backend
+ )
+ pub2 = decoded_key2.public_key().public_bytes(
+ Encoding.OpenSSH, PublicFormat.OpenSSH
+ )
+ assert pub1 == pub2
+
+ # memoryview(bytearray)
+ decoded_key2 = load_ssh_private_key(
+ memoryview(bytearray(encdata)), psw, backend
+ )
+ pub2 = decoded_key2.public_key().public_bytes(
+ Encoding.OpenSSH, PublicFormat.OpenSSH
+ )
+ assert pub1 == pub2
+
+ with pytest.raises(ValueError):
+ decoded_key = load_ssh_private_key(encdata, None, backend)
+ with pytest.raises(ValueError):
+ decoded_key = load_ssh_private_key(encdata, b"wrong", backend)
+
+ @pytest.mark.supported(
+ only_if=lambda backend: not ssh._bcrypt_supported,
+ skip_message="Requires that bcrypt is missing",
+ )
+ def test_missing_bcrypt(self, backend):
+ priv_data = load_vectors_from_file(
+ os.path.join("asymmetric", "OpenSSH", "ecdsa-psw.key"),
+ lambda f: f.read(),
+ mode="rb",
+ )
+ with pytest.raises(UnsupportedAlgorithm):
+ load_ssh_private_key(priv_data, b"password", backend)
+
+ private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+ with pytest.raises(UnsupportedAlgorithm):
+ private_key.private_bytes(
+ Encoding.PEM,
+ PrivateFormat.OpenSSH,
+ BestAvailableEncryption(b"x"),
+ )
+
+ def test_fraglist_corners(self):
+ f = ssh._FragList()
+ with pytest.raises(ValueError):
+ f.put_mpint(-1)
+ f.put_mpint(0)
+ f.put_mpint(0x80)
+ assert f.tobytes() == b"\0\0\0\0" + b"\0\0\0\x02" + b"\0\x80"
+
+ def make_file(
+ self,
+ magic=b"openssh-key-v1\0",
+ ciphername=b"none",
+ kdfname=b"none",
+ kdfoptions=b"",
+ nkeys=1,
+ pub_type=b"ecdsa-sha2-nistp256",
+ pub_fields=(
+ b"nistp256",
+ b"\x04" * 65,
+ ),
+ priv_type=None,
+ priv_fields=(b"nistp256", b"\x04" * 65, b"\x7F" * 32),
+ comment=b"comment",
+ checkval1=b"1234",
+ checkval2=b"1234",
+ pad=None,
+ header=b"-----BEGIN OPENSSH PRIVATE KEY-----\n",
+ footer=b"-----END OPENSSH PRIVATE KEY-----\n",
+ cut=8192,
+ ):
+ """Create private key file"""
+ if not priv_type:
+ priv_type = pub_type
+
+ pub = ssh._FragList()
+ for elem in (pub_type,) + pub_fields:
+ pub.put_sshstr(elem)
+
+ secret = ssh._FragList([checkval1, checkval2])
+ for i in range(nkeys):
+ for elem in (priv_type,) + priv_fields + (comment,):
+ secret.put_sshstr(elem)
+
+ if pad is None:
+ pad_len = 8 - (secret.size() % 8)
+ pad = bytearray(range(1, 1 + pad_len))
+ secret.put_raw(pad)
+
+ main = ssh._FragList([magic])
+ main.put_sshstr(ciphername)
+ main.put_sshstr(kdfname)
+ main.put_sshstr(kdfoptions)
+ main.put_u32(nkeys)
+ for i in range(nkeys):
+ main.put_sshstr(pub)
+ main.put_sshstr(secret)
+
+ res = main.tobytes()
+ return ssh._ssh_pem_encode(res[:cut], header, footer)
+
+ def test_ssh_make_file(self, backend):
+ # check if works by default
+ data = self.make_file()
+ key = load_ssh_private_key(data, None, backend)
+ assert isinstance(key, ec.EllipticCurvePrivateKey)
+
+ def test_load_ssh_private_key_errors(self, backend):
+ # bad kdf
+ data = self.make_file(kdfname=b"unknown", ciphername=b"aes256-ctr")
+ with pytest.raises(UnsupportedAlgorithm):
+ load_ssh_private_key(data, None, backend)
+
+ # bad cipher
+ data = self.make_file(ciphername=b"unknown", kdfname=b"bcrypt")
+ with pytest.raises(UnsupportedAlgorithm):
+ load_ssh_private_key(data, None, backend)
+
+ # bad magic
+ data = self.make_file(magic=b"unknown")
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+
+ # too few keys
+ data = self.make_file(nkeys=0)
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+
+ # too many keys
+ data = self.make_file(nkeys=2)
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+
+ def test_ssh_errors_bad_values(self, backend):
+ # bad curve
+ data = self.make_file(pub_type=b"ecdsa-sha2-nistp444")
+ with pytest.raises(UnsupportedAlgorithm):
+ load_ssh_private_key(data, None, backend)
+
+ # curve mismatch
+ data = self.make_file(priv_type=b"ecdsa-sha2-nistp384")
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+
+ # invalid bigint
+ data = self.make_file(
+ priv_fields=(b"nistp256", b"\x04" * 65, b"\x80" * 32)
+ )
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+
+ def test_ssh_errors_pubpriv_mismatch(self, backend):
+ # ecdsa public-private mismatch
+ data = self.make_file(
+ pub_fields=(
+ b"nistp256",
+ b"\x04" + b"\x05" * 64,
+ )
+ )
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+
+ # rsa public-private mismatch
+ data = self.make_file(
+ pub_type=b"ssh-rsa",
+ pub_fields=(b"x" * 32,) * 2,
+ priv_fields=(b"z" * 32,) * 6,
+ )
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+
+ # dsa public-private mismatch
+ data = self.make_file(
+ pub_type=b"ssh-dss",
+ pub_fields=(b"x" * 32,) * 4,
+ priv_fields=(b"z" * 32,) * 5,
+ )
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+
+ # ed25519 public-private mismatch
+ sk = b"x" * 32
+ pk1 = b"y" * 32
+ pk2 = b"z" * 32
+ data = self.make_file(
+ pub_type=b"ssh-ed25519",
+ pub_fields=(pk1,),
+ priv_fields=(
+ pk1,
+ sk + pk2,
+ ),
+ )
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+ data = self.make_file(
+ pub_type=b"ssh-ed25519",
+ pub_fields=(pk1,),
+ priv_fields=(
+ pk2,
+ sk + pk1,
+ ),
+ )
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+
+ def test_ssh_errors_bad_wrapper(self, backend):
+ # wrong header
+ data = self.make_file(header=b"-----BEGIN RSA PRIVATE KEY-----\n")
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+
+ # wring footer
+ data = self.make_file(footer=b"-----END RSA PRIVATE KEY-----\n")
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+
+ def test_ssh_no_padding(self, backend):
+ # no padding must work, if data is on block boundary
+ data = self.make_file(pad=b"", comment=b"")
+ key = load_ssh_private_key(data, None, backend)
+ assert isinstance(key, ec.EllipticCurvePrivateKey)
+
+ # no padding with right last byte
+ data = self.make_file(pad=b"", comment=b"\x08" * 8)
+ key = load_ssh_private_key(data, None, backend)
+ assert isinstance(key, ec.EllipticCurvePrivateKey)
+
+ # avoid unexpected padding removal
+ data = self.make_file(pad=b"", comment=b"1234\x01\x02\x03\x04")
+ key = load_ssh_private_key(data, None, backend)
+ assert isinstance(key, ec.EllipticCurvePrivateKey)
+
+ # bad padding with right size
+ data = self.make_file(pad=b"\x08" * 8, comment=b"")
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+
+ def test_ssh_errors_bad_secrets(self, backend):
+ # checkval mismatch
+ data = self.make_file(checkval2=b"4321")
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+
+ # bad padding, correct=1
+ data = self.make_file(pad=b"\x01\x02")
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+ data = self.make_file(pad=b"")
+ with pytest.raises(ValueError):
+ load_ssh_private_key(data, None, backend)
+
+ @pytest.mark.supported(
+ only_if=lambda backend: backend.elliptic_curve_supported(
+ ec.SECP192R1()
+ ),
+ skip_message="Requires backend support for ec.SECP192R1",
+ )
+ def test_serialize_ssh_private_key_errors_bad_curve(self, backend):
+ private_key = ec.generate_private_key(ec.SECP192R1(), backend)
+ with pytest.raises(ValueError):
+ private_key.private_bytes(
+ Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption()
+ )
+
+ def test_serialize_ssh_private_key_errors(self, backend):
+ # bad encoding
+ private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+ with pytest.raises(ValueError):
+ private_key.private_bytes(
+ Encoding.DER, PrivateFormat.OpenSSH, NoEncryption()
+ )
+
+ # bad object type
+ with pytest.raises(ValueError):
+ ssh.serialize_ssh_private_key(object(), None)
+
+ private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+
+ # too long password
+ with pytest.raises(ValueError):
+ private_key.private_bytes(
+ Encoding.PEM,
+ PrivateFormat.OpenSSH,
+ BestAvailableEncryption(b"p" * 73),
+ )
+
+ # unknown encryption class
+ with pytest.raises(ValueError):
+ private_key.private_bytes(
+ Encoding.PEM,
+ PrivateFormat.OpenSSH,
+ DummyKeySerializationEncryption(),
+ )
+
+ @pytest.mark.parametrize(
+ ("key_path", "supported"),
+ [
+ (["Traditional_OpenSSL_Serialization", "dsa.1024.pem"], True),
+ (["Traditional_OpenSSL_Serialization", "dsa.2048.pem"], False),
+ (["Traditional_OpenSSL_Serialization", "dsa.3072.pem"], False),
+ ],
+ )
+ def test_dsa_private_key_sizes(self, key_path, supported, backend):
+ key = load_vectors_from_file(
+ os.path.join("asymmetric", *key_path),
+ lambda pemfile: load_pem_private_key(
+ pemfile.read(), None, backend
+ ),
+ mode="rb",
+ )
+ assert isinstance(key, dsa.DSAPrivateKey)
+ if supported:
+ res = key.private_bytes(
+ Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption()
+ )
+ assert isinstance(res, bytes)
+ else:
+ with pytest.raises(ValueError):
+ key.private_bytes(
+ Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption()
+ )