use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3::types::PyBytes;
use synta::traits::{Decode, Encode};
use super::proof::PyHashAlgorithm;
#[pyfunction]
pub fn extract_leaf_index(serial: u64) -> u64 {
serial & 0xFFFF_FFFF_FFFF
}
#[pyfunction]
pub fn extract_log_number(serial: u64) -> u64 {
serial >> 48
}
#[pyfunction]
pub fn build_mtc_ca_extension<'py>(
py: Python<'py>,
hash_alg: &PyHashAlgorithm,
sig_alg_der: &[u8],
min_serial: u64,
) -> PyResult<(Bound<'py, PyBytes>, bool)> {
use synta_certificate::AlgorithmIdentifier;
let mut dec = synta::Decoder::new(sig_alg_der, synta::Encoding::Der);
let sig_alg = AlgorithmIdentifier::decode(&mut dec)
.map_err(|e| PyValueError::new_err(format!("invalid AlgorithmIdentifier DER: {e}")))?;
let (der, critical) = synta_mtc::builder::ca_extension::build_mtc_ca_extension_from_hash(
hash_alg.inner,
&sig_alg,
min_serial,
)
.map_err(|e| PyValueError::new_err(e.to_string()))?;
Ok((PyBytes::new(py, &der), critical))
}
#[pyfunction]
#[allow(clippy::type_complexity)]
pub fn parse_mtc_ca_extension<'py>(
py: Python<'py>,
cert_der: &[u8],
) -> PyResult<Option<(Py<PyHashAlgorithm>, Bound<'py, PyBytes>, u64)>> {
use synta::ObjectIdentifier;
use synta_mtc::builder::ca_extension::parse_mtc_ca_extension as rust_parse;
use synta_mtc::crypto::hash::HashAlgorithm;
let parsed = rust_parse(cert_der).map_err(|e| PyValueError::new_err(e.to_string()))?;
match parsed {
None => Ok(None),
Some(ext) => {
let hash_alg =
HashAlgorithm::from_oid_components(&ext.log_hash_oid).ok_or_else(|| {
let oid = ObjectIdentifier::new(&ext.log_hash_oid)
.map(|o| o.to_string())
.unwrap_or_else(|_| format!("{:?}", ext.log_hash_oid));
PyValueError::new_err(format!("unknown hash algorithm OID: {oid}"))
})?;
let py_hash_alg = Py::new(py, PyHashAlgorithm { inner: hash_alg })?;
let sig_oid = ObjectIdentifier::new(&ext.sig_alg_oid).map_err(|e| {
PyValueError::new_err(format!("invalid sig_alg OID components: {e}"))
})?;
let sig_alg = synta_certificate::AlgorithmIdentifier {
algorithm: sig_oid,
parameters: None,
};
let mut enc = synta::Encoder::new(synta::Encoding::Der);
sig_alg
.encode(&mut enc)
.map_err(|e| PyValueError::new_err(format!("encode sig_alg: {e}")))?;
let sig_alg_der = enc
.finish()
.map_err(|e| PyValueError::new_err(format!("finish sig_alg encoding: {e}")))?;
Ok(Some((
py_hash_alg,
PyBytes::new(py, &sig_alg_der),
ext.min_serial,
)))
}
}
}