xref: /dflybsd-src/crypto/libressl/ssl/bs_cbs.c (revision 961e30ea7dc61d1112b778ea4981eac68129fb86)
1*de0e0e4dSAntonio Huete Jimenez /*	$OpenBSD: bs_cbs.c,v 1.24 2021/12/15 17:36:49 jsing 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 
23f5b1c8a1SJohn Marino void
CBS_init(CBS * cbs,const uint8_t * data,size_t len)24f5b1c8a1SJohn Marino CBS_init(CBS *cbs, const uint8_t *data, size_t len)
25f5b1c8a1SJohn Marino {
26f5b1c8a1SJohn Marino 	cbs->data = data;
27f5b1c8a1SJohn Marino 	cbs->initial_len = len;
28f5b1c8a1SJohn Marino 	cbs->len = len;
29f5b1c8a1SJohn Marino }
30f5b1c8a1SJohn Marino 
31f5b1c8a1SJohn Marino void
CBS_dup(const CBS * cbs,CBS * out)32f5b1c8a1SJohn Marino CBS_dup(const CBS *cbs, CBS *out)
33f5b1c8a1SJohn Marino {
34f5b1c8a1SJohn Marino 	CBS_init(out, CBS_data(cbs), CBS_len(cbs));
35f5b1c8a1SJohn Marino 	out->initial_len = cbs->initial_len;
36f5b1c8a1SJohn Marino }
37f5b1c8a1SJohn Marino 
38f5b1c8a1SJohn Marino static int
cbs_get(CBS * cbs,const uint8_t ** p,size_t n)39f5b1c8a1SJohn Marino cbs_get(CBS *cbs, const uint8_t **p, size_t n)
40f5b1c8a1SJohn Marino {
41f5b1c8a1SJohn Marino 	if (cbs->len < n)
42f5b1c8a1SJohn Marino 		return 0;
43f5b1c8a1SJohn Marino 
44f5b1c8a1SJohn Marino 	*p = cbs->data;
45f5b1c8a1SJohn Marino 	cbs->data += n;
46f5b1c8a1SJohn Marino 	cbs->len -= n;
47f5b1c8a1SJohn Marino 	return 1;
48f5b1c8a1SJohn Marino }
49f5b1c8a1SJohn Marino 
50*de0e0e4dSAntonio Huete Jimenez static int
cbs_peek(CBS * cbs,const uint8_t ** p,size_t n)51*de0e0e4dSAntonio Huete Jimenez cbs_peek(CBS *cbs, const uint8_t **p, size_t n)
52*de0e0e4dSAntonio Huete Jimenez {
53*de0e0e4dSAntonio Huete Jimenez 	if (cbs->len < n)
54*de0e0e4dSAntonio Huete Jimenez 		return 0;
55*de0e0e4dSAntonio Huete Jimenez 
56*de0e0e4dSAntonio Huete Jimenez 	*p = cbs->data;
57*de0e0e4dSAntonio Huete Jimenez 	return 1;
58*de0e0e4dSAntonio Huete Jimenez }
59*de0e0e4dSAntonio Huete Jimenez 
60f5b1c8a1SJohn Marino size_t
CBS_offset(const CBS * cbs)61f5b1c8a1SJohn Marino CBS_offset(const CBS *cbs)
62f5b1c8a1SJohn Marino {
63f5b1c8a1SJohn Marino 	return cbs->initial_len - cbs->len;
64f5b1c8a1SJohn Marino }
65f5b1c8a1SJohn Marino 
66f5b1c8a1SJohn Marino int
CBS_skip(CBS * cbs,size_t len)67f5b1c8a1SJohn Marino CBS_skip(CBS *cbs, size_t len)
68f5b1c8a1SJohn Marino {
69f5b1c8a1SJohn Marino 	const uint8_t *dummy;
70f5b1c8a1SJohn Marino 	return cbs_get(cbs, &dummy, len);
71f5b1c8a1SJohn Marino }
72f5b1c8a1SJohn Marino 
73f5b1c8a1SJohn Marino const uint8_t *
CBS_data(const CBS * cbs)74f5b1c8a1SJohn Marino CBS_data(const CBS *cbs)
75f5b1c8a1SJohn Marino {
76f5b1c8a1SJohn Marino 	return cbs->data;
77f5b1c8a1SJohn Marino }
78f5b1c8a1SJohn Marino 
79f5b1c8a1SJohn Marino size_t
CBS_len(const CBS * cbs)80f5b1c8a1SJohn Marino CBS_len(const CBS *cbs)
81f5b1c8a1SJohn Marino {
82f5b1c8a1SJohn Marino 	return cbs->len;
83f5b1c8a1SJohn Marino }
84f5b1c8a1SJohn Marino 
85f5b1c8a1SJohn Marino int
CBS_stow(const CBS * cbs,uint8_t ** out_ptr,size_t * out_len)86f5b1c8a1SJohn Marino CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len)
87f5b1c8a1SJohn Marino {
88f5b1c8a1SJohn Marino 	free(*out_ptr);
89f5b1c8a1SJohn Marino 	*out_ptr = NULL;
90f5b1c8a1SJohn Marino 	*out_len = 0;
91f5b1c8a1SJohn Marino 
92f5b1c8a1SJohn Marino 	if (cbs->len == 0)
93f5b1c8a1SJohn Marino 		return 1;
94f5b1c8a1SJohn Marino 
95f5b1c8a1SJohn Marino 	if ((*out_ptr = malloc(cbs->len)) == NULL)
96f5b1c8a1SJohn Marino 		return 0;
97f5b1c8a1SJohn Marino 
98f5b1c8a1SJohn Marino 	memcpy(*out_ptr, cbs->data, cbs->len);
99f5b1c8a1SJohn Marino 
100f5b1c8a1SJohn Marino 	*out_len = cbs->len;
101f5b1c8a1SJohn Marino 	return 1;
102f5b1c8a1SJohn Marino }
103f5b1c8a1SJohn Marino 
104f5b1c8a1SJohn Marino int
CBS_strdup(const CBS * cbs,char ** out_ptr)105f5b1c8a1SJohn Marino CBS_strdup(const CBS *cbs, char **out_ptr)
106f5b1c8a1SJohn Marino {
107f5b1c8a1SJohn Marino 	free(*out_ptr);
108*de0e0e4dSAntonio Huete Jimenez 	*out_ptr = NULL;
109*de0e0e4dSAntonio Huete Jimenez 
110*de0e0e4dSAntonio Huete Jimenez 	if (CBS_contains_zero_byte(cbs))
111*de0e0e4dSAntonio Huete Jimenez 		return 0;
112*de0e0e4dSAntonio Huete Jimenez 
113f5b1c8a1SJohn Marino 	*out_ptr = strndup((const char *)cbs->data, cbs->len);
114f5b1c8a1SJohn Marino 	return (*out_ptr != NULL);
115f5b1c8a1SJohn Marino }
116f5b1c8a1SJohn Marino 
117f5b1c8a1SJohn Marino int
CBS_write_bytes(const CBS * cbs,uint8_t * dst,size_t dst_len,size_t * copied)118f5b1c8a1SJohn Marino CBS_write_bytes(const CBS *cbs, uint8_t *dst, size_t dst_len, size_t *copied)
119f5b1c8a1SJohn Marino {
120f5b1c8a1SJohn Marino 	if (dst_len < cbs->len)
121f5b1c8a1SJohn Marino 		return 0;
122f5b1c8a1SJohn Marino 
123f5b1c8a1SJohn Marino 	memmove(dst, cbs->data, cbs->len);
124f5b1c8a1SJohn Marino 
125f5b1c8a1SJohn Marino 	if (copied != NULL)
126f5b1c8a1SJohn Marino 		*copied = cbs->len;
127f5b1c8a1SJohn Marino 
128f5b1c8a1SJohn Marino 	return 1;
129f5b1c8a1SJohn Marino }
130f5b1c8a1SJohn Marino 
131f5b1c8a1SJohn Marino int
CBS_contains_zero_byte(const CBS * cbs)132f5b1c8a1SJohn Marino CBS_contains_zero_byte(const CBS *cbs)
133f5b1c8a1SJohn Marino {
134f5b1c8a1SJohn Marino 	return memchr(cbs->data, 0, cbs->len) != NULL;
135f5b1c8a1SJohn Marino }
136f5b1c8a1SJohn Marino 
137f5b1c8a1SJohn Marino int
CBS_mem_equal(const CBS * cbs,const uint8_t * data,size_t len)138f5b1c8a1SJohn Marino CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len)
139f5b1c8a1SJohn Marino {
140f5b1c8a1SJohn Marino 	if (len != cbs->len)
141f5b1c8a1SJohn Marino 		return 0;
142f5b1c8a1SJohn Marino 
143f5b1c8a1SJohn Marino 	return timingsafe_memcmp(cbs->data, data, len) == 0;
144f5b1c8a1SJohn Marino }
145f5b1c8a1SJohn Marino 
146f5b1c8a1SJohn Marino static int
cbs_get_u(CBS * cbs,uint32_t * out,size_t len)147f5b1c8a1SJohn Marino cbs_get_u(CBS *cbs, uint32_t *out, size_t len)
148f5b1c8a1SJohn Marino {
149f5b1c8a1SJohn Marino 	uint32_t result = 0;
150f5b1c8a1SJohn Marino 	size_t i;
151f5b1c8a1SJohn Marino 	const uint8_t *data;
152f5b1c8a1SJohn Marino 
153f5b1c8a1SJohn Marino 	if (len < 1 || len > 4)
154f5b1c8a1SJohn Marino 		return 0;
155f5b1c8a1SJohn Marino 
156f5b1c8a1SJohn Marino 	if (!cbs_get(cbs, &data, len))
157f5b1c8a1SJohn Marino 		return 0;
158f5b1c8a1SJohn Marino 
159f5b1c8a1SJohn Marino 	for (i = 0; i < len; i++) {
160f5b1c8a1SJohn Marino 		result <<= 8;
161f5b1c8a1SJohn Marino 		result |= data[i];
162f5b1c8a1SJohn Marino 	}
163f5b1c8a1SJohn Marino 	*out = result;
164f5b1c8a1SJohn Marino 	return 1;
165f5b1c8a1SJohn Marino }
166f5b1c8a1SJohn Marino 
167f5b1c8a1SJohn Marino int
CBS_get_u8(CBS * cbs,uint8_t * out)168f5b1c8a1SJohn Marino CBS_get_u8(CBS *cbs, uint8_t *out)
169f5b1c8a1SJohn Marino {
170f5b1c8a1SJohn Marino 	const uint8_t *v;
171f5b1c8a1SJohn Marino 
172f5b1c8a1SJohn Marino 	if (!cbs_get(cbs, &v, 1))
173f5b1c8a1SJohn Marino 		return 0;
174f5b1c8a1SJohn Marino 
175f5b1c8a1SJohn Marino 	*out = *v;
176f5b1c8a1SJohn Marino 	return 1;
177f5b1c8a1SJohn Marino }
178f5b1c8a1SJohn Marino 
179f5b1c8a1SJohn Marino int
CBS_get_u16(CBS * cbs,uint16_t * out)180f5b1c8a1SJohn Marino CBS_get_u16(CBS *cbs, uint16_t *out)
181f5b1c8a1SJohn Marino {
182f5b1c8a1SJohn Marino 	uint32_t v;
183f5b1c8a1SJohn Marino 
184f5b1c8a1SJohn Marino 	if (!cbs_get_u(cbs, &v, 2))
185f5b1c8a1SJohn Marino 		return 0;
186f5b1c8a1SJohn Marino 
187f5b1c8a1SJohn Marino 	*out = v;
188f5b1c8a1SJohn Marino 	return 1;
189f5b1c8a1SJohn Marino }
190f5b1c8a1SJohn Marino 
191f5b1c8a1SJohn Marino int
CBS_get_u24(CBS * cbs,uint32_t * out)192f5b1c8a1SJohn Marino CBS_get_u24(CBS *cbs, uint32_t *out)
193f5b1c8a1SJohn Marino {
194f5b1c8a1SJohn Marino 	return cbs_get_u(cbs, out, 3);
195f5b1c8a1SJohn Marino }
196f5b1c8a1SJohn Marino 
197f5b1c8a1SJohn Marino int
CBS_get_u32(CBS * cbs,uint32_t * out)198f5b1c8a1SJohn Marino CBS_get_u32(CBS *cbs, uint32_t *out)
199f5b1c8a1SJohn Marino {
200f5b1c8a1SJohn Marino 	return cbs_get_u(cbs, out, 4);
201f5b1c8a1SJohn Marino }
202f5b1c8a1SJohn Marino 
203f5b1c8a1SJohn Marino int
CBS_get_u64(CBS * cbs,uint64_t * out)204*de0e0e4dSAntonio Huete Jimenez CBS_get_u64(CBS *cbs, uint64_t *out)
205*de0e0e4dSAntonio Huete Jimenez {
206*de0e0e4dSAntonio Huete Jimenez 	uint32_t a, b;
207*de0e0e4dSAntonio Huete Jimenez 
208*de0e0e4dSAntonio Huete Jimenez 	if (cbs->len < 8)
209*de0e0e4dSAntonio Huete Jimenez 		return 0;
210*de0e0e4dSAntonio Huete Jimenez 
211*de0e0e4dSAntonio Huete Jimenez 	if (!CBS_get_u32(cbs, &a))
212*de0e0e4dSAntonio Huete Jimenez 		return 0;
213*de0e0e4dSAntonio Huete Jimenez 	if (!CBS_get_u32(cbs, &b))
214*de0e0e4dSAntonio Huete Jimenez 		return 0;
215*de0e0e4dSAntonio Huete Jimenez 
216*de0e0e4dSAntonio Huete Jimenez 	*out = (uint64_t)a << 32 | b;
217*de0e0e4dSAntonio Huete Jimenez 	return 1;
218*de0e0e4dSAntonio Huete Jimenez }
219*de0e0e4dSAntonio Huete Jimenez 
220*de0e0e4dSAntonio Huete Jimenez int
CBS_get_last_u8(CBS * cbs,uint8_t * out)221*de0e0e4dSAntonio Huete Jimenez CBS_get_last_u8(CBS *cbs, uint8_t *out)
222*de0e0e4dSAntonio Huete Jimenez {
223*de0e0e4dSAntonio Huete Jimenez 	if (cbs->len == 0)
224*de0e0e4dSAntonio Huete Jimenez 		return 0;
225*de0e0e4dSAntonio Huete Jimenez 
226*de0e0e4dSAntonio Huete Jimenez 	*out = cbs->data[cbs->len - 1];
227*de0e0e4dSAntonio Huete Jimenez 	cbs->len--;
228*de0e0e4dSAntonio Huete Jimenez 	return 1;
229*de0e0e4dSAntonio Huete Jimenez }
230*de0e0e4dSAntonio Huete Jimenez 
231*de0e0e4dSAntonio Huete Jimenez int
CBS_get_bytes(CBS * cbs,CBS * out,size_t len)232f5b1c8a1SJohn Marino CBS_get_bytes(CBS *cbs, CBS *out, size_t len)
233f5b1c8a1SJohn Marino {
234f5b1c8a1SJohn Marino 	const uint8_t *v;
235f5b1c8a1SJohn Marino 
236f5b1c8a1SJohn Marino 	if (!cbs_get(cbs, &v, len))
237f5b1c8a1SJohn Marino 		return 0;
238f5b1c8a1SJohn Marino 
239f5b1c8a1SJohn Marino 	CBS_init(out, v, len);
240f5b1c8a1SJohn Marino 	return 1;
241f5b1c8a1SJohn Marino }
242f5b1c8a1SJohn Marino 
243f5b1c8a1SJohn Marino static int
cbs_get_length_prefixed(CBS * cbs,CBS * out,size_t len_len)244f5b1c8a1SJohn Marino cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len)
245f5b1c8a1SJohn Marino {
246f5b1c8a1SJohn Marino 	uint32_t len;
247f5b1c8a1SJohn Marino 
248f5b1c8a1SJohn Marino 	if (!cbs_get_u(cbs, &len, len_len))
249f5b1c8a1SJohn Marino 		return 0;
250f5b1c8a1SJohn Marino 
251f5b1c8a1SJohn Marino 	return CBS_get_bytes(cbs, out, len);
252f5b1c8a1SJohn Marino }
253f5b1c8a1SJohn Marino 
254f5b1c8a1SJohn Marino int
CBS_get_u8_length_prefixed(CBS * cbs,CBS * out)255f5b1c8a1SJohn Marino CBS_get_u8_length_prefixed(CBS *cbs, CBS *out)
256f5b1c8a1SJohn Marino {
257f5b1c8a1SJohn Marino 	return cbs_get_length_prefixed(cbs, out, 1);
258f5b1c8a1SJohn Marino }
259f5b1c8a1SJohn Marino 
260f5b1c8a1SJohn Marino int
CBS_get_u16_length_prefixed(CBS * cbs,CBS * out)261f5b1c8a1SJohn Marino CBS_get_u16_length_prefixed(CBS *cbs, CBS *out)
262f5b1c8a1SJohn Marino {
263f5b1c8a1SJohn Marino 	return cbs_get_length_prefixed(cbs, out, 2);
264f5b1c8a1SJohn Marino }
265f5b1c8a1SJohn Marino 
266f5b1c8a1SJohn Marino int
CBS_get_u24_length_prefixed(CBS * cbs,CBS * out)267f5b1c8a1SJohn Marino CBS_get_u24_length_prefixed(CBS *cbs, CBS *out)
268f5b1c8a1SJohn Marino {
269f5b1c8a1SJohn Marino 	return cbs_get_length_prefixed(cbs, out, 3);
270f5b1c8a1SJohn Marino }
271f5b1c8a1SJohn Marino 
272*de0e0e4dSAntonio Huete Jimenez static int
cbs_peek_u(CBS * cbs,uint32_t * out,size_t len)273*de0e0e4dSAntonio Huete Jimenez cbs_peek_u(CBS *cbs, uint32_t *out, size_t len)
274*de0e0e4dSAntonio Huete Jimenez {
275*de0e0e4dSAntonio Huete Jimenez 	uint32_t result = 0;
276*de0e0e4dSAntonio Huete Jimenez 	size_t i;
277*de0e0e4dSAntonio Huete Jimenez 	const uint8_t *data;
278*de0e0e4dSAntonio Huete Jimenez 
279*de0e0e4dSAntonio Huete Jimenez 	if (len < 1 || len > 4)
280*de0e0e4dSAntonio Huete Jimenez 		return 0;
281*de0e0e4dSAntonio Huete Jimenez 
282*de0e0e4dSAntonio Huete Jimenez 	if (!cbs_peek(cbs, &data, len))
283*de0e0e4dSAntonio Huete Jimenez 		return 0;
284*de0e0e4dSAntonio Huete Jimenez 
285*de0e0e4dSAntonio Huete Jimenez 	for (i = 0; i < len; i++) {
286*de0e0e4dSAntonio Huete Jimenez 		result <<= 8;
287*de0e0e4dSAntonio Huete Jimenez 		result |= data[i];
288*de0e0e4dSAntonio Huete Jimenez 	}
289*de0e0e4dSAntonio Huete Jimenez 	*out = result;
290*de0e0e4dSAntonio Huete Jimenez 	return 1;
291*de0e0e4dSAntonio Huete Jimenez }
292*de0e0e4dSAntonio Huete Jimenez 
293*de0e0e4dSAntonio Huete Jimenez int
CBS_peek_u8(CBS * cbs,uint8_t * out)294*de0e0e4dSAntonio Huete Jimenez CBS_peek_u8(CBS *cbs, uint8_t *out)
295*de0e0e4dSAntonio Huete Jimenez {
296*de0e0e4dSAntonio Huete Jimenez 	const uint8_t *v;
297*de0e0e4dSAntonio Huete Jimenez 
298*de0e0e4dSAntonio Huete Jimenez 	if (!cbs_peek(cbs, &v, 1))
299*de0e0e4dSAntonio Huete Jimenez 		return 0;
300*de0e0e4dSAntonio Huete Jimenez 
301*de0e0e4dSAntonio Huete Jimenez 	*out = *v;
302*de0e0e4dSAntonio Huete Jimenez 	return 1;
303*de0e0e4dSAntonio Huete Jimenez }
304*de0e0e4dSAntonio Huete Jimenez 
305*de0e0e4dSAntonio Huete Jimenez int
CBS_peek_u16(CBS * cbs,uint16_t * out)306*de0e0e4dSAntonio Huete Jimenez CBS_peek_u16(CBS *cbs, uint16_t *out)
307*de0e0e4dSAntonio Huete Jimenez {
308*de0e0e4dSAntonio Huete Jimenez 	uint32_t v;
309*de0e0e4dSAntonio Huete Jimenez 
310*de0e0e4dSAntonio Huete Jimenez 	if (!cbs_peek_u(cbs, &v, 2))
311*de0e0e4dSAntonio Huete Jimenez 		return 0;
312*de0e0e4dSAntonio Huete Jimenez 
313*de0e0e4dSAntonio Huete Jimenez 	*out = v;
314*de0e0e4dSAntonio Huete Jimenez 	return 1;
315*de0e0e4dSAntonio Huete Jimenez }
316*de0e0e4dSAntonio Huete Jimenez 
317*de0e0e4dSAntonio Huete Jimenez int
CBS_peek_u24(CBS * cbs,uint32_t * out)318*de0e0e4dSAntonio Huete Jimenez CBS_peek_u24(CBS *cbs, uint32_t *out)
319*de0e0e4dSAntonio Huete Jimenez {
320*de0e0e4dSAntonio Huete Jimenez 	return cbs_peek_u(cbs, out, 3);
321*de0e0e4dSAntonio Huete Jimenez }
322*de0e0e4dSAntonio Huete Jimenez 
323*de0e0e4dSAntonio Huete Jimenez int
CBS_peek_u32(CBS * cbs,uint32_t * out)324*de0e0e4dSAntonio Huete Jimenez CBS_peek_u32(CBS *cbs, uint32_t *out)
325*de0e0e4dSAntonio Huete Jimenez {
326*de0e0e4dSAntonio Huete Jimenez 	return cbs_peek_u(cbs, out, 4);
327*de0e0e4dSAntonio Huete Jimenez }
328*de0e0e4dSAntonio Huete Jimenez 
329*de0e0e4dSAntonio Huete Jimenez int
CBS_peek_last_u8(CBS * cbs,uint8_t * out)330*de0e0e4dSAntonio Huete Jimenez CBS_peek_last_u8(CBS *cbs, uint8_t *out)
331*de0e0e4dSAntonio Huete Jimenez {
332*de0e0e4dSAntonio Huete Jimenez 	if (cbs->len == 0)
333*de0e0e4dSAntonio Huete Jimenez 		return 0;
334*de0e0e4dSAntonio Huete Jimenez 
335*de0e0e4dSAntonio Huete Jimenez 	*out = cbs->data[cbs->len - 1];
336*de0e0e4dSAntonio Huete Jimenez 	return 1;
337*de0e0e4dSAntonio Huete Jimenez }
338*de0e0e4dSAntonio Huete Jimenez 
339f5b1c8a1SJohn Marino int
CBS_get_any_asn1_element(CBS * cbs,CBS * out,unsigned int * out_tag,size_t * out_header_len)340f5b1c8a1SJohn Marino CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned int *out_tag,
341f5b1c8a1SJohn Marino     size_t *out_header_len)
342f5b1c8a1SJohn Marino {
343f5b1c8a1SJohn Marino 	return cbs_get_any_asn1_element_internal(cbs, out, out_tag,
344f5b1c8a1SJohn Marino 	    out_header_len, 1);
345f5b1c8a1SJohn Marino }
346f5b1c8a1SJohn Marino 
347f5b1c8a1SJohn Marino /*
348f5b1c8a1SJohn Marino  * Review X.690 for details on ASN.1 DER encoding.
349f5b1c8a1SJohn Marino  *
350f5b1c8a1SJohn Marino  * If non-strict mode is enabled, then DER rules are relaxed
351f5b1c8a1SJohn Marino  * for indefinite constructs (violates DER but a little closer to BER).
352f5b1c8a1SJohn Marino  * Non-strict mode should only be used by bs_ber.c
353f5b1c8a1SJohn Marino  *
354f5b1c8a1SJohn Marino  * Sections 8, 10 and 11 for DER encoding
355f5b1c8a1SJohn Marino  */
356f5b1c8a1SJohn Marino int
cbs_get_any_asn1_element_internal(CBS * cbs,CBS * out,unsigned int * out_tag,size_t * out_header_len,int strict)357f5b1c8a1SJohn Marino cbs_get_any_asn1_element_internal(CBS *cbs, CBS *out, unsigned int *out_tag,
358f5b1c8a1SJohn Marino     size_t *out_header_len, int strict)
359f5b1c8a1SJohn Marino {
360f5b1c8a1SJohn Marino 	uint8_t tag, length_byte;
361f5b1c8a1SJohn Marino 	CBS header = *cbs;
362f5b1c8a1SJohn Marino 	CBS throwaway;
363f5b1c8a1SJohn Marino 	size_t len;
364f5b1c8a1SJohn Marino 
365f5b1c8a1SJohn Marino 	if (out == NULL)
366f5b1c8a1SJohn Marino 		out = &throwaway;
367f5b1c8a1SJohn Marino 
368f5b1c8a1SJohn Marino 	/*
369f5b1c8a1SJohn Marino 	 * Get identifier octet and length octet.  Only 1 octet for each
370f5b1c8a1SJohn Marino 	 * is a CBS limitation.
371f5b1c8a1SJohn Marino 	 */
372f5b1c8a1SJohn Marino 	if (!CBS_get_u8(&header, &tag) || !CBS_get_u8(&header, &length_byte))
373f5b1c8a1SJohn Marino 		return 0;
374f5b1c8a1SJohn Marino 
375f5b1c8a1SJohn Marino 	/* CBS limitation: long form tags are not supported. */
376f5b1c8a1SJohn Marino 	if ((tag & 0x1f) == 0x1f)
377f5b1c8a1SJohn Marino 		return 0;
378f5b1c8a1SJohn Marino 
379f5b1c8a1SJohn Marino 	if (out_tag != NULL)
380f5b1c8a1SJohn Marino 		*out_tag = tag;
381f5b1c8a1SJohn Marino 
382f5b1c8a1SJohn Marino 	if ((length_byte & 0x80) == 0) {
383f5b1c8a1SJohn Marino 		/* Short form length. */
384f5b1c8a1SJohn Marino 		len = ((size_t) length_byte) + 2;
385f5b1c8a1SJohn Marino 		if (out_header_len != NULL)
386f5b1c8a1SJohn Marino 			*out_header_len = 2;
387f5b1c8a1SJohn Marino 
388f5b1c8a1SJohn Marino 	} else {
389f5b1c8a1SJohn Marino 		/* Long form length. */
390f5b1c8a1SJohn Marino 		const size_t num_bytes = length_byte & 0x7f;
391f5b1c8a1SJohn Marino 		uint32_t len32;
392f5b1c8a1SJohn Marino 
393f5b1c8a1SJohn Marino 		/* ASN.1 reserved value for future extensions */
394f5b1c8a1SJohn Marino 		if (num_bytes == 0x7f)
395f5b1c8a1SJohn Marino 			return 0;
396f5b1c8a1SJohn Marino 
397f5b1c8a1SJohn Marino 		/* Handle indefinite form length */
398f5b1c8a1SJohn Marino 		if (num_bytes == 0) {
399f5b1c8a1SJohn Marino 			/* DER encoding doesn't allow for indefinite form. */
400f5b1c8a1SJohn Marino 			if (strict)
401f5b1c8a1SJohn Marino 				return 0;
402f5b1c8a1SJohn Marino 
403f5b1c8a1SJohn Marino 			/* Primitive cannot use indefinite in BER or DER. */
404f5b1c8a1SJohn Marino 			if ((tag & CBS_ASN1_CONSTRUCTED) == 0)
405f5b1c8a1SJohn Marino 				return 0;
406f5b1c8a1SJohn Marino 
407f5b1c8a1SJohn Marino 			/* Constructed, indefinite length allowed in BER. */
408f5b1c8a1SJohn Marino 			if (out_header_len != NULL)
409f5b1c8a1SJohn Marino 				*out_header_len = 2;
410f5b1c8a1SJohn Marino 			return CBS_get_bytes(cbs, out, 2);
411f5b1c8a1SJohn Marino 		}
412f5b1c8a1SJohn Marino 
413f5b1c8a1SJohn Marino 		/* CBS limitation. */
414f5b1c8a1SJohn Marino 		if (num_bytes > 4)
415f5b1c8a1SJohn Marino 			return 0;
416f5b1c8a1SJohn Marino 
417f5b1c8a1SJohn Marino 		if (!cbs_get_u(&header, &len32, num_bytes))
418f5b1c8a1SJohn Marino 			return 0;
419f5b1c8a1SJohn Marino 
420f5b1c8a1SJohn Marino 		/* DER has a minimum length octet requirement. */
421f5b1c8a1SJohn Marino 		if (len32 < 128)
422f5b1c8a1SJohn Marino 			/* Should have used short form instead */
423f5b1c8a1SJohn Marino 			return 0;
424f5b1c8a1SJohn Marino 
425f5b1c8a1SJohn Marino 		if ((len32 >> ((num_bytes - 1) * 8)) == 0)
426f5b1c8a1SJohn Marino 			/* Length should have been at least one byte shorter. */
427f5b1c8a1SJohn Marino 			return 0;
428f5b1c8a1SJohn Marino 
429f5b1c8a1SJohn Marino 		len = len32;
430f5b1c8a1SJohn Marino 		if (len + 2 + num_bytes < len)
431f5b1c8a1SJohn Marino 			/* Overflow. */
432f5b1c8a1SJohn Marino 			return 0;
433f5b1c8a1SJohn Marino 
434f5b1c8a1SJohn Marino 		len += 2 + num_bytes;
435f5b1c8a1SJohn Marino 		if (out_header_len != NULL)
436f5b1c8a1SJohn Marino 			*out_header_len = 2 + num_bytes;
437f5b1c8a1SJohn Marino 	}
438f5b1c8a1SJohn Marino 
439f5b1c8a1SJohn Marino 	return CBS_get_bytes(cbs, out, len);
440f5b1c8a1SJohn Marino }
441f5b1c8a1SJohn Marino 
442f5b1c8a1SJohn Marino static int
cbs_get_asn1(CBS * cbs,CBS * out,unsigned int tag_value,int skip_header)443f5b1c8a1SJohn Marino cbs_get_asn1(CBS *cbs, CBS *out, unsigned int tag_value, int skip_header)
444f5b1c8a1SJohn Marino {
445f5b1c8a1SJohn Marino 	size_t header_len;
446f5b1c8a1SJohn Marino 	unsigned int tag;
447f5b1c8a1SJohn Marino 	CBS throwaway;
448f5b1c8a1SJohn Marino 
449f5b1c8a1SJohn Marino 	if (out == NULL)
450f5b1c8a1SJohn Marino 		out = &throwaway;
451f5b1c8a1SJohn Marino 
452f5b1c8a1SJohn Marino 	if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) ||
453f5b1c8a1SJohn Marino 	    tag != tag_value)
454f5b1c8a1SJohn Marino 		return 0;
455f5b1c8a1SJohn Marino 
45672c33676SMaxim Ag 	if (skip_header && !CBS_skip(out, header_len))
457f5b1c8a1SJohn Marino 		return 0;
458f5b1c8a1SJohn Marino 
459f5b1c8a1SJohn Marino 	return 1;
460f5b1c8a1SJohn Marino }
461f5b1c8a1SJohn Marino 
462f5b1c8a1SJohn Marino int
CBS_get_asn1(CBS * cbs,CBS * out,unsigned int tag_value)463f5b1c8a1SJohn Marino CBS_get_asn1(CBS *cbs, CBS *out, unsigned int tag_value)
464f5b1c8a1SJohn Marino {
465f5b1c8a1SJohn Marino 	return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */);
466f5b1c8a1SJohn Marino }
467f5b1c8a1SJohn Marino 
468f5b1c8a1SJohn Marino int
CBS_get_asn1_element(CBS * cbs,CBS * out,unsigned int tag_value)469f5b1c8a1SJohn Marino CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned int tag_value)
470f5b1c8a1SJohn Marino {
471f5b1c8a1SJohn Marino 	return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */);
472f5b1c8a1SJohn Marino }
473f5b1c8a1SJohn Marino 
474f5b1c8a1SJohn Marino int
CBS_peek_asn1_tag(const CBS * cbs,unsigned int tag_value)475f5b1c8a1SJohn Marino CBS_peek_asn1_tag(const CBS *cbs, unsigned int tag_value)
476f5b1c8a1SJohn Marino {
477f5b1c8a1SJohn Marino 	if (CBS_len(cbs) < 1)
478f5b1c8a1SJohn Marino 		return 0;
479f5b1c8a1SJohn Marino 
480f5b1c8a1SJohn Marino 	/*
481f5b1c8a1SJohn Marino 	 * Tag number 31 indicates the start of a long form number.
482f5b1c8a1SJohn Marino 	 * This is valid in ASN.1, but CBS only supports short form.
483f5b1c8a1SJohn Marino 	 */
484f5b1c8a1SJohn Marino 	if ((tag_value & 0x1f) == 0x1f)
485f5b1c8a1SJohn Marino 		return 0;
486f5b1c8a1SJohn Marino 
487f5b1c8a1SJohn Marino 	return CBS_data(cbs)[0] == tag_value;
488f5b1c8a1SJohn Marino }
489f5b1c8a1SJohn Marino 
490f5b1c8a1SJohn Marino /* Encoding details are in ASN.1: X.690 section 8.3 */
491f5b1c8a1SJohn Marino int
CBS_get_asn1_uint64(CBS * cbs,uint64_t * out)492f5b1c8a1SJohn Marino CBS_get_asn1_uint64(CBS *cbs, uint64_t *out)
493f5b1c8a1SJohn Marino {
494f5b1c8a1SJohn Marino 	CBS bytes;
495f5b1c8a1SJohn Marino 	const uint8_t *data;
496f5b1c8a1SJohn Marino 	size_t i, len;
497f5b1c8a1SJohn Marino 
498f5b1c8a1SJohn Marino 	if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER))
499f5b1c8a1SJohn Marino 		return 0;
500f5b1c8a1SJohn Marino 
501f5b1c8a1SJohn Marino 	*out = 0;
502f5b1c8a1SJohn Marino 	data = CBS_data(&bytes);
503f5b1c8a1SJohn Marino 	len = CBS_len(&bytes);
504f5b1c8a1SJohn Marino 
505f5b1c8a1SJohn Marino 	if (len == 0)
506f5b1c8a1SJohn Marino 		/* An INTEGER is encoded with at least one content octet. */
507f5b1c8a1SJohn Marino 		return 0;
508f5b1c8a1SJohn Marino 
509f5b1c8a1SJohn Marino 	if ((data[0] & 0x80) != 0)
510f5b1c8a1SJohn Marino 		/* Negative number. */
511f5b1c8a1SJohn Marino 		return 0;
512f5b1c8a1SJohn Marino 
513f5b1c8a1SJohn Marino 	if (data[0] == 0 && len > 1 && (data[1] & 0x80) == 0)
514f5b1c8a1SJohn Marino 		/* Violates smallest encoding rule: excessive leading zeros. */
515f5b1c8a1SJohn Marino 		return 0;
516f5b1c8a1SJohn Marino 
517f5b1c8a1SJohn Marino 	for (i = 0; i < len; i++) {
518f5b1c8a1SJohn Marino 		if ((*out >> 56) != 0)
519f5b1c8a1SJohn Marino 			/* Too large to represent as a uint64_t. */
520f5b1c8a1SJohn Marino 			return 0;
521f5b1c8a1SJohn Marino 
522f5b1c8a1SJohn Marino 		*out <<= 8;
523f5b1c8a1SJohn Marino 		*out |= data[i];
524f5b1c8a1SJohn Marino 	}
525f5b1c8a1SJohn Marino 
526f5b1c8a1SJohn Marino 	return 1;
527f5b1c8a1SJohn Marino }
528f5b1c8a1SJohn Marino 
529f5b1c8a1SJohn Marino int
CBS_get_optional_asn1(CBS * cbs,CBS * out,int * out_present,unsigned int tag)530f5b1c8a1SJohn Marino CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned int tag)
531f5b1c8a1SJohn Marino {
532f5b1c8a1SJohn Marino 	if (CBS_peek_asn1_tag(cbs, tag)) {
533f5b1c8a1SJohn Marino 		if (!CBS_get_asn1(cbs, out, tag))
534f5b1c8a1SJohn Marino 			return 0;
535f5b1c8a1SJohn Marino 
536f5b1c8a1SJohn Marino 		*out_present = 1;
537f5b1c8a1SJohn Marino 	} else {
538f5b1c8a1SJohn Marino 		*out_present = 0;
539f5b1c8a1SJohn Marino 	}
540f5b1c8a1SJohn Marino 	return 1;
541f5b1c8a1SJohn Marino }
542f5b1c8a1SJohn Marino 
543f5b1c8a1SJohn Marino int
CBS_get_optional_asn1_octet_string(CBS * cbs,CBS * out,int * out_present,unsigned int tag)544f5b1c8a1SJohn Marino CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present,
545f5b1c8a1SJohn Marino     unsigned int tag)
546f5b1c8a1SJohn Marino {
547f5b1c8a1SJohn Marino 	CBS child;
548f5b1c8a1SJohn Marino 	int present;
549f5b1c8a1SJohn Marino 
550f5b1c8a1SJohn Marino 	if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
551f5b1c8a1SJohn Marino 		return 0;
552f5b1c8a1SJohn Marino 
553f5b1c8a1SJohn Marino 	if (present) {
554f5b1c8a1SJohn Marino 		if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) ||
555f5b1c8a1SJohn Marino 		    CBS_len(&child) != 0)
556f5b1c8a1SJohn Marino 			return 0;
557f5b1c8a1SJohn Marino 	} else {
558f5b1c8a1SJohn Marino 		CBS_init(out, NULL, 0);
559f5b1c8a1SJohn Marino 	}
560f5b1c8a1SJohn Marino 	if (out_present)
561f5b1c8a1SJohn Marino 		*out_present = present;
562f5b1c8a1SJohn Marino 
563f5b1c8a1SJohn Marino 	return 1;
564f5b1c8a1SJohn Marino }
565f5b1c8a1SJohn Marino 
566f5b1c8a1SJohn Marino int
CBS_get_optional_asn1_uint64(CBS * cbs,uint64_t * out,unsigned int tag,uint64_t default_value)567f5b1c8a1SJohn Marino CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned int tag,
568f5b1c8a1SJohn Marino     uint64_t default_value)
569f5b1c8a1SJohn Marino {
570f5b1c8a1SJohn Marino 	CBS child;
571f5b1c8a1SJohn Marino 	int present;
572f5b1c8a1SJohn Marino 
573f5b1c8a1SJohn Marino 	if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
574f5b1c8a1SJohn Marino 		return 0;
575f5b1c8a1SJohn Marino 
576f5b1c8a1SJohn Marino 	if (present) {
577f5b1c8a1SJohn Marino 		if (!CBS_get_asn1_uint64(&child, out) ||
578f5b1c8a1SJohn Marino 		    CBS_len(&child) != 0)
579f5b1c8a1SJohn Marino 			return 0;
580f5b1c8a1SJohn Marino 	} else {
581f5b1c8a1SJohn Marino 		*out = default_value;
582f5b1c8a1SJohn Marino 	}
583f5b1c8a1SJohn Marino 	return 1;
584f5b1c8a1SJohn Marino }
585f5b1c8a1SJohn Marino 
586f5b1c8a1SJohn Marino int
CBS_get_optional_asn1_bool(CBS * cbs,int * out,unsigned int tag,int default_value)587f5b1c8a1SJohn Marino CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned int tag,
588f5b1c8a1SJohn Marino     int default_value)
589f5b1c8a1SJohn Marino {
590f5b1c8a1SJohn Marino 	CBS child, child2;
591f5b1c8a1SJohn Marino 	int present;
592f5b1c8a1SJohn Marino 
593f5b1c8a1SJohn Marino 	if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
594f5b1c8a1SJohn Marino 		return 0;
595f5b1c8a1SJohn Marino 
596f5b1c8a1SJohn Marino 	if (present) {
597f5b1c8a1SJohn Marino 		uint8_t boolean;
598f5b1c8a1SJohn Marino 
599f5b1c8a1SJohn Marino 		if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
600f5b1c8a1SJohn Marino 		    CBS_len(&child2) != 1 || CBS_len(&child) != 0)
601f5b1c8a1SJohn Marino 			return 0;
602f5b1c8a1SJohn Marino 
603f5b1c8a1SJohn Marino 		boolean = CBS_data(&child2)[0];
604f5b1c8a1SJohn Marino 		if (boolean == 0)
605f5b1c8a1SJohn Marino 			*out = 0;
606f5b1c8a1SJohn Marino 		else if (boolean == 0xff)
607f5b1c8a1SJohn Marino 			*out = 1;
608f5b1c8a1SJohn Marino 		else
609f5b1c8a1SJohn Marino 			return 0;
610f5b1c8a1SJohn Marino 
611f5b1c8a1SJohn Marino 	} else {
612f5b1c8a1SJohn Marino 		*out = default_value;
613f5b1c8a1SJohn Marino 	}
614f5b1c8a1SJohn Marino 	return 1;
615f5b1c8a1SJohn Marino }
616