synta 0.2.3

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
//! Convenience traits for encoding/decoding without explicit Encoder/Decoder construction
//!
//! These traits provide `to_der()`, `to_ber()`, `from_der()`, and `from_ber()`
//! methods on any type that implements [`Encode`] or [`Decode`], eliminating
//! boilerplate for the common single-value encode/decode case.
//!
//! Both traits are blanket-implemented, so they are automatically available on
//! all conforming types — including codegen-generated structs.
//!
//! # `from_der` / `from_ber` and lifetimes
//!
//! [`FromDer`] is blanket-implemented for `T: for<'a> Decode<'a>` — that is,
//! types that own all their data after decoding (e.g. `Integer`, `Boolean`,
//! `OctetString`, `ObjectIdentifier`, codegen structs using owned string
//! types).  Zero-copy borrowed types such as `OctetStringRef<'a>` cannot
//! satisfy the HRTB bound; use [`Decoder`] directly for those.
//!
//! [`Decoder`]: crate::Decoder

#[cfg(not(feature = "std"))]
use alloc::vec::Vec;

use crate::der::decoder::Decoder;
use crate::der::encoder::Encoder;
use crate::error::{Error, Result};
use crate::traits::decode::Decode;
use crate::traits::encode::Encode;
use crate::Encoding;

/// Encode a value to DER or BER bytes without constructing an [`Encoder`] manually.
///
/// Blanket-implemented for all types that implement [`Encode`].
///
/// # Examples
///
/// ```
/// use synta::{Integer, ToDer};
///
/// let n = Integer::from_i64(42);
/// let der = n.to_der().unwrap();
/// assert_eq!(der, &[0x02, 0x01, 0x2A]);
/// ```
pub trait ToDer: Encode + Sized {
    /// Encode `self` to DER and return the bytes.
    fn to_der(&self) -> Result<Vec<u8>> {
        let mut enc = Encoder::new(Encoding::Der);
        enc.encode(self)?;
        enc.finish()
    }

    /// Encode `self` to BER and return the bytes.
    fn to_ber(&self) -> Result<Vec<u8>> {
        let mut enc = Encoder::new(Encoding::Ber);
        enc.encode(self)?;
        enc.finish()
    }
}

/// Blanket implementation of [`ToDer`] for all types that implement [`Encode`].
///
/// This impl is what makes `to_der()` and `to_ber()` available on every
/// ASN.1 type in this crate — including types produced by `#[derive(Asn1Sequence)]`
/// and friends — without any additional boilerplate.
impl<T: Encode> ToDer for T {}

/// Decode a value from a DER or BER byte slice without constructing a [`Decoder`] manually.
///
/// Blanket-implemented for all owned types `T` that satisfy `for<'a> Decode<'a>`.
/// Zero-copy borrowed types (e.g. `OctetStringRef<'a>`) do not satisfy this
/// bound; use [`Decoder`] directly for those.
///
/// Both methods require that the input contains **exactly** one TLV — trailing
/// bytes cause [`Error::TrailingData`].
///
/// # Examples
///
/// ```
/// use synta::{Integer, FromDer};
///
/// let der = &[0x02, 0x01, 0x2A]; // INTEGER 42
/// let n = Integer::from_der(der).unwrap();
/// assert_eq!(n.as_i64().unwrap(), 42);
/// ```
///
/// ```
/// use synta::{ObjectIdentifier, FromDer, ToDer};
///
/// let oid = ObjectIdentifier::new(&[1, 2, 840, 113549]).unwrap();
/// let der = oid.to_der().unwrap();
/// let oid2 = ObjectIdentifier::from_der(&der).unwrap();
/// assert_eq!(oid, oid2);
/// ```
pub trait FromDer: Sized {
    /// Decode one value from DER-encoded `input`.
    ///
    /// Returns [`Error::TrailingData`] if the input contains bytes beyond
    /// the end of the decoded TLV.
    fn from_der(input: &[u8]) -> Result<Self>;

    /// Decode one value from BER-encoded `input`.
    ///
    /// Returns [`Error::TrailingData`] if the input contains bytes beyond
    /// the end of the decoded TLV.
    fn from_ber(input: &[u8]) -> Result<Self>;
}

/// Blanket implementation of [`FromDer`] for all fully-owned types.
///
/// The HRTB bound `T: for<'a> Decode<'a>` ensures that the type does not
/// borrow from the input buffer.  Zero-copy types such as `OctetStringRef<'a>`
/// carry a lifetime tied to the buffer and therefore do not satisfy the bound;
/// use [`Decoder`] directly for those.
///
/// [`Decoder`]: crate::Decoder
impl<T: for<'a> Decode<'a>> FromDer for T {
    fn from_der(input: &[u8]) -> Result<Self> {
        let mut dec = Decoder::new(input, Encoding::Der);
        let val = dec.decode()?;
        if !dec.is_empty() {
            return Err(Error::TrailingData {
                position: dec.position(),
            });
        }
        Ok(val)
    }

    fn from_ber(input: &[u8]) -> Result<Self> {
        let mut dec = Decoder::new(input, Encoding::Ber);
        let val = dec.decode()?;
        if !dec.is_empty() {
            return Err(Error::TrailingData {
                position: dec.position(),
            });
        }
        Ok(val)
    }
}