Consistently wrap errors in load_cert_chain
This wraps OpenSSL.SSL.Error with ssl.SSLError in
PyOpenSSLContext.load_cert_chain, similar to the error handling in
other methods of PyOpenSSLContext.
ADD
changelog/2628.bugfix.rst
+Wrap OpenSSL.SSL.Error with ssl.SSLError in PyOpenSSLContext.load_cert_chain.

MODIFY
src/urllib3/contrib/pyopenssl.py
src/urllib3/contrib/pyopenssl.py
@@ -486,12 +486,15 @@ class PyOpenSSLContext:
keyfile: Optional[str] = None,
password: Optional[str] = None,
) -> None:
+ try:
self._ctx.use_certificate_chain_file(certfile)
if password is not None:
if not isinstance(password, bytes):
password = password.encode("utf-8") # type: ignore[assignment]
self._ctx.set_passwd_cb(lambda *_: password)
self._ctx.use_privatekey_file(keyfile or certfile)
+ except OpenSSL.SSL.Error as e:
+ raise ssl.SSLError(f"Unable to load certificate chain: {e!r}") from e
def set_alpn_protocols(self, protocols: List[Union[bytes, str]]) -> None:
protocols = [util.util.to_bytes(p, "ascii") for p in protocols]

MODIFY
test/with_dummyserver/test_socketlevel.py
test/with_dummyserver/test_socketlevel.py
@@ -352,22 +352,22 @@ class TestClientCerts(SocketDummyServerTestCase):
def test_load_keyfile_with_invalid_password(self) -> None:
assert ssl_.SSLContext is not None
context = ssl_.SSLContext(ssl_.PROTOCOL_SSLv23)
-
- # Different error is raised depending on context.
- if ssl_.IS_PYOPENSSL:
- from OpenSSL.SSL import Error # type: ignore[import]
-
- expected_error = Error
- else:
- expected_error = ssl.SSLError
-
- with pytest.raises(expected_error):
+ with pytest.raises(ssl.SSLError):
context.load_cert_chain(
certfile=self.cert_path,
keyfile=self.password_key_path,
password=b"letmei",
)
+ # For SecureTransport, the validation that would raise an error in
+ # this case is deferred.
+ @notSecureTransport()
+ def test_load_invalid_cert_file(self) -> None:
+ assert ssl_.SSLContext is not None
+ context = ssl_.SSLContext(ssl_.PROTOCOL_SSLv23)
+ with pytest.raises(ssl.SSLError):
+ context.load_cert_chain(certfile=self.password_key_path)
+
class TestSocketClosing(SocketDummyServerTestCase):
def test_recovery_when_server_closes_connection(self) -> None:

Consistently wrap errors in load_cert_chain

This wraps OpenSSL.SSL.Error with ssl.SSLError in
PyOpenSSLContext.load_cert_chain, similar to the error handling in
other methods of PyOpenSSLContext.