Skip to content

Make X509StoreContextError more structured? #1132

@woodruffw

Description

@woodruffw

First of all, thanks for maintaining pyOpenSSL!

This is how an X509StoreContextError is currently constructed: it's a list of errors, combined with the cert that caused the error. The last member of the error list is a string representation of X509_STORE_CTX_get_error:

def _exception_from_context(self) -> X509StoreContextError:
"""
Convert an OpenSSL native context error failure into a Python
exception.
When a call to native OpenSSL X509_verify_cert fails, additional
information about the failure can be obtained from the store context.
"""
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"),
]
# 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)

As a result, it's inconvenient to introspect the different ways in which certificate verification can fail.

My proposal: the errors list stays the same, but the last member (the string representation) is also copied into a message attribute. In other words, something like this:

    def _exception_from_context(self) -> X509StoreContextError:
        """
        Convert an OpenSSL native context error failure into a Python
        exception.
        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),
            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(message, errors, pycert)

Let me know what you think. I'm happy to submit a PR with these changes, if there's interest.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions