Software APIs
asn1.h
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #ifndef OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_CERT_ASN1_H_
6 #define OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_CERT_ASN1_H_
7 
10 #include "sw/device/silicon_creator/lib/error.h"
11 
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15 
16 /**
17  * Structure holding the state of the asn1 generator.
18  *
19  * The fields in this structure should be considered
20  * private and not be read or written directly.
21  */
22 typedef struct asn1_state {
23  // Buffer containing the output.
24  uint8_t *buffer;
25  // Size of the output buffer.
26  size_t size;
27  // Current offset in the output.
28  size_t offset;
29  // Tracking the last active error.
30  // When there is an active error, all operations other than `asn1_start`,
31  // `asn1_finish` and `asn1_clear_error` will be no-op.
32  rom_error_t error;
33 } asn1_state_t;
34 
35 /**
36  * Clear the ASN1 builder active error in the `state`.
37  *
38  * @param[out] state Pointer to a user-allocated state to be cleared.
39  */
40 void asn1_clear_error(asn1_state_t *state);
41 
42 /**
43  * Start generating an ASN1 stream.
44  *
45  * @param[out] new_state Pointer to a user-allocated state to be initialized.
46  * @param buffer Pointer to a user-provided buffer.
47  * @param size Size of the user-provided buffer.
48  * @return The result of the operation.
49  */
51 rom_error_t asn1_start(asn1_state_t *new_state, uint8_t *buffer, size_t size);
52 
53 /**
54  * Finish an ASN1 stream and return the size.
55  *
56  * Note: the state will be cleared out after this call.
57  *
58  * @param state Pointer to the state initialized by asn1_start.
59  * @param[out] out_size Pointer to an integer that will be set to the size of
60  * the stream.
61  * @return The result of the operation.
62  */
64 rom_error_t asn1_finish(asn1_state_t *state, size_t *out_size);
65 
66 /**
67  * Push a byte into the ASN1 buffer.
68  *
69  * Note: This function tracks its error in the asn1 state, and the error will
70  * be returned by `asn1_finish` in the end. This function will be no-op when
71  * the state has an active error.
72  *
73  * @param state Pointer to the initialized by asn1_start.
74  * @param byte Byte to add to the buffer.
75  */
76 void asn1_push_byte(asn1_state_t *state, uint8_t byte);
77 
78 /**
79  * Push bytes into the ASN1 buffer.
80  *
81  * Note: This function tracks its error in the asn1 state, and the error will
82  * be returned by `asn1_finish` in the end. This function will be no-op when
83  * the state has an active error.
84  *
85  * @param state Pointer to the initialized by asn1_start.
86  * @param bytes Pointer to an array of bytes.
87  * @param size Number of bytes in the array.
88  */
89 void asn1_push_bytes(asn1_state_t *state, const uint8_t *bytes, size_t size);
90 
91 /**
92  * Structure holding the information about an unfinished tag sequence.
93  *
94  * The fields in this structure should be considered
95  * private and not be read or written directly.
96  */
97 typedef struct asn1_tag {
98  // Pointer to state.
99  asn1_state_t *state;
100  // Offset of the start of the length octets.
101  size_t len_offset;
102  // How many bytes were allocated for the length octets.
103  size_t len_size;
104 } asn1_tag_t;
105 
106 /**
107  * Structure holding the information about an unfinished bistring.
108  *
109  * The fields in this structure should be considered
110  * private and not be read or written directly.
111  */
112 typedef struct asn1_bitstring {
113  // Pointer to state.
114  asn1_state_t *state;
115  // Offset of the "unused bits" byte.
116  size_t unused_bits_offset;
117  // How many bits have been added to the current byte (between 0 and 7).
118  size_t used_bits;
119  // Current value of the last byte of the string.
120  uint8_t current_byte;
122 
123 // ASN1 tag classes.
124 typedef enum asn1_tag_class {
125  kAsn1TagClassUniversal = 0 << 6,
126  kAsn1TagClassApplication = 1 << 6,
127  kAsn1TagClassContext = 2 << 6,
128  kAsn1TagClassPrivate = 3 << 6,
129 } asn1_tag_class_t;
130 
131 // ASN1 tag primitive/constructed bit.
132 typedef enum asn1_tag_form {
133  kAsn1TagFormPrimitive = 0 << 5,
134  kAsn1TagFormConstructed = 1 << 5,
135 } asn1_tag_form_t;
136 
137 // ASN1 tag number (for universal tags).
138 typedef enum asn1_tag_number {
139  kAsn1TagNumberBoolean = 0x01,
140  kAsn1TagNumberInteger = 0x02,
141  kAsn1TagNumberBitString = 0x03,
142  kAsn1TagNumberOctetString = 0x04,
143  kAsn1TagNumberOid = 0x06,
144  kAsn1TagNumberUtf8String = 0x0c,
145  kAsn1TagNumberPrintableString = 0x13,
146  kAsn1TagNumberGeneralizedTime = 0x18,
147  kAsn1TagNumberSequence = 0x30,
148  kAsn1TagNumberSet = 0x31,
149 } asn1_tag_number_t;
150 
151 /**
152  * Start an ASN1 tag.
153  *
154  * Note: This function tracks its error in the asn1 state, and the error will
155  * be returned by `asn1_finish` in the end. This function will be no-op when
156  * the state has an active error.
157  *
158  * @param state Pointer to the state initialized by asn1_start.
159  * @param[out] new_tag Pointer to a user-allocated tag to be initialized.
160  * @param id Identifier byte of the tag (see ASN1_CLASS_*, ASN1_FORM_* and
161  * ASN1_TAG_*).
162  */
163 void asn1_start_tag(asn1_state_t *state, asn1_tag_t *new_tag, uint8_t id);
164 
165 /**
166  * Finish an ASN1 tag.
167  *
168  * If size hint provided to asn1_start_tag does not match the actual size
169  * of the data, this function will fix it up, potentially at the cost of moving
170  * bytes within the buffer.
171  *
172  * Note: the `tag` will be cleared out after this call.
173  *
174  * Note: This function tracks its error in the asn1 state, and the error will
175  * be returned by `asn1_finish` in the end. This function will be no-op when
176  * the state has an active error.
177  *
178  * @param state Pointer to the state initialized by asn1_start.
179  * @param tag Pointer to the tag initialized by asn1_start_tag.
180  */
181 void asn1_finish_tag(asn1_tag_t *tag);
182 
183 /**
184  * Push a tagged boolean into the buffer.
185  *
186  * Note: this function will encode true as 0xff (any non-zero value is
187  * acceptable per the specification).
188  *
189  * Note: This function tracks its error in the asn1 state, and the error will
190  * be returned by `asn1_finish` in the end. This function will be no-op when
191  * the state has an active error.
192  *
193  * @param state Pointer to the state initialized by asn1_start.
194  * @param tag Identifier octet of the tag.
195  * @param value Boolean value.
196  */
197 void asn1_push_bool(asn1_state_t *state, uint8_t tag, bool value);
198 
199 /**
200  * Push a tagged integer into the buffer.
201  *
202  * This function allows the caller to set the tag to a non-standard value which
203  * can be useful for IMPLICIT integers. Use ASN1_TAG_INTEGER for standard
204  * integers.
205  *
206  * Note: This function tracks its error in the asn1 state, and the error will
207  * be returned by `asn1_finish` in the end. This function will be no-op when
208  * the state has an active error.
209  *
210  * @param state Pointer to the state initialized by asn1_start.
211  * @param tag Identifier octet of the tag.
212  * @param value Integer value.
213  */
214 void asn1_push_int32(asn1_state_t *state, uint8_t tag, int32_t value);
215 
216 /**
217  * See asn1_push_int32()
218  */
219 void asn1_push_uint32(asn1_state_t *state, uint8_t tag, uint32_t value);
220 
221 /**
222  * Push a tagged integer into the buffer.
223  *
224  * This function allows the caller to set the tag to a non-standard value which
225  * can be useful for IMPLICIT integers. Use ASN1_TAG_INTEGER for standard
226  * integers.
227  *
228  * Note: This function tracks its error in the asn1 state, and the error will
229  * be returned by `asn1_finish` in the end. This function will be no-op when
230  * the state has an active error.
231  *
232  * @param state Pointer to the state initialized by asn1_start.
233  * @param tag Identifier octet of the tag.
234  * @param is_signed If true, the byte array represents a signed integer in two's
235  * complement.
236  * @param bytes_be Pointer to a byte array holding an integer in big-endian
237  * format.
238  * @param size Number of the bytes in the array.
239  */
240 void asn1_push_integer(asn1_state_t *state, uint8_t tag, bool is_signed,
241  const uint8_t *bytes_be, size_t size);
242 
243 /**
244  * Push a padded integer into the buffer.
245  *
246  * If the integer is unsigned, it will be padded to the required length with
247  * zeroes. If the integer is signed, it will be padded so as to preserve its
248  * value in two's complement. If the integer size is larger than the requested
249  * size with padding, an error will be reported.
250  *
251  * Note: This function tracks its error in the asn1 state, and the error will
252  * be returned by `asn1_finish` in the end. This function will be no-op when
253  * the state has an active error.
254  *
255  * @param state Pointer to the state initialized by asn1_start.
256  * @param is_signed If true, the byte array represents a signed integer in two's
257  * complement.
258  * @param bytes_be Pointer to a byte array holding an integer in big-endian
259  * format.
260  * @param size Number of the bytes in the array.
261  * @param size Number of the bytes to output with padding.
262  */
263 void asn1_push_integer_pad(asn1_state_t *state, bool is_signed,
264  const uint8_t *bytes_be, size_t size,
265  size_t padded_size);
266 
267 /**
268  * Push an object identifier into the buffer.
269  *
270  * The object identifier must already be encoded according to the X.690 spec,
271  * section 8.19 (https://www.itu.int/rec/T-REC-X.690).
272  *
273  * Note: This function tracks its error in the asn1 state, and the error will
274  * be returned by `asn1_finish` in the end. This function will be no-op when
275  * the state has an active error.
276  *
277  * @param state Pointer to the state initialized by asn1_start.
278  * @param bytes Pointer to a byte array holding the object identifier.
279  * @param size Number of the bytes in the array.
280  */
281 void asn1_push_oid_raw(asn1_state_t *state, const uint8_t *bytes, size_t size);
282 
283 /**
284  * Push a tagged string into the buffer.
285  *
286  * This function allows the caller to set the tag to a non-standard value which
287  * can be useful for IMPLICIT strings. Use ASN1_TAG_PRINTABLE_STRING or
288  * ASN1_TAG_UTF8_STRING for standard strings. It is the responsability of the
289  * caller to make sure that the provided string does not contain invalid
290  * characters for the selected encoding. This function will stop at the first 0
291  * in the string or after processing the provided number of characters,
292  * whichever comes first.
293  *
294  * Note: This function tracks its error in the asn1 state, and the error will
295  * be returned by `asn1_finish` in the end. This function will be no-op when
296  * the state has an active error.
297  *
298  * @param state Pointer to the state initialized by asn1_start.
299  * @param tag Identifier octet of the tag.
300  * @param str Pointer to a (not necessarily zero-terminated) string.
301  * @param max_len Maximum number of characters to read from the string.
302  */
303 void asn1_push_string(asn1_state_t *state, uint8_t tag, const char *str,
304  size_t max_len);
305 
306 /**
307  * Push a tagged hexstring into the buffer.
308  *
309  * This function allows the caller to set the tag to a non-standard value which
310  * can be useful for IMPLICIT strings. This function takes an array of bytes
311  * and output exactly two lowercase hex characters per byte in the input buffer.
312  *
313  * Note: This function tracks its error in the asn1 state, and the error will
314  * be returned by `asn1_finish` in the end. This function will be no-op when
315  * the state has an active error.
316  *
317  * @param state Pointer to the state initialized by asn1_start.
318  * @param tag Identifier octet of the tag.
319  * @param str Pointer to a byte array.
320  * @param size Number of the bytes in the array.
321  */
322 void asn1_push_hexstring(asn1_state_t *state, uint8_t tag, const uint8_t *bytes,
323  size_t size);
324 
325 /**
326  * Start an ASN1 bitstring.
327  *
328  * Note: This function tracks its error in the asn1 state, and the error will
329  * be returned by `asn1_finish` in the end. This function will be no-op when
330  * the state has an active error.
331  *
332  * @param state Pointer to the state initialized by asn1_start.
333  * @param[out] out_bitstring Pointer to a user-allocated bitstring to be
334  * initialized.
335  */
336 void asn1_start_bitstring(asn1_state_t *state, asn1_bitstring_t *out_bitstring);
337 
338 /** Add a bit to a bitstring.
339  *
340  * Note: This function tracks its error in the asn1 state, and the error will
341  * be returned by `asn1_finish` in the end. This function will be no-op when
342  * the state has an active error.
343  *
344  * @param bitstring Pointer to a bitstring initialized by asn1_start_bitstring.
345  * @param bit Bit to add at the end of the string.
346  */
347 void asn1_bitstring_push_bit(asn1_bitstring_t *bitstring, bool bit);
348 
349 /** Finish an ASN1 bitstring.
350  *
351  * Note: This function tracks its error in the asn1 state, and the error will
352  * be returned by `asn1_finish` in the end. This function will be no-op when
353  * the state has an active error.
354  *
355  * @param bitstring Pointer to a bitstring initialized by asn1_start_bitstring.
356  */
357 void asn1_finish_bitstring(asn1_bitstring_t *bitstring);
358 
359 #ifdef __cplusplus
360 } // extern "C"
361 #endif // __cplusplus
362 
363 #endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_CERT_ASN1_H_