Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix parsing of priv keys via pub key APIs to error properly in ossl3 #7135

Merged
merged 1 commit into from Apr 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 19 additions & 2 deletions src/cryptography/hazmat/backends/openssl/backend.py
Expand Up @@ -906,8 +906,20 @@ def load_pem_private_key(

def load_pem_public_key(self, data: bytes) -> PUBLIC_KEY_TYPES:
mem_bio = self._bytes_to_bio(data)
# In OpenSSL 3.0.x the PEM_read_bio_PUBKEY function will invoke
# the default password callback if you pass an encrypted private
# key. This is very, very, very bad as the default callback can
# trigger an interactive console prompt, which will hang the
# Python process. We therefore provide our own callback to
# catch this and error out properly.
userdata = self._ffi.new("CRYPTOGRAPHY_PASSWORD_DATA *")
evp_pkey = self._lib.PEM_read_bio_PUBKEY(
mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
mem_bio.bio,
self._ffi.NULL,
self._ffi.addressof(
self._lib._original_lib, "Cryptography_pem_password_cb"
),
userdata,
)
if evp_pkey != self._ffi.NULL:
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
Expand All @@ -920,7 +932,12 @@ def load_pem_public_key(self, data: bytes) -> PUBLIC_KEY_TYPES:
res = self._lib.BIO_reset(mem_bio.bio)
self.openssl_assert(res == 1)
rsa_cdata = self._lib.PEM_read_bio_RSAPublicKey(
mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
mem_bio.bio,
self._ffi.NULL,
self._ffi.addressof(
self._lib._original_lib, "Cryptography_pem_password_cb"
),
userdata,
)
if rsa_cdata != self._ffi.NULL:
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
Expand Down
15 changes: 15 additions & 0 deletions tests/hazmat/primitives/test_serialization.py
Expand Up @@ -39,6 +39,7 @@
)


from .fixtures_rsa import RSA_KEY_2048
from .test_ec import _skip_curve_unsupported
from .utils import (
_check_dsa_private_numbers,
Expand Down Expand Up @@ -513,6 +514,20 @@ def test_load_pem_rsa_public_key(self, key_file, backend):
numbers = key.public_numbers()
assert numbers.e == 65537

def test_load_priv_key_with_public_key_api_fails(self, backend):
# In OpenSSL 3.0.x the PEM_read_bio_PUBKEY function will invoke
# the default password callback if you pass an encrypted private
# key. This is very, very, very bad as the default callback can
# trigger an interactive console prompt, which will hang the
# Python process. This test makes sure we don't do that.
priv_key_serialized = RSA_KEY_2048.private_key().private_bytes(
Encoding.PEM,
PrivateFormat.PKCS8,
BestAvailableEncryption(b"password"),
)
with pytest.raises(ValueError):
load_pem_public_key(priv_key_serialized)

@pytest.mark.supported(
only_if=lambda backend: backend.dsa_supported(),
skip_message="Does not support DSA.",
Expand Down