tor/src/trunnel/link_handshake.c
Nick Mathewson df05e195ee 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.
2015-05-28 10:41:49 -04:00

1886 lines
40 KiB
C

/* 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;
}