enforce password must be bytes when loading PEM/DER asymmetric keys (#3383)
* enforce password must be bytes when loading PEM/DER asymmetric keys
Previously we were using an ffi.buffer on the Python string, which was
allowing text implicitly, but our documentation explicitly requires
bytes.
* add changelog entry
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index ee0a345..055651a 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -15,11 +15,15 @@
:meth:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKeyWithSerialization.private_bytes`
to
:class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKeyWithSerialization`.
-
* Added
:meth:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKeyWithSerialization.public_bytes`
to
:class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKeyWithSerialization`.
+* :func:`~cryptography.hazmat.primitives.serialization.load_pem_private_key`
+ and
+ :func:`~cryptography.hazmat.primitives.serialization.load_der_private_key`
+ now require that ``password`` must be bytes if provided. Previously this
+ was documented but not enforced.
1.7.2 - 2017-01-27
~~~~~~~~~~~~~~~~~~
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index e460ab5..e514495 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -66,6 +66,8 @@
class _PasswordUserdata(object):
def __init__(self, password):
+ if password is not None and not isinstance(password, bytes):
+ raise TypeError("Password must be bytes")
self.password = password
self.called = 0
self.exception = None
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 8fa64bc..a819831 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -523,7 +523,7 @@
backend._evp_pkey_to_public_key(key)
def test_very_long_pem_serialization_password(self):
- password = "x" * 1024
+ password = b"x" * 1024
with pytest.raises(ValueError):
load_vectors_from_file(
diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py
index 1ba8a3b..dad056c 100644
--- a/tests/hazmat/primitives/test_serialization.py
+++ b/tests/hazmat/primitives/test_serialization.py
@@ -78,6 +78,26 @@
_check_dsa_private_numbers(key.private_numbers())
@pytest.mark.parametrize(
+ "key_path",
+ [
+ ["DER_Serialization", "enc-rsa-pkcs8.der"],
+ ]
+ )
+ @pytest.mark.requires_backend_interface(interface=RSABackend)
+ def test_password_not_bytes(self, key_path, backend):
+ key_file = os.path.join("asymmetric", *key_path)
+ password = u"this password is not bytes"
+
+ with pytest.raises(TypeError):
+ load_vectors_from_file(
+ key_file,
+ lambda derfile: load_der_private_key(
+ derfile.read(), password, backend
+ ),
+ mode="rb"
+ )
+
+ @pytest.mark.parametrize(
("key_path", "password"),
[
(["DER_Serialization", "ec_private_key.der"], None),
@@ -499,6 +519,25 @@
["PKCS8", "enc-rsa-pkcs8.pem"]
]
)
+ def test_password_not_bytes(self, key_path, backend):
+ key_file = os.path.join("asymmetric", *key_path)
+ password = u"this password is not bytes"
+
+ with pytest.raises(TypeError):
+ load_vectors_from_file(
+ 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"]
+ ]
+ )
def test_wrong_password(self, key_path, backend):
key_file = os.path.join("asymmetric", *key_path)
password = b"this password is wrong"