summaryrefslogtreecommitdiff
path: root/src/rust
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2021-10-30 17:40:28 -0400
committerGitHub <noreply@github.com>2021-10-31 05:40:28 +0800
commit9275fd07e37688ed7fb301852d899d99a5ac7fc3 (patch)
treedcbdb35cb0754be35333f5fc25b82ee45b1d5cff /src/rust
parentc4f73412219d1db740faa743e155e58f626ec613 (diff)
downloadcryptography-9275fd07e37688ed7fb301852d899d99a5ac7fc3.tar.gz
Convert CRL creation to Rust (#6496)
* Convert CRL creation to Rust * fixes * small reflows * Delete all teh code * flake8
Diffstat (limited to 'src/rust')
-rw-r--r--src/rust/src/x509/certificate.rs2
-rw-r--r--src/rust/src/x509/crl.rs222
2 files changed, 133 insertions, 91 deletions
diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs
index 7557d951a..d9e53cf16 100644
--- a/src/rust/src/x509/certificate.rs
+++ b/src/rust/src/x509/certificate.rs
@@ -990,7 +990,7 @@ pub fn parse_cert_ext<'p>(
}
}
-fn time_from_py(val: &pyo3::PyAny) -> pyo3::PyResult<x509::Time> {
+pub(crate) fn time_from_py(val: &pyo3::PyAny) -> pyo3::PyResult<x509::Time> {
let dt = x509::py_to_chrono(val)?;
if dt.year() >= 2050 {
Ok(x509::Time::GeneralizedTime(asn1::GeneralizedTime::new(dt)))
diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs
index c253c686b..cbcd127b2 100644
--- a/src/rust/src/x509/crl.rs
+++ b/src/rust/src/x509/crl.rs
@@ -5,7 +5,7 @@
use crate::asn1::{big_asn1_uint_to_py, py_uint_to_big_endian_bytes, PyAsn1Error, PyAsn1Result};
use crate::x509;
use crate::x509::certificate;
-use pyo3::ToPyObject;
+use pyo3::{PyNativeType, ToPyObject};
use std::convert::TryInto;
use std::sync::Arc;
@@ -94,7 +94,7 @@ impl CertificateRevocationList {
.tbs_cert_list
.revoked_certificates
.as_ref()
- .map_or(0, |v| v.len())
+ .map_or(0, |v| v.unwrap_read().len())
}
}
@@ -128,7 +128,7 @@ impl pyo3::PyMappingProtocol for CertificateRevocationList {
self.raw.with(|val| {
val.revoked_certs.get_or_init(py, || {
match &val.value.tbs_cert_list.revoked_certificates {
- Some(c) => c.clone().collect(),
+ Some(c) => c.unwrap_read().clone().collect(),
None => vec![],
}
});
@@ -347,8 +347,8 @@ impl CertificateRevocationList {
) -> pyo3::PyResult<Option<RevokedCertificate>> {
let serial_bytes = py_uint_to_big_endian_bytes(py, serial)?;
let owned = OwnedRawRevokedCertificate::try_new(Arc::clone(&self.raw), |v| {
- let certs = match v.borrow_value().tbs_cert_list.revoked_certificates.clone() {
- Some(certs) => certs,
+ let certs = match &v.borrow_value().tbs_cert_list.revoked_certificates {
+ Some(certs) => certs.unwrap_read().clone(),
None => return Err(()),
};
@@ -408,7 +408,13 @@ impl pyo3::PyIterProtocol<'_> for CertificateRevocationList {
fn __iter__(slf: pyo3::PyRef<'p, Self>) -> CRLIterator {
CRLIterator {
contents: OwnedCRLIteratorData::try_new(Arc::clone(&slf.raw), |v| {
- Ok::<_, ()>(v.borrow_value().tbs_cert_list.revoked_certificates.clone())
+ Ok::<_, ()>(
+ v.borrow_value()
+ .tbs_cert_list
+ .revoked_certificates
+ .as_ref()
+ .map(|v| v.unwrap_read().clone()),
+ )
})
.unwrap(),
}
@@ -493,6 +499,14 @@ struct RawCertificateRevocationList<'a> {
signature_value: asn1::BitString<'a>,
}
+type RevokedCertificates<'a> = Option<
+ x509::Asn1ReadableOrWritable<
+ 'a,
+ asn1::SequenceOf<'a, RawRevokedCertificate<'a>>,
+ asn1::SequenceOfWriter<'a, RawRevokedCertificate<'a>, Vec<RawRevokedCertificate<'a>>>,
+ >,
+>;
+
#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash)]
struct TBSCertList<'a> {
version: Option<u8>,
@@ -500,7 +514,7 @@ struct TBSCertList<'a> {
issuer: x509::Name<'a>,
this_update: x509::Time,
next_update: Option<x509::Time>,
- revoked_certificates: Option<asn1::SequenceOf<'a, RawRevokedCertificate<'a>>>,
+ revoked_certificates: RevokedCertificates<'a>,
#[explicit(0)]
crl_extensions: Option<x509::Extensions<'a>>,
}
@@ -630,44 +644,35 @@ pub fn parse_crl_entry_ext<'p>(
}
}
-#[pyo3::prelude::pyfunction]
-fn encode_crl_extension<'p>(
- py: pyo3::Python<'p>,
+fn encode_crl_extension(
+ oid: &asn1::ObjectIdentifier<'_>,
ext: &pyo3::PyAny,
-) -> pyo3::PyResult<&'p pyo3::PyAny> {
- let oid = asn1::ObjectIdentifier::from_string(
- ext.getattr("oid")?
- .getattr("dotted_string")?
- .extract::<&str>()?,
- )
- .unwrap();
- if oid == *CRL_NUMBER_OID || oid == *DELTA_CRL_INDICATOR_OID {
+) -> pyo3::PyResult<Option<Vec<u8>>> {
+ if oid == &*CRL_NUMBER_OID || oid == &*DELTA_CRL_INDICATOR_OID {
let intval = ext
- .getattr("value")?
.getattr("crl_number")?
.downcast::<pyo3::types::PyLong>()?;
- let bytes = py_uint_to_big_endian_bytes(py, intval)?;
- let result = asn1::write_single(&asn1::BigUint::new(bytes).unwrap());
- Ok(pyo3::types::PyBytes::new(py, &result))
- } else if oid == *ISSUING_DISTRIBUTION_POINT_OID {
- let py_idp = ext.getattr("value")?;
-
- let only_some_reasons = if py_idp.getattr("only_some_reasons")?.is_true()? {
- let py_reasons = py_idp.getattr("only_some_reasons")?;
- let reasons = certificate::encode_distribution_point_reasons(py, py_reasons)?;
+ let bytes = py_uint_to_big_endian_bytes(ext.py(), intval)?;
+ Ok(Some(asn1::write_single(
+ &asn1::BigUint::new(bytes).unwrap(),
+ )))
+ } else if oid == &*ISSUING_DISTRIBUTION_POINT_OID {
+ let only_some_reasons = if ext.getattr("only_some_reasons")?.is_true()? {
+ let py_reasons = ext.getattr("only_some_reasons")?;
+ let reasons = certificate::encode_distribution_point_reasons(ext.py(), py_reasons)?;
Some(x509::Asn1ReadableOrWritable::new_write(reasons))
} else {
None
};
- let distribution_point = if py_idp.getattr("full_name")?.is_true()? {
- let gns = x509::common::encode_general_names(py, py_idp.getattr("full_name")?)?;
+ let distribution_point = if ext.getattr("full_name")?.is_true()? {
+ let gns = x509::common::encode_general_names(ext.py(), ext.getattr("full_name")?)?;
Some(certificate::DistributionPointName::FullName(
x509::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new(gns)),
))
- } else if py_idp.getattr("relative_name")?.is_true()? {
+ } else if ext.getattr("relative_name")?.is_true()? {
let mut name_entries = vec![];
- for py_name_entry in py_idp.getattr("relative_name")?.iter()? {
- name_entries.push(x509::common::encode_name_entry(py, py_name_entry?)?);
+ for py_name_entry in ext.getattr("relative_name")?.iter()? {
+ name_entries.push(x509::common::encode_name_entry(ext.py(), py_name_entry?)?);
}
Some(certificate::DistributionPointName::NameRelativeToCRLIssuer(
x509::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new(name_entries)),
@@ -678,82 +683,119 @@ fn encode_crl_extension<'p>(
let idp = IssuingDistributionPoint {
distribution_point,
- indirect_crl: py_idp.getattr("indirect_crl")?.extract()?,
- only_contains_attribute_certs: py_idp
+ indirect_crl: ext.getattr("indirect_crl")?.extract()?,
+ only_contains_attribute_certs: ext
.getattr("only_contains_attribute_certs")?
.extract()?,
- only_contains_ca_certs: py_idp.getattr("only_contains_ca_certs")?.extract()?,
- only_contains_user_certs: py_idp.getattr("only_contains_user_certs")?.extract()?,
+ only_contains_ca_certs: ext.getattr("only_contains_ca_certs")?.extract()?,
+ only_contains_user_certs: ext.getattr("only_contains_user_certs")?.extract()?,
only_some_reasons,
};
- let result = asn1::write_single(&idp);
- Ok(pyo3::types::PyBytes::new(py, &result))
- } else if oid == *FRESHEST_CRL_OID {
- let dps = certificate::encode_distribution_points(py, ext.getattr("value")?)?;
- let result = asn1::write_single(&asn1::SequenceOfWriter::new(dps));
- Ok(pyo3::types::PyBytes::new(py, &result))
- } else if oid == *AUTHORITY_INFORMATION_ACCESS_OID {
- let py_ads = ext.getattr("value")?;
- let ads = x509::common::encode_access_descriptions(py, py_ads)?;
- let result = asn1::write_single(&ads);
- Ok(pyo3::types::PyBytes::new(py, &result))
- } else if oid == *ISSUER_ALTERNATIVE_NAME_OID {
- let gns = x509::common::encode_general_names(py, ext.getattr("value")?)?;
- let result = asn1::write_single(&asn1::SequenceOfWriter::new(gns));
- Ok(pyo3::types::PyBytes::new(py, &result))
- } else if oid == *AUTHORITY_KEY_IDENTIFIER_OID {
- let aki = x509::certificate::encode_authority_key_identifier(py, ext.getattr("value")?)?;
- let result = asn1::write_single(&aki);
- Ok(pyo3::types::PyBytes::new(py, &result))
+ Ok(Some(asn1::write_single(&idp)))
+ } else if oid == &*FRESHEST_CRL_OID {
+ let dps = certificate::encode_distribution_points(ext.py(), ext)?;
+ Ok(Some(asn1::write_single(&asn1::SequenceOfWriter::new(dps))))
+ } else if oid == &*AUTHORITY_INFORMATION_ACCESS_OID {
+ let ads = x509::common::encode_access_descriptions(ext.py(), ext)?;
+ Ok(Some(asn1::write_single(&ads)))
+ } else if oid == &*ISSUER_ALTERNATIVE_NAME_OID {
+ let gns = x509::common::encode_general_names(ext.py(), ext)?;
+ Ok(Some(asn1::write_single(&asn1::SequenceOfWriter::new(gns))))
+ } else if oid == &*AUTHORITY_KEY_IDENTIFIER_OID {
+ let aki = x509::certificate::encode_authority_key_identifier(ext.py(), ext)?;
+ Ok(Some(asn1::write_single(&aki)))
} else {
- Err(pyo3::exceptions::PyNotImplementedError::new_err(format!(
- "Extension not supported: {}",
- oid
- )))
+ Ok(None)
}
}
-#[pyo3::prelude::pyfunction]
-fn encode_crl_entry_extension<'p>(
- py: pyo3::Python<'p>,
+fn encode_crl_entry_extension(
+ oid: &asn1::ObjectIdentifier<'_>,
ext: &pyo3::PyAny,
-) -> pyo3::PyResult<&'p pyo3::PyAny> {
- let oid = asn1::ObjectIdentifier::from_string(
- ext.getattr("oid")?
- .getattr("dotted_string")?
- .extract::<&str>()?,
- )
- .unwrap();
-
- if oid == *CRL_REASON_OID {
- let value = py
+) -> pyo3::PyResult<Option<Vec<u8>>> {
+ if oid == &*CRL_REASON_OID {
+ let value = ext
+ .py()
.import("cryptography.hazmat.backends.openssl.decode_asn1")?
.getattr("_CRL_ENTRY_REASON_ENUM_TO_CODE")?
- .get_item(ext.getattr("value")?.getattr("reason")?)?
+ .get_item(ext.getattr("reason")?)?
.extract::<u32>()?;
- let result = asn1::write_single(&asn1::Enumerated::new(value));
- Ok(pyo3::types::PyBytes::new(py, &result))
- } else if oid == *CERTIFICATE_ISSUER_OID {
- let gns = x509::common::encode_general_names(py, ext.getattr("value")?)?;
- let result = asn1::write_single(&asn1::SequenceOfWriter::new(gns));
- Ok(pyo3::types::PyBytes::new(py, &result))
- } else if oid == *INVALIDITY_DATE_OID {
- let chrono_dt = x509::py_to_chrono(ext.getattr("value")?.getattr("invalidity_date")?)?;
- let result = asn1::write_single(&asn1::GeneralizedTime::new(chrono_dt));
- Ok(pyo3::types::PyBytes::new(py, &result))
+ Ok(Some(asn1::write_single(&asn1::Enumerated::new(value))))
+ } else if oid == &*CERTIFICATE_ISSUER_OID {
+ let gns = x509::common::encode_general_names(ext.py(), ext)?;
+ Ok(Some(asn1::write_single(&asn1::SequenceOfWriter::new(gns))))
+ } else if oid == &*INVALIDITY_DATE_OID {
+ let chrono_dt = x509::py_to_chrono(ext.getattr("invalidity_date")?)?;
+ Ok(Some(asn1::write_single(&asn1::GeneralizedTime::new(
+ chrono_dt,
+ ))))
} else {
- Err(pyo3::exceptions::PyNotImplementedError::new_err(format!(
- "Extension not supported: {}",
- oid,
- )))
+ Ok(None)
}
}
+#[pyo3::prelude::pyfunction]
+fn create_x509_crl(
+ py: pyo3::Python<'_>,
+ builder: &pyo3::PyAny,
+ private_key: &pyo3::PyAny,
+ hash_algorithm: &pyo3::PyAny,
+) -> PyAsn1Result<CertificateRevocationList> {
+ let sigalg = x509::sign::compute_signature_algorithm(py, private_key, hash_algorithm)?;
+
+ let mut revoked_certs = vec![];
+ for py_revoked_cert in builder.getattr("_revoked_certificates")?.iter()? {
+ let py_revoked_cert = py_revoked_cert?;
+ let serial_number = py_revoked_cert.getattr("serial_number")?.extract()?;
+ let py_revocation_date = py_revoked_cert.getattr("revocation_date")?;
+ revoked_certs.push(RawRevokedCertificate {
+ user_certificate: asn1::BigUint::new(py_uint_to_big_endian_bytes(py, serial_number)?)
+ .unwrap(),
+ revocation_date: x509::certificate::time_from_py(py_revocation_date)?,
+ crl_entry_extensions: x509::common::encode_extensions(
+ py,
+ py_revoked_cert.getattr("extensions")?,
+ encode_crl_entry_extension,
+ )?,
+ });
+ }
+
+ let py_next_update = builder.getattr("_next_update")?;
+ let tbs_cert_list = TBSCertList {
+ version: Some(1),
+ signature: sigalg.clone(),
+ issuer: x509::common::encode_name(py, builder.getattr("_issuer_name")?)?,
+ this_update: x509::certificate::time_from_py(builder.getattr("_last_update")?)?,
+ next_update: Some(x509::certificate::time_from_py(py_next_update)?),
+ revoked_certificates: if revoked_certs.is_empty() {
+ None
+ } else {
+ Some(x509::Asn1ReadableOrWritable::new_write(
+ asn1::SequenceOfWriter::new(revoked_certs),
+ ))
+ },
+ crl_extensions: x509::common::encode_extensions(
+ py,
+ builder.getattr("_extensions")?,
+ encode_crl_extension,
+ )?,
+ };
+
+ let tbs_bytes = asn1::write_single(&tbs_cert_list);
+ let signature = x509::sign::sign_data(py, private_key, hash_algorithm, &tbs_bytes)?;
+ let data = asn1::write_single(&RawCertificateRevocationList {
+ tbs_cert_list,
+ signature_algorithm: sigalg,
+ signature_value: asn1::BitString::new(signature, 0).unwrap(),
+ });
+ // TODO: extra copy as we round-trip through a slice
+ load_der_x509_crl(py, &data)
+}
+
pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> {
module.add_wrapped(pyo3::wrap_pyfunction!(load_der_x509_crl))?;
module.add_wrapped(pyo3::wrap_pyfunction!(load_pem_x509_crl))?;
- module.add_wrapped(pyo3::wrap_pyfunction!(encode_crl_extension))?;
- module.add_wrapped(pyo3::wrap_pyfunction!(encode_crl_entry_extension))?;
+ module.add_wrapped(pyo3::wrap_pyfunction!(create_x509_crl))?;
module.add_class::<CertificateRevocationList>()?;
module.add_class::<RevokedCertificate>()?;