1*ae014d6eStb /* $OpenBSD: bs_cbs.c,v 1.3 2024/05/25 15:12:47 tb Exp $ */
23c46923dSjsing /*
33c46923dSjsing * Copyright (c) 2014, Google Inc.
43c46923dSjsing *
53c46923dSjsing * Permission to use, copy, modify, and/or distribute this software for any
63c46923dSjsing * purpose with or without fee is hereby granted, provided that the above
73c46923dSjsing * copyright notice and this permission notice appear in all copies.
83c46923dSjsing *
93c46923dSjsing * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
103c46923dSjsing * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
113c46923dSjsing * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
123c46923dSjsing * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
133c46923dSjsing * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
143c46923dSjsing * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
153c46923dSjsing * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
163c46923dSjsing */
173c46923dSjsing
18*ae014d6eStb #include <stdint.h>
193c46923dSjsing #include <stdlib.h>
203c46923dSjsing #include <string.h>
213c46923dSjsing
223c46923dSjsing #include "bytestring.h"
233c46923dSjsing
243c46923dSjsing void
CBS_init(CBS * cbs,const uint8_t * data,size_t len)253c46923dSjsing CBS_init(CBS *cbs, const uint8_t *data, size_t len)
263c46923dSjsing {
273c46923dSjsing cbs->data = data;
283c46923dSjsing cbs->initial_len = len;
293c46923dSjsing cbs->len = len;
303c46923dSjsing }
313c46923dSjsing
323c46923dSjsing void
CBS_dup(const CBS * cbs,CBS * out)333c46923dSjsing CBS_dup(const CBS *cbs, CBS *out)
343c46923dSjsing {
353c46923dSjsing CBS_init(out, CBS_data(cbs), CBS_len(cbs));
363c46923dSjsing out->initial_len = cbs->initial_len;
373c46923dSjsing }
383c46923dSjsing
393c46923dSjsing static int
cbs_get(CBS * cbs,const uint8_t ** p,size_t n)403c46923dSjsing cbs_get(CBS *cbs, const uint8_t **p, size_t n)
413c46923dSjsing {
423c46923dSjsing if (cbs->len < n)
433c46923dSjsing return 0;
443c46923dSjsing
453c46923dSjsing *p = cbs->data;
463c46923dSjsing cbs->data += n;
473c46923dSjsing cbs->len -= n;
483c46923dSjsing return 1;
493c46923dSjsing }
503c46923dSjsing
51470be27dSjsing static int
cbs_peek(CBS * cbs,const uint8_t ** p,size_t n)52470be27dSjsing cbs_peek(CBS *cbs, const uint8_t **p, size_t n)
53470be27dSjsing {
54470be27dSjsing if (cbs->len < n)
55470be27dSjsing return 0;
56470be27dSjsing
57470be27dSjsing *p = cbs->data;
58470be27dSjsing return 1;
59470be27dSjsing }
60470be27dSjsing
613c46923dSjsing size_t
CBS_offset(const CBS * cbs)623c46923dSjsing CBS_offset(const CBS *cbs)
633c46923dSjsing {
643c46923dSjsing return cbs->initial_len - cbs->len;
653c46923dSjsing }
663c46923dSjsing
673c46923dSjsing int
CBS_skip(CBS * cbs,size_t len)683c46923dSjsing CBS_skip(CBS *cbs, size_t len)
693c46923dSjsing {
703c46923dSjsing const uint8_t *dummy;
713c46923dSjsing return cbs_get(cbs, &dummy, len);
723c46923dSjsing }
733c46923dSjsing
743c46923dSjsing const uint8_t *
CBS_data(const CBS * cbs)753c46923dSjsing CBS_data(const CBS *cbs)
763c46923dSjsing {
773c46923dSjsing return cbs->data;
783c46923dSjsing }
793c46923dSjsing
803c46923dSjsing size_t
CBS_len(const CBS * cbs)813c46923dSjsing CBS_len(const CBS *cbs)
823c46923dSjsing {
833c46923dSjsing return cbs->len;
843c46923dSjsing }
853c46923dSjsing
863c46923dSjsing int
CBS_stow(const CBS * cbs,uint8_t ** out_ptr,size_t * out_len)873c46923dSjsing CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len)
883c46923dSjsing {
893c46923dSjsing free(*out_ptr);
903c46923dSjsing *out_ptr = NULL;
913c46923dSjsing *out_len = 0;
923c46923dSjsing
933c46923dSjsing if (cbs->len == 0)
943c46923dSjsing return 1;
953c46923dSjsing
963c46923dSjsing if ((*out_ptr = malloc(cbs->len)) == NULL)
973c46923dSjsing return 0;
983c46923dSjsing
993c46923dSjsing memcpy(*out_ptr, cbs->data, cbs->len);
1003c46923dSjsing
1013c46923dSjsing *out_len = cbs->len;
1023c46923dSjsing return 1;
1033c46923dSjsing }
1043c46923dSjsing
1053c46923dSjsing int
CBS_strdup(const CBS * cbs,char ** out_ptr)1063c46923dSjsing CBS_strdup(const CBS *cbs, char **out_ptr)
1073c46923dSjsing {
1083c46923dSjsing free(*out_ptr);
1093c46923dSjsing *out_ptr = NULL;
1103c46923dSjsing
1113c46923dSjsing if (CBS_contains_zero_byte(cbs))
1123c46923dSjsing return 0;
1133c46923dSjsing
1143c46923dSjsing *out_ptr = strndup((const char *)cbs->data, cbs->len);
1153c46923dSjsing return (*out_ptr != NULL);
1163c46923dSjsing }
1173c46923dSjsing
1183c46923dSjsing int
CBS_write_bytes(const CBS * cbs,uint8_t * dst,size_t dst_len,size_t * copied)1193c46923dSjsing CBS_write_bytes(const CBS *cbs, uint8_t *dst, size_t dst_len, size_t *copied)
1203c46923dSjsing {
1213c46923dSjsing if (dst_len < cbs->len)
1223c46923dSjsing return 0;
1233c46923dSjsing
1243c46923dSjsing memmove(dst, cbs->data, cbs->len);
1253c46923dSjsing
1263c46923dSjsing if (copied != NULL)
1273c46923dSjsing *copied = cbs->len;
1283c46923dSjsing
1293c46923dSjsing return 1;
1303c46923dSjsing }
1313c46923dSjsing
1323c46923dSjsing int
CBS_contains_zero_byte(const CBS * cbs)1333c46923dSjsing CBS_contains_zero_byte(const CBS *cbs)
1343c46923dSjsing {
1353c46923dSjsing return memchr(cbs->data, 0, cbs->len) != NULL;
1363c46923dSjsing }
1373c46923dSjsing
1383c46923dSjsing int
CBS_mem_equal(const CBS * cbs,const uint8_t * data,size_t len)1393c46923dSjsing CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len)
1403c46923dSjsing {
1413c46923dSjsing if (len != cbs->len)
1423c46923dSjsing return 0;
1433c46923dSjsing
1443c46923dSjsing return timingsafe_memcmp(cbs->data, data, len) == 0;
1453c46923dSjsing }
1463c46923dSjsing
1473c46923dSjsing static int
cbs_get_u(CBS * cbs,uint32_t * out,size_t len)1483c46923dSjsing cbs_get_u(CBS *cbs, uint32_t *out, size_t len)
1493c46923dSjsing {
1503c46923dSjsing uint32_t result = 0;
1513c46923dSjsing size_t i;
1523c46923dSjsing const uint8_t *data;
1533c46923dSjsing
1543c46923dSjsing if (len < 1 || len > 4)
1553c46923dSjsing return 0;
1563c46923dSjsing
1573c46923dSjsing if (!cbs_get(cbs, &data, len))
1583c46923dSjsing return 0;
1593c46923dSjsing
1603c46923dSjsing for (i = 0; i < len; i++) {
1613c46923dSjsing result <<= 8;
1623c46923dSjsing result |= data[i];
1633c46923dSjsing }
1643c46923dSjsing *out = result;
1653c46923dSjsing return 1;
1663c46923dSjsing }
1673c46923dSjsing
1683c46923dSjsing int
CBS_get_u8(CBS * cbs,uint8_t * out)1693c46923dSjsing CBS_get_u8(CBS *cbs, uint8_t *out)
1703c46923dSjsing {
1713c46923dSjsing const uint8_t *v;
1723c46923dSjsing
1733c46923dSjsing if (!cbs_get(cbs, &v, 1))
1743c46923dSjsing return 0;
1753c46923dSjsing
1763c46923dSjsing *out = *v;
1773c46923dSjsing return 1;
1783c46923dSjsing }
1793c46923dSjsing
1803c46923dSjsing int
CBS_get_u16(CBS * cbs,uint16_t * out)1813c46923dSjsing CBS_get_u16(CBS *cbs, uint16_t *out)
1823c46923dSjsing {
1833c46923dSjsing uint32_t v;
1843c46923dSjsing
1853c46923dSjsing if (!cbs_get_u(cbs, &v, 2))
1863c46923dSjsing return 0;
1873c46923dSjsing
1883c46923dSjsing *out = v;
1893c46923dSjsing return 1;
1903c46923dSjsing }
1913c46923dSjsing
1923c46923dSjsing int
CBS_get_u24(CBS * cbs,uint32_t * out)1933c46923dSjsing CBS_get_u24(CBS *cbs, uint32_t *out)
1943c46923dSjsing {
1953c46923dSjsing return cbs_get_u(cbs, out, 3);
1963c46923dSjsing }
1973c46923dSjsing
1983c46923dSjsing int
CBS_get_u32(CBS * cbs,uint32_t * out)1993c46923dSjsing CBS_get_u32(CBS *cbs, uint32_t *out)
2003c46923dSjsing {
2013c46923dSjsing return cbs_get_u(cbs, out, 4);
2023c46923dSjsing }
2033c46923dSjsing
2043c46923dSjsing int
CBS_get_u64(CBS * cbs,uint64_t * out)205470be27dSjsing CBS_get_u64(CBS *cbs, uint64_t *out)
206470be27dSjsing {
207470be27dSjsing uint32_t a, b;
208470be27dSjsing
209470be27dSjsing if (cbs->len < 8)
210470be27dSjsing return 0;
211470be27dSjsing
212470be27dSjsing if (!CBS_get_u32(cbs, &a))
213470be27dSjsing return 0;
214470be27dSjsing if (!CBS_get_u32(cbs, &b))
215470be27dSjsing return 0;
216470be27dSjsing
217470be27dSjsing *out = (uint64_t)a << 32 | b;
218470be27dSjsing return 1;
219470be27dSjsing }
220470be27dSjsing
221470be27dSjsing int
CBS_get_last_u8(CBS * cbs,uint8_t * out)222470be27dSjsing CBS_get_last_u8(CBS *cbs, uint8_t *out)
223470be27dSjsing {
224470be27dSjsing if (cbs->len == 0)
225470be27dSjsing return 0;
226470be27dSjsing
227470be27dSjsing *out = cbs->data[cbs->len - 1];
228470be27dSjsing cbs->len--;
229470be27dSjsing return 1;
230470be27dSjsing }
231470be27dSjsing
232470be27dSjsing int
CBS_get_bytes(CBS * cbs,CBS * out,size_t len)2333c46923dSjsing CBS_get_bytes(CBS *cbs, CBS *out, size_t len)
2343c46923dSjsing {
2353c46923dSjsing const uint8_t *v;
2363c46923dSjsing
2373c46923dSjsing if (!cbs_get(cbs, &v, len))
2383c46923dSjsing return 0;
2393c46923dSjsing
2403c46923dSjsing CBS_init(out, v, len);
2413c46923dSjsing return 1;
2423c46923dSjsing }
2433c46923dSjsing
2443c46923dSjsing static int
cbs_get_length_prefixed(CBS * cbs,CBS * out,size_t len_len)2453c46923dSjsing cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len)
2463c46923dSjsing {
2473c46923dSjsing uint32_t len;
2483c46923dSjsing
2493c46923dSjsing if (!cbs_get_u(cbs, &len, len_len))
2503c46923dSjsing return 0;
2513c46923dSjsing
2523c46923dSjsing return CBS_get_bytes(cbs, out, len);
2533c46923dSjsing }
2543c46923dSjsing
2553c46923dSjsing int
CBS_get_u8_length_prefixed(CBS * cbs,CBS * out)2563c46923dSjsing CBS_get_u8_length_prefixed(CBS *cbs, CBS *out)
2573c46923dSjsing {
2583c46923dSjsing return cbs_get_length_prefixed(cbs, out, 1);
2593c46923dSjsing }
2603c46923dSjsing
2613c46923dSjsing int
CBS_get_u16_length_prefixed(CBS * cbs,CBS * out)2623c46923dSjsing CBS_get_u16_length_prefixed(CBS *cbs, CBS *out)
2633c46923dSjsing {
2643c46923dSjsing return cbs_get_length_prefixed(cbs, out, 2);
2653c46923dSjsing }
2663c46923dSjsing
2673c46923dSjsing int
CBS_get_u24_length_prefixed(CBS * cbs,CBS * out)2683c46923dSjsing CBS_get_u24_length_prefixed(CBS *cbs, CBS *out)
2693c46923dSjsing {
2703c46923dSjsing return cbs_get_length_prefixed(cbs, out, 3);
2713c46923dSjsing }
2723c46923dSjsing
273470be27dSjsing static int
cbs_peek_u(CBS * cbs,uint32_t * out,size_t len)274470be27dSjsing cbs_peek_u(CBS *cbs, uint32_t *out, size_t len)
275470be27dSjsing {
276470be27dSjsing uint32_t result = 0;
277470be27dSjsing size_t i;
278470be27dSjsing const uint8_t *data;
279470be27dSjsing
280470be27dSjsing if (len < 1 || len > 4)
281470be27dSjsing return 0;
282470be27dSjsing
283470be27dSjsing if (!cbs_peek(cbs, &data, len))
284470be27dSjsing return 0;
285470be27dSjsing
286470be27dSjsing for (i = 0; i < len; i++) {
287470be27dSjsing result <<= 8;
288470be27dSjsing result |= data[i];
289470be27dSjsing }
290470be27dSjsing *out = result;
291470be27dSjsing return 1;
292470be27dSjsing }
293470be27dSjsing
294470be27dSjsing int
CBS_peek_u8(CBS * cbs,uint8_t * out)295470be27dSjsing CBS_peek_u8(CBS *cbs, uint8_t *out)
296470be27dSjsing {
297470be27dSjsing const uint8_t *v;
298470be27dSjsing
299470be27dSjsing if (!cbs_peek(cbs, &v, 1))
300470be27dSjsing return 0;
301470be27dSjsing
302470be27dSjsing *out = *v;
303470be27dSjsing return 1;
304470be27dSjsing }
305470be27dSjsing
306470be27dSjsing int
CBS_peek_u16(CBS * cbs,uint16_t * out)307470be27dSjsing CBS_peek_u16(CBS *cbs, uint16_t *out)
308470be27dSjsing {
309470be27dSjsing uint32_t v;
310470be27dSjsing
311470be27dSjsing if (!cbs_peek_u(cbs, &v, 2))
312470be27dSjsing return 0;
313470be27dSjsing
314470be27dSjsing *out = v;
315470be27dSjsing return 1;
316470be27dSjsing }
317470be27dSjsing
318470be27dSjsing int
CBS_peek_u24(CBS * cbs,uint32_t * out)319470be27dSjsing CBS_peek_u24(CBS *cbs, uint32_t *out)
320470be27dSjsing {
321470be27dSjsing return cbs_peek_u(cbs, out, 3);
322470be27dSjsing }
323470be27dSjsing
324470be27dSjsing int
CBS_peek_u32(CBS * cbs,uint32_t * out)325470be27dSjsing CBS_peek_u32(CBS *cbs, uint32_t *out)
326470be27dSjsing {
327470be27dSjsing return cbs_peek_u(cbs, out, 4);
328470be27dSjsing }
329470be27dSjsing
330470be27dSjsing int
CBS_peek_last_u8(CBS * cbs,uint8_t * out)331470be27dSjsing CBS_peek_last_u8(CBS *cbs, uint8_t *out)
332470be27dSjsing {
333470be27dSjsing if (cbs->len == 0)
334470be27dSjsing return 0;
335470be27dSjsing
336470be27dSjsing *out = cbs->data[cbs->len - 1];
337470be27dSjsing return 1;
338470be27dSjsing }
339470be27dSjsing
3403c46923dSjsing int
CBS_get_any_asn1_element(CBS * cbs,CBS * out,unsigned int * out_tag,size_t * out_header_len)3413c46923dSjsing CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned int *out_tag,
3423c46923dSjsing size_t *out_header_len)
3433c46923dSjsing {
3443c46923dSjsing return cbs_get_any_asn1_element_internal(cbs, out, out_tag,
3453c46923dSjsing out_header_len, 1);
3463c46923dSjsing }
3473c46923dSjsing
3483c46923dSjsing /*
3493c46923dSjsing * Review X.690 for details on ASN.1 DER encoding.
3503c46923dSjsing *
3513c46923dSjsing * If non-strict mode is enabled, then DER rules are relaxed
3523c46923dSjsing * for indefinite constructs (violates DER but a little closer to BER).
3533c46923dSjsing * Non-strict mode should only be used by bs_ber.c
3543c46923dSjsing *
3553c46923dSjsing * Sections 8, 10 and 11 for DER encoding
3563c46923dSjsing */
3573c46923dSjsing int
cbs_get_any_asn1_element_internal(CBS * cbs,CBS * out,unsigned int * out_tag,size_t * out_header_len,int strict)3583c46923dSjsing cbs_get_any_asn1_element_internal(CBS *cbs, CBS *out, unsigned int *out_tag,
3593c46923dSjsing size_t *out_header_len, int strict)
3603c46923dSjsing {
3613c46923dSjsing uint8_t tag, length_byte;
3623c46923dSjsing CBS header = *cbs;
3633c46923dSjsing CBS throwaway;
3643c46923dSjsing size_t len;
3653c46923dSjsing
3663c46923dSjsing if (out == NULL)
3673c46923dSjsing out = &throwaway;
3683c46923dSjsing
3693c46923dSjsing /*
3703c46923dSjsing * Get identifier octet and length octet. Only 1 octet for each
3713c46923dSjsing * is a CBS limitation.
3723c46923dSjsing */
3733c46923dSjsing if (!CBS_get_u8(&header, &tag) || !CBS_get_u8(&header, &length_byte))
3743c46923dSjsing return 0;
3753c46923dSjsing
3763c46923dSjsing /* CBS limitation: long form tags are not supported. */
3773c46923dSjsing if ((tag & 0x1f) == 0x1f)
3783c46923dSjsing return 0;
3793c46923dSjsing
3803c46923dSjsing if (out_tag != NULL)
3813c46923dSjsing *out_tag = tag;
3823c46923dSjsing
3833c46923dSjsing if ((length_byte & 0x80) == 0) {
3843c46923dSjsing /* Short form length. */
3853c46923dSjsing len = ((size_t) length_byte) + 2;
3863c46923dSjsing if (out_header_len != NULL)
3873c46923dSjsing *out_header_len = 2;
3883c46923dSjsing
3893c46923dSjsing } else {
3903c46923dSjsing /* Long form length. */
3913c46923dSjsing const size_t num_bytes = length_byte & 0x7f;
3923c46923dSjsing uint32_t len32;
3933c46923dSjsing
3943c46923dSjsing /* ASN.1 reserved value for future extensions */
3953c46923dSjsing if (num_bytes == 0x7f)
3963c46923dSjsing return 0;
3973c46923dSjsing
3983c46923dSjsing /* Handle indefinite form length */
3993c46923dSjsing if (num_bytes == 0) {
4003c46923dSjsing /* DER encoding doesn't allow for indefinite form. */
4013c46923dSjsing if (strict)
4023c46923dSjsing return 0;
4033c46923dSjsing
4043c46923dSjsing /* Primitive cannot use indefinite in BER or DER. */
4053c46923dSjsing if ((tag & CBS_ASN1_CONSTRUCTED) == 0)
4063c46923dSjsing return 0;
4073c46923dSjsing
4083c46923dSjsing /* Constructed, indefinite length allowed in BER. */
4093c46923dSjsing if (out_header_len != NULL)
4103c46923dSjsing *out_header_len = 2;
4113c46923dSjsing return CBS_get_bytes(cbs, out, 2);
4123c46923dSjsing }
4133c46923dSjsing
4143c46923dSjsing /* CBS limitation. */
4153c46923dSjsing if (num_bytes > 4)
4163c46923dSjsing return 0;
4173c46923dSjsing
4183c46923dSjsing if (!cbs_get_u(&header, &len32, num_bytes))
4193c46923dSjsing return 0;
4203c46923dSjsing
4213c46923dSjsing /* DER has a minimum length octet requirement. */
4223c46923dSjsing if (len32 < 128)
4233c46923dSjsing /* Should have used short form instead */
4243c46923dSjsing return 0;
4253c46923dSjsing
4263c46923dSjsing if ((len32 >> ((num_bytes - 1) * 8)) == 0)
4273c46923dSjsing /* Length should have been at least one byte shorter. */
4283c46923dSjsing return 0;
4293c46923dSjsing
4303c46923dSjsing len = len32;
4313c46923dSjsing if (len + 2 + num_bytes < len)
4323c46923dSjsing /* Overflow. */
4333c46923dSjsing return 0;
4343c46923dSjsing
4353c46923dSjsing len += 2 + num_bytes;
4363c46923dSjsing if (out_header_len != NULL)
4373c46923dSjsing *out_header_len = 2 + num_bytes;
4383c46923dSjsing }
4393c46923dSjsing
4403c46923dSjsing return CBS_get_bytes(cbs, out, len);
4413c46923dSjsing }
4423c46923dSjsing
4433c46923dSjsing static int
cbs_get_asn1(CBS * cbs,CBS * out,unsigned int tag_value,int skip_header)4443c46923dSjsing cbs_get_asn1(CBS *cbs, CBS *out, unsigned int tag_value, int skip_header)
4453c46923dSjsing {
4463c46923dSjsing size_t header_len;
4473c46923dSjsing unsigned int tag;
4483c46923dSjsing CBS throwaway;
4493c46923dSjsing
4503c46923dSjsing if (out == NULL)
4513c46923dSjsing out = &throwaway;
4523c46923dSjsing
4533c46923dSjsing if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) ||
4543c46923dSjsing tag != tag_value)
4553c46923dSjsing return 0;
4563c46923dSjsing
4573c46923dSjsing if (skip_header && !CBS_skip(out, header_len))
4583c46923dSjsing return 0;
4593c46923dSjsing
4603c46923dSjsing return 1;
4613c46923dSjsing }
4623c46923dSjsing
4633c46923dSjsing int
CBS_get_asn1(CBS * cbs,CBS * out,unsigned int tag_value)4643c46923dSjsing CBS_get_asn1(CBS *cbs, CBS *out, unsigned int tag_value)
4653c46923dSjsing {
4663c46923dSjsing return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */);
4673c46923dSjsing }
4683c46923dSjsing
4693c46923dSjsing int
CBS_get_asn1_element(CBS * cbs,CBS * out,unsigned int tag_value)4703c46923dSjsing CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned int tag_value)
4713c46923dSjsing {
4723c46923dSjsing return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */);
4733c46923dSjsing }
4743c46923dSjsing
4753c46923dSjsing int
CBS_peek_asn1_tag(const CBS * cbs,unsigned int tag_value)4763c46923dSjsing CBS_peek_asn1_tag(const CBS *cbs, unsigned int tag_value)
4773c46923dSjsing {
4783c46923dSjsing if (CBS_len(cbs) < 1)
4793c46923dSjsing return 0;
4803c46923dSjsing
4813c46923dSjsing /*
4823c46923dSjsing * Tag number 31 indicates the start of a long form number.
4833c46923dSjsing * This is valid in ASN.1, but CBS only supports short form.
4843c46923dSjsing */
4853c46923dSjsing if ((tag_value & 0x1f) == 0x1f)
4863c46923dSjsing return 0;
4873c46923dSjsing
4883c46923dSjsing return CBS_data(cbs)[0] == tag_value;
4893c46923dSjsing }
4903c46923dSjsing
4913c46923dSjsing /* Encoding details are in ASN.1: X.690 section 8.3 */
4923c46923dSjsing int
CBS_get_asn1_uint64(CBS * cbs,uint64_t * out)4933c46923dSjsing CBS_get_asn1_uint64(CBS *cbs, uint64_t *out)
4943c46923dSjsing {
4953c46923dSjsing CBS bytes;
4963c46923dSjsing const uint8_t *data;
4973c46923dSjsing size_t i, len;
4983c46923dSjsing
4993c46923dSjsing if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER))
5003c46923dSjsing return 0;
5013c46923dSjsing
5023c46923dSjsing *out = 0;
5033c46923dSjsing data = CBS_data(&bytes);
5043c46923dSjsing len = CBS_len(&bytes);
5053c46923dSjsing
5063c46923dSjsing if (len == 0)
5073c46923dSjsing /* An INTEGER is encoded with at least one content octet. */
5083c46923dSjsing return 0;
5093c46923dSjsing
5103c46923dSjsing if ((data[0] & 0x80) != 0)
5113c46923dSjsing /* Negative number. */
5123c46923dSjsing return 0;
5133c46923dSjsing
5143c46923dSjsing if (data[0] == 0 && len > 1 && (data[1] & 0x80) == 0)
5153c46923dSjsing /* Violates smallest encoding rule: excessive leading zeros. */
5163c46923dSjsing return 0;
5173c46923dSjsing
5183c46923dSjsing for (i = 0; i < len; i++) {
5193c46923dSjsing if ((*out >> 56) != 0)
5203c46923dSjsing /* Too large to represent as a uint64_t. */
5213c46923dSjsing return 0;
5223c46923dSjsing
5233c46923dSjsing *out <<= 8;
5243c46923dSjsing *out |= data[i];
5253c46923dSjsing }
5263c46923dSjsing
5273c46923dSjsing return 1;
5283c46923dSjsing }
5293c46923dSjsing
5303c46923dSjsing int
CBS_get_optional_asn1(CBS * cbs,CBS * out,int * out_present,unsigned int tag)5313c46923dSjsing CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned int tag)
5323c46923dSjsing {
5333c46923dSjsing if (CBS_peek_asn1_tag(cbs, tag)) {
5343c46923dSjsing if (!CBS_get_asn1(cbs, out, tag))
5353c46923dSjsing return 0;
5363c46923dSjsing
5373c46923dSjsing *out_present = 1;
5383c46923dSjsing } else {
5393c46923dSjsing *out_present = 0;
5403c46923dSjsing }
5413c46923dSjsing return 1;
5423c46923dSjsing }
5433c46923dSjsing
5443c46923dSjsing int
CBS_get_optional_asn1_octet_string(CBS * cbs,CBS * out,int * out_present,unsigned int tag)5453c46923dSjsing CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present,
5463c46923dSjsing unsigned int tag)
5473c46923dSjsing {
5483c46923dSjsing CBS child;
5493c46923dSjsing int present;
5503c46923dSjsing
5513c46923dSjsing if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
5523c46923dSjsing return 0;
5533c46923dSjsing
5543c46923dSjsing if (present) {
5553c46923dSjsing if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) ||
5563c46923dSjsing CBS_len(&child) != 0)
5573c46923dSjsing return 0;
5583c46923dSjsing } else {
5593c46923dSjsing CBS_init(out, NULL, 0);
5603c46923dSjsing }
5613c46923dSjsing if (out_present)
5623c46923dSjsing *out_present = present;
5633c46923dSjsing
5643c46923dSjsing return 1;
5653c46923dSjsing }
5663c46923dSjsing
5673c46923dSjsing int
CBS_get_optional_asn1_uint64(CBS * cbs,uint64_t * out,unsigned int tag,uint64_t default_value)5683c46923dSjsing CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned int tag,
5693c46923dSjsing uint64_t default_value)
5703c46923dSjsing {
5713c46923dSjsing CBS child;
5723c46923dSjsing int present;
5733c46923dSjsing
5743c46923dSjsing if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
5753c46923dSjsing return 0;
5763c46923dSjsing
5773c46923dSjsing if (present) {
5783c46923dSjsing if (!CBS_get_asn1_uint64(&child, out) ||
5793c46923dSjsing CBS_len(&child) != 0)
5803c46923dSjsing return 0;
5813c46923dSjsing } else {
5823c46923dSjsing *out = default_value;
5833c46923dSjsing }
5843c46923dSjsing return 1;
5853c46923dSjsing }
5863c46923dSjsing
5873c46923dSjsing int
CBS_get_optional_asn1_bool(CBS * cbs,int * out,unsigned int tag,int default_value)5883c46923dSjsing CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned int tag,
5893c46923dSjsing int default_value)
5903c46923dSjsing {
5913c46923dSjsing CBS child, child2;
5923c46923dSjsing int present;
5933c46923dSjsing
5943c46923dSjsing if (!CBS_get_optional_asn1(cbs, &child, &present, tag))
5953c46923dSjsing return 0;
5963c46923dSjsing
5973c46923dSjsing if (present) {
5983c46923dSjsing uint8_t boolean;
5993c46923dSjsing
6003c46923dSjsing if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
6013c46923dSjsing CBS_len(&child2) != 1 || CBS_len(&child) != 0)
6023c46923dSjsing return 0;
6033c46923dSjsing
6043c46923dSjsing boolean = CBS_data(&child2)[0];
6053c46923dSjsing if (boolean == 0)
6063c46923dSjsing *out = 0;
6073c46923dSjsing else if (boolean == 0xff)
6083c46923dSjsing *out = 1;
6093c46923dSjsing else
6103c46923dSjsing return 0;
6113c46923dSjsing
6123c46923dSjsing } else {
6133c46923dSjsing *out = default_value;
6143c46923dSjsing }
6153c46923dSjsing return 1;
6163c46923dSjsing }
617