diff --git a/src/cryptography/exceptions.py b/src/cryptography/exceptions.py index 59c7ebaff..47fdd18ee 100644 --- a/src/cryptography/exceptions.py +++ b/src/cryptography/exceptions.py @@ -6,25 +6,12 @@ from __future__ import annotations import typing -from cryptography import utils +from cryptography.hazmat.bindings._rust import exceptions as rust_exceptions if typing.TYPE_CHECKING: from cryptography.hazmat.bindings._rust import openssl as rust_openssl - -class _Reasons(utils.Enum): - BACKEND_MISSING_INTERFACE = 0 - UNSUPPORTED_HASH = 1 - UNSUPPORTED_CIPHER = 2 - UNSUPPORTED_PADDING = 3 - UNSUPPORTED_MGF = 4 - UNSUPPORTED_PUBLIC_KEY_ALGORITHM = 5 - UNSUPPORTED_ELLIPTIC_CURVE = 6 - UNSUPPORTED_SERIALIZATION = 7 - UNSUPPORTED_X509 = 8 - UNSUPPORTED_EXCHANGE_ALGORITHM = 9 - UNSUPPORTED_DIFFIE_HELLMAN = 10 - UNSUPPORTED_MAC = 11 +_Reasons = rust_exceptions._Reasons class UnsupportedAlgorithm(Exception): diff --git a/src/cryptography/hazmat/bindings/_rust/exceptions.pyi b/src/cryptography/hazmat/bindings/_rust/exceptions.pyi new file mode 100644 index 000000000..09f46b1e8 --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/exceptions.pyi @@ -0,0 +1,17 @@ +# 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. + +class _Reasons: + BACKEND_MISSING_INTERFACE: _Reasons + UNSUPPORTED_HASH: _Reasons + UNSUPPORTED_CIPHER: _Reasons + UNSUPPORTED_PADDING: _Reasons + UNSUPPORTED_MGF: _Reasons + UNSUPPORTED_PUBLIC_KEY_ALGORITHM: _Reasons + UNSUPPORTED_ELLIPTIC_CURVE: _Reasons + UNSUPPORTED_SERIALIZATION: _Reasons + UNSUPPORTED_X509: _Reasons + UNSUPPORTED_EXCHANGE_ALGORITHM: _Reasons + UNSUPPORTED_DIFFIE_HELLMAN: _Reasons + UNSUPPORTED_MAC: _Reasons diff --git a/src/rust/src/backend/hashes.rs b/src/rust/src/backend/hashes.rs index 14af3906a..6543094ee 100644 --- a/src/rust/src/backend/hashes.rs +++ b/src/rust/src/backend/hashes.rs @@ -4,6 +4,7 @@ use crate::buf::CffiBuf; use crate::error::{CryptographyError, CryptographyResult}; +use crate::exceptions; use std::borrow::Cow; #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.hashes")] @@ -71,21 +72,12 @@ pub(crate) fn message_digest_from_algorithm( match openssl::hash::MessageDigest::from_name(&openssl_name) { Some(md) => Ok(md), - None => { - let exceptions_module = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; - let reason = exceptions_module - .getattr(pyo3::intern!(py, "_Reasons"))? - .getattr(pyo3::intern!(py, "UNSUPPORTED_HASH"))?; - Err(CryptographyError::from(pyo3::PyErr::from_value( - exceptions_module.call_method1( - pyo3::intern!(py, "UnsupportedAlgorithm"), - ( - format!("{} is not a supported hash on this backend", name), - reason, - ), - )?, - ))) - } + None => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(( + format!("{} is not a supported hash on this backend", name), + exceptions::Reasons::UNSUPPORTED_HASH, + )), + )), } } diff --git a/src/rust/src/exceptions.rs b/src/rust/src/exceptions.rs new file mode 100644 index 000000000..be59a6351 --- /dev/null +++ b/src/rust/src/exceptions.rs @@ -0,0 +1,33 @@ +// 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. + +#[pyo3::prelude::pyclass( + module = "cryptography.hazmat.bindings._rust.exceptions", + name = "_Reasons" +)] +#[allow(non_camel_case_types)] +pub(crate) enum Reasons { + BACKEND_MISSING_INTERFACE, + UNSUPPORTED_HASH, + UNSUPPORTED_CIPHER, + UNSUPPORTED_PADDING, + UNSUPPORTED_MGF, + UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + UNSUPPORTED_ELLIPTIC_CURVE, + UNSUPPORTED_SERIALIZATION, + UNSUPPORTED_X509, + UNSUPPORTED_EXCHANGE_ALGORITHM, + UNSUPPORTED_DIFFIE_HELLMAN, + UNSUPPORTED_MAC, +} + +pyo3::import_exception!(cryptography.exceptions, UnsupportedAlgorithm); + +pub(crate) fn create_submodule(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let submod = pyo3::prelude::PyModule::new(py, "exceptions")?; + + submod.add_class::()?; + + Ok(submod) +} diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 74989350b..f39762c88 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -13,6 +13,7 @@ mod asn1; mod backend; mod buf; mod error; +mod exceptions; pub(crate) mod oid; mod pkcs7; mod pool; @@ -156,6 +157,7 @@ fn _rust(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> m.add_submodule(asn1::create_submodule(py)?)?; m.add_submodule(pkcs7::create_submodule(py)?)?; + m.add_submodule(exceptions::create_submodule(py)?)?; let x509_mod = pyo3::prelude::PyModule::new(py, "x509")?; crate::x509::certificate::add_to_module(x509_mod)?; diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index a20e3fe5f..889878972 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -6,8 +6,8 @@ use crate::asn1::{ big_byte_slice_to_py_int, encode_der_data, oid_to_py_oid, py_uint_to_big_endian_bytes, }; use crate::error::{CryptographyError, CryptographyResult}; -use crate::x509; use crate::x509::{extensions, sct, sign}; +use crate::{exceptions, x509}; use cryptography_x509::common::Asn1ReadableOrWritable; use cryptography_x509::extensions::{ AuthorityKeyIdentifier, BasicConstraints, DisplayText, DistributionPoint, @@ -244,16 +244,12 @@ impl Certificate { let hash_alg = sig_oids_to_hash.get_item(self.signature_algorithm_oid(py)?); match hash_alg { Ok(data) => Ok(data), - Err(_) => Err(CryptographyError::from(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1( - "UnsupportedAlgorithm", - (format!( - "Signature algorithm OID: {} not recognized", - self.raw.borrow_value().signature_alg.oid - ),), - )?, - ))), + Err(_) => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + self.raw.borrow_value().signature_alg.oid + )), + )), } } diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index ea04bb984..dcf09c731 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -6,8 +6,8 @@ use crate::asn1::{ big_byte_slice_to_py_int, encode_der_data, oid_to_py_oid, py_uint_to_big_endian_bytes, }; use crate::error::{CryptographyError, CryptographyResult}; -use crate::x509; use crate::x509::{certificate, extensions, sign}; +use crate::{exceptions, x509}; use cryptography_x509::{common, crl, name, oid}; use pyo3::{IntoPy, ToPyObject}; use std::sync::Arc; @@ -201,19 +201,15 @@ impl CertificateRevocationList { ) -> pyo3::PyResult<&'p pyo3::PyAny> { let oid = self.signature_algorithm_oid(py)?; let oid_module = py.import(pyo3::intern!(py, "cryptography.hazmat._oid"))?; - let exceptions_module = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; match oid_module .getattr(pyo3::intern!(py, "_SIG_OIDS_TO_HASH"))? .get_item(oid) { Ok(v) => Ok(v), - Err(_) => Err(pyo3::PyErr::from_value(exceptions_module.call_method1( - "UnsupportedAlgorithm", - (format!( - "Signature algorithm OID:{} not recognized", - self.owned.borrow_value().signature_algorithm.oid - ),), - )?)), + Err(_) => Err(exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + self.owned.borrow_value().signature_algorithm.oid + ))), } } diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index 6de3667ae..f376b9fed 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -4,8 +4,8 @@ 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, sign}; +use crate::{exceptions, x509}; use asn1::SimpleAsn1Readable; use cryptography_x509::csr::{check_attribute_length, Attribute, CertificationRequestInfo, Csr}; use cryptography_x509::{common, oid}; @@ -102,16 +102,12 @@ impl CertificateSigningRequest { let hash_alg = sig_oids_to_hash.get_item(self.signature_algorithm_oid(py)?); match hash_alg { Ok(data) => Ok(data), - Err(_) => Err(CryptographyError::from(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1( - "UnsupportedAlgorithm", - (format!( - "Signature algorithm OID: {} not recognized", - self.raw.borrow_value().signature_alg.oid - ),), - )?, - ))), + Err(_) => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + self.raw.borrow_value().signature_alg.oid + )), + )), } } diff --git a/src/rust/src/x509/ocsp_req.rs b/src/rust/src/x509/ocsp_req.rs index 856c60c93..701868e89 100644 --- a/src/rust/src/x509/ocsp_req.rs +++ b/src/rust/src/x509/ocsp_req.rs @@ -4,8 +4,8 @@ use crate::asn1::{big_byte_slice_to_py_int, oid_to_py_oid, py_uint_to_big_endian_bytes}; use crate::error::{CryptographyError, CryptographyResult}; -use crate::x509; use crate::x509::{extensions, ocsp}; +use crate::{exceptions, x509}; use cryptography_x509::{common, ocsp_req, oid}; use pyo3::IntoPy; @@ -88,17 +88,12 @@ impl OCSPRequest { let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; match ocsp::OIDS_TO_HASH.get(&cert_id.hash_algorithm.oid) { Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), - None => { - let exceptions = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; - Err(CryptographyError::from(pyo3::PyErr::from_value( - exceptions - .getattr(pyo3::intern!(py, "UnsupportedAlgorithm"))? - .call1((format!( - "Signature algorithm OID: {} not recognized", - cert_id.hash_algorithm.oid - ),))?, - ))) - } + None => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + cert_id.hash_algorithm.oid + )), + )), } } diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index 717be9565..103b610ec 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -4,8 +4,8 @@ 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, py_to_datetime, sct}; +use crate::{exceptions, x509}; use cryptography_x509::ocsp_resp::SingleResponse; use cryptography_x509::{common, ocsp_resp, oid}; use pyo3::IntoPy; @@ -187,10 +187,9 @@ impl OCSPResponse { "Signature algorithm OID: {} not recognized", self.requires_successful_response()?.signature_algorithm.oid ); - Err(CryptographyError::from(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1(pyo3::intern!(py, "UnsupportedAlgorithm"), (exc_messsage,))?, - ))) + Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(exc_messsage), + )) } } } @@ -480,17 +479,12 @@ fn singleresp_py_hash_algorithm<'p>( let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; match ocsp::OIDS_TO_HASH.get(&resp.cert_id.hash_algorithm.oid) { Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), - None => { - let exceptions = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; - Err(CryptographyError::from(pyo3::PyErr::from_value( - exceptions - .getattr(pyo3::intern!(py, "UnsupportedAlgorithm"))? - .call1((format!( - "Signature algorithm OID: {} not recognized", - resp.cert_id.hash_algorithm.oid - ),))?, - ))) - } + None => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + resp.cert_id.hash_algorithm.oid + )), + )), } } diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index 12579b35e..187dc54db 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -3,6 +3,7 @@ // for complete details. use crate::error::{CryptographyError, CryptographyResult}; +use crate::exceptions; use cryptography_x509::{common, oid}; use once_cell::sync::Lazy; @@ -120,16 +121,10 @@ fn identify_hash_type( "sha3-256" => Ok(HashType::Sha3_256), "sha3-384" => Ok(HashType::Sha3_384), "sha3-512" => Ok(HashType::Sha3_512), - name => Err(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1( - "UnsupportedAlgorithm", - (format!( - "Hash algorithm {:?} not supported for signatures", - name - ),), - )?, - )), + name => Err(exceptions::UnsupportedAlgorithm::new_err(format!( + "Hash algorithm {:?} not supported for signatures", + name + ))), } } @@ -239,12 +234,8 @@ pub(crate) fn compute_signature_algorithm<'p>( ( KeyType::Dsa, HashType::Sha3_224 | HashType::Sha3_256 | HashType::Sha3_384 | HashType::Sha3_512, - ) => Err(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1( - "UnsupportedAlgorithm", - ("SHA3 hashes are not supported with DSA keys",), - )?, + ) => Err(exceptions::UnsupportedAlgorithm::new_err( + "SHA3 hashes are not supported with DSA keys", )), (_, HashType::None) => Err(pyo3::exceptions::PyTypeError::new_err( "Algorithm must be a registered hash algorithm, not None.", diff --git a/tests/utils.py b/tests/utils.py index c87df65c1..bad0f87da 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -33,7 +33,7 @@ def raises_unsupported_algorithm(reason): with pytest.raises(UnsupportedAlgorithm) as exc_info: yield exc_info - assert exc_info.value._reason is reason + assert exc_info.value._reason == reason T = typing.TypeVar("T")