Visitar URL original
Fix loading unencrypted client keys with a password in pyOpenSSL (#5255) · urllib3/urllib3@0716e31 · GitHub
Skip to content

Commit 0716e31

Browse files
authored
Fix loading unencrypted client keys with a password in pyOpenSSL (#5255)
1 parent 43c68c8 commit 0716e31

2 files changed

Lines changed: 32 additions & 3 deletions

File tree

‎src/urllib3/contrib/pyopenssl.py‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,15 @@ def load_cert_chain(
512512
# versions because set_passwd_cb() became deprecated in 26.3.0.
513513
if int(OpenSSL.__version__.split(".")[0]) >= 26:
514514
with open(keyfile or certfile, "rb") as key_file:
515-
private_key = load_pem_private_key(key_file.read(), password)
515+
key_data = key_file.read()
516+
try:
517+
private_key = load_pem_private_key(key_data, password)
518+
except TypeError:
519+
# Match SSLContext by ignoring passwords supplied
520+
# for unencrypted keys.
521+
# Incorrect passwords for encrypted keys raise
522+
# ValueError instead.
523+
private_key = load_pem_private_key(key_data, None)
516524
# cryptography's loader returns a wider private-key union
517525
# than pyOpenSSL accepts, so we add `type: ignore` here.
518526
self._ctx.use_privatekey(private_key) # type: ignore[arg-type]

‎test/with_dummyserver/test_socketlevel.py‎

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,14 +438,35 @@ def socket_handler(listener: socket.socket) -> None:
438438

439439
assert len(client_certs) == 1
440440

441-
def test_load_keyfile_with_invalid_password(self) -> None:
441+
@pytest.mark.parametrize("password", [None, "", b"", "secret", b"secret"])
442+
@pytest.mark.parametrize("combined", [False, True])
443+
def test_load_unencrypted_keyfile_with_password(
444+
self, password: str | bytes | None, combined: bool
445+
) -> None:
446+
"""
447+
Test that unencrypted keys ignore unused passwords in separate or
448+
combined PEM files.
449+
"""
450+
assert ssl_.SSLContext is not None
451+
context = ssl_.SSLContext(ssl_.PROTOCOL_SSLv23)
452+
context.load_cert_chain(
453+
certfile=self.cert_combined_path if combined else self.cert_path,
454+
keyfile=None if combined else self.key_path,
455+
password=password,
456+
)
457+
458+
@pytest.mark.parametrize("password", ["", b"", "letmei", b"letmei"])
459+
def test_load_keyfile_with_invalid_password(self, password: str | bytes) -> None:
460+
"""
461+
Test that encrypted keys reject empty or incorrect passwords.
462+
"""
442463
assert ssl_.SSLContext is not None
443464
context = ssl_.SSLContext(ssl_.PROTOCOL_SSLv23)
444465
with pytest.raises(ssl.SSLError):
445466
context.load_cert_chain(
446467
certfile=self.cert_path,
447468
keyfile=self.password_key_path,
448-
password=b"letmei",
469+
password=password,
449470
)
450471

451472
def test_load_invalid_cert_file(self) -> None:

0 commit comments

Comments
 (0)