File Coverage

include/pdfmake_asn1.h
Criterion Covered Total %
statement 2 2 100.0
branch 2 4 50.0
condition n/a
subroutine n/a
pod n/a
total 4 6 66.6


line stmt bran cond sub pod time code
1             /*
2             * pdfmake_asn1.h — ASN.1 DER encoding/decoding
3             *
4             * Minimal ASN.1 DER codec for X.509, PKCS#7, PKCS#12 parsing and building.
5             * ISO 32000-2:2020 §12.8 (Digital Signatures)
6             */
7              
8             #ifndef PDFMAKE_ASN1_H
9             #define PDFMAKE_ASN1_H
10              
11             #include "pdfmake.h"
12             #include "pdfmake_buf.h"
13             #include
14             #include
15              
16             /*============================================================================
17             * ASN.1 Tag Classes and Types
18             *==========================================================================*/
19              
20             /* Tag class (bits 7-6) */
21             #define ASN1_CLASS_UNIVERSAL 0x00
22             #define ASN1_CLASS_APPLICATION 0x40
23             #define ASN1_CLASS_CONTEXT 0x80
24             #define ASN1_CLASS_PRIVATE 0xC0
25             #define ASN1_CLASS_MASK 0xC0
26              
27             /* Constructed flag (bit 5) */
28             #define ASN1_CONSTRUCTED 0x20
29              
30             /* Universal tags */
31             #define ASN1_TAG_EOC 0x00
32             #define ASN1_TAG_BOOLEAN 0x01
33             #define ASN1_TAG_INTEGER 0x02
34             #define ASN1_TAG_BIT_STRING 0x03
35             #define ASN1_TAG_OCTET_STRING 0x04
36             #define ASN1_TAG_NULL 0x05
37             #define ASN1_TAG_OID 0x06
38             #define ASN1_TAG_OBJECT_DESC 0x07
39             #define ASN1_TAG_EXTERNAL 0x08
40             #define ASN1_TAG_REAL 0x09
41             #define ASN1_TAG_ENUMERATED 0x0A
42             #define ASN1_TAG_EMBEDDED_PDV 0x0B
43             #define ASN1_TAG_UTF8STRING 0x0C
44             #define ASN1_TAG_RELATIVE_OID 0x0D
45             #define ASN1_TAG_SEQUENCE 0x10
46             #define ASN1_TAG_SET 0x11
47             #define ASN1_TAG_NUMERICSTRING 0x12
48             #define ASN1_TAG_PRINTABLESTRING 0x13
49             #define ASN1_TAG_T61STRING 0x14
50             #define ASN1_TAG_VIDEOTEXSTRING 0x15
51             #define ASN1_TAG_IA5STRING 0x16
52             #define ASN1_TAG_UTCTIME 0x17
53             #define ASN1_TAG_GENERALIZEDTIME 0x18
54             #define ASN1_TAG_GRAPHICSTRING 0x19
55             #define ASN1_TAG_VISIBLESTRING 0x1A
56             #define ASN1_TAG_GENERALSTRING 0x1B
57             #define ASN1_TAG_UNIVERSALSTRING 0x1C
58             #define ASN1_TAG_BMPSTRING 0x1E
59              
60             /*============================================================================
61             * ASN.1 Node Structure
62             *==========================================================================*/
63              
64             typedef struct pdfmake_asn1_node pdfmake_asn1_node_t;
65              
66             struct pdfmake_asn1_node {
67             uint8_t tag; /* Full tag byte (class + constructed + number) */
68             size_t length; /* Content length */
69             const uint8_t *data; /* Pointer to content (within original buffer) */
70            
71             /* For constructed types */
72             pdfmake_asn1_node_t *children; /* Linked list of children */
73             pdfmake_asn1_node_t *next; /* Next sibling */
74            
75             /* Parent reference (for navigation) */
76             pdfmake_asn1_node_t *parent;
77             };
78              
79             /*============================================================================
80             * Tag predicates (inline)
81             *==========================================================================*/
82              
83             /* True iff `node` is a constructed SEQUENCE (0x30). Safe on NULL. */
84 17           static PDFMAKE_INLINE int pdfmake_asn1_is_sequence(const pdfmake_asn1_node_t *node) {
85 17 50         return node && node->tag == (ASN1_TAG_SEQUENCE | ASN1_CONSTRUCTED);
    50          
86             }
87              
88             /* True iff `node` is a constructed SET (0x31). Safe on NULL. */
89             static PDFMAKE_INLINE int pdfmake_asn1_is_set(const pdfmake_asn1_node_t *node) {
90             return node && node->tag == (ASN1_TAG_SET | ASN1_CONSTRUCTED);
91             }
92              
93             /*============================================================================
94             * Parsing API
95             *==========================================================================*/
96              
97             /*
98             * Parse DER-encoded data into an ASN.1 tree.
99             * Returns root node allocated from arena, or NULL on error.
100             */
101             pdfmake_asn1_node_t *pdfmake_asn1_parse(
102             pdfmake_arena_t *arena,
103             const uint8_t *data,
104             size_t len
105             );
106              
107             /*
108             * Parse a single ASN.1 element (tag + length + content).
109             * Updates *pos to point past the element.
110             * Returns node or NULL on error.
111             */
112             pdfmake_asn1_node_t *pdfmake_asn1_parse_element(
113             pdfmake_arena_t *arena,
114             const uint8_t *data,
115             size_t len,
116             size_t *pos
117             );
118              
119             /*
120             * Get number of children for a constructed node.
121             */
122             size_t pdfmake_asn1_child_count(const pdfmake_asn1_node_t *node);
123              
124             /*
125             * Get child at index (0-based).
126             */
127             pdfmake_asn1_node_t *pdfmake_asn1_child_at(
128             const pdfmake_asn1_node_t *node,
129             size_t index
130             );
131              
132             /*
133             * Find child by tag.
134             */
135             pdfmake_asn1_node_t *pdfmake_asn1_find_tag(
136             const pdfmake_asn1_node_t *node,
137             uint8_t tag
138             );
139              
140             /*============================================================================
141             * Value Extraction
142             *==========================================================================*/
143              
144             /*
145             * Extract integer value (for small integers that fit in int64_t).
146             * Returns 0 on success, -1 on error.
147             */
148             int pdfmake_asn1_get_int64(const pdfmake_asn1_node_t *node, int64_t *out);
149              
150             /*
151             * Extract unsigned integer value.
152             */
153             int pdfmake_asn1_get_uint64(const pdfmake_asn1_node_t *node, uint64_t *out);
154              
155             /*
156             * Extract boolean value.
157             */
158             int pdfmake_asn1_get_bool(const pdfmake_asn1_node_t *node, int *out);
159              
160             /*
161             * Extract OID as dot-separated string (e.g., "1.2.840.113549.1.7.2").
162             * Caller must free returned string.
163             */
164             char *pdfmake_asn1_get_oid_string(
165             pdfmake_arena_t *arena,
166             const pdfmake_asn1_node_t *node
167             );
168              
169             /*
170             * Compare OID with expected value.
171             */
172             int pdfmake_asn1_oid_equals(
173             const pdfmake_asn1_node_t *node,
174             const char *oid_str
175             );
176              
177             /*
178             * Extract string (works for various string types).
179             * Returns arena-allocated null-terminated string.
180             */
181             char *pdfmake_asn1_get_string(
182             pdfmake_arena_t *arena,
183             const pdfmake_asn1_node_t *node
184             );
185              
186             /*
187             * Extract UTCTime or GeneralizedTime as Unix timestamp.
188             */
189             int pdfmake_asn1_get_time(const pdfmake_asn1_node_t *node, int64_t *out);
190              
191             /*
192             * Extract bit string (returns pointer to bits and bit count).
193             */
194             int pdfmake_asn1_get_bit_string(
195             const pdfmake_asn1_node_t *node,
196             const uint8_t **bits,
197             size_t *bit_count
198             );
199              
200             /*============================================================================
201             * Encoding API
202             *==========================================================================*/
203              
204             /*
205             * ASN.1 DER encoder context.
206             */
207             typedef struct pdfmake_asn1_encoder pdfmake_asn1_encoder_t;
208              
209             struct pdfmake_asn1_encoder {
210             pdfmake_buf_t *buf;
211             pdfmake_arena_t *arena;
212             };
213              
214             /*
215             * Initialize encoder.
216             */
217             pdfmake_err_t pdfmake_asn1_encoder_init(
218             pdfmake_asn1_encoder_t *enc,
219             pdfmake_arena_t *arena,
220             pdfmake_buf_t *buf
221             );
222              
223             /*
224             * Write tag and length header.
225             */
226             pdfmake_err_t pdfmake_asn1_write_header(
227             pdfmake_asn1_encoder_t *enc,
228             uint8_t tag,
229             size_t length
230             );
231              
232             /*
233             * Write complete TLV for various types.
234             */
235             pdfmake_err_t pdfmake_asn1_write_null(pdfmake_asn1_encoder_t *enc);
236             pdfmake_err_t pdfmake_asn1_write_bool(pdfmake_asn1_encoder_t *enc, int value);
237             pdfmake_err_t pdfmake_asn1_write_int64(pdfmake_asn1_encoder_t *enc, int64_t value);
238             pdfmake_err_t pdfmake_asn1_write_uint64(pdfmake_asn1_encoder_t *enc, uint64_t value);
239              
240             /*
241             * Write integer from big-endian byte array.
242             */
243             pdfmake_err_t pdfmake_asn1_write_integer(
244             pdfmake_asn1_encoder_t *enc,
245             const uint8_t *bytes,
246             size_t len
247             );
248              
249             /*
250             * Write OID from dot-separated string.
251             */
252             pdfmake_err_t pdfmake_asn1_write_oid(
253             pdfmake_asn1_encoder_t *enc,
254             const char *oid_str
255             );
256              
257             /*
258             * Write octet string.
259             */
260             pdfmake_err_t pdfmake_asn1_write_octet_string(
261             pdfmake_asn1_encoder_t *enc,
262             const uint8_t *data,
263             size_t len
264             );
265              
266             /*
267             * Write bit string.
268             */
269             pdfmake_err_t pdfmake_asn1_write_bit_string(
270             pdfmake_asn1_encoder_t *enc,
271             const uint8_t *bits,
272             size_t bit_count
273             );
274              
275             /*
276             * Write UTF-8 string.
277             */
278             pdfmake_err_t pdfmake_asn1_write_utf8_string(
279             pdfmake_asn1_encoder_t *enc,
280             const char *str
281             );
282              
283             /*
284             * Write printable string.
285             */
286             pdfmake_err_t pdfmake_asn1_write_printable_string(
287             pdfmake_asn1_encoder_t *enc,
288             const char *str
289             );
290              
291             /*
292             * Write IA5 string.
293             */
294             pdfmake_err_t pdfmake_asn1_write_ia5_string(
295             pdfmake_asn1_encoder_t *enc,
296             const char *str
297             );
298              
299             /*
300             * Write UTCTime.
301             */
302             pdfmake_err_t pdfmake_asn1_write_utc_time(
303             pdfmake_asn1_encoder_t *enc,
304             int64_t timestamp
305             );
306              
307             /*
308             * Write GeneralizedTime.
309             */
310             pdfmake_err_t pdfmake_asn1_write_generalized_time(
311             pdfmake_asn1_encoder_t *enc,
312             int64_t timestamp
313             );
314              
315             /*
316             * Begin a SEQUENCE or SET (returns position for length fixup).
317             */
318             size_t pdfmake_asn1_begin_sequence(pdfmake_asn1_encoder_t *enc);
319             size_t pdfmake_asn1_begin_set(pdfmake_asn1_encoder_t *enc);
320              
321             /*
322             * Begin context-tagged element.
323             */
324             size_t pdfmake_asn1_begin_context(
325             pdfmake_asn1_encoder_t *enc,
326             uint8_t tag_number,
327             int constructed
328             );
329              
330             /*
331             * End constructed element and fix up length.
332             */
333             pdfmake_err_t pdfmake_asn1_end_constructed(
334             pdfmake_asn1_encoder_t *enc,
335             size_t start_pos
336             );
337              
338             /*
339             * Write raw bytes (for embedding pre-encoded content).
340             */
341             pdfmake_err_t pdfmake_asn1_write_raw(
342             pdfmake_asn1_encoder_t *enc,
343             const uint8_t *data,
344             size_t len
345             );
346              
347             /*============================================================================
348             * Common OIDs
349             *==========================================================================*/
350              
351             /* PKCS#7 / CMS */
352             #define OID_PKCS7_DATA "1.2.840.113549.1.7.1"
353             #define OID_PKCS7_SIGNED_DATA "1.2.840.113549.1.7.2"
354             #define OID_PKCS7_ENVELOPED_DATA "1.2.840.113549.1.7.3"
355             #define OID_PKCS7_DIGESTED_DATA "1.2.840.113549.1.7.5"
356             #define OID_PKCS7_ENCRYPTED_DATA "1.2.840.113549.1.7.6"
357              
358             /* Hash algorithms */
359             #define OID_SHA1 "1.3.14.3.2.26"
360             #define OID_SHA256 "2.16.840.1.101.3.4.2.1"
361             #define OID_SHA384 "2.16.840.1.101.3.4.2.2"
362             #define OID_SHA512 "2.16.840.1.101.3.4.2.3"
363              
364             /* Signature algorithms */
365             #define OID_RSA_ENCRYPTION "1.2.840.113549.1.1.1"
366             #define OID_SHA1_WITH_RSA "1.2.840.113549.1.1.5"
367             #define OID_SHA256_WITH_RSA "1.2.840.113549.1.1.11"
368             #define OID_SHA384_WITH_RSA "1.2.840.113549.1.1.12"
369             #define OID_SHA512_WITH_RSA "1.2.840.113549.1.1.13"
370             #define OID_RSA_PSS "1.2.840.113549.1.1.10"
371              
372             /* ECDSA */
373             #define OID_EC_PUBLIC_KEY "1.2.840.10045.2.1"
374             #define OID_ECDSA_WITH_SHA256 "1.2.840.10045.4.3.2"
375             #define OID_ECDSA_WITH_SHA384 "1.2.840.10045.4.3.3"
376             #define OID_ECDSA_WITH_SHA512 "1.2.840.10045.4.3.4"
377              
378             /* Named curves */
379             #define OID_PRIME256V1 "1.2.840.10045.3.1.7"
380             #define OID_SECP384R1 "1.3.132.0.34"
381             #define OID_SECP521R1 "1.3.132.0.35"
382              
383             /* X.509 attribute types */
384             #define OID_COMMON_NAME "2.5.4.3"
385             #define OID_COUNTRY "2.5.4.6"
386             #define OID_LOCALITY "2.5.4.7"
387             #define OID_STATE "2.5.4.8"
388             #define OID_ORGANIZATION "2.5.4.10"
389             #define OID_ORG_UNIT "2.5.4.11"
390             #define OID_EMAIL "1.2.840.113549.1.9.1"
391              
392             /* X.509 extensions */
393             #define OID_BASIC_CONSTRAINTS "2.5.29.19"
394             #define OID_KEY_USAGE "2.5.29.15"
395             #define OID_EXT_KEY_USAGE "2.5.29.37"
396             #define OID_SUBJECT_KEY_ID "2.5.29.14"
397             #define OID_AUTHORITY_KEY_ID "2.5.29.35"
398             #define OID_SUBJECT_ALT_NAME "2.5.29.17"
399              
400             /* PKCS#9 attributes */
401             #define OID_CONTENT_TYPE "1.2.840.113549.1.9.3"
402             #define OID_MESSAGE_DIGEST "1.2.840.113549.1.9.4"
403             #define OID_SIGNING_TIME "1.2.840.113549.1.9.5"
404              
405             /* PKCS#12 */
406             #define OID_PKCS12_KEY_BAG "1.2.840.113549.1.12.10.1.1"
407             #define OID_PKCS12_PKCS8_KEY_BAG "1.2.840.113549.1.12.10.1.2"
408             #define OID_PKCS12_CERT_BAG "1.2.840.113549.1.12.10.1.3"
409             #define OID_PKCS12_CRL_BAG "1.2.840.113549.1.12.10.1.4"
410             #define OID_PKCS12_SECRET_BAG "1.2.840.113549.1.12.10.1.5"
411             #define OID_PKCS12_SAFE_CONTENTS "1.2.840.113549.1.12.10.1.6"
412              
413             /* PBE algorithms */
414             #define OID_PBE_SHA1_3DES "1.2.840.113549.1.12.1.3"
415             #define OID_PBE_SHA1_RC2_40 "1.2.840.113549.1.12.1.6"
416             #define OID_PBES2 "1.2.840.113549.1.5.13"
417             #define OID_PBKDF2 "1.2.840.113549.1.5.12"
418              
419             #endif /* PDFMAKE_ASN1_H */