1*de0e0e4dSAntonio Huete Jimenez /* $OpenBSD: bs_cbb.c,v 1.28 2022/07/07 17:12:15 tb Exp $ */
2f5b1c8a1SJohn Marino /*
3f5b1c8a1SJohn Marino * Copyright (c) 2014, Google Inc.
4f5b1c8a1SJohn Marino *
5f5b1c8a1SJohn Marino * Permission to use, copy, modify, and/or distribute this software for any
6f5b1c8a1SJohn Marino * purpose with or without fee is hereby granted, provided that the above
7f5b1c8a1SJohn Marino * copyright notice and this permission notice appear in all copies.
8f5b1c8a1SJohn Marino *
9f5b1c8a1SJohn Marino * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10f5b1c8a1SJohn Marino * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11f5b1c8a1SJohn Marino * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
12f5b1c8a1SJohn Marino * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13f5b1c8a1SJohn Marino * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
14f5b1c8a1SJohn Marino * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15*de0e0e4dSAntonio Huete Jimenez * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*de0e0e4dSAntonio Huete Jimenez */
17f5b1c8a1SJohn Marino
18f5b1c8a1SJohn Marino #include <stdlib.h>
19f5b1c8a1SJohn Marino #include <string.h>
20f5b1c8a1SJohn Marino
21f5b1c8a1SJohn Marino #include "bytestring.h"
22f5b1c8a1SJohn Marino
2372c33676SMaxim Ag #define CBB_INITIAL_SIZE 64
2472c33676SMaxim Ag
25f5b1c8a1SJohn Marino static int
cbb_init(CBB * cbb,uint8_t * buf,size_t cap)26f5b1c8a1SJohn Marino cbb_init(CBB *cbb, uint8_t *buf, size_t cap)
27f5b1c8a1SJohn Marino {
28f5b1c8a1SJohn Marino struct cbb_buffer_st *base;
29f5b1c8a1SJohn Marino
30cca6fc52SDaniel Fojt if ((base = calloc(1, sizeof(struct cbb_buffer_st))) == NULL)
31f5b1c8a1SJohn Marino return 0;
32f5b1c8a1SJohn Marino
33f5b1c8a1SJohn Marino base->buf = buf;
34f5b1c8a1SJohn Marino base->len = 0;
35f5b1c8a1SJohn Marino base->cap = cap;
36f5b1c8a1SJohn Marino base->can_resize = 1;
37f5b1c8a1SJohn Marino
38f5b1c8a1SJohn Marino cbb->base = base;
39f5b1c8a1SJohn Marino cbb->is_top_level = 1;
40f5b1c8a1SJohn Marino
41f5b1c8a1SJohn Marino return 1;
42f5b1c8a1SJohn Marino }
43f5b1c8a1SJohn Marino
44f5b1c8a1SJohn Marino int
CBB_init(CBB * cbb,size_t initial_capacity)45f5b1c8a1SJohn Marino CBB_init(CBB *cbb, size_t initial_capacity)
46f5b1c8a1SJohn Marino {
47f5b1c8a1SJohn Marino uint8_t *buf = NULL;
48f5b1c8a1SJohn Marino
49f5b1c8a1SJohn Marino memset(cbb, 0, sizeof(*cbb));
50f5b1c8a1SJohn Marino
5172c33676SMaxim Ag if (initial_capacity == 0)
5272c33676SMaxim Ag initial_capacity = CBB_INITIAL_SIZE;
5372c33676SMaxim Ag
54cca6fc52SDaniel Fojt if ((buf = calloc(1, initial_capacity)) == NULL)
55f5b1c8a1SJohn Marino return 0;
56f5b1c8a1SJohn Marino
57f5b1c8a1SJohn Marino if (!cbb_init(cbb, buf, initial_capacity)) {
58f5b1c8a1SJohn Marino free(buf);
59f5b1c8a1SJohn Marino return 0;
60f5b1c8a1SJohn Marino }
61f5b1c8a1SJohn Marino
62f5b1c8a1SJohn Marino return 1;
63f5b1c8a1SJohn Marino }
64f5b1c8a1SJohn Marino
65f5b1c8a1SJohn Marino int
CBB_init_fixed(CBB * cbb,uint8_t * buf,size_t len)66f5b1c8a1SJohn Marino CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len)
67f5b1c8a1SJohn Marino {
68f5b1c8a1SJohn Marino memset(cbb, 0, sizeof(*cbb));
69f5b1c8a1SJohn Marino
70f5b1c8a1SJohn Marino if (!cbb_init(cbb, buf, len))
71f5b1c8a1SJohn Marino return 0;
72f5b1c8a1SJohn Marino
73f5b1c8a1SJohn Marino cbb->base->can_resize = 0;
74f5b1c8a1SJohn Marino
75f5b1c8a1SJohn Marino return 1;
76f5b1c8a1SJohn Marino }
77f5b1c8a1SJohn Marino
78f5b1c8a1SJohn Marino void
CBB_cleanup(CBB * cbb)79f5b1c8a1SJohn Marino CBB_cleanup(CBB *cbb)
80f5b1c8a1SJohn Marino {
81f5b1c8a1SJohn Marino if (cbb->base) {
82f5b1c8a1SJohn Marino if (cbb->base->can_resize)
8372c33676SMaxim Ag freezero(cbb->base->buf, cbb->base->cap);
84f5b1c8a1SJohn Marino free(cbb->base);
85f5b1c8a1SJohn Marino }
86f5b1c8a1SJohn Marino cbb->base = NULL;
8772c33676SMaxim Ag cbb->child = NULL;
88f5b1c8a1SJohn Marino }
89f5b1c8a1SJohn Marino
90f5b1c8a1SJohn Marino static int
cbb_buffer_add(struct cbb_buffer_st * base,uint8_t ** out,size_t len)91f5b1c8a1SJohn Marino cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out, size_t len)
92f5b1c8a1SJohn Marino {
93f5b1c8a1SJohn Marino size_t newlen;
94f5b1c8a1SJohn Marino
95f5b1c8a1SJohn Marino if (base == NULL)
96f5b1c8a1SJohn Marino return 0;
97f5b1c8a1SJohn Marino
98f5b1c8a1SJohn Marino newlen = base->len + len;
99f5b1c8a1SJohn Marino if (newlen < base->len)
100f5b1c8a1SJohn Marino /* Overflow */
101f5b1c8a1SJohn Marino return 0;
102f5b1c8a1SJohn Marino
103f5b1c8a1SJohn Marino if (newlen > base->cap) {
104f5b1c8a1SJohn Marino size_t newcap = base->cap * 2;
105f5b1c8a1SJohn Marino uint8_t *newbuf;
106f5b1c8a1SJohn Marino
107f5b1c8a1SJohn Marino if (!base->can_resize)
108f5b1c8a1SJohn Marino return 0;
109f5b1c8a1SJohn Marino
110f5b1c8a1SJohn Marino if (newcap < base->cap || newcap < newlen)
111f5b1c8a1SJohn Marino newcap = newlen;
112f5b1c8a1SJohn Marino
11372c33676SMaxim Ag newbuf = recallocarray(base->buf, base->cap, newcap, 1);
114f5b1c8a1SJohn Marino if (newbuf == NULL)
115f5b1c8a1SJohn Marino return 0;
116f5b1c8a1SJohn Marino
117f5b1c8a1SJohn Marino base->buf = newbuf;
118f5b1c8a1SJohn Marino base->cap = newcap;
119f5b1c8a1SJohn Marino }
120f5b1c8a1SJohn Marino
121f5b1c8a1SJohn Marino if (out)
122f5b1c8a1SJohn Marino *out = base->buf + base->len;
123f5b1c8a1SJohn Marino
124f5b1c8a1SJohn Marino base->len = newlen;
125f5b1c8a1SJohn Marino return 1;
126f5b1c8a1SJohn Marino }
127f5b1c8a1SJohn Marino
128f5b1c8a1SJohn Marino static int
cbb_add_u(CBB * cbb,uint32_t v,size_t len_len)129f5b1c8a1SJohn Marino cbb_add_u(CBB *cbb, uint32_t v, size_t len_len)
130f5b1c8a1SJohn Marino {
131f5b1c8a1SJohn Marino uint8_t *buf;
132f5b1c8a1SJohn Marino size_t i;
133f5b1c8a1SJohn Marino
134f5b1c8a1SJohn Marino if (len_len == 0)
135f5b1c8a1SJohn Marino return 1;
136f5b1c8a1SJohn Marino
137f5b1c8a1SJohn Marino if (len_len > 4)
138f5b1c8a1SJohn Marino return 0;
139f5b1c8a1SJohn Marino
140f5b1c8a1SJohn Marino if (!CBB_flush(cbb) || !cbb_buffer_add(cbb->base, &buf, len_len))
141f5b1c8a1SJohn Marino return 0;
142f5b1c8a1SJohn Marino
143f5b1c8a1SJohn Marino for (i = len_len - 1; i < len_len; i--) {
144f5b1c8a1SJohn Marino buf[i] = v;
145f5b1c8a1SJohn Marino v >>= 8;
146f5b1c8a1SJohn Marino }
147f5b1c8a1SJohn Marino return 1;
148f5b1c8a1SJohn Marino }
149f5b1c8a1SJohn Marino
150f5b1c8a1SJohn Marino int
CBB_finish(CBB * cbb,uint8_t ** out_data,size_t * out_len)151f5b1c8a1SJohn Marino CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len)
152f5b1c8a1SJohn Marino {
153f5b1c8a1SJohn Marino if (!cbb->is_top_level)
154f5b1c8a1SJohn Marino return 0;
155f5b1c8a1SJohn Marino
156f5b1c8a1SJohn Marino if (!CBB_flush(cbb))
157f5b1c8a1SJohn Marino return 0;
158f5b1c8a1SJohn Marino
159f5b1c8a1SJohn Marino if (cbb->base->can_resize && (out_data == NULL || out_len == NULL))
160f5b1c8a1SJohn Marino /*
161f5b1c8a1SJohn Marino * |out_data| and |out_len| can only be NULL if the CBB is
162f5b1c8a1SJohn Marino * fixed.
163f5b1c8a1SJohn Marino */
164f5b1c8a1SJohn Marino return 0;
165f5b1c8a1SJohn Marino
166*de0e0e4dSAntonio Huete Jimenez if (out_data != NULL && *out_data != NULL)
167*de0e0e4dSAntonio Huete Jimenez return 0;
168*de0e0e4dSAntonio Huete Jimenez
169f5b1c8a1SJohn Marino if (out_data != NULL)
170f5b1c8a1SJohn Marino *out_data = cbb->base->buf;
171f5b1c8a1SJohn Marino
172f5b1c8a1SJohn Marino if (out_len != NULL)
173f5b1c8a1SJohn Marino *out_len = cbb->base->len;
174f5b1c8a1SJohn Marino
175f5b1c8a1SJohn Marino cbb->base->buf = NULL;
176f5b1c8a1SJohn Marino CBB_cleanup(cbb);
177f5b1c8a1SJohn Marino return 1;
178f5b1c8a1SJohn Marino }
179f5b1c8a1SJohn Marino
180f5b1c8a1SJohn Marino /*
181f5b1c8a1SJohn Marino * CBB_flush recurses and then writes out any pending length prefix. The current
182f5b1c8a1SJohn Marino * length of the underlying base is taken to be the length of the
183f5b1c8a1SJohn Marino * length-prefixed data.
184f5b1c8a1SJohn Marino */
185f5b1c8a1SJohn Marino int
CBB_flush(CBB * cbb)186f5b1c8a1SJohn Marino CBB_flush(CBB *cbb)
187f5b1c8a1SJohn Marino {
188f5b1c8a1SJohn Marino size_t child_start, i, len;
189f5b1c8a1SJohn Marino
190f5b1c8a1SJohn Marino if (cbb->base == NULL)
191f5b1c8a1SJohn Marino return 0;
192f5b1c8a1SJohn Marino
193f5b1c8a1SJohn Marino if (cbb->child == NULL || cbb->pending_len_len == 0)
194f5b1c8a1SJohn Marino return 1;
195f5b1c8a1SJohn Marino
196f5b1c8a1SJohn Marino child_start = cbb->offset + cbb->pending_len_len;
197f5b1c8a1SJohn Marino
198f5b1c8a1SJohn Marino if (!CBB_flush(cbb->child) || child_start < cbb->offset ||
199f5b1c8a1SJohn Marino cbb->base->len < child_start)
200f5b1c8a1SJohn Marino return 0;
201f5b1c8a1SJohn Marino
202f5b1c8a1SJohn Marino len = cbb->base->len - child_start;
203f5b1c8a1SJohn Marino
204f5b1c8a1SJohn Marino if (cbb->pending_is_asn1) {
205f5b1c8a1SJohn Marino /*
206f5b1c8a1SJohn Marino * For ASN.1, we assumed that we were using short form which
207f5b1c8a1SJohn Marino * only requires a single byte for the length octet.
208f5b1c8a1SJohn Marino *
209f5b1c8a1SJohn Marino * If it turns out that we need long form, we have to move
210f5b1c8a1SJohn Marino * the contents along in order to make space for more length
211f5b1c8a1SJohn Marino * octets.
212f5b1c8a1SJohn Marino */
213f5b1c8a1SJohn Marino size_t len_len = 1; /* total number of length octets */
214f5b1c8a1SJohn Marino uint8_t initial_length_byte;
215f5b1c8a1SJohn Marino
216f5b1c8a1SJohn Marino /* We already wrote 1 byte for the length. */
21772c33676SMaxim Ag if (cbb->pending_len_len != 1)
21872c33676SMaxim Ag return 0;
219f5b1c8a1SJohn Marino
220f5b1c8a1SJohn Marino /* Check for long form */
221f5b1c8a1SJohn Marino if (len > 0xfffffffe)
222f5b1c8a1SJohn Marino return 0; /* 0xffffffff is reserved */
223f5b1c8a1SJohn Marino else if (len > 0xffffff)
224f5b1c8a1SJohn Marino len_len = 5;
225f5b1c8a1SJohn Marino else if (len > 0xffff)
226f5b1c8a1SJohn Marino len_len = 4;
227f5b1c8a1SJohn Marino else if (len > 0xff)
228f5b1c8a1SJohn Marino len_len = 3;
229f5b1c8a1SJohn Marino else if (len > 0x7f)
230f5b1c8a1SJohn Marino len_len = 2;
231f5b1c8a1SJohn Marino
232f5b1c8a1SJohn Marino if (len_len == 1) {
233f5b1c8a1SJohn Marino /* For short form, the initial byte is the length. */
234f5b1c8a1SJohn Marino initial_length_byte = len;
235f5b1c8a1SJohn Marino len = 0;
236f5b1c8a1SJohn Marino
237f5b1c8a1SJohn Marino } else {
238f5b1c8a1SJohn Marino /*
239f5b1c8a1SJohn Marino * For long form, the initial byte is the number of
240f5b1c8a1SJohn Marino * subsequent length octets (plus bit 8 set).
241f5b1c8a1SJohn Marino */
242f5b1c8a1SJohn Marino initial_length_byte = 0x80 | (len_len - 1);
243f5b1c8a1SJohn Marino
244f5b1c8a1SJohn Marino /*
245f5b1c8a1SJohn Marino * We need to move the contents along in order to make
246f5b1c8a1SJohn Marino * space for the long form length octets.
247f5b1c8a1SJohn Marino */
248f5b1c8a1SJohn Marino size_t extra_bytes = len_len - 1;
249f5b1c8a1SJohn Marino if (!cbb_buffer_add(cbb->base, NULL, extra_bytes))
250f5b1c8a1SJohn Marino return 0;
251f5b1c8a1SJohn Marino
252f5b1c8a1SJohn Marino memmove(cbb->base->buf + child_start + extra_bytes,
253f5b1c8a1SJohn Marino cbb->base->buf + child_start, len);
254f5b1c8a1SJohn Marino }
255f5b1c8a1SJohn Marino cbb->base->buf[cbb->offset++] = initial_length_byte;
256f5b1c8a1SJohn Marino cbb->pending_len_len = len_len - 1;
257f5b1c8a1SJohn Marino }
258f5b1c8a1SJohn Marino
259f5b1c8a1SJohn Marino for (i = cbb->pending_len_len - 1; i < cbb->pending_len_len; i--) {
260f5b1c8a1SJohn Marino cbb->base->buf[cbb->offset + i] = len;
261f5b1c8a1SJohn Marino len >>= 8;
262f5b1c8a1SJohn Marino }
263f5b1c8a1SJohn Marino if (len != 0)
264f5b1c8a1SJohn Marino return 0;
265f5b1c8a1SJohn Marino
266f5b1c8a1SJohn Marino cbb->child->base = NULL;
267f5b1c8a1SJohn Marino cbb->child = NULL;
268f5b1c8a1SJohn Marino cbb->pending_len_len = 0;
269f5b1c8a1SJohn Marino cbb->pending_is_asn1 = 0;
270f5b1c8a1SJohn Marino cbb->offset = 0;
271f5b1c8a1SJohn Marino
272f5b1c8a1SJohn Marino return 1;
273f5b1c8a1SJohn Marino }
274f5b1c8a1SJohn Marino
27572c33676SMaxim Ag void
CBB_discard_child(CBB * cbb)27672c33676SMaxim Ag CBB_discard_child(CBB *cbb)
27772c33676SMaxim Ag {
27872c33676SMaxim Ag if (cbb->child == NULL)
27972c33676SMaxim Ag return;
28072c33676SMaxim Ag
28172c33676SMaxim Ag cbb->base->len = cbb->offset;
28272c33676SMaxim Ag
28372c33676SMaxim Ag cbb->child->base = NULL;
28472c33676SMaxim Ag cbb->child = NULL;
28572c33676SMaxim Ag cbb->pending_len_len = 0;
28672c33676SMaxim Ag cbb->pending_is_asn1 = 0;
28772c33676SMaxim Ag cbb->offset = 0;
28872c33676SMaxim Ag }
289f5b1c8a1SJohn Marino
290f5b1c8a1SJohn Marino static int
cbb_add_length_prefixed(CBB * cbb,CBB * out_contents,size_t len_len)291f5b1c8a1SJohn Marino cbb_add_length_prefixed(CBB *cbb, CBB *out_contents, size_t len_len)
292f5b1c8a1SJohn Marino {
293f5b1c8a1SJohn Marino uint8_t *prefix_bytes;
294f5b1c8a1SJohn Marino
295f5b1c8a1SJohn Marino if (!CBB_flush(cbb))
296f5b1c8a1SJohn Marino return 0;
297f5b1c8a1SJohn Marino
298f5b1c8a1SJohn Marino cbb->offset = cbb->base->len;
299f5b1c8a1SJohn Marino if (!cbb_buffer_add(cbb->base, &prefix_bytes, len_len))
300f5b1c8a1SJohn Marino return 0;
301f5b1c8a1SJohn Marino
302f5b1c8a1SJohn Marino memset(prefix_bytes, 0, len_len);
303f5b1c8a1SJohn Marino memset(out_contents, 0, sizeof(CBB));
304f5b1c8a1SJohn Marino out_contents->base = cbb->base;
305f5b1c8a1SJohn Marino cbb->child = out_contents;
306f5b1c8a1SJohn Marino cbb->pending_len_len = len_len;
307f5b1c8a1SJohn Marino cbb->pending_is_asn1 = 0;
308f5b1c8a1SJohn Marino
309f5b1c8a1SJohn Marino return 1;
310f5b1c8a1SJohn Marino }
311f5b1c8a1SJohn Marino
312f5b1c8a1SJohn Marino int
CBB_add_u8_length_prefixed(CBB * cbb,CBB * out_contents)313f5b1c8a1SJohn Marino CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents)
314f5b1c8a1SJohn Marino {
315f5b1c8a1SJohn Marino return cbb_add_length_prefixed(cbb, out_contents, 1);
316f5b1c8a1SJohn Marino }
317f5b1c8a1SJohn Marino
318f5b1c8a1SJohn Marino int
CBB_add_u16_length_prefixed(CBB * cbb,CBB * out_contents)319f5b1c8a1SJohn Marino CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents)
320f5b1c8a1SJohn Marino {
321f5b1c8a1SJohn Marino return cbb_add_length_prefixed(cbb, out_contents, 2);
322f5b1c8a1SJohn Marino }
323f5b1c8a1SJohn Marino
324f5b1c8a1SJohn Marino int
CBB_add_u24_length_prefixed(CBB * cbb,CBB * out_contents)325f5b1c8a1SJohn Marino CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents)
326f5b1c8a1SJohn Marino {
327f5b1c8a1SJohn Marino return cbb_add_length_prefixed(cbb, out_contents, 3);
328f5b1c8a1SJohn Marino }
329f5b1c8a1SJohn Marino
330f5b1c8a1SJohn Marino int
CBB_add_asn1(CBB * cbb,CBB * out_contents,unsigned int tag)331f5b1c8a1SJohn Marino CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned int tag)
332f5b1c8a1SJohn Marino {
333f5b1c8a1SJohn Marino if (tag > UINT8_MAX)
334f5b1c8a1SJohn Marino return 0;
335f5b1c8a1SJohn Marino
336f5b1c8a1SJohn Marino /* Long form identifier octets are not supported. */
337f5b1c8a1SJohn Marino if ((tag & 0x1f) == 0x1f)
338f5b1c8a1SJohn Marino return 0;
339f5b1c8a1SJohn Marino
340f5b1c8a1SJohn Marino /* Short-form identifier octet only needs a single byte */
341f5b1c8a1SJohn Marino if (!CBB_flush(cbb) || !CBB_add_u8(cbb, tag))
342f5b1c8a1SJohn Marino return 0;
343f5b1c8a1SJohn Marino
344f5b1c8a1SJohn Marino /*
345f5b1c8a1SJohn Marino * Add 1 byte to cover the short-form length octet case. If it turns
346f5b1c8a1SJohn Marino * out we need long-form, it will be extended later.
347f5b1c8a1SJohn Marino */
348f5b1c8a1SJohn Marino cbb->offset = cbb->base->len;
349f5b1c8a1SJohn Marino if (!CBB_add_u8(cbb, 0))
350f5b1c8a1SJohn Marino return 0;
351f5b1c8a1SJohn Marino
352f5b1c8a1SJohn Marino memset(out_contents, 0, sizeof(CBB));
353f5b1c8a1SJohn Marino out_contents->base = cbb->base;
354f5b1c8a1SJohn Marino cbb->child = out_contents;
355f5b1c8a1SJohn Marino cbb->pending_len_len = 1;
356f5b1c8a1SJohn Marino cbb->pending_is_asn1 = 1;
357f5b1c8a1SJohn Marino
358f5b1c8a1SJohn Marino return 1;
359f5b1c8a1SJohn Marino }
360f5b1c8a1SJohn Marino
361f5b1c8a1SJohn Marino int
CBB_add_bytes(CBB * cbb,const uint8_t * data,size_t len)362f5b1c8a1SJohn Marino CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len)
363f5b1c8a1SJohn Marino {
364f5b1c8a1SJohn Marino uint8_t *dest;
365f5b1c8a1SJohn Marino
3668edacedfSDaniel Fojt if (!CBB_flush(cbb) || !cbb_buffer_add(cbb->base, &dest, len))
367f5b1c8a1SJohn Marino return 0;
368f5b1c8a1SJohn Marino
369f5b1c8a1SJohn Marino memcpy(dest, data, len);
370f5b1c8a1SJohn Marino return 1;
371f5b1c8a1SJohn Marino }
372f5b1c8a1SJohn Marino
373f5b1c8a1SJohn Marino int
CBB_add_space(CBB * cbb,uint8_t ** out_data,size_t len)374f5b1c8a1SJohn Marino CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len)
375f5b1c8a1SJohn Marino {
376f5b1c8a1SJohn Marino if (!CBB_flush(cbb) || !cbb_buffer_add(cbb->base, out_data, len))
377f5b1c8a1SJohn Marino return 0;
378f5b1c8a1SJohn Marino
379cca6fc52SDaniel Fojt memset(*out_data, 0, len);
380f5b1c8a1SJohn Marino return 1;
381f5b1c8a1SJohn Marino }
382f5b1c8a1SJohn Marino
383f5b1c8a1SJohn Marino int
CBB_add_u8(CBB * cbb,size_t value)384f5b1c8a1SJohn Marino CBB_add_u8(CBB *cbb, size_t value)
385f5b1c8a1SJohn Marino {
386f5b1c8a1SJohn Marino if (value > UINT8_MAX)
387f5b1c8a1SJohn Marino return 0;
388f5b1c8a1SJohn Marino
389f5b1c8a1SJohn Marino return cbb_add_u(cbb, (uint32_t)value, 1);
390f5b1c8a1SJohn Marino }
391f5b1c8a1SJohn Marino
392f5b1c8a1SJohn Marino int
CBB_add_u16(CBB * cbb,size_t value)393f5b1c8a1SJohn Marino CBB_add_u16(CBB *cbb, size_t value)
394f5b1c8a1SJohn Marino {
395f5b1c8a1SJohn Marino if (value > UINT16_MAX)
396f5b1c8a1SJohn Marino return 0;
397f5b1c8a1SJohn Marino
398f5b1c8a1SJohn Marino return cbb_add_u(cbb, (uint32_t)value, 2);
399f5b1c8a1SJohn Marino }
400f5b1c8a1SJohn Marino
401f5b1c8a1SJohn Marino int
CBB_add_u24(CBB * cbb,size_t value)402f5b1c8a1SJohn Marino CBB_add_u24(CBB *cbb, size_t value)
403f5b1c8a1SJohn Marino {
404f5b1c8a1SJohn Marino if (value > 0xffffffUL)
405f5b1c8a1SJohn Marino return 0;
406f5b1c8a1SJohn Marino
407f5b1c8a1SJohn Marino return cbb_add_u(cbb, (uint32_t)value, 3);
408f5b1c8a1SJohn Marino }
409f5b1c8a1SJohn Marino
410f5b1c8a1SJohn Marino int
CBB_add_u32(CBB * cbb,size_t value)41172c33676SMaxim Ag CBB_add_u32(CBB *cbb, size_t value)
41272c33676SMaxim Ag {
41372c33676SMaxim Ag if (value > 0xffffffffUL)
41472c33676SMaxim Ag return 0;
41572c33676SMaxim Ag
41672c33676SMaxim Ag return cbb_add_u(cbb, (uint32_t)value, 4);
41772c33676SMaxim Ag }
41872c33676SMaxim Ag
41972c33676SMaxim Ag int
CBB_add_u64(CBB * cbb,uint64_t value)420*de0e0e4dSAntonio Huete Jimenez CBB_add_u64(CBB *cbb, uint64_t value)
421*de0e0e4dSAntonio Huete Jimenez {
422*de0e0e4dSAntonio Huete Jimenez uint32_t a, b;
423*de0e0e4dSAntonio Huete Jimenez
424*de0e0e4dSAntonio Huete Jimenez a = value >> 32;
425*de0e0e4dSAntonio Huete Jimenez b = value & 0xffffffff;
426*de0e0e4dSAntonio Huete Jimenez
427*de0e0e4dSAntonio Huete Jimenez if (!CBB_add_u32(cbb, a))
428*de0e0e4dSAntonio Huete Jimenez return 0;
429*de0e0e4dSAntonio Huete Jimenez return CBB_add_u32(cbb, b);
430*de0e0e4dSAntonio Huete Jimenez }
431*de0e0e4dSAntonio Huete Jimenez
432*de0e0e4dSAntonio Huete Jimenez int
CBB_add_asn1_uint64(CBB * cbb,uint64_t value)433f5b1c8a1SJohn Marino CBB_add_asn1_uint64(CBB *cbb, uint64_t value)
434f5b1c8a1SJohn Marino {
435f5b1c8a1SJohn Marino CBB child;
436f5b1c8a1SJohn Marino size_t i;
437f5b1c8a1SJohn Marino int started = 0;
438f5b1c8a1SJohn Marino
439f5b1c8a1SJohn Marino if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER))
440f5b1c8a1SJohn Marino return 0;
441f5b1c8a1SJohn Marino
442f5b1c8a1SJohn Marino for (i = 0; i < 8; i++) {
443f5b1c8a1SJohn Marino uint8_t byte = (value >> 8 * (7 - i)) & 0xff;
444f5b1c8a1SJohn Marino
445f5b1c8a1SJohn Marino /*
446f5b1c8a1SJohn Marino * ASN.1 restriction: first 9 bits cannot be all zeroes or
447f5b1c8a1SJohn Marino * all ones. Since this function only encodes unsigned
448f5b1c8a1SJohn Marino * integers, the only concerns are not encoding leading
449f5b1c8a1SJohn Marino * zeros and adding a padding byte if necessary.
450f5b1c8a1SJohn Marino *
451f5b1c8a1SJohn Marino * In practice, this means:
452f5b1c8a1SJohn Marino * 1) Skip leading octets of all zero bits in the value
453f5b1c8a1SJohn Marino * 2) After skipping the leading zero octets, if the next 9
454f5b1c8a1SJohn Marino * bits are all ones, add an all zero prefix octet (and
455f5b1c8a1SJohn Marino * set the high bit of the prefix octet if negative).
456f5b1c8a1SJohn Marino *
457f5b1c8a1SJohn Marino * Additionally, for an unsigned value, add an all zero
458f5b1c8a1SJohn Marino * prefix if the high bit of the first octet would be one.
459f5b1c8a1SJohn Marino */
460f5b1c8a1SJohn Marino if (!started) {
461f5b1c8a1SJohn Marino if (byte == 0)
462f5b1c8a1SJohn Marino /* Don't encode leading zeros. */
463f5b1c8a1SJohn Marino continue;
464f5b1c8a1SJohn Marino
465f5b1c8a1SJohn Marino /*
466f5b1c8a1SJohn Marino * If the high bit is set, add a padding byte to make it
467f5b1c8a1SJohn Marino * unsigned.
468f5b1c8a1SJohn Marino */
469f5b1c8a1SJohn Marino if ((byte & 0x80) && !CBB_add_u8(&child, 0))
470f5b1c8a1SJohn Marino return 0;
471f5b1c8a1SJohn Marino
472f5b1c8a1SJohn Marino started = 1;
473f5b1c8a1SJohn Marino }
474f5b1c8a1SJohn Marino if (!CBB_add_u8(&child, byte))
475f5b1c8a1SJohn Marino return 0;
476f5b1c8a1SJohn Marino }
477f5b1c8a1SJohn Marino
478f5b1c8a1SJohn Marino /* 0 is encoded as a single 0, not the empty string. */
479f5b1c8a1SJohn Marino if (!started && !CBB_add_u8(&child, 0))
480f5b1c8a1SJohn Marino return 0;
481f5b1c8a1SJohn Marino
482f5b1c8a1SJohn Marino return CBB_flush(cbb);
483f5b1c8a1SJohn Marino }
484