xref: /openbsd/lib/libssl/bs_cbb.c (revision c57a2cde)
1*c57a2cdeStb /*	$OpenBSD: bs_cbb.c,v 1.29 2024/05/25 15:14:26 tb Exp $	*/
2c4905cd3Sdoug /*
3c4905cd3Sdoug  * Copyright (c) 2014, Google Inc.
4c4905cd3Sdoug  *
5c4905cd3Sdoug  * Permission to use, copy, modify, and/or distribute this software for any
6c4905cd3Sdoug  * purpose with or without fee is hereby granted, provided that the above
7c4905cd3Sdoug  * copyright notice and this permission notice appear in all copies.
8c4905cd3Sdoug  *
9c4905cd3Sdoug  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10c4905cd3Sdoug  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11c4905cd3Sdoug  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
12c4905cd3Sdoug  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13c4905cd3Sdoug  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
14c4905cd3Sdoug  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15d2f1cbaeSjsing  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16d2f1cbaeSjsing  */
17c4905cd3Sdoug 
18*c57a2cdeStb #include <stdint.h>
19c4905cd3Sdoug #include <stdlib.h>
20c4905cd3Sdoug #include <string.h>
21c4905cd3Sdoug 
22c4905cd3Sdoug #include "bytestring.h"
23c4905cd3Sdoug 
24c99575daSjsing #define CBB_INITIAL_SIZE 64
25c99575daSjsing 
26732f1cb2Sdoug static int
cbb_init(CBB * cbb,uint8_t * buf,size_t cap)27732f1cb2Sdoug cbb_init(CBB *cbb, uint8_t *buf, size_t cap)
28732f1cb2Sdoug {
29c4905cd3Sdoug 	struct cbb_buffer_st *base;
30c4905cd3Sdoug 
31ef0fedfaSjsing 	if ((base = calloc(1, sizeof(struct cbb_buffer_st))) == NULL)
32c4905cd3Sdoug 		return 0;
33c4905cd3Sdoug 
34c4905cd3Sdoug 	base->buf = buf;
35c4905cd3Sdoug 	base->len = 0;
36c4905cd3Sdoug 	base->cap = cap;
37c4905cd3Sdoug 	base->can_resize = 1;
38c4905cd3Sdoug 
39c4905cd3Sdoug 	cbb->base = base;
40c4905cd3Sdoug 	cbb->is_top_level = 1;
4128a1f398Sjsing 
42c4905cd3Sdoug 	return 1;
43c4905cd3Sdoug }
44c4905cd3Sdoug 
45732f1cb2Sdoug int
CBB_init(CBB * cbb,size_t initial_capacity)46732f1cb2Sdoug CBB_init(CBB *cbb, size_t initial_capacity)
47732f1cb2Sdoug {
483a0c64b9Sdoug 	uint8_t *buf = NULL;
49c4905cd3Sdoug 
5028a1f398Sjsing 	memset(cbb, 0, sizeof(*cbb));
5128a1f398Sjsing 
52c99575daSjsing 	if (initial_capacity == 0)
53c99575daSjsing 		initial_capacity = CBB_INITIAL_SIZE;
54c99575daSjsing 
55ef0fedfaSjsing 	if ((buf = calloc(1, initial_capacity)) == NULL)
56c4905cd3Sdoug 		return 0;
57c4905cd3Sdoug 
5841724196Sdoug 	if (!cbb_init(cbb, buf, initial_capacity)) {
5941724196Sdoug 		free(buf);
6041724196Sdoug 		return 0;
6141724196Sdoug 	}
6228a1f398Sjsing 
6341724196Sdoug 	return 1;
64c4905cd3Sdoug }
65c4905cd3Sdoug 
66732f1cb2Sdoug int
CBB_init_fixed(CBB * cbb,uint8_t * buf,size_t len)67732f1cb2Sdoug CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len)
68732f1cb2Sdoug {
6928a1f398Sjsing 	memset(cbb, 0, sizeof(*cbb));
7028a1f398Sjsing 
71732f1cb2Sdoug 	if (!cbb_init(cbb, buf, len))
72c4905cd3Sdoug 		return 0;
73c4905cd3Sdoug 
74c4905cd3Sdoug 	cbb->base->can_resize = 0;
7528a1f398Sjsing 
76c4905cd3Sdoug 	return 1;
77c4905cd3Sdoug }
78c4905cd3Sdoug 
79732f1cb2Sdoug void
CBB_cleanup(CBB * cbb)80732f1cb2Sdoug CBB_cleanup(CBB *cbb)
81732f1cb2Sdoug {
82c4905cd3Sdoug 	if (cbb->base) {
833a0c64b9Sdoug 		if (cbb->base->can_resize)
842a6b7f1dSjsing 			freezero(cbb->base->buf, cbb->base->cap);
85c4905cd3Sdoug 		free(cbb->base);
86c4905cd3Sdoug 	}
87c4905cd3Sdoug 	cbb->base = NULL;
889234d803Sjsing 	cbb->child = NULL;
89c4905cd3Sdoug }
90c4905cd3Sdoug 
91732f1cb2Sdoug static int
cbb_buffer_add(struct cbb_buffer_st * base,uint8_t ** out,size_t len)92732f1cb2Sdoug cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out, size_t len)
93732f1cb2Sdoug {
94c4905cd3Sdoug 	size_t newlen;
95c4905cd3Sdoug 
96732f1cb2Sdoug 	if (base == NULL)
97c4905cd3Sdoug 		return 0;
98c4905cd3Sdoug 
99c4905cd3Sdoug 	newlen = base->len + len;
100732f1cb2Sdoug 	if (newlen < base->len)
101c4905cd3Sdoug 		/* Overflow */
102c4905cd3Sdoug 		return 0;
103c4905cd3Sdoug 
104c4905cd3Sdoug 	if (newlen > base->cap) {
105c4905cd3Sdoug 		size_t newcap = base->cap * 2;
106c4905cd3Sdoug 		uint8_t *newbuf;
107c4905cd3Sdoug 
108732f1cb2Sdoug 		if (!base->can_resize)
109c4905cd3Sdoug 			return 0;
110c4905cd3Sdoug 
111732f1cb2Sdoug 		if (newcap < base->cap || newcap < newlen)
112c4905cd3Sdoug 			newcap = newlen;
113732f1cb2Sdoug 
11442ccf58dSjsing 		newbuf = recallocarray(base->buf, base->cap, newcap, 1);
115732f1cb2Sdoug 		if (newbuf == NULL)
116c4905cd3Sdoug 			return 0;
117c4905cd3Sdoug 
118c4905cd3Sdoug 		base->buf = newbuf;
119c4905cd3Sdoug 		base->cap = newcap;
120c4905cd3Sdoug 	}
121c4905cd3Sdoug 
122732f1cb2Sdoug 	if (out)
123c4905cd3Sdoug 		*out = base->buf + base->len;
124732f1cb2Sdoug 
125c4905cd3Sdoug 	base->len = newlen;
126c4905cd3Sdoug 	return 1;
127c4905cd3Sdoug }
128c4905cd3Sdoug 
129732f1cb2Sdoug static int
cbb_add_u(CBB * cbb,uint32_t v,size_t len_len)130f49f1317Sdoug cbb_add_u(CBB *cbb, uint32_t v, size_t len_len)
131732f1cb2Sdoug {
132c4905cd3Sdoug 	uint8_t *buf;
133c4905cd3Sdoug 	size_t i;
134c4905cd3Sdoug 
135732f1cb2Sdoug 	if (len_len == 0)
136c4905cd3Sdoug 		return 1;
137732f1cb2Sdoug 
138c2c0b151Sdoug 	if (len_len > 4)
139c2c0b151Sdoug 		return 0;
140c2c0b151Sdoug 
141f49f1317Sdoug 	if (!CBB_flush(cbb) || !cbb_buffer_add(cbb->base, &buf, len_len))
142c4905cd3Sdoug 		return 0;
143c4905cd3Sdoug 
144c4905cd3Sdoug 	for (i = len_len - 1; i < len_len; i--) {
145c4905cd3Sdoug 		buf[i] = v;
146c4905cd3Sdoug 		v >>= 8;
147c4905cd3Sdoug 	}
148c4905cd3Sdoug 	return 1;
149c4905cd3Sdoug }
150c4905cd3Sdoug 
151732f1cb2Sdoug int
CBB_finish(CBB * cbb,uint8_t ** out_data,size_t * out_len)152732f1cb2Sdoug CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len)
153732f1cb2Sdoug {
154732f1cb2Sdoug 	if (!cbb->is_top_level)
155c4905cd3Sdoug 		return 0;
156c4905cd3Sdoug 
157732f1cb2Sdoug 	if (!CBB_flush(cbb))
158c4905cd3Sdoug 		return 0;
159c4905cd3Sdoug 
160732f1cb2Sdoug 	if (cbb->base->can_resize && (out_data == NULL || out_len == NULL))
161d7a08d8fSdoug 		/*
162d7a08d8fSdoug 		 * |out_data| and |out_len| can only be NULL if the CBB is
163d7a08d8fSdoug 		 * fixed.
164d7a08d8fSdoug 		 */
165c4905cd3Sdoug 		return 0;
166c4905cd3Sdoug 
1678ba2322eStb 	if (out_data != NULL && *out_data != NULL)
1688ba2322eStb 		return 0;
1698ba2322eStb 
170732f1cb2Sdoug 	if (out_data != NULL)
171c4905cd3Sdoug 		*out_data = cbb->base->buf;
172732f1cb2Sdoug 
173732f1cb2Sdoug 	if (out_len != NULL)
174c4905cd3Sdoug 		*out_len = cbb->base->len;
175732f1cb2Sdoug 
176c4905cd3Sdoug 	cbb->base->buf = NULL;
177c4905cd3Sdoug 	CBB_cleanup(cbb);
178c4905cd3Sdoug 	return 1;
179c4905cd3Sdoug }
180c4905cd3Sdoug 
181732f1cb2Sdoug /*
182732f1cb2Sdoug  * CBB_flush recurses and then writes out any pending length prefix. The current
183732f1cb2Sdoug  * length of the underlying base is taken to be the length of the
184732f1cb2Sdoug  * length-prefixed data.
185732f1cb2Sdoug  */
186732f1cb2Sdoug int
CBB_flush(CBB * cbb)187732f1cb2Sdoug CBB_flush(CBB *cbb)
188732f1cb2Sdoug {
189c4905cd3Sdoug 	size_t child_start, i, len;
190c4905cd3Sdoug 
191732f1cb2Sdoug 	if (cbb->base == NULL)
192c4905cd3Sdoug 		return 0;
193c4905cd3Sdoug 
194732f1cb2Sdoug 	if (cbb->child == NULL || cbb->pending_len_len == 0)
195c4905cd3Sdoug 		return 1;
196c4905cd3Sdoug 
197c4905cd3Sdoug 	child_start = cbb->offset + cbb->pending_len_len;
198c4905cd3Sdoug 
199732f1cb2Sdoug 	if (!CBB_flush(cbb->child) || child_start < cbb->offset ||
200732f1cb2Sdoug 	    cbb->base->len < child_start)
201c4905cd3Sdoug 		return 0;
202c4905cd3Sdoug 
203c4905cd3Sdoug 	len = cbb->base->len - child_start;
204c4905cd3Sdoug 
205c4905cd3Sdoug 	if (cbb->pending_is_asn1) {
206d7a08d8fSdoug 		/*
2076ea8e45cSdoug 		 * For ASN.1, we assumed that we were using short form which
2086ea8e45cSdoug 		 * only requires a single byte for the length octet.
2096ea8e45cSdoug 		 *
2106ea8e45cSdoug 		 * If it turns out that we need long form, we have to move
2116ea8e45cSdoug 		 * the contents along in order to make space for more length
2126ea8e45cSdoug 		 * octets.
213d7a08d8fSdoug 		 */
2146ea8e45cSdoug 		size_t len_len = 1;  /* total number of length octets */
215c4905cd3Sdoug 		uint8_t initial_length_byte;
216c4905cd3Sdoug 
2176ea8e45cSdoug 		/* We already wrote 1 byte for the length. */
21859f50346Sbeck 		if (cbb->pending_len_len != 1)
21959f50346Sbeck 			return 0;
220c4905cd3Sdoug 
2216ea8e45cSdoug 		/* Check for long form */
2226ea8e45cSdoug 		if (len > 0xfffffffe)
2236ea8e45cSdoug 			return 0;	/* 0xffffffff is reserved */
2246ea8e45cSdoug 		else if (len > 0xffffff)
225c4905cd3Sdoug 			len_len = 5;
2266ea8e45cSdoug 		else if (len > 0xffff)
227c4905cd3Sdoug 			len_len = 4;
2286ea8e45cSdoug 		else if (len > 0xff)
229c4905cd3Sdoug 			len_len = 3;
2306ea8e45cSdoug 		else if (len > 0x7f)
231c4905cd3Sdoug 			len_len = 2;
2326ea8e45cSdoug 
2336ea8e45cSdoug 		if (len_len == 1) {
2346ea8e45cSdoug 			/* For short form, the initial byte is the length. */
235c4905cd3Sdoug 			initial_length_byte = len;
236c4905cd3Sdoug 			len = 0;
237c4905cd3Sdoug 
2386ea8e45cSdoug 		} else {
2396ea8e45cSdoug 			/*
2406ea8e45cSdoug 			 * For long form, the initial byte is the number of
2416ea8e45cSdoug 			 * subsequent length octets (plus bit 8 set).
2426ea8e45cSdoug 			 */
2436ea8e45cSdoug 			initial_length_byte = 0x80 | (len_len - 1);
2446ea8e45cSdoug 
245d7a08d8fSdoug 			/*
246d7a08d8fSdoug 			 * We need to move the contents along in order to make
2476ea8e45cSdoug 			 * space for the long form length octets.
248d7a08d8fSdoug 			 */
249c4905cd3Sdoug 			size_t extra_bytes = len_len - 1;
250732f1cb2Sdoug 			if (!cbb_buffer_add(cbb->base, NULL, extra_bytes))
251c4905cd3Sdoug 				return 0;
252732f1cb2Sdoug 
253c4905cd3Sdoug 			memmove(cbb->base->buf + child_start + extra_bytes,
254c4905cd3Sdoug 			    cbb->base->buf + child_start, len);
255c4905cd3Sdoug 		}
256c4905cd3Sdoug 		cbb->base->buf[cbb->offset++] = initial_length_byte;
257c4905cd3Sdoug 		cbb->pending_len_len = len_len - 1;
258c4905cd3Sdoug 	}
259c4905cd3Sdoug 
260c4905cd3Sdoug 	for (i = cbb->pending_len_len - 1; i < cbb->pending_len_len; i--) {
261c4905cd3Sdoug 		cbb->base->buf[cbb->offset + i] = len;
262c4905cd3Sdoug 		len >>= 8;
263c4905cd3Sdoug 	}
264732f1cb2Sdoug 	if (len != 0)
265c4905cd3Sdoug 		return 0;
266c4905cd3Sdoug 
267c4905cd3Sdoug 	cbb->child->base = NULL;
268c4905cd3Sdoug 	cbb->child = NULL;
269c4905cd3Sdoug 	cbb->pending_len_len = 0;
270c4905cd3Sdoug 	cbb->pending_is_asn1 = 0;
271c4905cd3Sdoug 	cbb->offset = 0;
272c4905cd3Sdoug 
273c4905cd3Sdoug 	return 1;
274c4905cd3Sdoug }
275c4905cd3Sdoug 
276e87ff5aeSjsing void
CBB_discard_child(CBB * cbb)277e87ff5aeSjsing CBB_discard_child(CBB *cbb)
278e87ff5aeSjsing {
279e87ff5aeSjsing 	if (cbb->child == NULL)
280e87ff5aeSjsing 		return;
281e87ff5aeSjsing 
282e87ff5aeSjsing 	cbb->base->len = cbb->offset;
283e87ff5aeSjsing 
284e87ff5aeSjsing 	cbb->child->base = NULL;
285e87ff5aeSjsing 	cbb->child = NULL;
286e87ff5aeSjsing 	cbb->pending_len_len = 0;
287e87ff5aeSjsing 	cbb->pending_is_asn1 = 0;
288e87ff5aeSjsing 	cbb->offset = 0;
289e87ff5aeSjsing }
290c4905cd3Sdoug 
291732f1cb2Sdoug static int
cbb_add_length_prefixed(CBB * cbb,CBB * out_contents,size_t len_len)292732f1cb2Sdoug cbb_add_length_prefixed(CBB *cbb, CBB *out_contents, size_t len_len)
293732f1cb2Sdoug {
294c4905cd3Sdoug 	uint8_t *prefix_bytes;
295c4905cd3Sdoug 
296732f1cb2Sdoug 	if (!CBB_flush(cbb))
297c4905cd3Sdoug 		return 0;
298c4905cd3Sdoug 
299c4905cd3Sdoug 	cbb->offset = cbb->base->len;
300732f1cb2Sdoug 	if (!cbb_buffer_add(cbb->base, &prefix_bytes, len_len))
301c4905cd3Sdoug 		return 0;
302c4905cd3Sdoug 
303c4905cd3Sdoug 	memset(prefix_bytes, 0, len_len);
304c4905cd3Sdoug 	memset(out_contents, 0, sizeof(CBB));
305c4905cd3Sdoug 	out_contents->base = cbb->base;
306c4905cd3Sdoug 	cbb->child = out_contents;
307c4905cd3Sdoug 	cbb->pending_len_len = len_len;
308c4905cd3Sdoug 	cbb->pending_is_asn1 = 0;
309c4905cd3Sdoug 
310c4905cd3Sdoug 	return 1;
311c4905cd3Sdoug }
312c4905cd3Sdoug 
313732f1cb2Sdoug int
CBB_add_u8_length_prefixed(CBB * cbb,CBB * out_contents)314732f1cb2Sdoug CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents)
315732f1cb2Sdoug {
316c4905cd3Sdoug 	return cbb_add_length_prefixed(cbb, out_contents, 1);
317c4905cd3Sdoug }
318c4905cd3Sdoug 
319732f1cb2Sdoug int
CBB_add_u16_length_prefixed(CBB * cbb,CBB * out_contents)320732f1cb2Sdoug CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents)
321732f1cb2Sdoug {
322c4905cd3Sdoug 	return cbb_add_length_prefixed(cbb, out_contents, 2);
323c4905cd3Sdoug }
324c4905cd3Sdoug 
325732f1cb2Sdoug int
CBB_add_u24_length_prefixed(CBB * cbb,CBB * out_contents)326732f1cb2Sdoug CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents)
327732f1cb2Sdoug {
328c4905cd3Sdoug 	return cbb_add_length_prefixed(cbb, out_contents, 3);
329c4905cd3Sdoug }
330c4905cd3Sdoug 
331732f1cb2Sdoug int
CBB_add_asn1(CBB * cbb,CBB * out_contents,unsigned int tag)3329d4b5ca7Sdoug CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned int tag)
333732f1cb2Sdoug {
3349d4b5ca7Sdoug 	if (tag > UINT8_MAX)
3359d4b5ca7Sdoug 		return 0;
3369d4b5ca7Sdoug 
337d7a08d8fSdoug 	/* Long form identifier octets are not supported. */
338d7a08d8fSdoug 	if ((tag & 0x1f) == 0x1f)
339d7a08d8fSdoug 		return 0;
340d7a08d8fSdoug 
3416ea8e45cSdoug 	/* Short-form identifier octet only needs a single byte */
342732f1cb2Sdoug 	if (!CBB_flush(cbb) || !CBB_add_u8(cbb, tag))
343c4905cd3Sdoug 		return 0;
344c4905cd3Sdoug 
3456ea8e45cSdoug 	/*
3466ea8e45cSdoug 	 * Add 1 byte to cover the short-form length octet case.  If it turns
3476ea8e45cSdoug 	 * out we need long-form, it will be extended later.
3486ea8e45cSdoug 	 */
349c4905cd3Sdoug 	cbb->offset = cbb->base->len;
350732f1cb2Sdoug 	if (!CBB_add_u8(cbb, 0))
351c4905cd3Sdoug 		return 0;
352c4905cd3Sdoug 
353c4905cd3Sdoug 	memset(out_contents, 0, sizeof(CBB));
354c4905cd3Sdoug 	out_contents->base = cbb->base;
355c4905cd3Sdoug 	cbb->child = out_contents;
356c4905cd3Sdoug 	cbb->pending_len_len = 1;
357c4905cd3Sdoug 	cbb->pending_is_asn1 = 1;
358c4905cd3Sdoug 
359c4905cd3Sdoug 	return 1;
360c4905cd3Sdoug }
361c4905cd3Sdoug 
362732f1cb2Sdoug int
CBB_add_bytes(CBB * cbb,const uint8_t * data,size_t len)363732f1cb2Sdoug CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len)
364732f1cb2Sdoug {
365c4905cd3Sdoug 	uint8_t *dest;
366c4905cd3Sdoug 
367abd6eeeeSjsing 	if (!CBB_flush(cbb) || !cbb_buffer_add(cbb->base, &dest, len))
368c4905cd3Sdoug 		return 0;
369732f1cb2Sdoug 
370c4905cd3Sdoug 	memcpy(dest, data, len);
371c4905cd3Sdoug 	return 1;
372c4905cd3Sdoug }
373c4905cd3Sdoug 
374732f1cb2Sdoug int
CBB_add_space(CBB * cbb,uint8_t ** out_data,size_t len)375732f1cb2Sdoug CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len)
376732f1cb2Sdoug {
377732f1cb2Sdoug 	if (!CBB_flush(cbb) || !cbb_buffer_add(cbb->base, out_data, len))
378c4905cd3Sdoug 		return 0;
379732f1cb2Sdoug 
380df9bd75eSjsing 	memset(*out_data, 0, len);
381c4905cd3Sdoug 	return 1;
382c4905cd3Sdoug }
383c4905cd3Sdoug 
384732f1cb2Sdoug int
CBB_add_u8(CBB * cbb,size_t value)3859d4b5ca7Sdoug CBB_add_u8(CBB *cbb, size_t value)
386732f1cb2Sdoug {
3879d4b5ca7Sdoug 	if (value > UINT8_MAX)
3889d4b5ca7Sdoug 		return 0;
3899d4b5ca7Sdoug 
3909d4b5ca7Sdoug 	return cbb_add_u(cbb, (uint32_t)value, 1);
391c4905cd3Sdoug }
392c4905cd3Sdoug 
393732f1cb2Sdoug int
CBB_add_u16(CBB * cbb,size_t value)3949d4b5ca7Sdoug CBB_add_u16(CBB *cbb, size_t value)
395732f1cb2Sdoug {
3969d4b5ca7Sdoug 	if (value > UINT16_MAX)
3979d4b5ca7Sdoug 		return 0;
3989d4b5ca7Sdoug 
3999d4b5ca7Sdoug 	return cbb_add_u(cbb, (uint32_t)value, 2);
400c4905cd3Sdoug }
401c4905cd3Sdoug 
402732f1cb2Sdoug int
CBB_add_u24(CBB * cbb,size_t value)4039d4b5ca7Sdoug CBB_add_u24(CBB *cbb, size_t value)
404732f1cb2Sdoug {
4059d4b5ca7Sdoug 	if (value > 0xffffffUL)
4069d4b5ca7Sdoug 		return 0;
4079d4b5ca7Sdoug 
4089d4b5ca7Sdoug 	return cbb_add_u(cbb, (uint32_t)value, 3);
409c4905cd3Sdoug }
410c4905cd3Sdoug 
411732f1cb2Sdoug int
CBB_add_u32(CBB * cbb,size_t value)412bd94b8a5Sjsing CBB_add_u32(CBB *cbb, size_t value)
413bd94b8a5Sjsing {
414bd94b8a5Sjsing 	if (value > 0xffffffffUL)
415bd94b8a5Sjsing 		return 0;
416bd94b8a5Sjsing 
417bd94b8a5Sjsing 	return cbb_add_u(cbb, (uint32_t)value, 4);
418bd94b8a5Sjsing }
419bd94b8a5Sjsing 
420bd94b8a5Sjsing int
CBB_add_u64(CBB * cbb,uint64_t value)42154ced76bSjsing CBB_add_u64(CBB *cbb, uint64_t value)
42254ced76bSjsing {
42354ced76bSjsing 	uint32_t a, b;
42454ced76bSjsing 
42554ced76bSjsing 	a = value >> 32;
42654ced76bSjsing 	b = value & 0xffffffff;
42754ced76bSjsing 
42854ced76bSjsing 	if (!CBB_add_u32(cbb, a))
42954ced76bSjsing 		return 0;
43054ced76bSjsing 	return CBB_add_u32(cbb, b);
43154ced76bSjsing }
43254ced76bSjsing 
43354ced76bSjsing int
CBB_add_asn1_uint64(CBB * cbb,uint64_t value)434732f1cb2Sdoug CBB_add_asn1_uint64(CBB *cbb, uint64_t value)
435732f1cb2Sdoug {
436c4905cd3Sdoug 	CBB child;
437c4905cd3Sdoug 	size_t i;
438c4905cd3Sdoug 	int started = 0;
439c4905cd3Sdoug 
440732f1cb2Sdoug 	if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER))
441c4905cd3Sdoug 		return 0;
442c4905cd3Sdoug 
443c4905cd3Sdoug 	for (i = 0; i < 8; i++) {
444c4905cd3Sdoug 		uint8_t byte = (value >> 8 * (7 - i)) & 0xff;
445debb3ac7Sdoug 
446debb3ac7Sdoug 		/*
447debb3ac7Sdoug 		 * ASN.1 restriction: first 9 bits cannot be all zeroes or
448debb3ac7Sdoug 		 * all ones.  Since this function only encodes unsigned
449debb3ac7Sdoug 		 * integers, the only concerns are not encoding leading
450debb3ac7Sdoug 		 * zeros and adding a padding byte if necessary.
451debb3ac7Sdoug 		 *
452debb3ac7Sdoug 		 * In practice, this means:
453debb3ac7Sdoug 		 * 1) Skip leading octets of all zero bits in the value
454debb3ac7Sdoug 		 * 2) After skipping the leading zero octets, if the next 9
455debb3ac7Sdoug 		 *    bits are all ones, add an all zero prefix octet (and
456debb3ac7Sdoug 		 *    set the high bit of the prefix octet if negative).
457debb3ac7Sdoug 		 *
458debb3ac7Sdoug 		 * Additionally, for an unsigned value, add an all zero
459debb3ac7Sdoug 		 * prefix if the high bit of the first octet would be one.
460debb3ac7Sdoug 		 */
461c4905cd3Sdoug 		if (!started) {
462732f1cb2Sdoug 			if (byte == 0)
463c4905cd3Sdoug 				/* Don't encode leading zeros. */
464c4905cd3Sdoug 				continue;
465732f1cb2Sdoug 
466d7a08d8fSdoug 			/*
467d7a08d8fSdoug 			 * If the high bit is set, add a padding byte to make it
468d7a08d8fSdoug 			 * unsigned.
469d7a08d8fSdoug 			 */
470732f1cb2Sdoug 			if ((byte & 0x80) && !CBB_add_u8(&child, 0))
471c4905cd3Sdoug 				return 0;
472732f1cb2Sdoug 
473c4905cd3Sdoug 			started = 1;
474c4905cd3Sdoug 		}
475732f1cb2Sdoug 		if (!CBB_add_u8(&child, byte))
476c4905cd3Sdoug 			return 0;
477c4905cd3Sdoug 	}
478c4905cd3Sdoug 
479c4905cd3Sdoug 	/* 0 is encoded as a single 0, not the empty string. */
480732f1cb2Sdoug 	if (!started && !CBB_add_u8(&child, 0))
481c4905cd3Sdoug 		return 0;
482c4905cd3Sdoug 
483c4905cd3Sdoug 	return CBB_flush(cbb);
484c4905cd3Sdoug }
485