# Decoding
This walkthrough covers decoding ASN.1 data with the `synta` library.
## Creating a decoder
```rust
use synta::{Decoder, Encoding};
// DER mode (strict, for cryptographic data)
let mut decoder = Decoder::new(&data, Encoding::Der);
// BER mode (relaxed, for legacy or network data)
let mut decoder = Decoder::new(&data, Encoding::Ber);
```
## Quick decode with `FromDer`
For the common case of decoding a single value from a byte slice, `FromDer`
removes the need to construct a `Decoder` manually. Import the trait and call
`from_der()` directly on the target type:
```rust,ignore
use synta::{Integer, FromDer};
let der: &[u8] = &[0x02, 0x01, 0x2A]; // DER INTEGER 42
let n = Integer::from_der(der)?;
assert_eq!(n.as_i64()?, 42);
```
A `from_ber()` method is also provided for BER-encoded input:
```rust,ignore
use synta::{Integer, FromDer};
let n = Integer::from_ber(ber_data)?;
```
Both methods require the input to contain **exactly one** TLV — trailing bytes
produce `Error::TrailingData`.
**Roundtrip example** using `FromDer` together with `ToDer`:
```rust,ignore
use synta::{ObjectIdentifier, FromDer, ToDer};
let oid = ObjectIdentifier::new(&[1, 2, 840, 113549])?;
let der = oid.to_der()?;
let oid2 = ObjectIdentifier::from_der(&der)?;
assert_eq!(oid, oid2);
```
**Zero-copy borrowed types** — types that borrow from the input buffer (those
with a `'a` lifetime parameter, such as `OctetStringRef<'a>`) cannot satisfy
the `for<'a> Decode<'a>` bound that `FromDer` requires, because they tie their
lifetime to the input slice. Use `Decoder` directly for those:
```rust,ignore
use synta::{Decoder, Encoding};
use synta::types::string::OctetStringRef;
let mut decoder = Decoder::new(data, Encoding::Der);
let octets: OctetStringRef<'_> = decoder.decode()?;
// octets borrows from `data`; the Decoder API handles this correctly
```
## Decoding primitive types
### Integer
```rust
use synta::{Decoder, Encoding, Integer};
let data = vec![0x02, 0x01, 0x2A]; // DER INTEGER 42
let mut decoder = Decoder::new(&data, Encoding::Der);
let integer: Integer = decoder.decode()?;
// Convert to native types
let val_i64: i64 = integer.as_i64()?;
let val_i128: i128 = integer.as_i128()?;
// Access raw big-endian two's complement bytes
let bytes: &[u8] = integer.as_bytes();
```
### Boolean
```rust
use synta::types::primitive::Boolean;
let mut decoder = Decoder::new(&data, Encoding::Der);
let b: Boolean = decoder.decode()?;
let value: bool = b.value();
```
### OctetString
```rust
use synta::types::string::OctetString;
let mut decoder = Decoder::new(&data, Encoding::Der);
let octets: OctetString = decoder.decode()?;
let bytes: &[u8] = octets.as_bytes();
```
### ObjectIdentifier
```rust
use synta::types::oid::ObjectIdentifier;
use std::str::FromStr;
// Create from components
let components = &[1, 2, 840, 113549, 1, 1, 1]; // RSA
let oid = ObjectIdentifier::new(components)?;
// Create from dotted-decimal string
let oid2 = ObjectIdentifier::from_str("1.2.840.113549.1.1.1")?;
// Access
let comps: &[u32] = oid.components();
let oid_str = oid.to_string(); // "1.2.840.113549.1.1.1"
```
### Enumerated
```rust
use synta::types::primitive::Enumerated;
let der: &[u8] = &[0x0a, 0x01, 0x00]; // ENUMERATED 0
let mut dec = Decoder::new(der, Encoding::Der);
let status: Enumerated = dec.decode()?;
assert_eq!(status.as_i64()?, 0);
```
## Decoding string types
```rust
use synta::types::string::{Utf8String, PrintableString, IA5String};
// UTF-8 String
let utf8: Utf8String = decoder.decode()?;
// Printable String (restricted character set)
let printable: PrintableString = decoder.decode()?;
// IA5 String (ASCII)
let ia5: IA5String = decoder.decode()?;
```
## Decoding time types
```rust
use synta::types::time::{UtcTime, GeneralizedTime};
let utc: UtcTime = decoder.decode()?;
let gen: GeneralizedTime = decoder.decode()?;
```
## Decoding constructed types
### SEQUENCE
```rust
use synta::types::constructed::{Element, Sequence};
use synta::types::primitive::Integer;
let mut decoder = Decoder::new(&data, Encoding::Der);
let seq: Sequence = decoder.decode()?;
// Consuming iteration (lazy decode)
for element in seq {
match element? {
Element::Integer(i) => println!("Integer: {}", i.as_i64()?),
Element::OctetString(o) => println!("OctetString: {} bytes", o.as_bytes().len()),
_ => println!("Other type"),
}
}
```
### SET
```rust
use synta::types::constructed::Set;
let set: Set = decoder.decode()?;
// iterate same as Sequence
```
### SequenceOf / SetOf
```rust
use synta::types::constructed::SequenceOf;
use synta::types::primitive::Integer;
let seq_of: SequenceOf<Integer> = decoder.decode()?;
for int in seq_of.elements() {
println!("{}", int.as_i64()?);
}
```
## Decoding tagged types
### EXPLICIT tag
```rust
use synta::types::tagged::ExplicitTag;
use synta::types::primitive::Integer;
// Context-specific [0] EXPLICIT Integer
let tagged: ExplicitTag<Integer> = decoder.decode()?;
let inner: &Integer = tagged.inner();
```
### IMPLICIT tag
```rust
use synta::types::tagged::ImplicitTag;
use synta::types::primitive::Integer;
// Context-specific [0] IMPLICIT Integer
let tagged: ImplicitTag<Integer> = decoder.decode()?;
```
## Decoding unknown structures with Element
Use `Element` when you do not know the type ahead of time:
```rust
use synta::types::constructed::Element;
let element: Element = decoder.decode()?;
match element {
Element::Integer(i) => println!("Integer: {}", i.as_i64()?),
Element::OctetString(o) => println!("OctetString: {} bytes", o.as_bytes().len()),
Element::Sequence(s) => {
let elements = s.into_elements()?;
println!("Sequence with {} elements", elements.len());
}
_ => println!("Other type"),
}
```
## Peeking at the next tag
```rust
// Peek without consuming
let tag = decoder.peek_tag()?;
println!("Next tag: {:?}", tag);
```
## DER vs BER
DER is the strict subset used in cryptography. BER relaxes several rules:
| Boolean TRUE | must be `0xFF` | any non-zero value |
| Lengths | shortest form | any form |
| Indefinite length | not allowed | allowed |
| SET element order | must be sorted | any order |
```rust
// DER mode — strict
let mut decoder = Decoder::new(&data, Encoding::Der);
// BER mode — accepts any BER-legal encoding
let mut decoder = Decoder::new(&data, Encoding::Ber);
// BER with indefinite length
let ber_data = vec![
0x30, 0x80, // SEQUENCE, indefinite length
0x02, 0x01, 0x2A, // INTEGER 42
0x00, 0x00, // End-of-contents
];
let mut decoder = Decoder::new(&ber_data, Encoding::Ber);
let seq: Sequence = decoder.decode()?;
```
## Decoder configuration
Limit resource consumption when parsing untrusted input:
```rust
use synta::{Decoder, DecoderConfig, Encoding};
let config = DecoderConfig {
max_depth: 32, // maximum nesting depth
max_sequence_elements: 10_000, // maximum elements per SEQUENCE/SET
max_length: 16 * 1024 * 1024, // maximum encoded value length (16 MiB)
};
let mut decoder = Decoder::new_with_config(&data, Encoding::Der, &config);
```
## Error handling
All decode operations return `Result<T, synta::Error>`:
```rust
use synta::Error;
match decoder.decode::<Integer>() {
Ok(integer) => println!("Decoded: {}", integer.as_i64()?),
Err(Error::UnexpectedEof { position }) => {
println!("Unexpected EOF at position {}", position);
}
Err(Error::UnexpectedTag { position, expected, actual }) => {
println!("Wrong tag at {}: expected {:?}, got {:?}",
position, expected, actual);
}
Err(Error::DerViolation { position, reason }) => {
println!("DER violation at {}: {}", position, reason);
}
Err(e) => println!("Other error: {:?}", e),
}
```
Common error variants:
- `UnexpectedEof` — not enough data
- `UnexpectedTag` — wrong ASN.1 tag (type mismatch)
- `DerViolation` — data does not comply with DER rules
- `IntegerOverflow` — integer too large for requested native type
- `InvalidEncoding` — malformed ASN.1 data
Use the `?` operator for propagation:
```rust
fn parse_data(data: &[u8]) -> synta::Result<Integer> {
let mut decoder = Decoder::new(data, Encoding::Der);
decoder.decode()
}
```
## Roundtrip validation
```rust
fn validate_roundtrip<T>(value: &T) -> synta::Result<bool>
where
T: synta::Encode + for<'a> synta::Decode<'a> + PartialEq,
{
let mut encoder = Encoder::new(Encoding::Der);
encoder.encode(value)?;
let encoded = encoder.finish()?;
let mut decoder = Decoder::new(&encoded, Encoding::Der);
let decoded: T = decoder.decode()?;
Ok(value == &decoded)
}
```
## Next steps
- [Encoding](encoding.md) — building and encoding DER structures
- [PKI Workflow](pki-workflow.md) — certificate to CRL to OCSP end to end
- [ASN.1 Primitives](../asn1/primitives.md) — full type reference