diff options
author | Doug Hogan <doug@cvs.openbsd.org> | 2015-02-06 22:22:34 +0000 |
---|---|---|
committer | Doug Hogan <doug@cvs.openbsd.org> | 2015-02-06 22:22:34 +0000 |
commit | eafa184821fe3510e27a19823e5bda82e875a248 (patch) | |
tree | 597cbe8c90938bfdc16204d5c32ff7f2dd0fca89 | |
parent | 211f53371300f03d981cb9a7842ecc35a0984d1c (diff) |
KNF bytestring files.
I checked that this doesn't change anything. Compiled with clang using
-Wno-pointer-sign -g0 to reduce the differences. Only difference in the
asm is due to assert(0) line number changes in bs_cbs.c and bs_cbb.c.
miod is ok with the general process.
-rw-r--r-- | lib/libssl/src/ssl/bs_ber.c | 390 | ||||
-rw-r--r-- | lib/libssl/src/ssl/bs_cbb.c | 611 | ||||
-rw-r--r-- | lib/libssl/src/ssl/bs_cbs.c | 663 | ||||
-rw-r--r-- | lib/libssl/src/ssl/bytestring.h | 340 | ||||
-rw-r--r-- | regress/lib/libssl/bytestring/bytestringtest.c | 1178 |
5 files changed, 1692 insertions, 1490 deletions
diff --git a/lib/libssl/src/ssl/bs_ber.c b/lib/libssl/src/ssl/bs_ber.c index b94b63e37e5..cfc9475f9a2 100644 --- a/lib/libssl/src/ssl/bs_ber.c +++ b/lib/libssl/src/ssl/bs_ber.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bs_ber.c,v 1.1 2015/02/06 09:36:16 doug Exp $ */ +/* $OpenBSD: bs_ber.c,v 1.2 2015/02/06 22:22:33 doug Exp $ */ /* * Copyright (c) 2014, Google Inc. * @@ -20,201 +20,233 @@ #include "bytestring.h" -/* kMaxDepth is a just a sanity limit. The code should be such that the length +/* + * kMaxDepth is a just a sanity limit. The code should be such that the length * of the input being processes always decreases. None the less, a very large - * input could otherwise cause the stack to overflow. */ + * input could otherwise cause the stack to overflow. + */ static const unsigned kMaxDepth = 2048; -/* cbs_find_ber walks an ASN.1 structure in |orig_in| and sets |*ber_found| +/* + * cbs_find_ber walks an ASN.1 structure in |orig_in| and sets |*ber_found| * depending on whether an indefinite length element was found. The value of * |in| is not changed. It returns one on success (i.e. |*ber_found| was set) - * and zero on error. */ -static int cbs_find_ber(CBS *orig_in, char *ber_found, unsigned depth) { - CBS in; - - if (depth > kMaxDepth) { - return 0; - } - - CBS_init(&in, CBS_data(orig_in), CBS_len(orig_in)); - *ber_found = 0; - - while (CBS_len(&in) > 0) { - CBS contents; - unsigned tag; - size_t header_len; - - if (!CBS_get_any_asn1_element(&in, &contents, &tag, &header_len)) { - return 0; - } - if (CBS_len(&contents) == header_len && - header_len > 0 && - CBS_data(&contents)[header_len-1] == 0x80) { - *ber_found = 1; - return 1; - } - if (tag & CBS_ASN1_CONSTRUCTED) { - if (!CBS_skip(&contents, header_len) || - !cbs_find_ber(&contents, ber_found, depth + 1)) { - return 0; - } - } - } - - return 1; + * and zero on error. + */ +static int +cbs_find_ber(CBS *orig_in, char *ber_found, unsigned depth) +{ + CBS in; + + if (depth > kMaxDepth) + return 0; + + CBS_init(&in, CBS_data(orig_in), CBS_len(orig_in)); + *ber_found = 0; + + while (CBS_len(&in) > 0) { + CBS contents; + unsigned tag; + size_t header_len; + + if (!CBS_get_any_asn1_element(&in, &contents, &tag, + &header_len)) + return 0; + + if (CBS_len(&contents) == header_len && header_len > 0 && + CBS_data(&contents)[header_len-1] == 0x80) { + *ber_found = 1; + return 1; + } + if (tag & CBS_ASN1_CONSTRUCTED) { + if (!CBS_skip(&contents, header_len) || + !cbs_find_ber(&contents, ber_found, depth + 1)) + return 0; + } + } + + return 1; } -/* is_primitive_type returns true if |tag| likely a primitive type. Normally +/* + * is_primitive_type returns true if |tag| likely a primitive type. Normally * one can just test the "constructed" bit in the tag but, in BER, even * primitive tags can have the constructed bit if they have indefinite - * length. */ -static char is_primitive_type(unsigned tag) { - return (tag & 0xc0) == 0 && - (tag & 0x1f) != (CBS_ASN1_SEQUENCE & 0x1f) && - (tag & 0x1f) != (CBS_ASN1_SET & 0x1f); + * length. + */ +static char +is_primitive_type(unsigned tag) +{ + return (tag & 0xc0) == 0 && + (tag & 0x1f) != (CBS_ASN1_SEQUENCE & 0x1f) && + (tag & 0x1f) != (CBS_ASN1_SET & 0x1f); } -/* is_eoc returns true if |header_len| and |contents|, as returned by - * |CBS_get_any_asn1_element|, indicate an "end of contents" (EOC) value. */ -static char is_eoc(size_t header_len, CBS *contents) { - return header_len == 2 && CBS_len(contents) == 2 && - memcmp(CBS_data(contents), "\x00\x00", 2) == 0; +/* + * is_eoc returns true if |header_len| and |contents|, as returned by + * |CBS_get_any_asn1_element|, indicate an "end of contents" (EOC) value. + */ +static char +is_eoc(size_t header_len, CBS *contents) +{ + return header_len == 2 && CBS_len(contents) == 2 && + memcmp(CBS_data(contents), "\x00\x00", 2) == 0; } -/* cbs_convert_ber reads BER data from |in| and writes DER data to |out|. If +/* + * cbs_convert_ber reads BER data from |in| and writes DER data to |out|. If * |squash_header| is set then the top-level of elements from |in| will not * have their headers written. This is used when concatenating the fragments of * an indefinite length, primitive value. If |looking_for_eoc| is set then any * EOC elements found will cause the function to return after consuming it. - * It returns one on success and zero on error. */ -static int cbs_convert_ber(CBS *in, CBB *out, char squash_header, - char looking_for_eoc, unsigned depth) { - if (depth > kMaxDepth) { - return 0; - } - - while (CBS_len(in) > 0) { - CBS contents; - unsigned tag; - size_t header_len; - CBB *out_contents, out_contents_storage; - - if (!CBS_get_any_asn1_element(in, &contents, &tag, &header_len)) { - return 0; - } - out_contents = out; - - if (CBS_len(&contents) == header_len) { - if (is_eoc(header_len, &contents)) { - return looking_for_eoc; - } - - if (header_len > 0 && CBS_data(&contents)[header_len - 1] == 0x80) { - /* This is an indefinite length element. If it's a SEQUENCE or SET then - * we just need to write the out the contents as normal, but with a - * concrete length prefix. - * - * If it's a something else then the contents will be a series of BER - * elements of the same type which need to be concatenated. */ - const char context_specific = (tag & 0xc0) == 0x80; - char squash_child_headers = is_primitive_type(tag); - - /* This is a hack, but it sufficies to handle NSS's output. If we find - * an indefinite length, context-specific tag with a definite, primtive - * tag inside it, then we assume that the context-specific tag is - * implicit and the tags within are fragments of a primitive type that - * need to be concatenated. */ - if (context_specific && (tag & CBS_ASN1_CONSTRUCTED)) { - CBS in_copy, inner_contents; - unsigned inner_tag; - size_t inner_header_len; - - CBS_init(&in_copy, CBS_data(in), CBS_len(in)); - if (!CBS_get_any_asn1_element(&in_copy, &inner_contents, &inner_tag, - &inner_header_len)) { - return 0; - } - if (CBS_len(&inner_contents) > inner_header_len && - is_primitive_type(inner_tag)) { - squash_child_headers = 1; - } - } - - if (!squash_header) { - unsigned out_tag = tag; - if (squash_child_headers) { - out_tag &= ~CBS_ASN1_CONSTRUCTED; - } - if (!CBB_add_asn1(out, &out_contents_storage, out_tag)) { - return 0; - } - out_contents = &out_contents_storage; - } - - if (!cbs_convert_ber(in, out_contents, - squash_child_headers, - 1 /* looking for eoc */, depth + 1)) { - return 0; - } - if (out_contents != out && !CBB_flush(out)) { - return 0; - } - continue; - } - } - - if (!squash_header) { - if (!CBB_add_asn1(out, &out_contents_storage, tag)) { - return 0; - } - out_contents = &out_contents_storage; - } - - if (!CBS_skip(&contents, header_len)) { - return 0; - } - - if (tag & CBS_ASN1_CONSTRUCTED) { - if (!cbs_convert_ber(&contents, out_contents, 0 /* don't squash header */, - 0 /* not looking for eoc */, depth + 1)) { - return 0; - } - } else { - if (!CBB_add_bytes(out_contents, CBS_data(&contents), - CBS_len(&contents))) { - return 0; - } - } - - if (out_contents != out && !CBB_flush(out)) { - return 0; - } - } - - return looking_for_eoc == 0; + * It returns one on success and zero on error. + */ +static int +cbs_convert_ber(CBS *in, CBB *out, char squash_header, char looking_for_eoc, + unsigned depth) +{ + if (depth > kMaxDepth) + return 0; + + while (CBS_len(in) > 0) { + CBS contents; + unsigned tag; + size_t header_len; + CBB *out_contents, out_contents_storage; + + if (!CBS_get_any_asn1_element(in, &contents, &tag, &header_len)) + return 0; + + out_contents = out; + + if (CBS_len(&contents) == header_len) { + if (is_eoc(header_len, &contents)) + return looking_for_eoc; + + if (header_len > 0 && + CBS_data(&contents)[header_len - 1] == 0x80) { + /* + * This is an indefinite length element. If + * it's a SEQUENCE or SET then we just need to + * write the out the contents as normal, but + * with a concrete length prefix. + * + * If it's a something else then the contents + * will be a series of BER elements of the same + * type which need to be concatenated. + */ + const char context_specific = (tag & 0xc0) + == 0x80; + char squash_child_headers = + is_primitive_type(tag); + + /* + * This is a hack, but it sufficies to handle + * NSS's output. If we find an indefinite + * length, context-specific tag with a definite, + * primtive tag inside it, then we assume that + * the context-specific tag is implicit and the + * tags within are fragments of a primitive type + * that need to be concatenated. + */ + if (context_specific && + (tag & CBS_ASN1_CONSTRUCTED)) { + CBS in_copy, inner_contents; + unsigned inner_tag; + size_t inner_header_len; + + CBS_init(&in_copy, CBS_data(in), + CBS_len(in)); + if (!CBS_get_any_asn1_element(&in_copy, + &inner_contents, &inner_tag, + &inner_header_len)) + return 0; + + if (CBS_len(&inner_contents) > + inner_header_len && + is_primitive_type(inner_tag)) + squash_child_headers = 1; + } + + if (!squash_header) { + unsigned out_tag = tag; + + if (squash_child_headers) + out_tag &= + ~CBS_ASN1_CONSTRUCTED; + + if (!CBB_add_asn1(out, + &out_contents_storage, out_tag)) + return 0; + + out_contents = &out_contents_storage; + } + + if (!cbs_convert_ber(in, out_contents, + squash_child_headers, + 1 /* looking for eoc */, depth + 1)) + return 0; + + if (out_contents != out && !CBB_flush(out)) + return 0; + + continue; + } + } + + if (!squash_header) { + if (!CBB_add_asn1(out, &out_contents_storage, tag)) + return 0; + + out_contents = &out_contents_storage; + } + + if (!CBS_skip(&contents, header_len)) + return 0; + + if (tag & CBS_ASN1_CONSTRUCTED) { + if (!cbs_convert_ber(&contents, out_contents, + 0 /* don't squash header */, + 0 /* not looking for eoc */, depth + 1)) + return 0; + } else { + if (!CBB_add_bytes(out_contents, CBS_data(&contents), + CBS_len(&contents))) + return 0; + } + + if (out_contents != out && !CBB_flush(out)) + return 0; + } + + return looking_for_eoc == 0; } -int CBS_asn1_ber_to_der(CBS *in, uint8_t **out, size_t *out_len) { - CBB cbb; - - /* First, do a quick walk to find any indefinite-length elements. Most of the - * time we hope that there aren't any and thus we can quickly return. */ - char conversion_needed; - if (!cbs_find_ber(in, &conversion_needed, 0)) { - return 0; - } - - if (!conversion_needed) { - *out = NULL; - *out_len = 0; - return 1; - } - - CBB_init(&cbb, CBS_len(in)); - if (!cbs_convert_ber(in, &cbb, 0, 0, 0)) { - CBB_cleanup(&cbb); - return 0; - } - - return CBB_finish(&cbb, out, out_len); +int +CBS_asn1_ber_to_der(CBS *in, uint8_t **out, size_t *out_len) +{ + CBB cbb; + + /* + * First, do a quick walk to find any indefinite-length elements. Most + * of the time we hope that there aren't any and thus we can quickly + * return. + */ + char conversion_needed; + if (!cbs_find_ber(in, &conversion_needed, 0)) + return 0; + + if (!conversion_needed) { + *out = NULL; + *out_len = 0; + return 1; + } + + CBB_init(&cbb, CBS_len(in)); + if (!cbs_convert_ber(in, &cbb, 0, 0, 0)) { + CBB_cleanup(&cbb); + return 0; + } + + return CBB_finish(&cbb, out, out_len); } diff --git a/lib/libssl/src/ssl/bs_cbb.c b/lib/libssl/src/ssl/bs_cbb.c index 11688bcb7bb..94ca54f43b7 100644 --- a/lib/libssl/src/ssl/bs_cbb.c +++ b/lib/libssl/src/ssl/bs_cbb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bs_cbb.c,v 1.2 2015/02/06 10:06:30 doug Exp $ */ +/* $OpenBSD: bs_cbb.c,v 1.3 2015/02/06 22:22:33 doug Exp $ */ /* * Copyright (c) 2014, Google Inc. * @@ -22,356 +22,365 @@ #include "bytestring.h" -static int cbb_init(CBB *cbb, uint8_t *buf, size_t cap) { - struct cbb_buffer_st *base; +static int +cbb_init(CBB *cbb, uint8_t *buf, size_t cap) +{ + struct cbb_buffer_st *base; + + base = malloc(sizeof(struct cbb_buffer_st)); + if (base == NULL) { + free(buf); + return 0; + } + + base->buf = buf; + base->len = 0; + base->cap = cap; + base->can_resize = 1; + + memset(cbb, 0, sizeof(CBB)); + cbb->base = base; + cbb->is_top_level = 1; + return 1; +} - base = malloc(sizeof(struct cbb_buffer_st)); - if (base == NULL) { - free(buf); - return 0; - } +int +CBB_init(CBB *cbb, size_t initial_capacity) +{ + uint8_t *buf; - base->buf = buf; - base->len = 0; - base->cap = cap; - base->can_resize = 1; + buf = malloc(initial_capacity); + if (initial_capacity > 0 && buf == NULL) + return 0; - memset(cbb, 0, sizeof(CBB)); - cbb->base = base; - cbb->is_top_level = 1; - return 1; + return cbb_init(cbb, buf, initial_capacity); } -int CBB_init(CBB *cbb, size_t initial_capacity) { - uint8_t *buf; - - buf = malloc(initial_capacity); - if (initial_capacity > 0 && buf == NULL) { - return 0; - } +int +CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len) +{ + if (!cbb_init(cbb, buf, len)) + return 0; - return cbb_init(cbb, buf, initial_capacity); + cbb->base->can_resize = 0; + return 1; } -int CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len) { - if (!cbb_init(cbb, buf, len)) { - return 0; - } +void +CBB_cleanup(CBB *cbb) +{ + if (cbb->base) { + if (cbb->base->buf && cbb->base->can_resize) + free(cbb->base->buf); - cbb->base->can_resize = 0; - return 1; + free(cbb->base); + } + cbb->base = NULL; } -void CBB_cleanup(CBB *cbb) { - if (cbb->base) { - if (cbb->base->buf && cbb->base->can_resize) { - free(cbb->base->buf); - } - free(cbb->base); - } - cbb->base = NULL; -} +static int +cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out, size_t len) +{ + size_t newlen; + + if (base == NULL) + return 0; + + newlen = base->len + len; + if (newlen < base->len) + /* Overflow */ + return 0; + + if (newlen > base->cap) { + size_t newcap = base->cap * 2; + uint8_t *newbuf; + + if (!base->can_resize) + return 0; + + if (newcap < base->cap || newcap < newlen) + newcap = newlen; + + newbuf = realloc(base->buf, newcap); + if (newbuf == NULL) + return 0; + + base->buf = newbuf; + base->cap = newcap; + } + + if (out) + *out = base->buf + base->len; -static int cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out, - size_t len) { - size_t newlen; - - if (base == NULL) { - return 0; - } - - newlen = base->len + len; - if (newlen < base->len) { - /* Overflow */ - return 0; - } - - if (newlen > base->cap) { - size_t newcap = base->cap * 2; - uint8_t *newbuf; - - if (!base->can_resize) { - return 0; - } - - if (newcap < base->cap || newcap < newlen) { - newcap = newlen; - } - newbuf = realloc(base->buf, newcap); - if (newbuf == NULL) { - return 0; - } - - base->buf = newbuf; - base->cap = newcap; - } - - if (out) { - *out = base->buf + base->len; - } - base->len = newlen; - return 1; + base->len = newlen; + return 1; } -static int cbb_buffer_add_u(struct cbb_buffer_st *base, uint32_t v, - size_t len_len) { - uint8_t *buf; - size_t i; - - if (len_len == 0) { - return 1; - } - if (!cbb_buffer_add(base, &buf, len_len)) { - return 0; - } - - for (i = len_len - 1; i < len_len; i--) { - buf[i] = v; - v >>= 8; - } - return 1; +static int +cbb_buffer_add_u(struct cbb_buffer_st *base, uint32_t v, size_t len_len) +{ + uint8_t *buf; + size_t i; + + if (len_len == 0) + return 1; + + if (!cbb_buffer_add(base, &buf, len_len)) + return 0; + + for (i = len_len - 1; i < len_len; i--) { + buf[i] = v; + v >>= 8; + } + return 1; } -int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len) { - if (!cbb->is_top_level) { - return 0; - } - - if (!CBB_flush(cbb)) { - return 0; - } - - if (cbb->base->can_resize && (out_data == NULL || out_len == NULL)) { - /* |out_data| and |out_len| can only be NULL if the CBB is fixed. */ - return 0; - } - - if (out_data != NULL) { - *out_data = cbb->base->buf; - } - if (out_len != NULL) { - *out_len = cbb->base->len; - } - cbb->base->buf = NULL; - CBB_cleanup(cbb); - return 1; +int +CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len) +{ + if (!cbb->is_top_level) + return 0; + + if (!CBB_flush(cbb)) + return 0; + + if (cbb->base->can_resize && (out_data == NULL || out_len == NULL)) + /* |out_data| and |out_len| can only be NULL if the CBB is fixed. */ + return 0; + + if (out_data != NULL) + *out_data = cbb->base->buf; + + if (out_len != NULL) + *out_len = cbb->base->len; + + cbb->base->buf = NULL; + CBB_cleanup(cbb); + return 1; } -/* CBB_flush recurses and then writes out any pending length prefix. The - * current length of the underlying base is taken to be the length of the - * length-prefixed data. */ -int CBB_flush(CBB *cbb) { - size_t child_start, i, len; - - if (cbb->base == NULL) { - return 0; - } - - if (cbb->child == NULL || cbb->pending_len_len == 0) { - return 1; - } - - child_start = cbb->offset + cbb->pending_len_len; - - if (!CBB_flush(cbb->child) || - child_start < cbb->offset || - cbb->base->len < child_start) { - return 0; - } - - len = cbb->base->len - child_start; - - if (cbb->pending_is_asn1) { - /* For ASN.1 we assume that we'll only need a single byte for the length. - * If that turned out to be incorrect, we have to move the contents along - * in order to make space. */ - size_t len_len; - uint8_t initial_length_byte; - - assert (cbb->pending_len_len == 1); - - if (len > 0xfffffffe) { - /* Too large. */ - return 0; - } else if (len > 0xffffff) { - len_len = 5; - initial_length_byte = 0x80 | 4; - } else if (len > 0xffff) { - len_len = 4; - initial_length_byte = 0x80 | 3; - } else if (len > 0xff) { - len_len = 3; - initial_length_byte = 0x80 | 2; - } else if (len > 0x7f) { - len_len = 2; - initial_length_byte = 0x80 | 1; - } else { - len_len = 1; - initial_length_byte = len; - len = 0; - } - - if (len_len != 1) { - /* We need to move the contents along in order to make space. */ - size_t extra_bytes = len_len - 1; - if (!cbb_buffer_add(cbb->base, NULL, extra_bytes)) { - return 0; - } - memmove(cbb->base->buf + child_start + extra_bytes, - cbb->base->buf + child_start, len); - } - cbb->base->buf[cbb->offset++] = initial_length_byte; - cbb->pending_len_len = len_len - 1; - } - - for (i = cbb->pending_len_len - 1; i < cbb->pending_len_len; i--) { - cbb->base->buf[cbb->offset + i] = len; - len >>= 8; - } - if (len != 0) { - return 0; - } - - cbb->child->base = NULL; - cbb->child = NULL; - cbb->pending_len_len = 0; - cbb->pending_is_asn1 = 0; - cbb->offset = 0; - - return 1; +/* + * CBB_flush recurses and then writes out any pending length prefix. The current + * length of the underlying base is taken to be the length of the + * length-prefixed data. + */ +int +CBB_flush(CBB *cbb) +{ + size_t child_start, i, len; + + if (cbb->base == NULL) + return 0; + + if (cbb->child == NULL || cbb->pending_len_len == 0) + return 1; + + child_start = cbb->offset + cbb->pending_len_len; + + if (!CBB_flush(cbb->child) || child_start < cbb->offset || + cbb->base->len < child_start) + return 0; + + len = cbb->base->len - child_start; + + if (cbb->pending_is_asn1) { + /* For ASN.1 we assume that we'll only need a single byte for the length. + * If that turned out to be incorrect, we have to move the contents along + * in order to make space. */ + size_t len_len; + uint8_t initial_length_byte; + + assert (cbb->pending_len_len == 1); + + if (len > 0xfffffffe) { + /* Too large. */ + return 0; + } else if (len > 0xffffff) { + len_len = 5; + initial_length_byte = 0x80 | 4; + } else if (len > 0xffff) { + len_len = 4; + initial_length_byte = 0x80 | 3; + } else if (len > 0xff) { + len_len = 3; + initial_length_byte = 0x80 | 2; + } else if (len > 0x7f) { + len_len = 2; + initial_length_byte = 0x80 | 1; + } else { + len_len = 1; + initial_length_byte = len; + len = 0; + } + + if (len_len != 1) { + /* We need to move the contents along in order to make space. */ + size_t extra_bytes = len_len - 1; + if (!cbb_buffer_add(cbb->base, NULL, extra_bytes)) + return 0; + + memmove(cbb->base->buf + child_start + extra_bytes, + cbb->base->buf + child_start, len); + } + cbb->base->buf[cbb->offset++] = initial_length_byte; + cbb->pending_len_len = len_len - 1; + } + + for (i = cbb->pending_len_len - 1; i < cbb->pending_len_len; i--) { + cbb->base->buf[cbb->offset + i] = len; + len >>= 8; + } + if (len != 0) + return 0; + + cbb->child->base = NULL; + cbb->child = NULL; + cbb->pending_len_len = 0; + cbb->pending_is_asn1 = 0; + cbb->offset = 0; + + return 1; } -static int cbb_add_length_prefixed(CBB *cbb, CBB *out_contents, - size_t len_len) { - uint8_t *prefix_bytes; +static int +cbb_add_length_prefixed(CBB *cbb, CBB *out_contents, size_t len_len) +{ + uint8_t *prefix_bytes; - if (!CBB_flush(cbb)) { - return 0; - } + if (!CBB_flush(cbb)) + return 0; - cbb->offset = cbb->base->len; - if (!cbb_buffer_add(cbb->base, &prefix_bytes, len_len)) { - return 0; - } + cbb->offset = cbb->base->len; + if (!cbb_buffer_add(cbb->base, &prefix_bytes, len_len)) + return 0; - memset(prefix_bytes, 0, len_len); - memset(out_contents, 0, sizeof(CBB)); - out_contents->base = cbb->base; - cbb->child = out_contents; - cbb->pending_len_len = len_len; - cbb->pending_is_asn1 = 0; + memset(prefix_bytes, 0, len_len); + memset(out_contents, 0, sizeof(CBB)); + out_contents->base = cbb->base; + cbb->child = out_contents; + cbb->pending_len_len = len_len; + cbb->pending_is_asn1 = 0; - return 1; + return 1; } -int CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents) { - return cbb_add_length_prefixed(cbb, out_contents, 1); +int +CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents) +{ + return cbb_add_length_prefixed(cbb, out_contents, 1); } -int CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents) { - return cbb_add_length_prefixed(cbb, out_contents, 2); +int +CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents) +{ + return cbb_add_length_prefixed(cbb, out_contents, 2); } -int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) { - return cbb_add_length_prefixed(cbb, out_contents, 3); +int +CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) +{ + return cbb_add_length_prefixed(cbb, out_contents, 3); } -int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag) { - if (!CBB_flush(cbb) || - !CBB_add_u8(cbb, tag)) { - return 0; - } +int +CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag) +{ + if (!CBB_flush(cbb) || !CBB_add_u8(cbb, tag)) + return 0; - cbb->offset = cbb->base->len; - if (!CBB_add_u8(cbb, 0)) { - return 0; - } + cbb->offset = cbb->base->len; + if (!CBB_add_u8(cbb, 0)) + return 0; - memset(out_contents, 0, sizeof(CBB)); - out_contents->base = cbb->base; - cbb->child = out_contents; - cbb->pending_len_len = 1; - cbb->pending_is_asn1 = 1; + memset(out_contents, 0, sizeof(CBB)); + out_contents->base = cbb->base; + cbb->child = out_contents; + cbb->pending_len_len = 1; + cbb->pending_is_asn1 = 1; - return 1; + return 1; } -int CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len) { - uint8_t *dest; +int +CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len) +{ + uint8_t *dest; - if (!CBB_flush(cbb) || - !cbb_buffer_add(cbb->base, &dest, len)) { - return 0; - } - memcpy(dest, data, len); - return 1; + if (!CBB_flush(cbb) || !cbb_buffer_add(cbb->base, &dest, len)) + return 0; + + memcpy(dest, data, len); + return 1; } -int CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len) { - if (!CBB_flush(cbb) || - !cbb_buffer_add(cbb->base, out_data, len)) { - return 0; - } - return 1; +int +CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len) +{ + if (!CBB_flush(cbb) || !cbb_buffer_add(cbb->base, out_data, len)) + return 0; + + return 1; } -int CBB_add_u8(CBB *cbb, uint8_t value) { - if (!CBB_flush(cbb)) { - return 0; - } +int +CBB_add_u8(CBB *cbb, uint8_t value) +{ + if (!CBB_flush(cbb)) + return 0; - return cbb_buffer_add_u(cbb->base, value, 1); + return cbb_buffer_add_u(cbb->base, value, 1); } -int CBB_add_u16(CBB *cbb, uint16_t value) { - if (!CBB_flush(cbb)) { - return 0; - } +int +CBB_add_u16(CBB *cbb, uint16_t value) +{ + if (!CBB_flush(cbb)) + return 0; - return cbb_buffer_add_u(cbb->base, value, 2); + return cbb_buffer_add_u(cbb->base, value, 2); } -int CBB_add_u24(CBB *cbb, uint32_t value) { - if (!CBB_flush(cbb)) { - return 0; - } +int +CBB_add_u24(CBB *cbb, uint32_t value) +{ + if (!CBB_flush(cbb)) + return 0; - return cbb_buffer_add_u(cbb->base, value, 3); + return cbb_buffer_add_u(cbb->base, value, 3); } -int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) { - CBB child; - size_t i; - int started = 0; - - if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER)) { - return 0; - } - - for (i = 0; i < 8; i++) { - uint8_t byte = (value >> 8*(7-i)) & 0xff; - if (!started) { - if (byte == 0) { - /* Don't encode leading zeros. */ - continue; - } - /* If the high bit is set, add a padding byte to make it - * unsigned. */ - if ((byte & 0x80) && !CBB_add_u8(&child, 0)) { - return 0; - } - started = 1; - } - if (!CBB_add_u8(&child, byte)) { - return 0; - } - } - - /* 0 is encoded as a single 0, not the empty string. */ - if (!started && !CBB_add_u8(&child, 0)) { - return 0; - } - - return CBB_flush(cbb); +int +CBB_add_asn1_uint64(CBB *cbb, uint64_t value) +{ + CBB child; + size_t i; + int started = 0; + + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER)) + return 0; + + for (i = 0; i < 8; i++) { + uint8_t byte = (value >> 8*(7-i)) & 0xff; + if (!started) { + if (byte == 0) + /* Don't encode leading zeros. */ + continue; + + /* If the high bit is set, add a padding byte to make it + * unsigned. */ + if ((byte & 0x80) && !CBB_add_u8(&child, 0)) + return 0; + + started = 1; + } + if (!CBB_add_u8(&child, byte)) + return 0; + } + + /* 0 is encoded as a single 0, not the empty string. */ + if (!started && !CBB_add_u8(&child, 0)) + return 0; + + return CBB_flush(cbb); } diff --git a/lib/libssl/src/ssl/bs_cbs.c b/lib/libssl/src/ssl/bs_cbs.c index 7edfe652885..c3d3a8abf2a 100644 --- a/lib/libssl/src/ssl/bs_cbs.c +++ b/lib/libssl/src/ssl/bs_cbs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bs_cbs.c,v 1.1 2015/02/06 09:36:16 doug Exp $ */ +/* $OpenBSD: bs_cbs.c,v 1.2 2015/02/06 22:22:33 doug Exp $ */ /* * Copyright (c) 2014, Google Inc. * @@ -24,367 +24,416 @@ #include "bytestring.h" -void CBS_init(CBS *cbs, const uint8_t *data, size_t len) { - cbs->data = data; - cbs->len = len; +void +CBS_init(CBS *cbs, const uint8_t *data, size_t len) +{ + cbs->data = data; + cbs->len = len; } -static int cbs_get(CBS *cbs, const uint8_t **p, size_t n) { - if (cbs->len < n) { - return 0; - } +static int +cbs_get(CBS *cbs, const uint8_t **p, size_t n) +{ + if (cbs->len < n) + return 0; - *p = cbs->data; - cbs->data += n; - cbs->len -= n; - return 1; + *p = cbs->data; + cbs->data += n; + cbs->len -= n; + return 1; } -int CBS_skip(CBS *cbs, size_t len) { - const uint8_t *dummy; - return cbs_get(cbs, &dummy, len); +int +CBS_skip(CBS *cbs, size_t len) +{ + const uint8_t *dummy; + return cbs_get(cbs, &dummy, len); } -const uint8_t *CBS_data(const CBS *cbs) { - return cbs->data; +const uint8_t * +CBS_data(const CBS *cbs) +{ + return cbs->data; } -size_t CBS_len(const CBS *cbs) { - return cbs->len; +size_t +CBS_len(const CBS *cbs) +{ + return cbs->len; } -int CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len) { - if (*out_ptr != NULL) { - free(*out_ptr); - *out_ptr = NULL; - } - *out_len = 0; - - if (cbs->len == 0) { - return 1; - } - *out_ptr = BUF_memdup(cbs->data, cbs->len); - if (*out_ptr == NULL) { - return 0; - } - *out_len = cbs->len; - return 1; +int +CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len) +{ + if (*out_ptr != NULL) { + free(*out_ptr); + *out_ptr = NULL; + } + *out_len = 0; + + if (cbs->len == 0) + return 1; + + *out_ptr = BUF_memdup(cbs->data, cbs->len); + if (*out_ptr == NULL) + return 0; + + *out_len = cbs->len; + return 1; } -int CBS_strdup(const CBS *cbs, char **out_ptr) { - if (*out_ptr != NULL) { - free(*out_ptr); - } - *out_ptr = strndup((const char*)cbs->data, cbs->len); - return (*out_ptr != NULL); +int +CBS_strdup(const CBS *cbs, char **out_ptr) +{ + if (*out_ptr != NULL) + free(*out_ptr); + + *out_ptr = strndup((const char*)cbs->data, cbs->len); + return (*out_ptr != NULL); } -int CBS_contains_zero_byte(const CBS *cbs) { - return memchr(cbs->data, 0, cbs->len) != NULL; +int +CBS_contains_zero_byte(const CBS *cbs) +{ + return memchr(cbs->data, 0, cbs->len) != NULL; } -int CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len) { - if (len != cbs->len) - return 0; - return CRYPTO_memcmp(cbs->data, data, len) == 0; +int +CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len) +{ + if (len != cbs->len) + return 0; + + return CRYPTO_memcmp(cbs->data, data, len) == 0; } -static int cbs_get_u(CBS *cbs, uint32_t *out, size_t len) { - uint32_t result = 0; - size_t i; - const uint8_t *data; - - if (!cbs_get(cbs, &data, len)) { - return 0; - } - for (i = 0; i < len; i++) { - result <<= 8; - result |= data[i]; - } - *out = result; - return 1; +static int +cbs_get_u(CBS *cbs, uint32_t *out, size_t len) +{ + uint32_t result = 0; + size_t i; + const uint8_t *data; + + if (!cbs_get(cbs, &data, len)) + return 0; + + for (i = 0; i < len; i++) { + result <<= 8; + result |= data[i]; + } + *out = result; + return 1; } -int CBS_get_u8(CBS *cbs, uint8_t *out) { - const uint8_t *v; - if (!cbs_get(cbs, &v, 1)) { - return 0; - } - *out = *v; - return 1; +int +CBS_get_u8(CBS *cbs, uint8_t *out) +{ + const uint8_t *v; + + if (!cbs_get(cbs, &v, 1)) + return 0; + + *out = *v; + return 1; } -int CBS_get_u16(CBS *cbs, uint16_t *out) { - uint32_t v; - if (!cbs_get_u(cbs, &v, 2)) { - return 0; - } - *out = v; - return 1; +int +CBS_get_u16(CBS *cbs, uint16_t *out) +{ + uint32_t v; + + if (!cbs_get_u(cbs, &v, 2)) + return 0; + + *out = v; + return 1; } -int CBS_get_u24(CBS *cbs, uint32_t *out) { - return cbs_get_u(cbs, out, 3); +int +CBS_get_u24(CBS *cbs, uint32_t *out) +{ + return cbs_get_u(cbs, out, 3); } -int CBS_get_u32(CBS *cbs, uint32_t *out) { - return cbs_get_u(cbs, out, 4); +int +CBS_get_u32(CBS *cbs, uint32_t *out) +{ + return cbs_get_u(cbs, out, 4); } -int CBS_get_bytes(CBS *cbs, CBS *out, size_t len) { - const uint8_t *v; - if (!cbs_get(cbs, &v, len)) { - return 0; - } - CBS_init(out, v, len); - return 1; +int +CBS_get_bytes(CBS *cbs, CBS *out, size_t len) +{ + const uint8_t *v; + + if (!cbs_get(cbs, &v, len)) + return 0; + + CBS_init(out, v, len); + return 1; } -static int cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len) { - uint32_t len; - if (!cbs_get_u(cbs, &len, len_len)) { - return 0; - } - return CBS_get_bytes(cbs, out, len); +static int +cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len) +{ + uint32_t len; + + if (!cbs_get_u(cbs, &len, len_len)) + return 0; + + return CBS_get_bytes(cbs, out, len); } -int CBS_get_u8_length_prefixed(CBS *cbs, CBS *out) { - return cbs_get_length_prefixed(cbs, out, 1); +int +CBS_get_u8_length_prefixed(CBS *cbs, CBS *out) +{ + return cbs_get_length_prefixed(cbs, out, 1); } -int CBS_get_u16_length_prefixed(CBS *cbs, CBS *out) { - return cbs_get_length_prefixed(cbs, out, 2); +int +CBS_get_u16_length_prefixed(CBS *cbs, CBS *out) +{ + return cbs_get_length_prefixed(cbs, out, 2); } -int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) { - return cbs_get_length_prefixed(cbs, out, 3); +int +CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) +{ + return cbs_get_length_prefixed(cbs, out, 3); } -int CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, - size_t *out_header_len) { - uint8_t tag, length_byte; - CBS header = *cbs; - CBS throwaway; - - if (out == NULL) { - out = &throwaway; - } - - if (!CBS_get_u8(&header, &tag) || - !CBS_get_u8(&header, &length_byte)) { - return 0; - } - - if ((tag & 0x1f) == 0x1f) { - /* Long form tags are not supported. */ - return 0; - } - - if (out_tag != NULL) { - *out_tag = tag; - } - - size_t len; - if ((length_byte & 0x80) == 0) { - /* Short form length. */ - len = ((size_t) length_byte) + 2; - if (out_header_len != NULL) { - *out_header_len = 2; - } - } else { - /* Long form length. */ - const size_t num_bytes = length_byte & 0x7f; - uint32_t len32; - - if ((tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) { - /* indefinite length */ - *out_header_len = 2; - return CBS_get_bytes(cbs, out, 2); - } - - if (num_bytes == 0 || num_bytes > 4) { - return 0; - } - if (!cbs_get_u(&header, &len32, num_bytes)) { - return 0; - } - if (len32 < 128) { - /* Length should have used short-form encoding. */ - return 0; - } - if ((len32 >> ((num_bytes-1)*8)) == 0) { - /* Length should have been at least one byte shorter. */ - return 0; - } - len = len32; - if (len + 2 + num_bytes < len) { - /* Overflow. */ - return 0; - } - len += 2 + num_bytes; - if (out_header_len != NULL) { - *out_header_len = 2 + num_bytes; - } - } - - return CBS_get_bytes(cbs, out, len); +int +CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, + size_t *out_header_len) +{ + uint8_t tag, length_byte; + CBS header = *cbs; + CBS throwaway; + + if (out == NULL) + out = &throwaway; + + if (!CBS_get_u8(&header, &tag) || !CBS_get_u8(&header, &length_byte)) + return 0; + + if ((tag & 0x1f) == 0x1f) + /* Long form tags are not supported. */ + return 0; + + if (out_tag != NULL) + *out_tag = tag; + + size_t len; + if ((length_byte & 0x80) == 0) { + /* Short form length. */ + len = ((size_t) length_byte) + 2; + if (out_header_len != NULL) + *out_header_len = 2; + + } else { + /* Long form length. */ + const size_t num_bytes = length_byte & 0x7f; + uint32_t len32; + + if ((tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) { + /* indefinite length */ + *out_header_len = 2; + return CBS_get_bytes(cbs, out, 2); + } + + if (num_bytes == 0 || num_bytes > 4) + return 0; + + if (!cbs_get_u(&header, &len32, num_bytes)) + return 0; + + if (len32 < 128) + /* Length should have used short-form encoding. */ + return 0; + + if ((len32 >> ((num_bytes-1)*8)) == 0) + /* Length should have been at least one byte shorter. */ + return 0; + + len = len32; + if (len + 2 + num_bytes < len) + /* Overflow. */ + return 0; + + len += 2 + num_bytes; + if (out_header_len != NULL) + *out_header_len = 2 + num_bytes; + } + + return CBS_get_bytes(cbs, out, len); } -static int cbs_get_asn1(CBS *cbs, CBS *out, unsigned tag_value, - int skip_header) { - size_t header_len; - unsigned tag; - CBS throwaway; - - if (out == NULL) { - out = &throwaway; - } - - if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) || - tag != tag_value || - (header_len > 0 && - /* This ensures that the tag is either zero length or - * indefinite-length. */ - CBS_len(out) == header_len && - CBS_data(out)[header_len - 1] == 0x80)) { - return 0; - } - - if (skip_header && !CBS_skip(out, header_len)) { - assert(0); - return 0; - } - - return 1; +static int +cbs_get_asn1(CBS *cbs, CBS *out, unsigned tag_value, int skip_header) +{ + size_t header_len; + unsigned tag; + CBS throwaway; + + if (out == NULL) + out = &throwaway; + + if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) || + tag != tag_value || (header_len > 0 && + /* + * This ensures that the tag is either zero length or + * indefinite-length. + */ + CBS_len(out) == header_len && + CBS_data(out)[header_len - 1] == 0x80)) + return 0; + + if (skip_header && !CBS_skip(out, header_len)) { + assert(0); + return 0; + } + + return 1; } -int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value) { - return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */); +int +CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value) +{ + return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */); } -int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value) { - return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */); +int +CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value) +{ + return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */); } -int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value) { - if (CBS_len(cbs) < 1) { - return 0; - } - return CBS_data(cbs)[0] == tag_value; +int +CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value) +{ + if (CBS_len(cbs) < 1) + return 0; + + return CBS_data(cbs)[0] == tag_value; } -int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) { - CBS bytes; - const uint8_t *data; - size_t i, len; - - if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER)) { - return 0; - } - - *out = 0; - data = CBS_data(&bytes); - len = CBS_len(&bytes); - - if (len == 0) { - /* An INTEGER is encoded with at least one octet. */ - return 0; - } - - if ((data[0] & 0x80) != 0) { - /* negative number */ - return 0; - } - - for (i = 0; i < len; i++) { - if ((*out >> 56) != 0) { - /* Too large to represent as a uint64_t. */ - return 0; - } - *out <<= 8; - *out |= data[i]; - } - - return 1; +int +CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) +{ + CBS bytes; + const uint8_t *data; + size_t i, len; + + if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER)) + return 0; + + *out = 0; + data = CBS_data(&bytes); + len = CBS_len(&bytes); + + if (len == 0) + /* An INTEGER is encoded with at least one octet. */ + return 0; + + if ((data[0] & 0x80) != 0) + /* negative number */ + return 0; + + for (i = 0; i < len; i++) { + if ((*out >> 56) != 0) + /* Too large to represent as a uint64_t. */ + return 0; + + *out <<= 8; + *out |= data[i]; + } + + return 1; } -int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) { - if (CBS_peek_asn1_tag(cbs, tag)) { - if (!CBS_get_asn1(cbs, out, tag)) { - return 0; - } - *out_present = 1; - } else { - *out_present = 0; - } - return 1; +int +CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) +{ + if (CBS_peek_asn1_tag(cbs, tag)) { + if (!CBS_get_asn1(cbs, out, tag)) + return 0; + + *out_present = 1; + } else { + *out_present = 0; + } + return 1; } -int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present, - unsigned tag) { - CBS child; - int present; - if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { - return 0; - } - if (present) { - if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) || - CBS_len(&child) != 0) { - return 0; - } - } else { - CBS_init(out, NULL, 0); - } - if (out_present) { - *out_present = present; - } - return 1; +int +CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present, + unsigned tag) +{ + CBS child; + int present; + + if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) + return 0; + + if (present) { + if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) || + CBS_len(&child) != 0) + return 0; + } else { + CBS_init(out, NULL, 0); + } + if (out_present) + *out_present = present; + + return 1; } -int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag, - uint64_t default_value) { - CBS child; - int present; - if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { - return 0; - } - if (present) { - if (!CBS_get_asn1_uint64(&child, out) || - CBS_len(&child) != 0) { - return 0; - } - } else { - *out = default_value; - } - return 1; +int +CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag, + uint64_t default_value) +{ + CBS child; + int present; + + if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) + return 0; + + if (present) { + if (!CBS_get_asn1_uint64(&child, out) || + CBS_len(&child) != 0) + return 0; + } else { + *out = default_value; + } + return 1; } -int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, - int default_value) { - CBS child, child2; - int present; - if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { - return 0; - } - if (present) { - uint8_t boolean; - - if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) || - CBS_len(&child2) != 1 || - CBS_len(&child) != 0) { - return 0; - } - - boolean = CBS_data(&child2)[0]; - if (boolean == 0) { - *out = 0; - } else if (boolean == 0xff) { - *out = 1; - } else { - return 0; - } - } else { - *out = default_value; - } - return 1; +int +CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, int default_value) +{ + CBS child, child2; + int present; + + if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) + return 0; + + if (present) { + uint8_t boolean; + + if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) || + CBS_len(&child2) != 1 || CBS_len(&child) != 0) + return 0; + + boolean = CBS_data(&child2)[0]; + if (boolean == 0) + *out = 0; + else if (boolean == 0xff) + *out = 1; + else + return 0; + + } else { + *out = default_value; + } + return 1; } diff --git a/lib/libssl/src/ssl/bytestring.h b/lib/libssl/src/ssl/bytestring.h index 3c4e8eaaf3b..09414af0568 100644 --- a/lib/libssl/src/ssl/bytestring.h +++ b/lib/libssl/src/ssl/bytestring.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bytestring.h,v 1.1 2015/02/06 09:36:16 doug Exp $ */ +/* $OpenBSD: bytestring.h,v 1.2 2015/02/06 22:22:33 doug Exp $ */ /* * Copyright (c) 2014, Google Inc. * @@ -26,96 +26,127 @@ extern "C" { #include <openssl/opensslconf.h> -/* Bytestrings are used for parsing and building TLS and ASN.1 messages. +/* + * Bytestrings are used for parsing and building TLS and ASN.1 messages. * * A "CBS" (CRYPTO ByteString) represents a string of bytes in memory and * provides utility functions for safely parsing length-prefixed structures * like TLS and ASN.1 from it. * * A "CBB" (CRYPTO ByteBuilder) is a memory buffer that grows as needed and - * provides utility functions for building length-prefixed messages. */ - + * provides utility functions for building length-prefixed messages. + */ /* CRYPTO ByteString */ - typedef struct cbs_st { - const uint8_t *data; - size_t len; + const uint8_t *data; + size_t len; } CBS; -/* CBS_init sets |cbs| to point to |data|. It does not take ownership of - * |data|. */ +/* + * CBS_init sets |cbs| to point to |data|. It does not take ownership of + * |data|. + */ void CBS_init(CBS *cbs, const uint8_t *data, size_t len); -/* CBS_skip advances |cbs| by |len| bytes. It returns one on success and zero - * otherwise. */ +/* + * CBS_skip advances |cbs| by |len| bytes. It returns one on success and zero + * otherwise. + */ int CBS_skip(CBS *cbs, size_t len); -/* CBS_data returns a pointer to the contains of |cbs|. */ +/* + * CBS_data returns a pointer to the contains of |cbs|. + */ const uint8_t *CBS_data(const CBS *cbs); -/* CBS_len returns the number of bytes remaining in |cbs|. */ +/* + * CBS_len returns the number of bytes remaining in |cbs|. + */ size_t CBS_len(const CBS *cbs); -/* CBS_stow copies the current contents of |cbs| into |*out_ptr| and +/* + * CBS_stow copies the current contents of |cbs| into |*out_ptr| and * |*out_len|. If |*out_ptr| is not NULL, the contents are freed with * OPENSSL_free. It returns one on success and zero on allocation failure. On * success, |*out_ptr| should be freed with OPENSSL_free. If |cbs| is empty, - * |*out_ptr| will be NULL. */ + * |*out_ptr| will be NULL. + */ int CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len); -/* CBS_strdup copies the current contents of |cbs| into |*out_ptr| as a +/* + * CBS_strdup copies the current contents of |cbs| into |*out_ptr| as a * NUL-terminated C string. If |*out_ptr| is not NULL, the contents are freed * with OPENSSL_free. It returns one on success and zero on allocation * failure. On success, |*out_ptr| should be freed with OPENSSL_free. * * NOTE: If |cbs| contains NUL bytes, the string will be truncated. Call - * |CBS_contains_zero_byte(cbs)| to check for NUL bytes. */ + * |CBS_contains_zero_byte(cbs)| to check for NUL bytes. + */ int CBS_strdup(const CBS *cbs, char **out_ptr); -/* CBS_contains_zero_byte returns one if the current contents of |cbs| contains - * a NUL byte and zero otherwise. */ +/* + * CBS_contains_zero_byte returns one if the current contents of |cbs| contains + * a NUL byte and zero otherwise. + */ int CBS_contains_zero_byte(const CBS *cbs); -/* CBS_mem_equal compares the current contents of |cbs| with the |len| bytes +/* + * CBS_mem_equal compares the current contents of |cbs| with the |len| bytes * starting at |data|. If they're equal, it returns one, otherwise zero. If the - * lengths match, it uses a constant-time comparison. */ -int CBS_mem_equal(const CBS *cbs, const uint8_t *data, - size_t len); + * lengths match, it uses a constant-time comparison. + */ +int CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len); -/* CBS_get_u8 sets |*out| to the next uint8_t from |cbs| and advances |cbs|. It - * returns one on success and zero on error. */ +/* + * CBS_get_u8 sets |*out| to the next uint8_t from |cbs| and advances |cbs|. It + * returns one on success and zero on error. + */ int CBS_get_u8(CBS *cbs, uint8_t *out); -/* CBS_get_u16 sets |*out| to the next, big-endian uint16_t from |cbs| and - * advances |cbs|. It returns one on success and zero on error. */ +/* + * CBS_get_u16 sets |*out| to the next, big-endian uint16_t from |cbs| and + * advances |cbs|. It returns one on success and zero on error. + */ int CBS_get_u16(CBS *cbs, uint16_t *out); -/* CBS_get_u24 sets |*out| to the next, big-endian 24-bit value from |cbs| and - * advances |cbs|. It returns one on success and zero on error. */ +/* + * CBS_get_u24 sets |*out| to the next, big-endian 24-bit value from |cbs| and + * advances |cbs|. It returns one on success and zero on error. + */ int CBS_get_u24(CBS *cbs, uint32_t *out); -/* CBS_get_u32 sets |*out| to the next, big-endian uint32_t value from |cbs| - * and advances |cbs|. It returns one on success and zero on error. */ +/* + * CBS_get_u32 sets |*out| to the next, big-endian uint32_t value from |cbs| + * and advances |cbs|. It returns one on success and zero on error. + */ int CBS_get_u32(CBS *cbs, uint32_t *out); -/* CBS_get_bytes sets |*out| to the next |len| bytes from |cbs| and advances - * |cbs|. It returns one on success and zero on error. */ +/* + * CBS_get_bytes sets |*out| to the next |len| bytes from |cbs| and advances + * |cbs|. It returns one on success and zero on error. + */ int CBS_get_bytes(CBS *cbs, CBS *out, size_t len); -/* CBS_get_u8_length_prefixed sets |*out| to the contents of an 8-bit, +/* + * CBS_get_u8_length_prefixed sets |*out| to the contents of an 8-bit, * length-prefixed value from |cbs| and advances |cbs| over it. It returns one - * on success and zero on error. */ + * on success and zero on error. + */ int CBS_get_u8_length_prefixed(CBS *cbs, CBS *out); -/* CBS_get_u16_length_prefixed sets |*out| to the contents of a 16-bit, +/* + * CBS_get_u16_length_prefixed sets |*out| to the contents of a 16-bit, * big-endian, length-prefixed value from |cbs| and advances |cbs| over it. It - * returns one on success and zero on error. */ + * returns one on success and zero on error. + */ int CBS_get_u16_length_prefixed(CBS *cbs, CBS *out); -/* CBS_get_u24_length_prefixed sets |*out| to the contents of a 24-bit, +/* + * CBS_get_u24_length_prefixed sets |*out| to the contents of a 24-bit, * big-endian, length-prefixed value from |cbs| and advances |cbs| over it. It - * returns one on success and zero on error. */ + * returns one on success and zero on error. + */ int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out); @@ -133,80 +164,95 @@ int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out); #define CBS_ASN1_CONSTRUCTED 0x20 #define CBS_ASN1_CONTEXT_SPECIFIC 0x80 -/* CBS_get_asn1 sets |*out| to the contents of DER-encoded, ASN.1 element (not +/* + * CBS_get_asn1 sets |*out| to the contents of DER-encoded, ASN.1 element (not * including tag and length bytes) and advances |cbs| over it. The ASN.1 * element must match |tag_value|. It returns one on success and zero * on error. * - * Tag numbers greater than 31 are not supported. */ + * Tag numbers greater than 31 are not supported. + */ int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value); -/* CBS_get_asn1_element acts like |CBS_get_asn1| but |out| will include the - * ASN.1 header bytes too. */ +/* + * CBS_get_asn1_element acts like |CBS_get_asn1| but |out| will include the + * ASN.1 header bytes too. + */ int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value); -/* CBS_peek_asn1_tag looks ahead at the next ASN.1 tag and returns one +/* + * CBS_peek_asn1_tag looks ahead at the next ASN.1 tag and returns one * if the next ASN.1 element on |cbs| would have tag |tag_value|. If * |cbs| is empty or the tag does not match, it returns zero. Note: if * it returns one, CBS_get_asn1 may still fail if the rest of the - * element is malformed. */ + * element is malformed. + */ int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value); -/* CBS_get_any_asn1_element sets |*out| to contain the next ASN.1 element from +/* + * CBS_get_any_asn1_element sets |*out| to contain the next ASN.1 element from * |*cbs| (including header bytes) and advances |*cbs|. It sets |*out_tag| to * the tag number and |*out_header_len| to the length of the ASN.1 header. If * the element has indefinite length then |*out| will only contain the * header. Each of |out|, |out_tag|, and |out_header_len| may be NULL to ignore * the value. * - * Tag numbers greater than 31 are not supported. */ -int CBS_get_any_asn1_element(CBS *cbs, CBS *out, - unsigned *out_tag, - size_t *out_header_len); + * Tag numbers greater than 31 are not supported. + */ +int CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, + size_t *out_header_len); -/* CBS_get_asn1_uint64 gets an ASN.1 INTEGER from |cbs| using |CBS_get_asn1| +/* + * CBS_get_asn1_uint64 gets an ASN.1 INTEGER from |cbs| using |CBS_get_asn1| * and sets |*out| to its value. It returns one on success and zero on error, * where error includes the integer being negative, or too large to represent - * in 64 bits. */ + * in 64 bits. + */ int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out); -/* CBS_get_optional_asn1 gets an optional explicitly-tagged element +/* + * CBS_get_optional_asn1 gets an optional explicitly-tagged element * from |cbs| tagged with |tag| and sets |*out| to its contents. If * present, it sets |*out_present| to one, otherwise zero. It returns * one on success, whether or not the element was present, and zero on - * decode failure. */ -int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, - unsigned tag); + * decode failure. + */ +int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag); -/* CBS_get_optional_asn1_octet_string gets an optional +/* + * CBS_get_optional_asn1_octet_string gets an optional * explicitly-tagged OCTET STRING from |cbs|. If present, it sets * |*out| to the string and |*out_present| to one. Otherwise, it sets * |*out| to empty and |*out_present| to zero. |out_present| may be * NULL. It returns one on success, whether or not the element was - * present, and zero on decode failure. */ -int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, - int *out_present, - unsigned tag); + * present, and zero on decode failure. + */ +int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present, + unsigned tag); -/* CBS_get_optional_asn1_uint64 gets an optional explicitly-tagged +/* + * CBS_get_optional_asn1_uint64 gets an optional explicitly-tagged * INTEGER from |cbs|. If present, it sets |*out| to the * value. Otherwise, it sets |*out| to |default_value|. It returns one * on success, whether or not the element was present, and zero on - * decode failure. */ -int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, - unsigned tag, - uint64_t default_value); + * decode failure. + */ +int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag, + uint64_t default_value); -/* CBS_get_optional_asn1_bool gets an optional, explicitly-tagged BOOLEAN from +/* + * CBS_get_optional_asn1_bool gets an optional, explicitly-tagged BOOLEAN from * |cbs|. If present, it sets |*out| to either zero or one, based on the * boolean. Otherwise, it sets |*out| to |default_value|. It returns one on * success, whether or not the element was present, and zero on decode - * failure. */ + * failure. + */ int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, - int default_value); + int default_value); -/* CRYPTO ByteBuilder. +/* + * CRYPTO ByteBuilder. * * |CBB| objects allow one to build length-prefixed serialisations. A |CBB| * object is associated with a buffer and new buffers are created with @@ -218,111 +264,162 @@ int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, * not be used again. * * If one needs to force a length prefix to be written out because a |CBB| is - * going out of scope, use |CBB_flush|. */ + * going out of scope, use |CBB_flush|. + */ struct cbb_buffer_st { - uint8_t *buf; - size_t len; /* The number of valid bytes. */ - size_t cap; /* The size of buf. */ - char can_resize; /* One iff |buf| is owned by this object. If not then |buf| - cannot be resized. */ + uint8_t *buf; + + /* The number of valid bytes. */ + size_t len; + + /* The size of buf. */ + size_t cap; + + /* + * One iff |buf| is owned by this object. If not then |buf| cannot be + * resized. + */ + char can_resize; }; typedef struct cbb_st { - struct cbb_buffer_st *base; - /* offset is the offset from the start of |base->buf| to the position of any - * pending length-prefix. */ - size_t offset; - /* child points to a child CBB if a length-prefix is pending. */ - struct cbb_st *child; - /* pending_len_len contains the number of bytes in a pending length-prefix, - * or zero if no length-prefix is pending. */ - uint8_t pending_len_len; - char pending_is_asn1; - /* is_top_level is true iff this is a top-level |CBB| (as opposed to a child - * |CBB|). Top-level objects are valid arguments for |CBB_finish|. */ - char is_top_level; + struct cbb_buffer_st *base; + + /* + * offset is the offset from the start of |base->buf| to the position of any + * pending length-prefix. + */ + size_t offset; + + /* child points to a child CBB if a length-prefix is pending. */ + struct cbb_st *child; + + /* + * pending_len_len contains the number of bytes in a pending length-prefix, + * or zero if no length-prefix is pending. + */ + uint8_t pending_len_len; + + char pending_is_asn1; + + /* + * is_top_level is true iff this is a top-level |CBB| (as opposed to a child + * |CBB|). Top-level objects are valid arguments for |CBB_finish|. + */ + char is_top_level; } CBB; -/* CBB_init initialises |cbb| with |initial_capacity|. Since a |CBB| grows as +/* + * CBB_init initialises |cbb| with |initial_capacity|. Since a |CBB| grows as * needed, the |initial_capacity| is just a hint. It returns one on success or - * zero on error. */ + * zero on error. + */ int CBB_init(CBB *cbb, size_t initial_capacity); -/* CBB_init_fixed initialises |cbb| to write to |len| bytes at |buf|. Since +/* + * CBB_init_fixed initialises |cbb| to write to |len| bytes at |buf|. Since * |buf| cannot grow, trying to write more than |len| bytes will cause CBB - * functions to fail. It returns one on success or zero on error. */ + * functions to fail. It returns one on success or zero on error. + */ int CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len); -/* CBB_cleanup frees all resources owned by |cbb| and other |CBB| objects +/* + * CBB_cleanup frees all resources owned by |cbb| and other |CBB| objects * writing to the same buffer. This should be used in an error case where a - * serialisation is abandoned. */ + * serialisation is abandoned. + */ void CBB_cleanup(CBB *cbb); -/* CBB_finish completes any pending length prefix and sets |*out_data| to a +/* + * CBB_finish completes any pending length prefix and sets |*out_data| to a * malloced buffer and |*out_len| to the length of that buffer. The caller * takes ownership of the buffer and, unless the buffer was fixed with * |CBB_init_fixed|, must call |OPENSSL_free| when done. * * It can only be called on a "top level" |CBB|, i.e. one initialised with * |CBB_init| or |CBB_init_fixed|. It returns one on success and zero on - * error. */ + * error. + */ int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len); -/* CBB_flush causes any pending length prefixes to be written out and any child +/* + * CBB_flush causes any pending length prefixes to be written out and any child * |CBB| objects of |cbb| to be invalidated. It returns one on success or zero - * on error. */ + * on error. + */ int CBB_flush(CBB *cbb); -/* CBB_add_u8_length_prefixed sets |*out_contents| to a new child of |cbb|. The +/* + * CBB_add_u8_length_prefixed sets |*out_contents| to a new child of |cbb|. The * data written to |*out_contents| will be prefixed in |cbb| with an 8-bit - * length. It returns one on success or zero on error. */ + * length. It returns one on success or zero on error. + */ int CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents); -/* CBB_add_u16_length_prefixed sets |*out_contents| to a new child of |cbb|. +/* + * CBB_add_u16_length_prefixed sets |*out_contents| to a new child of |cbb|. * The data written to |*out_contents| will be prefixed in |cbb| with a 16-bit, - * big-endian length. It returns one on success or zero on error. */ + * big-endian length. It returns one on success or zero on error. + */ int CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents); -/* CBB_add_u24_length_prefixed sets |*out_contents| to a new child of |cbb|. +/* + * CBB_add_u24_length_prefixed sets |*out_contents| to a new child of |cbb|. * The data written to |*out_contents| will be prefixed in |cbb| with a 24-bit, - * big-endian length. It returns one on success or zero on error. */ + * big-endian length. It returns one on success or zero on error. + */ int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents); -/* CBB_add_asn sets |*out_contents| to a |CBB| into which the contents of an +/* + * CBB_add_asn sets |*out_contents| to a |CBB| into which the contents of an * ASN.1 object can be written. The |tag| argument will be used as the tag for - * the object. It returns one on success or zero on error. */ + * the object. It returns one on success or zero on error. + */ int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag); -/* CBB_add_bytes appends |len| bytes from |data| to |cbb|. It returns one on - * success and zero otherwise. */ +/* + * CBB_add_bytes appends |len| bytes from |data| to |cbb|. It returns one on + * success and zero otherwise. + */ int CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len); -/* CBB_add_space appends |len| bytes to |cbb| and sets |*out_data| to point to +/* + * CBB_add_space appends |len| bytes to |cbb| and sets |*out_data| to point to * the beginning of that space. The caller must then write |len| bytes of * actual contents to |*out_data|. It returns one on success and zero - * otherwise. */ + * otherwise. + */ int CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len); -/* CBB_add_u8 appends an 8-bit number from |value| to |cbb|. It returns one on - * success and zero otherwise. */ +/* + * CBB_add_u8 appends an 8-bit number from |value| to |cbb|. It returns one on + * success and zero otherwise. + */ int CBB_add_u8(CBB *cbb, uint8_t value); -/* CBB_add_u8 appends a 16-bit, big-endian number from |value| to |cbb|. It - * returns one on success and zero otherwise. */ +/* + * CBB_add_u8 appends a 16-bit, big-endian number from |value| to |cbb|. It + * returns one on success and zero otherwise. + */ int CBB_add_u16(CBB *cbb, uint16_t value); -/* CBB_add_u24 appends a 24-bit, big-endian number from |value| to |cbb|. It - * returns one on success and zero otherwise. */ +/* + * CBB_add_u24 appends a 24-bit, big-endian number from |value| to |cbb|. It + * returns one on success and zero otherwise. + */ int CBB_add_u24(CBB *cbb, uint32_t value); -/* CBB_add_asn1_uint64 writes an ASN.1 INTEGER into |cbb| using |CBB_add_asn1| +/* + * CBB_add_asn1_uint64 writes an ASN.1 INTEGER into |cbb| using |CBB_add_asn1| * and writes |value| in its contents. It returns one on success and zero on - * error. */ + * error. + */ int CBB_add_asn1_uint64(CBB *cbb, uint64_t value); #ifdef LIBRESSL_INTERNAL -/* CBS_asn1_ber_to_der reads an ASN.1 structure from |in|. If it finds +/* + * CBS_asn1_ber_to_der reads an ASN.1 structure from |in|. If it finds * indefinite-length elements then it attempts to convert the BER data to DER * and sets |*out| and |*out_length| to describe a malloced buffer containing * the DER data. Additionally, |*in| will be advanced over the ASN.1 data. @@ -335,7 +432,8 @@ int CBB_add_asn1_uint64(CBB *cbb, uint64_t value); * structure itself. However, this sufficies to handle the PKCS#7 and #12 output * from NSS. * - * It returns one on success and zero otherwise. */ + * It returns one on success and zero otherwise. + */ int CBS_asn1_ber_to_der(CBS *in, uint8_t **out, size_t *out_len); #endif /* LIBRESSL_INTERNAL */ diff --git a/regress/lib/libssl/bytestring/bytestringtest.c b/regress/lib/libssl/bytestring/bytestringtest.c index 92e33c02e7b..ba768e4bb07 100644 --- a/regress/lib/libssl/bytestring/bytestringtest.c +++ b/regress/lib/libssl/bytestring/bytestringtest.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bytestringtest.c,v 1.1 2015/02/06 09:36:16 doug Exp $ */ +/* $OpenBSD: bytestringtest.c,v 1.2 2015/02/06 22:22:33 doug Exp $ */ /* * Copyright (c) 2014, Google Inc. * @@ -25,631 +25,645 @@ /* This is from <openssl/base.h> in boringssl */ #define OPENSSL_U64(x) x##ULL -static int test_skip(void) { - static const uint8_t kData[] = {1, 2, 3}; - CBS data; - - CBS_init(&data, kData, sizeof(kData)); - return CBS_len(&data) == 3 && - CBS_skip(&data, 1) && - CBS_len(&data) == 2 && - CBS_skip(&data, 2) && - CBS_len(&data) == 0 && - !CBS_skip(&data, 1); +static int +test_skip(void) +{ + static const uint8_t kData[] = {1, 2, 3}; + CBS data; + + CBS_init(&data, kData, sizeof(kData)); + return CBS_len(&data) == 3 && + CBS_skip(&data, 1) && + CBS_len(&data) == 2 && + CBS_skip(&data, 2) && + CBS_len(&data) == 0 && + !CBS_skip(&data, 1); } -static int test_get_u(void) { - static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - uint8_t u8; - uint16_t u16; - uint32_t u32; - CBS data; - - CBS_init(&data, kData, sizeof(kData)); - return CBS_get_u8(&data, &u8) && - u8 == 1 && - CBS_get_u16(&data, &u16) && - u16 == 0x203 && - CBS_get_u24(&data, &u32) && - u32 == 0x40506 && - CBS_get_u32(&data, &u32) && - u32 == 0x708090a && - !CBS_get_u8(&data, &u8); +static int +test_get_u(void) +{ + static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + uint8_t u8; + uint16_t u16; + uint32_t u32; + CBS data; + + CBS_init(&data, kData, sizeof(kData)); + return CBS_get_u8(&data, &u8) && + u8 == 1 && + CBS_get_u16(&data, &u16) && + u16 == 0x203 && + CBS_get_u24(&data, &u32) && + u32 == 0x40506 && + CBS_get_u32(&data, &u32) && + u32 == 0x708090a && + !CBS_get_u8(&data, &u8); } -static int test_get_prefixed(void) { - static const uint8_t kData[] = {1, 2, 0, 2, 3, 4, 0, 0, 3, 3, 2, 1}; - uint8_t u8; - uint16_t u16; - uint32_t u32; - CBS data, prefixed; - - CBS_init(&data, kData, sizeof(kData)); - return CBS_get_u8_length_prefixed(&data, &prefixed) && - CBS_len(&prefixed) == 1 && - CBS_get_u8(&prefixed, &u8) && - u8 == 2 && - CBS_get_u16_length_prefixed(&data, &prefixed) && - CBS_len(&prefixed) == 2 && - CBS_get_u16(&prefixed, &u16) && - u16 == 0x304 && - CBS_get_u24_length_prefixed(&data, &prefixed) && - CBS_len(&prefixed) == 3 && - CBS_get_u24(&prefixed, &u32) && - u32 == 0x30201; +static int +test_get_prefixed(void) +{ + static const uint8_t kData[] = {1, 2, 0, 2, 3, 4, 0, 0, 3, 3, 2, 1}; + uint8_t u8; + uint16_t u16; + uint32_t u32; + CBS data, prefixed; + + CBS_init(&data, kData, sizeof(kData)); + return CBS_get_u8_length_prefixed(&data, &prefixed) && + CBS_len(&prefixed) == 1 && + CBS_get_u8(&prefixed, &u8) && + u8 == 2 && + CBS_get_u16_length_prefixed(&data, &prefixed) && + CBS_len(&prefixed) == 2 && + CBS_get_u16(&prefixed, &u16) && + u16 == 0x304 && + CBS_get_u24_length_prefixed(&data, &prefixed) && + CBS_len(&prefixed) == 3 && + CBS_get_u24(&prefixed, &u32) && + u32 == 0x30201; } -static int test_get_prefixed_bad(void) { - static const uint8_t kData1[] = {2, 1}; - static const uint8_t kData2[] = {0, 2, 1}; - static const uint8_t kData3[] = {0, 0, 2, 1}; - CBS data, prefixed; +static int +test_get_prefixed_bad(void) +{ + static const uint8_t kData1[] = {2, 1}; + static const uint8_t kData2[] = {0, 2, 1}; + static const uint8_t kData3[] = {0, 0, 2, 1}; + CBS data, prefixed; - CBS_init(&data, kData1, sizeof(kData1)); - if (CBS_get_u8_length_prefixed(&data, &prefixed)) { - return 0; - } + CBS_init(&data, kData1, sizeof(kData1)); + if (CBS_get_u8_length_prefixed(&data, &prefixed)) + return 0; - CBS_init(&data, kData2, sizeof(kData2)); - if (CBS_get_u16_length_prefixed(&data, &prefixed)) { - return 0; - } + CBS_init(&data, kData2, sizeof(kData2)); + if (CBS_get_u16_length_prefixed(&data, &prefixed)) + return 0; - CBS_init(&data, kData3, sizeof(kData3)); - if (CBS_get_u24_length_prefixed(&data, &prefixed)) { - return 0; - } + CBS_init(&data, kData3, sizeof(kData3)); + if (CBS_get_u24_length_prefixed(&data, &prefixed)) + return 0; - return 1; + return 1; } -static int test_get_asn1(void) { - static const uint8_t kData1[] = {0x30, 2, 1, 2}; - static const uint8_t kData2[] = {0x30, 3, 1, 2}; - static const uint8_t kData3[] = {0x30, 0x80}; - static const uint8_t kData4[] = {0x30, 0x81, 1, 1}; - static const uint8_t kData5[] = {0x30, 0x82, 0, 1, 1}; - static const uint8_t kData6[] = {0xa1, 3, 0x4, 1, 1}; - static const uint8_t kData7[] = {0xa1, 3, 0x4, 2, 1}; - static const uint8_t kData8[] = {0xa1, 3, 0x2, 1, 1}; - static const uint8_t kData9[] = {0xa1, 3, 0x2, 1, 0xff}; - - CBS data, contents; - int present; - uint64_t value; - - CBS_init(&data, kData1, sizeof(kData1)); - if (CBS_peek_asn1_tag(&data, 0x1) || - !CBS_peek_asn1_tag(&data, 0x30)) { - return 0; - } - if (!CBS_get_asn1(&data, &contents, 0x30) || - CBS_len(&contents) != 2 || - memcmp(CBS_data(&contents), "\x01\x02", 2) != 0) { - return 0; - } - - CBS_init(&data, kData2, sizeof(kData2)); - /* data is truncated */ - if (CBS_get_asn1(&data, &contents, 0x30)) { - return 0; - } - - CBS_init(&data, kData3, sizeof(kData3)); - /* zero byte length of length */ - if (CBS_get_asn1(&data, &contents, 0x30)) { - return 0; - } - - CBS_init(&data, kData4, sizeof(kData4)); - /* long form mistakenly used. */ - if (CBS_get_asn1(&data, &contents, 0x30)) { - return 0; - } - - CBS_init(&data, kData5, sizeof(kData5)); - /* length takes too many bytes. */ - if (CBS_get_asn1(&data, &contents, 0x30)) { - return 0; - } - - CBS_init(&data, kData1, sizeof(kData1)); - /* wrong tag. */ - if (CBS_get_asn1(&data, &contents, 0x31)) { - return 0; - } - - CBS_init(&data, NULL, 0); - /* peek at empty data. */ - if (CBS_peek_asn1_tag(&data, 0x30)) { - return 0; - } - - CBS_init(&data, NULL, 0); - /* optional elements at empty data. */ - if (!CBS_get_optional_asn1(&data, &contents, &present, 0xa0) || - present || - !CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0) || - present || - CBS_len(&contents) != 0 || - !CBS_get_optional_asn1_octet_string(&data, &contents, NULL, 0xa0) || - CBS_len(&contents) != 0 || - !CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42) || - value != 42) { - return 0; - } - - CBS_init(&data, kData6, sizeof(kData6)); - /* optional element. */ - if (!CBS_get_optional_asn1(&data, &contents, &present, 0xa0) || - present || - !CBS_get_optional_asn1(&data, &contents, &present, 0xa1) || - !present || - CBS_len(&contents) != 3 || - memcmp(CBS_data(&contents), "\x04\x01\x01", 3) != 0) { - return 0; - } - - CBS_init(&data, kData6, sizeof(kData6)); - /* optional octet string. */ - if (!CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0) || - present || - CBS_len(&contents) != 0 || - !CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1) || - !present || - CBS_len(&contents) != 1 || - CBS_data(&contents)[0] != 1) { - return 0; - } - - CBS_init(&data, kData7, sizeof(kData7)); - /* invalid optional octet string. */ - if (CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1)) { - return 0; - } - - CBS_init(&data, kData8, sizeof(kData8)); - /* optional octet string. */ - if (!CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42) || - value != 42 || - !CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42) || - value != 1) { - return 0; - } - - CBS_init(&data, kData9, sizeof(kData9)); - /* invalid optional integer. */ - if (CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42)) { - return 0; - } - - return 1; +static int +test_get_asn1(void) +{ + static const uint8_t kData1[] = {0x30, 2, 1, 2}; + static const uint8_t kData2[] = {0x30, 3, 1, 2}; + static const uint8_t kData3[] = {0x30, 0x80}; + static const uint8_t kData4[] = {0x30, 0x81, 1, 1}; + static const uint8_t kData5[] = {0x30, 0x82, 0, 1, 1}; + static const uint8_t kData6[] = {0xa1, 3, 0x4, 1, 1}; + static const uint8_t kData7[] = {0xa1, 3, 0x4, 2, 1}; + static const uint8_t kData8[] = {0xa1, 3, 0x2, 1, 1}; + static const uint8_t kData9[] = {0xa1, 3, 0x2, 1, 0xff}; + + CBS data, contents; + int present; + uint64_t value; + + CBS_init(&data, kData1, sizeof(kData1)); + if (CBS_peek_asn1_tag(&data, 0x1) || !CBS_peek_asn1_tag(&data, 0x30)) + return 0; + + if (!CBS_get_asn1(&data, &contents, 0x30) || + CBS_len(&contents) != 2 || + memcmp(CBS_data(&contents), "\x01\x02", 2) != 0) + return 0; + + CBS_init(&data, kData2, sizeof(kData2)); + /* data is truncated */ + if (CBS_get_asn1(&data, &contents, 0x30)) + return 0; + + CBS_init(&data, kData3, sizeof(kData3)); + /* zero byte length of length */ + if (CBS_get_asn1(&data, &contents, 0x30)) + return 0; + + CBS_init(&data, kData4, sizeof(kData4)); + /* long form mistakenly used. */ + if (CBS_get_asn1(&data, &contents, 0x30)) + return 0; + + CBS_init(&data, kData5, sizeof(kData5)); + /* length takes too many bytes. */ + if (CBS_get_asn1(&data, &contents, 0x30)) + return 0; + + CBS_init(&data, kData1, sizeof(kData1)); + /* wrong tag. */ + if (CBS_get_asn1(&data, &contents, 0x31)) + return 0; + + CBS_init(&data, NULL, 0); + /* peek at empty data. */ + if (CBS_peek_asn1_tag(&data, 0x30)) + return 0; + + CBS_init(&data, NULL, 0); + /* optional elements at empty data. */ + if (!CBS_get_optional_asn1(&data, &contents, &present, 0xa0) || + present || + !CBS_get_optional_asn1_octet_string(&data, &contents, &present, + 0xa0) || + present || + CBS_len(&contents) != 0 || + !CBS_get_optional_asn1_octet_string(&data, &contents, NULL, 0xa0) || + CBS_len(&contents) != 0 || + !CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42) || + value != 42) + return 0; + + CBS_init(&data, kData6, sizeof(kData6)); + /* optional element. */ + if (!CBS_get_optional_asn1(&data, &contents, &present, 0xa0) || + present || + !CBS_get_optional_asn1(&data, &contents, &present, 0xa1) || + !present || + CBS_len(&contents) != 3 || + memcmp(CBS_data(&contents), "\x04\x01\x01", 3) != 0) + return 0; + + CBS_init(&data, kData6, sizeof(kData6)); + /* optional octet string. */ + if (!CBS_get_optional_asn1_octet_string(&data, &contents, &present, + 0xa0) || + present || + CBS_len(&contents) != 0 || + !CBS_get_optional_asn1_octet_string(&data, &contents, &present, + 0xa1) || + !present || + CBS_len(&contents) != 1 || + CBS_data(&contents)[0] != 1) + return 0; + + CBS_init(&data, kData7, sizeof(kData7)); + /* invalid optional octet string. */ + if (CBS_get_optional_asn1_octet_string(&data, &contents, &present, + 0xa1)) + return 0; + + CBS_init(&data, kData8, sizeof(kData8)); + /* optional octet string. */ + if (!CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42) || + value != 42 || + !CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42) || + value != 1) + return 0; + + CBS_init(&data, kData9, sizeof(kData9)); + /* invalid optional integer. */ + if (CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42)) + return 0; + + return 1; } -static int test_get_optional_asn1_bool(void) { - CBS data; - int val; - - static const uint8_t kTrue[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0xff}; - static const uint8_t kFalse[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x00}; - static const uint8_t kInvalid[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x01}; - - CBS_init(&data, NULL, 0); - val = 2; - if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 0) || - val != 0) { - return 0; - } - - CBS_init(&data, kTrue, sizeof(kTrue)); - val = 2; - if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 0) || - val != 1) { - return 0; - } - - CBS_init(&data, kFalse, sizeof(kFalse)); - val = 2; - if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 1) || - val != 0) { - return 0; - } - - CBS_init(&data, kInvalid, sizeof(kInvalid)); - if (CBS_get_optional_asn1_bool(&data, &val, 0x0a, 1)) { - return 0; - } - - return 1; +static int +test_get_optional_asn1_bool(void) +{ + CBS data; + int val; + + static const uint8_t kTrue[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0xff}; + static const uint8_t kFalse[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x00}; + static const uint8_t kInvalid[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x01}; + + CBS_init(&data, NULL, 0); + val = 2; + if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 0) || val != 0) + return 0; + + CBS_init(&data, kTrue, sizeof(kTrue)); + val = 2; + if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 0) || val != 1) + return 0; + + CBS_init(&data, kFalse, sizeof(kFalse)); + val = 2; + if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 1) || val != 0) + return 0; + + CBS_init(&data, kInvalid, sizeof(kInvalid)); + if (CBS_get_optional_asn1_bool(&data, &val, 0x0a, 1)) + return 0; + + return 1; } -static int test_cbb_basic(void) { - static const uint8_t kExpected[] = {1, 2, 3, 4, 5, 6, 7, 8}; - uint8_t *buf; - size_t buf_len; - int ok; - CBB cbb; - - if (!CBB_init(&cbb, 100)) { - return 0; - } - CBB_cleanup(&cbb); - - if (!CBB_init(&cbb, 0) || - !CBB_add_u8(&cbb, 1) || - !CBB_add_u16(&cbb, 0x203) || - !CBB_add_u24(&cbb, 0x40506) || - !CBB_add_bytes(&cbb, (const uint8_t*) "\x07\x08", 2) || - !CBB_finish(&cbb, &buf, &buf_len)) { - return 0; - } - - ok = buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) == 0; - free(buf); - return ok; +static int +test_cbb_basic(void) +{ + static const uint8_t kExpected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + uint8_t *buf; + size_t buf_len; + int ok; + CBB cbb; + + if (!CBB_init(&cbb, 100)) + return 0; + + CBB_cleanup(&cbb); + + if (!CBB_init(&cbb, 0) || + !CBB_add_u8(&cbb, 1) || + !CBB_add_u16(&cbb, 0x203) || + !CBB_add_u24(&cbb, 0x40506) || + !CBB_add_bytes(&cbb, (const uint8_t*) "\x07\x08", 2) || + !CBB_finish(&cbb, &buf, &buf_len)) + return 0; + + ok = buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) + == 0; + free(buf); + return ok; } -static int test_cbb_fixed(void) { - CBB cbb; - uint8_t buf[1]; - uint8_t *out_buf; - size_t out_size; - - if (!CBB_init_fixed(&cbb, NULL, 0) || - CBB_add_u8(&cbb, 1) || - !CBB_finish(&cbb, &out_buf, &out_size) || - out_buf != NULL || - out_size != 0) { - return 0; - } - - if (!CBB_init_fixed(&cbb, buf, 1) || - !CBB_add_u8(&cbb, 1) || - CBB_add_u8(&cbb, 2) || - !CBB_finish(&cbb, &out_buf, &out_size) || - out_buf != buf || - out_size != 1 || - buf[0] != 1) { - return 0; - } - - return 1; +static int +test_cbb_fixed(void) +{ + CBB cbb; + uint8_t buf[1]; + uint8_t *out_buf; + size_t out_size; + + if (!CBB_init_fixed(&cbb, NULL, 0) || + CBB_add_u8(&cbb, 1) || + !CBB_finish(&cbb, &out_buf, &out_size) || + out_buf != NULL || + out_size != 0) + return 0; + + if (!CBB_init_fixed(&cbb, buf, 1) || + !CBB_add_u8(&cbb, 1) || + CBB_add_u8(&cbb, 2) || + !CBB_finish(&cbb, &out_buf, &out_size) || + out_buf != buf || + out_size != 1 || + buf[0] != 1) + return 0; + + return 1; } -static int test_cbb_finish_child(void) { - CBB cbb, child; - uint8_t *out_buf; - size_t out_size; - - if (!CBB_init(&cbb, 16) || - !CBB_add_u8_length_prefixed(&cbb, &child) || - CBB_finish(&child, &out_buf, &out_size) || - !CBB_finish(&cbb, &out_buf, &out_size) || - out_size != 1 || - out_buf[0] != 0) { - return 0; - } - - free(out_buf); - return 1; +static int +test_cbb_finish_child(void) +{ + CBB cbb, child; + uint8_t *out_buf; + size_t out_size; + + if (!CBB_init(&cbb, 16) || + !CBB_add_u8_length_prefixed(&cbb, &child) || + CBB_finish(&child, &out_buf, &out_size) || + !CBB_finish(&cbb, &out_buf, &out_size) || + out_size != 1 || + out_buf[0] != 0) + return 0; + + free(out_buf); + return 1; } -static int test_cbb_prefixed(void) { - static const uint8_t kExpected[] = {0, 1, 1, 0, 2, 2, 3, 0, 0, 3, - 4, 5, 6, 5, 4, 1, 0, 1, 2}; - uint8_t *buf; - size_t buf_len; - CBB cbb, contents, inner_contents, inner_inner_contents; - int ok; - - if (!CBB_init(&cbb, 0) || - !CBB_add_u8_length_prefixed(&cbb, &contents) || - !CBB_add_u8_length_prefixed(&cbb, &contents) || - !CBB_add_u8(&contents, 1) || - !CBB_add_u16_length_prefixed(&cbb, &contents) || - !CBB_add_u16(&contents, 0x203) || - !CBB_add_u24_length_prefixed(&cbb, &contents) || - !CBB_add_u24(&contents, 0x40506) || - !CBB_add_u8_length_prefixed(&cbb, &contents) || - !CBB_add_u8_length_prefixed(&contents, &inner_contents) || - !CBB_add_u8(&inner_contents, 1) || - !CBB_add_u16_length_prefixed(&inner_contents, &inner_inner_contents) || - !CBB_add_u8(&inner_inner_contents, 2) || - !CBB_finish(&cbb, &buf, &buf_len)) { - return 0; - } - - ok = buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) == 0; - free(buf); - return ok; +static int +test_cbb_prefixed(void) +{ + static const uint8_t kExpected[] = {0, 1, 1, 0, 2, 2, 3, 0, 0, 3, + 4, 5, 6, 5, 4, 1, 0, 1, 2}; + uint8_t *buf; + size_t buf_len; + CBB cbb, contents, inner_contents, inner_inner_contents; + int ok; + + if (!CBB_init(&cbb, 0) || + !CBB_add_u8_length_prefixed(&cbb, &contents) || + !CBB_add_u8_length_prefixed(&cbb, &contents) || + !CBB_add_u8(&contents, 1) || + !CBB_add_u16_length_prefixed(&cbb, &contents) || + !CBB_add_u16(&contents, 0x203) || + !CBB_add_u24_length_prefixed(&cbb, &contents) || + !CBB_add_u24(&contents, 0x40506) || + !CBB_add_u8_length_prefixed(&cbb, &contents) || + !CBB_add_u8_length_prefixed(&contents, &inner_contents) || + !CBB_add_u8(&inner_contents, 1) || + !CBB_add_u16_length_prefixed(&inner_contents, + &inner_inner_contents) || + !CBB_add_u8(&inner_inner_contents, 2) || + !CBB_finish(&cbb, &buf, &buf_len)) + return 0; + + ok = buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) + == 0; + free(buf); + return ok; } -static int test_cbb_misuse(void) { - CBB cbb, child, contents; - uint8_t *buf; - size_t buf_len; - - if (!CBB_init(&cbb, 0) || - !CBB_add_u8_length_prefixed(&cbb, &child) || - !CBB_add_u8(&child, 1) || - !CBB_add_u8(&cbb, 2)) { - return 0; - } - - /* Since we wrote to |cbb|, |child| is now invalid and attempts to write to - * it should fail. */ - if (CBB_add_u8(&child, 1) || - CBB_add_u16(&child, 1) || - CBB_add_u24(&child, 1) || - CBB_add_u8_length_prefixed(&child, &contents) || - CBB_add_u16_length_prefixed(&child, &contents) || - CBB_add_asn1(&child, &contents, 1) || - CBB_add_bytes(&child, (const uint8_t*) "a", 1)) { - fprintf(stderr, "CBB operation on invalid CBB did not fail.\n"); - return 0; - } - - if (!CBB_finish(&cbb, &buf, &buf_len) || - buf_len != 3 || - memcmp(buf, "\x01\x01\x02", 3) != 0) { - return 0; - } - - free(buf); - - return 1; +static int +test_cbb_misuse(void) +{ + CBB cbb, child, contents; + uint8_t *buf; + size_t buf_len; + + if (!CBB_init(&cbb, 0) || + !CBB_add_u8_length_prefixed(&cbb, &child) || + !CBB_add_u8(&child, 1) || + !CBB_add_u8(&cbb, 2)) + return 0; + + /* + * Since we wrote to |cbb|, |child| is now invalid and attempts to write + * to it should fail. + */ + if (CBB_add_u8(&child, 1) || + CBB_add_u16(&child, 1) || + CBB_add_u24(&child, 1) || + CBB_add_u8_length_prefixed(&child, &contents) || + CBB_add_u16_length_prefixed(&child, &contents) || + CBB_add_asn1(&child, &contents, 1) || + CBB_add_bytes(&child, (const uint8_t*) "a", 1)) { + fprintf(stderr, "CBB operation on invalid CBB did not fail.\n"); + return 0; + } + + if (!CBB_finish(&cbb, &buf, &buf_len) || buf_len != 3 || + memcmp(buf, "\x01\x01\x02", 3) != 0) + return 0; + + free(buf); + + return 1; } -static int test_cbb_asn1(void) { - static const uint8_t kExpected[] = {0x30, 3, 1, 2, 3}; - uint8_t *buf, *test_data; - size_t buf_len; - CBB cbb, contents, inner_contents; - - if (!CBB_init(&cbb, 0) || - !CBB_add_asn1(&cbb, &contents, 0x30) || - !CBB_add_bytes(&contents, (const uint8_t*) "\x01\x02\x03", 3) || - !CBB_finish(&cbb, &buf, &buf_len)) { - return 0; - } - - if (buf_len != sizeof(kExpected) || memcmp(buf, kExpected, buf_len) != 0) { - return 0; - } - free(buf); - - test_data = malloc(100000); - memset(test_data, 0x42, 100000); - - if (!CBB_init(&cbb, 0) || - !CBB_add_asn1(&cbb, &contents, 0x30) || - !CBB_add_bytes(&contents, test_data, 130) || - !CBB_finish(&cbb, &buf, &buf_len)) { - return 0; - } - - if (buf_len != 3 + 130 || - memcmp(buf, "\x30\x81\x82", 3) != 0 || - memcmp(buf + 3, test_data, 130) != 0) { - return 0; - } - free(buf); - - if (!CBB_init(&cbb, 0) || - !CBB_add_asn1(&cbb, &contents, 0x30) || - !CBB_add_bytes(&contents, test_data, 1000) || - !CBB_finish(&cbb, &buf, &buf_len)) { - return 0; - } - - if (buf_len != 4 + 1000 || - memcmp(buf, "\x30\x82\x03\xe8", 4) != 0 || - memcmp(buf + 4, test_data, 1000)) { - return 0; - } - free(buf); - - if (!CBB_init(&cbb, 0) || - !CBB_add_asn1(&cbb, &contents, 0x30) || - !CBB_add_asn1(&contents, &inner_contents, 0x30) || - !CBB_add_bytes(&inner_contents, test_data, 100000) || - !CBB_finish(&cbb, &buf, &buf_len)) { - return 0; - } - - if (buf_len != 5 + 5 + 100000 || - memcmp(buf, "\x30\x83\x01\x86\xa5\x30\x83\x01\x86\xa0", 10) != 0 || - memcmp(buf + 10, test_data, 100000)) { - return 0; - } - free(buf); - - free(test_data); - return 1; +static int +test_cbb_asn1(void) +{ + static const uint8_t kExpected[] = {0x30, 3, 1, 2, 3}; + uint8_t *buf, *test_data; + size_t buf_len; + CBB cbb, contents, inner_contents; + + if (!CBB_init(&cbb, 0) || + !CBB_add_asn1(&cbb, &contents, 0x30) || + !CBB_add_bytes(&contents, (const uint8_t*) "\x01\x02\x03", 3) || + !CBB_finish(&cbb, &buf, &buf_len)) + return 0; + + if (buf_len != sizeof(kExpected) || memcmp(buf, kExpected, buf_len) + != 0) + return 0; + + free(buf); + + test_data = malloc(100000); + memset(test_data, 0x42, 100000); + + if (!CBB_init(&cbb, 0) || + !CBB_add_asn1(&cbb, &contents, 0x30) || + !CBB_add_bytes(&contents, test_data, 130) || + !CBB_finish(&cbb, &buf, &buf_len)) + return 0; + + if (buf_len != 3 + 130 || + memcmp(buf, "\x30\x81\x82", 3) != 0 || + memcmp(buf + 3, test_data, 130) != 0) { + return 0; + } + free(buf); + + if (!CBB_init(&cbb, 0) || + !CBB_add_asn1(&cbb, &contents, 0x30) || + !CBB_add_bytes(&contents, test_data, 1000) || + !CBB_finish(&cbb, &buf, &buf_len)) + return 0; + + if (buf_len != 4 + 1000 || + memcmp(buf, "\x30\x82\x03\xe8", 4) != 0 || + memcmp(buf + 4, test_data, 1000)) { + return 0; + } + free(buf); + + if (!CBB_init(&cbb, 0) || + !CBB_add_asn1(&cbb, &contents, 0x30) || + !CBB_add_asn1(&contents, &inner_contents, 0x30) || + !CBB_add_bytes(&inner_contents, test_data, 100000) || + !CBB_finish(&cbb, &buf, &buf_len)) + return 0; + + if (buf_len != 5 + 5 + 100000 || + memcmp(buf, "\x30\x83\x01\x86\xa5\x30\x83\x01\x86\xa0", 10) != 0 || + memcmp(buf + 10, test_data, 100000)) + return 0; + + free(buf); + free(test_data); + + return 1; } -static int do_ber_convert(const char *name, - const uint8_t *der_expected, size_t der_len, - const uint8_t *ber, size_t ber_len) { - CBS in; - uint8_t *out; - size_t out_len; - - CBS_init(&in, ber, ber_len); - if (!CBS_asn1_ber_to_der(&in, &out, &out_len)) { - fprintf(stderr, "%s: CBS_asn1_ber_to_der failed.\n", name); - return 0; - } - - if (out == NULL) { - if (ber_len != der_len || - memcmp(der_expected, ber, ber_len) != 0) { - fprintf(stderr, "%s: incorrect unconverted result.\n", name); - return 0; - } - - return 1; - } - - if (out_len != der_len || - memcmp(out, der_expected, der_len) != 0) { - fprintf(stderr, "%s: incorrect converted result.\n", name); - return 0; - } - - free(out); - return 1; +static int +do_ber_convert(const char *name, const uint8_t *der_expected, size_t der_len, + const uint8_t *ber, size_t ber_len) +{ + CBS in; + uint8_t *out; + size_t out_len; + + CBS_init(&in, ber, ber_len); + if (!CBS_asn1_ber_to_der(&in, &out, &out_len)) { + fprintf(stderr, "%s: CBS_asn1_ber_to_der failed.\n", name); + return 0; + } + + if (out == NULL) { + if (ber_len != der_len || + memcmp(der_expected, ber, ber_len) != 0) { + fprintf(stderr, "%s: incorrect unconverted result.\n", + name); + return 0; + } + + return 1; + } + + if (out_len != der_len || memcmp(out, der_expected, der_len) != 0) { + fprintf(stderr, "%s: incorrect converted result.\n", name); + return 0; + } + + free(out); + return 1; } -static int test_ber_convert(void) { - static const uint8_t kSimpleBER[] = {0x01, 0x01, 0x00}; - - /* kIndefBER contains a SEQUENCE with an indefinite length. */ - static const uint8_t kIndefBER[] = {0x30, 0x80, 0x01, 0x01, 0x02, 0x00, 0x00}; - static const uint8_t kIndefDER[] = {0x30, 0x03, 0x01, 0x01, 0x02}; - - /* kOctetStringBER contains an indefinite length OCTETSTRING with two parts. - * These parts need to be concatenated in DER form. */ - static const uint8_t kOctetStringBER[] = {0x24, 0x80, 0x04, 0x02, 0, 1, - 0x04, 0x02, 2, 3, 0x00, 0x00}; - static const uint8_t kOctetStringDER[] = {0x04, 0x04, 0, 1, 2, 3}; - - /* kNSSBER is part of a PKCS#12 message generated by NSS that uses indefinite - * length elements extensively. */ - static const uint8_t kNSSBER[] = { - 0x30, 0x80, 0x02, 0x01, 0x03, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, - 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x80, 0x24, 0x80, 0x04, 0x04, - 0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x39, - 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, - 0x00, 0x04, 0x14, 0x84, 0x98, 0xfc, 0x66, 0x33, 0xee, 0xba, 0xe7, 0x90, - 0xc1, 0xb6, 0xe8, 0x8f, 0xfe, 0x1d, 0xc5, 0xa5, 0x97, 0x93, 0x3e, 0x04, - 0x10, 0x38, 0x62, 0xc6, 0x44, 0x12, 0xd5, 0x30, 0x00, 0xf8, 0xf2, 0x1b, - 0xf0, 0x6e, 0x10, 0x9b, 0xb8, 0x02, 0x02, 0x07, 0xd0, 0x00, 0x00, - }; - - static const uint8_t kNSSDER[] = { - 0x30, 0x53, 0x02, 0x01, 0x03, 0x30, 0x13, 0x06, 0x09, 0x2a, 0x86, - 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x06, 0x04, 0x04, - 0x01, 0x02, 0x03, 0x04, 0x30, 0x39, 0x30, 0x21, 0x30, 0x09, 0x06, - 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x84, - 0x98, 0xfc, 0x66, 0x33, 0xee, 0xba, 0xe7, 0x90, 0xc1, 0xb6, 0xe8, - 0x8f, 0xfe, 0x1d, 0xc5, 0xa5, 0x97, 0x93, 0x3e, 0x04, 0x10, 0x38, - 0x62, 0xc6, 0x44, 0x12, 0xd5, 0x30, 0x00, 0xf8, 0xf2, 0x1b, 0xf0, - 0x6e, 0x10, 0x9b, 0xb8, 0x02, 0x02, 0x07, 0xd0, - }; - - return do_ber_convert("kSimpleBER", kSimpleBER, sizeof(kSimpleBER), - kSimpleBER, sizeof(kSimpleBER)) && - do_ber_convert("kIndefBER", kIndefDER, sizeof(kIndefDER), kIndefBER, - sizeof(kIndefBER)) && - do_ber_convert("kOctetStringBER", kOctetStringDER, - sizeof(kOctetStringDER), kOctetStringBER, - sizeof(kOctetStringBER)) && - do_ber_convert("kNSSBER", kNSSDER, sizeof(kNSSDER), kNSSBER, - sizeof(kNSSBER)); +static int +test_ber_convert(void) +{ + static const uint8_t kSimpleBER[] = {0x01, 0x01, 0x00}; + + /* kIndefBER contains a SEQUENCE with an indefinite length. */ + static const uint8_t kIndefBER[] = {0x30, 0x80, 0x01, 0x01, 0x02, 0x00, + 0x00}; + static const uint8_t kIndefDER[] = {0x30, 0x03, 0x01, 0x01, 0x02}; + + /* + * kOctetStringBER contains an indefinite length OCTETSTRING with two + * parts. These parts need to be concatenated in DER form. + */ + static const uint8_t kOctetStringBER[] = {0x24, 0x80, 0x04, 0x02, 0, + 1, 0x04, 0x02, 2, 3, 0x00, 0x00}; + static const uint8_t kOctetStringDER[] = {0x04, 0x04, 0, 1, 2, 3}; + + /* + * kNSSBER is part of a PKCS#12 message generated by NSS that uses + * indefinite length elements extensively. + */ + static const uint8_t kNSSBER[] = { + 0x30, 0x80, 0x02, 0x01, 0x03, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x80, 0x24, 0x80, + 0x04, 0x04, 0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x39, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, + 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x84, 0x98, 0xfc, 0x66, + 0x33, 0xee, 0xba, 0xe7, 0x90, 0xc1, 0xb6, 0xe8, 0x8f, 0xfe, 0x1d, + 0xc5, 0xa5, 0x97, 0x93, 0x3e, 0x04, 0x10, 0x38, 0x62, 0xc6, 0x44, + 0x12, 0xd5, 0x30, 0x00, 0xf8, 0xf2, 0x1b, 0xf0, 0x6e, 0x10, 0x9b, + 0xb8, 0x02, 0x02, 0x07, 0xd0, 0x00, 0x00, + }; + + static const uint8_t kNSSDER[] = { + 0x30, 0x53, 0x02, 0x01, 0x03, 0x30, 0x13, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x06, 0x04, 0x04, + 0x01, 0x02, 0x03, 0x04, 0x30, 0x39, 0x30, 0x21, 0x30, 0x09, 0x06, + 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x84, + 0x98, 0xfc, 0x66, 0x33, 0xee, 0xba, 0xe7, 0x90, 0xc1, 0xb6, 0xe8, + 0x8f, 0xfe, 0x1d, 0xc5, 0xa5, 0x97, 0x93, 0x3e, 0x04, 0x10, 0x38, + 0x62, 0xc6, 0x44, 0x12, 0xd5, 0x30, 0x00, 0xf8, 0xf2, 0x1b, 0xf0, + 0x6e, 0x10, 0x9b, 0xb8, 0x02, 0x02, 0x07, 0xd0, + }; + + return do_ber_convert("kSimpleBER", kSimpleBER, sizeof(kSimpleBER), + kSimpleBER, sizeof(kSimpleBER)) && + do_ber_convert("kIndefBER", kIndefDER, sizeof(kIndefDER), kIndefBER, + sizeof(kIndefBER)) && + do_ber_convert("kOctetStringBER", kOctetStringDER, + sizeof(kOctetStringDER), kOctetStringBER, + sizeof(kOctetStringBER)) && + do_ber_convert("kNSSBER", kNSSDER, sizeof(kNSSDER), kNSSBER, + sizeof(kNSSBER)); } typedef struct { - uint64_t value; - const char *encoding; - size_t encoding_len; + uint64_t value; + const char *encoding; + size_t encoding_len; } ASN1_UINT64_TEST; static const ASN1_UINT64_TEST kAsn1Uint64Tests[] = { - {0, "\x02\x01\x00", 3}, - {1, "\x02\x01\x01", 3}, - {127, "\x02\x01\x7f", 3}, - {128, "\x02\x02\x00\x80", 4}, - {0xdeadbeef, "\x02\x05\x00\xde\xad\xbe\xef", 7}, - {OPENSSL_U64(0x0102030405060708), - "\x02\x08\x01\x02\x03\x04\x05\x06\x07\x08", 10}, - {OPENSSL_U64(0xffffffffffffffff), - "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff", 11}, + {0, "\x02\x01\x00", 3}, + {1, "\x02\x01\x01", 3}, + {127, "\x02\x01\x7f", 3}, + {128, "\x02\x02\x00\x80", 4}, + {0xdeadbeef, "\x02\x05\x00\xde\xad\xbe\xef", 7}, + {OPENSSL_U64(0x0102030405060708), + "\x02\x08\x01\x02\x03\x04\x05\x06\x07\x08", 10}, + {OPENSSL_U64(0xffffffffffffffff), + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff", 11}, }; typedef struct { - const char *encoding; - size_t encoding_len; + const char *encoding; + size_t encoding_len; } ASN1_INVALID_UINT64_TEST; static const ASN1_INVALID_UINT64_TEST kAsn1InvalidUint64Tests[] = { - /* Bad tag. */ - {"\x03\x01\x00", 3}, - /* Empty contents. */ - {"\x02\x00", 2}, - /* Negative number. */ - {"\x02\x01\x80", 3}, - /* Overflow */ - {"\x02\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00", 11}, + /* Bad tag. */ + {"\x03\x01\x00", 3}, + /* Empty contents. */ + {"\x02\x00", 2}, + /* Negative number. */ + {"\x02\x01\x80", 3}, + /* Overflow */ + {"\x02\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00", 11}, }; -static int test_asn1_uint64(void) { - size_t i; - - for (i = 0; i < sizeof(kAsn1Uint64Tests) / sizeof(kAsn1Uint64Tests[0]); i++) { - const ASN1_UINT64_TEST *test = &kAsn1Uint64Tests[i]; - CBS cbs; - uint64_t value; - CBB cbb; - uint8_t *out; - size_t len; - - CBS_init(&cbs, (const uint8_t *)test->encoding, test->encoding_len); - if (!CBS_get_asn1_uint64(&cbs, &value) || - CBS_len(&cbs) != 0 || - value != test->value) { - return 0; - } - - if (!CBB_init(&cbb, 0)) { - return 0; - } - if (!CBB_add_asn1_uint64(&cbb, test->value) || - !CBB_finish(&cbb, &out, &len)) { - CBB_cleanup(&cbb); - return 0; - } - if (len != test->encoding_len || memcmp(out, test->encoding, len) != 0) { - free(out); - return 0; - } - free(out); - } - - for (i = 0; - i < sizeof(kAsn1InvalidUint64Tests) / sizeof(kAsn1InvalidUint64Tests[0]); - i++) { - const ASN1_INVALID_UINT64_TEST *test = &kAsn1InvalidUint64Tests[i]; - CBS cbs; - uint64_t value; - - CBS_init(&cbs, (const uint8_t *)test->encoding, test->encoding_len); - if (CBS_get_asn1_uint64(&cbs, &value)) { - return 0; - } - } - - return 1; +static int +test_asn1_uint64(void) +{ + size_t i; + + for (i = 0; i < sizeof(kAsn1Uint64Tests) / sizeof(kAsn1Uint64Tests[0]); + i++) { + const ASN1_UINT64_TEST *test = &kAsn1Uint64Tests[i]; + CBS cbs; + uint64_t value; + CBB cbb; + uint8_t *out; + size_t len; + + CBS_init(&cbs, (const uint8_t *)test->encoding, + test->encoding_len); + + if (!CBS_get_asn1_uint64(&cbs, &value) || + CBS_len(&cbs) != 0 || + value != test->value) + return 0; + + if (!CBB_init(&cbb, 0)) + return 0; + + if (!CBB_add_asn1_uint64(&cbb, test->value) || + !CBB_finish(&cbb, &out, &len)) { + CBB_cleanup(&cbb); + return 0; + } + + if (len != test->encoding_len || memcmp(out, test->encoding, + len) != 0) { + free(out); + return 0; + } + free(out); + } + + for (i = 0; i < sizeof(kAsn1InvalidUint64Tests) + / sizeof(kAsn1InvalidUint64Tests[0]); i++) { + const ASN1_INVALID_UINT64_TEST *test = + &kAsn1InvalidUint64Tests[i]; + CBS cbs; + uint64_t value; + + CBS_init(&cbs, (const uint8_t *)test->encoding, + test->encoding_len); + if (CBS_get_asn1_uint64(&cbs, &value)) + return 0; + } + + return 1; } -int main(void) { - if (!test_skip() || - !test_get_u() || - !test_get_prefixed() || - !test_get_prefixed_bad() || - !test_get_asn1() || - !test_cbb_basic() || - !test_cbb_fixed() || - !test_cbb_finish_child() || - !test_cbb_misuse() || - !test_cbb_prefixed() || - !test_cbb_asn1() || - !test_ber_convert() || - !test_asn1_uint64() || - !test_get_optional_asn1_bool()) { - return 1; - } - - printf("PASS\n"); - return 0; +int +main(void) +{ + if (!test_skip() || + !test_get_u() || + !test_get_prefixed() || + !test_get_prefixed_bad() || + !test_get_asn1() || + !test_cbb_basic() || + !test_cbb_fixed() || + !test_cbb_finish_child() || + !test_cbb_misuse() || + !test_cbb_prefixed() || + !test_cbb_asn1() || + !test_ber_convert() || + !test_asn1_uint64() || + !test_get_optional_asn1_bool()) + return 1; + + printf("PASS\n"); + return 0; } |