1 /* $OpenBSD: bs_cbs.c,v 1.17 2015/06/24 09:44:18 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 <openssl/opensslconf.h>
22 #include <openssl/buffer.h>
23 #include <openssl/crypto.h>
25 #include "bytestring.h"
28 CBS_init(CBS
*cbs
, const uint8_t *data
, size_t len
)
31 cbs
->initial_len
= len
;
36 CBS_dup(const CBS
*cbs
, CBS
*out
)
38 CBS_init(out
, CBS_data(cbs
), CBS_len(cbs
));
39 out
->initial_len
= cbs
->initial_len
;
43 cbs_get(CBS
*cbs
, const uint8_t **p
, size_t n
)
55 CBS_offset(const CBS
*cbs
)
57 return cbs
->initial_len
- cbs
->len
;
61 CBS_skip(CBS
*cbs
, size_t len
)
64 return cbs_get(cbs
, &dummy
, len
);
68 CBS_data(const CBS
*cbs
)
74 CBS_len(const CBS
*cbs
)
80 CBS_stow(const CBS
*cbs
, uint8_t **out_ptr
, size_t *out_len
)
89 if ((*out_ptr
= malloc(cbs
->len
)) == NULL
)
92 memcpy(*out_ptr
, cbs
->data
, cbs
->len
);
99 CBS_strdup(const CBS
*cbs
, char **out_ptr
)
102 *out_ptr
= strndup((const char *)cbs
->data
, cbs
->len
);
103 return (*out_ptr
!= NULL
);
107 CBS_write_bytes(const CBS
*cbs
, uint8_t *dst
, size_t dst_len
, size_t *copied
)
109 if (dst_len
< cbs
->len
)
112 memmove(dst
, cbs
->data
, cbs
->len
);
121 CBS_contains_zero_byte(const CBS
*cbs
)
123 return memchr(cbs
->data
, 0, cbs
->len
) != NULL
;
127 CBS_mem_equal(const CBS
*cbs
, const uint8_t *data
, size_t len
)
132 return timingsafe_memcmp(cbs
->data
, data
, len
) == 0;
136 cbs_get_u(CBS
*cbs
, uint32_t *out
, size_t len
)
142 if (len
< 1 || len
> 4)
145 if (!cbs_get(cbs
, &data
, len
))
148 for (i
= 0; i
< len
; i
++) {
157 CBS_get_u8(CBS
*cbs
, uint8_t *out
)
161 if (!cbs_get(cbs
, &v
, 1))
169 CBS_get_u16(CBS
*cbs
, uint16_t *out
)
173 if (!cbs_get_u(cbs
, &v
, 2))
181 CBS_get_u24(CBS
*cbs
, uint32_t *out
)
183 return cbs_get_u(cbs
, out
, 3);
187 CBS_get_u32(CBS
*cbs
, uint32_t *out
)
189 return cbs_get_u(cbs
, out
, 4);
193 CBS_get_bytes(CBS
*cbs
, CBS
*out
, size_t len
)
197 if (!cbs_get(cbs
, &v
, len
))
200 CBS_init(out
, v
, len
);
205 cbs_get_length_prefixed(CBS
*cbs
, CBS
*out
, size_t len_len
)
209 if (!cbs_get_u(cbs
, &len
, len_len
))
212 return CBS_get_bytes(cbs
, out
, len
);
216 CBS_get_u8_length_prefixed(CBS
*cbs
, CBS
*out
)
218 return cbs_get_length_prefixed(cbs
, out
, 1);
222 CBS_get_u16_length_prefixed(CBS
*cbs
, CBS
*out
)
224 return cbs_get_length_prefixed(cbs
, out
, 2);
228 CBS_get_u24_length_prefixed(CBS
*cbs
, CBS
*out
)
230 return cbs_get_length_prefixed(cbs
, out
, 3);
234 CBS_get_any_asn1_element(CBS
*cbs
, CBS
*out
, unsigned int *out_tag
,
235 size_t *out_header_len
)
237 return cbs_get_any_asn1_element_internal(cbs
, out
, out_tag
,
242 * Review X.690 for details on ASN.1 DER encoding.
244 * If non-strict mode is enabled, then DER rules are relaxed
245 * for indefinite constructs (violates DER but a little closer to BER).
246 * Non-strict mode should only be used by bs_ber.c
248 * Sections 8, 10 and 11 for DER encoding
251 cbs_get_any_asn1_element_internal(CBS
*cbs
, CBS
*out
, unsigned int *out_tag
,
252 size_t *out_header_len
, int strict
)
254 uint8_t tag
, length_byte
;
263 * Get identifier octet and length octet. Only 1 octet for each
264 * is a CBS limitation.
266 if (!CBS_get_u8(&header
, &tag
) || !CBS_get_u8(&header
, &length_byte
))
269 /* CBS limitation: long form tags are not supported. */
270 if ((tag
& 0x1f) == 0x1f)
276 if ((length_byte
& 0x80) == 0) {
277 /* Short form length. */
278 len
= ((size_t) length_byte
) + 2;
279 if (out_header_len
!= NULL
)
283 /* Long form length. */
284 const size_t num_bytes
= length_byte
& 0x7f;
287 /* ASN.1 reserved value for future extensions */
288 if (num_bytes
== 0x7f)
291 /* Handle indefinite form length */
292 if (num_bytes
== 0) {
293 /* DER encoding doesn't allow for indefinite form. */
297 /* Primitive cannot use indefinite in BER or DER. */
298 if ((tag
& CBS_ASN1_CONSTRUCTED
) == 0)
301 /* Constructed, indefinite length allowed in BER. */
302 if (out_header_len
!= NULL
)
304 return CBS_get_bytes(cbs
, out
, 2);
307 /* CBS limitation. */
311 if (!cbs_get_u(&header
, &len32
, num_bytes
))
314 /* DER has a minimum length octet requirement. */
316 /* Should have used short form instead */
319 if ((len32
>> ((num_bytes
- 1) * 8)) == 0)
320 /* Length should have been at least one byte shorter. */
324 if (len
+ 2 + num_bytes
< len
)
328 len
+= 2 + num_bytes
;
329 if (out_header_len
!= NULL
)
330 *out_header_len
= 2 + num_bytes
;
333 return CBS_get_bytes(cbs
, out
, len
);
337 cbs_get_asn1(CBS
*cbs
, CBS
*out
, unsigned int tag_value
, int skip_header
)
346 if (!CBS_get_any_asn1_element(cbs
, out
, &tag
, &header_len
) ||
350 if (skip_header
&& !CBS_skip(out
, header_len
)) {
359 CBS_get_asn1(CBS
*cbs
, CBS
*out
, unsigned int tag_value
)
361 return cbs_get_asn1(cbs
, out
, tag_value
, 1 /* skip header */);
365 CBS_get_asn1_element(CBS
*cbs
, CBS
*out
, unsigned int tag_value
)
367 return cbs_get_asn1(cbs
, out
, tag_value
, 0 /* include header */);
371 CBS_peek_asn1_tag(const CBS
*cbs
, unsigned int tag_value
)
373 if (CBS_len(cbs
) < 1)
377 * Tag number 31 indicates the start of a long form number.
378 * This is valid in ASN.1, but CBS only supports short form.
380 if ((tag_value
& 0x1f) == 0x1f)
383 return CBS_data(cbs
)[0] == tag_value
;
386 /* Encoding details are in ASN.1: X.690 section 8.3 */
388 CBS_get_asn1_uint64(CBS
*cbs
, uint64_t *out
)
394 if (!CBS_get_asn1(cbs
, &bytes
, CBS_ASN1_INTEGER
))
398 data
= CBS_data(&bytes
);
399 len
= CBS_len(&bytes
);
402 /* An INTEGER is encoded with at least one content octet. */
405 if ((data
[0] & 0x80) != 0)
406 /* Negative number. */
409 if (data
[0] == 0 && len
> 1 && (data
[1] & 0x80) == 0)
410 /* Violates smallest encoding rule: excessive leading zeros. */
413 for (i
= 0; i
< len
; i
++) {
414 if ((*out
>> 56) != 0)
415 /* Too large to represent as a uint64_t. */
426 CBS_get_optional_asn1(CBS
*cbs
, CBS
*out
, int *out_present
, unsigned int tag
)
428 if (CBS_peek_asn1_tag(cbs
, tag
)) {
429 if (!CBS_get_asn1(cbs
, out
, tag
))
440 CBS_get_optional_asn1_octet_string(CBS
*cbs
, CBS
*out
, int *out_present
,
446 if (!CBS_get_optional_asn1(cbs
, &child
, &present
, tag
))
450 if (!CBS_get_asn1(&child
, out
, CBS_ASN1_OCTETSTRING
) ||
451 CBS_len(&child
) != 0)
454 CBS_init(out
, NULL
, 0);
457 *out_present
= present
;
463 CBS_get_optional_asn1_uint64(CBS
*cbs
, uint64_t *out
, unsigned int tag
,
464 uint64_t default_value
)
469 if (!CBS_get_optional_asn1(cbs
, &child
, &present
, tag
))
473 if (!CBS_get_asn1_uint64(&child
, out
) ||
474 CBS_len(&child
) != 0)
477 *out
= default_value
;
483 CBS_get_optional_asn1_bool(CBS
*cbs
, int *out
, unsigned int tag
,
489 if (!CBS_get_optional_asn1(cbs
, &child
, &present
, tag
))
495 if (!CBS_get_asn1(&child
, &child2
, CBS_ASN1_BOOLEAN
) ||
496 CBS_len(&child2
) != 1 || CBS_len(&child
) != 0)
499 boolean
= CBS_data(&child2
)[0];
502 else if (boolean
== 0xff)
508 *out
= default_value
;