diff options
author | Alex Gaynor <alex.gaynor@gmail.com> | 2023-05-14 16:37:20 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-15 04:37:20 +0800 |
commit | 4fc8e9aaa12f0b69fca0f36c544543aefb9c5d03 (patch) | |
tree | 536f8a838a5fa346156a50a56444afbb3cb011b8 | |
parent | cff3c8fee74ba08cc0ce4b67bbb635f73270f8b3 (diff) | |
download | cryptography-4fc8e9aaa12f0b69fca0f36c544543aefb9c5d03.tar.gz |
Move code to sign.rs (#8922)
-rw-r--r-- | src/rust/src/x509/certificate.rs | 140 | ||||
-rw-r--r-- | src/rust/src/x509/sign.rs | 143 |
2 files changed, 141 insertions, 142 deletions
diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 34e9ec0ec..3446bbbbb 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -17,28 +17,10 @@ use cryptography_x509::extensions::{ SequenceOfSubtrees, UserNotice, }; use cryptography_x509::{common, name, oid}; -use once_cell::sync::Lazy; use pyo3::{IntoPy, ToPyObject}; use std::collections::hash_map::DefaultHasher; -use std::collections::HashMap; use std::hash::{Hash, Hasher}; -// This is similar to a hashmap in ocsp.rs but contains more hash algorithms -// that aren't allowable in OCSP -static HASH_OIDS_TO_HASH: Lazy<HashMap<&asn1::ObjectIdentifier, &str>> = Lazy::new(|| { - let mut h = HashMap::new(); - h.insert(&oid::SHA1_OID, "SHA1"); - h.insert(&oid::SHA224_OID, "SHA224"); - h.insert(&oid::SHA256_OID, "SHA256"); - h.insert(&oid::SHA384_OID, "SHA384"); - h.insert(&oid::SHA512_OID, "SHA512"); - h.insert(&oid::SHA3_224_OID, "SHA3_224"); - h.insert(&oid::SHA3_256_OID, "SHA3_256"); - h.insert(&oid::SHA3_384_OID, "SHA3_384"); - h.insert(&oid::SHA3_512_OID, "SHA3_512"); - h -}); - #[ouroboros::self_referencing] pub(crate) struct OwnedCertificate { data: pyo3::Py<pyo3::types::PyBytes>, @@ -269,7 +251,7 @@ impl Certificate { &self, py: pyo3::Python<'p>, ) -> Result<&'p pyo3::PyAny, CryptographyError> { - identify_signature_hash_algorithm(py, &self.raw.borrow_value().signature_alg) + sign::identify_signature_hash_algorithm(py, &self.raw.borrow_value().signature_alg) } #[getter] @@ -282,7 +264,7 @@ impl Certificate { &'p self, py: pyo3::Python<'p>, ) -> CryptographyResult<&'p pyo3::PyAny> { - identify_signature_algorithm_parameters(py, &self.raw.borrow_value().signature_alg) + sign::identify_signature_algorithm_parameters(py, &self.raw.borrow_value().signature_alg) } #[getter] @@ -880,22 +862,6 @@ pub fn parse_cert_ext<'p>( } } -fn hash_oid_py_hash( - py: pyo3::Python<'_>, - oid: asn1::ObjectIdentifier, -) -> CryptographyResult<&pyo3::PyAny> { - let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; - match HASH_OIDS_TO_HASH.get(&oid) { - Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), - None => Err(CryptographyError::from( - exceptions::UnsupportedAlgorithm::new_err(format!( - "Signature algorithm OID: {} not recognized", - &oid - )), - )), - } -} - pub(crate) fn time_from_py( py: pyo3::Python<'_>, val: &pyo3::PyAny, @@ -994,108 +960,6 @@ pub(crate) fn set_bit(vals: &mut [u8], n: usize, set: bool) { } } -pub(crate) fn identify_signature_hash_algorithm<'p>( - py: pyo3::Python<'p>, - signature_algorithm: &common::AlgorithmIdentifier<'_>, -) -> CryptographyResult<&'p pyo3::PyAny> { - let sig_oids_to_hash = py - .import(pyo3::intern!(py, "cryptography.hazmat._oid"))? - .getattr(pyo3::intern!(py, "_SIG_OIDS_TO_HASH"))?; - match &signature_algorithm.params { - common::AlgorithmParameters::RsaPss(opt_pss) => { - let pss = opt_pss.as_ref().ok_or_else(|| { - pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters") - })?; - hash_oid_py_hash(py, pss.hash_algorithm.oid().clone()) - } - _ => { - let py_sig_alg_oid = oid_to_py_oid(py, signature_algorithm.oid())?; - let hash_alg = sig_oids_to_hash.get_item(py_sig_alg_oid); - match hash_alg { - Ok(data) => Ok(data), - Err(_) => Err(CryptographyError::from( - exceptions::UnsupportedAlgorithm::new_err(format!( - "Signature algorithm OID: {} not recognized", - signature_algorithm.oid() - )), - )), - } - } - } -} - -pub(crate) fn identify_signature_algorithm_parameters<'p>( - py: pyo3::Python<'p>, - signature_algorithm: &common::AlgorithmIdentifier<'_>, -) -> CryptographyResult<&'p pyo3::PyAny> { - match &signature_algorithm.params { - common::AlgorithmParameters::RsaPss(opt_pss) => { - let pss = opt_pss.as_ref().ok_or_else(|| { - pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters") - })?; - if pss.mask_gen_algorithm.oid != oid::MGF1_OID { - return Err(CryptographyError::from( - pyo3::exceptions::PyValueError::new_err(format!( - "Unsupported mask generation OID: {}", - pss.mask_gen_algorithm.oid - )), - )); - } - let py_mask_gen_hash_alg = - hash_oid_py_hash(py, pss.mask_gen_algorithm.params.oid().clone())?; - let padding = py.import(pyo3::intern!( - py, - "cryptography.hazmat.primitives.asymmetric.padding" - ))?; - let py_mgf = padding - .getattr(pyo3::intern!(py, "MGF1"))? - .call1((py_mask_gen_hash_alg,))?; - Ok(padding - .getattr(pyo3::intern!(py, "PSS"))? - .call1((py_mgf, pss.salt_length))?) - } - common::AlgorithmParameters::RsaWithSha1(_) - | common::AlgorithmParameters::RsaWithSha1Alt(_) - | common::AlgorithmParameters::RsaWithSha224(_) - | common::AlgorithmParameters::RsaWithSha256(_) - | common::AlgorithmParameters::RsaWithSha384(_) - | common::AlgorithmParameters::RsaWithSha512(_) - | common::AlgorithmParameters::RsaWithSha3_224(_) - | common::AlgorithmParameters::RsaWithSha3_256(_) - | common::AlgorithmParameters::RsaWithSha3_384(_) - | common::AlgorithmParameters::RsaWithSha3_512(_) => { - let pkcs = py - .import(pyo3::intern!( - py, - "cryptography.hazmat.primitives.asymmetric.padding" - ))? - .getattr(pyo3::intern!(py, "PKCS1v15"))? - .call0()?; - Ok(pkcs) - } - common::AlgorithmParameters::EcDsaWithSha224 - | common::AlgorithmParameters::EcDsaWithSha256 - | common::AlgorithmParameters::EcDsaWithSha384 - | common::AlgorithmParameters::EcDsaWithSha512 - | common::AlgorithmParameters::EcDsaWithSha3_224 - | common::AlgorithmParameters::EcDsaWithSha3_256 - | common::AlgorithmParameters::EcDsaWithSha3_384 - | common::AlgorithmParameters::EcDsaWithSha3_512 => { - let signature_hash_algorithm = - identify_signature_hash_algorithm(py, signature_algorithm)?; - - Ok(py - .import(pyo3::intern!( - py, - "cryptography.hazmat.primitives.asymmetric.ec" - ))? - .getattr(pyo3::intern!(py, "ECDSA"))? - .call1((signature_hash_algorithm,))?) - } - _ => Ok(py.None().into_ref(py)), - } -} - pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { module.add_function(pyo3::wrap_pyfunction!(load_der_x509_certificate, module)?)?; module.add_function(pyo3::wrap_pyfunction!(load_pem_x509_certificate, module)?)?; diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index 054300420..16db5a587 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -2,10 +2,28 @@ // 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; use crate::error::{CryptographyError, CryptographyResult}; use crate::exceptions; -use crate::x509::certificate; use cryptography_x509::{common, oid}; +use once_cell::sync::Lazy; +use std::collections::HashMap; + +// This is similar to a hashmap in ocsp.rs but contains more hash algorithms +// that aren't allowable in OCSP +static HASH_OIDS_TO_HASH: Lazy<HashMap<&asn1::ObjectIdentifier, &str>> = Lazy::new(|| { + let mut h = HashMap::new(); + h.insert(&oid::SHA1_OID, "SHA1"); + h.insert(&oid::SHA224_OID, "SHA224"); + h.insert(&oid::SHA256_OID, "SHA256"); + h.insert(&oid::SHA384_OID, "SHA384"); + h.insert(&oid::SHA512_OID, "SHA512"); + h.insert(&oid::SHA3_224_OID, "SHA3_224"); + h.insert(&oid::SHA3_256_OID, "SHA3_256"); + h.insert(&oid::SHA3_384_OID, "SHA3_384"); + h.insert(&oid::SHA3_512_OID, "SHA3_512"); + h +}); #[derive(Debug, PartialEq)] pub(crate) enum KeyType { @@ -368,9 +386,8 @@ pub(crate) fn verify_signature_with_signature_algorithm<'p>( )); } let py_signature_algorithm_parameters = - certificate::identify_signature_algorithm_parameters(py, signature_algorithm)?; - let py_signature_hash_algorithm = - certificate::identify_signature_hash_algorithm(py, signature_algorithm)?; + identify_signature_algorithm_parameters(py, signature_algorithm)?; + let py_signature_hash_algorithm = identify_signature_hash_algorithm(py, signature_algorithm)?; match key_type { KeyType::Ed25519 | KeyType::Ed448 => { issuer_public_key.call_method1(pyo3::intern!(py, "verify"), (signature, data))? @@ -504,6 +521,124 @@ fn identify_alg_params_for_hash_type( } } +fn hash_oid_py_hash( + py: pyo3::Python<'_>, + oid: asn1::ObjectIdentifier, +) -> CryptographyResult<&pyo3::PyAny> { + let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; + match HASH_OIDS_TO_HASH.get(&oid) { + Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), + None => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + &oid + )), + )), + } +} + +pub(crate) fn identify_signature_hash_algorithm<'p>( + py: pyo3::Python<'p>, + signature_algorithm: &common::AlgorithmIdentifier<'_>, +) -> CryptographyResult<&'p pyo3::PyAny> { + let sig_oids_to_hash = py + .import(pyo3::intern!(py, "cryptography.hazmat._oid"))? + .getattr(pyo3::intern!(py, "_SIG_OIDS_TO_HASH"))?; + match &signature_algorithm.params { + common::AlgorithmParameters::RsaPss(opt_pss) => { + let pss = opt_pss.as_ref().ok_or_else(|| { + pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters") + })?; + hash_oid_py_hash(py, pss.hash_algorithm.oid().clone()) + } + _ => { + let py_sig_alg_oid = oid_to_py_oid(py, signature_algorithm.oid())?; + let hash_alg = sig_oids_to_hash.get_item(py_sig_alg_oid); + match hash_alg { + Ok(data) => Ok(data), + Err(_) => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + signature_algorithm.oid() + )), + )), + } + } + } +} + +pub(crate) fn identify_signature_algorithm_parameters<'p>( + py: pyo3::Python<'p>, + signature_algorithm: &common::AlgorithmIdentifier<'_>, +) -> CryptographyResult<&'p pyo3::PyAny> { + match &signature_algorithm.params { + common::AlgorithmParameters::RsaPss(opt_pss) => { + let pss = opt_pss.as_ref().ok_or_else(|| { + pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters") + })?; + if pss.mask_gen_algorithm.oid != oid::MGF1_OID { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err(format!( + "Unsupported mask generation OID: {}", + pss.mask_gen_algorithm.oid + )), + )); + } + let py_mask_gen_hash_alg = + hash_oid_py_hash(py, pss.mask_gen_algorithm.params.oid().clone())?; + let padding = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.padding" + ))?; + let py_mgf = padding + .getattr(pyo3::intern!(py, "MGF1"))? + .call1((py_mask_gen_hash_alg,))?; + Ok(padding + .getattr(pyo3::intern!(py, "PSS"))? + .call1((py_mgf, pss.salt_length))?) + } + common::AlgorithmParameters::RsaWithSha1(_) + | common::AlgorithmParameters::RsaWithSha1Alt(_) + | common::AlgorithmParameters::RsaWithSha224(_) + | common::AlgorithmParameters::RsaWithSha256(_) + | common::AlgorithmParameters::RsaWithSha384(_) + | common::AlgorithmParameters::RsaWithSha512(_) + | common::AlgorithmParameters::RsaWithSha3_224(_) + | common::AlgorithmParameters::RsaWithSha3_256(_) + | common::AlgorithmParameters::RsaWithSha3_384(_) + | common::AlgorithmParameters::RsaWithSha3_512(_) => { + let pkcs = py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.padding" + ))? + .getattr(pyo3::intern!(py, "PKCS1v15"))? + .call0()?; + Ok(pkcs) + } + common::AlgorithmParameters::EcDsaWithSha224 + | common::AlgorithmParameters::EcDsaWithSha256 + | common::AlgorithmParameters::EcDsaWithSha384 + | common::AlgorithmParameters::EcDsaWithSha512 + | common::AlgorithmParameters::EcDsaWithSha3_224 + | common::AlgorithmParameters::EcDsaWithSha3_256 + | common::AlgorithmParameters::EcDsaWithSha3_384 + | common::AlgorithmParameters::EcDsaWithSha3_512 => { + let signature_hash_algorithm = + identify_signature_hash_algorithm(py, signature_algorithm)?; + + Ok(py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.ec" + ))? + .getattr(pyo3::intern!(py, "ECDSA"))? + .call1((signature_hash_algorithm,))?) + } + _ => Ok(py.None().into_ref(py)), + } +} + #[cfg(test)] mod tests { use super::{ |