diff options
author | Alex Gaynor <alex.gaynor@gmail.com> | 2023-03-16 01:05:33 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-16 13:05:33 +0800 |
commit | 8882c3c88d082f29b66fd2e72cb92273da96c427 (patch) | |
tree | c82d222726a8b58aa2834649e2d65a90a6d3da67 | |
parent | d6866c82b48283ee773054ba95b76b5f315ee556 (diff) | |
download | cryptography-8882c3c88d082f29b66fd2e72cb92273da96c427.tar.gz |
Support handling OpenSSL errors from Rust code (#8530)
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/backend.py | 4 | ||||
-rw-r--r-- | src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi (renamed from src/cryptography/hazmat/bindings/_rust/openssl.pyi) | 3 | ||||
-rw-r--r-- | src/cryptography/hazmat/bindings/openssl/binding.py | 41 | ||||
-rw-r--r-- | src/rust/src/asn1.rs | 104 | ||||
-rw-r--r-- | src/rust/src/error.rs | 167 | ||||
-rw-r--r-- | src/rust/src/lib.rs | 7 | ||||
-rw-r--r-- | src/rust/src/oid.rs | 2 | ||||
-rw-r--r-- | src/rust/src/pkcs7.rs | 3 | ||||
-rw-r--r-- | src/rust/src/x509/certificate.rs | 2 | ||||
-rw-r--r-- | src/rust/src/x509/common.rs | 3 | ||||
-rw-r--r-- | src/rust/src/x509/crl.rs | 2 | ||||
-rw-r--r-- | src/rust/src/x509/csr.rs | 5 | ||||
-rw-r--r-- | src/rust/src/x509/extensions.rs | 5 | ||||
-rw-r--r-- | src/rust/src/x509/ocsp.rs | 2 | ||||
-rw-r--r-- | src/rust/src/x509/ocsp_req.rs | 5 | ||||
-rw-r--r-- | src/rust/src/x509/ocsp_resp.rs | 3 | ||||
-rw-r--r-- | src/rust/src/x509/sct.rs | 2 | ||||
-rw-r--r-- | src/rust/src/x509/sign.rs | 2 | ||||
-rw-r--r-- | tests/hazmat/bindings/test_openssl.py | 26 |
19 files changed, 246 insertions, 142 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index a8964f365..0610b254e 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -485,12 +485,12 @@ class Backend: return self._ffi.buffer(buf)[:] def _consume_errors(self) -> typing.List[binding._OpenSSLError]: - return binding._consume_errors(self._lib) + return binding._consume_errors() def _consume_errors_with_text( self, ) -> typing.List[binding._OpenSSLErrorWithText]: - return binding._consume_errors_with_text(self._lib) + return binding._consume_errors_with_text() def _bn_to_int(self, bn) -> int: assert bn != self._ffi.NULL diff --git a/src/cryptography/hazmat/bindings/_rust/openssl.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi index 8cd7b3062..0e292a2fe 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -2,4 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +import typing + def openssl_version() -> int: ... +def raise_openssl_error() -> typing.NoReturn: ... diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py index 680164f41..b0fc8de28 100644 --- a/src/cryptography/hazmat/bindings/openssl/binding.py +++ b/src/cryptography/hazmat/bindings/openssl/binding.py @@ -22,6 +22,16 @@ class _OpenSSLErrorWithText(typing.NamedTuple): 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): @@ -29,6 +39,12 @@ class _OpenSSLError: 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 @@ -45,17 +61,14 @@ class _OpenSSLError: return self._reason -def _consume_errors(lib) -> typing.List[_OpenSSLError]: +def _consume_errors() -> typing.List[_OpenSSLError]: errors = [] while True: - code: int = lib.ERR_get_error() + code: int = _openssl.lib.ERR_get_error() if code == 0: break - err_lib: int = lib.ERR_GET_LIB(code) - err_reason: int = lib.ERR_GET_REASON(code) - - errors.append(_OpenSSLError(code, err_lib, err_reason)) + errors.append(_OpenSSLError.from_code(code)) return errors @@ -65,21 +78,13 @@ def _errors_with_text( ) -> typing.List[_OpenSSLErrorWithText]: errors_with_text = [] for err in errors: - 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) - - errors_with_text.append( - _OpenSSLErrorWithText( - err.code, err.lib, err.reason, err_text_reason - ) - ) + errors_with_text.append(_OpenSSLErrorWithText.from_err(err)) return errors_with_text -def _consume_errors_with_text(lib): - return _errors_with_text(_consume_errors(lib)) +def _consume_errors_with_text(): + return _errors_with_text(_consume_errors()) def _openssl_assert( @@ -87,7 +92,7 @@ def _openssl_assert( ) -> None: if not ok: if errors is None: - errors = _consume_errors(lib) + errors = _consume_errors() errors_with_text = _errors_with_text(errors) raise InternalError( diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 72dc7101d..0bc57341e 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -2,81 +2,12 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +use crate::error::{CryptographyError, CryptographyResult}; use crate::x509::Name; use pyo3::basic::CompareOp; use pyo3::types::IntoPyDict; use pyo3::ToPyObject; -pub enum CryptographyError { - Asn1Parse(asn1::ParseError), - Asn1Write(asn1::WriteError), - Py(pyo3::PyErr), -} - -impl From<asn1::ParseError> for CryptographyError { - fn from(e: asn1::ParseError) -> CryptographyError { - CryptographyError::Asn1Parse(e) - } -} - -impl From<asn1::WriteError> for CryptographyError { - fn from(e: asn1::WriteError) -> CryptographyError { - CryptographyError::Asn1Write(e) - } -} - -impl From<pyo3::PyErr> for CryptographyError { - fn from(e: pyo3::PyErr) -> CryptographyError { - CryptographyError::Py(e) - } -} - -impl From<pyo3::PyDowncastError<'_>> for CryptographyError { - fn from(e: pyo3::PyDowncastError<'_>) -> CryptographyError { - CryptographyError::Py(e.into()) - } -} - -impl From<pem::PemError> for CryptographyError { - fn from(e: pem::PemError) -> CryptographyError { - CryptographyError::Py(pyo3::exceptions::PyValueError::new_err(format!( - "Unable to load PEM file. See https://cryptography.io/en/latest/faq/#why-can-t-i-import-my-pem-file for more details. {:?}", - e - ))) - } -} - -impl From<CryptographyError> for pyo3::PyErr { - fn from(e: CryptographyError) -> pyo3::PyErr { - match e { - CryptographyError::Asn1Parse(asn1_error) => pyo3::exceptions::PyValueError::new_err( - format!("error parsing asn1 value: {:?}", asn1_error), - ), - CryptographyError::Asn1Write(asn1::WriteError::AllocationError) => { - pyo3::exceptions::PyMemoryError::new_err( - "failed to allocate memory while performing ASN.1 serialization", - ) - } - CryptographyError::Py(py_error) => py_error, - } - } -} - -impl CryptographyError { - pub(crate) fn add_location(self, loc: asn1::ParseLocation) -> Self { - match self { - CryptographyError::Py(e) => CryptographyError::Py(e), - CryptographyError::Asn1Parse(e) => CryptographyError::Asn1Parse(e.add_location(loc)), - CryptographyError::Asn1Write(e) => CryptographyError::Asn1Write(e), - } - } -} - -// The primary purpose of this alias is for brevity to keep function signatures -// to a single-line as a work around for coverage issues. See -// https://github.com/pyca/cryptography/pull/6173 -pub(crate) type CryptographyResult<T = pyo3::PyObject> = Result<T, CryptographyError>; - pub(crate) fn py_oid_to_oid(py_oid: &pyo3::PyAny) -> pyo3::PyResult<asn1::ObjectIdentifier> { Ok(py_oid .downcast::<pyo3::PyCell<crate::oid::ObjectIdentifier>>()? @@ -297,36 +228,3 @@ pub(crate) fn create_submodule(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::pr Ok(submod) } - -#[cfg(test)] -mod tests { - use super::CryptographyError; - - #[test] - fn test_cryptographyerror_from() { - pyo3::prepare_freethreaded_python(); - pyo3::Python::with_gil(|py| { - let e: CryptographyError = asn1::WriteError::AllocationError.into(); - assert!(matches!( - e, - CryptographyError::Asn1Write(asn1::WriteError::AllocationError) - )); - let py_e: pyo3::PyErr = e.into(); - assert!(py_e.is_instance::<pyo3::exceptions::PyMemoryError>(py)); - - let e: CryptographyError = - pyo3::PyDowncastError::new(py.None().as_ref(py), "abc").into(); - assert!(matches!(e, CryptographyError::Py(_))); - }) - } - - #[test] - fn test_cryptographyerror_add_location() { - let py_err = pyo3::PyErr::new::<pyo3::exceptions::PyValueError, _>("Error!"); - CryptographyError::Py(py_err).add_location(asn1::ParseLocation::Field("meh")); - - let asn1_write_err = asn1::WriteError::AllocationError; - CryptographyError::Asn1Write(asn1_write_err) - .add_location(asn1::ParseLocation::Field("meh")); - } -} diff --git a/src/rust/src/error.rs b/src/rust/src/error.rs new file mode 100644 index 000000000..ac3da6bd0 --- /dev/null +++ b/src/rust/src/error.rs @@ -0,0 +1,167 @@ +// This file is dual licensed under the terms of the Apache License, Version +// 2.0, and the BSD License. See the LICENSE file in the root of this repository +// for complete details. + +pub enum CryptographyError { + Asn1Parse(asn1::ParseError), + Asn1Write(asn1::WriteError), + Py(pyo3::PyErr), + OpenSSL(openssl::error::ErrorStack), +} + +impl From<asn1::ParseError> for CryptographyError { + fn from(e: asn1::ParseError) -> CryptographyError { + CryptographyError::Asn1Parse(e) + } +} + +impl From<asn1::WriteError> for CryptographyError { + fn from(e: asn1::WriteError) -> CryptographyError { + CryptographyError::Asn1Write(e) + } +} + +impl From<pyo3::PyErr> for CryptographyError { + fn from(e: pyo3::PyErr) -> CryptographyError { + CryptographyError::Py(e) + } +} + +impl From<pyo3::PyDowncastError<'_>> for CryptographyError { + fn from(e: pyo3::PyDowncastError<'_>) -> CryptographyError { + CryptographyError::Py(e.into()) + } +} + +impl From<openssl::error::ErrorStack> for CryptographyError { + fn from(e: openssl::error::ErrorStack) -> CryptographyError { + CryptographyError::OpenSSL(e) + } +} + +impl From<pem::PemError> for CryptographyError { + fn from(e: pem::PemError) -> CryptographyError { + CryptographyError::Py(pyo3::exceptions::PyValueError::new_err(format!( + "Unable to load PEM file. See https://cryptography.io/en/latest/faq/#why-can-t-i-import-my-pem-file for more details. {:?}", + e + ))) + } +} + +impl From<CryptographyError> for pyo3::PyErr { + fn from(e: CryptographyError) -> pyo3::PyErr { + match e { + CryptographyError::Asn1Parse(asn1_error) => pyo3::exceptions::PyValueError::new_err( + format!("error parsing asn1 value: {:?}", asn1_error), + ), + CryptographyError::Asn1Write(asn1::WriteError::AllocationError) => { + pyo3::exceptions::PyMemoryError::new_err( + "failed to allocate memory while performing ASN.1 serialization", + ) + } + CryptographyError::Py(py_error) => py_error, + CryptographyError::OpenSSL(error_stack) => { + let gil = pyo3::Python::acquire_gil(); + let py = gil.python(); + + let internal_error = py + .import("cryptography.exceptions") + .expect("Failed to import cryptography module") + .getattr(crate::intern!(py, "InternalError")) + .expect("Failed to get InternalError attribute"); + + let binding_mod = py + .import("cryptography.hazmat.bindings.openssl.binding") + .expect("Failed to import cryptography module"); + + let openssl_error = binding_mod + .getattr(crate::intern!(py, "_OpenSSLError")) + .expect("Failed to get _OpenSSL attribute"); + let openssl_error_with_text = binding_mod + .getattr(crate::intern!(py, "_OpenSSLErrorWithText")) + .expect("Failed to get _OpenSSLErrorWithText attribute"); + + let errors = pyo3::types::PyList::empty(py); + for e in error_stack.errors() { + let err = openssl_error + .call_method1("from_code", (e.code(),)) + .expect("Failed to call from_code"); + + errors + .append( + openssl_error_with_text + .call_method1("from_err", (err,)) + .expect("Failed to call from_err"), + ) + .expect("List append failed"); + } + pyo3::PyErr::from_instance( + internal_error + .call1(( + "Unknown OpenSSL error. This error is commonly encountered + when another library is not cleaning up the OpenSSL error + stack. If you are using cryptography with another library + that uses 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.", + errors, + )) + .expect("Failed to create InternalError"), + ) + } + } + } +} + +impl CryptographyError { + pub(crate) fn add_location(self, loc: asn1::ParseLocation) -> Self { + match self { + CryptographyError::Py(e) => CryptographyError::Py(e), + CryptographyError::Asn1Parse(e) => CryptographyError::Asn1Parse(e.add_location(loc)), + CryptographyError::Asn1Write(e) => CryptographyError::Asn1Write(e), + CryptographyError::OpenSSL(e) => CryptographyError::OpenSSL(e), + } + } +} + +// The primary purpose of this alias is for brevity to keep function signatures +// to a single-line as a work around for coverage issues. See +// https://github.com/pyca/cryptography/pull/6173 +pub(crate) type CryptographyResult<T = pyo3::PyObject> = Result<T, CryptographyError>; + +#[cfg(test)] +mod tests { + use super::CryptographyError; + + #[test] + fn test_cryptographyerror_from() { + pyo3::prepare_freethreaded_python(); + pyo3::Python::with_gil(|py| { + let e: CryptographyError = asn1::WriteError::AllocationError.into(); + assert!(matches!( + e, + CryptographyError::Asn1Write(asn1::WriteError::AllocationError) + )); + let py_e: pyo3::PyErr = e.into(); + assert!(py_e.is_instance::<pyo3::exceptions::PyMemoryError>(py)); + + let e: CryptographyError = + pyo3::PyDowncastError::new(py.None().as_ref(py), "abc").into(); + assert!(matches!(e, CryptographyError::Py(_))); + }) + } + + #[test] + fn test_cryptographyerror_add_location() { + let py_err = pyo3::PyErr::new::<pyo3::exceptions::PyValueError, _>("Error!"); + CryptographyError::Py(py_err).add_location(asn1::ParseLocation::Field("meh")); + + let asn1_write_err = asn1::WriteError::AllocationError; + CryptographyError::Asn1Write(asn1_write_err) + .add_location(asn1::ParseLocation::Field("meh")); + + let openssl_error = openssl::error::ErrorStack::get(); + CryptographyError::from(openssl_error).add_location(asn1::ParseLocation::Field("meh")); + } +} diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index c3cb25154..d5de05932 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -10,6 +10,7 @@ #![allow(unknown_lints, clippy::borrow_deref_ref)] mod asn1; +mod error; mod intern; pub(crate) mod oid; mod pkcs7; @@ -95,6 +96,11 @@ fn openssl_version() -> i64 { openssl::version::number() } +#[pyo3::prelude::pyfunction] +fn raise_openssl_error() -> crate::error::CryptographyResult<()> { + Err(openssl::error::ErrorStack::get().into()) +} + #[pyo3::prelude::pymodule] fn _rust(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { m.add_function(pyo3::wrap_pyfunction!(check_pkcs7_padding, m)?)?; @@ -133,6 +139,7 @@ fn _rust(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> let openssl_mod = pyo3::prelude::PyModule::new(py, "openssl")?; openssl_mod.add_function(pyo3::wrap_pyfunction!(openssl_version, m)?)?; + openssl_mod.add_function(pyo3::wrap_pyfunction!(raise_openssl_error, m)?)?; m.add_submodule(openssl_mod)?; Ok(()) diff --git a/src/rust/src/oid.rs b/src/rust/src/oid.rs index c172310c0..a13668579 100644 --- a/src/rust/src/oid.rs +++ b/src/rust/src/oid.rs @@ -2,7 +2,7 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::CryptographyResult; +use crate::error::CryptographyResult; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index 557c09be1..93d9a11e4 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -2,7 +2,8 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::{encode_der_data, CryptographyResult}; +use crate::asn1::encode_der_data; +use crate::error::CryptographyResult; use crate::x509; use chrono::Timelike; diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 39d0ebfb5..1a9820e5e 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -4,8 +4,8 @@ use crate::asn1::{ big_byte_slice_to_py_int, encode_der_data, oid_to_py_oid, py_uint_to_big_endian_bytes, - CryptographyError, CryptographyResult, }; +use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{crl, extensions, oid, sct, sign, Asn1ReadableOrWritable}; use chrono::Datelike; diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index e93ec7ec0..a765d6144 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -2,7 +2,8 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::{oid_to_py_oid, py_oid_to_oid, CryptographyError, CryptographyResult}; +use crate::asn1::{oid_to_py_oid, py_oid_to_oid}; +use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use chrono::{Datelike, TimeZone, Timelike}; use pyo3::types::IntoPyDict; diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index 75ac22541..c1b5c8c48 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -4,8 +4,8 @@ use crate::asn1::{ big_byte_slice_to_py_int, encode_der_data, oid_to_py_oid, py_uint_to_big_endian_bytes, - CryptographyError, CryptographyResult, }; +use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{certificate, extensions, oid, sign}; use pyo3::ToPyObject; diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index 66ce3413b..e16a58164 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -2,9 +2,8 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::{ - encode_der_data, oid_to_py_oid, py_oid_to_oid, CryptographyError, CryptographyResult, -}; +use crate::asn1::{encode_der_data, oid_to_py_oid, py_oid_to_oid}; +use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{certificate, oid, sign}; use asn1::SimpleAsn1Readable; diff --git a/src/rust/src/x509/extensions.rs b/src/rust/src/x509/extensions.rs index f8dd28a45..d93e87c0f 100644 --- a/src/rust/src/x509/extensions.rs +++ b/src/rust/src/x509/extensions.rs @@ -2,9 +2,8 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::{ - py_oid_to_oid, py_uint_to_big_endian_bytes, CryptographyError, CryptographyResult, -}; +use crate::asn1::{py_oid_to_oid, py_uint_to_big_endian_bytes}; +use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{certificate, crl, oid, sct}; diff --git a/src/rust/src/x509/ocsp.rs b/src/rust/src/x509/ocsp.rs index d06487021..a06e7f1cc 100644 --- a/src/rust/src/x509/ocsp.rs +++ b/src/rust/src/x509/ocsp.rs @@ -2,7 +2,7 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::CryptographyResult; +use crate::error::CryptographyResult; use crate::x509; use crate::x509::oid; use once_cell::sync::Lazy; diff --git a/src/rust/src/x509/ocsp_req.rs b/src/rust/src/x509/ocsp_req.rs index 078df6050..638caf9b2 100644 --- a/src/rust/src/x509/ocsp_req.rs +++ b/src/rust/src/x509/ocsp_req.rs @@ -2,9 +2,8 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::{ - big_byte_slice_to_py_int, py_uint_to_big_endian_bytes, CryptographyError, CryptographyResult, -}; +use crate::asn1::{big_byte_slice_to_py_int, py_uint_to_big_endian_bytes}; +use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{extensions, ocsp, oid}; use std::sync::Arc; diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index 35e1d672b..2f878b2c4 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -2,7 +2,8 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::{big_byte_slice_to_py_int, oid_to_py_oid, CryptographyError, CryptographyResult}; +use crate::asn1::{big_byte_slice_to_py_int, oid_to_py_oid}; +use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{certificate, crl, extensions, ocsp, oid, py_to_chrono, sct}; use chrono::Timelike; diff --git a/src/rust/src/x509/sct.rs b/src/rust/src/x509/sct.rs index 363a8187d..e3f7be4d9 100644 --- a/src/rust/src/x509/sct.rs +++ b/src/rust/src/x509/sct.rs @@ -2,7 +2,7 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::CryptographyError; +use crate::error::CryptographyError; use pyo3::types::IntoPyDict; use pyo3::ToPyObject; use std::collections::hash_map::DefaultHasher; diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index 4c1e9664f..33d293b21 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -2,7 +2,7 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::{CryptographyError, CryptographyResult}; +use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::oid; diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py index 0721fc09a..c80753bd0 100644 --- a/tests/hazmat/bindings/test_openssl.py +++ b/tests/hazmat/bindings/test_openssl.py @@ -5,6 +5,7 @@ import pytest from cryptography.exceptions import InternalError +from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.bindings.openssl.binding import ( Binding, _consume_errors, @@ -95,7 +96,7 @@ class TestOpenSSL: -1, ) b._register_osrandom_engine() - assert _consume_errors(b.lib) == [] + assert _consume_errors() == [] def test_version_mismatch(self): with pytest.raises(ImportError): @@ -106,3 +107,26 @@ class TestOpenSSL: _legacy_provider_error(False) _legacy_provider_error(True) + + def test_rust_internal_error(self): + with pytest.raises(InternalError) as exc_info: + rust_openssl.raise_openssl_error() + + assert len(exc_info.value.err_code) == 0 + + b = Binding() + b.lib.ERR_put_error( + b.lib.ERR_LIB_EVP, + b.lib.EVP_F_EVP_ENCRYPTFINAL_EX, + b.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH, + b"", + -1, + ) + with pytest.raises(InternalError) as exc_info: + rust_openssl.raise_openssl_error() + + error = exc_info.value.err_code[0] + assert error.lib == b.lib.ERR_LIB_EVP + assert error.reason == b.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH + if not b.lib.CRYPTOGRAPHY_IS_BORINGSSL: + assert b"data not multiple of block length" in error.reason_text |