diff options
| author | Alex Gaynor <alex.gaynor@gmail.com> | 2023-03-19 21:41:48 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-20 09:41:48 +0800 |
| commit | 45a5100e4ee2c154981aa0d6fbcf8d2f751f50f8 (patch) | |
| tree | da322e32ece9ee26ec6def0badc628762533c73b /src/cryptography | |
| parent | 7a5170629f0ba7ce4a8b46b005cd9a5c35e06d3f (diff) | |
| download | cryptography-45a5100e4ee2c154981aa0d6fbcf8d2f751f50f8.tar.gz | |
Simplify/unify Rust and Python OpenSSL error handling (#8552)
Diffstat (limited to 'src/cryptography')
| -rw-r--r-- | src/cryptography/exceptions.py | 6 | ||||
| -rw-r--r-- | src/cryptography/hazmat/backends/openssl/backend.py | 21 | ||||
| -rw-r--r-- | src/cryptography/hazmat/backends/openssl/dh.py | 4 | ||||
| -rw-r--r-- | src/cryptography/hazmat/backends/openssl/rsa.py | 6 | ||||
| -rw-r--r-- | src/cryptography/hazmat/backends/openssl/utils.py | 4 | ||||
| -rw-r--r-- | src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi | 10 | ||||
| -rw-r--r-- | src/cryptography/hazmat/bindings/openssl/binding.py | 82 |
7 files changed, 33 insertions, 100 deletions
diff --git a/src/cryptography/exceptions.py b/src/cryptography/exceptions.py index b0e2b4dac..5e69c1192 100644 --- a/src/cryptography/exceptions.py +++ b/src/cryptography/exceptions.py @@ -8,9 +8,7 @@ import typing from cryptography import utils if typing.TYPE_CHECKING: - from cryptography.hazmat.bindings.openssl.binding import ( - _OpenSSLErrorWithText, - ) + from cryptography.hazmat.bindings._rust import openssl as rust_openssl class _Reasons(utils.Enum): @@ -58,7 +56,7 @@ class InvalidSignature(Exception): class InternalError(Exception): def __init__( - self, msg: str, err_code: typing.List["_OpenSSLErrorWithText"] + self, msg: str, err_code: typing.List["rust_openssl.OpenSSLError"] ) -> None: super().__init__(msg) self.err_code = err_code diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 0610b254e..3415863b3 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -57,6 +57,7 @@ from cryptography.hazmat.backends.openssl.x25519 import ( _X25519PrivateKey, _X25519PublicKey, ) +from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.bindings.openssl import binding from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding @@ -209,7 +210,7 @@ class Backend: def openssl_assert( self, ok: bool, - errors: typing.Optional[typing.List[binding._OpenSSLError]] = None, + errors: typing.Optional[typing.List[rust_openssl.OpenSSLError]] = None, ) -> None: return binding._openssl_assert(self._lib, ok, errors=errors) @@ -484,13 +485,8 @@ class Backend: self.openssl_assert(res == 1) return self._ffi.buffer(buf)[:] - def _consume_errors(self) -> typing.List[binding._OpenSSLError]: - return binding._consume_errors() - - def _consume_errors_with_text( - self, - ) -> typing.List[binding._OpenSSLErrorWithText]: - return binding._consume_errors_with_text() + def _consume_errors(self) -> typing.List[rust_openssl.OpenSSLError]: + return rust_openssl.capture_error_stack() def _bn_to_int(self, bn) -> int: assert bn != self._ffi.NULL @@ -760,7 +756,7 @@ class Backend: elif key_type == self._lib.EVP_PKEY_EC: ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) if ec_cdata == self._ffi.NULL: - errors = self._consume_errors_with_text() + errors = self._consume_errors() raise ValueError("Unable to load EC key", errors) ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) @@ -1208,13 +1204,12 @@ class Backend: raise ValueError("Unsupported public key algorithm.") else: - errors_with_text = binding._errors_with_text(errors) raise ValueError( "Could not deserialize key data. The data may be in an " "incorrect format, it may be encrypted with an unsupported " "algorithm, or it may be an unsupported key type (e.g. EC " "curves with explicit parameters).", - errors_with_text, + errors, ) def elliptic_curve_supported(self, curve: ec.EllipticCurve) -> bool: @@ -1708,7 +1703,7 @@ class Backend: dh_param_cdata, key_size, generator, self._ffi.NULL ) if res != 1: - errors = self._consume_errors_with_text() + errors = self._consume_errors() raise ValueError("Unable to generate DH parameters", errors) return _DHParameters(self, dh_param_cdata) @@ -2051,7 +2046,7 @@ class Backend: length, ) if res != 1: - errors = self._consume_errors_with_text() + errors = self._consume_errors() # memory required formula explained here: # https://blog.filippo.io/the-scrypt-parameters/ min_memory = 128 * n * r // (1024**2) diff --git a/src/cryptography/hazmat/backends/openssl/dh.py b/src/cryptography/hazmat/backends/openssl/dh.py index c429c0239..87d6fb8af 100644 --- a/src/cryptography/hazmat/backends/openssl/dh.py +++ b/src/cryptography/hazmat/backends/openssl/dh.py @@ -188,10 +188,10 @@ class _DHPrivateKey(dh.DHPrivateKey): def _exchange_assert(self, ok: bool) -> None: if not ok: - errors_with_text = self._backend._consume_errors_with_text() + errors = self._backend._consume_errors() raise ValueError( "Error computing shared key.", - errors_with_text, + errors, ) def public_key(self) -> dh.DHPublicKey: diff --git a/src/cryptography/hazmat/backends/openssl/rsa.py b/src/cryptography/hazmat/backends/openssl/rsa.py index c04cae029..c960105e7 100644 --- a/src/cryptography/hazmat/backends/openssl/rsa.py +++ b/src/cryptography/hazmat/backends/openssl/rsa.py @@ -285,7 +285,7 @@ def _rsa_sig_sign( buf = backend._ffi.new("unsigned char[]", buflen[0]) res = backend._lib.EVP_PKEY_sign(pkey_ctx, buf, buflen, data, len(data)) if res != 1: - errors = backend._consume_errors_with_text() + errors = backend._consume_errors() raise ValueError( "Digest or salt length too long for key size. Use a larger key " "or shorter salt length if you are specifying a PSS salt", @@ -380,7 +380,7 @@ class _RSAPrivateKey(RSAPrivateKey): if not unsafe_skip_rsa_key_validation: res = backend._lib.RSA_check_key(rsa_cdata) if res != 1: - errors = backend._consume_errors_with_text() + errors = backend._consume_errors() raise ValueError("Invalid private key", errors) # 2 is prime and passes an RSA key check, so we also check # if p and q are odd just to be safe. @@ -392,7 +392,7 @@ class _RSAPrivateKey(RSAPrivateKey): p_odd = backend._lib.BN_is_odd(p[0]) q_odd = backend._lib.BN_is_odd(q[0]) if p_odd != 1 or q_odd != 1: - errors = backend._consume_errors_with_text() + errors = backend._consume_errors() raise ValueError("Invalid private key", errors) self._backend = backend diff --git a/src/cryptography/hazmat/backends/openssl/utils.py b/src/cryptography/hazmat/backends/openssl/utils.py index 019f412c7..64b4a8334 100644 --- a/src/cryptography/hazmat/backends/openssl/utils.py +++ b/src/cryptography/hazmat/backends/openssl/utils.py @@ -35,8 +35,8 @@ def _evp_pkey_derive(backend: "Backend", evp_pkey, peer_public_key) -> bytes: buf = backend._ffi.new("unsigned char[]", keylen[0]) res = backend._lib.EVP_PKEY_derive(ctx, buf, keylen) if res != 1: - errors_with_text = backend._consume_errors_with_text() - raise ValueError("Error computing shared key.", errors_with_text) + errors = backend._consume_errors() + raise ValueError("Error computing shared key.", errors) return backend._ffi.buffer(buf, keylen[0])[:] diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi index 0e292a2fe..d583500df 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -6,3 +6,13 @@ import typing def openssl_version() -> int: ... def raise_openssl_error() -> typing.NoReturn: ... +def capture_error_stack() -> typing.List[OpenSSLError]: ... + +class OpenSSLError: + @property + def lib(self) -> int: ... + @property + def reason(self) -> int: ... + @property + def reason_text(self) -> bytes: ... + def _lib_reason_match(self, lib: int, reason: int) -> bool: ... diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py index b0fc8de28..7327157fd 100644 --- a/src/cryptography/hazmat/bindings/openssl/binding.py +++ b/src/cryptography/hazmat/bindings/openssl/binding.py @@ -16,84 +16,14 @@ from cryptography.hazmat.bindings._rust import _openssl, openssl from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES -class _OpenSSLErrorWithText(typing.NamedTuple): - code: int - lib: int - reason: int - reason_text: bytes - - @classmethod - def from_err(cls, err: "_OpenSSLError") -> "_OpenSSLErrorWithText": - buf = _openssl.ffi.new("char[]", 256) - _openssl.lib.ERR_error_string_n(err.code, buf, len(buf)) - err_text_reason: bytes = _openssl.ffi.string(buf) - - return _OpenSSLErrorWithText( - err.code, err.lib, err.reason, err_text_reason - ) - - -class _OpenSSLError: - def __init__(self, code: int, lib: int, reason: int): - self._code = code - self._lib = lib - self._reason = reason - - @classmethod - def from_code(cls, code: int) -> "_OpenSSLError": - err_lib: int = _openssl.lib.ERR_GET_LIB(code) - err_reason: int = _openssl.lib.ERR_GET_REASON(code) - return cls(code, err_lib, err_reason) - - def _lib_reason_match(self, lib: int, reason: int) -> bool: - return lib == self.lib and reason == self.reason - - @property - def code(self) -> int: - return self._code - - @property - def lib(self) -> int: - return self._lib - - @property - def reason(self) -> int: - return self._reason - - -def _consume_errors() -> typing.List[_OpenSSLError]: - errors = [] - while True: - code: int = _openssl.lib.ERR_get_error() - if code == 0: - break - - errors.append(_OpenSSLError.from_code(code)) - - return errors - - -def _errors_with_text( - errors: typing.List[_OpenSSLError], -) -> typing.List[_OpenSSLErrorWithText]: - errors_with_text = [] - for err in errors: - errors_with_text.append(_OpenSSLErrorWithText.from_err(err)) - - return errors_with_text - - -def _consume_errors_with_text(): - return _errors_with_text(_consume_errors()) - - def _openssl_assert( - lib, ok: bool, errors: typing.Optional[typing.List[_OpenSSLError]] = None + lib, + ok: bool, + errors: typing.Optional[typing.List[openssl.OpenSSLError]] = None, ) -> None: if not ok: if errors is None: - errors = _consume_errors() - errors_with_text = _errors_with_text(errors) + errors = openssl.capture_error_stack() raise InternalError( "Unknown OpenSSL error. This error is commonly encountered when " @@ -102,8 +32,8 @@ def _openssl_assert( "OpenSSL try disabling it before reporting a bug. Otherwise " "please file an issue at https://github.com/pyca/cryptography/" "issues with information on how to reproduce " - "this. ({!r})".format(errors_with_text), - errors_with_text, + "this. ({!r})".format(errors), + errors, ) |
