1use std::sync::OnceLock;
8
9use pyo3::prelude::*;
10use pyo3::types::PyBytes;
11
12use synta::traits::Encode;
13use synta::{Decoder, Encoding};
14
15use crate::error::SyntaErr;
16use crate::types::PyObjectIdentifier;
17
18#[pyclass(frozen, name = "DssParms")]
32pub struct PyDssParms {
33 inner: synta_certificate::pkixalgs_types::DssParms,
34}
35
36#[pymethods]
37impl PyDssParms {
38 #[staticmethod]
43 fn from_der(data: &[u8]) -> PyResult<Self> {
44 let mut dec = Decoder::new(data, Encoding::Der);
45 let inner = dec
46 .decode::<synta_certificate::pkixalgs_types::DssParms>()
47 .map_err(SyntaErr)?;
48 Ok(Self { inner })
49 }
50
51 fn to_der<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
53 let mut enc = synta::Encoder::new(Encoding::Der);
54 self.inner.encode(&mut enc).map_err(SyntaErr)?;
55 Ok(PyBytes::new(py, &enc.finish().map_err(SyntaErr)?))
56 }
57
58 #[getter]
60 fn p<'py>(&self, py: Python<'py>) -> Bound<'py, PyBytes> {
61 PyBytes::new(py, self.inner.p.as_bytes())
62 }
63
64 #[getter]
66 fn q<'py>(&self, py: Python<'py>) -> Bound<'py, PyBytes> {
67 PyBytes::new(py, self.inner.q.as_bytes())
68 }
69
70 #[getter]
72 fn g<'py>(&self, py: Python<'py>) -> Bound<'py, PyBytes> {
73 PyBytes::new(py, self.inner.g.as_bytes())
74 }
75
76 fn __repr__(&self) -> String {
77 format!(
78 "DssParms(p=<{} bytes>, q=<{} bytes>, g=<{} bytes>)",
79 self.inner.p.as_bytes().len(),
80 self.inner.q.as_bytes().len(),
81 self.inner.g.as_bytes().len(),
82 )
83 }
84}
85
86#[pyclass(frozen, name = "DssSigValue")]
92pub struct PyDssSigValue {
93 inner: synta_certificate::pkixalgs_types::DssSigValue,
94}
95
96#[pymethods]
97impl PyDssSigValue {
98 #[staticmethod]
100 fn from_der(data: &[u8]) -> PyResult<Self> {
101 let mut dec = Decoder::new(data, Encoding::Der);
102 let inner = dec
103 .decode::<synta_certificate::pkixalgs_types::DssSigValue>()
104 .map_err(SyntaErr)?;
105 Ok(Self { inner })
106 }
107
108 fn to_der<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
110 let mut enc = synta::Encoder::new(Encoding::Der);
111 self.inner.encode(&mut enc).map_err(SyntaErr)?;
112 Ok(PyBytes::new(py, &enc.finish().map_err(SyntaErr)?))
113 }
114
115 #[getter]
117 fn r<'py>(&self, py: Python<'py>) -> Bound<'py, PyBytes> {
118 PyBytes::new(py, self.inner.r.as_bytes())
119 }
120
121 #[getter]
123 fn s<'py>(&self, py: Python<'py>) -> Bound<'py, PyBytes> {
124 PyBytes::new(py, self.inner.s.as_bytes())
125 }
126
127 fn __repr__(&self) -> String {
128 format!(
129 "DssSigValue(r=<{} bytes>, s=<{} bytes>)",
130 self.inner.r.as_bytes().len(),
131 self.inner.s.as_bytes().len(),
132 )
133 }
134}
135
136#[pyclass(frozen, name = "EcdsaSigValue")]
150pub struct PyEcdsaSigValue {
151 inner: synta_certificate::pkixalgs_types::EcdsaSigValue,
152}
153
154#[pymethods]
155impl PyEcdsaSigValue {
156 #[staticmethod]
158 fn from_der(data: &[u8]) -> PyResult<Self> {
159 let mut dec = Decoder::new(data, Encoding::Der);
160 let inner = dec
161 .decode::<synta_certificate::pkixalgs_types::EcdsaSigValue>()
162 .map_err(SyntaErr)?;
163 Ok(Self { inner })
164 }
165
166 fn to_der<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
168 let mut enc = synta::Encoder::new(Encoding::Der);
169 self.inner.encode(&mut enc).map_err(SyntaErr)?;
170 Ok(PyBytes::new(py, &enc.finish().map_err(SyntaErr)?))
171 }
172
173 #[getter]
175 fn r<'py>(&self, py: Python<'py>) -> Bound<'py, PyBytes> {
176 PyBytes::new(py, self.inner.r.as_bytes())
177 }
178
179 #[getter]
181 fn s<'py>(&self, py: Python<'py>) -> Bound<'py, PyBytes> {
182 PyBytes::new(py, self.inner.s.as_bytes())
183 }
184
185 fn __repr__(&self) -> String {
186 format!(
187 "EcdsaSigValue(r=<{} bytes>, s=<{} bytes>)",
188 self.inner.r.as_bytes().len(),
189 self.inner.s.as_bytes().len(),
190 )
191 }
192}
193
194#[pyclass(frozen, name = "ECParameters")]
214pub struct PyECParameters {
215 _data: Py<PyBytes>,
216 raw: &'static [u8],
217 inner: OnceLock<Box<synta_certificate::pkixalgs_types::ECParameters<'static>>>,
218}
219
220impl PyECParameters {
221 fn params(&self) -> PyResult<&synta_certificate::pkixalgs_types::ECParameters<'static>> {
222 if let Some(v) = self.inner.get() {
223 return Ok(v.as_ref());
224 }
225 let mut dec = Decoder::new(self.raw, Encoding::Der);
226 let decoded = dec
227 .decode::<synta_certificate::pkixalgs_types::ECParameters<'_>>()
228 .map_err(SyntaErr)?;
229 let decoded: synta_certificate::pkixalgs_types::ECParameters<'static> =
231 unsafe { std::mem::transmute(decoded) };
232 let _ = self.inner.set(Box::new(decoded));
233 Ok(self.inner.get().unwrap().as_ref())
234 }
235}
236
237#[pymethods]
238impl PyECParameters {
239 #[staticmethod]
241 fn from_der(py: Python<'_>, data: Bound<'_, PyBytes>) -> PyResult<Self> {
242 let py_bytes = data.unbind();
243 {
245 let raw = py_bytes.as_bytes(py);
246 Decoder::new(raw, Encoding::Der)
247 .decode::<synta_certificate::pkixalgs_types::ECParameters<'_>>()
248 .map_err(SyntaErr)?;
249 }
250 let raw: &'static [u8] = unsafe { std::mem::transmute(py_bytes.as_bytes(py)) };
251 Ok(Self {
252 _data: py_bytes,
253 raw,
254 inner: OnceLock::new(),
255 })
256 }
257
258 fn to_der<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
260 let mut enc = synta::Encoder::new(Encoding::Der);
261 self.params()?.encode(&mut enc).map_err(SyntaErr)?;
262 Ok(PyBytes::new(py, &enc.finish().map_err(SyntaErr)?))
263 }
264
265 #[getter]
268 fn arm(&self) -> PyResult<&'static str> {
269 use synta_certificate::pkixalgs_types::ECParameters::*;
270 Ok(match self.params()? {
271 NamedCurve(_) => "namedCurve",
272 EcParameters(_) => "ecParameters",
273 ImplicitlyCA(_) => "implicitlyCA",
274 })
275 }
276
277 #[getter]
279 fn named_curve_oid(&self, py: Python<'_>) -> PyResult<Option<Py<PyObjectIdentifier>>> {
280 use synta_certificate::pkixalgs_types::ECParameters::*;
281 match self.params()? {
282 NamedCurve(oid) => {
283 let obj = Py::new(py, PyObjectIdentifier::from_oid(oid.clone()))?;
284 Ok(Some(obj))
285 }
286 _ => Ok(None),
287 }
288 }
289
290 fn __repr__(&self) -> PyResult<String> {
291 Ok(format!("ECParameters(arm={})", self.arm()?))
292 }
293}
294
295pub(super) fn register_pkixalgs_submodule(parent: &Bound<'_, PyModule>) -> PyResult<()> {
299 let py = parent.py();
300 let m = PyModule::new(py, "pkixalgs")?;
301
302 m.add_class::<PyDssParms>()?;
303 m.add_class::<PyDssSigValue>()?;
304 m.add_class::<PyEcdsaSigValue>()?;
305 m.add_class::<PyECParameters>()?;
306
307 m.add(
309 "ID_DSA",
310 super::oid_const(py, synta_certificate::pkixalgs_types::ID_DSA),
311 )?;
312 m.add(
313 "ID_DSA_WITH_SHA1",
314 super::oid_const(py, synta_certificate::pkixalgs_types::ID_DSA_WITH_SHA1),
315 )?;
316 m.add(
317 "DHPUBLICNUMBER",
318 super::oid_const(py, synta_certificate::pkixalgs_types::DHPUBLICNUMBER),
319 )?;
320
321 m.add(
323 "ID_EC_PUBLIC_KEY",
324 super::oid_const(py, synta_certificate::pkixalgs_types::ID_EC_PUBLIC_KEY),
325 )?;
326 m.add(
327 "ECDSA_WITH_SHA1",
328 super::oid_const(py, synta_certificate::pkixalgs_types::ECDSA_WITH_SHA1),
329 )?;
330 m.add(
331 "ECDSA_WITH_SHA256",
332 super::oid_const(py, synta_certificate::pkixalgs_types::ECDSA_WITH_SHA256),
333 )?;
334 m.add(
335 "ECDSA_WITH_SHA384",
336 super::oid_const(py, synta_certificate::pkixalgs_types::ECDSA_WITH_SHA384),
337 )?;
338 m.add(
339 "ECDSA_WITH_SHA512",
340 super::oid_const(py, synta_certificate::pkixalgs_types::ECDSA_WITH_SHA512),
341 )?;
342
343 m.add(
345 "PRIME192V1",
346 super::oid_const(py, synta_certificate::pkixalgs_types::PRIME192V1),
347 )?;
348 m.add(
349 "PRIME256V1",
350 super::oid_const(py, synta_certificate::pkixalgs_types::PRIME256V1),
351 )?;
352 m.add(
353 "SECP224R1",
354 super::oid_const(py, synta_certificate::pkixalgs_types::SECP224R1),
355 )?;
356 m.add(
357 "SECP384R1",
358 super::oid_const(py, synta_certificate::pkixalgs_types::SECP384R1),
359 )?;
360 m.add(
361 "SECP521R1",
362 super::oid_const(py, synta_certificate::pkixalgs_types::SECP521R1),
363 )?;
364
365 crate::install_submodule(
366 parent,
367 &m,
368 "synta.pkixalgs",
369 Some(concat!(
370 "synta.pkixalgs — RFC 3279 algorithm parameter types.\n\n",
371 "Provides DssParms, DssSigValue, EcdsaSigValue, and ECParameters\n",
372 "for decoding DSA/DH domain parameters and DSA/ECDSA signature values,\n",
373 "along with OID constants for DSA, DH, EC, and named-curve algorithms.",
374 )),
375 )
376}