diff --git a/src/rust/cryptography-x509/src/certificate.rs b/src/rust/cryptography-x509/src/certificate.rs index 06fc3a3ba4df..d5b48a537194 100644 --- a/src/rust/cryptography-x509/src/certificate.rs +++ b/src/rust/cryptography-x509/src/certificate.rs @@ -4,8 +4,10 @@ use crate::common; use crate::extensions; +use crate::extensions::DuplicateExtensionsError; use crate::extensions::Extensions; use crate::name; +use crate::name::NameReadable; #[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Eq, Clone)] pub struct Certificate<'a> { @@ -14,6 +16,24 @@ pub struct Certificate<'a> { pub signature: asn1::BitString<'a>, } +impl Certificate<'_> { + /// Returns the certificate's issuer. + pub fn issuer(&self) -> &NameReadable<'_> { + self.tbs_cert.issuer.unwrap_read() + } + + /// Returns the certificate's subject. + pub fn subject(&self) -> &NameReadable<'_> { + self.tbs_cert.subject.unwrap_read() + } + + /// Returns an iterable container over the certificate's extension, or + /// an error if the extension set contains a duplicate extension. + pub fn extensions(&self) -> Result, DuplicateExtensionsError> { + self.tbs_cert.extensions() + } +} + #[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Eq, Clone)] pub struct TbsCertificate<'a> { #[explicit(0)] @@ -36,7 +56,7 @@ pub struct TbsCertificate<'a> { } impl TbsCertificate<'_> { - pub fn extensions(&self) -> Result, asn1::ObjectIdentifier> { + pub fn extensions(&self) -> Result, DuplicateExtensionsError> { Extensions::from_raw_extensions(self.raw_extensions.as_ref()) } } diff --git a/src/rust/cryptography-x509/src/extensions.rs b/src/rust/cryptography-x509/src/extensions.rs index cf48fdbf6087..cb24682a3b7b 100644 --- a/src/rust/cryptography-x509/src/extensions.rs +++ b/src/rust/cryptography-x509/src/extensions.rs @@ -8,6 +8,8 @@ use crate::common; use crate::crl; use crate::name; +pub struct DuplicateExtensionsError(pub asn1::ObjectIdentifier); + pub type RawExtensions<'a> = common::Asn1ReadableOrWritable< 'a, asn1::SequenceOf<'a, Extension<'a>>, @@ -27,14 +29,14 @@ impl<'a> Extensions<'a> { /// OID, if there are any duplicates. pub fn from_raw_extensions( raw: Option<&RawExtensions<'a>>, - ) -> Result { + ) -> Result { match raw { Some(raw_exts) => { let mut seen_oids = HashSet::new(); for ext in raw_exts.unwrap_read().clone() { if !seen_oids.insert(ext.extn_id.clone()) { - return Err(ext.extn_id); + return Err(DuplicateExtensionsError(ext.extn_id)); } } @@ -311,7 +313,7 @@ mod tests { let der = asn1::write_single(&extensions).unwrap(); let raw = asn1::parse_single(&der).unwrap(); - let extensions: Extensions = Extensions::from_raw_extensions(Some(&raw)).unwrap(); + let extensions: Extensions = Extensions::from_raw_extensions(Some(&raw)).ok().unwrap(); assert!(&extensions.get_extension(&BASIC_CONSTRAINTS_OID).is_some()); assert!(&extensions @@ -335,7 +337,7 @@ mod tests { let der = asn1::write_single(&extensions).unwrap(); let parsed = asn1::parse_single(&der).unwrap(); - let extensions: Extensions = Extensions::from_raw_extensions(Some(&parsed)).unwrap(); + let extensions: Extensions = Extensions::from_raw_extensions(Some(&parsed)).ok().unwrap(); let extension_list: Vec<_> = extensions.iter().collect(); assert_eq!(extension_list.len(), 1); diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index c085ab683820..49b048207f06 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -13,9 +13,10 @@ use cryptography_x509::certificate::Certificate as RawCertificate; use cryptography_x509::common::{AlgorithmParameters, Asn1ReadableOrWritable}; use cryptography_x509::extensions::{ AuthorityKeyIdentifier, BasicConstraints, DisplayText, DistributionPoint, - DistributionPointName, IssuerAlternativeName, KeyUsage, MSCertificateTemplate, NameConstraints, - PolicyConstraints, PolicyInformation, PolicyQualifierInfo, Qualifier, RawExtensions, - SequenceOfAccessDescriptions, SequenceOfSubtrees, UserNotice, + DistributionPointName, DuplicateExtensionsError, IssuerAlternativeName, KeyUsage, + MSCertificateTemplate, NameConstraints, PolicyConstraints, PolicyInformation, + PolicyQualifierInfo, Qualifier, RawExtensions, SequenceOfAccessDescriptions, + SequenceOfSubtrees, UserNotice, }; use cryptography_x509::extensions::{Extension, SubjectAlternativeName}; use cryptography_x509::{common, oid}; @@ -129,18 +130,14 @@ impl Certificate { #[getter] fn issuer<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - Ok( - x509::parse_name(py, &self.raw.borrow_dependent().tbs_cert.issuer) - .map_err(|e| e.add_location(asn1::ParseLocation::Field("issuer")))?, - ) + Ok(x509::parse_name(py, self.raw.borrow_dependent().issuer()) + .map_err(|e| e.add_location(asn1::ParseLocation::Field("issuer")))?) } #[getter] fn subject<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - Ok( - x509::parse_name(py, &self.raw.borrow_dependent().tbs_cert.subject) - .map_err(|e| e.add_location(asn1::ParseLocation::Field("subject")))?, - ) + Ok(x509::parse_name(py, self.raw.borrow_dependent().subject()) + .map_err(|e| e.add_location(asn1::ParseLocation::Field("subject")))?) } #[getter] @@ -160,7 +157,7 @@ impl Certificate { let val = self.raw.borrow_dependent(); let mut tbs_precert = val.tbs_cert.clone(); // Remove the SCT list extension - match val.tbs_cert.extensions() { + match val.extensions() { Ok(extensions) => { let ext_count = extensions .as_raw() @@ -185,10 +182,10 @@ impl Certificate { let result = asn1::write_single(&tbs_precert)?; Ok(pyo3::types::PyBytes::new(py, &result)) } - Err(oid) => { + Err(DuplicateExtensionsError(oid)) => { let oid_obj = oid_to_py_oid(py, &oid)?; Err(exceptions::DuplicateExtension::new_err(( - format!("Duplicate {} extension found", oid), + format!("Duplicate {} extension found", &oid), oid_obj.into_py(py), )) .into()) diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index e38f9b321730..81bf25326ab7 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -6,8 +6,10 @@ use crate::asn1::{oid_to_py_oid, py_oid_to_oid}; use crate::error::{CryptographyError, CryptographyResult}; use crate::{exceptions, x509}; use cryptography_x509::common::{Asn1ReadableOrWritable, AttributeTypeValue, RawTlv}; -use cryptography_x509::extensions::{AccessDescription, Extension, Extensions, RawExtensions}; -use cryptography_x509::name::{GeneralName, Name, OtherName, UnvalidatedIA5String}; +use cryptography_x509::extensions::{ + AccessDescription, DuplicateExtensionsError, Extension, Extensions, RawExtensions, +}; +use cryptography_x509::name::{GeneralName, Name, NameReadable, OtherName, UnvalidatedIA5String}; use pyo3::types::IntoPyDict; use pyo3::{IntoPy, ToPyObject}; @@ -173,11 +175,11 @@ pub(crate) fn encode_access_descriptions<'a>( pub(crate) fn parse_name<'p>( py: pyo3::Python<'p>, - name: &Name<'_>, + name: &NameReadable<'_>, ) -> Result<&'p pyo3::PyAny, CryptographyError> { let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let py_rdns = pyo3::types::PyList::empty(py); - for rdn in name.unwrap_read().clone() { + for rdn in name.clone() { let py_rdn = parse_rdn(py, &rdn)?; py_rdns.append(py_rdn)?; } @@ -272,7 +274,7 @@ pub(crate) fn parse_general_name( .call_method1(pyo3::intern!(py, "_init_without_validation"), (data.0,))? .to_object(py), GeneralName::DirectoryName(data) => { - let py_name = parse_name(py, &data)?; + let py_name = parse_name(py, data.unwrap_read())?; x509_module .call_method1(pyo3::intern!(py, "DirectoryName"), (py_name,))? .to_object(py) @@ -395,10 +397,10 @@ pub(crate) fn parse_and_cache_extensions< let extensions = match Extensions::from_raw_extensions(raw_extensions.as_ref()) { Ok(extensions) => extensions, - Err(oid) => { + Err(DuplicateExtensionsError(oid)) => { let oid_obj = oid_to_py_oid(py, &oid)?; return Err(exceptions::DuplicateExtension::new_err(( - format!("Duplicate {} extension found", oid), + format!("Duplicate {} extension found", &oid), oid_obj.into_py(py), ))); } diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index fbb7b4668bb1..807d3ddc1270 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -240,7 +240,11 @@ impl CertificateRevocationList { fn issuer<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { Ok(x509::parse_name( py, - &self.owned.borrow_dependent().tbs_cert_list.issuer, + self.owned + .borrow_dependent() + .tbs_cert_list + .issuer + .unwrap_read(), )?) } diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index 0df274c3e693..0a0941265216 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -74,7 +74,7 @@ impl CertificateSigningRequest { fn subject<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { Ok(x509::parse_name( py, - &self.raw.borrow_dependent().csr_info.subject, + self.raw.borrow_dependent().csr_info.subject.unwrap_read(), )?) } diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index abb32d526392..49cd67fda8aa 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -147,7 +147,9 @@ impl OCSPResponse { fn responder_name<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let resp = self.requires_successful_response()?; match resp.tbs_response_data.responder_id { - ocsp_resp::ResponderId::ByName(ref name) => Ok(x509::parse_name(py, name)?), + ocsp_resp::ResponderId::ByName(ref name) => { + Ok(x509::parse_name(py, name.unwrap_read())?) + } ocsp_resp::ResponderId::ByKey(_) => Ok(py.None().into_ref(py)), } }