aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2014-05-28 14:59:13 -0500
committerPaul Kehrer <paul.l.kehrer@gmail.com>2014-05-28 14:59:13 -0500
commit349cad67978a46d170b27ee2b680e878761755d9 (patch)
treed7a055f75fb78708208cac122baf64b2e2a93fad
parentfd3572923816d3bf89b5a57671ce21ee9959f222 (diff)
parent57496d9fe3991158569400599ab08d0f45a75eae (diff)
downloadcryptography-349cad67978a46d170b27ee2b680e878761755d9.tar.gz
cryptography-349cad67978a46d170b27ee2b680e878761755d9.tar.bz2
cryptography-349cad67978a46d170b27ee2b680e878761755d9.zip
Merge pull request #877 from public/pkcs8-loading
PKCS #8 loading
-rw-r--r--cryptography/hazmat/backends/interfaces.py10
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py59
-rw-r--r--cryptography/hazmat/bindings/openssl/err.py2
-rw-r--r--cryptography/hazmat/primitives/serialization.py6
-rw-r--r--docs/hazmat/primitives/asymmetric/serialization.rst52
-rw-r--r--pytest.ini1
-rw-r--r--tests/conftest.py8
-rw-r--r--tests/hazmat/primitives/test_serialization.py300
-rw-r--r--vectors/cryptography_vectors/asymmetric/PKCS8/bad-encryption-oid.pem17
-rw-r--r--vectors/cryptography_vectors/asymmetric/PKCS8/bad-oid-dsa-key.pem9
-rw-r--r--vectors/cryptography_vectors/asymmetric/PKCS8/unenc-dsa-pkcs8.pem9
11 files changed, 461 insertions, 12 deletions
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py
index 97a7a4fd..55d5cd78 100644
--- a/cryptography/hazmat/backends/interfaces.py
+++ b/cryptography/hazmat/backends/interfaces.py
@@ -196,6 +196,16 @@ class TraditionalOpenSSLSerializationBackend(object):
@six.add_metaclass(abc.ABCMeta)
+class PKCS8SerializationBackend(object):
+ @abc.abstractmethod
+ def load_pkcs8_pem_private_key(self, data, password):
+ """
+ Load a private key from PEM encoded data, using password if the data
+ is encrypted.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
class CMACBackend(object):
@abc.abstractmethod
def cmac_algorithm_supported(self, algorithm):
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 8d76160d..a5f21787 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -26,7 +26,8 @@ from cryptography.exceptions import (
)
from cryptography.hazmat.backends.interfaces import (
CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
- PBKDF2HMACBackend, RSABackend, TraditionalOpenSSLSerializationBackend
+ PBKDF2HMACBackend, PKCS8SerializationBackend, RSABackend,
+ TraditionalOpenSSLSerializationBackend
)
from cryptography.hazmat.bindings.openssl.binding import Binding
from cryptography.hazmat.primitives import hashes, interfaces
@@ -55,6 +56,7 @@ _OpenSSLError = collections.namedtuple("_OpenSSLError",
@utils.register_interface(PBKDF2HMACBackend)
@utils.register_interface(RSABackend)
@utils.register_interface(TraditionalOpenSSLSerializationBackend)
+@utils.register_interface(PKCS8SerializationBackend)
class Backend(object):
"""
OpenSSL API binding interfaces.
@@ -777,6 +779,12 @@ class Backend(object):
return _CMACContext(self, algorithm)
def load_traditional_openssl_pem_private_key(self, data, password):
+ # OpenSSLs API for loading PKCS#8 certs can also load the traditional
+ # format so we just use that for both of them.
+
+ return self.load_pkcs8_pem_private_key(data, password)
+
+ def load_pkcs8_pem_private_key(self, data, password):
mem_bio = self._bytes_to_bio(data)
password_callback, password_func = self._pem_password_cb(password)
@@ -793,10 +801,18 @@ class Backend(object):
if not errors:
raise ValueError("Could not unserialize key data.")
- if errors[0][1:] == (
- self._lib.ERR_LIB_PEM,
- self._lib.PEM_F_PEM_DO_HEADER,
- self._lib.PEM_R_BAD_PASSWORD_READ
+ if (
+ errors[0][1:] == (
+ self._lib.ERR_LIB_PEM,
+ self._lib.PEM_F_PEM_DO_HEADER,
+ self._lib.PEM_R_BAD_PASSWORD_READ
+ )
+ ) or (
+ errors[0][1:] == (
+ self._lib.ERR_LIB_PEM,
+ self._lib.PEM_F_PEM_READ_BIO_PRIVATEKEY,
+ self._lib.PEM_R_BAD_PASSWORD_READ
+ )
):
assert not password
raise TypeError(
@@ -811,13 +827,36 @@ class Backend(object):
"Bad decrypt. Incorrect password?"
)
- elif errors[0][1:] == (
- self._lib.ERR_LIB_PEM,
- self._lib.PEM_F_PEM_GET_EVP_CIPHER_INFO,
- self._lib.PEM_R_UNSUPPORTED_ENCRYPTION
+ elif errors[0][1:] in (
+ (
+ self._lib.ERR_LIB_PEM,
+ self._lib.PEM_F_PEM_GET_EVP_CIPHER_INFO,
+ self._lib.PEM_R_UNSUPPORTED_ENCRYPTION
+ ),
+
+ (
+ self._lib.ERR_LIB_EVP,
+ self._lib.EVP_F_EVP_PBE_CIPHERINIT,
+ self._lib.EVP_R_UNKNOWN_PBE_ALGORITHM
+ )
+ ):
+ raise UnsupportedAlgorithm(
+ "PEM data is encrypted with an unsupported cipher",
+ _Reasons.UNSUPPORTED_CIPHER
+ )
+
+ elif any(
+ error[1:] == (
+ self._lib.ERR_LIB_EVP,
+ self._lib.EVP_F_EVP_PKCS82PKEY,
+ self._lib.EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM
+ )
+ for error in errors
):
raise UnsupportedAlgorithm(
- "PEM data is encrypted with an unsupported cipher")
+ "Unsupported public key algorithm.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ )
else:
assert errors[0][1] in (
diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py
index f6456d66..f685e494 100644
--- a/cryptography/hazmat/bindings/openssl/err.py
+++ b/cryptography/hazmat/bindings/openssl/err.py
@@ -135,6 +135,7 @@ static const int EVP_F_PKCS5_V2_PBE_KEYIVGEN;
static const int EVP_F_PKCS8_SET_BROKEN;
static const int EVP_F_RC2_MAGIC_TO_METH;
static const int EVP_F_RC5_CTRL;
+
static const int EVP_R_AES_KEY_SETUP_FAILED;
static const int EVP_R_ASN1_LIB;
static const int EVP_R_BAD_BLOCK_LENGTH;
@@ -168,6 +169,7 @@ static const int EVP_R_UNSUPPORTED_CIPHER;
static const int EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION;
static const int EVP_R_UNSUPPORTED_KEYLENGTH;
static const int EVP_R_UNSUPPORTED_SALT_TYPE;
+static const int EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM;
static const int EVP_R_WRONG_FINAL_BLOCK_LENGTH;
static const int EVP_R_WRONG_PUBLIC_KEY_TYPE;
diff --git a/cryptography/hazmat/primitives/serialization.py b/cryptography/hazmat/primitives/serialization.py
index 38937508..ed73c4c4 100644
--- a/cryptography/hazmat/primitives/serialization.py
+++ b/cryptography/hazmat/primitives/serialization.py
@@ -18,3 +18,9 @@ def load_pem_traditional_openssl_private_key(data, password, backend):
return backend.load_traditional_openssl_pem_private_key(
data, password
)
+
+
+def load_pem_pkcs8_private_key(data, password, backend):
+ return backend.load_pkcs8_pem_private_key(
+ data, password
+ )
diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst
index 8d32ae58..2b3eb511 100644
--- a/docs/hazmat/primitives/asymmetric/serialization.rst
+++ b/docs/hazmat/primitives/asymmetric/serialization.rst
@@ -9,6 +9,58 @@ There are several common schemes for serializing asymmetric private and public
keys to bytes. They generally support encryption of private keys and additional
key metadata.
+Many serialization formats support multiple different types of asymmetric keys
+and will return an an instance of the appropriate type. You should check that
+the returned key matches the type your application expects when using these
+methods.
+
+ .. code-block:: pycon
+
+ >>> key = load_pkcs8_private_key(pem_data, None, backend)
+ >>> if isinstance(key, rsa.RSAPrivateKey):
+ >>> signature = sign_with_rsa_key(key, message)
+ >>> elif isinstance(key, dsa.DSAPrivateKey):
+ >>> signature = sign_with_dsa_key(key, message)
+ >>> else:
+ >>> raise TypeError
+
+
+PKCS #8 Format
+~~~~~~~~~~~~~~
+
+PKCS #8 is a serialization format originally standardized by RSA and
+currently maintained by the IETF in :rfc:`5208`. It supports password based
+encryption and additional key metadata attributes.
+
+
+.. function:: load_pkcs8_private_key(data, password, backend)
+
+ .. versionadded:: 0.5
+
+ Deserialize a private key from PEM encoded data to one of the supported
+ asymmetric private key types.
+
+ :param bytes data: The PEM encoded key data.
+
+ :param bytes password: The password to use to decrypt the data. Should
+ be ``None`` if the private key is not encrypted.
+ :param backend: A
+ :class:`~cryptography.hazmat.backends.interfaces.PKCS8SerializationBackend`
+ provider.
+
+ :returns: A new instance of a private key.
+
+ :raises ValueError: If the PEM data could not be decrypted or if its
+ structure could not be decoded successfully.
+
+ :raises TypeError: If a ``password`` was given and the private key was
+ not encrypted. Or if the key was encrypted but no
+ password was supplied.
+
+ :raises UnsupportedAlgorithm: If the serialized key is of a type that
+ is not supported by the backend or if the key is encrypted with a
+ symmetric cipher that is not supported by the backend.
+
Traditional OpenSSL Format
~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/pytest.ini b/pytest.ini
index f717693d..9b44f198 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -9,4 +9,5 @@ markers =
pbkdf2hmac: this test requires a backend providing PBKDF2HMACBackend
rsa: this test requires a backend providing RSABackend
traditional_openssl_serialization: this test requires a backend providing TraditionalOpenSSLSerializationBackend
+ pkcs8_serialization: this test requires a backend providing PKCS8SerializationBackend
supported: parametrized test requiring only_if and skip_message
diff --git a/tests/conftest.py b/tests/conftest.py
index 86d5a03b..b1326dc8 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -18,7 +18,8 @@ import pytest
from cryptography.hazmat.backends import _available_backends
from cryptography.hazmat.backends.interfaces import (
CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
- PBKDF2HMACBackend, RSABackend, TraditionalOpenSSLSerializationBackend
+ PBKDF2HMACBackend, PKCS8SerializationBackend, RSABackend,
+ TraditionalOpenSSLSerializationBackend
)
from .utils import check_backend_support, check_for_iface, select_backends
@@ -45,6 +46,11 @@ def pytest_runtest_setup(item):
TraditionalOpenSSLSerializationBackend,
item
)
+ check_for_iface(
+ "pkcs8_serialization",
+ PKCS8SerializationBackend,
+ item
+ )
check_backend_support(item)
diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py
index 8d3b8fd4..b19990e0 100644
--- a/tests/hazmat/primitives/test_serialization.py
+++ b/tests/hazmat/primitives/test_serialization.py
@@ -19,8 +19,10 @@ import textwrap
import pytest
+from cryptography.exceptions import _Reasons
from cryptography.hazmat.primitives.asymmetric import dsa, rsa
from cryptography.hazmat.primitives.serialization import (
+ load_pem_pkcs8_private_key,
load_pem_traditional_openssl_private_key
)
@@ -242,7 +244,303 @@ class TestTraditionalOpenSSLSerialisation(object):
password = b"password"
- with raises_unsupported_algorithm(None):
+ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
load_pem_traditional_openssl_private_key(
key_data, password, backend
)
+
+
+@pytest.mark.pkcs8_serialization
+class TestPKCS8Serialisation(object):
+ @pytest.mark.parametrize(
+ ("key_file", "password"),
+ [
+ ("unencpkcs8.pem", None),
+ ("encpkcs8.pem", b"foobar"),
+ ("enc2pkcs8.pem", b"baz"),
+ ("pkcs12_s2k_pem-X_9607.pem", b"123456"),
+ ("pkcs12_s2k_pem-X_9671.pem", b"123456"),
+ ("pkcs12_s2k_pem-X_9925.pem", b"123456"),
+ ("pkcs12_s2k_pem-X_9926.pem", b"123456"),
+ ("pkcs12_s2k_pem-X_9927.pem", b"123456"),
+ ("pkcs12_s2k_pem-X_9928.pem", b"123456"),
+ ("pkcs12_s2k_pem-X_9929.pem", b"123456"),
+ ("pkcs12_s2k_pem-X_9930.pem", b"123456"),
+ ("pkcs12_s2k_pem-X_9931.pem", b"123456"),
+ ("pkcs12_s2k_pem-X_9932.pem", b"123456"),
+ ]
+ )
+ def test_load_pem_rsa_private_key(self, key_file, password, backend):
+ key = load_vectors_from_file(
+ os.path.join(
+ "asymmetric", "PKCS8", key_file),
+ lambda pemfile: load_pem_pkcs8_private_key(
+ pemfile.read().encode(), password, backend
+ )
+ )
+
+ assert key
+ assert isinstance(key, rsa.RSAPrivateKey)
+ _check_rsa_private_key(key)
+
+ def test_unused_password(self, backend):
+ key_file = os.path.join(
+ "asymmetric", "PKCS8", "unencpkcs8.pem")
+ password = b"this password will not be used"
+
+ with pytest.raises(TypeError):
+ load_vectors_from_file(
+ key_file,
+ lambda pemfile: load_pem_pkcs8_private_key(
+ pemfile.read().encode(), password, backend
+ )
+ )
+
+ def test_wrong_password(self, backend):
+ key_file = os.path.join(
+ "asymmetric", "PKCS8", "encpkcs8.pem")
+ password = b"this password is wrong"
+
+ with pytest.raises(ValueError):
+ load_vectors_from_file(
+ key_file,
+ lambda pemfile: load_pem_pkcs8_private_key(
+ pemfile.read().encode(), password, backend
+ )
+ )
+
+ @pytest.mark.parametrize("password", [None, b""])
+ def test_missing_password(self, backend, password):
+ key_file = os.path.join(
+ "asymmetric",
+ "PKCS8",
+ "encpkcs8.pem"
+ )
+
+ with pytest.raises(TypeError):
+ load_vectors_from_file(
+ key_file,
+ lambda pemfile: load_pem_pkcs8_private_key(
+ pemfile.read().encode(), password, backend
+ )
+ )
+
+ def test_wrong_format(self, backend):
+ key_data = b"---- NOT A KEY ----\n"
+
+ with pytest.raises(ValueError):
+ load_pem_pkcs8_private_key(
+ key_data, None, backend
+ )
+
+ with pytest.raises(ValueError):
+ load_pem_pkcs8_private_key(
+ key_data, b"this password will not be used", backend
+ )
+
+ def test_corrupt_format(self, backend):
+ # unencpkcs8.pem with a bunch of data missing.
+ key_data = textwrap.dedent("""\
+ -----BEGIN PRIVATE KEY-----
+ MIICdQIBADALBgkqhkiG9w0BAQEEggJhMIICXQIBAAKBgQC7JHoJfg6yNzLMOWet
+ 8Z49a4KD0dCspMAYvo2YAMB7/wdEycocujbhJ2n/seONi+5XqTqqFkM5VBl8rmkk
+ FPZk/7x0xmdsTPECSWnHK+HhoaNDFPR3j8jQhVo1laxiqcEhAHegi5cwtFosuJAv
+ FiRC0Cgz+frQPFQEBsAV9RuasyQxqzxrR0Ow0qncBeGBWbYE6WZhqtcLAI895b+i
+ +F4lbB4iD7T9QeIDMU/aIMXA81UO4cns1z4qDAHKeyLLrPQrJ/B4X7XC+egUWm5+
+ hr1qmyAMusyXIBECQQDJWZ8piluf4yrYfsJAn6hF5T4RjTztbqvO0GVG2McHY7Uj
+ NPSffhzHx/ll0fQEQji+OgydCCX8o3HZrgw5YfSJAkEA7e+rqdU5nO5ZG//PSEQb
+ tjLnRiTzBH/elQhtdZ5nF7pcpNTi4k13zutmKcWW4GK75azcRGJUhu1kDM7QYAOd
+ SQJAVNkYcifkvna7GmooL5VYEsQsqLbM4v0NF2TIGNfG3z1MGp75KrC5LhL97MNR
+ we2p/bd2k0HYyCKUGnf2nMPDiQJBAI75pwittSoE240EobUGIDTSz8CJsXIxuDmL
+ z+KOpdpPRR5TQmbEMEspjsFpFymMiuYPgmihQbO2cJl1qScY5OkCQQCJ6m5tcN8l
+ Xxg/SNpjEIv+qAyUD96XVlOJlOIeLHQ8kYE0C6ZA+MsqYIzgAreJk88Yn0lU/X0/
+ mu/UpE/BRZmR
+ -----END PRIVATE KEY-----
+ """).encode()
+
+ with pytest.raises(ValueError):
+ load_pem_pkcs8_private_key(
+ key_data, None, backend
+ )
+
+ with pytest.raises(ValueError):
+ load_pem_pkcs8_private_key(
+ key_data, b"this password will not be used", backend
+ )
+
+ def test_encrypted_corrupt_format(self, backend):
+ # encpkcs8.pem with some bits flipped.
+ key_data = textwrap.dedent("""\
+ -----BEGIN ENCRYPTED PRIVATE KEY-----
+ MIICojAcBgoqhkiG9w0BDAEDMA4ECHK0M0+QuEL9AgIBIcSCAoDRq+KRY+0XP0tO
+ lwBTzViiXSXoyNnKAZKt5r5K/fGNntv22g/1s/ZNCetrqsJDC5eMUPPacz06jFq/
+ Ipsep4/OgjQ9UAOzXNrWEoNyrHnWDo7usgD3CW0mKyqER4+wG0adVMbt3N+CJHGB
+ 85jzRmQTfkdx1rSWeSx+XyswHn8ER4+hQ+omKWMVm7AFkjjmP/KnhUnLT98J8rhU
+ ArQoFPHz/6HVkypFccNaPPNg6IA4aS2A+TU9vJYOaXSVfFB2yf99hfYYzC+ukmuU
+ 5Lun0cysK5s/5uSwDueUmDQKspnaNyiaMGDxvw8hilJc7vg0fGObfnbIpizhxJwq
+ gKBfR7Zt0Hv8OYi1He4MehfMGdbHskztF+yQ40LplBGXQrvAqpU4zShga1BoQ98T
+ 0ekbBmqj7hg47VFsppXR7DKhx7G7rpMmdKbFhAZVCjae7rRGpUtD52cpFdPhMyAX
+ huhMkoczwUW8B/rM4272lkHo6Br0yk/TQfTEGkvryflNVu6lniPTV151WV5U1M3o
+ 3G3a44eDyt7Ln+WSOpWtbPQMTrpKhur6WXgJvrpa/m02oOGdvOlDsoOCgavgQMWg
+ 7xKKL7620pHl7p7f/8tlE8q6vLXVvyNtAOgt/JAr2rgvrHaZSzDE0DwgCjBXEm+7
+ cVMVNkHod7bLQefVanVtWqPzbmr8f7gKeuGwWSG9oew/lN2hxcLEPJHAQlnLgx3P
+ 0GdGjK9NvwA0EP2gYIeE4+UtSder7xQ7bVh25VB20R4TTIIs4aXXCVOoQPagnzaT
+ 6JLgl8FrvdfjHwIvmSOO1YMNmILBq000Q8WDqyErBDs4hsvtO6VQ4LeqJj6gClX3
+ qeJNaJFu
+ -----END ENCRYPTED PRIVATE KEY-----
+ """).encode()
+
+ password = b"this password is wrong"
+
+ with pytest.raises(ValueError):
+ load_pem_pkcs8_private_key(
+ key_data, None, backend
+ )
+
+ with pytest.raises(ValueError):
+ load_pem_pkcs8_private_key(
+ key_data, password, backend
+ )
+
+ def test_key1_pem_encrypted_values(self, backend):
+ pkey = load_vectors_from_file(
+ os.path.join(
+ "asymmetric", "PKCS8", "encpkcs8.pem"),
+ lambda pemfile: load_pem_pkcs8_private_key(
+ pemfile.read().encode(), b"foobar", backend
+ )
+ )
+ assert pkey
+
+ assert pkey.modulus == int(
+ "00beec64d6db5760ac2fd4c971145641b9bd7f5c56558ece608795c79807"
+ "376a7fe5b19f95b35ca358ea5c8abd7ae051d49cd2f1e45969a1ae945460"
+ "3c14b278664a0e414ebc8913acb6203626985525e17a600611b028542dd0"
+ "562aad787fb4f1650aa318cdcff751e1b187cbf6785fbe164e9809491b95"
+ "dd68480567c99b1a57", 16
+ )
+
+ assert pkey.public_exponent == 65537
+
+ assert pkey.private_exponent == int(
+ "0cfe316e9dc6b8817f4fcfd5ae38a0886f68f773b8a6db4c9e6d8703c599"
+ "f3d9785c3a2c09e4c8090909fb3721e19a3009ec21221523a729265707a5"
+ "8f13063671c42a4096cad378ef2510cb59e23071489d8893ac4934dd149f"
+ "34f2d094bea57f1c8027c3a77248ac9b91218737d0c3c3dfa7d7829e6977"
+ "cf7d995688c86c81", 16
+ )
+
+ assert pkey.p == int(
+ "00db122ac857b2c0437d7616daa98e597bb75ca9ad3a47a70bec10c10036"
+ "03328794b225c8e3eee6ffd3fd6d2253d28e071fe27d629ab072faa14377"
+ "ce6118cb67", 16
+ )
+
+ assert pkey.q == int(
+ "00df1b8aa8506fcbbbb9d00257f2975e38b33d2698fd0f37e82d7ef38c56"
+ "f21b6ced63c825383782a7115cfcc093300987dbd2853b518d1c8f26382a"
+ "2d2586d391", 16
+ )
+
+ assert pkey.dmp1 == int(
+ "00be18aca13e60712fdf5daa85421eb10d86d654b269e1255656194fb0c4"
+ "2dd01a1070ea12c19f5c39e09587af02f7b1a1030d016a9ffabf3b36d699"
+ "ceaf38d9bf", 16
+ )
+
+ assert pkey.dmq1 == int(
+ "71aa8978f90a0c050744b77cf1263725b203ac9f730606d8ae1d289dce4a"
+ "28b8d534e9ea347aeb808c73107e583eb80c546d2bddadcdb3c82693a4c1"
+ "3d863451", 16
+ )
+
+ assert pkey.iqmp == int(
+ "136b7b1afac6e6279f71b24217b7083485a5e827d156024609dae39d48a6"
+ "bdb55af2f062cc4a3b077434e6fffad5faa29a2b5dba2bed3e4621e478c0"
+ "97ccfe7f", 16
+ )
+
+ @pytest.mark.parametrize(
+ ("key_file", "password"),
+ [
+ ("unenc-dsa-pkcs8.pem", None),
+ ]
+ )
+ def test_load_pem_dsa_private_key(self, key_file, password, backend):
+ key = load_vectors_from_file(
+ os.path.join(
+ "asymmetric", "PKCS8", key_file),
+ lambda pemfile: load_pem_traditional_openssl_private_key(
+ pemfile.read().encode(), password, backend
+ )
+ )
+ assert key
+ assert isinstance(key, dsa.DSAPrivateKey)
+
+ params = key.parameters()
+ assert isinstance(params, dsa.DSAParameters)
+
+ assert key.x == int("00a535a8e1d0d91beafc8bee1d9b2a3a8de3311203", 16)
+ assert key.y == int(
+ "2b260ea97dc6a12ae932c640e7df3d8ff04a8a05a0324f8d5f1b23f15fa1"
+ "70ff3f42061124eff2586cb11b49a82dcdc1b90fc6a84fb10109cb67db5d"
+ "2da971aeaf17be5e37284563e4c64d9e5fc8480258b319f0de29d54d8350"
+ "70d9e287914d77df81491f4423b62da984eb3f45eb2a29fcea5dae525ac6"
+ "ab6bcce04bfdf5b6",
+ 16
+ )
+
+ assert params.p == int(
+ "00aa0930cc145825221caffa28ac2894196a27833de5ec21270791689420"
+ "7774a2e7b238b0d36f1b2499a2c2585083eb01432924418d867faa212dd1"
+ "071d4dceb2782794ad393cc08a4d4ada7f68d6e839a5fcd34b4e402d82cb"
+ "8a8cb40fec31911bf9bd360b034caacb4c5e947992573c9e90099c1b0f05"
+ "940cabe5d2de49a167",
+ 16
+ )
+
+ assert params.q == int("00adc0e869b36f0ac013a681fdf4d4899d69820451",
+ 16)
+
+ assert params.g == int(
+ "008c6b4589afa53a4d1048bfc346d1f386ca75521ccf72ddaa251286880e"
+ "e13201ff48890bbfc33d79bacaec71e7a778507bd5f1a66422e39415be03"
+ "e71141ba324f5b93131929182c88a9fa4062836066cebe74b5c6690c7d10"
+ "1106c240ab7ebd54e4e3301fd086ce6adac922fb2713a2b0887cba13b9bc"
+ "68ce5cfff241cd3246",
+ 16
+ )
+
+ @pytest.mark.parametrize(
+ ("key_file", "password"),
+ [
+ ("bad-oid-dsa-key.pem", None),
+ ]
+ )
+ def test_load_bad_oid_key(self, key_file, password, backend):
+ with raises_unsupported_algorithm(
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ ):
+ load_vectors_from_file(
+ os.path.join(
+ "asymmetric", "PKCS8", key_file),
+ lambda pemfile: load_pem_traditional_openssl_private_key(
+ pemfile.read().encode(), password, backend
+ )
+ )
+
+ @pytest.mark.parametrize(
+ ("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):
+ load_vectors_from_file(
+ os.path.join(
+ "asymmetric", "PKCS8", key_file),
+ lambda pemfile: load_pem_traditional_openssl_private_key(
+ pemfile.read().encode(), password, backend
+ )
+ )
diff --git a/vectors/cryptography_vectors/asymmetric/PKCS8/bad-encryption-oid.pem b/vectors/cryptography_vectors/asymmetric/PKCS8/bad-encryption-oid.pem
new file mode 100644
index 00000000..4ebcc12c
--- /dev/null
+++ b/vectors/cryptography_vectors/asymmetric/PKCS8/bad-encryption-oid.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICojAcBgoYYYYYYYYYYYYYMA4ECHK0M0+QuEL9AgIBIgSCAoDRq+KRY+0XP0tO
+lwBTzViiXSXoyNnKAZKt5r5K/fGNntv22g/1s/ZNCetrqsJDC5eMUPPacz06jFq/
+Ipsep4/OgjQ9UAOzXNrWEoNyrHnWDo7usgD3CW0mKyqER4+wG0ZdVMbt3N+CJHGB
+85jzRmQTfkdx1rSWeSx+XyswHn8ER4+hQ+omKWMVm7AFkjjmP/KmhUnLT98J8rhU
+ArQoFPHz/6HVkypFccNaPPNg6IA4aS2A+TU9vJYOaXSVfFB2yf99hfYYzC+ukmuU
+5Lun0cysK5s/5uSwDueUmDQKspnaNyiaMGDxvw8hilJc7vg0fGObfnbIpizhxJwq
+gKBfR7Zt0Hv8OYi1He4MehfMGdbHskztF+yQ40LplBGXQrvAqpU4zShga1BoQ98T
+0ekbBmqj7hg47VFsppXR7DKhx7G7rpMmdKbFhAZVCjae7rRGpUtD52cpFdPhMyAX
+huhMkoczwUW8B/rM4272lkHo6Br0yk/TQfTEGkvryflNVu6lniPTV151WV5U1M3o
+3G3a44eDyt7Ln+WSOpWtbPQMTrpKhur6WXgJvrpa/m02oOGdvOlDsoOCgavgQMWg
+7xKKL7620pHl7p7f/8tlE8q6vLXVvyNtAOgt/JAr2rgvrHaZSzDE0DwgCjBXEm+7
+cVMVNkHod7bLQefVanVtWqPzbmr8f7gKeuGwWSG9oew/lN2hxcLEPJHAQlnLgx3P
+0GdGjK9NvwA0EP2gYIeE4+UtSder7xQ7bVh25VB20R4TTIIs4aXXCVOoQPagnzaT
+6JLgl8FrvdfjHwIvmSOO1YMNmILBq000Q8WDqyErBDs4hsvtO6VQ4LeqJj6gClX3
+qeJNaJFu
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/vectors/cryptography_vectors/asymmetric/PKCS8/bad-oid-dsa-key.pem b/vectors/cryptography_vectors/asymmetric/PKCS8/bad-oid-dsa-key.pem
new file mode 100644
index 00000000..50d045be
--- /dev/null
+++ b/vectors/cryptography_vectors/asymmetric/PKCS8/bad-oid-dsa-key.pem
@@ -0,0 +1,9 @@
+-----BEGIN PRIVATE KEY-----
+MIIBTAIBADCCASwGByXXXXXXXXEwggEfAoGBAKoJMMwUWCUiHK/6KKwolBlqJ4M9
+5ewhJweRaJQgd3Si57I4sNNvGySZosJYUIPrAUMpJEGNhn+qIS3RBx1NzrJ4J5St
+OTzAik1K2n9o1ug5pfzTS05ALYLLioy0D+wxkRv5vTYLA0yqy0xelHmSVzyekAmc
+Gw8FlAyr5dLeSaFnAhUArcDoabNvCsATpoH99NSJnWmCBFECgYEAjGtFia+lOk0Q
+SL/DRtHzhsp1UhzPct2qJRKGiA7hMgH/SIkLv8M9ebrK7HHnp3hQe9XxpmQi45QV
+vgPnEUG6Mk9bkxMZKRgsiKn6QGKDYGbOvnS1xmkMfRARBsJAq369VOTjMB/Qhs5q
+2ski+ycTorCIfLoTubxozlz/8kHNMkYEFwIVAKU1qOHQ2Rvq/IvuHZsqOo3jMRID
+-----END PRIVATE KEY-----
diff --git a/vectors/cryptography_vectors/asymmetric/PKCS8/unenc-dsa-pkcs8.pem b/vectors/cryptography_vectors/asymmetric/PKCS8/unenc-dsa-pkcs8.pem
new file mode 100644
index 00000000..7b2099d3
--- /dev/null
+++ b/vectors/cryptography_vectors/asymmetric/PKCS8/unenc-dsa-pkcs8.pem
@@ -0,0 +1,9 @@
+-----BEGIN PRIVATE KEY-----
+MIIBTAIBADCCASwGByqGSM44BAEwggEfAoGBAKoJMMwUWCUiHK/6KKwolBlqJ4M9
+5ewhJweRaJQgd3Si57I4sNNvGySZosJYUIPrAUMpJEGNhn+qIS3RBx1NzrJ4J5St
+OTzAik1K2n9o1ug5pfzTS05ALYLLioy0D+wxkRv5vTYLA0yqy0xelHmSVzyekAmc
+Gw8FlAyr5dLeSaFnAhUArcDoabNvCsATpoH99NSJnWmCBFECgYEAjGtFia+lOk0Q
+SL/DRtHzhsp1UhzPct2qJRKGiA7hMgH/SIkLv8M9ebrK7HHnp3hQe9XxpmQi45QV
+vgPnEUG6Mk9bkxMZKRgsiKn6QGKDYGbOvnS1xmkMfRARBsJAq369VOTjMB/Qhs5q
+2ski+ycTorCIfLoTubxozlz/8kHNMkYEFwIVAKU1qOHQ2Rvq/IvuHZsqOo3jMRID
+-----END PRIVATE KEY-----