Updated USING.MD with current state
[quick-der] / PACK-SYNTAX.MD
1 # Syntax for Packing Paths
2
3 <img alt="Quick DER logo" src="quick-der-logo.png" style="float: right;"/>
4
5 This specification describes the path format used by `der_unpack()` and
6 `der_pack()` to pass through a DER binary and map it to (or from) an array
7 of `dercursor` values.
8
9 A simpler variation of a similar idea is the
10 [WALK SYNTAX](WALK-SYNTAX.MD),
11 which limits itself to finding a single element, but also based on a
12 (different) walking path expression.
13
14 ## Declaring and Using a Walking Path
15
16 The walk path is described as a sequence of values that ends in `DER_PACK_END`:
17
18     #include <quick-der/api.h>
19
20     derwalk path_demo [] = {
21             ...,
22             DER_PACK_END
23     }
24
25 which is then used to unpack the DER binary data under a `dercursor crs` with
26
27     int prsok;
28     prsok = der_unpack (&crs, path_demo, outputs, 1);
29
30 The `outputs` is an array of `dercursor` that will be filled with information
31 found in the `path_demo`.  Explicit storage instructions will put the information
32 there, so the required size of the array is equal to the fixed number of such
33 instructions in `path_demo`.
34
35 ## Diving in Head-First
36
37 The path described by `path_demo` should be a depth-first traversal of a
38 *static* structure.  That means that `SEQUENCE OF` and `SET OF`, the two ways
39 of expressing dynamically sized structures in ASN.1, require special handling.
40
41 To dive in, use a flag `DER_PACK_ENTER` and to leave a nested structure, use
42 the `DER_PACK_LEAVE` flag.  To store intermediate values, use `DER_PACK_STORE`
43 as a flag, as in
44
45     derwalk path_demo [] = {
46             DER_PACK_ENTER | ...,
47             DER_PACK_STORE | ...,
48             ...,
49             DER_PACK_LEAVE,
50             DER_PACK_END
51     }
52
53 Note that `DER_PACK_LEAVE` is an instruction on its own.  The other two
54 forms are extended with a tag that is verified to match, for instance
55
56     derwalk path_demo [] = {
57             DER_PACK_ENTER | DER_TAG_SEQUENCE,
58             DER_PACK_ENTER | DER_TAG_CONTEXT (0),
59             DER_PACK_STORE | DER_TAG_INTEGER,
60             DER_PACK_LEAVE,
61             DER_PACK_STORE | DER_TAG_OCTETSTRING,
62             DER_PACK_LEAVE,
63             DER_PACK_END
64     }
65
66 An example ASN.1 structure that could be traversed by this would be
67
68     demoStruct ::= SEQUENCE {
69             demoCounter [0] INTEGER,
70             demoName OCTET STRING
71     }
72
73 After invoking `der_unpack()` on this path, there are two values in the `output`
74 array of `dercursor`, namely for the two `DER_PACK_STORE` instructions.  From the
75 following input data
76
77     30 16                                -- tag SEQUENCE, length 16
78        a0 03                             -- tag a0 for [0], length 3
79           02 01 07                       -- tag INTEGER, length 1, value 7
80        04 09 51 75 69 63 6b 20 44 45 52  -- tag 4, length 9, "Quick DER"
81
82 this would make `output[0]` point to the `INTEGER` value 7, with 1 byte length,
83 and `output[1]` would point to the `OCTETSTRING` contents "Quick DER", with a
84 length of 9 bytes.
85
86 Note how nothing remains of the DER tags or lengths.  This is what you should
87 expect from a Quick and Easy DER parser.
88
89 ## Dealing with Variable Structures
90
91 It is possible to not store everything we encounter.  In the previous situation
92 we might have used
93
94     derwalk path_demo [] = {
95             DER_PACK_ENTER | DER_TAG_SEQUENCE,
96             DER_PACK_STORE | DER_TAG_CONTEXT (0),
97             DER_PACK_STORE | DER_TAG_OCTETSTRING,
98             DER_PACK_LEAVE,
99             DER_PACK_END
100     }
101
102 to find `output[0]` set to the DER sequence *contained in* `[0] INTEGER`,
103 which means the `INTEGER` in DER coding, so in hex
104 the bytes `02 01 07` instead of just to `07`.  This can be useful at
105 some times.
106
107 Imagine the ASN.1 structure
108
109     aFewPrimes ::= SET OF INTEGER
110
111 which is a `SET OF` and can thus contain as many `INTEGER` values as desired.
112 An example hexdump of a DER value listing the first 5 primes would be
113
114     31 0f        -- SET, containing 15 bytes
115        02 01 02  -- INTEGER 2
116        02 01 03  -- INTEGER 3
117        02 01 05  -- INTEGER 5
118        02 01 07  -- INTEGER 7
119        02 01 0b  -- INTEGER 11
120
121 If we had to store each `INTEGER` in a separate `output[]` entry, we would need
122 a variable-sized output array.  What `der_unpack()` does in these cases is the
123 same as demonstrated for `[0] INTEGER` above; it stores the entire structure
124 *contained inside* the `SET OF` and leaves it for further processing.
125
126 The path expression to store this set would be
127
128     derwalk path_primes [] = {
129             DER_PACK_STORE | DER_TAG_SET_OF,
130             DER_PACK_END
131     }
132
133 The result would be stored in `output[0]` as the sequence `02 01 02 ...`
134 of length 15.  It is now possible to do a few things:
135
136   * use `der_iterate_first()` and `der_iterate_next()` to find the individual
137     values in the set;
138   * manually skip through the list with `der_skip()` until it hits the end of
139     the set;
140   * counting the entries with `der_countelements()` and then allocate an array
141     `dercursor primal[5]`, in the heap or on the stack, and pass it into
142     `der_unpack ()` with the last parameter set to the count of 5.
143
144
145 ## Optionals, Choices and the ANYs
146
147 Not everything declared in ASN.1 is included in the binary DER format.
148 Some parts are `OPTIONAL` (and may have a `DEFAULT`, which Quick DER does not
149 capture) and others are a `CHOICE` from variants.
150
151 To encode an option, prefix `DER_PACK_OPTIONAL,` to the optional part.  If the
152 optional part is flagged wth `DER_PACK_ENTER`, then the optionality will
153 continue to the corresponding `DER_PACK_LEAVE`.  Note that ASN.1 ensures that
154 the DER format can always be parsed based on a singly tag lookahead, which we
155 exploit in this case.
156
157 A somewhat similar structure is the `CHOICE` which permits choosing a syntax
158 variety from among alternatives.  Again, ASN.1 ensures that parsing can be done
159 based on the first tag.  We use this once more, for paths between
160 `DER_PACK_CHOICE_BEGIN` and `DER_PACK_CHOICE_END`.  Note that the programmer
161 of the walking path is responsible for proper nesting, also with respect to
162 `ENTER`/`LEAVE` structure.
163
164 Finally, the forms `ANY` and `ANY DEFINED BY` are used in ASN.1 to describe
165 wildcard typing.  These have no representation in DER either, but at the
166 point where it comes across the `DER_PACK_STORE | DER_PACK_ANY` instruction,
167 it will match anything, and store the result in the output array of
168 `dercursor`.  The stored result is special however, in that it includes the
169 entire DER structure including tag and length bytes.  This is because you
170 will have to do further processing.
171
172
173 ## Overlay structures
174
175 The idea of static structure is a great benefit to us as programmers, because
176 we can create overlay structures that consist solely of `dercursor` and other
177 overlay structures.  These give us a way to navigate through the data using
178 ASN.1 labels.
179
180 The first ASN.1 structure
181
182     demoStruct ::= SEQUENCE {
183             demoCounter [0] INTEGER,
184             demoName OCTET STRING
185     }
186
187 could be overlaid with the C structure
188
189     typedef struct {
190             dercursor demoCounter;
191             dercursor demoName;
192     } ovly_demoStruct;
193
194 and the program could declare
195
196     ovly_demoStruct output;
197
198 and pass that to `der_unpack()` as `(dercursor *) &output` for type correctness.
199
200 The datafields could then be addressed with something like
201
202     printf ("Found \"%.*s\"\n", output.demoName.derlen, output.demoName.derptr);
203
204
205 ## Repacking
206
207 There is a function `der_pack()` that does the exact opposite of `der_unpack()`,
208 using the same walking paths.
209
210 *Something to ignore until you run into trouble:*
211 You may need to `der_prepack()` first if you have nested elements that are not
212 a `SET (OF)` or `SEQUENCE (OF)` or other form that is always Constructed.
213 Without `der_prepack()` your DER representation may end up being Primitive.
214
215
216 ## ASN.1 Compiler and RFC Library
217
218 The can generate this syntax automatically from common ASN.1 files, including
219 the overlay structures.  The result of this is a headerfile providing macros
220 that can fill paths, and structures that capture the structure of ASN.1 and
221 specifically the labels used.
222
223 Now we have a compiler, we have started to collect RFCs (and we may later add
224 other specifications) that use ASN.1 syntax, and to derive their header files
225 for distribution in the developer version of Quick and Easy DER.
226
227 These things combined enable you to specify things like
228
229     #include <quick-der/api.h>
230     #include <quick-der/rfc5280.h>
231
232     typedef DER_OVLY_rfc5280_Certificate Certificate;
233     derwalk path_cert [] = { DER_PACK_rfc5280_Certificate, DER_PACK_END };
234
235     void print (dercursor *input) {
236             Certificate crt;
237             if (der_unpack (&input, path_cert, (dercursor *) &crt, 1) == 0) {
238                     ...crt.tbsCertificate.issuer...
239             }
240     }
241
242 In short, you are already up and running with DER-encoded PKIX Certificates.
243
244 And it will be
245
246 Quick... and Easy!