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