xref: /openbsd-src/lib/libssl/bs_cbs.c (revision c57a2cde1c3e37c4d965970508afb482cdffc12d)
1*c57a2cdeStb /*	$OpenBSD: bs_cbs.c,v 1.25 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 
24732f1cb2Sdoug void
CBS_init(CBS * cbs,const uint8_t * data,size_t len)25732f1cb2Sdoug CBS_init(CBS *cbs, const uint8_t *data, size_t len)
26732f1cb2Sdoug {
27c4905cd3Sdoug 	cbs->data = data;
2834e475baSdoug 	cbs->initial_len = len;
29c4905cd3Sdoug 	cbs->len = len;
30c4905cd3Sdoug }
31c4905cd3Sdoug 
3242fa457bSdoug void
CBS_dup(const CBS * cbs,CBS * out)3342fa457bSdoug CBS_dup(const CBS *cbs, CBS *out)
3442fa457bSdoug {
3542fa457bSdoug 	CBS_init(out, CBS_data(cbs), CBS_len(cbs));
366cb2edf4Sdoug 	out->initial_len = cbs->initial_len;
3742fa457bSdoug }
3842fa457bSdoug 
39732f1cb2Sdoug static int
cbs_get(CBS * cbs,const uint8_t ** p,size_t n)40732f1cb2Sdoug cbs_get(CBS *cbs, const uint8_t **p, size_t n)
41732f1cb2Sdoug {
42732f1cb2Sdoug 	if (cbs->len < n)
43c4905cd3Sdoug 		return 0;
44c4905cd3Sdoug 
45c4905cd3Sdoug 	*p = cbs->data;
46c4905cd3Sdoug 	cbs->data += n;
47c4905cd3Sdoug 	cbs->len -= n;
48c4905cd3Sdoug 	return 1;
49c4905cd3Sdoug }
50c4905cd3Sdoug 
519c2102cfSjsing static int
cbs_peek(CBS * cbs,const uint8_t ** p,size_t n)529c2102cfSjsing cbs_peek(CBS *cbs, const uint8_t **p, size_t n)
539c2102cfSjsing {
549c2102cfSjsing 	if (cbs->len < n)
559c2102cfSjsing 		return 0;
569c2102cfSjsing 
579c2102cfSjsing 	*p = cbs->data;
589c2102cfSjsing 	return 1;
599c2102cfSjsing }
609c2102cfSjsing 
6134e475baSdoug size_t
CBS_offset(const CBS * cbs)6234e475baSdoug CBS_offset(const CBS *cbs)
6334e475baSdoug {
6434e475baSdoug 	return cbs->initial_len - cbs->len;
6534e475baSdoug }
6634e475baSdoug 
67732f1cb2Sdoug int
CBS_skip(CBS * cbs,size_t len)68732f1cb2Sdoug CBS_skip(CBS *cbs, size_t len)
69732f1cb2Sdoug {
70c4905cd3Sdoug 	const uint8_t *dummy;
71c4905cd3Sdoug 	return cbs_get(cbs, &dummy, len);
72c4905cd3Sdoug }
73c4905cd3Sdoug 
74732f1cb2Sdoug const uint8_t *
CBS_data(const CBS * cbs)75732f1cb2Sdoug CBS_data(const CBS *cbs)
76732f1cb2Sdoug {
77c4905cd3Sdoug 	return cbs->data;
78c4905cd3Sdoug }
79c4905cd3Sdoug 
80732f1cb2Sdoug size_t
CBS_len(const CBS * cbs)81732f1cb2Sdoug CBS_len(const CBS *cbs)
82732f1cb2Sdoug {
83c4905cd3Sdoug 	return cbs->len;
84c4905cd3Sdoug }
85c4905cd3Sdoug 
86732f1cb2Sdoug int
CBS_stow(const CBS * cbs,uint8_t ** out_ptr,size_t * out_len)87732f1cb2Sdoug CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len)
88732f1cb2Sdoug {
89c4905cd3Sdoug 	free(*out_ptr);
90c4905cd3Sdoug 	*out_ptr = NULL;
91c4905cd3Sdoug 	*out_len = 0;
92c4905cd3Sdoug 
93732f1cb2Sdoug 	if (cbs->len == 0)
94c4905cd3Sdoug 		return 1;
95732f1cb2Sdoug 
969b57e268Sjsing 	if ((*out_ptr = malloc(cbs->len)) == NULL)
97c4905cd3Sdoug 		return 0;
98732f1cb2Sdoug 
999b57e268Sjsing 	memcpy(*out_ptr, cbs->data, cbs->len);
1009b57e268Sjsing 
101c4905cd3Sdoug 	*out_len = cbs->len;
102c4905cd3Sdoug 	return 1;
103c4905cd3Sdoug }
104c4905cd3Sdoug 
105732f1cb2Sdoug int
CBS_strdup(const CBS * cbs,char ** out_ptr)106732f1cb2Sdoug CBS_strdup(const CBS *cbs, char **out_ptr)
107732f1cb2Sdoug {
108c4905cd3Sdoug 	free(*out_ptr);
109fdf93b5cSjsing 	*out_ptr = NULL;
110fdf93b5cSjsing 
111fdf93b5cSjsing 	if (CBS_contains_zero_byte(cbs))
112fdf93b5cSjsing 		return 0;
113fdf93b5cSjsing 
114c4905cd3Sdoug 	*out_ptr = strndup((const char *)cbs->data, cbs->len);
115c4905cd3Sdoug 	return (*out_ptr != NULL);
116c4905cd3Sdoug }
117c4905cd3Sdoug 
118732f1cb2Sdoug int
CBS_write_bytes(const CBS * cbs,uint8_t * dst,size_t dst_len,size_t * copied)119df129122Sdoug CBS_write_bytes(const CBS *cbs, uint8_t *dst, size_t dst_len, size_t *copied)
120df129122Sdoug {
121df129122Sdoug 	if (dst_len < cbs->len)
122df129122Sdoug 		return 0;
123df129122Sdoug 
124df129122Sdoug 	memmove(dst, cbs->data, cbs->len);
125df129122Sdoug 
126df129122Sdoug 	if (copied != NULL)
127df129122Sdoug 		*copied = cbs->len;
128df129122Sdoug 
129df129122Sdoug 	return 1;
130df129122Sdoug }
131df129122Sdoug 
132df129122Sdoug int
CBS_contains_zero_byte(const CBS * cbs)133732f1cb2Sdoug CBS_contains_zero_byte(const CBS *cbs)
134732f1cb2Sdoug {
135c4905cd3Sdoug 	return memchr(cbs->data, 0, cbs->len) != NULL;
136c4905cd3Sdoug }
137c4905cd3Sdoug 
138732f1cb2Sdoug int
CBS_mem_equal(const CBS * cbs,const uint8_t * data,size_t len)139732f1cb2Sdoug CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len)
140732f1cb2Sdoug {
141c4905cd3Sdoug 	if (len != cbs->len)
142c4905cd3Sdoug 		return 0;
143732f1cb2Sdoug 
144bc3bf85dSdoug 	return timingsafe_memcmp(cbs->data, data, len) == 0;
145c4905cd3Sdoug }
146c4905cd3Sdoug 
147732f1cb2Sdoug static int
cbs_get_u(CBS * cbs,uint32_t * out,size_t len)148732f1cb2Sdoug cbs_get_u(CBS *cbs, uint32_t *out, size_t len)
149732f1cb2Sdoug {
150c4905cd3Sdoug 	uint32_t result = 0;
151c4905cd3Sdoug 	size_t i;
152c4905cd3Sdoug 	const uint8_t *data;
153c4905cd3Sdoug 
154eb92844bSdoug 	if (len < 1 || len > 4)
155eb92844bSdoug 		return 0;
156eb92844bSdoug 
157732f1cb2Sdoug 	if (!cbs_get(cbs, &data, len))
158c4905cd3Sdoug 		return 0;
159732f1cb2Sdoug 
160c4905cd3Sdoug 	for (i = 0; i < len; i++) {
161c4905cd3Sdoug 		result <<= 8;
162c4905cd3Sdoug 		result |= data[i];
163c4905cd3Sdoug 	}
164c4905cd3Sdoug 	*out = result;
165c4905cd3Sdoug 	return 1;
166c4905cd3Sdoug }
167c4905cd3Sdoug 
168732f1cb2Sdoug int
CBS_get_u8(CBS * cbs,uint8_t * out)169732f1cb2Sdoug CBS_get_u8(CBS *cbs, uint8_t *out)
170732f1cb2Sdoug {
171c4905cd3Sdoug 	const uint8_t *v;
172732f1cb2Sdoug 
173732f1cb2Sdoug 	if (!cbs_get(cbs, &v, 1))
174c4905cd3Sdoug 		return 0;
175732f1cb2Sdoug 
176c4905cd3Sdoug 	*out = *v;
177c4905cd3Sdoug 	return 1;
178c4905cd3Sdoug }
179c4905cd3Sdoug 
180732f1cb2Sdoug int
CBS_get_u16(CBS * cbs,uint16_t * out)181732f1cb2Sdoug CBS_get_u16(CBS *cbs, uint16_t *out)
182732f1cb2Sdoug {
183c4905cd3Sdoug 	uint32_t v;
184732f1cb2Sdoug 
185732f1cb2Sdoug 	if (!cbs_get_u(cbs, &v, 2))
186c4905cd3Sdoug 		return 0;
187732f1cb2Sdoug 
188c4905cd3Sdoug 	*out = v;
189c4905cd3Sdoug 	return 1;
190c4905cd3Sdoug }
191c4905cd3Sdoug 
192732f1cb2Sdoug int
CBS_get_u24(CBS * cbs,uint32_t * out)193732f1cb2Sdoug CBS_get_u24(CBS *cbs, uint32_t *out)
194732f1cb2Sdoug {
195c4905cd3Sdoug 	return cbs_get_u(cbs, out, 3);
196c4905cd3Sdoug }
197c4905cd3Sdoug 
198732f1cb2Sdoug int
CBS_get_u32(CBS * cbs,uint32_t * out)199732f1cb2Sdoug CBS_get_u32(CBS *cbs, uint32_t *out)
200732f1cb2Sdoug {
201c4905cd3Sdoug 	return cbs_get_u(cbs, out, 4);
202c4905cd3Sdoug }
203c4905cd3Sdoug 
204732f1cb2Sdoug int
CBS_get_u64(CBS * cbs,uint64_t * out)205d2653aa9Sjsing CBS_get_u64(CBS *cbs, uint64_t *out)
206d2653aa9Sjsing {
207d2653aa9Sjsing 	uint32_t a, b;
208d2653aa9Sjsing 
209d2653aa9Sjsing 	if (cbs->len < 8)
210d2653aa9Sjsing 		return 0;
211d2653aa9Sjsing 
212d2653aa9Sjsing 	if (!CBS_get_u32(cbs, &a))
213d2653aa9Sjsing 		return 0;
214d2653aa9Sjsing 	if (!CBS_get_u32(cbs, &b))
215d2653aa9Sjsing 		return 0;
216d2653aa9Sjsing 
217d2653aa9Sjsing 	*out = (uint64_t)a << 32 | b;
218d2653aa9Sjsing 	return 1;
219d2653aa9Sjsing }
220d2653aa9Sjsing 
221d2653aa9Sjsing int
CBS_get_last_u8(CBS * cbs,uint8_t * out)222a44c0c8fSjsing CBS_get_last_u8(CBS *cbs, uint8_t *out)
223a44c0c8fSjsing {
224a44c0c8fSjsing 	if (cbs->len == 0)
225a44c0c8fSjsing 		return 0;
226a44c0c8fSjsing 
227a44c0c8fSjsing 	*out = cbs->data[cbs->len - 1];
228a44c0c8fSjsing 	cbs->len--;
229a44c0c8fSjsing 	return 1;
230a44c0c8fSjsing }
231a44c0c8fSjsing 
232a44c0c8fSjsing int
CBS_get_bytes(CBS * cbs,CBS * out,size_t len)233732f1cb2Sdoug CBS_get_bytes(CBS *cbs, CBS *out, size_t len)
234732f1cb2Sdoug {
235c4905cd3Sdoug 	const uint8_t *v;
236732f1cb2Sdoug 
237732f1cb2Sdoug 	if (!cbs_get(cbs, &v, len))
238c4905cd3Sdoug 		return 0;
239732f1cb2Sdoug 
240c4905cd3Sdoug 	CBS_init(out, v, len);
241c4905cd3Sdoug 	return 1;
242c4905cd3Sdoug }
243c4905cd3Sdoug 
244732f1cb2Sdoug static int
cbs_get_length_prefixed(CBS * cbs,CBS * out,size_t len_len)245732f1cb2Sdoug cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len)
246732f1cb2Sdoug {
247c4905cd3Sdoug 	uint32_t len;
248732f1cb2Sdoug 
249732f1cb2Sdoug 	if (!cbs_get_u(cbs, &len, len_len))
250c4905cd3Sdoug 		return 0;
251732f1cb2Sdoug 
252c4905cd3Sdoug 	return CBS_get_bytes(cbs, out, len);
253c4905cd3Sdoug }
254c4905cd3Sdoug 
255732f1cb2Sdoug int
CBS_get_u8_length_prefixed(CBS * cbs,CBS * out)256732f1cb2Sdoug CBS_get_u8_length_prefixed(CBS *cbs, CBS *out)
257732f1cb2Sdoug {
258c4905cd3Sdoug 	return cbs_get_length_prefixed(cbs, out, 1);
259c4905cd3Sdoug }
260c4905cd3Sdoug 
261732f1cb2Sdoug int
CBS_get_u16_length_prefixed(CBS * cbs,CBS * out)262732f1cb2Sdoug CBS_get_u16_length_prefixed(CBS *cbs, CBS *out)
263732f1cb2Sdoug {
264c4905cd3Sdoug 	return cbs_get_length_prefixed(cbs, out, 2);
265c4905cd3Sdoug }
266c4905cd3Sdoug 
267732f1cb2Sdoug int
CBS_get_u24_length_prefixed(CBS * cbs,CBS * out)268732f1cb2Sdoug CBS_get_u24_length_prefixed(CBS *cbs, CBS *out)
269732f1cb2Sdoug {
270c4905cd3Sdoug 	return cbs_get_length_prefixed(cbs, out, 3);
271c4905cd3Sdoug }
272c4905cd3Sdoug 
2739c2102cfSjsing static int
cbs_peek_u(CBS * cbs,uint32_t * out,size_t len)2749c2102cfSjsing cbs_peek_u(CBS *cbs, uint32_t *out, size_t len)
2759c2102cfSjsing {
2769c2102cfSjsing 	uint32_t result = 0;
2779c2102cfSjsing 	size_t i;
2789c2102cfSjsing 	const uint8_t *data;
2799c2102cfSjsing 
2809c2102cfSjsing 	if (len < 1 || len > 4)
2819c2102cfSjsing 		return 0;
2829c2102cfSjsing 
2839c2102cfSjsing 	if (!cbs_peek(cbs, &data, len))
2849c2102cfSjsing 		return 0;
2859c2102cfSjsing 
2869c2102cfSjsing 	for (i = 0; i < len; i++) {
2879c2102cfSjsing 		result <<= 8;
2889c2102cfSjsing 		result |= data[i];
2899c2102cfSjsing 	}
2909c2102cfSjsing 	*out = result;
2919c2102cfSjsing 	return 1;
2929c2102cfSjsing }
2939c2102cfSjsing 
2949c2102cfSjsing int
CBS_peek_u8(CBS * cbs,uint8_t * out)2959c2102cfSjsing CBS_peek_u8(CBS *cbs, uint8_t *out)
2969c2102cfSjsing {
2979c2102cfSjsing 	const uint8_t *v;
2989c2102cfSjsing 
2999c2102cfSjsing 	if (!cbs_peek(cbs, &v, 1))
3009c2102cfSjsing 		return 0;
3019c2102cfSjsing 
3029c2102cfSjsing 	*out = *v;
3039c2102cfSjsing 	return 1;
3049c2102cfSjsing }
3059c2102cfSjsing 
3069c2102cfSjsing int
CBS_peek_u16(CBS * cbs,uint16_t * out)3079c2102cfSjsing CBS_peek_u16(CBS *cbs, uint16_t *out)
3089c2102cfSjsing {
3099c2102cfSjsing 	uint32_t v;
3109c2102cfSjsing 
3119c2102cfSjsing 	if (!cbs_peek_u(cbs, &v, 2))
3129c2102cfSjsing 		return 0;
3139c2102cfSjsing 
3149c2102cfSjsing 	*out = v;
3159c2102cfSjsing 	return 1;
3169c2102cfSjsing }
3179c2102cfSjsing 
3189c2102cfSjsing int
CBS_peek_u24(CBS * cbs,uint32_t * out)3199c2102cfSjsing CBS_peek_u24(CBS *cbs, uint32_t *out)
3209c2102cfSjsing {
3219c2102cfSjsing 	return cbs_peek_u(cbs, out, 3);
3229c2102cfSjsing }
3239c2102cfSjsing 
3249c2102cfSjsing int
CBS_peek_u32(CBS * cbs,uint32_t * out)3259c2102cfSjsing CBS_peek_u32(CBS *cbs, uint32_t *out)
3269c2102cfSjsing {
3279c2102cfSjsing 	return cbs_peek_u(cbs, out, 4);
3289c2102cfSjsing }
3299c2102cfSjsing 
3309c2102cfSjsing int
CBS_peek_last_u8(CBS * cbs,uint8_t * out)3319c2102cfSjsing CBS_peek_last_u8(CBS *cbs, uint8_t *out)
3329c2102cfSjsing {
3339c2102cfSjsing 	if (cbs->len == 0)
3349c2102cfSjsing 		return 0;
3359c2102cfSjsing 
3369c2102cfSjsing 	*out = cbs->data[cbs->len - 1];
3379c2102cfSjsing 	return 1;
3389c2102cfSjsing }
3399c2102cfSjsing 
340732f1cb2Sdoug int
CBS_get_any_asn1_element(CBS * cbs,CBS * out,unsigned int * out_tag,size_t * out_header_len)3410ad3dcfdSdoug CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned int *out_tag,
342732f1cb2Sdoug     size_t *out_header_len)
343732f1cb2Sdoug {
3440870ee34Sdoug 	return cbs_get_any_asn1_element_internal(cbs, out, out_tag,
3450870ee34Sdoug 	    out_header_len, 1);
3460870ee34Sdoug }
3470870ee34Sdoug 
3480870ee34Sdoug /*
3490870ee34Sdoug  * Review X.690 for details on ASN.1 DER encoding.
3500870ee34Sdoug  *
3510870ee34Sdoug  * If non-strict mode is enabled, then DER rules are relaxed
3520870ee34Sdoug  * for indefinite constructs (violates DER but a little closer to BER).
3530870ee34Sdoug  * Non-strict mode should only be used by bs_ber.c
3540870ee34Sdoug  *
3550870ee34Sdoug  * Sections 8, 10 and 11 for DER encoding
3560870ee34Sdoug  */
3570870ee34Sdoug int
cbs_get_any_asn1_element_internal(CBS * cbs,CBS * out,unsigned int * out_tag,size_t * out_header_len,int strict)3580ad3dcfdSdoug cbs_get_any_asn1_element_internal(CBS *cbs, CBS *out, unsigned int *out_tag,
3590870ee34Sdoug     size_t *out_header_len, int strict)
3600870ee34Sdoug {
361c4905cd3Sdoug 	uint8_t tag, length_byte;
362c4905cd3Sdoug 	CBS header = *cbs;
363c4905cd3Sdoug 	CBS throwaway;
3640870ee34Sdoug 	size_t len;
365c4905cd3Sdoug 
366732f1cb2Sdoug 	if (out == NULL)
367c4905cd3Sdoug 		out = &throwaway;
368c4905cd3Sdoug 
3690870ee34Sdoug 	/*
3700870ee34Sdoug 	 * Get identifier octet and length octet.  Only 1 octet for each
3710870ee34Sdoug 	 * is a CBS limitation.
3720870ee34Sdoug 	 */
373732f1cb2Sdoug 	if (!CBS_get_u8(&header, &tag) || !CBS_get_u8(&header, &length_byte))
374c4905cd3Sdoug 		return 0;
375c4905cd3Sdoug 
3760870ee34Sdoug 	/* CBS limitation: long form tags are not supported. */
377732f1cb2Sdoug 	if ((tag & 0x1f) == 0x1f)
378c4905cd3Sdoug 		return 0;
379c4905cd3Sdoug 
380732f1cb2Sdoug 	if (out_tag != NULL)
381c4905cd3Sdoug 		*out_tag = tag;
382c4905cd3Sdoug 
383c4905cd3Sdoug 	if ((length_byte & 0x80) == 0) {
384c4905cd3Sdoug 		/* Short form length. */
385c4905cd3Sdoug 		len = ((size_t) length_byte) + 2;
386732f1cb2Sdoug 		if (out_header_len != NULL)
387c4905cd3Sdoug 			*out_header_len = 2;
388732f1cb2Sdoug 
389c4905cd3Sdoug 	} else {
390c4905cd3Sdoug 		/* Long form length. */
391c4905cd3Sdoug 		const size_t num_bytes = length_byte & 0x7f;
392c4905cd3Sdoug 		uint32_t len32;
393c4905cd3Sdoug 
3940870ee34Sdoug 		/* ASN.1 reserved value for future extensions */
3950870ee34Sdoug 		if (num_bytes == 0x7f)
3960870ee34Sdoug 			return 0;
3970870ee34Sdoug 
3980870ee34Sdoug 		/* Handle indefinite form length */
3990870ee34Sdoug 		if (num_bytes == 0) {
4000870ee34Sdoug 			/* DER encoding doesn't allow for indefinite form. */
4012b93cbaaSdoug 			if (strict)
4020870ee34Sdoug 				return 0;
4030870ee34Sdoug 
4042b93cbaaSdoug 			/* Primitive cannot use indefinite in BER or DER. */
4052b93cbaaSdoug 			if ((tag & CBS_ASN1_CONSTRUCTED) == 0)
4062b93cbaaSdoug 				return 0;
4072b93cbaaSdoug 
4082b93cbaaSdoug 			/* Constructed, indefinite length allowed in BER. */
409874a9cdcSdoug 			if (out_header_len != NULL)
410c4905cd3Sdoug 				*out_header_len = 2;
411c4905cd3Sdoug 			return CBS_get_bytes(cbs, out, 2);
412c4905cd3Sdoug 		}
413c4905cd3Sdoug 
4140870ee34Sdoug 		/* CBS limitation. */
4150870ee34Sdoug 		if (num_bytes > 4)
416c4905cd3Sdoug 			return 0;
417732f1cb2Sdoug 
418732f1cb2Sdoug 		if (!cbs_get_u(&header, &len32, num_bytes))
419c4905cd3Sdoug 			return 0;
420732f1cb2Sdoug 
4212b93cbaaSdoug 		/* DER has a minimum length octet requirement. */
422732f1cb2Sdoug 		if (len32 < 128)
4230870ee34Sdoug 			/* Should have used short form instead */
424c4905cd3Sdoug 			return 0;
425732f1cb2Sdoug 
426732f1cb2Sdoug 		if ((len32 >> ((num_bytes - 1) * 8)) == 0)
427c4905cd3Sdoug 			/* Length should have been at least one byte shorter. */
428c4905cd3Sdoug 			return 0;
429732f1cb2Sdoug 
430c4905cd3Sdoug 		len = len32;
431732f1cb2Sdoug 		if (len + 2 + num_bytes < len)
432c4905cd3Sdoug 			/* Overflow. */
433c4905cd3Sdoug 			return 0;
434732f1cb2Sdoug 
435c4905cd3Sdoug 		len += 2 + num_bytes;
436732f1cb2Sdoug 		if (out_header_len != NULL)
437c4905cd3Sdoug 			*out_header_len = 2 + num_bytes;
438c4905cd3Sdoug 	}
439c4905cd3Sdoug 
440c4905cd3Sdoug 	return CBS_get_bytes(cbs, out, len);
441c4905cd3Sdoug }
442c4905cd3Sdoug 
443732f1cb2Sdoug static int
cbs_get_asn1(CBS * cbs,CBS * out,unsigned int tag_value,int skip_header)4440ad3dcfdSdoug cbs_get_asn1(CBS *cbs, CBS *out, unsigned int tag_value, int skip_header)
445732f1cb2Sdoug {
446c4905cd3Sdoug 	size_t header_len;
4470ad3dcfdSdoug 	unsigned int tag;
448c4905cd3Sdoug 	CBS throwaway;
449c4905cd3Sdoug 
450732f1cb2Sdoug 	if (out == NULL)
451c4905cd3Sdoug 		out = &throwaway;
452c4905cd3Sdoug 
453c4905cd3Sdoug 	if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) ||
4540870ee34Sdoug 	    tag != tag_value)
455c4905cd3Sdoug 		return 0;
456c4905cd3Sdoug 
45759f50346Sbeck 	if (skip_header && !CBS_skip(out, header_len))
458c4905cd3Sdoug 		return 0;
459c4905cd3Sdoug 
460c4905cd3Sdoug 	return 1;
461c4905cd3Sdoug }
462c4905cd3Sdoug 
463732f1cb2Sdoug int
CBS_get_asn1(CBS * cbs,CBS * out,unsigned int tag_value)4640ad3dcfdSdoug CBS_get_asn1(CBS *cbs, CBS *out, unsigned int tag_value)
465732f1cb2Sdoug {
466c4905cd3Sdoug 	return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */);
467c4905cd3Sdoug }
468c4905cd3Sdoug 
469732f1cb2Sdoug int
CBS_get_asn1_element(CBS * cbs,CBS * out,unsigned int tag_value)4700ad3dcfdSdoug CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned int tag_value)
471732f1cb2Sdoug {
472c4905cd3Sdoug 	return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */);
473c4905cd3Sdoug }
474c4905cd3Sdoug 
475732f1cb2Sdoug int
CBS_peek_asn1_tag(const CBS * cbs,unsigned int tag_value)4760ad3dcfdSdoug CBS_peek_asn1_tag(const CBS *cbs, unsigned int tag_value)
477732f1cb2Sdoug {
478732f1cb2Sdoug 	if (CBS_len(cbs) < 1)
479c4905cd3Sdoug 		return 0;
480732f1cb2Sdoug 
4810e95035fSdoug 	/*
4820e95035fSdoug 	 * Tag number 31 indicates the start of a long form number.
4830e95035fSdoug 	 * This is valid in ASN.1, but CBS only supports short form.
4840e95035fSdoug 	 */
4850e95035fSdoug 	if ((tag_value & 0x1f) == 0x1f)
4860e95035fSdoug 		return 0;
4870e95035fSdoug 
488c4905cd3Sdoug 	return CBS_data(cbs)[0] == tag_value;
489c4905cd3Sdoug }
490c4905cd3Sdoug 
491d1ca6158Sdoug /* Encoding details are in ASN.1: X.690 section 8.3 */
492732f1cb2Sdoug int
CBS_get_asn1_uint64(CBS * cbs,uint64_t * out)493732f1cb2Sdoug CBS_get_asn1_uint64(CBS *cbs, uint64_t *out)
494732f1cb2Sdoug {
495c4905cd3Sdoug 	CBS bytes;
496c4905cd3Sdoug 	const uint8_t *data;
497c4905cd3Sdoug 	size_t i, len;
498c4905cd3Sdoug 
499732f1cb2Sdoug 	if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER))
500c4905cd3Sdoug 		return 0;
501c4905cd3Sdoug 
502c4905cd3Sdoug 	*out = 0;
503c4905cd3Sdoug 	data = CBS_data(&bytes);
504c4905cd3Sdoug 	len = CBS_len(&bytes);
505c4905cd3Sdoug 
506732f1cb2Sdoug 	if (len == 0)
507d1ca6158Sdoug 		/* An INTEGER is encoded with at least one content octet. */
508c4905cd3Sdoug 		return 0;
509c4905cd3Sdoug 
510732f1cb2Sdoug 	if ((data[0] & 0x80) != 0)
511d1ca6158Sdoug 		/* Negative number. */
512d1ca6158Sdoug 		return 0;
513d1ca6158Sdoug 
514d1ca6158Sdoug 	if (data[0] == 0 && len > 1 && (data[1] & 0x80) == 0)
515d1ca6158Sdoug 		/* Violates smallest encoding rule: excessive leading zeros. */
516c4905cd3Sdoug 		return 0;
517c4905cd3Sdoug 
518c4905cd3Sdoug 	for (i = 0; i < len; i++) {
519732f1cb2Sdoug 		if ((*out >> 56) != 0)
520c4905cd3Sdoug 			/* Too large to represent as a uint64_t. */
521c4905cd3Sdoug 			return 0;
522732f1cb2Sdoug 
523c4905cd3Sdoug 		*out <<= 8;
524c4905cd3Sdoug 		*out |= data[i];
525c4905cd3Sdoug 	}
526c4905cd3Sdoug 
527c4905cd3Sdoug 	return 1;
528c4905cd3Sdoug }
529c4905cd3Sdoug 
530732f1cb2Sdoug int
CBS_get_optional_asn1(CBS * cbs,CBS * out,int * out_present,unsigned int tag)5310ad3dcfdSdoug CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned int tag)
532732f1cb2Sdoug {
533c4905cd3Sdoug 	if (CBS_peek_asn1_tag(cbs, tag)) {
534732f1cb2Sdoug 		if (!CBS_get_asn1(cbs, out, tag))
535c4905cd3Sdoug 			return 0;
536732f1cb2Sdoug 
537c4905cd3Sdoug 		*out_present = 1;
538c4905cd3Sdoug 	} else {
539c4905cd3Sdoug 		*out_present = 0;
540c4905cd3Sdoug 	}
541c4905cd3Sdoug 	return 1;
542c4905cd3Sdoug }
543c4905cd3Sdoug 
544732f1cb2Sdoug int
CBS_get_optional_asn1_octet_string(CBS * cbs,CBS * out,int * out_present,unsigned int tag)545732f1cb2Sdoug CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present,
5460ad3dcfdSdoug     unsigned int tag)
547732f1cb2Sdoug {
548c4905cd3Sdoug 	CBS child;
549c4905cd3Sdoug 	int present;
550732f1cb2Sdoug 
551732f1cb2Sdoug 	if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
552c4905cd3Sdoug 		return 0;
553732f1cb2Sdoug 
554c4905cd3Sdoug 	if (present) {
555c4905cd3Sdoug 		if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) ||
556732f1cb2Sdoug 		    CBS_len(&child) != 0)
557c4905cd3Sdoug 			return 0;
558c4905cd3Sdoug 	} else {
559c4905cd3Sdoug 		CBS_init(out, NULL, 0);
560c4905cd3Sdoug 	}
561732f1cb2Sdoug 	if (out_present)
562c4905cd3Sdoug 		*out_present = present;
563732f1cb2Sdoug 
564c4905cd3Sdoug 	return 1;
565c4905cd3Sdoug }
566c4905cd3Sdoug 
567732f1cb2Sdoug int
CBS_get_optional_asn1_uint64(CBS * cbs,uint64_t * out,unsigned int tag,uint64_t default_value)5680ad3dcfdSdoug CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned int tag,
569732f1cb2Sdoug     uint64_t default_value)
570732f1cb2Sdoug {
571c4905cd3Sdoug 	CBS child;
572c4905cd3Sdoug 	int present;
573732f1cb2Sdoug 
574732f1cb2Sdoug 	if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
575c4905cd3Sdoug 		return 0;
576732f1cb2Sdoug 
577c4905cd3Sdoug 	if (present) {
578c4905cd3Sdoug 		if (!CBS_get_asn1_uint64(&child, out) ||
579732f1cb2Sdoug 		    CBS_len(&child) != 0)
580c4905cd3Sdoug 			return 0;
581c4905cd3Sdoug 	} else {
582c4905cd3Sdoug 		*out = default_value;
583c4905cd3Sdoug 	}
584c4905cd3Sdoug 	return 1;
585c4905cd3Sdoug }
586c4905cd3Sdoug 
587732f1cb2Sdoug int
CBS_get_optional_asn1_bool(CBS * cbs,int * out,unsigned int tag,int default_value)5880ad3dcfdSdoug CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned int tag,
5890ad3dcfdSdoug     int default_value)
590732f1cb2Sdoug {
591c4905cd3Sdoug 	CBS child, child2;
592c4905cd3Sdoug 	int present;
593732f1cb2Sdoug 
594732f1cb2Sdoug 	if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
595c4905cd3Sdoug 		return 0;
596732f1cb2Sdoug 
597c4905cd3Sdoug 	if (present) {
598c4905cd3Sdoug 		uint8_t boolean;
599c4905cd3Sdoug 
600c4905cd3Sdoug 		if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
601732f1cb2Sdoug 		    CBS_len(&child2) != 1 || CBS_len(&child) != 0)
602c4905cd3Sdoug 			return 0;
603c4905cd3Sdoug 
604c4905cd3Sdoug 		boolean = CBS_data(&child2)[0];
605732f1cb2Sdoug 		if (boolean == 0)
606c4905cd3Sdoug 			*out = 0;
607732f1cb2Sdoug 		else if (boolean == 0xff)
608c4905cd3Sdoug 			*out = 1;
609732f1cb2Sdoug 		else
610c4905cd3Sdoug 			return 0;
611732f1cb2Sdoug 
612c4905cd3Sdoug 	} else {
613c4905cd3Sdoug 		*out = default_value;
614c4905cd3Sdoug 	}
615c4905cd3Sdoug 	return 1;
616c4905cd3Sdoug }
617