Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Certificate: useful APIs #9300

Merged
merged 15 commits into from
Jul 26, 2023
22 changes: 21 additions & 1 deletion src/rust/cryptography-x509/src/certificate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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<Extensions<'_>, DuplicateExtensionsError> {
self.tbs_cert.extensions()
}
}

#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Eq, Clone)]
pub struct TbsCertificate<'a> {
#[explicit(0)]
Expand All @@ -36,7 +56,7 @@ pub struct TbsCertificate<'a> {
}

impl TbsCertificate<'_> {
pub fn extensions(&self) -> Result<Extensions<'_>, asn1::ObjectIdentifier> {
pub fn extensions(&self) -> Result<Extensions<'_>, DuplicateExtensionsError> {
Extensions::from_raw_extensions(self.raw_extensions.as_ref())
}
}
Expand Down
7 changes: 5 additions & 2 deletions src/rust/cryptography-x509/src/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ use crate::common;
use crate::crl;
use crate::name;

#[derive(Debug)]
pub struct DuplicateExtensionsError(pub asn1::ObjectIdentifier);

pub type RawExtensions<'a> = common::Asn1ReadableOrWritable<
'a,
asn1::SequenceOf<'a, Extension<'a>>,
Expand All @@ -27,14 +30,14 @@ impl<'a> Extensions<'a> {
/// OID, if there are any duplicates.
pub fn from_raw_extensions(
raw: Option<&RawExtensions<'a>>,
) -> Result<Self, asn1::ObjectIdentifier> {
) -> Result<Self, DuplicateExtensionsError> {
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));
}
}

Expand Down
25 changes: 11 additions & 14 deletions src/rust/src/x509/certificate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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]
Expand All @@ -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()
Expand All @@ -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())
Expand Down
16 changes: 9 additions & 7 deletions src/rust/src/x509/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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)?;
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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),
)));
}
Expand Down
6 changes: 5 additions & 1 deletion src/rust/src/x509/crl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
)?)
}

Expand Down
2 changes: 1 addition & 1 deletion src/rust/src/x509/csr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
)?)
}

Expand Down
4 changes: 3 additions & 1 deletion src/rust/src/x509/ocsp_resp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
}
}
Expand Down
Loading