// SPDX-FileCopyrightText: © 2022—2026 Vladimir Zorin // SPDX-License-Identifier: LicenseRef-OWL-1.0-or-later // Licensed under OWL v1.0+. See LICENSE. /* * LITLS -- Lilush TLS Stack * Minimal ASN.1/DER reader and writer for X.509 parsing and CSR generation. * * Internal header -- not part of the public litls.h API. */ #ifndef LITLS_ASN1_H #define LITLS_ASN1_H #include #include /* ── ASN.1 tag constants ──────────────────────────────── */ #define ASN1_BOOLEAN 0x01 #define ASN1_INTEGER 0x02 #define ASN1_BIT_STRING 0x03 #define ASN1_OCTET_STRING 0x04 #define ASN1_NULL 0x05 #define ASN1_OID 0x06 #define ASN1_UTF8STRING 0x0C #define ASN1_PRINTABLESTRING 0x13 #define ASN1_IA5STRING 0x16 #define ASN1_UTCTIME 0x17 #define ASN1_GENERALIZEDTIME 0x18 #define ASN1_SEQUENCE 0x30 #define ASN1_SET 0x31 #define ASN1_CONTEXT(n) (0xA0 | (n)) /* ── DER reader ───────────────────────────────────────── */ typedef struct { const uint8_t *buf; size_t len; size_t pos; } litls_der_cursor; typedef struct { uint8_t tag; const uint8_t *value; size_t length; /* Total bytes consumed (tag + length octets + value) */ size_t total; } litls_der_element; /* Initialize cursor over a DER buffer. */ void litls_der_init(litls_der_cursor *c, const uint8_t *buf, size_t len); /* Read the next TLV element. Returns 0 on success, -1 on end/error. */ int litls_der_next(litls_der_cursor *c, litls_der_element *elem); /* Create a sub-cursor bounded to elem's value bytes. Returns 0. */ int litls_der_enter(litls_der_cursor *sub, const litls_der_element *elem); /* Skip over the next element without returning it. Returns 0 or -1. */ int litls_der_skip(litls_der_cursor *c); /* Peek at the tag of the next element without advancing. Returns -1 at end. */ int litls_der_peek_tag(const litls_der_cursor *c, uint8_t *tag); /* Returns bytes remaining in the cursor. */ size_t litls_der_remaining(const litls_der_cursor *c); /* Compare an OID element's value against a known OID. Returns 1 on match. */ int litls_der_oid_eq(const litls_der_element *elem, const uint8_t *oid, size_t oid_len); /* Parse UTCTime or GeneralizedTime into a Unix timestamp. * Returns 0 on success, -1 on parse error. */ int litls_der_parse_time(const litls_der_element *elem, int64_t *ts); /* ── DER writer ───────────────────────────────────────── */ typedef struct { uint8_t *buf; size_t cap; size_t len; int err; /* set to -1 on overflow */ } litls_der_writer; void litls_der_writer_init(litls_der_writer *w, uint8_t *buf, size_t cap); /* Write a complete TLV. Returns 0 or -1. */ int litls_der_write_tlv(litls_der_writer *w, uint8_t tag, const uint8_t *value, size_t length); /* Write an OID element. */ int litls_der_write_oid(litls_der_writer *w, const uint8_t *oid, size_t oid_len); /* Write an INTEGER from raw big-endian bytes (adds leading 0x00 if high bit set). */ int litls_der_write_integer(litls_der_writer *w, const uint8_t *val, size_t val_len); /* Start a SEQUENCE. Returns a marker for litls_der_end_sequence. */ size_t litls_der_begin_sequence(litls_der_writer *w); /* Start a SET. Returns a marker for litls_der_end_constructed. */ size_t litls_der_begin_set(litls_der_writer *w); /* Start a context-tagged constructed element [n]. */ size_t litls_der_begin_context(litls_der_writer *w, int n); /* Finalize a constructed element (SEQUENCE/SET/CONTEXT) started at marker. * Back-patches the length field. Returns 0 or -1. */ int litls_der_end_constructed(litls_der_writer *w, size_t marker); /* Write a BIT STRING wrapping raw bytes (prepends unused-bits=0 octet). */ int litls_der_write_bit_string(litls_der_writer *w, const uint8_t *data, size_t data_len); /* Write raw bytes directly (no tag/length). For building sub-structures. */ int litls_der_write_raw(litls_der_writer *w, const uint8_t *data, size_t len); #endif /* LITLS_ASN1_H */