diff options
author | Nick Mathewson <nickm@torproject.org> | 2014-10-08 14:43:33 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2015-05-28 10:41:49 -0400 |
commit | df05e195ee64d7ed1b5a1b5d74c5868683788ba2 (patch) | |
tree | 6279c16881d61e890918704db459e89beaa45053 /src/trunnel/link_handshake.c | |
parent | 24b720a984cc6c05ebc51d0c699a36119c518ee4 (diff) | |
download | tor-df05e195ee64d7ed1b5a1b5d74c5868683788ba2.tar.gz tor-df05e195ee64d7ed1b5a1b5d74c5868683788ba2.zip |
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.
Diffstat (limited to 'src/trunnel/link_handshake.c')
-rw-r--r-- | src/trunnel/link_handshake.c | 1885 |
1 files changed, 1885 insertions, 0 deletions
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 <stdlib.h> +#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; +} |