From 3d1546b69c0dae8b69d04e8f513237ab4d6827ee Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Wed, 6 Jul 2022 10:12:54 -0400 Subject: [PATCH 1/4] OpenSSL/crypto: make X509StoreContextError's message friendlier Closes #1132. Signed-off-by: William Woodruff --- src/OpenSSL/crypto.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/OpenSSL/crypto.py b/src/OpenSSL/crypto.py index d6ef67e00..102603b62 100644 --- a/src/OpenSSL/crypto.py +++ b/src/OpenSSL/crypto.py @@ -1776,8 +1776,9 @@ class X509StoreContextError(Exception): :type certificate: :class:`X509` """ - def __init__(self, message: Any, certificate: X509) -> None: + def __init__(self, message: str, errors: List[Any], certificate: X509) -> None: super(X509StoreContextError, self).__init__(message) + self.errors = errors self.certificate = certificate @@ -1878,21 +1879,22 @@ def _exception_from_context(self) -> X509StoreContextError: When a call to native OpenSSL X509_verify_cert fails, additional information about the failure can be obtained from the store context. """ + message = _ffi.string( + _lib.X509_verify_cert_error_string( + _lib.X509_STORE_CTX_get_error(self._store_ctx) + ) + ).decode("utf-8") errors = [ _lib.X509_STORE_CTX_get_error(self._store_ctx), _lib.X509_STORE_CTX_get_error_depth(self._store_ctx), - _ffi.string( - _lib.X509_verify_cert_error_string( - _lib.X509_STORE_CTX_get_error(self._store_ctx) - ) - ).decode("utf-8"), + message, ] # A context error should always be associated with a certificate, so we # expect this call to never return :class:`None`. _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx) _cert = _lib.X509_dup(_x509) pycert = X509._from_raw_x509_ptr(_cert) - return X509StoreContextError(errors, pycert) + return X509StoreContextError(message, errors, pycert) def set_store(self, store: X509Store) -> None: """ From 11a33fe8d41942c7ed5157ad1d9c2af58b66d70f Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Wed, 6 Jul 2022 10:13:35 -0400 Subject: [PATCH 2/4] tests: update exception tests Signed-off-by: William Woodruff --- tests/test_crypto.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/test_crypto.py b/tests/test_crypto.py index 8c190300c..8ad4d684b 100644 --- a/tests/test_crypto.py +++ b/tests/test_crypto.py @@ -3874,7 +3874,7 @@ def test_verify_with_revoked(self): store_ctx = X509StoreContext(store, self.intermediate_server_cert) with pytest.raises(X509StoreContextError) as err: store_ctx.verify_certificate() - assert err.value.args[0][2] == "certificate revoked" + assert str(err.value) == "certificate revoked" def test_verify_with_missing_crl(self): """ @@ -3894,7 +3894,7 @@ def test_verify_with_missing_crl(self): store_ctx = X509StoreContext(store, self.intermediate_server_cert) with pytest.raises(X509StoreContextError) as err: store_ctx.verify_certificate() - assert err.value.args[0][2] == "unable to get certificate CRL" + assert str(err.value) == "unable to get certificate CRL" assert err.value.certificate.get_subject().CN == "intermediate-service" def test_convert_from_cryptography(self): @@ -4106,7 +4106,7 @@ def test_untrusted_self_signed(self): store_ctx.verify_certificate() # OpenSSL 1.1.x and 3.0.x have different error messages - assert exc.value.args[0][2] in [ + assert str(exc.value) in [ "self signed certificate", "self-signed certificate", ] @@ -4124,7 +4124,7 @@ def test_invalid_chain_no_root(self): with pytest.raises(X509StoreContextError) as exc: store_ctx.verify_certificate() - assert exc.value.args[0][2] == "unable to get issuer certificate" + assert str(exc.value) == "unable to get issuer certificate" assert exc.value.certificate.get_subject().CN == "intermediate" def test_invalid_chain_no_intermediate(self): @@ -4139,7 +4139,7 @@ def test_invalid_chain_no_intermediate(self): with pytest.raises(X509StoreContextError) as exc: store_ctx.verify_certificate() - assert exc.value.args[0][2] == "unable to get local issuer certificate" + assert str(exc.value) == "unable to get local issuer certificate" assert exc.value.certificate.get_subject().CN == "intermediate-service" def test_modification_pre_verify(self): @@ -4157,7 +4157,7 @@ def test_modification_pre_verify(self): with pytest.raises(X509StoreContextError) as exc: store_ctx.verify_certificate() - assert exc.value.args[0][2] == "unable to get issuer certificate" + assert str(exc.value) == "unable to get issuer certificate" assert exc.value.certificate.get_subject().CN == "intermediate" store_ctx.set_store(store_good) @@ -4182,7 +4182,7 @@ def test_verify_with_time(self): with pytest.raises(X509StoreContextError) as exc: store_ctx.verify_certificate() - assert exc.value.args[0][2] == "certificate has expired" + assert str(exc.value) == "certificate has expired" def test_get_verified_chain(self): """ @@ -4216,7 +4216,7 @@ def test_get_verified_chain_invalid_chain_no_root(self): with pytest.raises(X509StoreContextError) as exc: store_ctx.get_verified_chain() - assert exc.value.args[0][2] == "unable to get issuer certificate" + assert str(exc.value) == "unable to get issuer certificate" assert exc.value.certificate.get_subject().CN == "intermediate" @pytest.fixture @@ -4281,7 +4281,7 @@ def test_verify_failure_with_empty_ca_directory(self, tmpdir): with pytest.raises(X509StoreContextError) as exc: store_ctx.verify_certificate() - assert exc.value.args[0][2] == "unable to get local issuer certificate" + assert str(exc.value) == "unable to get local issuer certificate" class TestSignVerify: From cff26bccefb488cbcd43b3d65c0026eccc2f0fdc Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Wed, 6 Jul 2022 10:17:39 -0400 Subject: [PATCH 3/4] OpenSSL/crypto: blacken Signed-off-by: William Woodruff --- src/OpenSSL/crypto.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/OpenSSL/crypto.py b/src/OpenSSL/crypto.py index 102603b62..6f034d09e 100644 --- a/src/OpenSSL/crypto.py +++ b/src/OpenSSL/crypto.py @@ -1776,7 +1776,9 @@ class X509StoreContextError(Exception): :type certificate: :class:`X509` """ - def __init__(self, message: str, errors: List[Any], certificate: X509) -> None: + def __init__( + self, message: str, errors: List[Any], certificate: X509 + ) -> None: super(X509StoreContextError, self).__init__(message) self.errors = errors self.certificate = certificate From 9192e04781a7efa725b1fe0a3c7a5f822c10ec4d Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 7 Jul 2022 15:39:38 -0400 Subject: [PATCH 4/4] CHANGELOG: record changes Signed-off-by: William Woodruff --- CHANGELOG.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5f2589f72..e1546f7a2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,9 @@ Backward-incompatible changes: - Remove support for SSLv2 and SSLv3. - The minimum ``cryptography`` version is now 37.0.2. +- The ``OpenSSL.crypto.X509StoreContextError`` exception has been refactored, + changing its internal attributes. + `#1133 `_ Deprecations: ^^^^^^^^^^^^^