commit f22eb2730cccab44de579c64ba2386a94abef0fa Author: David Goulet dgoulet@torproject.org Date: Mon Aug 29 15:28:58 2016 -0400
prop224: Add ESTABLISH_INTRO and INTRO_ESTABLISHED trunnel definition
Signed-off-by: David Goulet dgoulet@torproject.org --- src/trunnel/hs/cell_common.c | 594 ++++++++++++++++++++++ src/trunnel/hs/cell_common.h | 198 ++++++++ src/trunnel/hs/cell_common.trunnel | 12 + src/trunnel/hs/cell_establish_intro.c | 735 ++++++++++++++++++++++++++++ src/trunnel/hs/cell_establish_intro.h | 275 +++++++++++ src/trunnel/hs/cell_establish_intro.trunnel | 41 ++ src/trunnel/include.am | 13 +- 7 files changed, 1863 insertions(+), 5 deletions(-)
diff --git a/src/trunnel/hs/cell_common.c b/src/trunnel/hs/cell_common.c new file mode 100644 index 0000000..c6c610d --- /dev/null +++ b/src/trunnel/hs/cell_common.c @@ -0,0 +1,594 @@ +/* cell_common.c -- generated by Trunnel v1.5. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#include <stdlib.h> +#include "trunnel-impl.h" + +#include "cell_common.h" + +#define TRUNNEL_SET_ERROR_CODE(obj) \ + do { \ + (obj)->trunnel_error_code_ = 1; \ + } while (0) + +#if defined(__COVERITY__) || defined(__clang_analyzer__) +/* If we're runnning a static analysis tool, we don't want it to complain + * that some of our remaining-bytes checks are dead-code. */ +int cellcommon_deadcode_dummy__ = 0; +#define OR_DEADCODE_DUMMY || cellcommon_deadcode_dummy__ +#else +#define OR_DEADCODE_DUMMY +#endif + +#define CHECK_REMAINING(nbytes, label) \ + do { \ + if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \ + goto label; \ + } \ + } while (0) + +cell_extension_fields_t * +cell_extension_fields_new(void) +{ + cell_extension_fields_t *val = trunnel_calloc(1, sizeof(cell_extension_fields_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +cell_extension_fields_clear(cell_extension_fields_t *obj) +{ + (void) obj; + TRUNNEL_DYNARRAY_WIPE(&obj->field); + TRUNNEL_DYNARRAY_CLEAR(&obj->field); +} + +void +cell_extension_fields_free(cell_extension_fields_t *obj) +{ + if (obj == NULL) + return; + cell_extension_fields_clear(obj); + trunnel_memwipe(obj, sizeof(cell_extension_fields_t)); + trunnel_free_(obj); +} + +uint8_t +cell_extension_fields_get_field_type(cell_extension_fields_t *inp) +{ + return inp->field_type; +} +int +cell_extension_fields_set_field_type(cell_extension_fields_t *inp, uint8_t val) +{ + inp->field_type = val; + return 0; +} +uint8_t +cell_extension_fields_get_field_len(cell_extension_fields_t *inp) +{ + return inp->field_len; +} +int +cell_extension_fields_set_field_len(cell_extension_fields_t *inp, uint8_t val) +{ + inp->field_len = val; + return 0; +} +size_t +cell_extension_fields_getlen_field(const cell_extension_fields_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->field); +} + +uint8_t +cell_extension_fields_get_field(cell_extension_fields_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->field, idx); +} + +uint8_t +cell_extension_fields_getconst_field(const cell_extension_fields_t *inp, size_t idx) +{ + return cell_extension_fields_get_field((cell_extension_fields_t*)inp, idx); +} +int +cell_extension_fields_set_field(cell_extension_fields_t *inp, size_t idx, uint8_t elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->field, idx, elt); + return 0; +} +int +cell_extension_fields_add_field(cell_extension_fields_t *inp, uint8_t elt) +{ +#if SIZE_MAX >= UINT8_MAX + if (inp->field.n_ == UINT8_MAX) + goto trunnel_alloc_failed; +#endif + TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->field, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +uint8_t * +cell_extension_fields_getarray_field(cell_extension_fields_t *inp) +{ + return inp->field.elts_; +} +const uint8_t * +cell_extension_fields_getconstarray_field(const cell_extension_fields_t *inp) +{ + return (const uint8_t *)cell_extension_fields_getarray_field((cell_extension_fields_t*)inp); +} +int +cell_extension_fields_setlen_field(cell_extension_fields_t *inp, size_t newlen) +{ + uint8_t *newptr; +#if UINT8_MAX < SIZE_MAX + if (newlen > UINT8_MAX) + goto trunnel_alloc_failed; +#endif + newptr = trunnel_dynarray_setlen(&inp->field.allocated_, + &inp->field.n_, inp->field.elts_, newlen, + sizeof(inp->field.elts_[0]), (trunnel_free_fn_t) NULL, + &inp->trunnel_error_code_); + if (newlen != 0 && newptr == NULL) + goto trunnel_alloc_failed; + inp->field.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +const char * +cell_extension_fields_check(const cell_extension_fields_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + if (TRUNNEL_DYNARRAY_LEN(&obj->field) != obj->field_len) + return "Length mismatch for field"; + return NULL; +} + +ssize_t +cell_extension_fields_encoded_len(const cell_extension_fields_t *obj) +{ + ssize_t result = 0; + + if (NULL != cell_extension_fields_check(obj)) + return -1; + + + /* Length of u8 field_type */ + result += 1; + + /* Length of u8 field_len */ + result += 1; + + /* Length of u8 field[field_len] */ + result += TRUNNEL_DYNARRAY_LEN(&obj->field); + return result; +} +int +cell_extension_fields_clear_errors(cell_extension_fields_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +cell_extension_fields_encode(uint8_t *output, const size_t avail, const cell_extension_fields_t *obj) +{ + ssize_t result = 0; + size_t written = 0; + uint8_t *ptr = output; + const char *msg; +#ifdef TRUNNEL_CHECK_ENCODED_LEN + const ssize_t encoded_len = cell_extension_fields_encoded_len(obj); +#endif + + if (NULL != (msg = cell_extension_fields_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 field_type */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->field_type)); + written += 1; ptr += 1; + + /* Encode u8 field_len */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->field_len)); + written += 1; ptr += 1; + + /* Encode u8 field[field_len] */ + { + size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->field); + trunnel_assert(obj->field_len == elt_len); + trunnel_assert(written <= avail); + if (avail - written < elt_len) + goto truncated; + if (elt_len) + memcpy(ptr, obj->field.elts_, elt_len); + written += elt_len; ptr += elt_len; + } + + + trunnel_assert(ptr == output + written); +#ifdef TRUNNEL_CHECK_ENCODED_LEN + { + trunnel_assert(encoded_len >= 0); + trunnel_assert((size_t)encoded_len == written); + } + +#endif + + return written; + + truncated: + result = -2; + goto fail; + check_failed: + (void)msg; + result = -1; + goto fail; + fail: + trunnel_assert(result < 0); + return result; +} + +/** As cell_extension_fields_parse(), but do not allocate the output + * object. + */ +static ssize_t +cell_extension_fields_parse_into(cell_extension_fields_t *obj, const uint8_t *input, const size_t len_in) +{ + const uint8_t *ptr = input; + size_t remaining = len_in; + ssize_t result = 0; + (void)result; + + /* Parse u8 field_type */ + CHECK_REMAINING(1, truncated); + obj->field_type = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + + /* Parse u8 field_len */ + CHECK_REMAINING(1, truncated); + obj->field_len = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + + /* Parse u8 field[field_len] */ + CHECK_REMAINING(obj->field_len, truncated); + TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->field, obj->field_len, {}); + obj->field.n_ = obj->field_len; + if (obj->field_len) + memcpy(obj->field.elts_, ptr, obj->field_len); + ptr += obj->field_len; remaining -= obj->field_len; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + trunnel_alloc_failed: + return -1; +} + +ssize_t +cell_extension_fields_parse(cell_extension_fields_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = cell_extension_fields_new(); + if (NULL == *output) + return -1; + result = cell_extension_fields_parse_into(*output, input, len_in); + if (result < 0) { + cell_extension_fields_free(*output); + *output = NULL; + } + return result; +} +cell_extension_t * +cell_extension_new(void) +{ + cell_extension_t *val = trunnel_calloc(1, sizeof(cell_extension_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +cell_extension_clear(cell_extension_t *obj) +{ + (void) obj; + { + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->fields); ++idx) { + cell_extension_fields_free(TRUNNEL_DYNARRAY_GET(&obj->fields, idx)); + } + } + TRUNNEL_DYNARRAY_WIPE(&obj->fields); + TRUNNEL_DYNARRAY_CLEAR(&obj->fields); +} + +void +cell_extension_free(cell_extension_t *obj) +{ + if (obj == NULL) + return; + cell_extension_clear(obj); + trunnel_memwipe(obj, sizeof(cell_extension_t)); + trunnel_free_(obj); +} + +uint8_t +cell_extension_get_num(cell_extension_t *inp) +{ + return inp->num; +} +int +cell_extension_set_num(cell_extension_t *inp, uint8_t val) +{ + inp->num = val; + return 0; +} +size_t +cell_extension_getlen_fields(const cell_extension_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->fields); +} + +struct cell_extension_fields_st * +cell_extension_get_fields(cell_extension_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->fields, idx); +} + + const struct cell_extension_fields_st * +cell_extension_getconst_fields(const cell_extension_t *inp, size_t idx) +{ + return cell_extension_get_fields((cell_extension_t*)inp, idx); +} +int +cell_extension_set_fields(cell_extension_t *inp, size_t idx, struct cell_extension_fields_st * elt) +{ + cell_extension_fields_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->fields, idx); + if (oldval && oldval != elt) + cell_extension_fields_free(oldval); + return cell_extension_set0_fields(inp, idx, elt); +} +int +cell_extension_set0_fields(cell_extension_t *inp, size_t idx, struct cell_extension_fields_st * elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->fields, idx, elt); + return 0; +} +int +cell_extension_add_fields(cell_extension_t *inp, struct cell_extension_fields_st * elt) +{ +#if SIZE_MAX >= UINT8_MAX + if (inp->fields.n_ == UINT8_MAX) + goto trunnel_alloc_failed; +#endif + TRUNNEL_DYNARRAY_ADD(struct cell_extension_fields_st *, &inp->fields, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +struct cell_extension_fields_st * * +cell_extension_getarray_fields(cell_extension_t *inp) +{ + return inp->fields.elts_; +} +const struct cell_extension_fields_st * const * +cell_extension_getconstarray_fields(const cell_extension_t *inp) +{ + return (const struct cell_extension_fields_st * const *)cell_extension_getarray_fields((cell_extension_t*)inp); +} +int +cell_extension_setlen_fields(cell_extension_t *inp, size_t newlen) +{ + struct cell_extension_fields_st * *newptr; +#if UINT8_MAX < SIZE_MAX + if (newlen > UINT8_MAX) + goto trunnel_alloc_failed; +#endif + newptr = trunnel_dynarray_setlen(&inp->fields.allocated_, + &inp->fields.n_, inp->fields.elts_, newlen, + sizeof(inp->fields.elts_[0]), (trunnel_free_fn_t) cell_extension_fields_free, + &inp->trunnel_error_code_); + if (newlen != 0 && newptr == NULL) + goto trunnel_alloc_failed; + inp->fields.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +const char * +cell_extension_check(const cell_extension_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + { + const char *msg; + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->fields); ++idx) { + if (NULL != (msg = cell_extension_fields_check(TRUNNEL_DYNARRAY_GET(&obj->fields, idx)))) + return msg; + } + } + if (TRUNNEL_DYNARRAY_LEN(&obj->fields) != obj->num) + return "Length mismatch for fields"; + return NULL; +} + +ssize_t +cell_extension_encoded_len(const cell_extension_t *obj) +{ + ssize_t result = 0; + + if (NULL != cell_extension_check(obj)) + return -1; + + + /* Length of u8 num */ + result += 1; + + /* Length of struct cell_extension_fields fields[num] */ + { + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->fields); ++idx) { + result += cell_extension_fields_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->fields, idx)); + } + } + return result; +} +int +cell_extension_clear_errors(cell_extension_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +cell_extension_encode(uint8_t *output, const size_t avail, const cell_extension_t *obj) +{ + ssize_t result = 0; + size_t written = 0; + uint8_t *ptr = output; + const char *msg; +#ifdef TRUNNEL_CHECK_ENCODED_LEN + const ssize_t encoded_len = cell_extension_encoded_len(obj); +#endif + + if (NULL != (msg = cell_extension_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 num */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->num)); + written += 1; ptr += 1; + + /* Encode struct cell_extension_fields fields[num] */ + { + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->fields); ++idx) { + trunnel_assert(written <= avail); + result = cell_extension_fields_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->fields, idx)); + if (result < 0) + goto fail; /* XXXXXXX !*/ + written += result; ptr += result; + } + } + + + trunnel_assert(ptr == output + written); +#ifdef TRUNNEL_CHECK_ENCODED_LEN + { + trunnel_assert(encoded_len >= 0); + trunnel_assert((size_t)encoded_len == written); + } + +#endif + + return written; + + truncated: + result = -2; + goto fail; + check_failed: + (void)msg; + result = -1; + goto fail; + fail: + trunnel_assert(result < 0); + return result; +} + +/** As cell_extension_parse(), but do not allocate the output object. + */ +static ssize_t +cell_extension_parse_into(cell_extension_t *obj, const uint8_t *input, const size_t len_in) +{ + const uint8_t *ptr = input; + size_t remaining = len_in; + ssize_t result = 0; + (void)result; + + /* Parse u8 num */ + CHECK_REMAINING(1, truncated); + obj->num = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + + /* Parse struct cell_extension_fields fields[num] */ + TRUNNEL_DYNARRAY_EXPAND(cell_extension_fields_t *, &obj->fields, obj->num, {}); + { + cell_extension_fields_t * elt; + unsigned idx; + for (idx = 0; idx < obj->num; ++idx) { + result = cell_extension_fields_parse(&elt, ptr, remaining); + if (result < 0) + goto relay_fail; + trunnel_assert((size_t)result <= remaining); + remaining -= result; ptr += result; + TRUNNEL_DYNARRAY_ADD(cell_extension_fields_t *, &obj->fields, elt, {cell_extension_fields_free(elt);}); + } + } + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + relay_fail: + trunnel_assert(result < 0); + return result; + trunnel_alloc_failed: + return -1; +} + +ssize_t +cell_extension_parse(cell_extension_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = cell_extension_new(); + if (NULL == *output) + return -1; + result = cell_extension_parse_into(*output, input, len_in); + if (result < 0) { + cell_extension_free(*output); + *output = NULL; + } + return result; +} diff --git a/src/trunnel/hs/cell_common.h b/src/trunnel/hs/cell_common.h new file mode 100644 index 0000000..3c847f7 --- /dev/null +++ b/src/trunnel/hs/cell_common.h @@ -0,0 +1,198 @@ +/* cell_common.h -- generated by by Trunnel v1.5. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#ifndef TRUNNEL_CELL_COMMON_H +#define TRUNNEL_CELL_COMMON_H + +#include <stdint.h> +#include "trunnel.h" + +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_CELL_EXTENSION_FIELDS) +struct cell_extension_fields_st { + uint8_t field_type; + uint8_t field_len; + TRUNNEL_DYNARRAY_HEAD(, uint8_t) field; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct cell_extension_fields_st cell_extension_fields_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_CELL_EXTENSION) +struct cell_extension_st { + uint8_t num; + TRUNNEL_DYNARRAY_HEAD(, struct cell_extension_fields_st *) fields; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct cell_extension_st cell_extension_t; +/** Return a newly allocated cell_extension_fields with all elements + * set to zero. + */ +cell_extension_fields_t *cell_extension_fields_new(void); +/** Release all storage held by the cell_extension_fields in 'victim'. + * (Do nothing if 'victim' is NULL.) + */ +void cell_extension_fields_free(cell_extension_fields_t *victim); +/** Try to parse a cell_extension_fields from the buffer in 'input', + * using up to 'len_in' bytes from the input buffer. On success, + * return the number of bytes consumed and set *output to the newly + * allocated cell_extension_fields_t. On failure, return -2 if the + * input appears truncated, and -1 if the input is otherwise invalid. + */ +ssize_t cell_extension_fields_parse(cell_extension_fields_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * cell_extension_fields in 'obj'. On failure, return a negative + * value. Note that this value may be an overestimate, and can even be + * an underestimate for certain unencodeable objects. + */ +ssize_t cell_extension_fields_encoded_len(const cell_extension_fields_t *obj); +/** Try to encode the cell_extension_fields from 'input' into the + * buffer at 'output', using up to 'avail' bytes of the output buffer. + * On success, return the number of bytes used. On failure, return -2 + * if the buffer was not long enough, and -1 if the input was invalid. + */ +ssize_t cell_extension_fields_encode(uint8_t *output, size_t avail, const cell_extension_fields_t *input); +/** Check whether the internal state of the cell_extension_fields in + * 'obj' is consistent. Return NULL if it is, and a short message if + * it is not. + */ +const char *cell_extension_fields_check(const cell_extension_fields_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int cell_extension_fields_clear_errors(cell_extension_fields_t *obj); +/** Return the value of the field_type field of the + * cell_extension_fields_t in 'inp' + */ +uint8_t cell_extension_fields_get_field_type(cell_extension_fields_t *inp); +/** Set the value of the field_type field of the + * cell_extension_fields_t in 'inp' to 'val'. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int cell_extension_fields_set_field_type(cell_extension_fields_t *inp, uint8_t val); +/** Return the value of the field_len field of the + * cell_extension_fields_t in 'inp' + */ +uint8_t cell_extension_fields_get_field_len(cell_extension_fields_t *inp); +/** Set the value of the field_len field of the + * cell_extension_fields_t in 'inp' to 'val'. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int cell_extension_fields_set_field_len(cell_extension_fields_t *inp, uint8_t val); +/** Return the length of the dynamic array holding the field field of + * the cell_extension_fields_t in 'inp'. + */ +size_t cell_extension_fields_getlen_field(const cell_extension_fields_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * field of the cell_extension_fields_t in 'inp'. + */ +uint8_t cell_extension_fields_get_field(cell_extension_fields_t *inp, size_t idx); +/** As cell_extension_fields_get_field, but take and return a const + * pointer + */ +uint8_t cell_extension_fields_getconst_field(const cell_extension_fields_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * field of the cell_extension_fields_t in 'inp', so that it will hold + * the value 'elt'. + */ +int cell_extension_fields_set_field(cell_extension_fields_t *inp, size_t idx, uint8_t elt); +/** Append a new element 'elt' to the dynamic array field field of the + * cell_extension_fields_t in 'inp'. + */ +int cell_extension_fields_add_field(cell_extension_fields_t *inp, uint8_t elt); +/** Return a pointer to the variable-length array field field of + * 'inp'. + */ +uint8_t * cell_extension_fields_getarray_field(cell_extension_fields_t *inp); +/** As cell_extension_fields_get_field, but take and return a const + * pointer + */ +const uint8_t * cell_extension_fields_getconstarray_field(const cell_extension_fields_t *inp); +/** Change the length of the variable-length array field field of + * 'inp' to 'newlen'.Fill extra elements with 0. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int cell_extension_fields_setlen_field(cell_extension_fields_t *inp, size_t newlen); +/** Return a newly allocated cell_extension with all elements set to + * zero. + */ +cell_extension_t *cell_extension_new(void); +/** Release all storage held by the cell_extension in 'victim'. (Do + * nothing if 'victim' is NULL.) + */ +void cell_extension_free(cell_extension_t *victim); +/** Try to parse a cell_extension from the buffer in 'input', using up + * to 'len_in' bytes from the input buffer. On success, return the + * number of bytes consumed and set *output to the newly allocated + * cell_extension_t. On failure, return -2 if the input appears + * truncated, and -1 if the input is otherwise invalid. + */ +ssize_t cell_extension_parse(cell_extension_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * cell_extension in 'obj'. On failure, return a negative value. Note + * that this value may be an overestimate, and can even be an + * underestimate for certain unencodeable objects. + */ +ssize_t cell_extension_encoded_len(const cell_extension_t *obj); +/** Try to encode the cell_extension from 'input' into the buffer at + * 'output', using up to 'avail' bytes of the output buffer. On + * success, return the number of bytes used. On failure, return -2 if + * the buffer was not long enough, and -1 if the input was invalid. + */ +ssize_t cell_extension_encode(uint8_t *output, size_t avail, const cell_extension_t *input); +/** Check whether the internal state of the cell_extension in 'obj' is + * consistent. Return NULL if it is, and a short message if it is not. + */ +const char *cell_extension_check(const cell_extension_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int cell_extension_clear_errors(cell_extension_t *obj); +/** Return the value of the num field of the cell_extension_t in 'inp' + */ +uint8_t cell_extension_get_num(cell_extension_t *inp); +/** Set the value of the num field of the cell_extension_t in 'inp' to + * 'val'. Return 0 on success; return -1 and set the error code on + * 'inp' on failure. + */ +int cell_extension_set_num(cell_extension_t *inp, uint8_t val); +/** Return the length of the dynamic array holding the fields field of + * the cell_extension_t in 'inp'. + */ +size_t cell_extension_getlen_fields(const cell_extension_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * fields of the cell_extension_t in 'inp'. + */ +struct cell_extension_fields_st * cell_extension_get_fields(cell_extension_t *inp, size_t idx); +/** As cell_extension_get_fields, but take and return a const pointer + */ + const struct cell_extension_fields_st * cell_extension_getconst_fields(const cell_extension_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * fields of the cell_extension_t in 'inp', so that it will hold the + * value 'elt'. Free the previous value, if any. + */ +int cell_extension_set_fields(cell_extension_t *inp, size_t idx, struct cell_extension_fields_st * elt); +/** As cell_extension_set_fields, but does not free the previous + * value. + */ +int cell_extension_set0_fields(cell_extension_t *inp, size_t idx, struct cell_extension_fields_st * elt); +/** Append a new element 'elt' to the dynamic array field fields of + * the cell_extension_t in 'inp'. + */ +int cell_extension_add_fields(cell_extension_t *inp, struct cell_extension_fields_st * elt); +/** Return a pointer to the variable-length array field fields of + * 'inp'. + */ +struct cell_extension_fields_st * * cell_extension_getarray_fields(cell_extension_t *inp); +/** As cell_extension_get_fields, but take and return a const pointer + */ +const struct cell_extension_fields_st * const * cell_extension_getconstarray_fields(const cell_extension_t *inp); +/** Change the length of the variable-length array field fields of + * 'inp' to 'newlen'.Fill extra elements with NULL; free removed + * elements. Return 0 on success; return -1 and set the error code on + * 'inp' on failure. + */ +int cell_extension_setlen_fields(cell_extension_t *inp, size_t newlen); + + +#endif diff --git a/src/trunnel/hs/cell_common.trunnel b/src/trunnel/hs/cell_common.trunnel new file mode 100644 index 0000000..1bbec5a --- /dev/null +++ b/src/trunnel/hs/cell_common.trunnel @@ -0,0 +1,12 @@ +/* This file contains common data structure that cells use. */ + +struct cell_extension_fields { + u8 field_type; + u8 field_len; + u8 field[field_len]; +}; + +struct cell_extension { + u8 num; + struct cell_extension_fields fields[num]; +}; diff --git a/src/trunnel/hs/cell_establish_intro.c b/src/trunnel/hs/cell_establish_intro.c new file mode 100644 index 0000000..f3a3f53 --- /dev/null +++ b/src/trunnel/hs/cell_establish_intro.c @@ -0,0 +1,735 @@ +/* cell_establish_intro.c -- generated by Trunnel v1.5. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#include <stdlib.h> +#include "trunnel-impl.h" + +#include "cell_establish_intro.h" + +#define TRUNNEL_SET_ERROR_CODE(obj) \ + do { \ + (obj)->trunnel_error_code_ = 1; \ + } while (0) + +#if defined(__COVERITY__) || defined(__clang_analyzer__) +/* If we're runnning a static analysis tool, we don't want it to complain + * that some of our remaining-bytes checks are dead-code. */ +int cellestablishintro_deadcode_dummy__ = 0; +#define OR_DEADCODE_DUMMY || cellestablishintro_deadcode_dummy__ +#else +#define OR_DEADCODE_DUMMY +#endif + +#define CHECK_REMAINING(nbytes, label) \ + do { \ + if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \ + goto label; \ + } \ + } while (0) + +typedef struct cell_extension_st cell_extension_t; +cell_extension_t *cell_extension_new(void); +void cell_extension_free(cell_extension_t *victim); +ssize_t cell_extension_parse(cell_extension_t **output, const uint8_t *input, const size_t len_in); +ssize_t cell_extension_encoded_len(const cell_extension_t *obj); +ssize_t cell_extension_encode(uint8_t *output, size_t avail, const cell_extension_t *input); +const char *cell_extension_check(const cell_extension_t *obj); +int cell_extension_clear_errors(cell_extension_t *obj); +hs_cell_establish_intro_t * +hs_cell_establish_intro_new(void) +{ + hs_cell_establish_intro_t *val = trunnel_calloc(1, sizeof(hs_cell_establish_intro_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +hs_cell_establish_intro_clear(hs_cell_establish_intro_t *obj) +{ + (void) obj; + TRUNNEL_DYNARRAY_WIPE(&obj->auth_key); + TRUNNEL_DYNARRAY_CLEAR(&obj->auth_key); + cell_extension_free(obj->extensions); + obj->extensions = NULL; + TRUNNEL_DYNARRAY_WIPE(&obj->sig); + TRUNNEL_DYNARRAY_CLEAR(&obj->sig); +} + +void +hs_cell_establish_intro_free(hs_cell_establish_intro_t *obj) +{ + if (obj == NULL) + return; + hs_cell_establish_intro_clear(obj); + trunnel_memwipe(obj, sizeof(hs_cell_establish_intro_t)); + trunnel_free_(obj); +} + +const uint8_t * +hs_cell_establish_intro_get_start_cell(const hs_cell_establish_intro_t *inp) +{ + return inp->start_cell; +} +uint8_t +hs_cell_establish_intro_get_auth_key_type(hs_cell_establish_intro_t *inp) +{ + return inp->auth_key_type; +} +int +hs_cell_establish_intro_set_auth_key_type(hs_cell_establish_intro_t *inp, uint8_t val) +{ + if (! ((val == 0 || val == 1 || val == 2))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->auth_key_type = val; + return 0; +} +uint16_t +hs_cell_establish_intro_get_auth_key_len(hs_cell_establish_intro_t *inp) +{ + return inp->auth_key_len; +} +int +hs_cell_establish_intro_set_auth_key_len(hs_cell_establish_intro_t *inp, uint16_t val) +{ + inp->auth_key_len = val; + return 0; +} +size_t +hs_cell_establish_intro_getlen_auth_key(const hs_cell_establish_intro_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->auth_key); +} + +uint8_t +hs_cell_establish_intro_get_auth_key(hs_cell_establish_intro_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->auth_key, idx); +} + +uint8_t +hs_cell_establish_intro_getconst_auth_key(const hs_cell_establish_intro_t *inp, size_t idx) +{ + return hs_cell_establish_intro_get_auth_key((hs_cell_establish_intro_t*)inp, idx); +} +int +hs_cell_establish_intro_set_auth_key(hs_cell_establish_intro_t *inp, size_t idx, uint8_t elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->auth_key, idx, elt); + return 0; +} +int +hs_cell_establish_intro_add_auth_key(hs_cell_establish_intro_t *inp, uint8_t elt) +{ +#if SIZE_MAX >= UINT16_MAX + if (inp->auth_key.n_ == UINT16_MAX) + goto trunnel_alloc_failed; +#endif + TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->auth_key, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +uint8_t * +hs_cell_establish_intro_getarray_auth_key(hs_cell_establish_intro_t *inp) +{ + return inp->auth_key.elts_; +} +const uint8_t * +hs_cell_establish_intro_getconstarray_auth_key(const hs_cell_establish_intro_t *inp) +{ + return (const uint8_t *)hs_cell_establish_intro_getarray_auth_key((hs_cell_establish_intro_t*)inp); +} +int +hs_cell_establish_intro_setlen_auth_key(hs_cell_establish_intro_t *inp, size_t newlen) +{ + uint8_t *newptr; +#if UINT16_MAX < SIZE_MAX + if (newlen > UINT16_MAX) + goto trunnel_alloc_failed; +#endif + newptr = trunnel_dynarray_setlen(&inp->auth_key.allocated_, + &inp->auth_key.n_, inp->auth_key.elts_, newlen, + sizeof(inp->auth_key.elts_[0]), (trunnel_free_fn_t) NULL, + &inp->trunnel_error_code_); + if (newlen != 0 && newptr == NULL) + goto trunnel_alloc_failed; + inp->auth_key.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +struct cell_extension_st * +hs_cell_establish_intro_get_extensions(hs_cell_establish_intro_t *inp) +{ + return inp->extensions; +} +const struct cell_extension_st * +hs_cell_establish_intro_getconst_extensions(const hs_cell_establish_intro_t *inp) +{ + return hs_cell_establish_intro_get_extensions((hs_cell_establish_intro_t*) inp); +} +int +hs_cell_establish_intro_set_extensions(hs_cell_establish_intro_t *inp, struct cell_extension_st *val) +{ + if (inp->extensions && inp->extensions != val) + cell_extension_free(inp->extensions); + return hs_cell_establish_intro_set0_extensions(inp, val); +} +int +hs_cell_establish_intro_set0_extensions(hs_cell_establish_intro_t *inp, struct cell_extension_st *val) +{ + inp->extensions = val; + return 0; +} +const uint8_t * +hs_cell_establish_intro_get_end_mac_fields(const hs_cell_establish_intro_t *inp) +{ + return inp->end_mac_fields; +} +size_t +hs_cell_establish_intro_getlen_handshake_mac(const hs_cell_establish_intro_t *inp) +{ + (void)inp; return TRUNNEL_SHA3_256_LEN; +} + +uint8_t +hs_cell_establish_intro_get_handshake_mac(hs_cell_establish_intro_t *inp, size_t idx) +{ + trunnel_assert(idx < TRUNNEL_SHA3_256_LEN); + return inp->handshake_mac[idx]; +} + +uint8_t +hs_cell_establish_intro_getconst_handshake_mac(const hs_cell_establish_intro_t *inp, size_t idx) +{ + return hs_cell_establish_intro_get_handshake_mac((hs_cell_establish_intro_t*)inp, idx); +} +int +hs_cell_establish_intro_set_handshake_mac(hs_cell_establish_intro_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < TRUNNEL_SHA3_256_LEN); + inp->handshake_mac[idx] = elt; + return 0; +} + +uint8_t * +hs_cell_establish_intro_getarray_handshake_mac(hs_cell_establish_intro_t *inp) +{ + return inp->handshake_mac; +} +const uint8_t * +hs_cell_establish_intro_getconstarray_handshake_mac(const hs_cell_establish_intro_t *inp) +{ + return (const uint8_t *)hs_cell_establish_intro_getarray_handshake_mac((hs_cell_establish_intro_t*)inp); +} +uint16_t +hs_cell_establish_intro_get_sig_len(hs_cell_establish_intro_t *inp) +{ + return inp->sig_len; +} +int +hs_cell_establish_intro_set_sig_len(hs_cell_establish_intro_t *inp, uint16_t val) +{ + inp->sig_len = val; + return 0; +} +const uint8_t * +hs_cell_establish_intro_get_end_sig_fields(const hs_cell_establish_intro_t *inp) +{ + return inp->end_sig_fields; +} +size_t +hs_cell_establish_intro_getlen_sig(const hs_cell_establish_intro_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->sig); +} + +uint8_t +hs_cell_establish_intro_get_sig(hs_cell_establish_intro_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->sig, idx); +} + +uint8_t +hs_cell_establish_intro_getconst_sig(const hs_cell_establish_intro_t *inp, size_t idx) +{ + return hs_cell_establish_intro_get_sig((hs_cell_establish_intro_t*)inp, idx); +} +int +hs_cell_establish_intro_set_sig(hs_cell_establish_intro_t *inp, size_t idx, uint8_t elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->sig, idx, elt); + return 0; +} +int +hs_cell_establish_intro_add_sig(hs_cell_establish_intro_t *inp, uint8_t elt) +{ +#if SIZE_MAX >= UINT16_MAX + if (inp->sig.n_ == UINT16_MAX) + goto trunnel_alloc_failed; +#endif + TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->sig, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +uint8_t * +hs_cell_establish_intro_getarray_sig(hs_cell_establish_intro_t *inp) +{ + return inp->sig.elts_; +} +const uint8_t * +hs_cell_establish_intro_getconstarray_sig(const hs_cell_establish_intro_t *inp) +{ + return (const uint8_t *)hs_cell_establish_intro_getarray_sig((hs_cell_establish_intro_t*)inp); +} +int +hs_cell_establish_intro_setlen_sig(hs_cell_establish_intro_t *inp, size_t newlen) +{ + uint8_t *newptr; +#if UINT16_MAX < SIZE_MAX + if (newlen > UINT16_MAX) + goto trunnel_alloc_failed; +#endif + newptr = trunnel_dynarray_setlen(&inp->sig.allocated_, + &inp->sig.n_, inp->sig.elts_, newlen, + sizeof(inp->sig.elts_[0]), (trunnel_free_fn_t) NULL, + &inp->trunnel_error_code_); + if (newlen != 0 && newptr == NULL) + goto trunnel_alloc_failed; + inp->sig.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +const char * +hs_cell_establish_intro_check(const hs_cell_establish_intro_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + if (! (obj->auth_key_type == 0 || obj->auth_key_type == 1 || obj->auth_key_type == 2)) + return "Integer out of bounds"; + if (TRUNNEL_DYNARRAY_LEN(&obj->auth_key) != obj->auth_key_len) + return "Length mismatch for auth_key"; + { + const char *msg; + if (NULL != (msg = cell_extension_check(obj->extensions))) + return msg; + } + if (TRUNNEL_DYNARRAY_LEN(&obj->sig) != obj->sig_len) + return "Length mismatch for sig"; + return NULL; +} + +ssize_t +hs_cell_establish_intro_encoded_len(const hs_cell_establish_intro_t *obj) +{ + ssize_t result = 0; + + if (NULL != hs_cell_establish_intro_check(obj)) + return -1; + + + /* Length of u8 auth_key_type IN [0, 1, 2] */ + result += 1; + + /* Length of u16 auth_key_len */ + result += 2; + + /* Length of u8 auth_key[auth_key_len] */ + result += TRUNNEL_DYNARRAY_LEN(&obj->auth_key); + + /* Length of struct cell_extension extensions */ + result += cell_extension_encoded_len(obj->extensions); + + /* Length of u8 handshake_mac[TRUNNEL_SHA3_256_LEN] */ + result += TRUNNEL_SHA3_256_LEN; + + /* Length of u16 sig_len */ + result += 2; + + /* Length of u8 sig[sig_len] */ + result += TRUNNEL_DYNARRAY_LEN(&obj->sig); + return result; +} +int +hs_cell_establish_intro_clear_errors(hs_cell_establish_intro_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +hs_cell_establish_intro_encode(uint8_t *output, const size_t avail, const hs_cell_establish_intro_t *obj) +{ + ssize_t result = 0; + size_t written = 0; + uint8_t *ptr = output; + const char *msg; +#ifdef TRUNNEL_CHECK_ENCODED_LEN + const ssize_t encoded_len = hs_cell_establish_intro_encoded_len(obj); +#endif + + if (NULL != (msg = hs_cell_establish_intro_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 auth_key_type IN [0, 1, 2] */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->auth_key_type)); + written += 1; ptr += 1; + + /* Encode u16 auth_key_len */ + trunnel_assert(written <= avail); + if (avail - written < 2) + goto truncated; + trunnel_set_uint16(ptr, trunnel_htons(obj->auth_key_len)); + written += 2; ptr += 2; + + /* Encode u8 auth_key[auth_key_len] */ + { + size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->auth_key); + trunnel_assert(obj->auth_key_len == elt_len); + trunnel_assert(written <= avail); + if (avail - written < elt_len) + goto truncated; + if (elt_len) + memcpy(ptr, obj->auth_key.elts_, elt_len); + written += elt_len; ptr += elt_len; + } + + /* Encode struct cell_extension extensions */ + trunnel_assert(written <= avail); + result = cell_extension_encode(ptr, avail - written, obj->extensions); + if (result < 0) + goto fail; /* XXXXXXX !*/ + written += result; ptr += result; + + /* Encode u8 handshake_mac[TRUNNEL_SHA3_256_LEN] */ + trunnel_assert(written <= avail); + if (avail - written < TRUNNEL_SHA3_256_LEN) + goto truncated; + memcpy(ptr, obj->handshake_mac, TRUNNEL_SHA3_256_LEN); + written += TRUNNEL_SHA3_256_LEN; ptr += TRUNNEL_SHA3_256_LEN; + + /* Encode u16 sig_len */ + trunnel_assert(written <= avail); + if (avail - written < 2) + goto truncated; + trunnel_set_uint16(ptr, trunnel_htons(obj->sig_len)); + written += 2; ptr += 2; + + /* Encode u8 sig[sig_len] */ + { + size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->sig); + trunnel_assert(obj->sig_len == elt_len); + trunnel_assert(written <= avail); + if (avail - written < elt_len) + goto truncated; + if (elt_len) + memcpy(ptr, obj->sig.elts_, elt_len); + written += elt_len; ptr += elt_len; + } + + + trunnel_assert(ptr == output + written); +#ifdef TRUNNEL_CHECK_ENCODED_LEN + { + trunnel_assert(encoded_len >= 0); + trunnel_assert((size_t)encoded_len == written); + } + +#endif + + return written; + + truncated: + result = -2; + goto fail; + check_failed: + (void)msg; + result = -1; + goto fail; + fail: + trunnel_assert(result < 0); + return result; +} + +/** As hs_cell_establish_intro_parse(), but do not allocate the output + * object. + */ +static ssize_t +hs_cell_establish_intro_parse_into(hs_cell_establish_intro_t *obj, const uint8_t *input, const size_t len_in) +{ + const uint8_t *ptr = input; + size_t remaining = len_in; + ssize_t result = 0; + (void)result; + obj->start_cell = ptr; + + /* Parse u8 auth_key_type IN [0, 1, 2] */ + CHECK_REMAINING(1, truncated); + obj->auth_key_type = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->auth_key_type == 0 || obj->auth_key_type == 1 || obj->auth_key_type == 2)) + goto fail; + + /* Parse u16 auth_key_len */ + CHECK_REMAINING(2, truncated); + obj->auth_key_len = trunnel_ntohs(trunnel_get_uint16(ptr)); + remaining -= 2; ptr += 2; + + /* Parse u8 auth_key[auth_key_len] */ + CHECK_REMAINING(obj->auth_key_len, truncated); + TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->auth_key, obj->auth_key_len, {}); + obj->auth_key.n_ = obj->auth_key_len; + if (obj->auth_key_len) + memcpy(obj->auth_key.elts_, ptr, obj->auth_key_len); + ptr += obj->auth_key_len; remaining -= obj->auth_key_len; + + /* Parse struct cell_extension extensions */ + result = cell_extension_parse(&obj->extensions, ptr, remaining); + if (result < 0) + goto relay_fail; + trunnel_assert((size_t)result <= remaining); + remaining -= result; ptr += result; + obj->end_mac_fields = ptr; + + /* Parse u8 handshake_mac[TRUNNEL_SHA3_256_LEN] */ + CHECK_REMAINING(TRUNNEL_SHA3_256_LEN, truncated); + memcpy(obj->handshake_mac, ptr, TRUNNEL_SHA3_256_LEN); + remaining -= TRUNNEL_SHA3_256_LEN; ptr += TRUNNEL_SHA3_256_LEN; + + /* Parse u16 sig_len */ + CHECK_REMAINING(2, truncated); + obj->sig_len = trunnel_ntohs(trunnel_get_uint16(ptr)); + remaining -= 2; ptr += 2; + obj->end_sig_fields = ptr; + + /* Parse u8 sig[sig_len] */ + CHECK_REMAINING(obj->sig_len, truncated); + TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->sig, obj->sig_len, {}); + obj->sig.n_ = obj->sig_len; + if (obj->sig_len) + memcpy(obj->sig.elts_, ptr, obj->sig_len); + ptr += obj->sig_len; remaining -= obj->sig_len; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + relay_fail: + trunnel_assert(result < 0); + return result; + trunnel_alloc_failed: + return -1; + fail: + result = -1; + return result; +} + +ssize_t +hs_cell_establish_intro_parse(hs_cell_establish_intro_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = hs_cell_establish_intro_new(); + if (NULL == *output) + return -1; + result = hs_cell_establish_intro_parse_into(*output, input, len_in); + if (result < 0) { + hs_cell_establish_intro_free(*output); + *output = NULL; + } + return result; +} +hs_cell_intro_established_t * +hs_cell_intro_established_new(void) +{ + hs_cell_intro_established_t *val = trunnel_calloc(1, sizeof(hs_cell_intro_established_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +hs_cell_intro_established_clear(hs_cell_intro_established_t *obj) +{ + (void) obj; + cell_extension_free(obj->extensions); + obj->extensions = NULL; +} + +void +hs_cell_intro_established_free(hs_cell_intro_established_t *obj) +{ + if (obj == NULL) + return; + hs_cell_intro_established_clear(obj); + trunnel_memwipe(obj, sizeof(hs_cell_intro_established_t)); + trunnel_free_(obj); +} + +struct cell_extension_st * +hs_cell_intro_established_get_extensions(hs_cell_intro_established_t *inp) +{ + return inp->extensions; +} +const struct cell_extension_st * +hs_cell_intro_established_getconst_extensions(const hs_cell_intro_established_t *inp) +{ + return hs_cell_intro_established_get_extensions((hs_cell_intro_established_t*) inp); +} +int +hs_cell_intro_established_set_extensions(hs_cell_intro_established_t *inp, struct cell_extension_st *val) +{ + if (inp->extensions && inp->extensions != val) + cell_extension_free(inp->extensions); + return hs_cell_intro_established_set0_extensions(inp, val); +} +int +hs_cell_intro_established_set0_extensions(hs_cell_intro_established_t *inp, struct cell_extension_st *val) +{ + inp->extensions = val; + return 0; +} +const char * +hs_cell_intro_established_check(const hs_cell_intro_established_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + { + const char *msg; + if (NULL != (msg = cell_extension_check(obj->extensions))) + return msg; + } + return NULL; +} + +ssize_t +hs_cell_intro_established_encoded_len(const hs_cell_intro_established_t *obj) +{ + ssize_t result = 0; + + if (NULL != hs_cell_intro_established_check(obj)) + return -1; + + + /* Length of struct cell_extension extensions */ + result += cell_extension_encoded_len(obj->extensions); + return result; +} +int +hs_cell_intro_established_clear_errors(hs_cell_intro_established_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +hs_cell_intro_established_encode(uint8_t *output, const size_t avail, const hs_cell_intro_established_t *obj) +{ + ssize_t result = 0; + size_t written = 0; + uint8_t *ptr = output; + const char *msg; +#ifdef TRUNNEL_CHECK_ENCODED_LEN + const ssize_t encoded_len = hs_cell_intro_established_encoded_len(obj); +#endif + + if (NULL != (msg = hs_cell_intro_established_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode struct cell_extension extensions */ + trunnel_assert(written <= avail); + result = cell_extension_encode(ptr, avail - written, obj->extensions); + if (result < 0) + goto fail; /* XXXXXXX !*/ + written += result; ptr += result; + + + trunnel_assert(ptr == output + written); +#ifdef TRUNNEL_CHECK_ENCODED_LEN + { + trunnel_assert(encoded_len >= 0); + trunnel_assert((size_t)encoded_len == written); + } + +#endif + + return written; + + check_failed: + (void)msg; + result = -1; + goto fail; + fail: + trunnel_assert(result < 0); + return result; +} + +/** As hs_cell_intro_established_parse(), but do not allocate the + * output object. + */ +static ssize_t +hs_cell_intro_established_parse_into(hs_cell_intro_established_t *obj, const uint8_t *input, const size_t len_in) +{ + const uint8_t *ptr = input; + size_t remaining = len_in; + ssize_t result = 0; + (void)result; + + /* Parse struct cell_extension extensions */ + result = cell_extension_parse(&obj->extensions, ptr, remaining); + if (result < 0) + goto relay_fail; + trunnel_assert((size_t)result <= remaining); + remaining -= result; ptr += result; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + relay_fail: + trunnel_assert(result < 0); + return result; +} + +ssize_t +hs_cell_intro_established_parse(hs_cell_intro_established_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = hs_cell_intro_established_new(); + if (NULL == *output) + return -1; + result = hs_cell_intro_established_parse_into(*output, input, len_in); + if (result < 0) { + hs_cell_intro_established_free(*output); + *output = NULL; + } + return result; +} diff --git a/src/trunnel/hs/cell_establish_intro.h b/src/trunnel/hs/cell_establish_intro.h new file mode 100644 index 0000000..9a066b1 --- /dev/null +++ b/src/trunnel/hs/cell_establish_intro.h @@ -0,0 +1,275 @@ +/* cell_establish_intro.h -- generated by by Trunnel v1.5. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#ifndef TRUNNEL_CELL_ESTABLISH_INTRO_H +#define TRUNNEL_CELL_ESTABLISH_INTRO_H + +#include <stdint.h> +#include "trunnel.h" + +struct cell_extension_st; +#define TRUNNEL_SHA3_256_LEN 32 +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_HS_CELL_ESTABLISH_INTRO) +struct hs_cell_establish_intro_st { + const uint8_t *start_cell; + uint8_t auth_key_type; + uint16_t auth_key_len; + TRUNNEL_DYNARRAY_HEAD(, uint8_t) auth_key; + struct cell_extension_st *extensions; + const uint8_t *end_mac_fields; + uint8_t handshake_mac[TRUNNEL_SHA3_256_LEN]; + uint16_t sig_len; + const uint8_t *end_sig_fields; + TRUNNEL_DYNARRAY_HEAD(, uint8_t) sig; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct hs_cell_establish_intro_st hs_cell_establish_intro_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_HS_CELL_INTRO_ESTABLISHED) +struct hs_cell_intro_established_st { + struct cell_extension_st *extensions; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct hs_cell_intro_established_st hs_cell_intro_established_t; +/** Return a newly allocated hs_cell_establish_intro with all elements + * set to zero. + */ +hs_cell_establish_intro_t *hs_cell_establish_intro_new(void); +/** Release all storage held by the hs_cell_establish_intro in + * 'victim'. (Do nothing if 'victim' is NULL.) + */ +void hs_cell_establish_intro_free(hs_cell_establish_intro_t *victim); +/** Try to parse a hs_cell_establish_intro from the buffer in 'input', + * using up to 'len_in' bytes from the input buffer. On success, + * return the number of bytes consumed and set *output to the newly + * allocated hs_cell_establish_intro_t. On failure, return -2 if the + * input appears truncated, and -1 if the input is otherwise invalid. + */ +ssize_t hs_cell_establish_intro_parse(hs_cell_establish_intro_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * hs_cell_establish_intro in 'obj'. On failure, return a negative + * value. Note that this value may be an overestimate, and can even be + * an underestimate for certain unencodeable objects. + */ +ssize_t hs_cell_establish_intro_encoded_len(const hs_cell_establish_intro_t *obj); +/** Try to encode the hs_cell_establish_intro from 'input' into the + * buffer at 'output', using up to 'avail' bytes of the output buffer. + * On success, return the number of bytes used. On failure, return -2 + * if the buffer was not long enough, and -1 if the input was invalid. + */ +ssize_t hs_cell_establish_intro_encode(uint8_t *output, size_t avail, const hs_cell_establish_intro_t *input); +/** Check whether the internal state of the hs_cell_establish_intro in + * 'obj' is consistent. Return NULL if it is, and a short message if + * it is not. + */ +const char *hs_cell_establish_intro_check(const hs_cell_establish_intro_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int hs_cell_establish_intro_clear_errors(hs_cell_establish_intro_t *obj); +/** Return the position for start_cell when we parsed this object + */ +const uint8_t * hs_cell_establish_intro_get_start_cell(const hs_cell_establish_intro_t *inp); +/** Return the value of the auth_key_type field of the + * hs_cell_establish_intro_t in 'inp' + */ +uint8_t hs_cell_establish_intro_get_auth_key_type(hs_cell_establish_intro_t *inp); +/** Set the value of the auth_key_type field of the + * hs_cell_establish_intro_t in 'inp' to 'val'. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int hs_cell_establish_intro_set_auth_key_type(hs_cell_establish_intro_t *inp, uint8_t val); +/** Return the value of the auth_key_len field of the + * hs_cell_establish_intro_t in 'inp' + */ +uint16_t hs_cell_establish_intro_get_auth_key_len(hs_cell_establish_intro_t *inp); +/** Set the value of the auth_key_len field of the + * hs_cell_establish_intro_t in 'inp' to 'val'. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int hs_cell_establish_intro_set_auth_key_len(hs_cell_establish_intro_t *inp, uint16_t val); +/** Return the length of the dynamic array holding the auth_key field + * of the hs_cell_establish_intro_t in 'inp'. + */ +size_t hs_cell_establish_intro_getlen_auth_key(const hs_cell_establish_intro_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * auth_key of the hs_cell_establish_intro_t in 'inp'. + */ +uint8_t hs_cell_establish_intro_get_auth_key(hs_cell_establish_intro_t *inp, size_t idx); +/** As hs_cell_establish_intro_get_auth_key, but take and return a + * const pointer + */ +uint8_t hs_cell_establish_intro_getconst_auth_key(const hs_cell_establish_intro_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * auth_key of the hs_cell_establish_intro_t in 'inp', so that it will + * hold the value 'elt'. + */ +int hs_cell_establish_intro_set_auth_key(hs_cell_establish_intro_t *inp, size_t idx, uint8_t elt); +/** Append a new element 'elt' to the dynamic array field auth_key of + * the hs_cell_establish_intro_t in 'inp'. + */ +int hs_cell_establish_intro_add_auth_key(hs_cell_establish_intro_t *inp, uint8_t elt); +/** Return a pointer to the variable-length array field auth_key of + * 'inp'. + */ +uint8_t * hs_cell_establish_intro_getarray_auth_key(hs_cell_establish_intro_t *inp); +/** As hs_cell_establish_intro_get_auth_key, but take and return a + * const pointer + */ +const uint8_t * hs_cell_establish_intro_getconstarray_auth_key(const hs_cell_establish_intro_t *inp); +/** Change the length of the variable-length array field auth_key of + * 'inp' to 'newlen'.Fill extra elements with 0. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int hs_cell_establish_intro_setlen_auth_key(hs_cell_establish_intro_t *inp, size_t newlen); +/** Return the value of the extensions field of the + * hs_cell_establish_intro_t in 'inp' + */ +struct cell_extension_st * hs_cell_establish_intro_get_extensions(hs_cell_establish_intro_t *inp); +/** As hs_cell_establish_intro_get_extensions, but take and return a + * const pointer + */ +const struct cell_extension_st * hs_cell_establish_intro_getconst_extensions(const hs_cell_establish_intro_t *inp); +/** Set the value of the extensions field of the + * hs_cell_establish_intro_t in 'inp' to 'val'. Free the old value if + * any. Steals the referenceto 'val'.Return 0 on success; return -1 + * and set the error code on 'inp' on failure. + */ +int hs_cell_establish_intro_set_extensions(hs_cell_establish_intro_t *inp, struct cell_extension_st *val); +/** As hs_cell_establish_intro_set_extensions, but does not free the + * previous value. + */ +int hs_cell_establish_intro_set0_extensions(hs_cell_establish_intro_t *inp, struct cell_extension_st *val); +/** Return the position for end_mac_fields when we parsed this object + */ +const uint8_t * hs_cell_establish_intro_get_end_mac_fields(const hs_cell_establish_intro_t *inp); +/** Return the (constant) length of the array holding the + * handshake_mac field of the hs_cell_establish_intro_t in 'inp'. + */ +size_t hs_cell_establish_intro_getlen_handshake_mac(const hs_cell_establish_intro_t *inp); +/** Return the element at position 'idx' of the fixed array field + * handshake_mac of the hs_cell_establish_intro_t in 'inp'. + */ +uint8_t hs_cell_establish_intro_get_handshake_mac(hs_cell_establish_intro_t *inp, size_t idx); +/** As hs_cell_establish_intro_get_handshake_mac, but take and return + * a const pointer + */ +uint8_t hs_cell_establish_intro_getconst_handshake_mac(const hs_cell_establish_intro_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * handshake_mac of the hs_cell_establish_intro_t in 'inp', so that it + * will hold the value 'elt'. + */ +int hs_cell_establish_intro_set_handshake_mac(hs_cell_establish_intro_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the TRUNNEL_SHA3_256_LEN-element array field + * handshake_mac of 'inp'. + */ +uint8_t * hs_cell_establish_intro_getarray_handshake_mac(hs_cell_establish_intro_t *inp); +/** As hs_cell_establish_intro_get_handshake_mac, but take and return + * a const pointer + */ +const uint8_t * hs_cell_establish_intro_getconstarray_handshake_mac(const hs_cell_establish_intro_t *inp); +/** Return the value of the sig_len field of the + * hs_cell_establish_intro_t in 'inp' + */ +uint16_t hs_cell_establish_intro_get_sig_len(hs_cell_establish_intro_t *inp); +/** Set the value of the sig_len field of the + * hs_cell_establish_intro_t in 'inp' to 'val'. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int hs_cell_establish_intro_set_sig_len(hs_cell_establish_intro_t *inp, uint16_t val); +/** Return the position for end_sig_fields when we parsed this object + */ +const uint8_t * hs_cell_establish_intro_get_end_sig_fields(const hs_cell_establish_intro_t *inp); +/** Return the length of the dynamic array holding the sig field of + * the hs_cell_establish_intro_t in 'inp'. + */ +size_t hs_cell_establish_intro_getlen_sig(const hs_cell_establish_intro_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * sig of the hs_cell_establish_intro_t in 'inp'. + */ +uint8_t hs_cell_establish_intro_get_sig(hs_cell_establish_intro_t *inp, size_t idx); +/** As hs_cell_establish_intro_get_sig, but take and return a const + * pointer + */ +uint8_t hs_cell_establish_intro_getconst_sig(const hs_cell_establish_intro_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * sig of the hs_cell_establish_intro_t in 'inp', so that it will hold + * the value 'elt'. + */ +int hs_cell_establish_intro_set_sig(hs_cell_establish_intro_t *inp, size_t idx, uint8_t elt); +/** Append a new element 'elt' to the dynamic array field sig of the + * hs_cell_establish_intro_t in 'inp'. + */ +int hs_cell_establish_intro_add_sig(hs_cell_establish_intro_t *inp, uint8_t elt); +/** Return a pointer to the variable-length array field sig of 'inp'. + */ +uint8_t * hs_cell_establish_intro_getarray_sig(hs_cell_establish_intro_t *inp); +/** As hs_cell_establish_intro_get_sig, but take and return a const + * pointer + */ +const uint8_t * hs_cell_establish_intro_getconstarray_sig(const hs_cell_establish_intro_t *inp); +/** Change the length of the variable-length array field sig of 'inp' + * to 'newlen'.Fill extra elements with 0. Return 0 on success; return + * -1 and set the error code on 'inp' on failure. + */ +int hs_cell_establish_intro_setlen_sig(hs_cell_establish_intro_t *inp, size_t newlen); +/** Return a newly allocated hs_cell_intro_established with all + * elements set to zero. + */ +hs_cell_intro_established_t *hs_cell_intro_established_new(void); +/** Release all storage held by the hs_cell_intro_established in + * 'victim'. (Do nothing if 'victim' is NULL.) + */ +void hs_cell_intro_established_free(hs_cell_intro_established_t *victim); +/** Try to parse a hs_cell_intro_established from the buffer in + * 'input', using up to 'len_in' bytes from the input buffer. On + * success, return the number of bytes consumed and set *output to the + * newly allocated hs_cell_intro_established_t. On failure, return -2 + * if the input appears truncated, and -1 if the input is otherwise + * invalid. + */ +ssize_t hs_cell_intro_established_parse(hs_cell_intro_established_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * hs_cell_intro_established in 'obj'. On failure, return a negative + * value. Note that this value may be an overestimate, and can even be + * an underestimate for certain unencodeable objects. + */ +ssize_t hs_cell_intro_established_encoded_len(const hs_cell_intro_established_t *obj); +/** Try to encode the hs_cell_intro_established from 'input' into the + * buffer at 'output', using up to 'avail' bytes of the output buffer. + * On success, return the number of bytes used. On failure, return -2 + * if the buffer was not long enough, and -1 if the input was invalid. + */ +ssize_t hs_cell_intro_established_encode(uint8_t *output, size_t avail, const hs_cell_intro_established_t *input); +/** Check whether the internal state of the hs_cell_intro_established + * in 'obj' is consistent. Return NULL if it is, and a short message + * if it is not. + */ +const char *hs_cell_intro_established_check(const hs_cell_intro_established_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int hs_cell_intro_established_clear_errors(hs_cell_intro_established_t *obj); +/** Return the value of the extensions field of the + * hs_cell_intro_established_t in 'inp' + */ +struct cell_extension_st * hs_cell_intro_established_get_extensions(hs_cell_intro_established_t *inp); +/** As hs_cell_intro_established_get_extensions, but take and return a + * const pointer + */ +const struct cell_extension_st * hs_cell_intro_established_getconst_extensions(const hs_cell_intro_established_t *inp); +/** Set the value of the extensions field of the + * hs_cell_intro_established_t in 'inp' to 'val'. Free the old value + * if any. Steals the referenceto 'val'.Return 0 on success; return -1 + * and set the error code on 'inp' on failure. + */ +int hs_cell_intro_established_set_extensions(hs_cell_intro_established_t *inp, struct cell_extension_st *val); +/** As hs_cell_intro_established_set_extensions, but does not free the + * previous value. + */ +int hs_cell_intro_established_set0_extensions(hs_cell_intro_established_t *inp, struct cell_extension_st *val); + + +#endif diff --git a/src/trunnel/hs/cell_establish_intro.trunnel b/src/trunnel/hs/cell_establish_intro.trunnel new file mode 100644 index 0000000..4f9e8f7 --- /dev/null +++ b/src/trunnel/hs/cell_establish_intro.trunnel @@ -0,0 +1,41 @@ +/* + * This contains the definition of the ESTABLISH_INTRO and INTRO_ESTABLISHED + * cell for onion service version 3 and onward. The following format is + * specified in proposal 224 section 3.1. + */ + +extern struct cell_extension; + +const TRUNNEL_SHA3_256_LEN = 32; + +/* ESTABLISH_INTRO payload. See details in section 3.1.1 */ +struct hs_cell_establish_intro { + /* Indicate the start of the handshake authentication data. */ + @ptr start_cell; + + /* Authentication key material. */ + u8 auth_key_type IN [0x00, 0x01, 0x02]; + u16 auth_key_len; + u8 auth_key[auth_key_len]; + + /* Extension(s). Reserved fields. */ + struct cell_extension extensions; + @ptr end_mac_fields; + + /* Handshake MAC. */ + u8 handshake_mac[TRUNNEL_SHA3_256_LEN]; + + /* Signature */ + u16 sig_len; + /* Indicate the end of the handshake authentication data. */ + @ptr end_sig_fields; + u8 sig[sig_len]; +}; + +/* INTRO_ESTABLISHED payload which is an acknowledge of the ESTABLISH_INTRO + * cell. For legacy node, this payload is empty so the following only applies + * to version >= 3. */ +struct hs_cell_intro_established { + /* Extension(s). Reserved fields. */ + struct cell_extension extensions; +}; diff --git a/src/trunnel/include.am b/src/trunnel/include.am index b1448b7..d48971a 100644 --- a/src/trunnel/include.am +++ b/src/trunnel/include.am @@ -1,4 +1,3 @@ - noinst_LIBRARIES += \ src/trunnel/libor-trunnel.a
@@ -18,15 +17,19 @@ TRUNNELSOURCES = \ src/ext/trunnel/trunnel.c \ src/trunnel/ed25519_cert.c \ src/trunnel/link_handshake.c \ - src/trunnel/pwbox.c + src/trunnel/pwbox.c \ + src/trunnel/hs/cell_common.c \ + src/trunnel/hs/cell_establish_intro.c
TRUNNELHEADERS = \ src/ext/trunnel/trunnel.h \ src/ext/trunnel/trunnel-impl.h \ - src/trunnel/trunnel-local.h \ + src/trunnel/trunnel-local.h \ src/trunnel/ed25519_cert.h \ - src/trunnel/link_handshake.h \ - src/trunnel/pwbox.h + src/trunnel/link_handshake.h \ + src/trunnel/pwbox.h \ + src/trunnel/hs/cell_common.h \ + src/trunnel/hs/cell_establish_intro.h
src_trunnel_libor_trunnel_a_SOURCES = $(TRUNNELSOURCES) src_trunnel_libor_trunnel_a_CPPFLAGS = -DTRUNNEL_LOCAL_H $(AM_CPPFLAGS)