From 818e6f939d4bd241e762970da4c6360858993cd5 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 30 Sep 2014 16:00:17 -0400 Subject: prop220: Implement certificates and key storage/creation For prop220, we have a new ed25519 certificate type. This patch implements the code to create, parse, and validate those, along with code for routers to maintain their own sets of certificates and keys. (Some parts of master identity key encryption are done, but the implementation of that isn't finished) --- src/trunnel/ed25519_cert.c | 887 +++++++++++++++++++++++++++++++++++++++ src/trunnel/ed25519_cert.h | 288 +++++++++++++ src/trunnel/ed25519_cert.trunnel | 76 ++++ src/trunnel/include.am | 18 +- 4 files changed, 1263 insertions(+), 6 deletions(-) create mode 100644 src/trunnel/ed25519_cert.c create mode 100644 src/trunnel/ed25519_cert.h create mode 100644 src/trunnel/ed25519_cert.trunnel (limited to 'src/trunnel') diff --git a/src/trunnel/ed25519_cert.c b/src/trunnel/ed25519_cert.c new file mode 100644 index 0000000000..2a84e4b163 --- /dev/null +++ b/src/trunnel/ed25519_cert.c @@ -0,0 +1,887 @@ +/* ed25519_cert.c -- generated by Trunnel v1.2. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#include +#include "trunnel-impl.h" + +#include "ed25519_cert.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 edcert_deadcode_dummy__ = 0; +#define OR_DEADCODE_DUMMY || edcert_deadcode_dummy__ +#else +#define OR_DEADCODE_DUMMY +#endif + +#define CHECK_REMAINING(nbytes, label) \ + do { \ + if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \ + goto label; \ + } \ + } while (0) + +ed25519_cert_extension_t * +ed25519_cert_extension_new(void) +{ + ed25519_cert_extension_t *val = trunnel_calloc(1, sizeof(ed25519_cert_extension_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +ed25519_cert_extension_clear(ed25519_cert_extension_t *obj) +{ + (void) obj; + TRUNNEL_DYNARRAY_WIPE(&obj->un_unparsed); + TRUNNEL_DYNARRAY_CLEAR(&obj->un_unparsed); +} + +void +ed25519_cert_extension_free(ed25519_cert_extension_t *obj) +{ + if (obj == NULL) + return; + ed25519_cert_extension_clear(obj); + trunnel_memwipe(obj, sizeof(ed25519_cert_extension_t)); + trunnel_free_(obj); +} + +uint16_t +ed25519_cert_extension_get_ext_length(ed25519_cert_extension_t *inp) +{ + return inp->ext_length; +} +int +ed25519_cert_extension_set_ext_length(ed25519_cert_extension_t *inp, uint16_t val) +{ + inp->ext_length = val; + return 0; +} +uint8_t +ed25519_cert_extension_get_ext_type(ed25519_cert_extension_t *inp) +{ + return inp->ext_type; +} +int +ed25519_cert_extension_set_ext_type(ed25519_cert_extension_t *inp, uint8_t val) +{ + inp->ext_type = val; + return 0; +} +uint8_t +ed25519_cert_extension_get_ext_flags(ed25519_cert_extension_t *inp) +{ + return inp->ext_flags; +} +int +ed25519_cert_extension_set_ext_flags(ed25519_cert_extension_t *inp, uint8_t val) +{ + inp->ext_flags = val; + return 0; +} +size_t +ed25519_cert_extension_getlen_un_signing_key(const ed25519_cert_extension_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +ed25519_cert_extension_get_un_signing_key(const ed25519_cert_extension_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->un_signing_key[idx]; +} + +int +ed25519_cert_extension_set_un_signing_key(ed25519_cert_extension_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->un_signing_key[idx] = elt; + return 0; +} + +uint8_t * +ed25519_cert_extension_getarray_un_signing_key(ed25519_cert_extension_t *inp) +{ + return inp->un_signing_key; +} +size_t +ed25519_cert_extension_getlen_un_unparsed(const ed25519_cert_extension_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->un_unparsed); +} + +uint8_t +ed25519_cert_extension_get_un_unparsed(ed25519_cert_extension_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->un_unparsed, idx); +} + +int +ed25519_cert_extension_set_un_unparsed(ed25519_cert_extension_t *inp, size_t idx, uint8_t elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->un_unparsed, idx, elt); + return 0; +} +int +ed25519_cert_extension_add_un_unparsed(ed25519_cert_extension_t *inp, uint8_t elt) +{ + TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->un_unparsed, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +uint8_t * +ed25519_cert_extension_getarray_un_unparsed(ed25519_cert_extension_t *inp) +{ + return inp->un_unparsed.elts_; +} +int +ed25519_cert_extension_setlen_un_unparsed(ed25519_cert_extension_t *inp, size_t newlen) +{ + uint8_t *newptr; + newptr = trunnel_dynarray_setlen(&inp->un_unparsed.allocated_, + &inp->un_unparsed.n_, inp->un_unparsed.elts_, newlen, + sizeof(inp->un_unparsed.elts_[0]), (trunnel_free_fn_t) NULL, + &inp->trunnel_error_code_); + if (newptr == NULL) + goto trunnel_alloc_failed; + inp->un_unparsed.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +const char * +ed25519_cert_extension_check(const ed25519_cert_extension_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + switch (obj->ext_type) { + + case CERTEXT_SIGNED_WITH_KEY: + break; + + default: + break; + } + return NULL; +} + +ssize_t +ed25519_cert_extension_encoded_len(const ed25519_cert_extension_t *obj) +{ + ssize_t result = 0; + + if (NULL != ed25519_cert_extension_check(obj)) + return -1; + + + /* Length of u16 ext_length */ + result += 2; + + /* Length of u8 ext_type */ + result += 1; + + /* Length of u8 ext_flags */ + result += 1; + switch (obj->ext_type) { + + case CERTEXT_SIGNED_WITH_KEY: + + /* Length of u8 un_signing_key[32] */ + result += 32; + break; + + default: + + /* Length of u8 un_unparsed[] */ + result += TRUNNEL_DYNARRAY_LEN(&obj->un_unparsed); + break; + } + return result; +} +int +ed25519_cert_extension_clear_errors(ed25519_cert_extension_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +ed25519_cert_extension_encode(uint8_t *output, const size_t avail, const ed25519_cert_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 = ed25519_cert_extension_encoded_len(obj); +#endif + + uint8_t *backptr_ext_length = NULL; + + if (NULL != (msg = ed25519_cert_extension_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u16 ext_length */ + backptr_ext_length = ptr; + trunnel_assert(written <= avail); + if (avail - written < 2) + goto truncated; + trunnel_set_uint16(ptr, trunnel_htons(obj->ext_length)); + written += 2; ptr += 2; + + /* Encode u8 ext_type */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->ext_type)); + written += 1; ptr += 1; + + /* Encode u8 ext_flags */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->ext_flags)); + written += 1; ptr += 1; + { + size_t written_before_union = written; + + /* Encode union un[ext_type] */ + trunnel_assert(written <= avail); + switch (obj->ext_type) { + + case CERTEXT_SIGNED_WITH_KEY: + + /* Encode u8 un_signing_key[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->un_signing_key, 32); + written += 32; ptr += 32; + break; + + default: + + /* Encode u8 un_unparsed[] */ + { + size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->un_unparsed); + trunnel_assert(written <= avail); + if (avail - written < elt_len) + goto truncated; + memcpy(ptr, obj->un_unparsed.elts_, elt_len); + written += elt_len; ptr += elt_len; + } + break; + } + /* Write the length field back to ext_length */ + trunnel_assert(written >= written_before_union); +#if UINT16_MAX < SIZE_MAX + if (written - written_before_union > UINT16_MAX) + goto check_failed; +#endif + trunnel_set_uint16(backptr_ext_length, trunnel_htons(written - written_before_union)); + } + + + 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 ed25519_cert_extension_parse(), but do not allocate the output + * object. + */ +static ssize_t +ed25519_cert_extension_parse_into(ed25519_cert_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 u16 ext_length */ + CHECK_REMAINING(2, truncated); + obj->ext_length = trunnel_ntohs(trunnel_get_uint16(ptr)); + remaining -= 2; ptr += 2; + + /* Parse u8 ext_type */ + CHECK_REMAINING(1, truncated); + obj->ext_type = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + + /* Parse u8 ext_flags */ + CHECK_REMAINING(1, truncated); + obj->ext_flags = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + { + size_t remaining_after; + CHECK_REMAINING(obj->ext_length, truncated); + remaining_after = remaining - obj->ext_length; + remaining = obj->ext_length; + + /* Parse union un[ext_type] */ + switch (obj->ext_type) { + + case CERTEXT_SIGNED_WITH_KEY: + + /* Parse u8 un_signing_key[32] */ + CHECK_REMAINING(32, fail); + memcpy(obj->un_signing_key, ptr, 32); + remaining -= 32; ptr += 32; + break; + + default: + + /* Parse u8 un_unparsed[] */ + TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->un_unparsed, remaining, {}); + obj->un_unparsed.n_ = remaining; + memcpy(obj->un_unparsed.elts_, ptr, remaining); + ptr += remaining; remaining -= remaining; + break; + } + if (remaining != 0) + goto fail; + remaining = remaining_after; + } + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + trunnel_alloc_failed: + return -1; + fail: + result = -1; + return result; +} + +ssize_t +ed25519_cert_extension_parse(ed25519_cert_extension_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = ed25519_cert_extension_new(); + if (NULL == *output) + return -1; + result = ed25519_cert_extension_parse_into(*output, input, len_in); + if (result < 0) { + ed25519_cert_extension_free(*output); + *output = NULL; + } + return result; +} +ed25519_cert_t * +ed25519_cert_new(void) +{ + ed25519_cert_t *val = trunnel_calloc(1, sizeof(ed25519_cert_t)); + if (NULL == val) + return NULL; + val->version = 1; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +ed25519_cert_clear(ed25519_cert_t *obj) +{ + (void) obj; + { + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ext); ++idx) { + ed25519_cert_extension_free(TRUNNEL_DYNARRAY_GET(&obj->ext, idx)); + } + } + TRUNNEL_DYNARRAY_WIPE(&obj->ext); + TRUNNEL_DYNARRAY_CLEAR(&obj->ext); +} + +void +ed25519_cert_free(ed25519_cert_t *obj) +{ + if (obj == NULL) + return; + ed25519_cert_clear(obj); + trunnel_memwipe(obj, sizeof(ed25519_cert_t)); + trunnel_free_(obj); +} + +uint8_t +ed25519_cert_get_version(ed25519_cert_t *inp) +{ + return inp->version; +} +int +ed25519_cert_set_version(ed25519_cert_t *inp, uint8_t val) +{ + if (! ((val == 1))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->version = val; + return 0; +} +uint8_t +ed25519_cert_get_cert_type(ed25519_cert_t *inp) +{ + return inp->cert_type; +} +int +ed25519_cert_set_cert_type(ed25519_cert_t *inp, uint8_t val) +{ + inp->cert_type = val; + return 0; +} +uint32_t +ed25519_cert_get_exp_field(ed25519_cert_t *inp) +{ + return inp->exp_field; +} +int +ed25519_cert_set_exp_field(ed25519_cert_t *inp, uint32_t val) +{ + inp->exp_field = val; + return 0; +} +uint8_t +ed25519_cert_get_cert_key_type(ed25519_cert_t *inp) +{ + return inp->cert_key_type; +} +int +ed25519_cert_set_cert_key_type(ed25519_cert_t *inp, uint8_t val) +{ + inp->cert_key_type = val; + return 0; +} +size_t +ed25519_cert_getlen_certified_key(const ed25519_cert_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +ed25519_cert_get_certified_key(const ed25519_cert_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->certified_key[idx]; +} + +int +ed25519_cert_set_certified_key(ed25519_cert_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->certified_key[idx] = elt; + return 0; +} + +uint8_t * +ed25519_cert_getarray_certified_key(ed25519_cert_t *inp) +{ + return inp->certified_key; +} +uint8_t +ed25519_cert_get_n_extensions(ed25519_cert_t *inp) +{ + return inp->n_extensions; +} +int +ed25519_cert_set_n_extensions(ed25519_cert_t *inp, uint8_t val) +{ + inp->n_extensions = val; + return 0; +} +size_t +ed25519_cert_getlen_ext(const ed25519_cert_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->ext); +} + +struct ed25519_cert_extension_st * +ed25519_cert_get_ext(ed25519_cert_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->ext, idx); +} + +int +ed25519_cert_set_ext(ed25519_cert_t *inp, size_t idx, struct ed25519_cert_extension_st * elt) +{ + ed25519_cert_extension_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->ext, idx); + if (oldval && oldval != elt) + ed25519_cert_extension_free(oldval); + return ed25519_cert_set0_ext(inp, idx, elt); +} +int +ed25519_cert_set0_ext(ed25519_cert_t *inp, size_t idx, struct ed25519_cert_extension_st * elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->ext, idx, elt); + return 0; +} +int +ed25519_cert_add_ext(ed25519_cert_t *inp, struct ed25519_cert_extension_st * elt) +{ +#if SIZE_MAX >= UINT8_MAX + if (inp->ext.n_ == UINT8_MAX) + goto trunnel_alloc_failed; +#endif + TRUNNEL_DYNARRAY_ADD(struct ed25519_cert_extension_st *, &inp->ext, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +struct ed25519_cert_extension_st * * +ed25519_cert_getarray_ext(ed25519_cert_t *inp) +{ + return inp->ext.elts_; +} +int +ed25519_cert_setlen_ext(ed25519_cert_t *inp, size_t newlen) +{ + struct ed25519_cert_extension_st * *newptr; +#if UINT8_MAX < SIZE_MAX + if (newlen > UINT8_MAX) + goto trunnel_alloc_failed; +#endif + newptr = trunnel_dynarray_setlen(&inp->ext.allocated_, + &inp->ext.n_, inp->ext.elts_, newlen, + sizeof(inp->ext.elts_[0]), (trunnel_free_fn_t) ed25519_cert_extension_free, + &inp->trunnel_error_code_); + if (newptr == NULL) + goto trunnel_alloc_failed; + inp->ext.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +size_t +ed25519_cert_getlen_signature(const ed25519_cert_t *inp) +{ + (void)inp; return 64; +} + +uint8_t +ed25519_cert_get_signature(const ed25519_cert_t *inp, size_t idx) +{ + trunnel_assert(idx < 64); + return inp->signature[idx]; +} + +int +ed25519_cert_set_signature(ed25519_cert_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 64); + inp->signature[idx] = elt; + return 0; +} + +uint8_t * +ed25519_cert_getarray_signature(ed25519_cert_t *inp) +{ + return inp->signature; +} +const char * +ed25519_cert_check(const ed25519_cert_t *obj) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + if (! (obj->version == 1)) + return "Integer out of bounds"; + { + const char *msg; + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ext); ++idx) { + if (NULL != (msg = ed25519_cert_extension_check(TRUNNEL_DYNARRAY_GET(&obj->ext, idx)))) + return msg; + } + } + if (TRUNNEL_DYNARRAY_LEN(&obj->ext) != obj->n_extensions) + return "Length mismatch for ext"; + return NULL; +} + +ssize_t +ed25519_cert_encoded_len(const ed25519_cert_t *obj) +{ + ssize_t result = 0; + + if (NULL != ed25519_cert_check(obj)) + return -1; + + + /* Length of u8 version IN [1] */ + result += 1; + + /* Length of u8 cert_type */ + result += 1; + + /* Length of u32 exp_field */ + result += 4; + + /* Length of u8 cert_key_type */ + result += 1; + + /* Length of u8 certified_key[32] */ + result += 32; + + /* Length of u8 n_extensions */ + result += 1; + + /* Length of struct ed25519_cert_extension ext[n_extensions] */ + { + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ext); ++idx) { + result += ed25519_cert_extension_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->ext, idx)); + } + } + + /* Length of u8 signature[64] */ + result += 64; + return result; +} +int +ed25519_cert_clear_errors(ed25519_cert_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +ed25519_cert_encode(uint8_t *output, const size_t avail, const ed25519_cert_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 = ed25519_cert_encoded_len(obj); +#endif + + if (NULL != (msg = ed25519_cert_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 version IN [1] */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->version)); + written += 1; ptr += 1; + + /* Encode u8 cert_type */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->cert_type)); + written += 1; ptr += 1; + + /* Encode u32 exp_field */ + trunnel_assert(written <= avail); + if (avail - written < 4) + goto truncated; + trunnel_set_uint32(ptr, trunnel_htonl(obj->exp_field)); + written += 4; ptr += 4; + + /* Encode u8 cert_key_type */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->cert_key_type)); + written += 1; ptr += 1; + + /* Encode u8 certified_key[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->certified_key, 32); + written += 32; ptr += 32; + + /* Encode u8 n_extensions */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->n_extensions)); + written += 1; ptr += 1; + + /* Encode struct ed25519_cert_extension ext[n_extensions] */ + { + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ext); ++idx) { + trunnel_assert(written <= avail); + result = ed25519_cert_extension_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->ext, idx)); + if (result < 0) + goto fail; /* XXXXXXX !*/ + written += result; ptr += result; + } + } + + /* Encode u8 signature[64] */ + trunnel_assert(written <= avail); + if (avail - written < 64) + goto truncated; + memcpy(ptr, obj->signature, 64); + written += 64; ptr += 64; + + + 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 ed25519_cert_parse(), but do not allocate the output object. + */ +static ssize_t +ed25519_cert_parse_into(ed25519_cert_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 version IN [1] */ + CHECK_REMAINING(1, truncated); + obj->version = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->version == 1)) + goto fail; + + /* Parse u8 cert_type */ + CHECK_REMAINING(1, truncated); + obj->cert_type = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + + /* Parse u32 exp_field */ + CHECK_REMAINING(4, truncated); + obj->exp_field = trunnel_ntohl(trunnel_get_uint32(ptr)); + remaining -= 4; ptr += 4; + + /* Parse u8 cert_key_type */ + CHECK_REMAINING(1, truncated); + obj->cert_key_type = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + + /* Parse u8 certified_key[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->certified_key, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u8 n_extensions */ + CHECK_REMAINING(1, truncated); + obj->n_extensions = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + + /* Parse struct ed25519_cert_extension ext[n_extensions] */ + TRUNNEL_DYNARRAY_EXPAND(ed25519_cert_extension_t *, &obj->ext, obj->n_extensions, {}); + { + ed25519_cert_extension_t * elt; + unsigned idx; + for (idx = 0; idx < obj->n_extensions; ++idx) { + result = ed25519_cert_extension_parse(&elt, ptr, remaining); + if (result < 0) + goto relay_fail; + trunnel_assert((size_t)result <= remaining); + remaining -= result; ptr += result; + TRUNNEL_DYNARRAY_ADD(ed25519_cert_extension_t *, &obj->ext, elt, {ed25519_cert_extension_free(elt);}); + } + } + + /* Parse u8 signature[64] */ + CHECK_REMAINING(64, truncated); + memcpy(obj->signature, ptr, 64); + remaining -= 64; ptr += 64; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + relay_fail: + if (result >= 0) result = -1; + return result; + trunnel_alloc_failed: + return -1; + fail: + result = -1; + return result; +} + +ssize_t +ed25519_cert_parse(ed25519_cert_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = ed25519_cert_new(); + if (NULL == *output) + return -1; + result = ed25519_cert_parse_into(*output, input, len_in); + if (result < 0) { + ed25519_cert_free(*output); + *output = NULL; + } + return result; +} diff --git a/src/trunnel/ed25519_cert.h b/src/trunnel/ed25519_cert.h new file mode 100644 index 0000000000..3ddf95ef9f --- /dev/null +++ b/src/trunnel/ed25519_cert.h @@ -0,0 +1,288 @@ +/* ed25519_cert.h -- generated by by Trunnel v1.2. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#ifndef TRUNNEL_ED25519_CERT_H +#define TRUNNEL_ED25519_CERT_H + +#include +#include "trunnel.h" + +#define CERTEXT_SIGNED_WITH_KEY 4 +#define CERTEXT_FLAG_AFFECTS_VALIDATION 1 +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_ED25519_CERT_EXTENSION) +struct ed25519_cert_extension_st { + uint16_t ext_length; + uint8_t ext_type; + uint8_t ext_flags; + uint8_t un_signing_key[32]; + TRUNNEL_DYNARRAY_HEAD(, uint8_t) un_unparsed; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct ed25519_cert_extension_st ed25519_cert_extension_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_ED25519_CERT) +struct ed25519_cert_st { + uint8_t version; + uint8_t cert_type; + uint32_t exp_field; + uint8_t cert_key_type; + uint8_t certified_key[32]; + uint8_t n_extensions; + TRUNNEL_DYNARRAY_HEAD(, struct ed25519_cert_extension_st *) ext; + uint8_t signature[64]; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct ed25519_cert_st ed25519_cert_t; +/** Return a newly allocated ed25519_cert_extension with all elements + * set to zero. + */ +ed25519_cert_extension_t *ed25519_cert_extension_new(void); +/** Release all storage held by the ed25519_cert_extension in + * 'victim'. (Do nothing if 'victim' is NULL.) + */ +void ed25519_cert_extension_free(ed25519_cert_extension_t *victim); +/** Try to parse a ed25519_cert_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 ed25519_cert_extension_t. On failure, return -2 if the + * input appears truncated, and -1 if the input is otherwise invalid. + */ +ssize_t ed25519_cert_extension_parse(ed25519_cert_extension_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * ed25519_cert_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 ed25519_cert_extension_encoded_len(const ed25519_cert_extension_t *obj); +/** Try to encode the ed25519_cert_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 ed25519_cert_extension_encode(uint8_t *output, const size_t avail, const ed25519_cert_extension_t *input); +/** Check whether the internal state of the ed25519_cert_extension in + * 'obj' is consistent. Return NULL if it is, and a short message if + * it is not. + */ +const char *ed25519_cert_extension_check(const ed25519_cert_extension_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int ed25519_cert_extension_clear_errors(ed25519_cert_extension_t *obj); +/** Return the value of the ext_length field of the + * ed25519_cert_extension_t in 'inp' + */ +uint16_t ed25519_cert_extension_get_ext_length(ed25519_cert_extension_t *inp); +/** Set the value of the ext_length field of the + * ed25519_cert_extension_t in 'inp' to 'val'. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int ed25519_cert_extension_set_ext_length(ed25519_cert_extension_t *inp, uint16_t val); +/** Return the value of the ext_type field of the + * ed25519_cert_extension_t in 'inp' + */ +uint8_t ed25519_cert_extension_get_ext_type(ed25519_cert_extension_t *inp); +/** Set the value of the ext_type field of the + * ed25519_cert_extension_t in 'inp' to 'val'. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int ed25519_cert_extension_set_ext_type(ed25519_cert_extension_t *inp, uint8_t val); +/** Return the value of the ext_flags field of the + * ed25519_cert_extension_t in 'inp' + */ +uint8_t ed25519_cert_extension_get_ext_flags(ed25519_cert_extension_t *inp); +/** Set the value of the ext_flags field of the + * ed25519_cert_extension_t in 'inp' to 'val'. Return 0 on success; + * return -1 and set the error code on 'inp' on failure. + */ +int ed25519_cert_extension_set_ext_flags(ed25519_cert_extension_t *inp, uint8_t val); +/** Return the (constant) length of the array holding the + * un_signing_key field of the ed25519_cert_extension_t in 'inp'. + */ +size_t ed25519_cert_extension_getlen_un_signing_key(const ed25519_cert_extension_t *inp); +/** Return the element at position 'idx' of the fixed array field + * un_signing_key of the ed25519_cert_extension_t in 'inp'. + */ +uint8_t ed25519_cert_extension_get_un_signing_key(const ed25519_cert_extension_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * un_signing_key of the ed25519_cert_extension_t in 'inp', so that it + * will hold the value 'elt'. + */ +int ed25519_cert_extension_set_un_signing_key(ed25519_cert_extension_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field un_signing_key of + * 'inp'. + */ +uint8_t * ed25519_cert_extension_getarray_un_signing_key(ed25519_cert_extension_t *inp); +/** Return the length of the dynamic array holding the un_unparsed + * field of the ed25519_cert_extension_t in 'inp'. + */ +size_t ed25519_cert_extension_getlen_un_unparsed(const ed25519_cert_extension_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * un_unparsed of the ed25519_cert_extension_t in 'inp'. + */ +uint8_t ed25519_cert_extension_get_un_unparsed(ed25519_cert_extension_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * un_unparsed of the ed25519_cert_extension_t in 'inp', so that it + * will hold the value 'elt'. + */ +int ed25519_cert_extension_set_un_unparsed(ed25519_cert_extension_t *inp, size_t idx, uint8_t elt); +/** Append a new element 'elt' to the dynamic array field un_unparsed + * of the ed25519_cert_extension_t in 'inp'. + */ +int ed25519_cert_extension_add_un_unparsed(ed25519_cert_extension_t *inp, uint8_t elt); +/** Return a pointer to the variable-length array field un_unparsed of + * 'inp'. + */ +uint8_t * ed25519_cert_extension_getarray_un_unparsed(ed25519_cert_extension_t *inp); +/** Change the length of the variable-length array field un_unparsed + * 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 ed25519_cert_extension_setlen_un_unparsed(ed25519_cert_extension_t *inp, size_t newlen); +/** Return a newly allocated ed25519_cert with all elements set to + * zero. + */ +ed25519_cert_t *ed25519_cert_new(void); +/** Release all storage held by the ed25519_cert in 'victim'. (Do + * nothing if 'victim' is NULL.) + */ +void ed25519_cert_free(ed25519_cert_t *victim); +/** Try to parse a ed25519_cert 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 + * ed25519_cert_t. On failure, return -2 if the input appears + * truncated, and -1 if the input is otherwise invalid. + */ +ssize_t ed25519_cert_parse(ed25519_cert_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * ed25519_cert 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 ed25519_cert_encoded_len(const ed25519_cert_t *obj); +/** Try to encode the ed25519_cert 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 ed25519_cert_encode(uint8_t *output, const size_t avail, const ed25519_cert_t *input); +/** Check whether the internal state of the ed25519_cert in 'obj' is + * consistent. Return NULL if it is, and a short message if it is not. + */ +const char *ed25519_cert_check(const ed25519_cert_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int ed25519_cert_clear_errors(ed25519_cert_t *obj); +/** Return the value of the version field of the ed25519_cert_t in + * 'inp' + */ +uint8_t ed25519_cert_get_version(ed25519_cert_t *inp); +/** Set the value of the version field of the ed25519_cert_t in 'inp' + * to 'val'. Return 0 on success; return -1 and set the error code on + * 'inp' on failure. + */ +int ed25519_cert_set_version(ed25519_cert_t *inp, uint8_t val); +/** Return the value of the cert_type field of the ed25519_cert_t in + * 'inp' + */ +uint8_t ed25519_cert_get_cert_type(ed25519_cert_t *inp); +/** Set the value of the cert_type field of the ed25519_cert_t in + * 'inp' to 'val'. Return 0 on success; return -1 and set the error + * code on 'inp' on failure. + */ +int ed25519_cert_set_cert_type(ed25519_cert_t *inp, uint8_t val); +/** Return the value of the exp_field field of the ed25519_cert_t in + * 'inp' + */ +uint32_t ed25519_cert_get_exp_field(ed25519_cert_t *inp); +/** Set the value of the exp_field field of the ed25519_cert_t in + * 'inp' to 'val'. Return 0 on success; return -1 and set the error + * code on 'inp' on failure. + */ +int ed25519_cert_set_exp_field(ed25519_cert_t *inp, uint32_t val); +/** Return the value of the cert_key_type field of the ed25519_cert_t + * in 'inp' + */ +uint8_t ed25519_cert_get_cert_key_type(ed25519_cert_t *inp); +/** Set the value of the cert_key_type field of the ed25519_cert_t in + * 'inp' to 'val'. Return 0 on success; return -1 and set the error + * code on 'inp' on failure. + */ +int ed25519_cert_set_cert_key_type(ed25519_cert_t *inp, uint8_t val); +/** Return the (constant) length of the array holding the + * certified_key field of the ed25519_cert_t in 'inp'. + */ +size_t ed25519_cert_getlen_certified_key(const ed25519_cert_t *inp); +/** Return the element at position 'idx' of the fixed array field + * certified_key of the ed25519_cert_t in 'inp'. + */ +uint8_t ed25519_cert_get_certified_key(const ed25519_cert_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * certified_key of the ed25519_cert_t in 'inp', so that it will hold + * the value 'elt'. + */ +int ed25519_cert_set_certified_key(ed25519_cert_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field certified_key of + * 'inp'. + */ +uint8_t * ed25519_cert_getarray_certified_key(ed25519_cert_t *inp); +/** Return the value of the n_extensions field of the ed25519_cert_t + * in 'inp' + */ +uint8_t ed25519_cert_get_n_extensions(ed25519_cert_t *inp); +/** Set the value of the n_extensions field of the ed25519_cert_t in + * 'inp' to 'val'. Return 0 on success; return -1 and set the error + * code on 'inp' on failure. + */ +int ed25519_cert_set_n_extensions(ed25519_cert_t *inp, uint8_t val); +/** Return the length of the dynamic array holding the ext field of + * the ed25519_cert_t in 'inp'. + */ +size_t ed25519_cert_getlen_ext(const ed25519_cert_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * ext of the ed25519_cert_t in 'inp'. + */ +struct ed25519_cert_extension_st * ed25519_cert_get_ext(ed25519_cert_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * ext of the ed25519_cert_t in 'inp', so that it will hold the value + * 'elt'. Free the previous value, if any. + */ +int ed25519_cert_set_ext(ed25519_cert_t *inp, size_t idx, struct ed25519_cert_extension_st * elt); +/** As ed25519_cert_set_ext, but does not free the previous value. + */ +int ed25519_cert_set0_ext(ed25519_cert_t *inp, size_t idx, struct ed25519_cert_extension_st * elt); +/** Append a new element 'elt' to the dynamic array field ext of the + * ed25519_cert_t in 'inp'. + */ +int ed25519_cert_add_ext(ed25519_cert_t *inp, struct ed25519_cert_extension_st * elt); +/** Return a pointer to the variable-length array field ext of 'inp'. + */ +struct ed25519_cert_extension_st * * ed25519_cert_getarray_ext(ed25519_cert_t *inp); +/** Change the length of the variable-length array field ext 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 ed25519_cert_setlen_ext(ed25519_cert_t *inp, size_t newlen); +/** Return the (constant) length of the array holding the signature + * field of the ed25519_cert_t in 'inp'. + */ +size_t ed25519_cert_getlen_signature(const ed25519_cert_t *inp); +/** Return the element at position 'idx' of the fixed array field + * signature of the ed25519_cert_t in 'inp'. + */ +uint8_t ed25519_cert_get_signature(const ed25519_cert_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * signature of the ed25519_cert_t in 'inp', so that it will hold the + * value 'elt'. + */ +int ed25519_cert_set_signature(ed25519_cert_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 64-element array field signature of 'inp'. + */ +uint8_t * ed25519_cert_getarray_signature(ed25519_cert_t *inp); + + +#endif diff --git a/src/trunnel/ed25519_cert.trunnel b/src/trunnel/ed25519_cert.trunnel new file mode 100644 index 0000000000..c46f1b6c6b --- /dev/null +++ b/src/trunnel/ed25519_cert.trunnel @@ -0,0 +1,76 @@ + +struct ed25519_cert { + u8 version IN [1]; + u8 cert_type; + u32 exp_field; + u8 cert_key_type; + u8 certified_key[32]; + u8 n_extensions; + struct ed25519_cert_extension ext[n_extensions]; + u8 signature[64]; +} + +const CERTEXT_SIGNED_WITH_KEY = 4; +const CERTEXT_FLAG_AFFECTS_VALIDATION = 1; + +struct ed25519_cert_extension { + u16 ext_length; + u8 ext_type; + u8 ext_flags; + union un[ext_type] with length ext_length { + CERTEXT_SIGNED_WITH_KEY : u8 signing_key[32]; + default: u8 unparsed[]; + }; +} + +/* +struct cert_revocation { + u8 prefix[8]; + u8 version IN [1]; + u8 keytype; + u8 identity_key[32]; + u8 revoked_key[32]; + u64 published; + u8 n_extensions; + struct cert_extension ext[n_extensions]; + u8 signature[64]; +} + +struct crosscert_ed_rsa { + u8 ed_key[32]; + u32 expiration_date; + u8 signature[128]; +} + +struct auth02_cell { + u8 type[8]; + u8 cid[32]; + u8 sid[32]; + u8 cid_ed[32]; + u8 sid_ed[32]; + u8 slog[32]; + u8 clog[32]; + u8 scert[32]; + u8 tlssecrets[32]; + u8 rand[24]; + u8 sig[64]; +} + +const LS_IPV4 = 0x00; +const LS_IPV6 = 0x01; +const LS_LEGACY_ID = 0x02; +const LS_ED25519_ID = 0x03; + +// amended from tor.trunnel +struct link_specifier { + u8 ls_type; + u8 ls_len; + union un[ls_type] with length ls_len { + LS_IPV4: u32 ipv4_addr; u16 ipv4_port; + LS_IPV6: u8 ipv6_addr[16]; u16 ipv6_port; + LS_LEGACY_ID: u8 legacy_id[20]; + LS_ED25519_ID: u8 ed25519_id[32]; + default: u8 unrecognized[]; + }; +} +*/ \ No newline at end of file diff --git a/src/trunnel/include.am b/src/trunnel/include.am index c7ac1679d0..6e7851aafe 100644 --- a/src/trunnel/include.am +++ b/src/trunnel/include.am @@ -9,15 +9,21 @@ endif AM_CPPFLAGS += -I$(srcdir)/src/ext/trunnel -I$(srcdir)/src/trunnel +TRUNNELINPUTS = \ + src/trunnel/ed25519_cert.trunnel \ + src/trunnel/pwbox.trunnel + TRUNNELSOURCES = \ - src/ext/trunnel/trunnel.c \ - src/trunnel/pwbox.c + src/ext/trunnel/trunnel.c \ + src/trunnel/ed25519_cert.c \ + src/trunnel/pwbox.c TRUNNELHEADERS = \ - src/ext/trunnel/trunnel.h \ - src/ext/trunnel/trunnel-impl.h \ - src/trunnel/trunnel-local.h \ - src/trunnel/pwbox.h + src/ext/trunnel/trunnel.h \ + src/ext/trunnel/trunnel-impl.h \ + src/trunnel/trunnel-local.h \ + src/trunnel/ed25519_cert.h \ + src/trunnel/pwbox.h src_trunnel_libor_trunnel_a_SOURCES = $(TRUNNELSOURCES) src_trunnel_libor_trunnel_a_CPPFLAGS = -DTRUNNEL_LOCAL_H $(AM_CPPFLAGS) -- cgit v1.2.3-54-g00ecf From df05e195ee64d7ed1b5a1b5d74c5868683788ba2 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 8 Oct 2014 14:43:33 -0400 Subject: Add trunnel-generated items for link handshake code. This includes the link handshake variations for proposal220. We'll use this for testing first, and then use it to extend our current code to support prop220. --- scripts/codegen/run_trunnel.sh | 4 +- src/trunnel/include.am | 3 + src/trunnel/link_handshake.c | 1885 ++++++++++++++++++++++++++++++++++++ src/trunnel/link_handshake.h | 654 +++++++++++++ src/trunnel/link_handshake.trunnel | 57 ++ 5 files changed, 2601 insertions(+), 2 deletions(-) create mode 100644 src/trunnel/link_handshake.c create mode 100644 src/trunnel/link_handshake.h create mode 100644 src/trunnel/link_handshake.trunnel (limited to 'src/trunnel') diff --git a/scripts/codegen/run_trunnel.sh b/scripts/codegen/run_trunnel.sh index 5f694ce6c9..d2669931e9 100755 --- a/scripts/codegen/run_trunnel.sh +++ b/scripts/codegen/run_trunnel.sh @@ -5,7 +5,7 @@ if test "x$TRUNNEL_PATH" != "x"; then export PYTHONPATH fi -python -m trunnel --require-version=1.2 ./src/trunnel/*.trunnel +python -m trunnel --require-version=1.4 ./src/trunnel/*.trunnel -python -m trunnel --require-version=1.2 --write-c-files --target-dir=./src/ext/trunnel/ +python -m trunnel --require-version=1.4 --write-c-files --target-dir=./src/ext/trunnel/ diff --git a/src/trunnel/include.am b/src/trunnel/include.am index 6e7851aafe..2d8c051f19 100644 --- a/src/trunnel/include.am +++ b/src/trunnel/include.am @@ -11,11 +11,13 @@ AM_CPPFLAGS += -I$(srcdir)/src/ext/trunnel -I$(srcdir)/src/trunnel TRUNNELINPUTS = \ src/trunnel/ed25519_cert.trunnel \ + src/trunnel/link_handshake.trunnel \ src/trunnel/pwbox.trunnel TRUNNELSOURCES = \ src/ext/trunnel/trunnel.c \ src/trunnel/ed25519_cert.c \ + src/trunnel/link_handshake.c \ src/trunnel/pwbox.c TRUNNELHEADERS = \ @@ -23,6 +25,7 @@ TRUNNELHEADERS = \ src/ext/trunnel/trunnel-impl.h \ src/trunnel/trunnel-local.h \ src/trunnel/ed25519_cert.h \ + src/trunnel/link_handshake.h \ src/trunnel/pwbox.h src_trunnel_libor_trunnel_a_SOURCES = $(TRUNNELSOURCES) diff --git a/src/trunnel/link_handshake.c b/src/trunnel/link_handshake.c new file mode 100644 index 0000000000..9630d1340d --- /dev/null +++ b/src/trunnel/link_handshake.c @@ -0,0 +1,1885 @@ +/* link_handshake.c -- generated by Trunnel v1.4-pre. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#include +#include "trunnel-impl.h" + +#include "link_handshake.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 linkhandshake_deadcode_dummy__ = 0; +#define OR_DEADCODE_DUMMY || linkhandshake_deadcode_dummy__ +#else +#define OR_DEADCODE_DUMMY +#endif + +#define CHECK_REMAINING(nbytes, label) \ + do { \ + if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \ + goto label; \ + } \ + } while (0) + +auth_challenge_cell_t * +auth_challenge_cell_new(void) +{ + auth_challenge_cell_t *val = trunnel_calloc(1, sizeof(auth_challenge_cell_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +auth_challenge_cell_clear(auth_challenge_cell_t *obj) +{ + (void) obj; + TRUNNEL_DYNARRAY_WIPE(&obj->methods); + TRUNNEL_DYNARRAY_CLEAR(&obj->methods); +} + +void +auth_challenge_cell_free(auth_challenge_cell_t *obj) +{ + if (obj == NULL) + return; + auth_challenge_cell_clear(obj); + trunnel_memwipe(obj, sizeof(auth_challenge_cell_t)); + trunnel_free_(obj); +} + +size_t +auth_challenge_cell_getlen_challenge(const auth_challenge_cell_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth_challenge_cell_get_challenge(const auth_challenge_cell_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->challenge[idx]; +} + +int +auth_challenge_cell_set_challenge(auth_challenge_cell_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->challenge[idx] = elt; + return 0; +} + +uint8_t * +auth_challenge_cell_getarray_challenge(auth_challenge_cell_t *inp) +{ + return inp->challenge; +} +uint16_t +auth_challenge_cell_get_n_methods(auth_challenge_cell_t *inp) +{ + return inp->n_methods; +} +int +auth_challenge_cell_set_n_methods(auth_challenge_cell_t *inp, uint16_t val) +{ + inp->n_methods = val; + return 0; +} +size_t +auth_challenge_cell_getlen_methods(const auth_challenge_cell_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->methods); +} + +uint16_t +auth_challenge_cell_get_methods(auth_challenge_cell_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->methods, idx); +} + +int +auth_challenge_cell_set_methods(auth_challenge_cell_t *inp, size_t idx, uint16_t elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->methods, idx, elt); + return 0; +} +int +auth_challenge_cell_add_methods(auth_challenge_cell_t *inp, uint16_t elt) +{ +#if SIZE_MAX >= UINT16_MAX + if (inp->methods.n_ == UINT16_MAX) + goto trunnel_alloc_failed; +#endif + TRUNNEL_DYNARRAY_ADD(uint16_t, &inp->methods, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +uint16_t * +auth_challenge_cell_getarray_methods(auth_challenge_cell_t *inp) +{ + return inp->methods.elts_; +} +int +auth_challenge_cell_setlen_methods(auth_challenge_cell_t *inp, size_t newlen) +{ + uint16_t *newptr; +#if UINT16_MAX < SIZE_MAX + if (newlen > UINT16_MAX) + goto trunnel_alloc_failed; +#endif + newptr = trunnel_dynarray_setlen(&inp->methods.allocated_, + &inp->methods.n_, inp->methods.elts_, newlen, + sizeof(inp->methods.elts_[0]), (trunnel_free_fn_t) NULL, + &inp->trunnel_error_code_); + if (newptr == NULL) + goto trunnel_alloc_failed; + inp->methods.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +const char * +auth_challenge_cell_check(const auth_challenge_cell_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->methods) != obj->n_methods) + return "Length mismatch for methods"; + return NULL; +} + +ssize_t +auth_challenge_cell_encoded_len(const auth_challenge_cell_t *obj) +{ + ssize_t result = 0; + + if (NULL != auth_challenge_cell_check(obj)) + return -1; + + + /* Length of u8 challenge[32] */ + result += 32; + + /* Length of u16 n_methods */ + result += 2; + + /* Length of u16 methods[n_methods] */ + result += 2 * TRUNNEL_DYNARRAY_LEN(&obj->methods); + return result; +} +int +auth_challenge_cell_clear_errors(auth_challenge_cell_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +auth_challenge_cell_encode(uint8_t *output, const size_t avail, const auth_challenge_cell_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 = auth_challenge_cell_encoded_len(obj); +#endif + + if (NULL != (msg = auth_challenge_cell_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 challenge[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->challenge, 32); + written += 32; ptr += 32; + + /* Encode u16 n_methods */ + trunnel_assert(written <= avail); + if (avail - written < 2) + goto truncated; + trunnel_set_uint16(ptr, trunnel_htons(obj->n_methods)); + written += 2; ptr += 2; + + /* Encode u16 methods[n_methods] */ + { + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->methods); ++idx) { + trunnel_assert(written <= avail); + if (avail - written < 2) + goto truncated; + trunnel_set_uint16(ptr, trunnel_htons(TRUNNEL_DYNARRAY_GET(&obj->methods, idx))); + written += 2; ptr += 2; + } + } + + + 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 auth_challenge_cell_parse(), but do not allocate the output + * object. + */ +static ssize_t +auth_challenge_cell_parse_into(auth_challenge_cell_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 challenge[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->challenge, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u16 n_methods */ + CHECK_REMAINING(2, truncated); + obj->n_methods = trunnel_ntohs(trunnel_get_uint16(ptr)); + remaining -= 2; ptr += 2; + + /* Parse u16 methods[n_methods] */ + TRUNNEL_DYNARRAY_EXPAND(uint16_t, &obj->methods, obj->n_methods, {}); + { + uint16_t elt; + unsigned idx; + for (idx = 0; idx < obj->n_methods; ++idx) { + CHECK_REMAINING(2, truncated); + elt = trunnel_ntohs(trunnel_get_uint16(ptr)); + remaining -= 2; ptr += 2; + TRUNNEL_DYNARRAY_ADD(uint16_t, &obj->methods, elt, {}); + } + } + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + trunnel_alloc_failed: + return -1; +} + +ssize_t +auth_challenge_cell_parse(auth_challenge_cell_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = auth_challenge_cell_new(); + if (NULL == *output) + return -1; + result = auth_challenge_cell_parse_into(*output, input, len_in); + if (result < 0) { + auth_challenge_cell_free(*output); + *output = NULL; + } + return result; +} +auth_ctx_t * +auth_ctx_new(void) +{ + auth_ctx_t *val = trunnel_calloc(1, sizeof(auth_ctx_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +auth_ctx_clear(auth_ctx_t *obj) +{ + (void) obj; +} + +void +auth_ctx_free(auth_ctx_t *obj) +{ + if (obj == NULL) + return; + auth_ctx_clear(obj); + trunnel_memwipe(obj, sizeof(auth_ctx_t)); + trunnel_free_(obj); +} + +uint8_t +auth_ctx_get_is_ed(auth_ctx_t *inp) +{ + return inp->is_ed; +} +int +auth_ctx_set_is_ed(auth_ctx_t *inp, uint8_t val) +{ + inp->is_ed = val; + return 0; +} +certs_cell_cert_t * +certs_cell_cert_new(void) +{ + certs_cell_cert_t *val = trunnel_calloc(1, sizeof(certs_cell_cert_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +certs_cell_cert_clear(certs_cell_cert_t *obj) +{ + (void) obj; + TRUNNEL_DYNARRAY_WIPE(&obj->body); + TRUNNEL_DYNARRAY_CLEAR(&obj->body); +} + +void +certs_cell_cert_free(certs_cell_cert_t *obj) +{ + if (obj == NULL) + return; + certs_cell_cert_clear(obj); + trunnel_memwipe(obj, sizeof(certs_cell_cert_t)); + trunnel_free_(obj); +} + +uint8_t +certs_cell_cert_get_cert_type(certs_cell_cert_t *inp) +{ + return inp->cert_type; +} +int +certs_cell_cert_set_cert_type(certs_cell_cert_t *inp, uint8_t val) +{ + inp->cert_type = val; + return 0; +} +uint16_t +certs_cell_cert_get_cert_len(certs_cell_cert_t *inp) +{ + return inp->cert_len; +} +int +certs_cell_cert_set_cert_len(certs_cell_cert_t *inp, uint16_t val) +{ + inp->cert_len = val; + return 0; +} +size_t +certs_cell_cert_getlen_body(const certs_cell_cert_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->body); +} + +uint8_t +certs_cell_cert_get_body(certs_cell_cert_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->body, idx); +} + +int +certs_cell_cert_set_body(certs_cell_cert_t *inp, size_t idx, uint8_t elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->body, idx, elt); + return 0; +} +int +certs_cell_cert_add_body(certs_cell_cert_t *inp, uint8_t elt) +{ +#if SIZE_MAX >= UINT16_MAX + if (inp->body.n_ == UINT16_MAX) + goto trunnel_alloc_failed; +#endif + TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->body, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +uint8_t * +certs_cell_cert_getarray_body(certs_cell_cert_t *inp) +{ + return inp->body.elts_; +} +int +certs_cell_cert_setlen_body(certs_cell_cert_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->body.allocated_, + &inp->body.n_, inp->body.elts_, newlen, + sizeof(inp->body.elts_[0]), (trunnel_free_fn_t) NULL, + &inp->trunnel_error_code_); + if (newptr == NULL) + goto trunnel_alloc_failed; + inp->body.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +const char * +certs_cell_cert_check(const certs_cell_cert_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->body) != obj->cert_len) + return "Length mismatch for body"; + return NULL; +} + +ssize_t +certs_cell_cert_encoded_len(const certs_cell_cert_t *obj) +{ + ssize_t result = 0; + + if (NULL != certs_cell_cert_check(obj)) + return -1; + + + /* Length of u8 cert_type */ + result += 1; + + /* Length of u16 cert_len */ + result += 2; + + /* Length of u8 body[cert_len] */ + result += TRUNNEL_DYNARRAY_LEN(&obj->body); + return result; +} +int +certs_cell_cert_clear_errors(certs_cell_cert_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +certs_cell_cert_encode(uint8_t *output, const size_t avail, const certs_cell_cert_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 = certs_cell_cert_encoded_len(obj); +#endif + + if (NULL != (msg = certs_cell_cert_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 cert_type */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->cert_type)); + written += 1; ptr += 1; + + /* Encode u16 cert_len */ + trunnel_assert(written <= avail); + if (avail - written < 2) + goto truncated; + trunnel_set_uint16(ptr, trunnel_htons(obj->cert_len)); + written += 2; ptr += 2; + + /* Encode u8 body[cert_len] */ + { + size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->body); + trunnel_assert(obj->cert_len == elt_len); + trunnel_assert(written <= avail); + if (avail - written < elt_len) + goto truncated; + memcpy(ptr, obj->body.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 certs_cell_cert_parse(), but do not allocate the output object. + */ +static ssize_t +certs_cell_cert_parse_into(certs_cell_cert_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 cert_type */ + CHECK_REMAINING(1, truncated); + obj->cert_type = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + + /* Parse u16 cert_len */ + CHECK_REMAINING(2, truncated); + obj->cert_len = trunnel_ntohs(trunnel_get_uint16(ptr)); + remaining -= 2; ptr += 2; + + /* Parse u8 body[cert_len] */ + CHECK_REMAINING(obj->cert_len, truncated); + TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->body, obj->cert_len, {}); + obj->body.n_ = obj->cert_len; + memcpy(obj->body.elts_, ptr, obj->cert_len); + ptr += obj->cert_len; remaining -= obj->cert_len; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + trunnel_alloc_failed: + return -1; +} + +ssize_t +certs_cell_cert_parse(certs_cell_cert_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = certs_cell_cert_new(); + if (NULL == *output) + return -1; + result = certs_cell_cert_parse_into(*output, input, len_in); + if (result < 0) { + certs_cell_cert_free(*output); + *output = NULL; + } + return result; +} +rsa_ed_crosscert_t * +rsa_ed_crosscert_new(void) +{ + rsa_ed_crosscert_t *val = trunnel_calloc(1, sizeof(rsa_ed_crosscert_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +rsa_ed_crosscert_clear(rsa_ed_crosscert_t *obj) +{ + (void) obj; + TRUNNEL_DYNARRAY_WIPE(&obj->sig); + TRUNNEL_DYNARRAY_CLEAR(&obj->sig); +} + +void +rsa_ed_crosscert_free(rsa_ed_crosscert_t *obj) +{ + if (obj == NULL) + return; + rsa_ed_crosscert_clear(obj); + trunnel_memwipe(obj, sizeof(rsa_ed_crosscert_t)); + trunnel_free_(obj); +} + +size_t +rsa_ed_crosscert_getlen_ed_key(const rsa_ed_crosscert_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +rsa_ed_crosscert_get_ed_key(const rsa_ed_crosscert_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->ed_key[idx]; +} + +int +rsa_ed_crosscert_set_ed_key(rsa_ed_crosscert_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->ed_key[idx] = elt; + return 0; +} + +uint8_t * +rsa_ed_crosscert_getarray_ed_key(rsa_ed_crosscert_t *inp) +{ + return inp->ed_key; +} +uint32_t +rsa_ed_crosscert_get_expiration(rsa_ed_crosscert_t *inp) +{ + return inp->expiration; +} +int +rsa_ed_crosscert_set_expiration(rsa_ed_crosscert_t *inp, uint32_t val) +{ + inp->expiration = val; + return 0; +} +const uint8_t * +rsa_ed_crosscert_get_end_of_signed(const rsa_ed_crosscert_t *inp) +{ + return inp->end_of_signed; +} +uint8_t +rsa_ed_crosscert_get_sig_len(rsa_ed_crosscert_t *inp) +{ + return inp->sig_len; +} +int +rsa_ed_crosscert_set_sig_len(rsa_ed_crosscert_t *inp, uint8_t val) +{ + inp->sig_len = val; + return 0; +} +size_t +rsa_ed_crosscert_getlen_sig(const rsa_ed_crosscert_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->sig); +} + +uint8_t +rsa_ed_crosscert_get_sig(rsa_ed_crosscert_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->sig, idx); +} + +int +rsa_ed_crosscert_set_sig(rsa_ed_crosscert_t *inp, size_t idx, uint8_t elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->sig, idx, elt); + return 0; +} +int +rsa_ed_crosscert_add_sig(rsa_ed_crosscert_t *inp, uint8_t elt) +{ +#if SIZE_MAX >= UINT8_MAX + if (inp->sig.n_ == UINT8_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 * +rsa_ed_crosscert_getarray_sig(rsa_ed_crosscert_t *inp) +{ + return inp->sig.elts_; +} +int +rsa_ed_crosscert_setlen_sig(rsa_ed_crosscert_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->sig.allocated_, + &inp->sig.n_, inp->sig.elts_, newlen, + sizeof(inp->sig.elts_[0]), (trunnel_free_fn_t) NULL, + &inp->trunnel_error_code_); + if (newptr == NULL) + goto trunnel_alloc_failed; + inp->sig.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +const char * +rsa_ed_crosscert_check(const rsa_ed_crosscert_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->sig) != obj->sig_len) + return "Length mismatch for sig"; + return NULL; +} + +ssize_t +rsa_ed_crosscert_encoded_len(const rsa_ed_crosscert_t *obj) +{ + ssize_t result = 0; + + if (NULL != rsa_ed_crosscert_check(obj)) + return -1; + + + /* Length of u8 ed_key[32] */ + result += 32; + + /* Length of u32 expiration */ + result += 4; + + /* Length of u8 sig_len */ + result += 1; + + /* Length of u8 sig[sig_len] */ + result += TRUNNEL_DYNARRAY_LEN(&obj->sig); + return result; +} +int +rsa_ed_crosscert_clear_errors(rsa_ed_crosscert_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +rsa_ed_crosscert_encode(uint8_t *output, const size_t avail, const rsa_ed_crosscert_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 = rsa_ed_crosscert_encoded_len(obj); +#endif + + if (NULL != (msg = rsa_ed_crosscert_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 ed_key[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->ed_key, 32); + written += 32; ptr += 32; + + /* Encode u32 expiration */ + trunnel_assert(written <= avail); + if (avail - written < 4) + goto truncated; + trunnel_set_uint32(ptr, trunnel_htonl(obj->expiration)); + written += 4; ptr += 4; + + /* Encode u8 sig_len */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->sig_len)); + written += 1; ptr += 1; + + /* 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; + 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 rsa_ed_crosscert_parse(), but do not allocate the output + * object. + */ +static ssize_t +rsa_ed_crosscert_parse_into(rsa_ed_crosscert_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 ed_key[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->ed_key, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u32 expiration */ + CHECK_REMAINING(4, truncated); + obj->expiration = trunnel_ntohl(trunnel_get_uint32(ptr)); + remaining -= 4; ptr += 4; + obj->end_of_signed = ptr; + + /* Parse u8 sig_len */ + CHECK_REMAINING(1, truncated); + obj->sig_len = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + + /* 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; + 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; + trunnel_alloc_failed: + return -1; +} + +ssize_t +rsa_ed_crosscert_parse(rsa_ed_crosscert_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = rsa_ed_crosscert_new(); + if (NULL == *output) + return -1; + result = rsa_ed_crosscert_parse_into(*output, input, len_in); + if (result < 0) { + rsa_ed_crosscert_free(*output); + *output = NULL; + } + return result; +} +auth1_t * +auth1_new(void) +{ + auth1_t *val = trunnel_calloc(1, sizeof(auth1_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +auth1_clear(auth1_t *obj) +{ + (void) obj; + TRUNNEL_DYNARRAY_WIPE(&obj->sig); + TRUNNEL_DYNARRAY_CLEAR(&obj->sig); +} + +void +auth1_free(auth1_t *obj) +{ + if (obj == NULL) + return; + auth1_clear(obj); + trunnel_memwipe(obj, sizeof(auth1_t)); + trunnel_free_(obj); +} + +size_t +auth1_getlen_type(const auth1_t *inp) +{ + (void)inp; return 8; +} + +uint8_t +auth1_get_type(const auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 8); + return inp->type[idx]; +} + +int +auth1_set_type(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 8); + inp->type[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_type(auth1_t *inp) +{ + return inp->type; +} +size_t +auth1_getlen_cid(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_cid(const auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->cid[idx]; +} + +int +auth1_set_cid(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->cid[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_cid(auth1_t *inp) +{ + return inp->cid; +} +size_t +auth1_getlen_sid(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_sid(const auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->sid[idx]; +} + +int +auth1_set_sid(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->sid[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_sid(auth1_t *inp) +{ + return inp->sid; +} +size_t +auth1_getlen_u1_cid_ed(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_u1_cid_ed(const auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->u1_cid_ed[idx]; +} + +int +auth1_set_u1_cid_ed(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->u1_cid_ed[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_u1_cid_ed(auth1_t *inp) +{ + return inp->u1_cid_ed; +} +size_t +auth1_getlen_u1_sid_ed(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_u1_sid_ed(const auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->u1_sid_ed[idx]; +} + +int +auth1_set_u1_sid_ed(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->u1_sid_ed[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_u1_sid_ed(auth1_t *inp) +{ + return inp->u1_sid_ed; +} +size_t +auth1_getlen_slog(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_slog(const auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->slog[idx]; +} + +int +auth1_set_slog(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->slog[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_slog(auth1_t *inp) +{ + return inp->slog; +} +size_t +auth1_getlen_clog(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_clog(const auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->clog[idx]; +} + +int +auth1_set_clog(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->clog[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_clog(auth1_t *inp) +{ + return inp->clog; +} +size_t +auth1_getlen_scert(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_scert(const auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->scert[idx]; +} + +int +auth1_set_scert(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->scert[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_scert(auth1_t *inp) +{ + return inp->scert; +} +size_t +auth1_getlen_tlssecrets(const auth1_t *inp) +{ + (void)inp; return 32; +} + +uint8_t +auth1_get_tlssecrets(const auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 32); + return inp->tlssecrets[idx]; +} + +int +auth1_set_tlssecrets(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 32); + inp->tlssecrets[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_tlssecrets(auth1_t *inp) +{ + return inp->tlssecrets; +} +const uint8_t * +auth1_get_end_of_fixed_part(const auth1_t *inp) +{ + return inp->end_of_fixed_part; +} +size_t +auth1_getlen_rand(const auth1_t *inp) +{ + (void)inp; return 24; +} + +uint8_t +auth1_get_rand(const auth1_t *inp, size_t idx) +{ + trunnel_assert(idx < 24); + return inp->rand[idx]; +} + +int +auth1_set_rand(auth1_t *inp, size_t idx, uint8_t elt) +{ + trunnel_assert(idx < 24); + inp->rand[idx] = elt; + return 0; +} + +uint8_t * +auth1_getarray_rand(auth1_t *inp) +{ + return inp->rand; +} +const uint8_t * +auth1_get_end_of_signed(const auth1_t *inp) +{ + return inp->end_of_signed; +} +size_t +auth1_getlen_sig(const auth1_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->sig); +} + +uint8_t +auth1_get_sig(auth1_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->sig, idx); +} + +int +auth1_set_sig(auth1_t *inp, size_t idx, uint8_t elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->sig, idx, elt); + return 0; +} +int +auth1_add_sig(auth1_t *inp, uint8_t elt) +{ + TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->sig, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +uint8_t * +auth1_getarray_sig(auth1_t *inp) +{ + return inp->sig.elts_; +} +int +auth1_setlen_sig(auth1_t *inp, size_t newlen) +{ + uint8_t *newptr; + 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 (newptr == NULL) + goto trunnel_alloc_failed; + inp->sig.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +const char * +auth1_check(const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx) +{ + if (obj == NULL) + return "Object was NULL"; + if (obj->trunnel_error_code_) + return "A set function failed on this object"; + if (auth_ctx_ctx == NULL) + return "Context was NULL"; + switch (auth_ctx_ctx->is_ed) { + + case 0: + break; + + case 1: + break; + + default: + return "Bad tag for union"; + break; + } + return NULL; +} + +ssize_t +auth1_encoded_len(const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx) +{ + ssize_t result = 0; + + if (NULL != auth1_check(obj, auth_ctx_ctx)) + return -1; + + + /* Length of u8 type[8] */ + result += 8; + + /* Length of u8 cid[32] */ + result += 32; + + /* Length of u8 sid[32] */ + result += 32; + switch (auth_ctx_ctx->is_ed) { + + case 0: + break; + + case 1: + + /* Length of u8 u1_cid_ed[32] */ + result += 32; + + /* Length of u8 u1_sid_ed[32] */ + result += 32; + break; + + default: + trunnel_assert(0); + break; + } + + /* Length of u8 slog[32] */ + result += 32; + + /* Length of u8 clog[32] */ + result += 32; + + /* Length of u8 scert[32] */ + result += 32; + + /* Length of u8 tlssecrets[32] */ + result += 32; + + /* Length of u8 rand[24] */ + result += 24; + + /* Length of u8 sig[] */ + result += TRUNNEL_DYNARRAY_LEN(&obj->sig); + return result; +} +int +auth1_clear_errors(auth1_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +auth1_encode(uint8_t *output, const size_t avail, const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx) +{ + 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 = auth1_encoded_len(obj, auth_ctx_ctx); +#endif + + if (NULL != (msg = auth1_check(obj, auth_ctx_ctx))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 type[8] */ + trunnel_assert(written <= avail); + if (avail - written < 8) + goto truncated; + memcpy(ptr, obj->type, 8); + written += 8; ptr += 8; + + /* Encode u8 cid[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->cid, 32); + written += 32; ptr += 32; + + /* Encode u8 sid[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->sid, 32); + written += 32; ptr += 32; + + /* Encode union u1[auth_ctx.is_ed] */ + trunnel_assert(written <= avail); + switch (auth_ctx_ctx->is_ed) { + + case 0: + break; + + case 1: + + /* Encode u8 u1_cid_ed[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->u1_cid_ed, 32); + written += 32; ptr += 32; + + /* Encode u8 u1_sid_ed[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->u1_sid_ed, 32); + written += 32; ptr += 32; + break; + + default: + trunnel_assert(0); + break; + } + + /* Encode u8 slog[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->slog, 32); + written += 32; ptr += 32; + + /* Encode u8 clog[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->clog, 32); + written += 32; ptr += 32; + + /* Encode u8 scert[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->scert, 32); + written += 32; ptr += 32; + + /* Encode u8 tlssecrets[32] */ + trunnel_assert(written <= avail); + if (avail - written < 32) + goto truncated; + memcpy(ptr, obj->tlssecrets, 32); + written += 32; ptr += 32; + + /* Encode u8 rand[24] */ + trunnel_assert(written <= avail); + if (avail - written < 24) + goto truncated; + memcpy(ptr, obj->rand, 24); + written += 24; ptr += 24; + + /* Encode u8 sig[] */ + { + size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->sig); + trunnel_assert(written <= avail); + if (avail - written < elt_len) + goto truncated; + 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 auth1_parse(), but do not allocate the output object. + */ +static ssize_t +auth1_parse_into(auth1_t *obj, const uint8_t *input, const size_t len_in, const auth_ctx_t *auth_ctx_ctx) +{ + const uint8_t *ptr = input; + size_t remaining = len_in; + ssize_t result = 0; + (void)result; + if (auth_ctx_ctx == NULL) + return -1; + + /* Parse u8 type[8] */ + CHECK_REMAINING(8, truncated); + memcpy(obj->type, ptr, 8); + remaining -= 8; ptr += 8; + + /* Parse u8 cid[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->cid, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u8 sid[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->sid, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse union u1[auth_ctx.is_ed] */ + switch (auth_ctx_ctx->is_ed) { + + case 0: + break; + + case 1: + + /* Parse u8 u1_cid_ed[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->u1_cid_ed, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u8 u1_sid_ed[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->u1_sid_ed, ptr, 32); + remaining -= 32; ptr += 32; + break; + + default: + goto fail; + break; + } + + /* Parse u8 slog[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->slog, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u8 clog[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->clog, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u8 scert[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->scert, ptr, 32); + remaining -= 32; ptr += 32; + + /* Parse u8 tlssecrets[32] */ + CHECK_REMAINING(32, truncated); + memcpy(obj->tlssecrets, ptr, 32); + remaining -= 32; ptr += 32; + obj->end_of_fixed_part = ptr; + + /* Parse u8 rand[24] */ + CHECK_REMAINING(24, truncated); + memcpy(obj->rand, ptr, 24); + remaining -= 24; ptr += 24; + obj->end_of_signed = ptr; + + /* Parse u8 sig[] */ + TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->sig, remaining, {}); + obj->sig.n_ = remaining; + memcpy(obj->sig.elts_, ptr, remaining); + ptr += remaining; remaining -= remaining; + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + trunnel_alloc_failed: + return -1; + fail: + result = -1; + return result; +} + +ssize_t +auth1_parse(auth1_t **output, const uint8_t *input, const size_t len_in, const auth_ctx_t *auth_ctx_ctx) +{ + ssize_t result; + *output = auth1_new(); + if (NULL == *output) + return -1; + result = auth1_parse_into(*output, input, len_in, auth_ctx_ctx); + if (result < 0) { + auth1_free(*output); + *output = NULL; + } + return result; +} +certs_cell_t * +certs_cell_new(void) +{ + certs_cell_t *val = trunnel_calloc(1, sizeof(certs_cell_t)); + if (NULL == val) + return NULL; + return val; +} + +/** Release all storage held inside 'obj', but do not free 'obj'. + */ +static void +certs_cell_clear(certs_cell_t *obj) +{ + (void) obj; + { + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->certs); ++idx) { + certs_cell_cert_free(TRUNNEL_DYNARRAY_GET(&obj->certs, idx)); + } + } + TRUNNEL_DYNARRAY_WIPE(&obj->certs); + TRUNNEL_DYNARRAY_CLEAR(&obj->certs); +} + +void +certs_cell_free(certs_cell_t *obj) +{ + if (obj == NULL) + return; + certs_cell_clear(obj); + trunnel_memwipe(obj, sizeof(certs_cell_t)); + trunnel_free_(obj); +} + +uint8_t +certs_cell_get_n_certs(certs_cell_t *inp) +{ + return inp->n_certs; +} +int +certs_cell_set_n_certs(certs_cell_t *inp, uint8_t val) +{ + inp->n_certs = val; + return 0; +} +size_t +certs_cell_getlen_certs(const certs_cell_t *inp) +{ + return TRUNNEL_DYNARRAY_LEN(&inp->certs); +} + +struct certs_cell_cert_st * +certs_cell_get_certs(certs_cell_t *inp, size_t idx) +{ + return TRUNNEL_DYNARRAY_GET(&inp->certs, idx); +} + +int +certs_cell_set_certs(certs_cell_t *inp, size_t idx, struct certs_cell_cert_st * elt) +{ + certs_cell_cert_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->certs, idx); + if (oldval && oldval != elt) + certs_cell_cert_free(oldval); + return certs_cell_set0_certs(inp, idx, elt); +} +int +certs_cell_set0_certs(certs_cell_t *inp, size_t idx, struct certs_cell_cert_st * elt) +{ + TRUNNEL_DYNARRAY_SET(&inp->certs, idx, elt); + return 0; +} +int +certs_cell_add_certs(certs_cell_t *inp, struct certs_cell_cert_st * elt) +{ +#if SIZE_MAX >= UINT8_MAX + if (inp->certs.n_ == UINT8_MAX) + goto trunnel_alloc_failed; +#endif + TRUNNEL_DYNARRAY_ADD(struct certs_cell_cert_st *, &inp->certs, elt, {}); + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} + +struct certs_cell_cert_st * * +certs_cell_getarray_certs(certs_cell_t *inp) +{ + return inp->certs.elts_; +} +int +certs_cell_setlen_certs(certs_cell_t *inp, size_t newlen) +{ + struct certs_cell_cert_st * *newptr; +#if UINT8_MAX < SIZE_MAX + if (newlen > UINT8_MAX) + goto trunnel_alloc_failed; +#endif + newptr = trunnel_dynarray_setlen(&inp->certs.allocated_, + &inp->certs.n_, inp->certs.elts_, newlen, + sizeof(inp->certs.elts_[0]), (trunnel_free_fn_t) certs_cell_cert_free, + &inp->trunnel_error_code_); + if (newptr == NULL) + goto trunnel_alloc_failed; + inp->certs.elts_ = newptr; + return 0; + trunnel_alloc_failed: + TRUNNEL_SET_ERROR_CODE(inp); + return -1; +} +const char * +certs_cell_check(const certs_cell_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->certs); ++idx) { + if (NULL != (msg = certs_cell_cert_check(TRUNNEL_DYNARRAY_GET(&obj->certs, idx)))) + return msg; + } + } + if (TRUNNEL_DYNARRAY_LEN(&obj->certs) != obj->n_certs) + return "Length mismatch for certs"; + return NULL; +} + +ssize_t +certs_cell_encoded_len(const certs_cell_t *obj) +{ + ssize_t result = 0; + + if (NULL != certs_cell_check(obj)) + return -1; + + + /* Length of u8 n_certs */ + result += 1; + + /* Length of struct certs_cell_cert certs[n_certs] */ + { + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->certs); ++idx) { + result += certs_cell_cert_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->certs, idx)); + } + } + return result; +} +int +certs_cell_clear_errors(certs_cell_t *obj) +{ + int r = obj->trunnel_error_code_; + obj->trunnel_error_code_ = 0; + return r; +} +ssize_t +certs_cell_encode(uint8_t *output, const size_t avail, const certs_cell_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 = certs_cell_encoded_len(obj); +#endif + + if (NULL != (msg = certs_cell_check(obj))) + goto check_failed; + +#ifdef TRUNNEL_CHECK_ENCODED_LEN + trunnel_assert(encoded_len >= 0); +#endif + + /* Encode u8 n_certs */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->n_certs)); + written += 1; ptr += 1; + + /* Encode struct certs_cell_cert certs[n_certs] */ + { + + unsigned idx; + for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->certs); ++idx) { + trunnel_assert(written <= avail); + result = certs_cell_cert_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->certs, 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 certs_cell_parse(), but do not allocate the output object. + */ +static ssize_t +certs_cell_parse_into(certs_cell_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 n_certs */ + CHECK_REMAINING(1, truncated); + obj->n_certs = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + + /* Parse struct certs_cell_cert certs[n_certs] */ + TRUNNEL_DYNARRAY_EXPAND(certs_cell_cert_t *, &obj->certs, obj->n_certs, {}); + { + certs_cell_cert_t * elt; + unsigned idx; + for (idx = 0; idx < obj->n_certs; ++idx) { + result = certs_cell_cert_parse(&elt, ptr, remaining); + if (result < 0) + goto relay_fail; + trunnel_assert((size_t)result <= remaining); + remaining -= result; ptr += result; + TRUNNEL_DYNARRAY_ADD(certs_cell_cert_t *, &obj->certs, elt, {certs_cell_cert_free(elt);}); + } + } + trunnel_assert(ptr + remaining == input + len_in); + return len_in - remaining; + + truncated: + return -2; + relay_fail: + if (result >= 0) result = -1; + return result; + trunnel_alloc_failed: + return -1; +} + +ssize_t +certs_cell_parse(certs_cell_t **output, const uint8_t *input, const size_t len_in) +{ + ssize_t result; + *output = certs_cell_new(); + if (NULL == *output) + return -1; + result = certs_cell_parse_into(*output, input, len_in); + if (result < 0) { + certs_cell_free(*output); + *output = NULL; + } + return result; +} diff --git a/src/trunnel/link_handshake.h b/src/trunnel/link_handshake.h new file mode 100644 index 0000000000..109fe8d065 --- /dev/null +++ b/src/trunnel/link_handshake.h @@ -0,0 +1,654 @@ +/* link_handshake.h -- generated by by Trunnel v1.4-pre. + * https://gitweb.torproject.org/trunnel.git + * You probably shouldn't edit this file. + */ +#ifndef TRUNNEL_LINK_HANDSHAKE_H +#define TRUNNEL_LINK_HANDSHAKE_H + +#include +#include "trunnel.h" + +#define CERTTYPE_RSA1024_ID_LINK 1 +#define CERTTYPE_RSA1024_ID_ID 2 +#define CERTTYPE_RSA1024_ID_AUTH 3 +#define CERTTYPE_ED_ID_SIGN 4 +#define CERTTYPE_ED_SIGN_LINK 5 +#define CERTTYPE_ED_SIGN_AUTH 6 +#define CERTTYPE_RSA1024_ID_EDID 7 +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_AUTH_CHALLENGE_CELL) +struct auth_challenge_cell_st { + uint8_t challenge[32]; + uint16_t n_methods; + TRUNNEL_DYNARRAY_HEAD(, uint16_t) methods; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct auth_challenge_cell_st auth_challenge_cell_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_AUTH_CTX) +struct auth_ctx_st { + uint8_t is_ed; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct auth_ctx_st auth_ctx_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_CERTS_CELL_CERT) +struct certs_cell_cert_st { + uint8_t cert_type; + uint16_t cert_len; + TRUNNEL_DYNARRAY_HEAD(, uint8_t) body; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct certs_cell_cert_st certs_cell_cert_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_RSA_ED_CROSSCERT) +struct rsa_ed_crosscert_st { + uint8_t ed_key[32]; + uint32_t expiration; + const uint8_t *end_of_signed; + uint8_t sig_len; + TRUNNEL_DYNARRAY_HEAD(, uint8_t) sig; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct rsa_ed_crosscert_st rsa_ed_crosscert_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_AUTH1) +struct auth1_st { + uint8_t type[8]; + uint8_t cid[32]; + uint8_t sid[32]; + uint8_t u1_cid_ed[32]; + uint8_t u1_sid_ed[32]; + uint8_t slog[32]; + uint8_t clog[32]; + uint8_t scert[32]; + uint8_t tlssecrets[32]; + const uint8_t *end_of_fixed_part; + uint8_t rand[24]; + const uint8_t *end_of_signed; + TRUNNEL_DYNARRAY_HEAD(, uint8_t) sig; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct auth1_st auth1_t; +#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_CERTS_CELL) +struct certs_cell_st { + uint8_t n_certs; + TRUNNEL_DYNARRAY_HEAD(, struct certs_cell_cert_st *) certs; + uint8_t trunnel_error_code_; +}; +#endif +typedef struct certs_cell_st certs_cell_t; +/** Return a newly allocated auth_challenge_cell with all elements set + * to zero. + */ +auth_challenge_cell_t *auth_challenge_cell_new(void); +/** Release all storage held by the auth_challenge_cell in 'victim'. + * (Do nothing if 'victim' is NULL.) + */ +void auth_challenge_cell_free(auth_challenge_cell_t *victim); +/** Try to parse a auth_challenge_cell 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 auth_challenge_cell_t. On failure, return -2 if the input + * appears truncated, and -1 if the input is otherwise invalid. + */ +ssize_t auth_challenge_cell_parse(auth_challenge_cell_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * auth_challenge_cell 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 auth_challenge_cell_encoded_len(const auth_challenge_cell_t *obj); +/** Try to encode the auth_challenge_cell 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 auth_challenge_cell_encode(uint8_t *output, const size_t avail, const auth_challenge_cell_t *input); +/** Check whether the internal state of the auth_challenge_cell in + * 'obj' is consistent. Return NULL if it is, and a short message if + * it is not. + */ +const char *auth_challenge_cell_check(const auth_challenge_cell_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int auth_challenge_cell_clear_errors(auth_challenge_cell_t *obj); +/** Return the (constant) length of the array holding the challenge + * field of the auth_challenge_cell_t in 'inp'. + */ +size_t auth_challenge_cell_getlen_challenge(const auth_challenge_cell_t *inp); +/** Return the element at position 'idx' of the fixed array field + * challenge of the auth_challenge_cell_t in 'inp'. + */ +uint8_t auth_challenge_cell_get_challenge(const auth_challenge_cell_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * challenge of the auth_challenge_cell_t in 'inp', so that it will + * hold the value 'elt'. + */ +int auth_challenge_cell_set_challenge(auth_challenge_cell_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field challenge of 'inp'. + */ +uint8_t * auth_challenge_cell_getarray_challenge(auth_challenge_cell_t *inp); +/** Return the value of the n_methods field of the + * auth_challenge_cell_t in 'inp' + */ +uint16_t auth_challenge_cell_get_n_methods(auth_challenge_cell_t *inp); +/** Set the value of the n_methods field of the auth_challenge_cell_t + * in 'inp' to 'val'. Return 0 on success; return -1 and set the error + * code on 'inp' on failure. + */ +int auth_challenge_cell_set_n_methods(auth_challenge_cell_t *inp, uint16_t val); +/** Return the length of the dynamic array holding the methods field + * of the auth_challenge_cell_t in 'inp'. + */ +size_t auth_challenge_cell_getlen_methods(const auth_challenge_cell_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * methods of the auth_challenge_cell_t in 'inp'. + */ +uint16_t auth_challenge_cell_get_methods(auth_challenge_cell_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * methods of the auth_challenge_cell_t in 'inp', so that it will hold + * the value 'elt'. + */ +int auth_challenge_cell_set_methods(auth_challenge_cell_t *inp, size_t idx, uint16_t elt); +/** Append a new element 'elt' to the dynamic array field methods of + * the auth_challenge_cell_t in 'inp'. + */ +int auth_challenge_cell_add_methods(auth_challenge_cell_t *inp, uint16_t elt); +/** Return a pointer to the variable-length array field methods of + * 'inp'. + */ +uint16_t * auth_challenge_cell_getarray_methods(auth_challenge_cell_t *inp); +/** Change the length of the variable-length array field methods 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 auth_challenge_cell_setlen_methods(auth_challenge_cell_t *inp, size_t newlen); +/** Return a newly allocated auth_ctx with all elements set to zero. + */ +auth_ctx_t *auth_ctx_new(void); +/** Release all storage held by the auth_ctx in 'victim'. (Do nothing + * if 'victim' is NULL.) + */ +void auth_ctx_free(auth_ctx_t *victim); +/** Return the value of the is_ed field of the auth_ctx_t in 'inp' + */ +uint8_t auth_ctx_get_is_ed(auth_ctx_t *inp); +/** Set the value of the is_ed field of the auth_ctx_t in 'inp' to + * 'val'. Return 0 on success; return -1 and set the error code on + * 'inp' on failure. + */ +int auth_ctx_set_is_ed(auth_ctx_t *inp, uint8_t val); +/** Return a newly allocated certs_cell_cert with all elements set to + * zero. + */ +certs_cell_cert_t *certs_cell_cert_new(void); +/** Release all storage held by the certs_cell_cert in 'victim'. (Do + * nothing if 'victim' is NULL.) + */ +void certs_cell_cert_free(certs_cell_cert_t *victim); +/** Try to parse a certs_cell_cert 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 + * certs_cell_cert_t. On failure, return -2 if the input appears + * truncated, and -1 if the input is otherwise invalid. + */ +ssize_t certs_cell_cert_parse(certs_cell_cert_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * certs_cell_cert 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 certs_cell_cert_encoded_len(const certs_cell_cert_t *obj); +/** Try to encode the certs_cell_cert 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 certs_cell_cert_encode(uint8_t *output, const size_t avail, const certs_cell_cert_t *input); +/** Check whether the internal state of the certs_cell_cert in 'obj' + * is consistent. Return NULL if it is, and a short message if it is + * not. + */ +const char *certs_cell_cert_check(const certs_cell_cert_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int certs_cell_cert_clear_errors(certs_cell_cert_t *obj); +/** Return the value of the cert_type field of the certs_cell_cert_t + * in 'inp' + */ +uint8_t certs_cell_cert_get_cert_type(certs_cell_cert_t *inp); +/** Set the value of the cert_type field of the certs_cell_cert_t in + * 'inp' to 'val'. Return 0 on success; return -1 and set the error + * code on 'inp' on failure. + */ +int certs_cell_cert_set_cert_type(certs_cell_cert_t *inp, uint8_t val); +/** Return the value of the cert_len field of the certs_cell_cert_t in + * 'inp' + */ +uint16_t certs_cell_cert_get_cert_len(certs_cell_cert_t *inp); +/** Set the value of the cert_len field of the certs_cell_cert_t in + * 'inp' to 'val'. Return 0 on success; return -1 and set the error + * code on 'inp' on failure. + */ +int certs_cell_cert_set_cert_len(certs_cell_cert_t *inp, uint16_t val); +/** Return the length of the dynamic array holding the body field of + * the certs_cell_cert_t in 'inp'. + */ +size_t certs_cell_cert_getlen_body(const certs_cell_cert_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * body of the certs_cell_cert_t in 'inp'. + */ +uint8_t certs_cell_cert_get_body(certs_cell_cert_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * body of the certs_cell_cert_t in 'inp', so that it will hold the + * value 'elt'. + */ +int certs_cell_cert_set_body(certs_cell_cert_t *inp, size_t idx, uint8_t elt); +/** Append a new element 'elt' to the dynamic array field body of the + * certs_cell_cert_t in 'inp'. + */ +int certs_cell_cert_add_body(certs_cell_cert_t *inp, uint8_t elt); +/** Return a pointer to the variable-length array field body of 'inp'. + */ +uint8_t * certs_cell_cert_getarray_body(certs_cell_cert_t *inp); +/** Change the length of the variable-length array field body 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 certs_cell_cert_setlen_body(certs_cell_cert_t *inp, size_t newlen); +/** Return a newly allocated rsa_ed_crosscert with all elements set to + * zero. + */ +rsa_ed_crosscert_t *rsa_ed_crosscert_new(void); +/** Release all storage held by the rsa_ed_crosscert in 'victim'. (Do + * nothing if 'victim' is NULL.) + */ +void rsa_ed_crosscert_free(rsa_ed_crosscert_t *victim); +/** Try to parse a rsa_ed_crosscert 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 + * rsa_ed_crosscert_t. On failure, return -2 if the input appears + * truncated, and -1 if the input is otherwise invalid. + */ +ssize_t rsa_ed_crosscert_parse(rsa_ed_crosscert_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * rsa_ed_crosscert 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 rsa_ed_crosscert_encoded_len(const rsa_ed_crosscert_t *obj); +/** Try to encode the rsa_ed_crosscert 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 rsa_ed_crosscert_encode(uint8_t *output, const size_t avail, const rsa_ed_crosscert_t *input); +/** Check whether the internal state of the rsa_ed_crosscert in 'obj' + * is consistent. Return NULL if it is, and a short message if it is + * not. + */ +const char *rsa_ed_crosscert_check(const rsa_ed_crosscert_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int rsa_ed_crosscert_clear_errors(rsa_ed_crosscert_t *obj); +/** Return the (constant) length of the array holding the ed_key field + * of the rsa_ed_crosscert_t in 'inp'. + */ +size_t rsa_ed_crosscert_getlen_ed_key(const rsa_ed_crosscert_t *inp); +/** Return the element at position 'idx' of the fixed array field + * ed_key of the rsa_ed_crosscert_t in 'inp'. + */ +uint8_t rsa_ed_crosscert_get_ed_key(const rsa_ed_crosscert_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * ed_key of the rsa_ed_crosscert_t in 'inp', so that it will hold the + * value 'elt'. + */ +int rsa_ed_crosscert_set_ed_key(rsa_ed_crosscert_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field ed_key of 'inp'. + */ +uint8_t * rsa_ed_crosscert_getarray_ed_key(rsa_ed_crosscert_t *inp); +/** Return the value of the expiration field of the rsa_ed_crosscert_t + * in 'inp' + */ +uint32_t rsa_ed_crosscert_get_expiration(rsa_ed_crosscert_t *inp); +/** Set the value of the expiration field of the rsa_ed_crosscert_t in + * 'inp' to 'val'. Return 0 on success; return -1 and set the error + * code on 'inp' on failure. + */ +int rsa_ed_crosscert_set_expiration(rsa_ed_crosscert_t *inp, uint32_t val); +/** Return the position for end_of_signed when we parsed this object + */ +const uint8_t * rsa_ed_crosscert_get_end_of_signed(const rsa_ed_crosscert_t *inp); +/** Return the value of the sig_len field of the rsa_ed_crosscert_t in + * 'inp' + */ +uint8_t rsa_ed_crosscert_get_sig_len(rsa_ed_crosscert_t *inp); +/** Set the value of the sig_len field of the rsa_ed_crosscert_t in + * 'inp' to 'val'. Return 0 on success; return -1 and set the error + * code on 'inp' on failure. + */ +int rsa_ed_crosscert_set_sig_len(rsa_ed_crosscert_t *inp, uint8_t val); +/** Return the length of the dynamic array holding the sig field of + * the rsa_ed_crosscert_t in 'inp'. + */ +size_t rsa_ed_crosscert_getlen_sig(const rsa_ed_crosscert_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * sig of the rsa_ed_crosscert_t in 'inp'. + */ +uint8_t rsa_ed_crosscert_get_sig(rsa_ed_crosscert_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * sig of the rsa_ed_crosscert_t in 'inp', so that it will hold the + * value 'elt'. + */ +int rsa_ed_crosscert_set_sig(rsa_ed_crosscert_t *inp, size_t idx, uint8_t elt); +/** Append a new element 'elt' to the dynamic array field sig of the + * rsa_ed_crosscert_t in 'inp'. + */ +int rsa_ed_crosscert_add_sig(rsa_ed_crosscert_t *inp, uint8_t elt); +/** Return a pointer to the variable-length array field sig of 'inp'. + */ +uint8_t * rsa_ed_crosscert_getarray_sig(rsa_ed_crosscert_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 rsa_ed_crosscert_setlen_sig(rsa_ed_crosscert_t *inp, size_t newlen); +/** Return a newly allocated auth1 with all elements set to zero. + */ +auth1_t *auth1_new(void); +/** Release all storage held by the auth1 in 'victim'. (Do nothing if + * 'victim' is NULL.) + */ +void auth1_free(auth1_t *victim); +/** Try to parse a auth1 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 auth1_t. + * On failure, return -2 if the input appears truncated, and -1 if the + * input is otherwise invalid. + */ +ssize_t auth1_parse(auth1_t **output, const uint8_t *input, const size_t len_in, const auth_ctx_t *auth_ctx_ctx); +/** Return the number of bytes we expect to need to encode the auth1 + * 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 auth1_encoded_len(const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx); +/** Try to encode the auth1 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 auth1_encode(uint8_t *output, const size_t avail, const auth1_t *input, const auth_ctx_t *auth_ctx_ctx); +/** Check whether the internal state of the auth1 in 'obj' is + * consistent. Return NULL if it is, and a short message if it is not. + */ +const char *auth1_check(const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int auth1_clear_errors(auth1_t *obj); +/** Return the (constant) length of the array holding the type field + * of the auth1_t in 'inp'. + */ +size_t auth1_getlen_type(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field type + * of the auth1_t in 'inp'. + */ +uint8_t auth1_get_type(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field type + * of the auth1_t in 'inp', so that it will hold the value 'elt'. + */ +int auth1_set_type(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 8-element array field type of 'inp'. + */ +uint8_t * auth1_getarray_type(auth1_t *inp); +/** Return the (constant) length of the array holding the cid field of + * the auth1_t in 'inp'. + */ +size_t auth1_getlen_cid(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field cid + * of the auth1_t in 'inp'. + */ +uint8_t auth1_get_cid(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field cid + * of the auth1_t in 'inp', so that it will hold the value 'elt'. + */ +int auth1_set_cid(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field cid of 'inp'. + */ +uint8_t * auth1_getarray_cid(auth1_t *inp); +/** Return the (constant) length of the array holding the sid field of + * the auth1_t in 'inp'. + */ +size_t auth1_getlen_sid(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field sid + * of the auth1_t in 'inp'. + */ +uint8_t auth1_get_sid(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field sid + * of the auth1_t in 'inp', so that it will hold the value 'elt'. + */ +int auth1_set_sid(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field sid of 'inp'. + */ +uint8_t * auth1_getarray_sid(auth1_t *inp); +/** Return the (constant) length of the array holding the u1_cid_ed + * field of the auth1_t in 'inp'. + */ +size_t auth1_getlen_u1_cid_ed(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field + * u1_cid_ed of the auth1_t in 'inp'. + */ +uint8_t auth1_get_u1_cid_ed(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * u1_cid_ed of the auth1_t in 'inp', so that it will hold the value + * 'elt'. + */ +int auth1_set_u1_cid_ed(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field u1_cid_ed of 'inp'. + */ +uint8_t * auth1_getarray_u1_cid_ed(auth1_t *inp); +/** Return the (constant) length of the array holding the u1_sid_ed + * field of the auth1_t in 'inp'. + */ +size_t auth1_getlen_u1_sid_ed(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field + * u1_sid_ed of the auth1_t in 'inp'. + */ +uint8_t auth1_get_u1_sid_ed(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * u1_sid_ed of the auth1_t in 'inp', so that it will hold the value + * 'elt'. + */ +int auth1_set_u1_sid_ed(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field u1_sid_ed of 'inp'. + */ +uint8_t * auth1_getarray_u1_sid_ed(auth1_t *inp); +/** Return the (constant) length of the array holding the slog field + * of the auth1_t in 'inp'. + */ +size_t auth1_getlen_slog(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field slog + * of the auth1_t in 'inp'. + */ +uint8_t auth1_get_slog(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field slog + * of the auth1_t in 'inp', so that it will hold the value 'elt'. + */ +int auth1_set_slog(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field slog of 'inp'. + */ +uint8_t * auth1_getarray_slog(auth1_t *inp); +/** Return the (constant) length of the array holding the clog field + * of the auth1_t in 'inp'. + */ +size_t auth1_getlen_clog(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field clog + * of the auth1_t in 'inp'. + */ +uint8_t auth1_get_clog(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field clog + * of the auth1_t in 'inp', so that it will hold the value 'elt'. + */ +int auth1_set_clog(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field clog of 'inp'. + */ +uint8_t * auth1_getarray_clog(auth1_t *inp); +/** Return the (constant) length of the array holding the scert field + * of the auth1_t in 'inp'. + */ +size_t auth1_getlen_scert(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field + * scert of the auth1_t in 'inp'. + */ +uint8_t auth1_get_scert(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * scert of the auth1_t in 'inp', so that it will hold the value + * 'elt'. + */ +int auth1_set_scert(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field scert of 'inp'. + */ +uint8_t * auth1_getarray_scert(auth1_t *inp); +/** Return the (constant) length of the array holding the tlssecrets + * field of the auth1_t in 'inp'. + */ +size_t auth1_getlen_tlssecrets(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field + * tlssecrets of the auth1_t in 'inp'. + */ +uint8_t auth1_get_tlssecrets(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field + * tlssecrets of the auth1_t in 'inp', so that it will hold the value + * 'elt'. + */ +int auth1_set_tlssecrets(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 32-element array field tlssecrets of + * 'inp'. + */ +uint8_t * auth1_getarray_tlssecrets(auth1_t *inp); +/** Return the position for end_of_fixed_part when we parsed this + * object + */ +const uint8_t * auth1_get_end_of_fixed_part(const auth1_t *inp); +/** Return the (constant) length of the array holding the rand field + * of the auth1_t in 'inp'. + */ +size_t auth1_getlen_rand(const auth1_t *inp); +/** Return the element at position 'idx' of the fixed array field rand + * of the auth1_t in 'inp'. + */ +uint8_t auth1_get_rand(const auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the fixed array field rand + * of the auth1_t in 'inp', so that it will hold the value 'elt'. + */ +int auth1_set_rand(auth1_t *inp, size_t idx, uint8_t elt); +/** Return a pointer to the 24-element array field rand of 'inp'. + */ +uint8_t * auth1_getarray_rand(auth1_t *inp); +/** Return the position for end_of_signed when we parsed this object + */ +const uint8_t * auth1_get_end_of_signed(const auth1_t *inp); +/** Return the length of the dynamic array holding the sig field of + * the auth1_t in 'inp'. + */ +size_t auth1_getlen_sig(const auth1_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * sig of the auth1_t in 'inp'. + */ +uint8_t auth1_get_sig(auth1_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * sig of the auth1_t in 'inp', so that it will hold the value 'elt'. + */ +int auth1_set_sig(auth1_t *inp, size_t idx, uint8_t elt); +/** Append a new element 'elt' to the dynamic array field sig of the + * auth1_t in 'inp'. + */ +int auth1_add_sig(auth1_t *inp, uint8_t elt); +/** Return a pointer to the variable-length array field sig of 'inp'. + */ +uint8_t * auth1_getarray_sig(auth1_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 auth1_setlen_sig(auth1_t *inp, size_t newlen); +/** Return a newly allocated certs_cell with all elements set to zero. + */ +certs_cell_t *certs_cell_new(void); +/** Release all storage held by the certs_cell in 'victim'. (Do + * nothing if 'victim' is NULL.) + */ +void certs_cell_free(certs_cell_t *victim); +/** Try to parse a certs_cell 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 + * certs_cell_t. On failure, return -2 if the input appears truncated, + * and -1 if the input is otherwise invalid. + */ +ssize_t certs_cell_parse(certs_cell_t **output, const uint8_t *input, const size_t len_in); +/** Return the number of bytes we expect to need to encode the + * certs_cell 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 certs_cell_encoded_len(const certs_cell_t *obj); +/** Try to encode the certs_cell 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 certs_cell_encode(uint8_t *output, const size_t avail, const certs_cell_t *input); +/** Check whether the internal state of the certs_cell in 'obj' is + * consistent. Return NULL if it is, and a short message if it is not. + */ +const char *certs_cell_check(const certs_cell_t *obj); +/** Clear any errors that were set on the object 'obj' by its setter + * functions. Return true iff errors were cleared. + */ +int certs_cell_clear_errors(certs_cell_t *obj); +/** Return the value of the n_certs field of the certs_cell_t in 'inp' + */ +uint8_t certs_cell_get_n_certs(certs_cell_t *inp); +/** Set the value of the n_certs field of the certs_cell_t in 'inp' to + * 'val'. Return 0 on success; return -1 and set the error code on + * 'inp' on failure. + */ +int certs_cell_set_n_certs(certs_cell_t *inp, uint8_t val); +/** Return the length of the dynamic array holding the certs field of + * the certs_cell_t in 'inp'. + */ +size_t certs_cell_getlen_certs(const certs_cell_t *inp); +/** Return the element at position 'idx' of the dynamic array field + * certs of the certs_cell_t in 'inp'. + */ +struct certs_cell_cert_st * certs_cell_get_certs(certs_cell_t *inp, size_t idx); +/** Change the element at position 'idx' of the dynamic array field + * certs of the certs_cell_t in 'inp', so that it will hold the value + * 'elt'. Free the previous value, if any. + */ +int certs_cell_set_certs(certs_cell_t *inp, size_t idx, struct certs_cell_cert_st * elt); +/** As certs_cell_set_certs, but does not free the previous value. + */ +int certs_cell_set0_certs(certs_cell_t *inp, size_t idx, struct certs_cell_cert_st * elt); +/** Append a new element 'elt' to the dynamic array field certs of the + * certs_cell_t in 'inp'. + */ +int certs_cell_add_certs(certs_cell_t *inp, struct certs_cell_cert_st * elt); +/** Return a pointer to the variable-length array field certs of + * 'inp'. + */ +struct certs_cell_cert_st * * certs_cell_getarray_certs(certs_cell_t *inp); +/** Change the length of the variable-length array field certs 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 certs_cell_setlen_certs(certs_cell_t *inp, size_t newlen); + + +#endif diff --git a/src/trunnel/link_handshake.trunnel b/src/trunnel/link_handshake.trunnel new file mode 100644 index 0000000000..b858e17c60 --- /dev/null +++ b/src/trunnel/link_handshake.trunnel @@ -0,0 +1,57 @@ + +struct certs_cell { + u8 n_certs; + struct certs_cell_cert certs[n_certs]; +} + +const CERTTYPE_RSA1024_ID_LINK = 1; +const CERTTYPE_RSA1024_ID_ID = 2; +const CERTTYPE_RSA1024_ID_AUTH = 3; +const CERTTYPE_ED_ID_SIGN = 4; +const CERTTYPE_ED_SIGN_LINK = 5; +const CERTTYPE_ED_SIGN_AUTH = 6; +const CERTTYPE_RSA1024_ID_EDID = 7; + +struct certs_cell_cert { + u8 cert_type; + u16 cert_len; + u8 body[cert_len]; +} + +struct rsa_ed_crosscert { + u8 ed_key[32]; + u32 expiration; + @ptr end_of_signed; + u8 sig_len; + u8 sig[sig_len]; // mismatches spec. +} + +struct auth_challenge_cell { + u8 challenge[32]; + u16 n_methods; + u16 methods[n_methods]; +} + +context auth_ctx { + u8 is_ed; +} + +struct auth1 with context auth_ctx { + u8 type[8]; + u8 cid[32]; + u8 sid[32]; + union u1[auth_ctx.is_ed] { + 0 : ; + 1 : u8 cid_ed[32]; + u8 sid_ed[32]; + default: fail; + }; + u8 slog[32]; + u8 clog[32]; + u8 scert[32]; + u8 tlssecrets[32]; + @ptr end_of_fixed_part; + u8 rand[24]; + @ptr end_of_signed; + u8 sig[]; +} -- cgit v1.2.3-54-g00ecf