From a0cb4a2b0a0d4d75a998e970846e9d9e9dc4432c Mon Sep 17 00:00:00 2001 From: doug <> Date: Fri, 6 Feb 2015 22:22:33 +0000 Subject: 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. --- src/lib/libssl/bs_ber.c | 390 +++++++++++---------- src/lib/libssl/bs_cbb.c | 611 +++++++++++++++++---------------- src/lib/libssl/bs_cbs.c | 663 +++++++++++++++++++----------------- src/lib/libssl/bytestring.h | 340 +++++++++++------- src/lib/libssl/src/ssl/bs_ber.c | 390 +++++++++++---------- src/lib/libssl/src/ssl/bs_cbb.c | 611 +++++++++++++++++---------------- src/lib/libssl/src/ssl/bs_cbs.c | 663 +++++++++++++++++++----------------- src/lib/libssl/src/ssl/bytestring.h | 340 +++++++++++------- 8 files changed, 2192 insertions(+), 1816 deletions(-) (limited to 'src/lib') diff --git a/src/lib/libssl/bs_ber.c b/src/lib/libssl/bs_ber.c index b94b63e37e..cfc9475f9a 100644 --- a/src/lib/libssl/bs_ber.c +++ b/src/lib/libssl/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/src/lib/libssl/bs_cbb.c b/src/lib/libssl/bs_cbb.c index 11688bcb7b..94ca54f43b 100644 --- a/src/lib/libssl/bs_cbb.c +++ b/src/lib/libssl/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/src/lib/libssl/bs_cbs.c b/src/lib/libssl/bs_cbs.c index 7edfe65288..c3d3a8abf2 100644 --- a/src/lib/libssl/bs_cbs.c +++ b/src/lib/libssl/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/src/lib/libssl/bytestring.h b/src/lib/libssl/bytestring.h index 3c4e8eaaf3..09414af056 100644 --- a/src/lib/libssl/bytestring.h +++ b/src/lib/libssl/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 -/* 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/src/lib/libssl/src/ssl/bs_ber.c b/src/lib/libssl/src/ssl/bs_ber.c index b94b63e37e..cfc9475f9a 100644 --- a/src/lib/libssl/src/ssl/bs_ber.c +++ b/src/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/src/lib/libssl/src/ssl/bs_cbb.c b/src/lib/libssl/src/ssl/bs_cbb.c index 11688bcb7b..94ca54f43b 100644 --- a/src/lib/libssl/src/ssl/bs_cbb.c +++ b/src/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/src/lib/libssl/src/ssl/bs_cbs.c b/src/lib/libssl/src/ssl/bs_cbs.c index 7edfe65288..c3d3a8abf2 100644 --- a/src/lib/libssl/src/ssl/bs_cbs.c +++ b/src/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/src/lib/libssl/src/ssl/bytestring.h b/src/lib/libssl/src/ssl/bytestring.h index 3c4e8eaaf3..09414af056 100644 --- a/src/lib/libssl/src/ssl/bytestring.h +++ b/src/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 -/* 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 */ -- cgit v1.2.3-55-g6feb