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