⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/net/
asn1.rs

1//! ASN.1/BER Encoding Library
2//!
3//! Provides ASN.1 Basic Encoding Rules (BER) serialization and deserialization
4//! for use by LDAP, Kerberos, and other protocols that depend on ASN.1
5//! structured data.
6//!
7//! # Features
8//!
9//! - Tag encoding/decoding with all four tag classes
10//! - Definite-length BER encoding (short and long forms)
11//! - Primitive types: Boolean, Integer, BigInteger, BitString, OctetString,
12//!   Null, OID, UTF8String, Enumerated
13//! - Constructed types: Sequence, Set
14//! - Context-specific tagged values
15//! - Builder API for constructing ASN.1 structures fluently
16//! - Full OID encoding/decoding with base-128 variable-length encoding
17
18#![allow(dead_code)]
19
20#[cfg(feature = "alloc")]
21extern crate alloc;
22
23#[cfg(feature = "alloc")]
24use alloc::{string::String, vec, vec::Vec};
25
26use crate::error::KernelError;
27
28// ---------------------------------------------------------------------------
29// Tag classes and types
30// ---------------------------------------------------------------------------
31
32/// ASN.1 tag class
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34#[repr(u8)]
35pub enum TagClass {
36    /// Universal (0)
37    Universal = 0,
38    /// Application (1)
39    Application = 1,
40    /// Context-specific (2)
41    ContextSpecific = 2,
42    /// Private (3)
43    Private = 3,
44}
45
46impl TagClass {
47    /// Create from the top 2 bits of a tag byte
48    fn from_byte(b: u8) -> Self {
49        match (b >> 6) & 0x03 {
50            0 => TagClass::Universal,
51            1 => TagClass::Application,
52            2 => TagClass::ContextSpecific,
53            3 => TagClass::Private,
54            _ => TagClass::Universal,
55        }
56    }
57}
58
59/// ASN.1 tag identifiers
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub enum Tag {
62    /// BOOLEAN (1)
63    Boolean,
64    /// INTEGER (2)
65    Integer,
66    /// BIT STRING (3)
67    BitString,
68    /// OCTET STRING (4)
69    OctetString,
70    /// NULL (5)
71    Null,
72    /// OBJECT IDENTIFIER (6)
73    ObjectIdentifier,
74    /// ENUMERATED (10)
75    Enumerated,
76    /// UTF8String (12)
77    Utf8String,
78    /// PrintableString (19)
79    PrintableString,
80    /// IA5String (22)
81    Ia5String,
82    /// UTCTime (23)
83    UtcTime,
84    /// SEQUENCE (0x30)
85    Sequence,
86    /// SET (0x31)
87    Set,
88    /// Context-specific tag with class and number
89    ContextSpecific(TagClass, u8),
90}
91
92impl Tag {
93    /// Get the tag number for universal types
94    fn universal_number(&self) -> Option<u8> {
95        match self {
96            Tag::Boolean => Some(1),
97            Tag::Integer => Some(2),
98            Tag::BitString => Some(3),
99            Tag::OctetString => Some(4),
100            Tag::Null => Some(5),
101            Tag::ObjectIdentifier => Some(6),
102            Tag::Enumerated => Some(10),
103            Tag::Utf8String => Some(12),
104            Tag::PrintableString => Some(19),
105            Tag::Ia5String => Some(22),
106            Tag::UtcTime => Some(23),
107            Tag::Sequence => Some(16), // 0x30 = constructed + 16
108            Tag::Set => Some(17),      // 0x31 = constructed + 17
109            Tag::ContextSpecific(_, _) => None,
110        }
111    }
112
113    /// Whether this tag represents a constructed (vs primitive) encoding
114    fn is_constructed(&self) -> bool {
115        matches!(self, Tag::Sequence | Tag::Set | Tag::ContextSpecific(_, _))
116    }
117}
118
119// ---------------------------------------------------------------------------
120// ASN.1 value types
121// ---------------------------------------------------------------------------
122
123/// ASN.1 value
124#[cfg(feature = "alloc")]
125#[derive(Debug, Clone, PartialEq, Eq)]
126pub enum AsnValue {
127    /// BOOLEAN
128    Boolean(bool),
129    /// INTEGER (fits in i64)
130    Integer(i64),
131    /// INTEGER (arbitrary precision, big-endian two's complement)
132    BigInteger(Vec<u8>),
133    /// BIT STRING (data bytes, unused bits in last byte)
134    BitString(Vec<u8>, u8),
135    /// OCTET STRING
136    OctetString(Vec<u8>),
137    /// NULL
138    Null,
139    /// OBJECT IDENTIFIER (arc components)
140    Oid(Vec<u32>),
141    /// UTF8String
142    Utf8String(String),
143    /// PrintableString
144    PrintableString(String),
145    /// IA5String
146    Ia5String(String),
147    /// UTCTime (raw string)
148    UtcTime(String),
149    /// SEQUENCE (ordered list)
150    Sequence(Vec<AsnValue>),
151    /// SET (unordered collection)
152    Set(Vec<AsnValue>),
153    /// ENUMERATED
154    Enumerated(i64),
155    /// Context-specific tagged value (tag number, raw bytes)
156    ContextSpecific(u8, Vec<u8>),
157}
158
159// ---------------------------------------------------------------------------
160// Length encoding/decoding
161// ---------------------------------------------------------------------------
162
163/// Encode a BER definite-length value.
164///
165/// Short form: lengths 0..=127 use a single byte.
166/// Long form: lengths >= 128 use one byte for the count of length bytes,
167/// followed by that many bytes encoding the length in big-endian.
168#[cfg(feature = "alloc")]
169pub fn encode_length(length: usize, out: &mut Vec<u8>) {
170    if length < 128 {
171        out.push(length as u8);
172    } else if length <= 0xFF {
173        out.push(0x81);
174        out.push(length as u8);
175    } else if length <= 0xFFFF {
176        out.push(0x82);
177        out.push((length >> 8) as u8);
178        out.push(length as u8);
179    } else if length <= 0xFF_FFFF {
180        out.push(0x83);
181        out.push((length >> 16) as u8);
182        out.push((length >> 8) as u8);
183        out.push(length as u8);
184    } else {
185        out.push(0x84);
186        out.push((length >> 24) as u8);
187        out.push((length >> 16) as u8);
188        out.push((length >> 8) as u8);
189        out.push(length as u8);
190    }
191}
192
193/// Decode a BER definite-length value.
194///
195/// Returns `(length, bytes_consumed)` or an error if the data is truncated.
196pub fn decode_length(data: &[u8]) -> Result<(usize, usize), KernelError> {
197    if data.is_empty() {
198        return Err(KernelError::InvalidArgument {
199            name: "asn1_length",
200            value: "truncated",
201        });
202    }
203
204    let first = data[0];
205    if first < 128 {
206        Ok((first as usize, 1))
207    } else {
208        let num_bytes = (first & 0x7F) as usize;
209        if num_bytes == 0 || num_bytes > 4 {
210            return Err(KernelError::InvalidArgument {
211                name: "asn1_length",
212                value: "unsupported length encoding",
213            });
214        }
215        if data.len() < 1 + num_bytes {
216            return Err(KernelError::InvalidArgument {
217                name: "asn1_length",
218                value: "truncated long form",
219            });
220        }
221        let mut length: usize = 0;
222        for i in 0..num_bytes {
223            length = (length << 8) | (data[1 + i] as usize);
224        }
225        Ok((length, 1 + num_bytes))
226    }
227}
228
229// ---------------------------------------------------------------------------
230// Tag encoding/decoding
231// ---------------------------------------------------------------------------
232
233/// Encode a tag byte (or bytes for high-tag-number form).
234///
235/// For tags 0..=30, a single byte suffices:
236///   `[class << 6 | constructed << 5 | tag_number]`
237///
238/// High-tag-number form (tag >= 31) is supported but uncommon.
239#[cfg(feature = "alloc")]
240pub fn encode_tag(class: TagClass, constructed: bool, number: u8, out: &mut Vec<u8>) {
241    let class_bits = (class as u8) << 6;
242    let constructed_bit = if constructed { 0x20 } else { 0 };
243
244    if number < 31 {
245        out.push(class_bits | constructed_bit | number);
246    } else {
247        out.push(class_bits | constructed_bit | 0x1F);
248        // Base-128 encoding for tag number >= 31
249        encode_base128(number as u32, out);
250    }
251}
252
253/// Decode a tag from the data stream.
254///
255/// Returns `(class, constructed, tag_number, bytes_consumed)`.
256pub fn decode_tag(data: &[u8]) -> Result<(TagClass, bool, u8, usize), KernelError> {
257    if data.is_empty() {
258        return Err(KernelError::InvalidArgument {
259            name: "asn1_tag",
260            value: "truncated",
261        });
262    }
263
264    let first = data[0];
265    let class = TagClass::from_byte(first);
266    let constructed = (first & 0x20) != 0;
267    let low_bits = first & 0x1F;
268
269    if low_bits < 31 {
270        Ok((class, constructed, low_bits, 1))
271    } else {
272        // High-tag-number form
273        let mut number: u32 = 0;
274        let mut pos = 1;
275        loop {
276            if pos >= data.len() {
277                return Err(KernelError::InvalidArgument {
278                    name: "asn1_tag",
279                    value: "truncated high tag",
280                });
281            }
282            let b = data[pos];
283            number = (number << 7) | ((b & 0x7F) as u32);
284            pos += 1;
285            if b & 0x80 == 0 {
286                break;
287            }
288            if number > 255 {
289                return Err(KernelError::InvalidArgument {
290                    name: "asn1_tag",
291                    value: "tag number too large",
292                });
293            }
294        }
295        Ok((class, constructed, number as u8, pos))
296    }
297}
298
299// ---------------------------------------------------------------------------
300// OID encoding/decoding
301// ---------------------------------------------------------------------------
302
303/// Encode an OID to BER content bytes.
304///
305/// The first two arcs are combined as `first * 40 + second`.
306/// Subsequent arcs use base-128 variable-length encoding.
307#[cfg(feature = "alloc")]
308fn encode_oid(arcs: &[u32]) -> Vec<u8> {
309    let mut out = Vec::new();
310    if arcs.len() < 2 {
311        return out;
312    }
313
314    // First two components combined
315    let first_byte = arcs[0].saturating_mul(40).saturating_add(arcs[1]);
316    encode_base128(first_byte, &mut out);
317
318    for &arc in &arcs[2..] {
319        encode_base128(arc, &mut out);
320    }
321
322    out
323}
324
325/// Decode OID content bytes into arc components.
326#[cfg(feature = "alloc")]
327fn decode_oid(data: &[u8]) -> Result<Vec<u32>, KernelError> {
328    if data.is_empty() {
329        return Err(KernelError::InvalidArgument {
330            name: "asn1_oid",
331            value: "empty",
332        });
333    }
334
335    let mut arcs = Vec::new();
336    let mut pos = 0;
337
338    // Decode first byte (combines first two arcs)
339    let (first_combined, consumed) = decode_base128(data, pos)?;
340    pos += consumed;
341
342    if first_combined < 40 {
343        arcs.push(0);
344        arcs.push(first_combined);
345    } else if first_combined < 80 {
346        arcs.push(1);
347        arcs.push(first_combined - 40);
348    } else {
349        arcs.push(2);
350        arcs.push(first_combined - 80);
351    }
352
353    // Decode remaining arcs
354    while pos < data.len() {
355        let (arc, consumed) = decode_base128(data, pos)?;
356        pos += consumed;
357        arcs.push(arc);
358    }
359
360    Ok(arcs)
361}
362
363// ---------------------------------------------------------------------------
364// Base-128 variable-length integer encoding
365// ---------------------------------------------------------------------------
366
367/// Encode a u32 in base-128 variable-length format.
368/// Each byte has bit 7 set except the last.
369#[cfg(feature = "alloc")]
370fn encode_base128(mut value: u32, out: &mut Vec<u8>) {
371    if value == 0 {
372        out.push(0);
373        return;
374    }
375
376    // Collect bytes in reverse order
377    let mut bytes = [0u8; 5];
378    let mut count = 0;
379    while value > 0 {
380        bytes[count] = (value & 0x7F) as u8;
381        value >>= 7;
382        count += 1;
383    }
384
385    // Write in correct order with continuation bits
386    for i in (0..count).rev() {
387        let b = bytes[i];
388        if i > 0 {
389            out.push(b | 0x80);
390        } else {
391            out.push(b);
392        }
393    }
394}
395
396/// Decode a base-128 variable-length integer.
397/// Returns `(value, bytes_consumed)`.
398fn decode_base128(data: &[u8], start: usize) -> Result<(u32, usize), KernelError> {
399    let mut value: u32 = 0;
400    let mut pos = start;
401
402    loop {
403        if pos >= data.len() {
404            return Err(KernelError::InvalidArgument {
405                name: "asn1_base128",
406                value: "truncated",
407            });
408        }
409        let b = data[pos];
410        value = value
411            .checked_mul(128)
412            .and_then(|v| v.checked_add((b & 0x7F) as u32))
413            .ok_or(KernelError::InvalidArgument {
414                name: "asn1_base128",
415                value: "overflow",
416            })?;
417        pos += 1;
418        if b & 0x80 == 0 {
419            break;
420        }
421    }
422
423    Ok((value, pos - start))
424}
425
426// ---------------------------------------------------------------------------
427// ASN.1 Encoder
428// ---------------------------------------------------------------------------
429
430/// Encodes an `AsnValue` tree into BER-encoded bytes.
431#[cfg(feature = "alloc")]
432pub struct AsnEncoder;
433
434#[cfg(feature = "alloc")]
435impl AsnEncoder {
436    /// Encode an ASN.1 value to BER bytes.
437    pub fn encode(value: &AsnValue) -> Vec<u8> {
438        let mut out = Vec::new();
439        Self::encode_value(value, &mut out);
440        out
441    }
442
443    fn encode_value(value: &AsnValue, out: &mut Vec<u8>) {
444        match value {
445            AsnValue::Boolean(b) => {
446                out.push(0x01); // tag
447                out.push(0x01); // length
448                out.push(if *b { 0xFF } else { 0x00 });
449            }
450            AsnValue::Integer(n) => {
451                let content = Self::encode_integer(*n);
452                out.push(0x02); // tag
453                encode_length(content.len(), out);
454                out.extend_from_slice(&content);
455            }
456            AsnValue::BigInteger(bytes) => {
457                out.push(0x02); // tag
458                encode_length(bytes.len(), out);
459                out.extend_from_slice(bytes);
460            }
461            AsnValue::BitString(data, unused_bits) => {
462                out.push(0x03); // tag
463                encode_length(data.len() + 1, out);
464                out.push(*unused_bits);
465                out.extend_from_slice(data);
466            }
467            AsnValue::OctetString(data) => {
468                out.push(0x04); // tag
469                encode_length(data.len(), out);
470                out.extend_from_slice(data);
471            }
472            AsnValue::Null => {
473                out.push(0x05); // tag
474                out.push(0x00); // length
475            }
476            AsnValue::Oid(arcs) => {
477                let content = encode_oid(arcs);
478                out.push(0x06); // tag
479                encode_length(content.len(), out);
480                out.extend_from_slice(&content);
481            }
482            AsnValue::Utf8String(s) => {
483                out.push(0x0C); // tag 12
484                encode_length(s.len(), out);
485                out.extend_from_slice(s.as_bytes());
486            }
487            AsnValue::PrintableString(s) => {
488                out.push(0x13); // tag 19
489                encode_length(s.len(), out);
490                out.extend_from_slice(s.as_bytes());
491            }
492            AsnValue::Ia5String(s) => {
493                out.push(0x16); // tag 22
494                encode_length(s.len(), out);
495                out.extend_from_slice(s.as_bytes());
496            }
497            AsnValue::UtcTime(s) => {
498                out.push(0x17); // tag 23
499                encode_length(s.len(), out);
500                out.extend_from_slice(s.as_bytes());
501            }
502            AsnValue::Sequence(items) => {
503                let mut content = Vec::new();
504                for item in items {
505                    Self::encode_value(item, &mut content);
506                }
507                out.push(0x30); // tag (constructed)
508                encode_length(content.len(), out);
509                out.extend_from_slice(&content);
510            }
511            AsnValue::Set(items) => {
512                let mut content = Vec::new();
513                for item in items {
514                    Self::encode_value(item, &mut content);
515                }
516                out.push(0x31); // tag (constructed)
517                encode_length(content.len(), out);
518                out.extend_from_slice(&content);
519            }
520            AsnValue::Enumerated(n) => {
521                let content = Self::encode_integer(*n);
522                out.push(0x0A); // tag 10
523                encode_length(content.len(), out);
524                out.extend_from_slice(&content);
525            }
526            AsnValue::ContextSpecific(number, data) => {
527                // Context-specific, constructed
528                encode_tag(TagClass::ContextSpecific, true, *number, out);
529                encode_length(data.len(), out);
530                out.extend_from_slice(data);
531            }
532        }
533    }
534
535    /// Encode a signed integer in minimal two's complement form.
536    fn encode_integer(value: i64) -> Vec<u8> {
537        if value == 0 {
538            return vec![0x00];
539        }
540
541        let bytes = value.to_be_bytes();
542        let mut start = 0;
543
544        if value > 0 {
545            // Skip leading 0x00 bytes, but keep one if the next byte has bit 7 set
546            while start < 7 && bytes[start] == 0x00 {
547                start += 1;
548            }
549            // If high bit is set, prepend a 0x00 for positive numbers
550            if bytes[start] & 0x80 != 0 {
551                let mut result = vec![0x00];
552                result.extend_from_slice(&bytes[start..]);
553                return result;
554            }
555        } else {
556            // Negative: skip leading 0xFF bytes, but keep one if next byte has bit 7 clear
557            while start < 7 && bytes[start] == 0xFF {
558                start += 1;
559            }
560            if bytes[start] & 0x80 == 0 {
561                let mut result = vec![0xFF];
562                result.extend_from_slice(&bytes[start..]);
563                return result;
564            }
565        }
566
567        bytes[start..].to_vec()
568    }
569}
570
571// ---------------------------------------------------------------------------
572// ASN.1 Decoder
573// ---------------------------------------------------------------------------
574
575/// Decodes BER-encoded bytes into an `AsnValue` tree.
576#[cfg(feature = "alloc")]
577pub struct AsnDecoder;
578
579#[cfg(feature = "alloc")]
580impl AsnDecoder {
581    /// Decode a single ASN.1 TLV from the beginning of `data`.
582    ///
583    /// Returns `(value, bytes_consumed)`.
584    pub fn decode(data: &[u8]) -> Result<(AsnValue, usize), KernelError> {
585        if data.is_empty() {
586            return Err(KernelError::InvalidArgument {
587                name: "asn1_decode",
588                value: "empty input",
589            });
590        }
591
592        let (class, constructed, tag_number, tag_len) = decode_tag(data)?;
593        let (content_len, len_bytes) = decode_length(&data[tag_len..])?;
594        let header_len = tag_len + len_bytes;
595
596        if data.len() < header_len + content_len {
597            return Err(KernelError::InvalidArgument {
598                name: "asn1_decode",
599                value: "truncated content",
600            });
601        }
602
603        let content = &data[header_len..header_len + content_len];
604        let total = header_len + content_len;
605
606        // Context-specific tags
607        if class == TagClass::ContextSpecific || class == TagClass::Application {
608            return Ok((
609                AsnValue::ContextSpecific(tag_number, content.to_vec()),
610                total,
611            ));
612        }
613
614        // Universal tags
615        let value = if constructed {
616            match tag_number {
617                16 => {
618                    // SEQUENCE
619                    let items = Self::decode_sequence(content)?;
620                    AsnValue::Sequence(items)
621                }
622                17 => {
623                    // SET
624                    let items = Self::decode_sequence(content)?;
625                    AsnValue::Set(items)
626                }
627                _ => AsnValue::ContextSpecific(tag_number, content.to_vec()),
628            }
629        } else {
630            match tag_number {
631                1 => {
632                    // BOOLEAN
633                    if content.is_empty() {
634                        return Err(KernelError::InvalidArgument {
635                            name: "asn1_boolean",
636                            value: "empty",
637                        });
638                    }
639                    AsnValue::Boolean(content[0] != 0)
640                }
641                2 => {
642                    // INTEGER
643                    Self::decode_integer(content)?
644                }
645                3 => {
646                    // BIT STRING
647                    if content.is_empty() {
648                        return Err(KernelError::InvalidArgument {
649                            name: "asn1_bitstring",
650                            value: "empty",
651                        });
652                    }
653                    let unused_bits = content[0];
654                    AsnValue::BitString(content[1..].to_vec(), unused_bits)
655                }
656                4 => {
657                    // OCTET STRING
658                    AsnValue::OctetString(content.to_vec())
659                }
660                5 => {
661                    // NULL
662                    AsnValue::Null
663                }
664                6 => {
665                    // OID
666                    let arcs = decode_oid(content)?;
667                    AsnValue::Oid(arcs)
668                }
669                10 => {
670                    // ENUMERATED
671                    match Self::decode_integer(content)? {
672                        AsnValue::Integer(n) => AsnValue::Enumerated(n),
673                        AsnValue::BigInteger(b) => {
674                            // Treat as small if possible
675                            let n = Self::big_to_i64(&b);
676                            AsnValue::Enumerated(n)
677                        }
678                        _ => {
679                            return Err(KernelError::InvalidArgument {
680                                name: "asn1_enumerated",
681                                value: "unexpected decode",
682                            })
683                        }
684                    }
685                }
686                12 => {
687                    // UTF8String
688                    let s = core::str::from_utf8(content).map_err(|_| {
689                        KernelError::InvalidArgument {
690                            name: "asn1_utf8string",
691                            value: "invalid utf8",
692                        }
693                    })?;
694                    AsnValue::Utf8String(String::from(s))
695                }
696                19 => {
697                    // PrintableString
698                    let s = core::str::from_utf8(content).map_err(|_| {
699                        KernelError::InvalidArgument {
700                            name: "asn1_printablestring",
701                            value: "invalid utf8",
702                        }
703                    })?;
704                    AsnValue::PrintableString(String::from(s))
705                }
706                22 => {
707                    // IA5String
708                    let s = core::str::from_utf8(content).map_err(|_| {
709                        KernelError::InvalidArgument {
710                            name: "asn1_ia5string",
711                            value: "invalid utf8",
712                        }
713                    })?;
714                    AsnValue::Ia5String(String::from(s))
715                }
716                23 => {
717                    // UTCTime
718                    let s = core::str::from_utf8(content).map_err(|_| {
719                        KernelError::InvalidArgument {
720                            name: "asn1_utctime",
721                            value: "invalid utf8",
722                        }
723                    })?;
724                    AsnValue::UtcTime(String::from(s))
725                }
726                _ => AsnValue::OctetString(content.to_vec()),
727            }
728        };
729
730        Ok((value, total))
731    }
732
733    /// Decode a sequence of TLV items from concatenated content bytes.
734    fn decode_sequence(data: &[u8]) -> Result<Vec<AsnValue>, KernelError> {
735        let mut items = Vec::new();
736        let mut pos = 0;
737        while pos < data.len() {
738            let (value, consumed) = Self::decode(&data[pos..])?;
739            items.push(value);
740            pos += consumed;
741        }
742        Ok(items)
743    }
744
745    /// Decode an integer from content bytes.
746    ///
747    /// If the value fits in i64, returns `AsnValue::Integer`.
748    /// Otherwise returns `AsnValue::BigInteger`.
749    fn decode_integer(content: &[u8]) -> Result<AsnValue, KernelError> {
750        if content.is_empty() {
751            return Err(KernelError::InvalidArgument {
752                name: "asn1_integer",
753                value: "empty",
754            });
755        }
756
757        // Try to fit in i64 (up to 8 bytes)
758        if content.len() <= 8 {
759            let negative = content[0] & 0x80 != 0;
760            let mut value: i64 = if negative { -1 } else { 0 };
761            for &b in content {
762                value = (value << 8) | (b as i64);
763            }
764            Ok(AsnValue::Integer(value))
765        } else {
766            Ok(AsnValue::BigInteger(content.to_vec()))
767        }
768    }
769
770    /// Convert a BigInteger byte slice to i64 (truncating if too large).
771    fn big_to_i64(bytes: &[u8]) -> i64 {
772        if bytes.is_empty() {
773            return 0;
774        }
775        let negative = bytes[0] & 0x80 != 0;
776        let mut value: i64 = if negative { -1 } else { 0 };
777        let start = if bytes.len() > 8 { bytes.len() - 8 } else { 0 };
778        for &b in &bytes[start..] {
779            value = (value << 8) | (b as i64);
780        }
781        value
782    }
783}
784
785// ---------------------------------------------------------------------------
786// Builder API
787// ---------------------------------------------------------------------------
788
789/// Fluent builder for constructing ASN.1 values.
790///
791/// # Example
792///
793/// ```ignore
794/// let data = AsnBuilder::new()
795///     .sequence(|s| {
796///         s.integer(42)
797///          .octet_string(b"hello")
798///          .boolean(true)
799///     })
800///     .build();
801/// ```
802#[cfg(feature = "alloc")]
803pub struct AsnBuilder {
804    items: Vec<AsnValue>,
805}
806
807#[cfg(feature = "alloc")]
808impl Default for AsnBuilder {
809    fn default() -> Self {
810        Self::new()
811    }
812}
813
814#[cfg(feature = "alloc")]
815impl AsnBuilder {
816    /// Create a new empty builder.
817    pub fn new() -> Self {
818        Self { items: Vec::new() }
819    }
820
821    /// Add a BOOLEAN value.
822    pub fn boolean(mut self, value: bool) -> Self {
823        self.items.push(AsnValue::Boolean(value));
824        self
825    }
826
827    /// Add an INTEGER value.
828    pub fn integer(mut self, value: i64) -> Self {
829        self.items.push(AsnValue::Integer(value));
830        self
831    }
832
833    /// Add a BigInteger value (raw bytes, two's complement).
834    pub fn big_integer(mut self, bytes: &[u8]) -> Self {
835        self.items.push(AsnValue::BigInteger(bytes.to_vec()));
836        self
837    }
838
839    /// Add a BIT STRING value.
840    pub fn bit_string(mut self, data: &[u8], unused_bits: u8) -> Self {
841        self.items
842            .push(AsnValue::BitString(data.to_vec(), unused_bits));
843        self
844    }
845
846    /// Add an OCTET STRING value.
847    pub fn octet_string(mut self, data: &[u8]) -> Self {
848        self.items.push(AsnValue::OctetString(data.to_vec()));
849        self
850    }
851
852    /// Add a NULL value.
853    pub fn null(mut self) -> Self {
854        self.items.push(AsnValue::Null);
855        self
856    }
857
858    /// Add an OBJECT IDENTIFIER value.
859    pub fn oid(mut self, arcs: &[u32]) -> Self {
860        self.items.push(AsnValue::Oid(arcs.to_vec()));
861        self
862    }
863
864    /// Add a UTF8String value.
865    pub fn utf8_string(mut self, s: &str) -> Self {
866        self.items.push(AsnValue::Utf8String(String::from(s)));
867        self
868    }
869
870    /// Add an ENUMERATED value.
871    pub fn enumerated(mut self, value: i64) -> Self {
872        self.items.push(AsnValue::Enumerated(value));
873        self
874    }
875
876    /// Add a context-specific tagged value.
877    pub fn context_specific(mut self, number: u8, data: &[u8]) -> Self {
878        self.items
879            .push(AsnValue::ContextSpecific(number, data.to_vec()));
880        self
881    }
882
883    /// Add a context-specific tagged value wrapping an encoded ASN.1 value.
884    pub fn context_specific_value(mut self, number: u8, value: &AsnValue) -> Self {
885        let encoded = AsnEncoder::encode(value);
886        self.items.push(AsnValue::ContextSpecific(number, encoded));
887        self
888    }
889
890    /// Add a nested SEQUENCE built with a closure.
891    pub fn sequence<F>(mut self, f: F) -> Self
892    where
893        F: FnOnce(AsnBuilder) -> AsnBuilder,
894    {
895        let inner = f(AsnBuilder::new());
896        self.items.push(AsnValue::Sequence(inner.items));
897        self
898    }
899
900    /// Add a nested SET built with a closure.
901    pub fn set<F>(mut self, f: F) -> Self
902    where
903        F: FnOnce(AsnBuilder) -> AsnBuilder,
904    {
905        let inner = f(AsnBuilder::new());
906        self.items.push(AsnValue::Set(inner.items));
907        self
908    }
909
910    /// Add a raw pre-built AsnValue.
911    pub fn value(mut self, v: AsnValue) -> Self {
912        self.items.push(v);
913        self
914    }
915
916    /// Build the accumulated items.
917    ///
918    /// If there is exactly one item, returns its encoded form.
919    /// If there are multiple items, wraps them in a SEQUENCE.
920    pub fn build(self) -> Vec<u8> {
921        if self.items.len() == 1 {
922            AsnEncoder::encode(&self.items[0])
923        } else {
924            AsnEncoder::encode(&AsnValue::Sequence(self.items))
925        }
926    }
927
928    /// Build and return the items as an `AsnValue::Sequence`.
929    pub fn build_value(self) -> AsnValue {
930        if self.items.len() == 1 {
931            self.items.into_iter().next().unwrap_or(AsnValue::Null)
932        } else {
933            AsnValue::Sequence(self.items)
934        }
935    }
936}
937
938// ---------------------------------------------------------------------------
939// Helper: encode a context-specific wrapper around encoded content
940// ---------------------------------------------------------------------------
941
942/// Encode a context-specific tagged wrapper.
943///
944/// Produces `[tag_byte, length, content...]`.
945#[cfg(feature = "alloc")]
946pub fn encode_context_specific(number: u8, constructed: bool, content: &[u8]) -> Vec<u8> {
947    let mut out = Vec::new();
948    encode_tag(TagClass::ContextSpecific, constructed, number, &mut out);
949    encode_length(content.len(), &mut out);
950    out.extend_from_slice(content);
951    out
952}
953
954/// Encode an application-tagged wrapper.
955#[cfg(feature = "alloc")]
956pub fn encode_application(number: u8, constructed: bool, content: &[u8]) -> Vec<u8> {
957    let mut out = Vec::new();
958    encode_tag(TagClass::Application, constructed, number, &mut out);
959    encode_length(content.len(), &mut out);
960    out.extend_from_slice(content);
961    out
962}
963
964// ---------------------------------------------------------------------------
965// Tests
966// ---------------------------------------------------------------------------
967
968#[cfg(test)]
969mod tests {
970    use super::*;
971
972    #[test]
973    fn test_encode_length_short() {
974        let mut out = Vec::new();
975        encode_length(0, &mut out);
976        assert_eq!(out, [0x00]);
977
978        let mut out = Vec::new();
979        encode_length(127, &mut out);
980        assert_eq!(out, [0x7F]);
981    }
982
983    #[test]
984    fn test_encode_length_long() {
985        let mut out = Vec::new();
986        encode_length(128, &mut out);
987        assert_eq!(out, [0x81, 0x80]);
988
989        let mut out = Vec::new();
990        encode_length(256, &mut out);
991        assert_eq!(out, [0x82, 0x01, 0x00]);
992    }
993
994    #[test]
995    fn test_decode_length_short() {
996        let data = [0x05];
997        let (len, consumed) = decode_length(&data).unwrap();
998        assert_eq!(len, 5);
999        assert_eq!(consumed, 1);
1000    }
1001
1002    #[test]
1003    fn test_decode_length_long() {
1004        let data = [0x82, 0x01, 0x00];
1005        let (len, consumed) = decode_length(&data).unwrap();
1006        assert_eq!(len, 256);
1007        assert_eq!(consumed, 3);
1008    }
1009
1010    #[test]
1011    fn test_encode_decode_boolean() {
1012        let val = AsnValue::Boolean(true);
1013        let encoded = AsnEncoder::encode(&val);
1014        let (decoded, consumed) = AsnDecoder::decode(&encoded).unwrap();
1015        assert_eq!(consumed, encoded.len());
1016        assert_eq!(decoded, AsnValue::Boolean(true));
1017    }
1018
1019    #[test]
1020    fn test_encode_decode_integer_positive() {
1021        let val = AsnValue::Integer(42);
1022        let encoded = AsnEncoder::encode(&val);
1023        let (decoded, _) = AsnDecoder::decode(&encoded).unwrap();
1024        assert_eq!(decoded, AsnValue::Integer(42));
1025    }
1026
1027    #[test]
1028    fn test_encode_decode_integer_negative() {
1029        let val = AsnValue::Integer(-128);
1030        let encoded = AsnEncoder::encode(&val);
1031        let (decoded, _) = AsnDecoder::decode(&encoded).unwrap();
1032        assert_eq!(decoded, AsnValue::Integer(-128));
1033    }
1034
1035    #[test]
1036    fn test_encode_decode_integer_zero() {
1037        let val = AsnValue::Integer(0);
1038        let encoded = AsnEncoder::encode(&val);
1039        let (decoded, _) = AsnDecoder::decode(&encoded).unwrap();
1040        assert_eq!(decoded, AsnValue::Integer(0));
1041    }
1042
1043    #[test]
1044    fn test_encode_decode_null() {
1045        let val = AsnValue::Null;
1046        let encoded = AsnEncoder::encode(&val);
1047        assert_eq!(encoded, [0x05, 0x00]);
1048        let (decoded, _) = AsnDecoder::decode(&encoded).unwrap();
1049        assert_eq!(decoded, AsnValue::Null);
1050    }
1051
1052    #[test]
1053    fn test_encode_decode_octet_string() {
1054        let val = AsnValue::OctetString(vec![0x01, 0x02, 0x03]);
1055        let encoded = AsnEncoder::encode(&val);
1056        let (decoded, _) = AsnDecoder::decode(&encoded).unwrap();
1057        assert_eq!(decoded, val);
1058    }
1059
1060    #[test]
1061    fn test_encode_decode_utf8_string() {
1062        let val = AsnValue::Utf8String(String::from("hello"));
1063        let encoded = AsnEncoder::encode(&val);
1064        let (decoded, _) = AsnDecoder::decode(&encoded).unwrap();
1065        assert_eq!(decoded, AsnValue::Utf8String(String::from("hello")));
1066    }
1067
1068    #[test]
1069    fn test_encode_decode_oid() {
1070        // OID 1.2.840.113549.1.1.1 (RSA encryption)
1071        let val = AsnValue::Oid(vec![1, 2, 840, 113549, 1, 1, 1]);
1072        let encoded = AsnEncoder::encode(&val);
1073        let (decoded, _) = AsnDecoder::decode(&encoded).unwrap();
1074        assert_eq!(decoded, val);
1075    }
1076
1077    #[test]
1078    fn test_encode_decode_sequence() {
1079        let val = AsnValue::Sequence(vec![
1080            AsnValue::Integer(1),
1081            AsnValue::Boolean(true),
1082            AsnValue::OctetString(vec![0xAB]),
1083        ]);
1084        let encoded = AsnEncoder::encode(&val);
1085        let (decoded, _) = AsnDecoder::decode(&encoded).unwrap();
1086        assert_eq!(decoded, val);
1087    }
1088
1089    #[test]
1090    fn test_encode_decode_enumerated() {
1091        let val = AsnValue::Enumerated(3);
1092        let encoded = AsnEncoder::encode(&val);
1093        let (decoded, _) = AsnDecoder::decode(&encoded).unwrap();
1094        assert_eq!(decoded, AsnValue::Enumerated(3));
1095    }
1096
1097    #[test]
1098    fn test_encode_decode_bit_string() {
1099        let val = AsnValue::BitString(vec![0xFF, 0x80], 1);
1100        let encoded = AsnEncoder::encode(&val);
1101        let (decoded, _) = AsnDecoder::decode(&encoded).unwrap();
1102        assert_eq!(decoded, val);
1103    }
1104
1105    #[test]
1106    fn test_builder_single_value() {
1107        let data = AsnBuilder::new().integer(42).build();
1108        let (decoded, _) = AsnDecoder::decode(&data).unwrap();
1109        assert_eq!(decoded, AsnValue::Integer(42));
1110    }
1111
1112    #[test]
1113    fn test_builder_sequence() {
1114        let data = AsnBuilder::new()
1115            .sequence(|s| s.integer(1).boolean(false).null())
1116            .build();
1117        let (decoded, _) = AsnDecoder::decode(&data).unwrap();
1118        match decoded {
1119            AsnValue::Sequence(items) => {
1120                assert_eq!(items.len(), 3);
1121                assert_eq!(items[0], AsnValue::Integer(1));
1122                assert_eq!(items[1], AsnValue::Boolean(false));
1123                assert_eq!(items[2], AsnValue::Null);
1124            }
1125            _ => panic!("expected sequence"),
1126        }
1127    }
1128
1129    #[test]
1130    fn test_decode_truncated_returns_error() {
1131        let data: &[u8] = &[0x02, 0x05, 0x01]; // integer with length 5 but only 1 byte of content
1132        let result = AsnDecoder::decode(data);
1133        assert!(result.is_err());
1134    }
1135
1136    #[test]
1137    fn test_tag_encode_decode_roundtrip() {
1138        let mut out = Vec::new();
1139        encode_tag(TagClass::Application, true, 3, &mut out);
1140        let (class, constructed, number, _) = decode_tag(&out).unwrap();
1141        assert_eq!(class, TagClass::Application);
1142        assert!(constructed);
1143        assert_eq!(number, 3);
1144    }
1145}