xref: /dflybsd-src/crypto/libressl/ssl/bs_cbb.c (revision 72c3367655e64985522b7a48ddfab613e869dc68)
1*72c33676SMaxim Ag /*	$OpenBSD: bs_cbb.c,v 1.20 2019/01/23 22:20:40 beck 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
15f5b1c8a1SJohn Marino  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
16f5b1c8a1SJohn Marino 
17f5b1c8a1SJohn Marino #include <stdlib.h>
18f5b1c8a1SJohn Marino #include <string.h>
19f5b1c8a1SJohn Marino 
20f5b1c8a1SJohn Marino #include <openssl/opensslconf.h>
21f5b1c8a1SJohn Marino 
22f5b1c8a1SJohn Marino #include "bytestring.h"
23f5b1c8a1SJohn Marino 
24*72c33676SMaxim Ag #define CBB_INITIAL_SIZE 64
25*72c33676SMaxim Ag 
26f5b1c8a1SJohn Marino static int
27f5b1c8a1SJohn Marino cbb_init(CBB *cbb, uint8_t *buf, size_t cap)
28f5b1c8a1SJohn Marino {
29f5b1c8a1SJohn Marino 	struct cbb_buffer_st *base;
30f5b1c8a1SJohn Marino 
31f5b1c8a1SJohn Marino 	base = malloc(sizeof(struct cbb_buffer_st));
32f5b1c8a1SJohn Marino 	if (base == NULL)
33f5b1c8a1SJohn Marino 		return 0;
34f5b1c8a1SJohn Marino 
35f5b1c8a1SJohn Marino 	base->buf = buf;
36f5b1c8a1SJohn Marino 	base->len = 0;
37f5b1c8a1SJohn Marino 	base->cap = cap;
38f5b1c8a1SJohn Marino 	base->can_resize = 1;
39f5b1c8a1SJohn Marino 
40f5b1c8a1SJohn Marino 	cbb->base = base;
41f5b1c8a1SJohn Marino 	cbb->is_top_level = 1;
42f5b1c8a1SJohn Marino 
43f5b1c8a1SJohn Marino 	return 1;
44f5b1c8a1SJohn Marino }
45f5b1c8a1SJohn Marino 
46f5b1c8a1SJohn Marino int
47f5b1c8a1SJohn Marino CBB_init(CBB *cbb, size_t initial_capacity)
48f5b1c8a1SJohn Marino {
49f5b1c8a1SJohn Marino 	uint8_t *buf = NULL;
50f5b1c8a1SJohn Marino 
51f5b1c8a1SJohn Marino 	memset(cbb, 0, sizeof(*cbb));
52f5b1c8a1SJohn Marino 
53*72c33676SMaxim Ag 	if (initial_capacity == 0)
54*72c33676SMaxim Ag 		initial_capacity = CBB_INITIAL_SIZE;
55*72c33676SMaxim Ag 
56f5b1c8a1SJohn Marino 	if ((buf = malloc(initial_capacity)) == NULL)
57f5b1c8a1SJohn Marino 		return 0;
58f5b1c8a1SJohn Marino 
59f5b1c8a1SJohn Marino 	if (!cbb_init(cbb, buf, initial_capacity)) {
60f5b1c8a1SJohn Marino 		free(buf);
61f5b1c8a1SJohn Marino 		return 0;
62f5b1c8a1SJohn Marino 	}
63f5b1c8a1SJohn Marino 
64f5b1c8a1SJohn Marino 	return 1;
65f5b1c8a1SJohn Marino }
66f5b1c8a1SJohn Marino 
67f5b1c8a1SJohn Marino int
68f5b1c8a1SJohn Marino CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len)
69f5b1c8a1SJohn Marino {
70f5b1c8a1SJohn Marino 	memset(cbb, 0, sizeof(*cbb));
71f5b1c8a1SJohn Marino 
72f5b1c8a1SJohn Marino 	if (!cbb_init(cbb, buf, len))
73f5b1c8a1SJohn Marino 		return 0;
74f5b1c8a1SJohn Marino 
75f5b1c8a1SJohn Marino 	cbb->base->can_resize = 0;
76f5b1c8a1SJohn Marino 
77f5b1c8a1SJohn Marino 	return 1;
78f5b1c8a1SJohn Marino }
79f5b1c8a1SJohn Marino 
80f5b1c8a1SJohn Marino void
81f5b1c8a1SJohn Marino CBB_cleanup(CBB *cbb)
82f5b1c8a1SJohn Marino {
83f5b1c8a1SJohn Marino 	if (cbb->base) {
84f5b1c8a1SJohn Marino 		if (cbb->base->can_resize)
85*72c33676SMaxim Ag 			freezero(cbb->base->buf, cbb->base->cap);
86f5b1c8a1SJohn Marino 		free(cbb->base);
87f5b1c8a1SJohn Marino 	}
88f5b1c8a1SJohn Marino 	cbb->base = NULL;
89*72c33676SMaxim Ag 	cbb->child = NULL;
90f5b1c8a1SJohn Marino }
91f5b1c8a1SJohn Marino 
92f5b1c8a1SJohn Marino static int
93f5b1c8a1SJohn Marino cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out, size_t len)
94f5b1c8a1SJohn Marino {
95f5b1c8a1SJohn Marino 	size_t newlen;
96f5b1c8a1SJohn Marino 
97f5b1c8a1SJohn Marino 	if (base == NULL)
98f5b1c8a1SJohn Marino 		return 0;
99f5b1c8a1SJohn Marino 
100f5b1c8a1SJohn Marino 	newlen = base->len + len;
101f5b1c8a1SJohn Marino 	if (newlen < base->len)
102f5b1c8a1SJohn Marino 		/* Overflow */
103f5b1c8a1SJohn Marino 		return 0;
104f5b1c8a1SJohn Marino 
105f5b1c8a1SJohn Marino 	if (newlen > base->cap) {
106f5b1c8a1SJohn Marino 		size_t newcap = base->cap * 2;
107f5b1c8a1SJohn Marino 		uint8_t *newbuf;
108f5b1c8a1SJohn Marino 
109f5b1c8a1SJohn Marino 		if (!base->can_resize)
110f5b1c8a1SJohn Marino 			return 0;
111f5b1c8a1SJohn Marino 
112f5b1c8a1SJohn Marino 		if (newcap < base->cap || newcap < newlen)
113f5b1c8a1SJohn Marino 			newcap = newlen;
114f5b1c8a1SJohn Marino 
115*72c33676SMaxim Ag 		newbuf = recallocarray(base->buf, base->cap, newcap, 1);
116f5b1c8a1SJohn Marino 		if (newbuf == NULL)
117f5b1c8a1SJohn Marino 			return 0;
118f5b1c8a1SJohn Marino 
119f5b1c8a1SJohn Marino 		base->buf = newbuf;
120f5b1c8a1SJohn Marino 		base->cap = newcap;
121f5b1c8a1SJohn Marino 	}
122f5b1c8a1SJohn Marino 
123f5b1c8a1SJohn Marino 	if (out)
124f5b1c8a1SJohn Marino 		*out = base->buf + base->len;
125f5b1c8a1SJohn Marino 
126f5b1c8a1SJohn Marino 	base->len = newlen;
127f5b1c8a1SJohn Marino 	return 1;
128f5b1c8a1SJohn Marino }
129f5b1c8a1SJohn Marino 
130f5b1c8a1SJohn Marino static int
131f5b1c8a1SJohn Marino cbb_add_u(CBB *cbb, uint32_t v, size_t len_len)
132f5b1c8a1SJohn Marino {
133f5b1c8a1SJohn Marino 	uint8_t *buf;
134f5b1c8a1SJohn Marino 	size_t i;
135f5b1c8a1SJohn Marino 
136f5b1c8a1SJohn Marino 	if (len_len == 0)
137f5b1c8a1SJohn Marino 		return 1;
138f5b1c8a1SJohn Marino 
139f5b1c8a1SJohn Marino 	if (len_len > 4)
140f5b1c8a1SJohn Marino 		return 0;
141f5b1c8a1SJohn Marino 
142f5b1c8a1SJohn Marino 	if (!CBB_flush(cbb) || !cbb_buffer_add(cbb->base, &buf, len_len))
143f5b1c8a1SJohn Marino 		return 0;
144f5b1c8a1SJohn Marino 
145f5b1c8a1SJohn Marino 	for (i = len_len - 1; i < len_len; i--) {
146f5b1c8a1SJohn Marino 		buf[i] = v;
147f5b1c8a1SJohn Marino 		v >>= 8;
148f5b1c8a1SJohn Marino 	}
149f5b1c8a1SJohn Marino 	return 1;
150f5b1c8a1SJohn Marino }
151f5b1c8a1SJohn Marino 
152f5b1c8a1SJohn Marino int
153f5b1c8a1SJohn Marino CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len)
154f5b1c8a1SJohn Marino {
155f5b1c8a1SJohn Marino 	if (!cbb->is_top_level)
156f5b1c8a1SJohn Marino 		return 0;
157f5b1c8a1SJohn Marino 
158f5b1c8a1SJohn Marino 	if (!CBB_flush(cbb))
159f5b1c8a1SJohn Marino 		return 0;
160f5b1c8a1SJohn Marino 
161f5b1c8a1SJohn Marino 	if (cbb->base->can_resize && (out_data == NULL || out_len == NULL))
162f5b1c8a1SJohn Marino 		/*
163f5b1c8a1SJohn Marino 		 * |out_data| and |out_len| can only be NULL if the CBB is
164f5b1c8a1SJohn Marino 		 * fixed.
165f5b1c8a1SJohn Marino 		 */
166f5b1c8a1SJohn Marino 		return 0;
167f5b1c8a1SJohn Marino 
168f5b1c8a1SJohn Marino 	if (out_data != NULL)
169f5b1c8a1SJohn Marino 		*out_data = cbb->base->buf;
170f5b1c8a1SJohn Marino 
171f5b1c8a1SJohn Marino 	if (out_len != NULL)
172f5b1c8a1SJohn Marino 		*out_len = cbb->base->len;
173f5b1c8a1SJohn Marino 
174f5b1c8a1SJohn Marino 	cbb->base->buf = NULL;
175f5b1c8a1SJohn Marino 	CBB_cleanup(cbb);
176f5b1c8a1SJohn Marino 	return 1;
177f5b1c8a1SJohn Marino }
178f5b1c8a1SJohn Marino 
179f5b1c8a1SJohn Marino /*
180f5b1c8a1SJohn Marino  * CBB_flush recurses and then writes out any pending length prefix. The current
181f5b1c8a1SJohn Marino  * length of the underlying base is taken to be the length of the
182f5b1c8a1SJohn Marino  * length-prefixed data.
183f5b1c8a1SJohn Marino  */
184f5b1c8a1SJohn Marino int
185f5b1c8a1SJohn Marino CBB_flush(CBB *cbb)
186f5b1c8a1SJohn Marino {
187f5b1c8a1SJohn Marino 	size_t child_start, i, len;
188f5b1c8a1SJohn Marino 
189f5b1c8a1SJohn Marino 	if (cbb->base == NULL)
190f5b1c8a1SJohn Marino 		return 0;
191f5b1c8a1SJohn Marino 
192f5b1c8a1SJohn Marino 	if (cbb->child == NULL || cbb->pending_len_len == 0)
193f5b1c8a1SJohn Marino 		return 1;
194f5b1c8a1SJohn Marino 
195f5b1c8a1SJohn Marino 	child_start = cbb->offset + cbb->pending_len_len;
196f5b1c8a1SJohn Marino 
197f5b1c8a1SJohn Marino 	if (!CBB_flush(cbb->child) || child_start < cbb->offset ||
198f5b1c8a1SJohn Marino 	    cbb->base->len < child_start)
199f5b1c8a1SJohn Marino 		return 0;
200f5b1c8a1SJohn Marino 
201f5b1c8a1SJohn Marino 	len = cbb->base->len - child_start;
202f5b1c8a1SJohn Marino 
203f5b1c8a1SJohn Marino 	if (cbb->pending_is_asn1) {
204f5b1c8a1SJohn Marino 		/*
205f5b1c8a1SJohn Marino 		 * For ASN.1, we assumed that we were using short form which
206f5b1c8a1SJohn Marino 		 * only requires a single byte for the length octet.
207f5b1c8a1SJohn Marino 		 *
208f5b1c8a1SJohn Marino 		 * If it turns out that we need long form, we have to move
209f5b1c8a1SJohn Marino 		 * the contents along in order to make space for more length
210f5b1c8a1SJohn Marino 		 * octets.
211f5b1c8a1SJohn Marino 		 */
212f5b1c8a1SJohn Marino 		size_t len_len = 1;  /* total number of length octets */
213f5b1c8a1SJohn Marino 		uint8_t initial_length_byte;
214f5b1c8a1SJohn Marino 
215f5b1c8a1SJohn Marino 		/* We already wrote 1 byte for the length. */
216*72c33676SMaxim Ag 		if (cbb->pending_len_len != 1)
217*72c33676SMaxim Ag 			return 0;
218f5b1c8a1SJohn Marino 
219f5b1c8a1SJohn Marino 		/* Check for long form */
220f5b1c8a1SJohn Marino 		if (len > 0xfffffffe)
221f5b1c8a1SJohn Marino 			return 0;	/* 0xffffffff is reserved */
222f5b1c8a1SJohn Marino 		else if (len > 0xffffff)
223f5b1c8a1SJohn Marino 			len_len = 5;
224f5b1c8a1SJohn Marino 		else if (len > 0xffff)
225f5b1c8a1SJohn Marino 			len_len = 4;
226f5b1c8a1SJohn Marino 		else if (len > 0xff)
227f5b1c8a1SJohn Marino 			len_len = 3;
228f5b1c8a1SJohn Marino 		else if (len > 0x7f)
229f5b1c8a1SJohn Marino 			len_len = 2;
230f5b1c8a1SJohn Marino 
231f5b1c8a1SJohn Marino 		if (len_len == 1) {
232f5b1c8a1SJohn Marino 			/* For short form, the initial byte is the length. */
233f5b1c8a1SJohn Marino 			initial_length_byte = len;
234f5b1c8a1SJohn Marino 			len = 0;
235f5b1c8a1SJohn Marino 
236f5b1c8a1SJohn Marino 		} else {
237f5b1c8a1SJohn Marino 			/*
238f5b1c8a1SJohn Marino 			 * For long form, the initial byte is the number of
239f5b1c8a1SJohn Marino 			 * subsequent length octets (plus bit 8 set).
240f5b1c8a1SJohn Marino 			 */
241f5b1c8a1SJohn Marino 			initial_length_byte = 0x80 | (len_len - 1);
242f5b1c8a1SJohn Marino 
243f5b1c8a1SJohn Marino 			/*
244f5b1c8a1SJohn Marino 			 * We need to move the contents along in order to make
245f5b1c8a1SJohn Marino 			 * space for the long form length octets.
246f5b1c8a1SJohn Marino 			 */
247f5b1c8a1SJohn Marino 			size_t extra_bytes = len_len - 1;
248f5b1c8a1SJohn Marino 			if (!cbb_buffer_add(cbb->base, NULL, extra_bytes))
249f5b1c8a1SJohn Marino 				return 0;
250f5b1c8a1SJohn Marino 
251f5b1c8a1SJohn Marino 			memmove(cbb->base->buf + child_start + extra_bytes,
252f5b1c8a1SJohn Marino 			    cbb->base->buf + child_start, len);
253f5b1c8a1SJohn Marino 		}
254f5b1c8a1SJohn Marino 		cbb->base->buf[cbb->offset++] = initial_length_byte;
255f5b1c8a1SJohn Marino 		cbb->pending_len_len = len_len - 1;
256f5b1c8a1SJohn Marino 	}
257f5b1c8a1SJohn Marino 
258f5b1c8a1SJohn Marino 	for (i = cbb->pending_len_len - 1; i < cbb->pending_len_len; i--) {
259f5b1c8a1SJohn Marino 		cbb->base->buf[cbb->offset + i] = len;
260f5b1c8a1SJohn Marino 		len >>= 8;
261f5b1c8a1SJohn Marino 	}
262f5b1c8a1SJohn Marino 	if (len != 0)
263f5b1c8a1SJohn Marino 		return 0;
264f5b1c8a1SJohn Marino 
265f5b1c8a1SJohn Marino 	cbb->child->base = NULL;
266f5b1c8a1SJohn Marino 	cbb->child = NULL;
267f5b1c8a1SJohn Marino 	cbb->pending_len_len = 0;
268f5b1c8a1SJohn Marino 	cbb->pending_is_asn1 = 0;
269f5b1c8a1SJohn Marino 	cbb->offset = 0;
270f5b1c8a1SJohn Marino 
271f5b1c8a1SJohn Marino 	return 1;
272f5b1c8a1SJohn Marino }
273f5b1c8a1SJohn Marino 
274*72c33676SMaxim Ag void
275*72c33676SMaxim Ag CBB_discard_child(CBB *cbb)
276*72c33676SMaxim Ag {
277*72c33676SMaxim Ag 	if (cbb->child == NULL)
278*72c33676SMaxim Ag 		return;
279*72c33676SMaxim Ag 
280*72c33676SMaxim Ag 	cbb->base->len = cbb->offset;
281*72c33676SMaxim Ag 
282*72c33676SMaxim Ag 	cbb->child->base = NULL;
283*72c33676SMaxim Ag 	cbb->child = NULL;
284*72c33676SMaxim Ag 	cbb->pending_len_len = 0;
285*72c33676SMaxim Ag 	cbb->pending_is_asn1 = 0;
286*72c33676SMaxim Ag 	cbb->offset = 0;
287*72c33676SMaxim Ag }
288f5b1c8a1SJohn Marino 
289f5b1c8a1SJohn Marino static int
290f5b1c8a1SJohn Marino cbb_add_length_prefixed(CBB *cbb, CBB *out_contents, size_t len_len)
291f5b1c8a1SJohn Marino {
292f5b1c8a1SJohn Marino 	uint8_t *prefix_bytes;
293f5b1c8a1SJohn Marino 
294f5b1c8a1SJohn Marino 	if (!CBB_flush(cbb))
295f5b1c8a1SJohn Marino 		return 0;
296f5b1c8a1SJohn Marino 
297f5b1c8a1SJohn Marino 	cbb->offset = cbb->base->len;
298f5b1c8a1SJohn Marino 	if (!cbb_buffer_add(cbb->base, &prefix_bytes, len_len))
299f5b1c8a1SJohn Marino 		return 0;
300f5b1c8a1SJohn Marino 
301f5b1c8a1SJohn Marino 	memset(prefix_bytes, 0, len_len);
302f5b1c8a1SJohn Marino 	memset(out_contents, 0, sizeof(CBB));
303f5b1c8a1SJohn Marino 	out_contents->base = cbb->base;
304f5b1c8a1SJohn Marino 	cbb->child = out_contents;
305f5b1c8a1SJohn Marino 	cbb->pending_len_len = len_len;
306f5b1c8a1SJohn Marino 	cbb->pending_is_asn1 = 0;
307f5b1c8a1SJohn Marino 
308f5b1c8a1SJohn Marino 	return 1;
309f5b1c8a1SJohn Marino }
310f5b1c8a1SJohn Marino 
311f5b1c8a1SJohn Marino int
312f5b1c8a1SJohn Marino CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents)
313f5b1c8a1SJohn Marino {
314f5b1c8a1SJohn Marino 	return cbb_add_length_prefixed(cbb, out_contents, 1);
315f5b1c8a1SJohn Marino }
316f5b1c8a1SJohn Marino 
317f5b1c8a1SJohn Marino int
318f5b1c8a1SJohn Marino CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents)
319f5b1c8a1SJohn Marino {
320f5b1c8a1SJohn Marino 	return cbb_add_length_prefixed(cbb, out_contents, 2);
321f5b1c8a1SJohn Marino }
322f5b1c8a1SJohn Marino 
323f5b1c8a1SJohn Marino int
324f5b1c8a1SJohn Marino CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents)
325f5b1c8a1SJohn Marino {
326f5b1c8a1SJohn Marino 	return cbb_add_length_prefixed(cbb, out_contents, 3);
327f5b1c8a1SJohn Marino }
328f5b1c8a1SJohn Marino 
329f5b1c8a1SJohn Marino int
330f5b1c8a1SJohn Marino CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned int tag)
331f5b1c8a1SJohn Marino {
332f5b1c8a1SJohn Marino 	if (tag > UINT8_MAX)
333f5b1c8a1SJohn Marino 		return 0;
334f5b1c8a1SJohn Marino 
335f5b1c8a1SJohn Marino 	/* Long form identifier octets are not supported. */
336f5b1c8a1SJohn Marino 	if ((tag & 0x1f) == 0x1f)
337f5b1c8a1SJohn Marino 		return 0;
338f5b1c8a1SJohn Marino 
339f5b1c8a1SJohn Marino 	/* Short-form identifier octet only needs a single byte */
340f5b1c8a1SJohn Marino 	if (!CBB_flush(cbb) || !CBB_add_u8(cbb, tag))
341f5b1c8a1SJohn Marino 		return 0;
342f5b1c8a1SJohn Marino 
343f5b1c8a1SJohn Marino 	/*
344f5b1c8a1SJohn Marino 	 * Add 1 byte to cover the short-form length octet case.  If it turns
345f5b1c8a1SJohn Marino 	 * out we need long-form, it will be extended later.
346f5b1c8a1SJohn Marino 	 */
347f5b1c8a1SJohn Marino 	cbb->offset = cbb->base->len;
348f5b1c8a1SJohn Marino 	if (!CBB_add_u8(cbb, 0))
349f5b1c8a1SJohn Marino 		return 0;
350f5b1c8a1SJohn Marino 
351f5b1c8a1SJohn Marino 	memset(out_contents, 0, sizeof(CBB));
352f5b1c8a1SJohn Marino 	out_contents->base = cbb->base;
353f5b1c8a1SJohn Marino 	cbb->child = out_contents;
354f5b1c8a1SJohn Marino 	cbb->pending_len_len = 1;
355f5b1c8a1SJohn Marino 	cbb->pending_is_asn1 = 1;
356f5b1c8a1SJohn Marino 
357f5b1c8a1SJohn Marino 	return 1;
358f5b1c8a1SJohn Marino }
359f5b1c8a1SJohn Marino 
360f5b1c8a1SJohn Marino int
361f5b1c8a1SJohn Marino CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len)
362f5b1c8a1SJohn Marino {
363f5b1c8a1SJohn Marino 	uint8_t *dest;
364f5b1c8a1SJohn Marino 
365f5b1c8a1SJohn Marino 	if (!CBB_add_space(cbb, &dest, len))
366f5b1c8a1SJohn Marino 		return 0;
367f5b1c8a1SJohn Marino 
368f5b1c8a1SJohn Marino 	memcpy(dest, data, len);
369f5b1c8a1SJohn Marino 	return 1;
370f5b1c8a1SJohn Marino }
371f5b1c8a1SJohn Marino 
372f5b1c8a1SJohn Marino int
373f5b1c8a1SJohn Marino CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len)
374f5b1c8a1SJohn Marino {
375f5b1c8a1SJohn Marino 	if (!CBB_flush(cbb) || !cbb_buffer_add(cbb->base, out_data, len))
376f5b1c8a1SJohn Marino 		return 0;
377f5b1c8a1SJohn Marino 
378f5b1c8a1SJohn Marino 	return 1;
379f5b1c8a1SJohn Marino }
380f5b1c8a1SJohn Marino 
381f5b1c8a1SJohn Marino int
382f5b1c8a1SJohn Marino CBB_add_u8(CBB *cbb, size_t value)
383f5b1c8a1SJohn Marino {
384f5b1c8a1SJohn Marino 	if (value > UINT8_MAX)
385f5b1c8a1SJohn Marino 		return 0;
386f5b1c8a1SJohn Marino 
387f5b1c8a1SJohn Marino 	return cbb_add_u(cbb, (uint32_t)value, 1);
388f5b1c8a1SJohn Marino }
389f5b1c8a1SJohn Marino 
390f5b1c8a1SJohn Marino int
391f5b1c8a1SJohn Marino CBB_add_u16(CBB *cbb, size_t value)
392f5b1c8a1SJohn Marino {
393f5b1c8a1SJohn Marino 	if (value > UINT16_MAX)
394f5b1c8a1SJohn Marino 		return 0;
395f5b1c8a1SJohn Marino 
396f5b1c8a1SJohn Marino 	return cbb_add_u(cbb, (uint32_t)value, 2);
397f5b1c8a1SJohn Marino }
398f5b1c8a1SJohn Marino 
399f5b1c8a1SJohn Marino int
400f5b1c8a1SJohn Marino CBB_add_u24(CBB *cbb, size_t value)
401f5b1c8a1SJohn Marino {
402f5b1c8a1SJohn Marino 	if (value > 0xffffffUL)
403f5b1c8a1SJohn Marino 		return 0;
404f5b1c8a1SJohn Marino 
405f5b1c8a1SJohn Marino 	return cbb_add_u(cbb, (uint32_t)value, 3);
406f5b1c8a1SJohn Marino }
407f5b1c8a1SJohn Marino 
408f5b1c8a1SJohn Marino int
409*72c33676SMaxim Ag CBB_add_u32(CBB *cbb, size_t value)
410*72c33676SMaxim Ag {
411*72c33676SMaxim Ag 	if (value > 0xffffffffUL)
412*72c33676SMaxim Ag 		return 0;
413*72c33676SMaxim Ag 
414*72c33676SMaxim Ag 	return cbb_add_u(cbb, (uint32_t)value, 4);
415*72c33676SMaxim Ag }
416*72c33676SMaxim Ag 
417*72c33676SMaxim Ag int
418f5b1c8a1SJohn Marino CBB_add_asn1_uint64(CBB *cbb, uint64_t value)
419f5b1c8a1SJohn Marino {
420f5b1c8a1SJohn Marino 	CBB child;
421f5b1c8a1SJohn Marino 	size_t i;
422f5b1c8a1SJohn Marino 	int started = 0;
423f5b1c8a1SJohn Marino 
424f5b1c8a1SJohn Marino 	if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER))
425f5b1c8a1SJohn Marino 		return 0;
426f5b1c8a1SJohn Marino 
427f5b1c8a1SJohn Marino 	for (i = 0; i < 8; i++) {
428f5b1c8a1SJohn Marino 		uint8_t byte = (value >> 8 * (7 - i)) & 0xff;
429f5b1c8a1SJohn Marino 
430f5b1c8a1SJohn Marino 		/*
431f5b1c8a1SJohn Marino 		 * ASN.1 restriction: first 9 bits cannot be all zeroes or
432f5b1c8a1SJohn Marino 		 * all ones.  Since this function only encodes unsigned
433f5b1c8a1SJohn Marino 		 * integers, the only concerns are not encoding leading
434f5b1c8a1SJohn Marino 		 * zeros and adding a padding byte if necessary.
435f5b1c8a1SJohn Marino 		 *
436f5b1c8a1SJohn Marino 		 * In practice, this means:
437f5b1c8a1SJohn Marino 		 * 1) Skip leading octets of all zero bits in the value
438f5b1c8a1SJohn Marino 		 * 2) After skipping the leading zero octets, if the next 9
439f5b1c8a1SJohn Marino 		 *    bits are all ones, add an all zero prefix octet (and
440f5b1c8a1SJohn Marino 		 *    set the high bit of the prefix octet if negative).
441f5b1c8a1SJohn Marino 		 *
442f5b1c8a1SJohn Marino 		 * Additionally, for an unsigned value, add an all zero
443f5b1c8a1SJohn Marino 		 * prefix if the high bit of the first octet would be one.
444f5b1c8a1SJohn Marino 		 */
445f5b1c8a1SJohn Marino 		if (!started) {
446f5b1c8a1SJohn Marino 			if (byte == 0)
447f5b1c8a1SJohn Marino 				/* Don't encode leading zeros. */
448f5b1c8a1SJohn Marino 				continue;
449f5b1c8a1SJohn Marino 
450f5b1c8a1SJohn Marino 			/*
451f5b1c8a1SJohn Marino 			 * If the high bit is set, add a padding byte to make it
452f5b1c8a1SJohn Marino 			 * unsigned.
453f5b1c8a1SJohn Marino 			 */
454f5b1c8a1SJohn Marino 			if ((byte & 0x80) && !CBB_add_u8(&child, 0))
455f5b1c8a1SJohn Marino 				return 0;
456f5b1c8a1SJohn Marino 
457f5b1c8a1SJohn Marino 			started = 1;
458f5b1c8a1SJohn Marino 		}
459f5b1c8a1SJohn Marino 		if (!CBB_add_u8(&child, byte))
460f5b1c8a1SJohn Marino 			return 0;
461f5b1c8a1SJohn Marino 	}
462f5b1c8a1SJohn Marino 
463f5b1c8a1SJohn Marino 	/* 0 is encoded as a single 0, not the empty string. */
464f5b1c8a1SJohn Marino 	if (!started && !CBB_add_u8(&child, 0))
465f5b1c8a1SJohn Marino 		return 0;
466f5b1c8a1SJohn Marino 
467f5b1c8a1SJohn Marino 	return CBB_flush(cbb);
468f5b1c8a1SJohn Marino }
469