Skip to main content

synta/traits/
convenience.rs

1//! Convenience traits for encoding/decoding without explicit Encoder/Decoder construction
2//!
3//! These traits provide `to_der()`, `to_ber()`, `from_der()`, and `from_ber()`
4//! methods on any type that implements [`Encode`] or [`Decode`], eliminating
5//! boilerplate for the common single-value encode/decode case.
6//!
7//! Both traits are blanket-implemented, so they are automatically available on
8//! all conforming types — including codegen-generated structs.
9//!
10//! # `from_der` / `from_ber` and lifetimes
11//!
12//! [`FromDer`] is blanket-implemented for `T: for<'a> Decode<'a>` — that is,
13//! types that own all their data after decoding (e.g. `Integer`, `Boolean`,
14//! `OctetString`, `ObjectIdentifier`, codegen structs using owned string
15//! types).  Zero-copy borrowed types such as `OctetStringRef<'a>` cannot
16//! satisfy the HRTB bound; use [`Decoder`] directly for those.
17//!
18//! [`Decoder`]: crate::Decoder
19
20#[cfg(not(feature = "std"))]
21use alloc::vec::Vec;
22
23use crate::der::decoder::Decoder;
24use crate::der::encoder::Encoder;
25use crate::error::{Error, Result};
26use crate::traits::decode::Decode;
27use crate::traits::encode::Encode;
28use crate::Encoding;
29
30/// Encode a value to DER or BER bytes without constructing an [`Encoder`] manually.
31///
32/// Blanket-implemented for all types that implement [`Encode`].
33///
34/// # Examples
35///
36/// ```
37/// use synta::{Integer, ToDer};
38///
39/// let n = Integer::from_i64(42);
40/// let der = n.to_der().unwrap();
41/// assert_eq!(der, &[0x02, 0x01, 0x2A]);
42/// ```
43pub trait ToDer: Encode + Sized {
44    /// Encode `self` to DER and return the bytes.
45    fn to_der(&self) -> Result<Vec<u8>> {
46        let mut enc = Encoder::new(Encoding::Der);
47        enc.encode(self)?;
48        enc.finish()
49    }
50
51    /// Encode `self` to BER and return the bytes.
52    fn to_ber(&self) -> Result<Vec<u8>> {
53        let mut enc = Encoder::new(Encoding::Ber);
54        enc.encode(self)?;
55        enc.finish()
56    }
57}
58
59/// Blanket implementation of [`ToDer`] for all types that implement [`Encode`].
60///
61/// This impl is what makes `to_der()` and `to_ber()` available on every
62/// ASN.1 type in this crate — including types produced by `#[derive(Asn1Sequence)]`
63/// and friends — without any additional boilerplate.
64impl<T: Encode> ToDer for T {}
65
66/// Decode a value from a DER or BER byte slice without constructing a [`Decoder`] manually.
67///
68/// Blanket-implemented for all owned types `T` that satisfy `for<'a> Decode<'a>`.
69/// Zero-copy borrowed types (e.g. `OctetStringRef<'a>`) do not satisfy this
70/// bound; use [`Decoder`] directly for those.
71///
72/// Both methods require that the input contains **exactly** one TLV — trailing
73/// bytes cause [`Error::TrailingData`].
74///
75/// # Examples
76///
77/// ```
78/// use synta::{Integer, FromDer};
79///
80/// let der = &[0x02, 0x01, 0x2A]; // INTEGER 42
81/// let n = Integer::from_der(der).unwrap();
82/// assert_eq!(n.as_i64().unwrap(), 42);
83/// ```
84///
85/// ```
86/// use synta::{ObjectIdentifier, FromDer, ToDer};
87///
88/// let oid = ObjectIdentifier::new(&[1, 2, 840, 113549]).unwrap();
89/// let der = oid.to_der().unwrap();
90/// let oid2 = ObjectIdentifier::from_der(&der).unwrap();
91/// assert_eq!(oid, oid2);
92/// ```
93pub trait FromDer: Sized {
94    /// Decode one value from DER-encoded `input`.
95    ///
96    /// Returns [`Error::TrailingData`] if the input contains bytes beyond
97    /// the end of the decoded TLV.
98    fn from_der(input: &[u8]) -> Result<Self>;
99
100    /// Decode one value from BER-encoded `input`.
101    ///
102    /// Returns [`Error::TrailingData`] if the input contains bytes beyond
103    /// the end of the decoded TLV.
104    fn from_ber(input: &[u8]) -> Result<Self>;
105}
106
107/// Blanket implementation of [`FromDer`] for all fully-owned types.
108///
109/// The HRTB bound `T: for<'a> Decode<'a>` ensures that the type does not
110/// borrow from the input buffer.  Zero-copy types such as `OctetStringRef<'a>`
111/// carry a lifetime tied to the buffer and therefore do not satisfy the bound;
112/// use [`Decoder`] directly for those.
113///
114/// [`Decoder`]: crate::Decoder
115impl<T: for<'a> Decode<'a>> FromDer for T {
116    fn from_der(input: &[u8]) -> Result<Self> {
117        let mut dec = Decoder::new(input, Encoding::Der);
118        let val = dec.decode()?;
119        if !dec.is_empty() {
120            return Err(Error::TrailingData {
121                position: dec.position(),
122            });
123        }
124        Ok(val)
125    }
126
127    fn from_ber(input: &[u8]) -> Result<Self> {
128        let mut dec = Decoder::new(input, Encoding::Ber);
129        let val = dec.decode()?;
130        if !dec.is_empty() {
131            return Err(Error::TrailingData {
132                position: dec.position(),
133            });
134        }
135        Ok(val)
136    }
137}