synta 0.1.8

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
//! Zero-copy raw DER/TLV capture.

/// Captures a complete ASN.1 TLV (tag + length + value) from the input
/// buffer without decoding the content.  The raw bytes are borrowed
/// directly from the decoder's input with lifetime `'a`.
///
/// Use `RawDer` for fields whose content should be decoded lazily on first
/// access rather than eagerly at parse time.  A `RawDer<'a>` is very
/// cheap to create: it reads the tag and length to advance the cursor,
/// then stores a slice of the original input — no heap allocation.
///
/// # Example
///
/// ```rust,ignore
/// // TBSCertificate stores large optional fields as RawDer
/// pub struct TBSCertificate<'a> {
///     pub issuer: RawDer<'a>,  // zero-cost at parse time
///     ...
/// }
/// // Decode issuer lazily:
/// let name: SequenceOf<Element> = Decoder::new(cert.tbs.issuer.as_bytes(), Der).decode()?;
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RawDer<'a>(pub &'a [u8]);

impl<'a> RawDer<'a> {
    /// The complete TLV bytes (tag + length + value) captured from the input.
    pub fn as_bytes(&self) -> &'a [u8] {
        self.0
    }
}

impl<'a> crate::traits::Decode<'a> for RawDer<'a> {
    #[inline]
    fn decode(decoder: &mut crate::der::decoder::Decoder<'a>) -> crate::Result<Self> {
        // Snapshot the cursor *before* consuming anything — this is the TLV start.
        let start = decoder.remaining();
        // Consume the tag.
        decoder.read_tag()?;
        // Consume the length, then the value bytes.
        let length = decoder.read_length()?;
        if length.is_indefinite() {
            // BER/CER indefinite-length element: advance the cursor past the content
            // and the end-of-contents (00 00) octets.  The returned slice includes
            // the original 0x80 indefinite-length byte and all EOC pairs so that
            // `as_bytes()` returns re-decodable BER bytes.
            decoder.read_indefinite_content()?;
        } else {
            let len = length.definite()?;
            decoder.read_bytes(len)?;
        }
        // The bytes consumed are exactly start[..total].
        let total = start.len() - decoder.remaining().len();
        Ok(RawDer(&start[..total]))
    }
}

// ---- DecodeImplicit ----
//
// When a `RawDer<'a>` field carries an IMPLICIT context tag the outer
// context-specific wrapper is consumed by the derive macro, which then calls
// `decode_implicit` with just the **value bytes** (no context tag, no length
// prefix).  `RawDer::as_bytes()` will return those raw value bytes.
//
// For SEQUENCE-based types that are IMPLICITLY tagged, the value bytes equal the
// SEQUENCE's content (all fields concatenated); for OCTET STRING / SET OF, the
// value bytes are the element payload.  Callers that need the original TLV
// header (e.g. to re-hash `signedAttrs` with the SET tag for CMS signing) must
// prepend the appropriate tag and length manually.
impl<'a> crate::traits::DecodeImplicit<'a> for RawDer<'a> {
    #[inline]
    fn decode_implicit(content: &'a [u8], _encoding: crate::Encoding) -> crate::Result<Self> {
        Ok(RawDer(content))
    }
}

// `Vec<T>: DecodeImplicit<'a>` — IMPLICIT-tagged SEQUENCE OF support.
//
// When a `Vec<T>` field (or type alias thereof, e.g. `GeneralNames<'a>`) carries
// an IMPLICIT context tag, the context-specific wrapper is consumed by the parent
// decoder and the raw content bytes are passed here.  Those bytes are the SEQUENCE
// body — the concatenated encodings of the individual elements — without the outer
// SEQUENCE tag or length prefix.  We create a sub-decoder and pull elements one
// by one until exhausted.
impl<'a, T: crate::traits::Decode<'a>> crate::traits::DecodeImplicit<'a> for Vec<T> {
    fn decode_implicit(content: &'a [u8], encoding: crate::Encoding) -> crate::Result<Self> {
        let mut decoder = crate::Decoder::new(content, encoding);
        let mut elements = Vec::new();
        while !decoder.is_empty() {
            elements.push(T::decode(&mut decoder)?);
        }
        Ok(elements)
    }
}

// ---- serde support ----

#[cfg(feature = "serde")]
impl serde::Serialize for RawDer<'_> {
    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        let hex = crate::serde_impl::bytes_to_hex(self.0);
        s.serialize_str(&hex)
    }
}

// RawDer<'a> is a polymorphic "any TLV" capture type — it has no single fixed
// tag.  Implementing TagForOptional with None tells derive macros to treat
// Option<RawDer<'a>> fields as "accept any remaining content" (must be last).
impl<'a> crate::traits::TagForOptional for RawDer<'a> {
    fn optional_tag() -> Option<crate::Tag> {
        None
    }
}

impl crate::traits::Encode for RawDer<'_> {
    #[inline]
    fn encode(&self, encoder: &mut crate::der::encoder::Encoder) -> crate::Result<()> {
        // Write the captured TLV bytes verbatim — no re-encoding needed.
        encoder.write_bytes(self.0);
        Ok(())
    }

    #[inline]
    fn encoded_len(&self) -> crate::Result<usize> {
        Ok(self.0.len())
    }
}