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