_synta/certificate/
pkcs8.rs1use std::sync::OnceLock;
7
8use pyo3::prelude::*;
9use pyo3::types::PyBytes;
10
11use synta::{Decoder, Encoding};
12
13use crate::error::SyntaErr;
14use crate::types::PyObjectIdentifier;
15
16#[pyclass(frozen, name = "OneAsymmetricKey")]
40pub struct PyOneAsymmetricKey {
41 _data: Py<PyBytes>,
42 raw: &'static [u8],
43 inner: OnceLock<Box<synta_certificate::pkcs8_types::OneAsymmetricKey<'static>>>,
44 alg_oid_cache: OnceLock<Py<PyObjectIdentifier>>,
46}
47
48impl PyOneAsymmetricKey {
49 fn key(&self) -> PyResult<&synta_certificate::pkcs8_types::OneAsymmetricKey<'static>> {
50 if let Some(v) = self.inner.get() {
51 return Ok(v.as_ref());
52 }
53 let mut dec = Decoder::new(self.raw, Encoding::Der);
54 let decoded = dec
55 .decode::<synta_certificate::pkcs8_types::OneAsymmetricKey<'static>>()
56 .map_err(SyntaErr)?;
57 let _ = self.inner.set(Box::new(decoded));
58 Ok(self.inner.get().unwrap().as_ref())
59 }
60}
61
62#[pymethods]
63impl PyOneAsymmetricKey {
64 #[staticmethod]
70 fn from_der(py: Python<'_>, data: Bound<'_, PyBytes>) -> PyResult<Self> {
71 let py_bytes = data.unbind();
72 {
73 let raw = py_bytes.as_bytes(py);
74 Decoder::new(raw, Encoding::Der)
75 .decode::<synta_certificate::pkcs8_types::OneAsymmetricKey<'_>>()
76 .map_err(SyntaErr)?;
77 }
78 let raw: &'static [u8] = unsafe {
79 let s = py_bytes.bind(py).as_bytes();
80 std::slice::from_raw_parts(s.as_ptr(), s.len())
81 };
82 Ok(Self {
83 _data: py_bytes,
84 raw,
85 inner: OnceLock::new(),
86 alg_oid_cache: OnceLock::new(),
87 })
88 }
89
90 fn to_der<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
94 Ok(PyBytes::new(py, &self.key()?.to_der().map_err(SyntaErr)?))
95 }
96
97 #[getter]
99 fn version(&self) -> PyResult<i64> {
100 Ok(self.key()?.version.as_i64().map_err(SyntaErr)?)
101 }
102
103 #[getter]
108 fn private_key_algorithm<'py>(
109 &self,
110 py: Python<'py>,
111 ) -> PyResult<Bound<'py, PyObjectIdentifier>> {
112 if let Some(c) = self.alg_oid_cache.get() {
113 return Ok(c.clone_ref(py).into_bound(py));
114 }
115 let k = self.key()?;
116 let oid_obj = Py::new(
117 py,
118 PyObjectIdentifier::from_oid(k.private_key_algorithm.algorithm.clone()),
119 )?;
120 let _ = self.alg_oid_cache.set(oid_obj.clone_ref(py));
121 Ok(oid_obj.into_bound(py))
122 }
123
124 #[getter]
130 fn private_key<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
131 Ok(PyBytes::new(py, self.key()?.private_key.as_bytes()))
132 }
133
134 #[getter]
139 fn attributes_der<'py>(&self, py: Python<'py>) -> PyResult<Option<Bound<'py, PyBytes>>> {
140 Ok(self
141 .key()?
142 .attributes
143 .as_ref()
144 .map(|a| PyBytes::new(py, a.as_bytes())))
145 }
146
147 #[getter]
151 fn public_key_der<'py>(&self, py: Python<'py>) -> PyResult<Option<Bound<'py, PyBytes>>> {
152 Ok(self
153 .key()?
154 .public_key
155 .as_ref()
156 .map(|pk| PyBytes::new(py, pk.as_bytes())))
157 }
158
159 #[getter]
164 fn alg_parameters_der<'py>(&self, py: Python<'py>) -> PyResult<Option<Bound<'py, PyBytes>>> {
165 let k = self.key()?;
166 Ok(k.private_key_algorithm.parameters.as_ref().map(|p| {
167 let mut enc = synta::Encoder::new(Encoding::Der);
168 if enc.encode(p).is_err() {
169 return PyBytes::new(py, &[]);
170 }
171 PyBytes::new(py, &enc.finish().unwrap_or_default())
172 }))
173 }
174
175 fn __repr__(&self, py: Python<'_>) -> PyResult<String> {
176 let alg = self.private_key_algorithm(py)?;
177 Ok(format!(
178 "OneAsymmetricKey(version={}, algorithm={})",
179 self.version()?,
180 alg.borrow().inner,
181 ))
182 }
183}
184
185pub(super) fn register_pkcs8_submodule(parent: &Bound<'_, PyModule>) -> PyResult<()> {
189 let py = parent.py();
190 let m = PyModule::new(py, "pkcs8")?;
191
192 m.add_class::<PyOneAsymmetricKey>()?;
193
194 m.add("PrivateKeyInfo", m.getattr("OneAsymmetricKey")?)?;
197
198 crate::install_submodule(
199 parent,
200 &m,
201 "synta.pkcs8",
202 Some(concat!(
203 "synta.pkcs8 — PKCS #8 / RFC 5958 private key structures.\n\n",
204 "Provides OneAsymmetricKey (PrivateKeyInfo) for parsing DER-encoded\n",
205 "private key envelopes produced by OpenSSL and other PKI tools.",
206 )),
207 )
208}