1 /* $OpenBSD: bs_cbs.c,v 1.24 2021/12/15 17:36:49 jsing Exp $ */
3 * Copyright (c) 2014, Google Inc.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
12 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
14 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include "bytestring.h"
24 CBS_init(CBS
*cbs
, const uint8_t *data
, size_t len
)
27 cbs
->initial_len
= len
;
32 CBS_dup(const CBS
*cbs
, CBS
*out
)
34 CBS_init(out
, CBS_data(cbs
), CBS_len(cbs
));
35 out
->initial_len
= cbs
->initial_len
;
39 cbs_get(CBS
*cbs
, const uint8_t **p
, size_t n
)
51 cbs_peek(CBS
*cbs
, const uint8_t **p
, size_t n
)
61 CBS_offset(const CBS
*cbs
)
63 return cbs
->initial_len
- cbs
->len
;
67 CBS_skip(CBS
*cbs
, size_t len
)
70 return cbs_get(cbs
, &dummy
, len
);
74 CBS_data(const CBS
*cbs
)
80 CBS_len(const CBS
*cbs
)
86 CBS_stow(const CBS
*cbs
, uint8_t **out_ptr
, size_t *out_len
)
95 if ((*out_ptr
= malloc(cbs
->len
)) == NULL
)
98 memcpy(*out_ptr
, cbs
->data
, cbs
->len
);
105 CBS_strdup(const CBS
*cbs
, char **out_ptr
)
110 if (CBS_contains_zero_byte(cbs
))
113 *out_ptr
= strndup((const char *)cbs
->data
, cbs
->len
);
114 return (*out_ptr
!= NULL
);
118 CBS_write_bytes(const CBS
*cbs
, uint8_t *dst
, size_t dst_len
, size_t *copied
)
120 if (dst_len
< cbs
->len
)
123 memmove(dst
, cbs
->data
, cbs
->len
);
132 CBS_contains_zero_byte(const CBS
*cbs
)
134 return memchr(cbs
->data
, 0, cbs
->len
) != NULL
;
138 CBS_mem_equal(const CBS
*cbs
, const uint8_t *data
, size_t len
)
143 return timingsafe_memcmp(cbs
->data
, data
, len
) == 0;
147 cbs_get_u(CBS
*cbs
, uint32_t *out
, size_t len
)
153 if (len
< 1 || len
> 4)
156 if (!cbs_get(cbs
, &data
, len
))
159 for (i
= 0; i
< len
; i
++) {
168 CBS_get_u8(CBS
*cbs
, uint8_t *out
)
172 if (!cbs_get(cbs
, &v
, 1))
180 CBS_get_u16(CBS
*cbs
, uint16_t *out
)
184 if (!cbs_get_u(cbs
, &v
, 2))
192 CBS_get_u24(CBS
*cbs
, uint32_t *out
)
194 return cbs_get_u(cbs
, out
, 3);
198 CBS_get_u32(CBS
*cbs
, uint32_t *out
)
200 return cbs_get_u(cbs
, out
, 4);
204 CBS_get_u64(CBS
*cbs
, uint64_t *out
)
211 if (!CBS_get_u32(cbs
, &a
))
213 if (!CBS_get_u32(cbs
, &b
))
216 *out
= (uint64_t)a
<< 32 | b
;
221 CBS_get_last_u8(CBS
*cbs
, uint8_t *out
)
226 *out
= cbs
->data
[cbs
->len
- 1];
232 CBS_get_bytes(CBS
*cbs
, CBS
*out
, size_t len
)
236 if (!cbs_get(cbs
, &v
, len
))
239 CBS_init(out
, v
, len
);
244 cbs_get_length_prefixed(CBS
*cbs
, CBS
*out
, size_t len_len
)
248 if (!cbs_get_u(cbs
, &len
, len_len
))
251 return CBS_get_bytes(cbs
, out
, len
);
255 CBS_get_u8_length_prefixed(CBS
*cbs
, CBS
*out
)
257 return cbs_get_length_prefixed(cbs
, out
, 1);
261 CBS_get_u16_length_prefixed(CBS
*cbs
, CBS
*out
)
263 return cbs_get_length_prefixed(cbs
, out
, 2);
267 CBS_get_u24_length_prefixed(CBS
*cbs
, CBS
*out
)
269 return cbs_get_length_prefixed(cbs
, out
, 3);
273 cbs_peek_u(CBS
*cbs
, uint32_t *out
, size_t len
)
279 if (len
< 1 || len
> 4)
282 if (!cbs_peek(cbs
, &data
, len
))
285 for (i
= 0; i
< len
; i
++) {
294 CBS_peek_u8(CBS
*cbs
, uint8_t *out
)
298 if (!cbs_peek(cbs
, &v
, 1))
306 CBS_peek_u16(CBS
*cbs
, uint16_t *out
)
310 if (!cbs_peek_u(cbs
, &v
, 2))
318 CBS_peek_u24(CBS
*cbs
, uint32_t *out
)
320 return cbs_peek_u(cbs
, out
, 3);
324 CBS_peek_u32(CBS
*cbs
, uint32_t *out
)
326 return cbs_peek_u(cbs
, out
, 4);
330 CBS_peek_last_u8(CBS
*cbs
, uint8_t *out
)
335 *out
= cbs
->data
[cbs
->len
- 1];
340 CBS_get_any_asn1_element(CBS
*cbs
, CBS
*out
, unsigned int *out_tag
,
341 size_t *out_header_len
)
343 return cbs_get_any_asn1_element_internal(cbs
, out
, out_tag
,
348 * Review X.690 for details on ASN.1 DER encoding.
350 * If non-strict mode is enabled, then DER rules are relaxed
351 * for indefinite constructs (violates DER but a little closer to BER).
352 * Non-strict mode should only be used by bs_ber.c
354 * Sections 8, 10 and 11 for DER encoding
357 cbs_get_any_asn1_element_internal(CBS
*cbs
, CBS
*out
, unsigned int *out_tag
,
358 size_t *out_header_len
, int strict
)
360 uint8_t tag
, length_byte
;
369 * Get identifier octet and length octet. Only 1 octet for each
370 * is a CBS limitation.
372 if (!CBS_get_u8(&header
, &tag
) || !CBS_get_u8(&header
, &length_byte
))
375 /* CBS limitation: long form tags are not supported. */
376 if ((tag
& 0x1f) == 0x1f)
382 if ((length_byte
& 0x80) == 0) {
383 /* Short form length. */
384 len
= ((size_t) length_byte
) + 2;
385 if (out_header_len
!= NULL
)
389 /* Long form length. */
390 const size_t num_bytes
= length_byte
& 0x7f;
393 /* ASN.1 reserved value for future extensions */
394 if (num_bytes
== 0x7f)
397 /* Handle indefinite form length */
398 if (num_bytes
== 0) {
399 /* DER encoding doesn't allow for indefinite form. */
403 /* Primitive cannot use indefinite in BER or DER. */
404 if ((tag
& CBS_ASN1_CONSTRUCTED
) == 0)
407 /* Constructed, indefinite length allowed in BER. */
408 if (out_header_len
!= NULL
)
410 return CBS_get_bytes(cbs
, out
, 2);
413 /* CBS limitation. */
417 if (!cbs_get_u(&header
, &len32
, num_bytes
))
420 /* DER has a minimum length octet requirement. */
422 /* Should have used short form instead */
425 if ((len32
>> ((num_bytes
- 1) * 8)) == 0)
426 /* Length should have been at least one byte shorter. */
430 if (len
+ 2 + num_bytes
< len
)
434 len
+= 2 + num_bytes
;
435 if (out_header_len
!= NULL
)
436 *out_header_len
= 2 + num_bytes
;
439 return CBS_get_bytes(cbs
, out
, len
);
443 cbs_get_asn1(CBS
*cbs
, CBS
*out
, unsigned int tag_value
, int skip_header
)
452 if (!CBS_get_any_asn1_element(cbs
, out
, &tag
, &header_len
) ||
456 if (skip_header
&& !CBS_skip(out
, header_len
))
463 CBS_get_asn1(CBS
*cbs
, CBS
*out
, unsigned int tag_value
)
465 return cbs_get_asn1(cbs
, out
, tag_value
, 1 /* skip header */);
469 CBS_get_asn1_element(CBS
*cbs
, CBS
*out
, unsigned int tag_value
)
471 return cbs_get_asn1(cbs
, out
, tag_value
, 0 /* include header */);
475 CBS_peek_asn1_tag(const CBS
*cbs
, unsigned int tag_value
)
477 if (CBS_len(cbs
) < 1)
481 * Tag number 31 indicates the start of a long form number.
482 * This is valid in ASN.1, but CBS only supports short form.
484 if ((tag_value
& 0x1f) == 0x1f)
487 return CBS_data(cbs
)[0] == tag_value
;
490 /* Encoding details are in ASN.1: X.690 section 8.3 */
492 CBS_get_asn1_uint64(CBS
*cbs
, uint64_t *out
)
498 if (!CBS_get_asn1(cbs
, &bytes
, CBS_ASN1_INTEGER
))
502 data
= CBS_data(&bytes
);
503 len
= CBS_len(&bytes
);
506 /* An INTEGER is encoded with at least one content octet. */
509 if ((data
[0] & 0x80) != 0)
510 /* Negative number. */
513 if (data
[0] == 0 && len
> 1 && (data
[1] & 0x80) == 0)
514 /* Violates smallest encoding rule: excessive leading zeros. */
517 for (i
= 0; i
< len
; i
++) {
518 if ((*out
>> 56) != 0)
519 /* Too large to represent as a uint64_t. */
530 CBS_get_optional_asn1(CBS
*cbs
, CBS
*out
, int *out_present
, unsigned int tag
)
532 if (CBS_peek_asn1_tag(cbs
, tag
)) {
533 if (!CBS_get_asn1(cbs
, out
, tag
))
544 CBS_get_optional_asn1_octet_string(CBS
*cbs
, CBS
*out
, int *out_present
,
550 if (!CBS_get_optional_asn1(cbs
, &child
, &present
, tag
))
554 if (!CBS_get_asn1(&child
, out
, CBS_ASN1_OCTETSTRING
) ||
555 CBS_len(&child
) != 0)
558 CBS_init(out
, NULL
, 0);
561 *out_present
= present
;
567 CBS_get_optional_asn1_uint64(CBS
*cbs
, uint64_t *out
, unsigned int tag
,
568 uint64_t default_value
)
573 if (!CBS_get_optional_asn1(cbs
, &child
, &present
, tag
))
577 if (!CBS_get_asn1_uint64(&child
, out
) ||
578 CBS_len(&child
) != 0)
581 *out
= default_value
;
587 CBS_get_optional_asn1_bool(CBS
*cbs
, int *out
, unsigned int tag
,
593 if (!CBS_get_optional_asn1(cbs
, &child
, &present
, tag
))
599 if (!CBS_get_asn1(&child
, &child2
, CBS_ASN1_BOOLEAN
) ||
600 CBS_len(&child2
) != 1 || CBS_len(&child
) != 0)
603 boolean
= CBS_data(&child2
)[0];
606 else if (boolean
== 0xff)
612 *out
= default_value
;