tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

ed25519_cert.c (66056B)


      1 /* ed25519_cert.c -- generated by Trunnel v1.5.3.
      2 * https://gitweb.torproject.org/trunnel.git
      3 * You probably shouldn't edit this file.
      4 */
      5 #include <stdlib.h>
      6 #include "trunnel-impl.h"
      7 
      8 #include "ed25519_cert.h"
      9 
     10 #define TRUNNEL_SET_ERROR_CODE(obj) \
     11  do {                              \
     12    (obj)->trunnel_error_code_ = 1; \
     13  } while (0)
     14 
     15 #if defined(__COVERITY__) || defined(__clang_analyzer__)
     16 /* If we're running a static analysis tool, we don't want it to complain
     17 * that some of our remaining-bytes checks are dead-code. */
     18 int edcert_deadcode_dummy__ = 0;
     19 #define OR_DEADCODE_DUMMY || edcert_deadcode_dummy__
     20 #else
     21 #define OR_DEADCODE_DUMMY
     22 #endif
     23 
     24 #define CHECK_REMAINING(nbytes, label)                           \
     25  do {                                                           \
     26    if (remaining < (nbytes) OR_DEADCODE_DUMMY) {                \
     27      goto label;                                                \
     28    }                                                            \
     29  } while (0)
     30 
     31 create2_cell_body_t *
     32 create2_cell_body_new(void)
     33 {
     34  create2_cell_body_t *val = trunnel_calloc(1, sizeof(create2_cell_body_t));
     35  if (NULL == val)
     36    return NULL;
     37  return val;
     38 }
     39 
     40 /** Release all storage held inside 'obj', but do not free 'obj'.
     41 */
     42 static void
     43 create2_cell_body_clear(create2_cell_body_t *obj)
     44 {
     45  (void) obj;
     46  TRUNNEL_DYNARRAY_WIPE(&obj->handshake_data);
     47  TRUNNEL_DYNARRAY_CLEAR(&obj->handshake_data);
     48 }
     49 
     50 void
     51 create2_cell_body_free(create2_cell_body_t *obj)
     52 {
     53  if (obj == NULL)
     54    return;
     55  create2_cell_body_clear(obj);
     56  trunnel_memwipe(obj, sizeof(create2_cell_body_t));
     57  trunnel_free_(obj);
     58 }
     59 
     60 uint16_t
     61 create2_cell_body_get_handshake_type(const create2_cell_body_t *inp)
     62 {
     63  return inp->handshake_type;
     64 }
     65 int
     66 create2_cell_body_set_handshake_type(create2_cell_body_t *inp, uint16_t val)
     67 {
     68  inp->handshake_type = val;
     69  return 0;
     70 }
     71 uint16_t
     72 create2_cell_body_get_handshake_len(const create2_cell_body_t *inp)
     73 {
     74  return inp->handshake_len;
     75 }
     76 int
     77 create2_cell_body_set_handshake_len(create2_cell_body_t *inp, uint16_t val)
     78 {
     79  inp->handshake_len = val;
     80  return 0;
     81 }
     82 size_t
     83 create2_cell_body_getlen_handshake_data(const create2_cell_body_t *inp)
     84 {
     85  return TRUNNEL_DYNARRAY_LEN(&inp->handshake_data);
     86 }
     87 
     88 uint8_t
     89 create2_cell_body_get_handshake_data(create2_cell_body_t *inp, size_t idx)
     90 {
     91  return TRUNNEL_DYNARRAY_GET(&inp->handshake_data, idx);
     92 }
     93 
     94 uint8_t
     95 create2_cell_body_getconst_handshake_data(const create2_cell_body_t *inp, size_t idx)
     96 {
     97  return create2_cell_body_get_handshake_data((create2_cell_body_t*)inp, idx);
     98 }
     99 int
    100 create2_cell_body_set_handshake_data(create2_cell_body_t *inp, size_t idx, uint8_t elt)
    101 {
    102  TRUNNEL_DYNARRAY_SET(&inp->handshake_data, idx, elt);
    103  return 0;
    104 }
    105 int
    106 create2_cell_body_add_handshake_data(create2_cell_body_t *inp, uint8_t elt)
    107 {
    108 #if SIZE_MAX >= UINT16_MAX
    109  if (inp->handshake_data.n_ == UINT16_MAX)
    110    goto trunnel_alloc_failed;
    111 #endif
    112  TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->handshake_data, elt, {});
    113  return 0;
    114 trunnel_alloc_failed:
    115  TRUNNEL_SET_ERROR_CODE(inp);
    116  return -1;
    117 }
    118 
    119 uint8_t *
    120 create2_cell_body_getarray_handshake_data(create2_cell_body_t *inp)
    121 {
    122  return inp->handshake_data.elts_;
    123 }
    124 const uint8_t  *
    125 create2_cell_body_getconstarray_handshake_data(const create2_cell_body_t *inp)
    126 {
    127  return (const uint8_t  *)create2_cell_body_getarray_handshake_data((create2_cell_body_t*)inp);
    128 }
    129 int
    130 create2_cell_body_setlen_handshake_data(create2_cell_body_t *inp, size_t newlen)
    131 {
    132  uint8_t *newptr;
    133 #if UINT16_MAX < SIZE_MAX
    134  if (newlen > UINT16_MAX)
    135    goto trunnel_alloc_failed;
    136 #endif
    137  newptr = trunnel_dynarray_setlen(&inp->handshake_data.allocated_,
    138                 &inp->handshake_data.n_, inp->handshake_data.elts_, newlen,
    139                 sizeof(inp->handshake_data.elts_[0]), (trunnel_free_fn_t) NULL,
    140                 &inp->trunnel_error_code_);
    141  if (newlen != 0 && newptr == NULL)
    142    goto trunnel_alloc_failed;
    143  inp->handshake_data.elts_ = newptr;
    144  return 0;
    145 trunnel_alloc_failed:
    146  TRUNNEL_SET_ERROR_CODE(inp);
    147  return -1;
    148 }
    149 const char *
    150 create2_cell_body_check(const create2_cell_body_t *obj)
    151 {
    152  if (obj == NULL)
    153    return "Object was NULL";
    154  if (obj->trunnel_error_code_)
    155    return "A set function failed on this object";
    156  if (TRUNNEL_DYNARRAY_LEN(&obj->handshake_data) != obj->handshake_len)
    157    return "Length mismatch for handshake_data";
    158  return NULL;
    159 }
    160 
    161 ssize_t
    162 create2_cell_body_encoded_len(const create2_cell_body_t *obj)
    163 {
    164  ssize_t result = 0;
    165 
    166  if (NULL != create2_cell_body_check(obj))
    167     return -1;
    168 
    169 
    170  /* Length of u16 handshake_type */
    171  result += 2;
    172 
    173  /* Length of u16 handshake_len */
    174  result += 2;
    175 
    176  /* Length of u8 handshake_data[handshake_len] */
    177  result += TRUNNEL_DYNARRAY_LEN(&obj->handshake_data);
    178  return result;
    179 }
    180 int
    181 create2_cell_body_clear_errors(create2_cell_body_t *obj)
    182 {
    183  int r = obj->trunnel_error_code_;
    184  obj->trunnel_error_code_ = 0;
    185  return r;
    186 }
    187 ssize_t
    188 create2_cell_body_encode(uint8_t *output, const size_t avail, const create2_cell_body_t *obj)
    189 {
    190  ssize_t result = 0;
    191  size_t written = 0;
    192  uint8_t *ptr = output;
    193  const char *msg;
    194 #ifdef TRUNNEL_CHECK_ENCODED_LEN
    195  const ssize_t encoded_len = create2_cell_body_encoded_len(obj);
    196 #endif
    197 
    198  if (NULL != (msg = create2_cell_body_check(obj)))
    199    goto check_failed;
    200 
    201 #ifdef TRUNNEL_CHECK_ENCODED_LEN
    202  trunnel_assert(encoded_len >= 0);
    203 #endif
    204 
    205  /* Encode u16 handshake_type */
    206  trunnel_assert(written <= avail);
    207  if (avail - written < 2)
    208    goto truncated;
    209  trunnel_set_uint16(ptr, trunnel_htons(obj->handshake_type));
    210  written += 2; ptr += 2;
    211 
    212  /* Encode u16 handshake_len */
    213  trunnel_assert(written <= avail);
    214  if (avail - written < 2)
    215    goto truncated;
    216  trunnel_set_uint16(ptr, trunnel_htons(obj->handshake_len));
    217  written += 2; ptr += 2;
    218 
    219  /* Encode u8 handshake_data[handshake_len] */
    220  {
    221    size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->handshake_data);
    222    trunnel_assert(obj->handshake_len == elt_len);
    223    trunnel_assert(written <= avail);
    224    if (avail - written < elt_len)
    225      goto truncated;
    226    if (elt_len)
    227      memcpy(ptr, obj->handshake_data.elts_, elt_len);
    228    written += elt_len; ptr += elt_len;
    229  }
    230 
    231 
    232  trunnel_assert(ptr == output + written);
    233 #ifdef TRUNNEL_CHECK_ENCODED_LEN
    234  {
    235    trunnel_assert(encoded_len >= 0);
    236    trunnel_assert((size_t)encoded_len == written);
    237  }
    238 
    239 #endif
    240 
    241  return written;
    242 
    243 truncated:
    244  result = -2;
    245  goto fail;
    246 check_failed:
    247  (void)msg;
    248  result = -1;
    249  goto fail;
    250 fail:
    251  trunnel_assert(result < 0);
    252  return result;
    253 }
    254 
    255 /** As create2_cell_body_parse(), but do not allocate the output
    256 * object.
    257 */
    258 static ssize_t
    259 create2_cell_body_parse_into(create2_cell_body_t *obj, const uint8_t *input, const size_t len_in)
    260 {
    261  const uint8_t *ptr = input;
    262  size_t remaining = len_in;
    263  ssize_t result = 0;
    264  (void)result;
    265 
    266  /* Parse u16 handshake_type */
    267  CHECK_REMAINING(2, truncated);
    268  obj->handshake_type = trunnel_ntohs(trunnel_get_uint16(ptr));
    269  remaining -= 2; ptr += 2;
    270 
    271  /* Parse u16 handshake_len */
    272  CHECK_REMAINING(2, truncated);
    273  obj->handshake_len = trunnel_ntohs(trunnel_get_uint16(ptr));
    274  remaining -= 2; ptr += 2;
    275 
    276  /* Parse u8 handshake_data[handshake_len] */
    277  CHECK_REMAINING(obj->handshake_len, truncated);
    278  TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->handshake_data, obj->handshake_len, {});
    279  obj->handshake_data.n_ = obj->handshake_len;
    280  if (obj->handshake_len)
    281    memcpy(obj->handshake_data.elts_, ptr, obj->handshake_len);
    282  ptr += obj->handshake_len; remaining -= obj->handshake_len;
    283  trunnel_assert(ptr + remaining == input + len_in);
    284  return len_in - remaining;
    285 
    286 truncated:
    287  return -2;
    288 trunnel_alloc_failed:
    289  return -1;
    290 }
    291 
    292 ssize_t
    293 create2_cell_body_parse(create2_cell_body_t **output, const uint8_t *input, const size_t len_in)
    294 {
    295  ssize_t result;
    296  *output = create2_cell_body_new();
    297  if (NULL == *output)
    298    return -1;
    299  result = create2_cell_body_parse_into(*output, input, len_in);
    300  if (result < 0) {
    301    create2_cell_body_free(*output);
    302    *output = NULL;
    303  }
    304  return result;
    305 }
    306 ed25519_cert_extension_t *
    307 ed25519_cert_extension_new(void)
    308 {
    309  ed25519_cert_extension_t *val = trunnel_calloc(1, sizeof(ed25519_cert_extension_t));
    310  if (NULL == val)
    311    return NULL;
    312  return val;
    313 }
    314 
    315 /** Release all storage held inside 'obj', but do not free 'obj'.
    316 */
    317 static void
    318 ed25519_cert_extension_clear(ed25519_cert_extension_t *obj)
    319 {
    320  (void) obj;
    321  TRUNNEL_DYNARRAY_WIPE(&obj->un_unparsed);
    322  TRUNNEL_DYNARRAY_CLEAR(&obj->un_unparsed);
    323 }
    324 
    325 void
    326 ed25519_cert_extension_free(ed25519_cert_extension_t *obj)
    327 {
    328  if (obj == NULL)
    329    return;
    330  ed25519_cert_extension_clear(obj);
    331  trunnel_memwipe(obj, sizeof(ed25519_cert_extension_t));
    332  trunnel_free_(obj);
    333 }
    334 
    335 uint16_t
    336 ed25519_cert_extension_get_ext_length(const ed25519_cert_extension_t *inp)
    337 {
    338  return inp->ext_length;
    339 }
    340 int
    341 ed25519_cert_extension_set_ext_length(ed25519_cert_extension_t *inp, uint16_t val)
    342 {
    343  inp->ext_length = val;
    344  return 0;
    345 }
    346 uint8_t
    347 ed25519_cert_extension_get_ext_type(const ed25519_cert_extension_t *inp)
    348 {
    349  return inp->ext_type;
    350 }
    351 int
    352 ed25519_cert_extension_set_ext_type(ed25519_cert_extension_t *inp, uint8_t val)
    353 {
    354  inp->ext_type = val;
    355  return 0;
    356 }
    357 uint8_t
    358 ed25519_cert_extension_get_ext_flags(const ed25519_cert_extension_t *inp)
    359 {
    360  return inp->ext_flags;
    361 }
    362 int
    363 ed25519_cert_extension_set_ext_flags(ed25519_cert_extension_t *inp, uint8_t val)
    364 {
    365  inp->ext_flags = val;
    366  return 0;
    367 }
    368 size_t
    369 ed25519_cert_extension_getlen_un_signing_key(const ed25519_cert_extension_t *inp)
    370 {
    371  (void)inp;  return 32;
    372 }
    373 
    374 uint8_t
    375 ed25519_cert_extension_get_un_signing_key(ed25519_cert_extension_t *inp, size_t idx)
    376 {
    377  trunnel_assert(idx < 32);
    378  return inp->un_signing_key[idx];
    379 }
    380 
    381 uint8_t
    382 ed25519_cert_extension_getconst_un_signing_key(const ed25519_cert_extension_t *inp, size_t idx)
    383 {
    384  return ed25519_cert_extension_get_un_signing_key((ed25519_cert_extension_t*)inp, idx);
    385 }
    386 int
    387 ed25519_cert_extension_set_un_signing_key(ed25519_cert_extension_t *inp, size_t idx, uint8_t elt)
    388 {
    389  trunnel_assert(idx < 32);
    390  inp->un_signing_key[idx] = elt;
    391  return 0;
    392 }
    393 
    394 uint8_t *
    395 ed25519_cert_extension_getarray_un_signing_key(ed25519_cert_extension_t *inp)
    396 {
    397  return inp->un_signing_key;
    398 }
    399 const uint8_t  *
    400 ed25519_cert_extension_getconstarray_un_signing_key(const ed25519_cert_extension_t *inp)
    401 {
    402  return (const uint8_t  *)ed25519_cert_extension_getarray_un_signing_key((ed25519_cert_extension_t*)inp);
    403 }
    404 size_t
    405 ed25519_cert_extension_getlen_un_unparsed(const ed25519_cert_extension_t *inp)
    406 {
    407  return TRUNNEL_DYNARRAY_LEN(&inp->un_unparsed);
    408 }
    409 
    410 uint8_t
    411 ed25519_cert_extension_get_un_unparsed(ed25519_cert_extension_t *inp, size_t idx)
    412 {
    413  return TRUNNEL_DYNARRAY_GET(&inp->un_unparsed, idx);
    414 }
    415 
    416 uint8_t
    417 ed25519_cert_extension_getconst_un_unparsed(const ed25519_cert_extension_t *inp, size_t idx)
    418 {
    419  return ed25519_cert_extension_get_un_unparsed((ed25519_cert_extension_t*)inp, idx);
    420 }
    421 int
    422 ed25519_cert_extension_set_un_unparsed(ed25519_cert_extension_t *inp, size_t idx, uint8_t elt)
    423 {
    424  TRUNNEL_DYNARRAY_SET(&inp->un_unparsed, idx, elt);
    425  return 0;
    426 }
    427 int
    428 ed25519_cert_extension_add_un_unparsed(ed25519_cert_extension_t *inp, uint8_t elt)
    429 {
    430  TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->un_unparsed, elt, {});
    431  return 0;
    432 trunnel_alloc_failed:
    433  TRUNNEL_SET_ERROR_CODE(inp);
    434  return -1;
    435 }
    436 
    437 uint8_t *
    438 ed25519_cert_extension_getarray_un_unparsed(ed25519_cert_extension_t *inp)
    439 {
    440  return inp->un_unparsed.elts_;
    441 }
    442 const uint8_t  *
    443 ed25519_cert_extension_getconstarray_un_unparsed(const ed25519_cert_extension_t *inp)
    444 {
    445  return (const uint8_t  *)ed25519_cert_extension_getarray_un_unparsed((ed25519_cert_extension_t*)inp);
    446 }
    447 int
    448 ed25519_cert_extension_setlen_un_unparsed(ed25519_cert_extension_t *inp, size_t newlen)
    449 {
    450  uint8_t *newptr;
    451  newptr = trunnel_dynarray_setlen(&inp->un_unparsed.allocated_,
    452                 &inp->un_unparsed.n_, inp->un_unparsed.elts_, newlen,
    453                 sizeof(inp->un_unparsed.elts_[0]), (trunnel_free_fn_t) NULL,
    454                 &inp->trunnel_error_code_);
    455  if (newlen != 0 && newptr == NULL)
    456    goto trunnel_alloc_failed;
    457  inp->un_unparsed.elts_ = newptr;
    458  return 0;
    459 trunnel_alloc_failed:
    460  TRUNNEL_SET_ERROR_CODE(inp);
    461  return -1;
    462 }
    463 const char *
    464 ed25519_cert_extension_check(const ed25519_cert_extension_t *obj)
    465 {
    466  if (obj == NULL)
    467    return "Object was NULL";
    468  if (obj->trunnel_error_code_)
    469    return "A set function failed on this object";
    470  switch (obj->ext_type) {
    471 
    472    case CERTEXT_SIGNED_WITH_KEY:
    473      break;
    474 
    475    default:
    476      break;
    477  }
    478  return NULL;
    479 }
    480 
    481 ssize_t
    482 ed25519_cert_extension_encoded_len(const ed25519_cert_extension_t *obj)
    483 {
    484  ssize_t result = 0;
    485 
    486  if (NULL != ed25519_cert_extension_check(obj))
    487     return -1;
    488 
    489 
    490  /* Length of u16 ext_length */
    491  result += 2;
    492 
    493  /* Length of u8 ext_type */
    494  result += 1;
    495 
    496  /* Length of u8 ext_flags */
    497  result += 1;
    498  switch (obj->ext_type) {
    499 
    500    case CERTEXT_SIGNED_WITH_KEY:
    501 
    502      /* Length of u8 un_signing_key[32] */
    503      result += 32;
    504      break;
    505 
    506    default:
    507 
    508      /* Length of u8 un_unparsed[] */
    509      result += TRUNNEL_DYNARRAY_LEN(&obj->un_unparsed);
    510      break;
    511  }
    512  return result;
    513 }
    514 int
    515 ed25519_cert_extension_clear_errors(ed25519_cert_extension_t *obj)
    516 {
    517  int r = obj->trunnel_error_code_;
    518  obj->trunnel_error_code_ = 0;
    519  return r;
    520 }
    521 ssize_t
    522 ed25519_cert_extension_encode(uint8_t *output, const size_t avail, const ed25519_cert_extension_t *obj)
    523 {
    524  ssize_t result = 0;
    525  size_t written = 0;
    526  uint8_t *ptr = output;
    527  const char *msg;
    528 #ifdef TRUNNEL_CHECK_ENCODED_LEN
    529  const ssize_t encoded_len = ed25519_cert_extension_encoded_len(obj);
    530 #endif
    531 
    532  uint8_t *backptr_ext_length = NULL;
    533 
    534  if (NULL != (msg = ed25519_cert_extension_check(obj)))
    535    goto check_failed;
    536 
    537 #ifdef TRUNNEL_CHECK_ENCODED_LEN
    538  trunnel_assert(encoded_len >= 0);
    539 #endif
    540 
    541  /* Encode u16 ext_length */
    542  backptr_ext_length = ptr;
    543  trunnel_assert(written <= avail);
    544  if (avail - written < 2)
    545    goto truncated;
    546  trunnel_set_uint16(ptr, trunnel_htons(obj->ext_length));
    547  written += 2; ptr += 2;
    548 
    549  /* Encode u8 ext_type */
    550  trunnel_assert(written <= avail);
    551  if (avail - written < 1)
    552    goto truncated;
    553  trunnel_set_uint8(ptr, (obj->ext_type));
    554  written += 1; ptr += 1;
    555 
    556  /* Encode u8 ext_flags */
    557  trunnel_assert(written <= avail);
    558  if (avail - written < 1)
    559    goto truncated;
    560  trunnel_set_uint8(ptr, (obj->ext_flags));
    561  written += 1; ptr += 1;
    562  {
    563    size_t written_before_union = written;
    564 
    565    /* Encode union un[ext_type] */
    566    trunnel_assert(written <= avail);
    567    switch (obj->ext_type) {
    568 
    569      case CERTEXT_SIGNED_WITH_KEY:
    570 
    571        /* Encode u8 un_signing_key[32] */
    572        trunnel_assert(written <= avail);
    573        if (avail - written < 32)
    574          goto truncated;
    575        memcpy(ptr, obj->un_signing_key, 32);
    576        written += 32; ptr += 32;
    577        break;
    578 
    579      default:
    580 
    581        /* Encode u8 un_unparsed[] */
    582        {
    583          size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->un_unparsed);
    584          trunnel_assert(written <= avail);
    585          if (avail - written < elt_len)
    586            goto truncated;
    587          if (elt_len)
    588            memcpy(ptr, obj->un_unparsed.elts_, elt_len);
    589          written += elt_len; ptr += elt_len;
    590        }
    591        break;
    592    }
    593    /* Write the length field back to ext_length */
    594    trunnel_assert(written >= written_before_union);
    595 #if UINT16_MAX < SIZE_MAX
    596    if (written - written_before_union > UINT16_MAX)
    597      goto check_failed;
    598 #endif
    599    trunnel_set_uint16(backptr_ext_length, trunnel_htons(written - written_before_union));
    600  }
    601 
    602 
    603  trunnel_assert(ptr == output + written);
    604 #ifdef TRUNNEL_CHECK_ENCODED_LEN
    605  {
    606    trunnel_assert(encoded_len >= 0);
    607    trunnel_assert((size_t)encoded_len == written);
    608  }
    609 
    610 #endif
    611 
    612  return written;
    613 
    614 truncated:
    615  result = -2;
    616  goto fail;
    617 check_failed:
    618  (void)msg;
    619  result = -1;
    620  goto fail;
    621 fail:
    622  trunnel_assert(result < 0);
    623  return result;
    624 }
    625 
    626 /** As ed25519_cert_extension_parse(), but do not allocate the output
    627 * object.
    628 */
    629 static ssize_t
    630 ed25519_cert_extension_parse_into(ed25519_cert_extension_t *obj, const uint8_t *input, const size_t len_in)
    631 {
    632  const uint8_t *ptr = input;
    633  size_t remaining = len_in;
    634  ssize_t result = 0;
    635  (void)result;
    636 
    637  /* Parse u16 ext_length */
    638  CHECK_REMAINING(2, truncated);
    639  obj->ext_length = trunnel_ntohs(trunnel_get_uint16(ptr));
    640  remaining -= 2; ptr += 2;
    641 
    642  /* Parse u8 ext_type */
    643  CHECK_REMAINING(1, truncated);
    644  obj->ext_type = (trunnel_get_uint8(ptr));
    645  remaining -= 1; ptr += 1;
    646 
    647  /* Parse u8 ext_flags */
    648  CHECK_REMAINING(1, truncated);
    649  obj->ext_flags = (trunnel_get_uint8(ptr));
    650  remaining -= 1; ptr += 1;
    651  {
    652    size_t remaining_after;
    653    CHECK_REMAINING(obj->ext_length, truncated);
    654    remaining_after = remaining - obj->ext_length;
    655    remaining = obj->ext_length;
    656 
    657    /* Parse union un[ext_type] */
    658    switch (obj->ext_type) {
    659 
    660      case CERTEXT_SIGNED_WITH_KEY:
    661 
    662        /* Parse u8 un_signing_key[32] */
    663        CHECK_REMAINING(32, fail);
    664        memcpy(obj->un_signing_key, ptr, 32);
    665        remaining -= 32; ptr += 32;
    666        break;
    667 
    668      default:
    669 
    670        /* Parse u8 un_unparsed[] */
    671        TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->un_unparsed, remaining, {});
    672        obj->un_unparsed.n_ = remaining;
    673        if (remaining)
    674          memcpy(obj->un_unparsed.elts_, ptr, remaining);
    675        ptr += remaining; remaining -= remaining;
    676        break;
    677    }
    678    if (remaining != 0)
    679      goto fail;
    680    remaining = remaining_after;
    681  }
    682  trunnel_assert(ptr + remaining == input + len_in);
    683  return len_in - remaining;
    684 
    685 truncated:
    686  return -2;
    687 trunnel_alloc_failed:
    688  return -1;
    689 fail:
    690  result = -1;
    691  return result;
    692 }
    693 
    694 ssize_t
    695 ed25519_cert_extension_parse(ed25519_cert_extension_t **output, const uint8_t *input, const size_t len_in)
    696 {
    697  ssize_t result;
    698  *output = ed25519_cert_extension_new();
    699  if (NULL == *output)
    700    return -1;
    701  result = ed25519_cert_extension_parse_into(*output, input, len_in);
    702  if (result < 0) {
    703    ed25519_cert_extension_free(*output);
    704    *output = NULL;
    705  }
    706  return result;
    707 }
    708 extend1_cell_body_t *
    709 extend1_cell_body_new(void)
    710 {
    711  extend1_cell_body_t *val = trunnel_calloc(1, sizeof(extend1_cell_body_t));
    712  if (NULL == val)
    713    return NULL;
    714  return val;
    715 }
    716 
    717 /** Release all storage held inside 'obj', but do not free 'obj'.
    718 */
    719 static void
    720 extend1_cell_body_clear(extend1_cell_body_t *obj)
    721 {
    722  (void) obj;
    723 }
    724 
    725 void
    726 extend1_cell_body_free(extend1_cell_body_t *obj)
    727 {
    728  if (obj == NULL)
    729    return;
    730  extend1_cell_body_clear(obj);
    731  trunnel_memwipe(obj, sizeof(extend1_cell_body_t));
    732  trunnel_free_(obj);
    733 }
    734 
    735 uint32_t
    736 extend1_cell_body_get_ipv4addr(const extend1_cell_body_t *inp)
    737 {
    738  return inp->ipv4addr;
    739 }
    740 int
    741 extend1_cell_body_set_ipv4addr(extend1_cell_body_t *inp, uint32_t val)
    742 {
    743  inp->ipv4addr = val;
    744  return 0;
    745 }
    746 uint16_t
    747 extend1_cell_body_get_port(const extend1_cell_body_t *inp)
    748 {
    749  return inp->port;
    750 }
    751 int
    752 extend1_cell_body_set_port(extend1_cell_body_t *inp, uint16_t val)
    753 {
    754  inp->port = val;
    755  return 0;
    756 }
    757 size_t
    758 extend1_cell_body_getlen_onionskin(const extend1_cell_body_t *inp)
    759 {
    760  (void)inp;  return 186;
    761 }
    762 
    763 uint8_t
    764 extend1_cell_body_get_onionskin(extend1_cell_body_t *inp, size_t idx)
    765 {
    766  trunnel_assert(idx < 186);
    767  return inp->onionskin[idx];
    768 }
    769 
    770 uint8_t
    771 extend1_cell_body_getconst_onionskin(const extend1_cell_body_t *inp, size_t idx)
    772 {
    773  return extend1_cell_body_get_onionskin((extend1_cell_body_t*)inp, idx);
    774 }
    775 int
    776 extend1_cell_body_set_onionskin(extend1_cell_body_t *inp, size_t idx, uint8_t elt)
    777 {
    778  trunnel_assert(idx < 186);
    779  inp->onionskin[idx] = elt;
    780  return 0;
    781 }
    782 
    783 uint8_t *
    784 extend1_cell_body_getarray_onionskin(extend1_cell_body_t *inp)
    785 {
    786  return inp->onionskin;
    787 }
    788 const uint8_t  *
    789 extend1_cell_body_getconstarray_onionskin(const extend1_cell_body_t *inp)
    790 {
    791  return (const uint8_t  *)extend1_cell_body_getarray_onionskin((extend1_cell_body_t*)inp);
    792 }
    793 size_t
    794 extend1_cell_body_getlen_identity(const extend1_cell_body_t *inp)
    795 {
    796  (void)inp;  return 20;
    797 }
    798 
    799 uint8_t
    800 extend1_cell_body_get_identity(extend1_cell_body_t *inp, size_t idx)
    801 {
    802  trunnel_assert(idx < 20);
    803  return inp->identity[idx];
    804 }
    805 
    806 uint8_t
    807 extend1_cell_body_getconst_identity(const extend1_cell_body_t *inp, size_t idx)
    808 {
    809  return extend1_cell_body_get_identity((extend1_cell_body_t*)inp, idx);
    810 }
    811 int
    812 extend1_cell_body_set_identity(extend1_cell_body_t *inp, size_t idx, uint8_t elt)
    813 {
    814  trunnel_assert(idx < 20);
    815  inp->identity[idx] = elt;
    816  return 0;
    817 }
    818 
    819 uint8_t *
    820 extend1_cell_body_getarray_identity(extend1_cell_body_t *inp)
    821 {
    822  return inp->identity;
    823 }
    824 const uint8_t  *
    825 extend1_cell_body_getconstarray_identity(const extend1_cell_body_t *inp)
    826 {
    827  return (const uint8_t  *)extend1_cell_body_getarray_identity((extend1_cell_body_t*)inp);
    828 }
    829 const char *
    830 extend1_cell_body_check(const extend1_cell_body_t *obj)
    831 {
    832  if (obj == NULL)
    833    return "Object was NULL";
    834  if (obj->trunnel_error_code_)
    835    return "A set function failed on this object";
    836  return NULL;
    837 }
    838 
    839 ssize_t
    840 extend1_cell_body_encoded_len(const extend1_cell_body_t *obj)
    841 {
    842  ssize_t result = 0;
    843 
    844  if (NULL != extend1_cell_body_check(obj))
    845     return -1;
    846 
    847 
    848  /* Length of u32 ipv4addr */
    849  result += 4;
    850 
    851  /* Length of u16 port */
    852  result += 2;
    853 
    854  /* Length of u8 onionskin[186] */
    855  result += 186;
    856 
    857  /* Length of u8 identity[20] */
    858  result += 20;
    859  return result;
    860 }
    861 int
    862 extend1_cell_body_clear_errors(extend1_cell_body_t *obj)
    863 {
    864  int r = obj->trunnel_error_code_;
    865  obj->trunnel_error_code_ = 0;
    866  return r;
    867 }
    868 ssize_t
    869 extend1_cell_body_encode(uint8_t *output, const size_t avail, const extend1_cell_body_t *obj)
    870 {
    871  ssize_t result = 0;
    872  size_t written = 0;
    873  uint8_t *ptr = output;
    874  const char *msg;
    875 #ifdef TRUNNEL_CHECK_ENCODED_LEN
    876  const ssize_t encoded_len = extend1_cell_body_encoded_len(obj);
    877 #endif
    878 
    879  if (NULL != (msg = extend1_cell_body_check(obj)))
    880    goto check_failed;
    881 
    882 #ifdef TRUNNEL_CHECK_ENCODED_LEN
    883  trunnel_assert(encoded_len >= 0);
    884 #endif
    885 
    886  /* Encode u32 ipv4addr */
    887  trunnel_assert(written <= avail);
    888  if (avail - written < 4)
    889    goto truncated;
    890  trunnel_set_uint32(ptr, trunnel_htonl(obj->ipv4addr));
    891  written += 4; ptr += 4;
    892 
    893  /* Encode u16 port */
    894  trunnel_assert(written <= avail);
    895  if (avail - written < 2)
    896    goto truncated;
    897  trunnel_set_uint16(ptr, trunnel_htons(obj->port));
    898  written += 2; ptr += 2;
    899 
    900  /* Encode u8 onionskin[186] */
    901  trunnel_assert(written <= avail);
    902  if (avail - written < 186)
    903    goto truncated;
    904  memcpy(ptr, obj->onionskin, 186);
    905  written += 186; ptr += 186;
    906 
    907  /* Encode u8 identity[20] */
    908  trunnel_assert(written <= avail);
    909  if (avail - written < 20)
    910    goto truncated;
    911  memcpy(ptr, obj->identity, 20);
    912  written += 20; ptr += 20;
    913 
    914 
    915  trunnel_assert(ptr == output + written);
    916 #ifdef TRUNNEL_CHECK_ENCODED_LEN
    917  {
    918    trunnel_assert(encoded_len >= 0);
    919    trunnel_assert((size_t)encoded_len == written);
    920  }
    921 
    922 #endif
    923 
    924  return written;
    925 
    926 truncated:
    927  result = -2;
    928  goto fail;
    929 check_failed:
    930  (void)msg;
    931  result = -1;
    932  goto fail;
    933 fail:
    934  trunnel_assert(result < 0);
    935  return result;
    936 }
    937 
    938 /** As extend1_cell_body_parse(), but do not allocate the output
    939 * object.
    940 */
    941 static ssize_t
    942 extend1_cell_body_parse_into(extend1_cell_body_t *obj, const uint8_t *input, const size_t len_in)
    943 {
    944  const uint8_t *ptr = input;
    945  size_t remaining = len_in;
    946  ssize_t result = 0;
    947  (void)result;
    948 
    949  /* Parse u32 ipv4addr */
    950  CHECK_REMAINING(4, truncated);
    951  obj->ipv4addr = trunnel_ntohl(trunnel_get_uint32(ptr));
    952  remaining -= 4; ptr += 4;
    953 
    954  /* Parse u16 port */
    955  CHECK_REMAINING(2, truncated);
    956  obj->port = trunnel_ntohs(trunnel_get_uint16(ptr));
    957  remaining -= 2; ptr += 2;
    958 
    959  /* Parse u8 onionskin[186] */
    960  CHECK_REMAINING(186, truncated);
    961  memcpy(obj->onionskin, ptr, 186);
    962  remaining -= 186; ptr += 186;
    963 
    964  /* Parse u8 identity[20] */
    965  CHECK_REMAINING(20, truncated);
    966  memcpy(obj->identity, ptr, 20);
    967  remaining -= 20; ptr += 20;
    968  trunnel_assert(ptr + remaining == input + len_in);
    969  return len_in - remaining;
    970 
    971 truncated:
    972  return -2;
    973 }
    974 
    975 ssize_t
    976 extend1_cell_body_parse(extend1_cell_body_t **output, const uint8_t *input, const size_t len_in)
    977 {
    978  ssize_t result;
    979  *output = extend1_cell_body_new();
    980  if (NULL == *output)
    981    return -1;
    982  result = extend1_cell_body_parse_into(*output, input, len_in);
    983  if (result < 0) {
    984    extend1_cell_body_free(*output);
    985    *output = NULL;
    986  }
    987  return result;
    988 }
    989 link_specifier_t *
    990 link_specifier_new(void)
    991 {
    992  link_specifier_t *val = trunnel_calloc(1, sizeof(link_specifier_t));
    993  if (NULL == val)
    994    return NULL;
    995  return val;
    996 }
    997 
    998 /** Release all storage held inside 'obj', but do not free 'obj'.
    999 */
   1000 static void
   1001 link_specifier_clear(link_specifier_t *obj)
   1002 {
   1003  (void) obj;
   1004  TRUNNEL_DYNARRAY_WIPE(&obj->un_unrecognized);
   1005  TRUNNEL_DYNARRAY_CLEAR(&obj->un_unrecognized);
   1006 }
   1007 
   1008 void
   1009 link_specifier_free(link_specifier_t *obj)
   1010 {
   1011  if (obj == NULL)
   1012    return;
   1013  link_specifier_clear(obj);
   1014  trunnel_memwipe(obj, sizeof(link_specifier_t));
   1015  trunnel_free_(obj);
   1016 }
   1017 
   1018 uint8_t
   1019 link_specifier_get_ls_type(const link_specifier_t *inp)
   1020 {
   1021  return inp->ls_type;
   1022 }
   1023 int
   1024 link_specifier_set_ls_type(link_specifier_t *inp, uint8_t val)
   1025 {
   1026  inp->ls_type = val;
   1027  return 0;
   1028 }
   1029 uint8_t
   1030 link_specifier_get_ls_len(const link_specifier_t *inp)
   1031 {
   1032  return inp->ls_len;
   1033 }
   1034 int
   1035 link_specifier_set_ls_len(link_specifier_t *inp, uint8_t val)
   1036 {
   1037  inp->ls_len = val;
   1038  return 0;
   1039 }
   1040 uint32_t
   1041 link_specifier_get_un_ipv4_addr(const link_specifier_t *inp)
   1042 {
   1043  return inp->un_ipv4_addr;
   1044 }
   1045 int
   1046 link_specifier_set_un_ipv4_addr(link_specifier_t *inp, uint32_t val)
   1047 {
   1048  inp->un_ipv4_addr = val;
   1049  return 0;
   1050 }
   1051 uint16_t
   1052 link_specifier_get_un_ipv4_port(const link_specifier_t *inp)
   1053 {
   1054  return inp->un_ipv4_port;
   1055 }
   1056 int
   1057 link_specifier_set_un_ipv4_port(link_specifier_t *inp, uint16_t val)
   1058 {
   1059  inp->un_ipv4_port = val;
   1060  return 0;
   1061 }
   1062 size_t
   1063 link_specifier_getlen_un_ipv6_addr(const link_specifier_t *inp)
   1064 {
   1065  (void)inp;  return 16;
   1066 }
   1067 
   1068 uint8_t
   1069 link_specifier_get_un_ipv6_addr(link_specifier_t *inp, size_t idx)
   1070 {
   1071  trunnel_assert(idx < 16);
   1072  return inp->un_ipv6_addr[idx];
   1073 }
   1074 
   1075 uint8_t
   1076 link_specifier_getconst_un_ipv6_addr(const link_specifier_t *inp, size_t idx)
   1077 {
   1078  return link_specifier_get_un_ipv6_addr((link_specifier_t*)inp, idx);
   1079 }
   1080 int
   1081 link_specifier_set_un_ipv6_addr(link_specifier_t *inp, size_t idx, uint8_t elt)
   1082 {
   1083  trunnel_assert(idx < 16);
   1084  inp->un_ipv6_addr[idx] = elt;
   1085  return 0;
   1086 }
   1087 
   1088 uint8_t *
   1089 link_specifier_getarray_un_ipv6_addr(link_specifier_t *inp)
   1090 {
   1091  return inp->un_ipv6_addr;
   1092 }
   1093 const uint8_t  *
   1094 link_specifier_getconstarray_un_ipv6_addr(const link_specifier_t *inp)
   1095 {
   1096  return (const uint8_t  *)link_specifier_getarray_un_ipv6_addr((link_specifier_t*)inp);
   1097 }
   1098 uint16_t
   1099 link_specifier_get_un_ipv6_port(const link_specifier_t *inp)
   1100 {
   1101  return inp->un_ipv6_port;
   1102 }
   1103 int
   1104 link_specifier_set_un_ipv6_port(link_specifier_t *inp, uint16_t val)
   1105 {
   1106  inp->un_ipv6_port = val;
   1107  return 0;
   1108 }
   1109 size_t
   1110 link_specifier_getlen_un_legacy_id(const link_specifier_t *inp)
   1111 {
   1112  (void)inp;  return 20;
   1113 }
   1114 
   1115 uint8_t
   1116 link_specifier_get_un_legacy_id(link_specifier_t *inp, size_t idx)
   1117 {
   1118  trunnel_assert(idx < 20);
   1119  return inp->un_legacy_id[idx];
   1120 }
   1121 
   1122 uint8_t
   1123 link_specifier_getconst_un_legacy_id(const link_specifier_t *inp, size_t idx)
   1124 {
   1125  return link_specifier_get_un_legacy_id((link_specifier_t*)inp, idx);
   1126 }
   1127 int
   1128 link_specifier_set_un_legacy_id(link_specifier_t *inp, size_t idx, uint8_t elt)
   1129 {
   1130  trunnel_assert(idx < 20);
   1131  inp->un_legacy_id[idx] = elt;
   1132  return 0;
   1133 }
   1134 
   1135 uint8_t *
   1136 link_specifier_getarray_un_legacy_id(link_specifier_t *inp)
   1137 {
   1138  return inp->un_legacy_id;
   1139 }
   1140 const uint8_t  *
   1141 link_specifier_getconstarray_un_legacy_id(const link_specifier_t *inp)
   1142 {
   1143  return (const uint8_t  *)link_specifier_getarray_un_legacy_id((link_specifier_t*)inp);
   1144 }
   1145 size_t
   1146 link_specifier_getlen_un_ed25519_id(const link_specifier_t *inp)
   1147 {
   1148  (void)inp;  return 32;
   1149 }
   1150 
   1151 uint8_t
   1152 link_specifier_get_un_ed25519_id(link_specifier_t *inp, size_t idx)
   1153 {
   1154  trunnel_assert(idx < 32);
   1155  return inp->un_ed25519_id[idx];
   1156 }
   1157 
   1158 uint8_t
   1159 link_specifier_getconst_un_ed25519_id(const link_specifier_t *inp, size_t idx)
   1160 {
   1161  return link_specifier_get_un_ed25519_id((link_specifier_t*)inp, idx);
   1162 }
   1163 int
   1164 link_specifier_set_un_ed25519_id(link_specifier_t *inp, size_t idx, uint8_t elt)
   1165 {
   1166  trunnel_assert(idx < 32);
   1167  inp->un_ed25519_id[idx] = elt;
   1168  return 0;
   1169 }
   1170 
   1171 uint8_t *
   1172 link_specifier_getarray_un_ed25519_id(link_specifier_t *inp)
   1173 {
   1174  return inp->un_ed25519_id;
   1175 }
   1176 const uint8_t  *
   1177 link_specifier_getconstarray_un_ed25519_id(const link_specifier_t *inp)
   1178 {
   1179  return (const uint8_t  *)link_specifier_getarray_un_ed25519_id((link_specifier_t*)inp);
   1180 }
   1181 size_t
   1182 link_specifier_getlen_un_unrecognized(const link_specifier_t *inp)
   1183 {
   1184  return TRUNNEL_DYNARRAY_LEN(&inp->un_unrecognized);
   1185 }
   1186 
   1187 uint8_t
   1188 link_specifier_get_un_unrecognized(link_specifier_t *inp, size_t idx)
   1189 {
   1190  return TRUNNEL_DYNARRAY_GET(&inp->un_unrecognized, idx);
   1191 }
   1192 
   1193 uint8_t
   1194 link_specifier_getconst_un_unrecognized(const link_specifier_t *inp, size_t idx)
   1195 {
   1196  return link_specifier_get_un_unrecognized((link_specifier_t*)inp, idx);
   1197 }
   1198 int
   1199 link_specifier_set_un_unrecognized(link_specifier_t *inp, size_t idx, uint8_t elt)
   1200 {
   1201  TRUNNEL_DYNARRAY_SET(&inp->un_unrecognized, idx, elt);
   1202  return 0;
   1203 }
   1204 int
   1205 link_specifier_add_un_unrecognized(link_specifier_t *inp, uint8_t elt)
   1206 {
   1207  TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->un_unrecognized, elt, {});
   1208  return 0;
   1209 trunnel_alloc_failed:
   1210  TRUNNEL_SET_ERROR_CODE(inp);
   1211  return -1;
   1212 }
   1213 
   1214 uint8_t *
   1215 link_specifier_getarray_un_unrecognized(link_specifier_t *inp)
   1216 {
   1217  return inp->un_unrecognized.elts_;
   1218 }
   1219 const uint8_t  *
   1220 link_specifier_getconstarray_un_unrecognized(const link_specifier_t *inp)
   1221 {
   1222  return (const uint8_t  *)link_specifier_getarray_un_unrecognized((link_specifier_t*)inp);
   1223 }
   1224 int
   1225 link_specifier_setlen_un_unrecognized(link_specifier_t *inp, size_t newlen)
   1226 {
   1227  uint8_t *newptr;
   1228  newptr = trunnel_dynarray_setlen(&inp->un_unrecognized.allocated_,
   1229                 &inp->un_unrecognized.n_, inp->un_unrecognized.elts_, newlen,
   1230                 sizeof(inp->un_unrecognized.elts_[0]), (trunnel_free_fn_t) NULL,
   1231                 &inp->trunnel_error_code_);
   1232  if (newlen != 0 && newptr == NULL)
   1233    goto trunnel_alloc_failed;
   1234  inp->un_unrecognized.elts_ = newptr;
   1235  return 0;
   1236 trunnel_alloc_failed:
   1237  TRUNNEL_SET_ERROR_CODE(inp);
   1238  return -1;
   1239 }
   1240 const char *
   1241 link_specifier_check(const link_specifier_t *obj)
   1242 {
   1243  if (obj == NULL)
   1244    return "Object was NULL";
   1245  if (obj->trunnel_error_code_)
   1246    return "A set function failed on this object";
   1247  switch (obj->ls_type) {
   1248 
   1249    case LS_IPV4:
   1250      break;
   1251 
   1252    case LS_IPV6:
   1253      break;
   1254 
   1255    case LS_LEGACY_ID:
   1256      break;
   1257 
   1258    case LS_ED25519_ID:
   1259      break;
   1260 
   1261    default:
   1262      break;
   1263  }
   1264  return NULL;
   1265 }
   1266 
   1267 ssize_t
   1268 link_specifier_encoded_len(const link_specifier_t *obj)
   1269 {
   1270  ssize_t result = 0;
   1271 
   1272  if (NULL != link_specifier_check(obj))
   1273     return -1;
   1274 
   1275 
   1276  /* Length of u8 ls_type */
   1277  result += 1;
   1278 
   1279  /* Length of u8 ls_len */
   1280  result += 1;
   1281  switch (obj->ls_type) {
   1282 
   1283    case LS_IPV4:
   1284 
   1285      /* Length of u32 un_ipv4_addr */
   1286      result += 4;
   1287 
   1288      /* Length of u16 un_ipv4_port */
   1289      result += 2;
   1290      break;
   1291 
   1292    case LS_IPV6:
   1293 
   1294      /* Length of u8 un_ipv6_addr[16] */
   1295      result += 16;
   1296 
   1297      /* Length of u16 un_ipv6_port */
   1298      result += 2;
   1299      break;
   1300 
   1301    case LS_LEGACY_ID:
   1302 
   1303      /* Length of u8 un_legacy_id[20] */
   1304      result += 20;
   1305      break;
   1306 
   1307    case LS_ED25519_ID:
   1308 
   1309      /* Length of u8 un_ed25519_id[32] */
   1310      result += 32;
   1311      break;
   1312 
   1313    default:
   1314 
   1315      /* Length of u8 un_unrecognized[] */
   1316      result += TRUNNEL_DYNARRAY_LEN(&obj->un_unrecognized);
   1317      break;
   1318  }
   1319  return result;
   1320 }
   1321 int
   1322 link_specifier_clear_errors(link_specifier_t *obj)
   1323 {
   1324  int r = obj->trunnel_error_code_;
   1325  obj->trunnel_error_code_ = 0;
   1326  return r;
   1327 }
   1328 ssize_t
   1329 link_specifier_encode(uint8_t *output, const size_t avail, const link_specifier_t *obj)
   1330 {
   1331  ssize_t result = 0;
   1332  size_t written = 0;
   1333  uint8_t *ptr = output;
   1334  const char *msg;
   1335 #ifdef TRUNNEL_CHECK_ENCODED_LEN
   1336  const ssize_t encoded_len = link_specifier_encoded_len(obj);
   1337 #endif
   1338 
   1339  uint8_t *backptr_ls_len = NULL;
   1340 
   1341  if (NULL != (msg = link_specifier_check(obj)))
   1342    goto check_failed;
   1343 
   1344 #ifdef TRUNNEL_CHECK_ENCODED_LEN
   1345  trunnel_assert(encoded_len >= 0);
   1346 #endif
   1347 
   1348  /* Encode u8 ls_type */
   1349  trunnel_assert(written <= avail);
   1350  if (avail - written < 1)
   1351    goto truncated;
   1352  trunnel_set_uint8(ptr, (obj->ls_type));
   1353  written += 1; ptr += 1;
   1354 
   1355  /* Encode u8 ls_len */
   1356  backptr_ls_len = ptr;
   1357  trunnel_assert(written <= avail);
   1358  if (avail - written < 1)
   1359    goto truncated;
   1360  trunnel_set_uint8(ptr, (obj->ls_len));
   1361  written += 1; ptr += 1;
   1362  {
   1363    size_t written_before_union = written;
   1364 
   1365    /* Encode union un[ls_type] */
   1366    trunnel_assert(written <= avail);
   1367    switch (obj->ls_type) {
   1368 
   1369      case LS_IPV4:
   1370 
   1371        /* Encode u32 un_ipv4_addr */
   1372        trunnel_assert(written <= avail);
   1373        if (avail - written < 4)
   1374          goto truncated;
   1375        trunnel_set_uint32(ptr, trunnel_htonl(obj->un_ipv4_addr));
   1376        written += 4; ptr += 4;
   1377 
   1378        /* Encode u16 un_ipv4_port */
   1379        trunnel_assert(written <= avail);
   1380        if (avail - written < 2)
   1381          goto truncated;
   1382        trunnel_set_uint16(ptr, trunnel_htons(obj->un_ipv4_port));
   1383        written += 2; ptr += 2;
   1384        break;
   1385 
   1386      case LS_IPV6:
   1387 
   1388        /* Encode u8 un_ipv6_addr[16] */
   1389        trunnel_assert(written <= avail);
   1390        if (avail - written < 16)
   1391          goto truncated;
   1392        memcpy(ptr, obj->un_ipv6_addr, 16);
   1393        written += 16; ptr += 16;
   1394 
   1395        /* Encode u16 un_ipv6_port */
   1396        trunnel_assert(written <= avail);
   1397        if (avail - written < 2)
   1398          goto truncated;
   1399        trunnel_set_uint16(ptr, trunnel_htons(obj->un_ipv6_port));
   1400        written += 2; ptr += 2;
   1401        break;
   1402 
   1403      case LS_LEGACY_ID:
   1404 
   1405        /* Encode u8 un_legacy_id[20] */
   1406        trunnel_assert(written <= avail);
   1407        if (avail - written < 20)
   1408          goto truncated;
   1409        memcpy(ptr, obj->un_legacy_id, 20);
   1410        written += 20; ptr += 20;
   1411        break;
   1412 
   1413      case LS_ED25519_ID:
   1414 
   1415        /* Encode u8 un_ed25519_id[32] */
   1416        trunnel_assert(written <= avail);
   1417        if (avail - written < 32)
   1418          goto truncated;
   1419        memcpy(ptr, obj->un_ed25519_id, 32);
   1420        written += 32; ptr += 32;
   1421        break;
   1422 
   1423      default:
   1424 
   1425        /* Encode u8 un_unrecognized[] */
   1426        {
   1427          size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->un_unrecognized);
   1428          trunnel_assert(written <= avail);
   1429          if (avail - written < elt_len)
   1430            goto truncated;
   1431          if (elt_len)
   1432            memcpy(ptr, obj->un_unrecognized.elts_, elt_len);
   1433          written += elt_len; ptr += elt_len;
   1434        }
   1435        break;
   1436    }
   1437    /* Write the length field back to ls_len */
   1438    trunnel_assert(written >= written_before_union);
   1439 #if UINT8_MAX < SIZE_MAX
   1440    if (written - written_before_union > UINT8_MAX)
   1441      goto check_failed;
   1442 #endif
   1443    trunnel_set_uint8(backptr_ls_len, (written - written_before_union));
   1444  }
   1445 
   1446 
   1447  trunnel_assert(ptr == output + written);
   1448 #ifdef TRUNNEL_CHECK_ENCODED_LEN
   1449  {
   1450    trunnel_assert(encoded_len >= 0);
   1451    trunnel_assert((size_t)encoded_len == written);
   1452  }
   1453 
   1454 #endif
   1455 
   1456  return written;
   1457 
   1458 truncated:
   1459  result = -2;
   1460  goto fail;
   1461 check_failed:
   1462  (void)msg;
   1463  result = -1;
   1464  goto fail;
   1465 fail:
   1466  trunnel_assert(result < 0);
   1467  return result;
   1468 }
   1469 
   1470 /** As link_specifier_parse(), but do not allocate the output object.
   1471 */
   1472 static ssize_t
   1473 link_specifier_parse_into(link_specifier_t *obj, const uint8_t *input, const size_t len_in)
   1474 {
   1475  const uint8_t *ptr = input;
   1476  size_t remaining = len_in;
   1477  ssize_t result = 0;
   1478  (void)result;
   1479 
   1480  /* Parse u8 ls_type */
   1481  CHECK_REMAINING(1, truncated);
   1482  obj->ls_type = (trunnel_get_uint8(ptr));
   1483  remaining -= 1; ptr += 1;
   1484 
   1485  /* Parse u8 ls_len */
   1486  CHECK_REMAINING(1, truncated);
   1487  obj->ls_len = (trunnel_get_uint8(ptr));
   1488  remaining -= 1; ptr += 1;
   1489  {
   1490    size_t remaining_after;
   1491    CHECK_REMAINING(obj->ls_len, truncated);
   1492    remaining_after = remaining - obj->ls_len;
   1493    remaining = obj->ls_len;
   1494 
   1495    /* Parse union un[ls_type] */
   1496    switch (obj->ls_type) {
   1497 
   1498      case LS_IPV4:
   1499 
   1500        /* Parse u32 un_ipv4_addr */
   1501        CHECK_REMAINING(4, fail);
   1502        obj->un_ipv4_addr = trunnel_ntohl(trunnel_get_uint32(ptr));
   1503        remaining -= 4; ptr += 4;
   1504 
   1505        /* Parse u16 un_ipv4_port */
   1506        CHECK_REMAINING(2, fail);
   1507        obj->un_ipv4_port = trunnel_ntohs(trunnel_get_uint16(ptr));
   1508        remaining -= 2; ptr += 2;
   1509        break;
   1510 
   1511      case LS_IPV6:
   1512 
   1513        /* Parse u8 un_ipv6_addr[16] */
   1514        CHECK_REMAINING(16, fail);
   1515        memcpy(obj->un_ipv6_addr, ptr, 16);
   1516        remaining -= 16; ptr += 16;
   1517 
   1518        /* Parse u16 un_ipv6_port */
   1519        CHECK_REMAINING(2, fail);
   1520        obj->un_ipv6_port = trunnel_ntohs(trunnel_get_uint16(ptr));
   1521        remaining -= 2; ptr += 2;
   1522        break;
   1523 
   1524      case LS_LEGACY_ID:
   1525 
   1526        /* Parse u8 un_legacy_id[20] */
   1527        CHECK_REMAINING(20, fail);
   1528        memcpy(obj->un_legacy_id, ptr, 20);
   1529        remaining -= 20; ptr += 20;
   1530        break;
   1531 
   1532      case LS_ED25519_ID:
   1533 
   1534        /* Parse u8 un_ed25519_id[32] */
   1535        CHECK_REMAINING(32, fail);
   1536        memcpy(obj->un_ed25519_id, ptr, 32);
   1537        remaining -= 32; ptr += 32;
   1538        break;
   1539 
   1540      default:
   1541 
   1542        /* Parse u8 un_unrecognized[] */
   1543        TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->un_unrecognized, remaining, {});
   1544        obj->un_unrecognized.n_ = remaining;
   1545        if (remaining)
   1546          memcpy(obj->un_unrecognized.elts_, ptr, remaining);
   1547        ptr += remaining; remaining -= remaining;
   1548        break;
   1549    }
   1550    if (remaining != 0)
   1551      goto fail;
   1552    remaining = remaining_after;
   1553  }
   1554  trunnel_assert(ptr + remaining == input + len_in);
   1555  return len_in - remaining;
   1556 
   1557 truncated:
   1558  return -2;
   1559 trunnel_alloc_failed:
   1560  return -1;
   1561 fail:
   1562  result = -1;
   1563  return result;
   1564 }
   1565 
   1566 ssize_t
   1567 link_specifier_parse(link_specifier_t **output, const uint8_t *input, const size_t len_in)
   1568 {
   1569  ssize_t result;
   1570  *output = link_specifier_new();
   1571  if (NULL == *output)
   1572    return -1;
   1573  result = link_specifier_parse_into(*output, input, len_in);
   1574  if (result < 0) {
   1575    link_specifier_free(*output);
   1576    *output = NULL;
   1577  }
   1578  return result;
   1579 }
   1580 ed25519_cert_t *
   1581 ed25519_cert_new(void)
   1582 {
   1583  ed25519_cert_t *val = trunnel_calloc(1, sizeof(ed25519_cert_t));
   1584  if (NULL == val)
   1585    return NULL;
   1586  val->version = 1;
   1587  return val;
   1588 }
   1589 
   1590 /** Release all storage held inside 'obj', but do not free 'obj'.
   1591 */
   1592 static void
   1593 ed25519_cert_clear(ed25519_cert_t *obj)
   1594 {
   1595  (void) obj;
   1596  {
   1597 
   1598    unsigned idx;
   1599    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ext); ++idx) {
   1600      ed25519_cert_extension_free(TRUNNEL_DYNARRAY_GET(&obj->ext, idx));
   1601    }
   1602  }
   1603  TRUNNEL_DYNARRAY_WIPE(&obj->ext);
   1604  TRUNNEL_DYNARRAY_CLEAR(&obj->ext);
   1605 }
   1606 
   1607 void
   1608 ed25519_cert_free(ed25519_cert_t *obj)
   1609 {
   1610  if (obj == NULL)
   1611    return;
   1612  ed25519_cert_clear(obj);
   1613  trunnel_memwipe(obj, sizeof(ed25519_cert_t));
   1614  trunnel_free_(obj);
   1615 }
   1616 
   1617 uint8_t
   1618 ed25519_cert_get_version(const ed25519_cert_t *inp)
   1619 {
   1620  return inp->version;
   1621 }
   1622 int
   1623 ed25519_cert_set_version(ed25519_cert_t *inp, uint8_t val)
   1624 {
   1625  if (! ((val == 1))) {
   1626     TRUNNEL_SET_ERROR_CODE(inp);
   1627     return -1;
   1628  }
   1629  inp->version = val;
   1630  return 0;
   1631 }
   1632 uint8_t
   1633 ed25519_cert_get_cert_type(const ed25519_cert_t *inp)
   1634 {
   1635  return inp->cert_type;
   1636 }
   1637 int
   1638 ed25519_cert_set_cert_type(ed25519_cert_t *inp, uint8_t val)
   1639 {
   1640  inp->cert_type = val;
   1641  return 0;
   1642 }
   1643 uint32_t
   1644 ed25519_cert_get_exp_field(const ed25519_cert_t *inp)
   1645 {
   1646  return inp->exp_field;
   1647 }
   1648 int
   1649 ed25519_cert_set_exp_field(ed25519_cert_t *inp, uint32_t val)
   1650 {
   1651  inp->exp_field = val;
   1652  return 0;
   1653 }
   1654 uint8_t
   1655 ed25519_cert_get_cert_key_type(const ed25519_cert_t *inp)
   1656 {
   1657  return inp->cert_key_type;
   1658 }
   1659 int
   1660 ed25519_cert_set_cert_key_type(ed25519_cert_t *inp, uint8_t val)
   1661 {
   1662  inp->cert_key_type = val;
   1663  return 0;
   1664 }
   1665 size_t
   1666 ed25519_cert_getlen_certified_key(const ed25519_cert_t *inp)
   1667 {
   1668  (void)inp;  return 32;
   1669 }
   1670 
   1671 uint8_t
   1672 ed25519_cert_get_certified_key(ed25519_cert_t *inp, size_t idx)
   1673 {
   1674  trunnel_assert(idx < 32);
   1675  return inp->certified_key[idx];
   1676 }
   1677 
   1678 uint8_t
   1679 ed25519_cert_getconst_certified_key(const ed25519_cert_t *inp, size_t idx)
   1680 {
   1681  return ed25519_cert_get_certified_key((ed25519_cert_t*)inp, idx);
   1682 }
   1683 int
   1684 ed25519_cert_set_certified_key(ed25519_cert_t *inp, size_t idx, uint8_t elt)
   1685 {
   1686  trunnel_assert(idx < 32);
   1687  inp->certified_key[idx] = elt;
   1688  return 0;
   1689 }
   1690 
   1691 uint8_t *
   1692 ed25519_cert_getarray_certified_key(ed25519_cert_t *inp)
   1693 {
   1694  return inp->certified_key;
   1695 }
   1696 const uint8_t  *
   1697 ed25519_cert_getconstarray_certified_key(const ed25519_cert_t *inp)
   1698 {
   1699  return (const uint8_t  *)ed25519_cert_getarray_certified_key((ed25519_cert_t*)inp);
   1700 }
   1701 uint8_t
   1702 ed25519_cert_get_n_extensions(const ed25519_cert_t *inp)
   1703 {
   1704  return inp->n_extensions;
   1705 }
   1706 int
   1707 ed25519_cert_set_n_extensions(ed25519_cert_t *inp, uint8_t val)
   1708 {
   1709  inp->n_extensions = val;
   1710  return 0;
   1711 }
   1712 size_t
   1713 ed25519_cert_getlen_ext(const ed25519_cert_t *inp)
   1714 {
   1715  return TRUNNEL_DYNARRAY_LEN(&inp->ext);
   1716 }
   1717 
   1718 struct ed25519_cert_extension_st *
   1719 ed25519_cert_get_ext(ed25519_cert_t *inp, size_t idx)
   1720 {
   1721  return TRUNNEL_DYNARRAY_GET(&inp->ext, idx);
   1722 }
   1723 
   1724 const struct ed25519_cert_extension_st *
   1725 ed25519_cert_getconst_ext(const ed25519_cert_t *inp, size_t idx)
   1726 {
   1727  return ed25519_cert_get_ext((ed25519_cert_t*)inp, idx);
   1728 }
   1729 int
   1730 ed25519_cert_set_ext(ed25519_cert_t *inp, size_t idx, struct ed25519_cert_extension_st * elt)
   1731 {
   1732  ed25519_cert_extension_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->ext, idx);
   1733  if (oldval && oldval != elt)
   1734    ed25519_cert_extension_free(oldval);
   1735  return ed25519_cert_set0_ext(inp, idx, elt);
   1736 }
   1737 int
   1738 ed25519_cert_set0_ext(ed25519_cert_t *inp, size_t idx, struct ed25519_cert_extension_st * elt)
   1739 {
   1740  TRUNNEL_DYNARRAY_SET(&inp->ext, idx, elt);
   1741  return 0;
   1742 }
   1743 int
   1744 ed25519_cert_add_ext(ed25519_cert_t *inp, struct ed25519_cert_extension_st * elt)
   1745 {
   1746 #if SIZE_MAX >= UINT8_MAX
   1747  if (inp->ext.n_ == UINT8_MAX)
   1748    goto trunnel_alloc_failed;
   1749 #endif
   1750  TRUNNEL_DYNARRAY_ADD(struct ed25519_cert_extension_st *, &inp->ext, elt, {});
   1751  return 0;
   1752 trunnel_alloc_failed:
   1753  TRUNNEL_SET_ERROR_CODE(inp);
   1754  return -1;
   1755 }
   1756 
   1757 struct ed25519_cert_extension_st * *
   1758 ed25519_cert_getarray_ext(ed25519_cert_t *inp)
   1759 {
   1760  return inp->ext.elts_;
   1761 }
   1762 const struct ed25519_cert_extension_st *  const  *
   1763 ed25519_cert_getconstarray_ext(const ed25519_cert_t *inp)
   1764 {
   1765  return (const struct ed25519_cert_extension_st *  const  *)ed25519_cert_getarray_ext((ed25519_cert_t*)inp);
   1766 }
   1767 int
   1768 ed25519_cert_setlen_ext(ed25519_cert_t *inp, size_t newlen)
   1769 {
   1770  struct ed25519_cert_extension_st * *newptr;
   1771 #if UINT8_MAX < SIZE_MAX
   1772  if (newlen > UINT8_MAX)
   1773    goto trunnel_alloc_failed;
   1774 #endif
   1775  newptr = trunnel_dynarray_setlen(&inp->ext.allocated_,
   1776                 &inp->ext.n_, inp->ext.elts_, newlen,
   1777                 sizeof(inp->ext.elts_[0]), (trunnel_free_fn_t) ed25519_cert_extension_free,
   1778                 &inp->trunnel_error_code_);
   1779  if (newlen != 0 && newptr == NULL)
   1780    goto trunnel_alloc_failed;
   1781  inp->ext.elts_ = newptr;
   1782  return 0;
   1783 trunnel_alloc_failed:
   1784  TRUNNEL_SET_ERROR_CODE(inp);
   1785  return -1;
   1786 }
   1787 size_t
   1788 ed25519_cert_getlen_signature(const ed25519_cert_t *inp)
   1789 {
   1790  (void)inp;  return 64;
   1791 }
   1792 
   1793 uint8_t
   1794 ed25519_cert_get_signature(ed25519_cert_t *inp, size_t idx)
   1795 {
   1796  trunnel_assert(idx < 64);
   1797  return inp->signature[idx];
   1798 }
   1799 
   1800 uint8_t
   1801 ed25519_cert_getconst_signature(const ed25519_cert_t *inp, size_t idx)
   1802 {
   1803  return ed25519_cert_get_signature((ed25519_cert_t*)inp, idx);
   1804 }
   1805 int
   1806 ed25519_cert_set_signature(ed25519_cert_t *inp, size_t idx, uint8_t elt)
   1807 {
   1808  trunnel_assert(idx < 64);
   1809  inp->signature[idx] = elt;
   1810  return 0;
   1811 }
   1812 
   1813 uint8_t *
   1814 ed25519_cert_getarray_signature(ed25519_cert_t *inp)
   1815 {
   1816  return inp->signature;
   1817 }
   1818 const uint8_t  *
   1819 ed25519_cert_getconstarray_signature(const ed25519_cert_t *inp)
   1820 {
   1821  return (const uint8_t  *)ed25519_cert_getarray_signature((ed25519_cert_t*)inp);
   1822 }
   1823 const char *
   1824 ed25519_cert_check(const ed25519_cert_t *obj)
   1825 {
   1826  if (obj == NULL)
   1827    return "Object was NULL";
   1828  if (obj->trunnel_error_code_)
   1829    return "A set function failed on this object";
   1830  if (! (obj->version == 1))
   1831    return "Integer out of bounds";
   1832  {
   1833    const char *msg;
   1834 
   1835    unsigned idx;
   1836    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ext); ++idx) {
   1837      if (NULL != (msg = ed25519_cert_extension_check(TRUNNEL_DYNARRAY_GET(&obj->ext, idx))))
   1838        return msg;
   1839    }
   1840  }
   1841  if (TRUNNEL_DYNARRAY_LEN(&obj->ext) != obj->n_extensions)
   1842    return "Length mismatch for ext";
   1843  return NULL;
   1844 }
   1845 
   1846 ssize_t
   1847 ed25519_cert_encoded_len(const ed25519_cert_t *obj)
   1848 {
   1849  ssize_t result = 0;
   1850 
   1851  if (NULL != ed25519_cert_check(obj))
   1852     return -1;
   1853 
   1854 
   1855  /* Length of u8 version IN [1] */
   1856  result += 1;
   1857 
   1858  /* Length of u8 cert_type */
   1859  result += 1;
   1860 
   1861  /* Length of u32 exp_field */
   1862  result += 4;
   1863 
   1864  /* Length of u8 cert_key_type */
   1865  result += 1;
   1866 
   1867  /* Length of u8 certified_key[32] */
   1868  result += 32;
   1869 
   1870  /* Length of u8 n_extensions */
   1871  result += 1;
   1872 
   1873  /* Length of struct ed25519_cert_extension ext[n_extensions] */
   1874  {
   1875 
   1876    unsigned idx;
   1877    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ext); ++idx) {
   1878      result += ed25519_cert_extension_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->ext, idx));
   1879    }
   1880  }
   1881 
   1882  /* Length of u8 signature[64] */
   1883  result += 64;
   1884  return result;
   1885 }
   1886 int
   1887 ed25519_cert_clear_errors(ed25519_cert_t *obj)
   1888 {
   1889  int r = obj->trunnel_error_code_;
   1890  obj->trunnel_error_code_ = 0;
   1891  return r;
   1892 }
   1893 ssize_t
   1894 ed25519_cert_encode(uint8_t *output, const size_t avail, const ed25519_cert_t *obj)
   1895 {
   1896  ssize_t result = 0;
   1897  size_t written = 0;
   1898  uint8_t *ptr = output;
   1899  const char *msg;
   1900 #ifdef TRUNNEL_CHECK_ENCODED_LEN
   1901  const ssize_t encoded_len = ed25519_cert_encoded_len(obj);
   1902 #endif
   1903 
   1904  if (NULL != (msg = ed25519_cert_check(obj)))
   1905    goto check_failed;
   1906 
   1907 #ifdef TRUNNEL_CHECK_ENCODED_LEN
   1908  trunnel_assert(encoded_len >= 0);
   1909 #endif
   1910 
   1911  /* Encode u8 version IN [1] */
   1912  trunnel_assert(written <= avail);
   1913  if (avail - written < 1)
   1914    goto truncated;
   1915  trunnel_set_uint8(ptr, (obj->version));
   1916  written += 1; ptr += 1;
   1917 
   1918  /* Encode u8 cert_type */
   1919  trunnel_assert(written <= avail);
   1920  if (avail - written < 1)
   1921    goto truncated;
   1922  trunnel_set_uint8(ptr, (obj->cert_type));
   1923  written += 1; ptr += 1;
   1924 
   1925  /* Encode u32 exp_field */
   1926  trunnel_assert(written <= avail);
   1927  if (avail - written < 4)
   1928    goto truncated;
   1929  trunnel_set_uint32(ptr, trunnel_htonl(obj->exp_field));
   1930  written += 4; ptr += 4;
   1931 
   1932  /* Encode u8 cert_key_type */
   1933  trunnel_assert(written <= avail);
   1934  if (avail - written < 1)
   1935    goto truncated;
   1936  trunnel_set_uint8(ptr, (obj->cert_key_type));
   1937  written += 1; ptr += 1;
   1938 
   1939  /* Encode u8 certified_key[32] */
   1940  trunnel_assert(written <= avail);
   1941  if (avail - written < 32)
   1942    goto truncated;
   1943  memcpy(ptr, obj->certified_key, 32);
   1944  written += 32; ptr += 32;
   1945 
   1946  /* Encode u8 n_extensions */
   1947  trunnel_assert(written <= avail);
   1948  if (avail - written < 1)
   1949    goto truncated;
   1950  trunnel_set_uint8(ptr, (obj->n_extensions));
   1951  written += 1; ptr += 1;
   1952 
   1953  /* Encode struct ed25519_cert_extension ext[n_extensions] */
   1954  {
   1955 
   1956    unsigned idx;
   1957    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ext); ++idx) {
   1958      trunnel_assert(written <= avail);
   1959      result = ed25519_cert_extension_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->ext, idx));
   1960      if (result < 0)
   1961        goto fail; /* XXXXXXX !*/
   1962      written += result; ptr += result;
   1963    }
   1964  }
   1965 
   1966  /* Encode u8 signature[64] */
   1967  trunnel_assert(written <= avail);
   1968  if (avail - written < 64)
   1969    goto truncated;
   1970  memcpy(ptr, obj->signature, 64);
   1971  written += 64; ptr += 64;
   1972 
   1973 
   1974  trunnel_assert(ptr == output + written);
   1975 #ifdef TRUNNEL_CHECK_ENCODED_LEN
   1976  {
   1977    trunnel_assert(encoded_len >= 0);
   1978    trunnel_assert((size_t)encoded_len == written);
   1979  }
   1980 
   1981 #endif
   1982 
   1983  return written;
   1984 
   1985 truncated:
   1986  result = -2;
   1987  goto fail;
   1988 check_failed:
   1989  (void)msg;
   1990  result = -1;
   1991  goto fail;
   1992 fail:
   1993  trunnel_assert(result < 0);
   1994  return result;
   1995 }
   1996 
   1997 /** As ed25519_cert_parse(), but do not allocate the output object.
   1998 */
   1999 static ssize_t
   2000 ed25519_cert_parse_into(ed25519_cert_t *obj, const uint8_t *input, const size_t len_in)
   2001 {
   2002  const uint8_t *ptr = input;
   2003  size_t remaining = len_in;
   2004  ssize_t result = 0;
   2005  (void)result;
   2006 
   2007  /* Parse u8 version IN [1] */
   2008  CHECK_REMAINING(1, truncated);
   2009  obj->version = (trunnel_get_uint8(ptr));
   2010  remaining -= 1; ptr += 1;
   2011  if (! (obj->version == 1))
   2012    goto fail;
   2013 
   2014  /* Parse u8 cert_type */
   2015  CHECK_REMAINING(1, truncated);
   2016  obj->cert_type = (trunnel_get_uint8(ptr));
   2017  remaining -= 1; ptr += 1;
   2018 
   2019  /* Parse u32 exp_field */
   2020  CHECK_REMAINING(4, truncated);
   2021  obj->exp_field = trunnel_ntohl(trunnel_get_uint32(ptr));
   2022  remaining -= 4; ptr += 4;
   2023 
   2024  /* Parse u8 cert_key_type */
   2025  CHECK_REMAINING(1, truncated);
   2026  obj->cert_key_type = (trunnel_get_uint8(ptr));
   2027  remaining -= 1; ptr += 1;
   2028 
   2029  /* Parse u8 certified_key[32] */
   2030  CHECK_REMAINING(32, truncated);
   2031  memcpy(obj->certified_key, ptr, 32);
   2032  remaining -= 32; ptr += 32;
   2033 
   2034  /* Parse u8 n_extensions */
   2035  CHECK_REMAINING(1, truncated);
   2036  obj->n_extensions = (trunnel_get_uint8(ptr));
   2037  remaining -= 1; ptr += 1;
   2038 
   2039  /* Parse struct ed25519_cert_extension ext[n_extensions] */
   2040  TRUNNEL_DYNARRAY_EXPAND(ed25519_cert_extension_t *, &obj->ext, obj->n_extensions, {});
   2041  {
   2042    ed25519_cert_extension_t * elt;
   2043    unsigned idx;
   2044    for (idx = 0; idx < obj->n_extensions; ++idx) {
   2045      result = ed25519_cert_extension_parse(&elt, ptr, remaining);
   2046      if (result < 0)
   2047        goto relay_fail;
   2048      trunnel_assert((size_t)result <= remaining);
   2049      remaining -= result; ptr += result;
   2050      TRUNNEL_DYNARRAY_ADD(ed25519_cert_extension_t *, &obj->ext, elt, {ed25519_cert_extension_free(elt);});
   2051    }
   2052  }
   2053 
   2054  /* Parse u8 signature[64] */
   2055  CHECK_REMAINING(64, truncated);
   2056  memcpy(obj->signature, ptr, 64);
   2057  remaining -= 64; ptr += 64;
   2058  trunnel_assert(ptr + remaining == input + len_in);
   2059  return len_in - remaining;
   2060 
   2061 truncated:
   2062  return -2;
   2063 relay_fail:
   2064  trunnel_assert(result < 0);
   2065  return result;
   2066 trunnel_alloc_failed:
   2067  return -1;
   2068 fail:
   2069  result = -1;
   2070  return result;
   2071 }
   2072 
   2073 ssize_t
   2074 ed25519_cert_parse(ed25519_cert_t **output, const uint8_t *input, const size_t len_in)
   2075 {
   2076  ssize_t result;
   2077  *output = ed25519_cert_new();
   2078  if (NULL == *output)
   2079    return -1;
   2080  result = ed25519_cert_parse_into(*output, input, len_in);
   2081  if (result < 0) {
   2082    ed25519_cert_free(*output);
   2083    *output = NULL;
   2084  }
   2085  return result;
   2086 }
   2087 extend2_cell_body_t *
   2088 extend2_cell_body_new(void)
   2089 {
   2090  extend2_cell_body_t *val = trunnel_calloc(1, sizeof(extend2_cell_body_t));
   2091  if (NULL == val)
   2092    return NULL;
   2093  return val;
   2094 }
   2095 
   2096 /** Release all storage held inside 'obj', but do not free 'obj'.
   2097 */
   2098 static void
   2099 extend2_cell_body_clear(extend2_cell_body_t *obj)
   2100 {
   2101  (void) obj;
   2102  {
   2103 
   2104    unsigned idx;
   2105    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ls); ++idx) {
   2106      link_specifier_free(TRUNNEL_DYNARRAY_GET(&obj->ls, idx));
   2107    }
   2108  }
   2109  TRUNNEL_DYNARRAY_WIPE(&obj->ls);
   2110  TRUNNEL_DYNARRAY_CLEAR(&obj->ls);
   2111  create2_cell_body_free(obj->create2);
   2112  obj->create2 = NULL;
   2113 }
   2114 
   2115 void
   2116 extend2_cell_body_free(extend2_cell_body_t *obj)
   2117 {
   2118  if (obj == NULL)
   2119    return;
   2120  extend2_cell_body_clear(obj);
   2121  trunnel_memwipe(obj, sizeof(extend2_cell_body_t));
   2122  trunnel_free_(obj);
   2123 }
   2124 
   2125 uint8_t
   2126 extend2_cell_body_get_n_spec(const extend2_cell_body_t *inp)
   2127 {
   2128  return inp->n_spec;
   2129 }
   2130 int
   2131 extend2_cell_body_set_n_spec(extend2_cell_body_t *inp, uint8_t val)
   2132 {
   2133  inp->n_spec = val;
   2134  return 0;
   2135 }
   2136 size_t
   2137 extend2_cell_body_getlen_ls(const extend2_cell_body_t *inp)
   2138 {
   2139  return TRUNNEL_DYNARRAY_LEN(&inp->ls);
   2140 }
   2141 
   2142 struct link_specifier_st *
   2143 extend2_cell_body_get_ls(extend2_cell_body_t *inp, size_t idx)
   2144 {
   2145  return TRUNNEL_DYNARRAY_GET(&inp->ls, idx);
   2146 }
   2147 
   2148 const struct link_specifier_st *
   2149 extend2_cell_body_getconst_ls(const extend2_cell_body_t *inp, size_t idx)
   2150 {
   2151  return extend2_cell_body_get_ls((extend2_cell_body_t*)inp, idx);
   2152 }
   2153 int
   2154 extend2_cell_body_set_ls(extend2_cell_body_t *inp, size_t idx, struct link_specifier_st * elt)
   2155 {
   2156  link_specifier_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->ls, idx);
   2157  if (oldval && oldval != elt)
   2158    link_specifier_free(oldval);
   2159  return extend2_cell_body_set0_ls(inp, idx, elt);
   2160 }
   2161 int
   2162 extend2_cell_body_set0_ls(extend2_cell_body_t *inp, size_t idx, struct link_specifier_st * elt)
   2163 {
   2164  TRUNNEL_DYNARRAY_SET(&inp->ls, idx, elt);
   2165  return 0;
   2166 }
   2167 int
   2168 extend2_cell_body_add_ls(extend2_cell_body_t *inp, struct link_specifier_st * elt)
   2169 {
   2170 #if SIZE_MAX >= UINT8_MAX
   2171  if (inp->ls.n_ == UINT8_MAX)
   2172    goto trunnel_alloc_failed;
   2173 #endif
   2174  TRUNNEL_DYNARRAY_ADD(struct link_specifier_st *, &inp->ls, elt, {});
   2175  return 0;
   2176 trunnel_alloc_failed:
   2177  TRUNNEL_SET_ERROR_CODE(inp);
   2178  return -1;
   2179 }
   2180 
   2181 struct link_specifier_st * *
   2182 extend2_cell_body_getarray_ls(extend2_cell_body_t *inp)
   2183 {
   2184  return inp->ls.elts_;
   2185 }
   2186 const struct link_specifier_st *  const  *
   2187 extend2_cell_body_getconstarray_ls(const extend2_cell_body_t *inp)
   2188 {
   2189  return (const struct link_specifier_st *  const  *)extend2_cell_body_getarray_ls((extend2_cell_body_t*)inp);
   2190 }
   2191 int
   2192 extend2_cell_body_setlen_ls(extend2_cell_body_t *inp, size_t newlen)
   2193 {
   2194  struct link_specifier_st * *newptr;
   2195 #if UINT8_MAX < SIZE_MAX
   2196  if (newlen > UINT8_MAX)
   2197    goto trunnel_alloc_failed;
   2198 #endif
   2199  newptr = trunnel_dynarray_setlen(&inp->ls.allocated_,
   2200                 &inp->ls.n_, inp->ls.elts_, newlen,
   2201                 sizeof(inp->ls.elts_[0]), (trunnel_free_fn_t) link_specifier_free,
   2202                 &inp->trunnel_error_code_);
   2203  if (newlen != 0 && newptr == NULL)
   2204    goto trunnel_alloc_failed;
   2205  inp->ls.elts_ = newptr;
   2206  return 0;
   2207 trunnel_alloc_failed:
   2208  TRUNNEL_SET_ERROR_CODE(inp);
   2209  return -1;
   2210 }
   2211 struct create2_cell_body_st *
   2212 extend2_cell_body_get_create2(extend2_cell_body_t *inp)
   2213 {
   2214  return inp->create2;
   2215 }
   2216 const struct create2_cell_body_st *
   2217 extend2_cell_body_getconst_create2(const extend2_cell_body_t *inp)
   2218 {
   2219  return extend2_cell_body_get_create2((extend2_cell_body_t*) inp);
   2220 }
   2221 int
   2222 extend2_cell_body_set_create2(extend2_cell_body_t *inp, struct create2_cell_body_st *val)
   2223 {
   2224  if (inp->create2 && inp->create2 != val)
   2225    create2_cell_body_free(inp->create2);
   2226  return extend2_cell_body_set0_create2(inp, val);
   2227 }
   2228 int
   2229 extend2_cell_body_set0_create2(extend2_cell_body_t *inp, struct create2_cell_body_st *val)
   2230 {
   2231  inp->create2 = val;
   2232  return 0;
   2233 }
   2234 const char *
   2235 extend2_cell_body_check(const extend2_cell_body_t *obj)
   2236 {
   2237  if (obj == NULL)
   2238    return "Object was NULL";
   2239  if (obj->trunnel_error_code_)
   2240    return "A set function failed on this object";
   2241  {
   2242    const char *msg;
   2243 
   2244    unsigned idx;
   2245    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ls); ++idx) {
   2246      if (NULL != (msg = link_specifier_check(TRUNNEL_DYNARRAY_GET(&obj->ls, idx))))
   2247        return msg;
   2248    }
   2249  }
   2250  if (TRUNNEL_DYNARRAY_LEN(&obj->ls) != obj->n_spec)
   2251    return "Length mismatch for ls";
   2252  {
   2253    const char *msg;
   2254    if (NULL != (msg = create2_cell_body_check(obj->create2)))
   2255      return msg;
   2256  }
   2257  return NULL;
   2258 }
   2259 
   2260 ssize_t
   2261 extend2_cell_body_encoded_len(const extend2_cell_body_t *obj)
   2262 {
   2263  ssize_t result = 0;
   2264 
   2265  if (NULL != extend2_cell_body_check(obj))
   2266     return -1;
   2267 
   2268 
   2269  /* Length of u8 n_spec */
   2270  result += 1;
   2271 
   2272  /* Length of struct link_specifier ls[n_spec] */
   2273  {
   2274 
   2275    unsigned idx;
   2276    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ls); ++idx) {
   2277      result += link_specifier_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->ls, idx));
   2278    }
   2279  }
   2280 
   2281  /* Length of struct create2_cell_body create2 */
   2282  result += create2_cell_body_encoded_len(obj->create2);
   2283  return result;
   2284 }
   2285 int
   2286 extend2_cell_body_clear_errors(extend2_cell_body_t *obj)
   2287 {
   2288  int r = obj->trunnel_error_code_;
   2289  obj->trunnel_error_code_ = 0;
   2290  return r;
   2291 }
   2292 ssize_t
   2293 extend2_cell_body_encode(uint8_t *output, const size_t avail, const extend2_cell_body_t *obj)
   2294 {
   2295  ssize_t result = 0;
   2296  size_t written = 0;
   2297  uint8_t *ptr = output;
   2298  const char *msg;
   2299 #ifdef TRUNNEL_CHECK_ENCODED_LEN
   2300  const ssize_t encoded_len = extend2_cell_body_encoded_len(obj);
   2301 #endif
   2302 
   2303  if (NULL != (msg = extend2_cell_body_check(obj)))
   2304    goto check_failed;
   2305 
   2306 #ifdef TRUNNEL_CHECK_ENCODED_LEN
   2307  trunnel_assert(encoded_len >= 0);
   2308 #endif
   2309 
   2310  /* Encode u8 n_spec */
   2311  trunnel_assert(written <= avail);
   2312  if (avail - written < 1)
   2313    goto truncated;
   2314  trunnel_set_uint8(ptr, (obj->n_spec));
   2315  written += 1; ptr += 1;
   2316 
   2317  /* Encode struct link_specifier ls[n_spec] */
   2318  {
   2319 
   2320    unsigned idx;
   2321    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->ls); ++idx) {
   2322      trunnel_assert(written <= avail);
   2323      result = link_specifier_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->ls, idx));
   2324      if (result < 0)
   2325        goto fail; /* XXXXXXX !*/
   2326      written += result; ptr += result;
   2327    }
   2328  }
   2329 
   2330  /* Encode struct create2_cell_body create2 */
   2331  trunnel_assert(written <= avail);
   2332  result = create2_cell_body_encode(ptr, avail - written, obj->create2);
   2333  if (result < 0)
   2334    goto fail; /* XXXXXXX !*/
   2335  written += result; ptr += result;
   2336 
   2337 
   2338  trunnel_assert(ptr == output + written);
   2339 #ifdef TRUNNEL_CHECK_ENCODED_LEN
   2340  {
   2341    trunnel_assert(encoded_len >= 0);
   2342    trunnel_assert((size_t)encoded_len == written);
   2343  }
   2344 
   2345 #endif
   2346 
   2347  return written;
   2348 
   2349 truncated:
   2350  result = -2;
   2351  goto fail;
   2352 check_failed:
   2353  (void)msg;
   2354  result = -1;
   2355  goto fail;
   2356 fail:
   2357  trunnel_assert(result < 0);
   2358  return result;
   2359 }
   2360 
   2361 /** As extend2_cell_body_parse(), but do not allocate the output
   2362 * object.
   2363 */
   2364 static ssize_t
   2365 extend2_cell_body_parse_into(extend2_cell_body_t *obj, const uint8_t *input, const size_t len_in)
   2366 {
   2367  const uint8_t *ptr = input;
   2368  size_t remaining = len_in;
   2369  ssize_t result = 0;
   2370  (void)result;
   2371 
   2372  /* Parse u8 n_spec */
   2373  CHECK_REMAINING(1, truncated);
   2374  obj->n_spec = (trunnel_get_uint8(ptr));
   2375  remaining -= 1; ptr += 1;
   2376 
   2377  /* Parse struct link_specifier ls[n_spec] */
   2378  TRUNNEL_DYNARRAY_EXPAND(link_specifier_t *, &obj->ls, obj->n_spec, {});
   2379  {
   2380    link_specifier_t * elt;
   2381    unsigned idx;
   2382    for (idx = 0; idx < obj->n_spec; ++idx) {
   2383      result = link_specifier_parse(&elt, ptr, remaining);
   2384      if (result < 0)
   2385        goto relay_fail;
   2386      trunnel_assert((size_t)result <= remaining);
   2387      remaining -= result; ptr += result;
   2388      TRUNNEL_DYNARRAY_ADD(link_specifier_t *, &obj->ls, elt, {link_specifier_free(elt);});
   2389    }
   2390  }
   2391 
   2392  /* Parse struct create2_cell_body create2 */
   2393  result = create2_cell_body_parse(&obj->create2, ptr, remaining);
   2394  if (result < 0)
   2395    goto relay_fail;
   2396  trunnel_assert((size_t)result <= remaining);
   2397  remaining -= result; ptr += result;
   2398  trunnel_assert(ptr + remaining == input + len_in);
   2399  return len_in - remaining;
   2400 
   2401 truncated:
   2402  return -2;
   2403 relay_fail:
   2404  trunnel_assert(result < 0);
   2405  return result;
   2406 trunnel_alloc_failed:
   2407  return -1;
   2408 }
   2409 
   2410 ssize_t
   2411 extend2_cell_body_parse(extend2_cell_body_t **output, const uint8_t *input, const size_t len_in)
   2412 {
   2413  ssize_t result;
   2414  *output = extend2_cell_body_new();
   2415  if (NULL == *output)
   2416    return -1;
   2417  result = extend2_cell_body_parse_into(*output, input, len_in);
   2418  if (result < 0) {
   2419    extend2_cell_body_free(*output);
   2420    *output = NULL;
   2421  }
   2422  return result;
   2423 }
   2424 link_specifier_list_t *
   2425 link_specifier_list_new(void)
   2426 {
   2427  link_specifier_list_t *val = trunnel_calloc(1, sizeof(link_specifier_list_t));
   2428  if (NULL == val)
   2429    return NULL;
   2430  return val;
   2431 }
   2432 
   2433 /** Release all storage held inside 'obj', but do not free 'obj'.
   2434 */
   2435 static void
   2436 link_specifier_list_clear(link_specifier_list_t *obj)
   2437 {
   2438  (void) obj;
   2439  {
   2440 
   2441    unsigned idx;
   2442    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->spec); ++idx) {
   2443      link_specifier_free(TRUNNEL_DYNARRAY_GET(&obj->spec, idx));
   2444    }
   2445  }
   2446  TRUNNEL_DYNARRAY_WIPE(&obj->spec);
   2447  TRUNNEL_DYNARRAY_CLEAR(&obj->spec);
   2448 }
   2449 
   2450 void
   2451 link_specifier_list_free(link_specifier_list_t *obj)
   2452 {
   2453  if (obj == NULL)
   2454    return;
   2455  link_specifier_list_clear(obj);
   2456  trunnel_memwipe(obj, sizeof(link_specifier_list_t));
   2457  trunnel_free_(obj);
   2458 }
   2459 
   2460 uint8_t
   2461 link_specifier_list_get_n_spec(const link_specifier_list_t *inp)
   2462 {
   2463  return inp->n_spec;
   2464 }
   2465 int
   2466 link_specifier_list_set_n_spec(link_specifier_list_t *inp, uint8_t val)
   2467 {
   2468  inp->n_spec = val;
   2469  return 0;
   2470 }
   2471 size_t
   2472 link_specifier_list_getlen_spec(const link_specifier_list_t *inp)
   2473 {
   2474  return TRUNNEL_DYNARRAY_LEN(&inp->spec);
   2475 }
   2476 
   2477 struct link_specifier_st *
   2478 link_specifier_list_get_spec(link_specifier_list_t *inp, size_t idx)
   2479 {
   2480  return TRUNNEL_DYNARRAY_GET(&inp->spec, idx);
   2481 }
   2482 
   2483 const struct link_specifier_st *
   2484 link_specifier_list_getconst_spec(const link_specifier_list_t *inp, size_t idx)
   2485 {
   2486  return link_specifier_list_get_spec((link_specifier_list_t*)inp, idx);
   2487 }
   2488 int
   2489 link_specifier_list_set_spec(link_specifier_list_t *inp, size_t idx, struct link_specifier_st * elt)
   2490 {
   2491  link_specifier_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->spec, idx);
   2492  if (oldval && oldval != elt)
   2493    link_specifier_free(oldval);
   2494  return link_specifier_list_set0_spec(inp, idx, elt);
   2495 }
   2496 int
   2497 link_specifier_list_set0_spec(link_specifier_list_t *inp, size_t idx, struct link_specifier_st * elt)
   2498 {
   2499  TRUNNEL_DYNARRAY_SET(&inp->spec, idx, elt);
   2500  return 0;
   2501 }
   2502 int
   2503 link_specifier_list_add_spec(link_specifier_list_t *inp, struct link_specifier_st * elt)
   2504 {
   2505 #if SIZE_MAX >= UINT8_MAX
   2506  if (inp->spec.n_ == UINT8_MAX)
   2507    goto trunnel_alloc_failed;
   2508 #endif
   2509  TRUNNEL_DYNARRAY_ADD(struct link_specifier_st *, &inp->spec, elt, {});
   2510  return 0;
   2511 trunnel_alloc_failed:
   2512  TRUNNEL_SET_ERROR_CODE(inp);
   2513  return -1;
   2514 }
   2515 
   2516 struct link_specifier_st * *
   2517 link_specifier_list_getarray_spec(link_specifier_list_t *inp)
   2518 {
   2519  return inp->spec.elts_;
   2520 }
   2521 const struct link_specifier_st *  const  *
   2522 link_specifier_list_getconstarray_spec(const link_specifier_list_t *inp)
   2523 {
   2524  return (const struct link_specifier_st *  const  *)link_specifier_list_getarray_spec((link_specifier_list_t*)inp);
   2525 }
   2526 int
   2527 link_specifier_list_setlen_spec(link_specifier_list_t *inp, size_t newlen)
   2528 {
   2529  struct link_specifier_st * *newptr;
   2530 #if UINT8_MAX < SIZE_MAX
   2531  if (newlen > UINT8_MAX)
   2532    goto trunnel_alloc_failed;
   2533 #endif
   2534  newptr = trunnel_dynarray_setlen(&inp->spec.allocated_,
   2535                 &inp->spec.n_, inp->spec.elts_, newlen,
   2536                 sizeof(inp->spec.elts_[0]), (trunnel_free_fn_t) link_specifier_free,
   2537                 &inp->trunnel_error_code_);
   2538  if (newlen != 0 && newptr == NULL)
   2539    goto trunnel_alloc_failed;
   2540  inp->spec.elts_ = newptr;
   2541  return 0;
   2542 trunnel_alloc_failed:
   2543  TRUNNEL_SET_ERROR_CODE(inp);
   2544  return -1;
   2545 }
   2546 const char *
   2547 link_specifier_list_check(const link_specifier_list_t *obj)
   2548 {
   2549  if (obj == NULL)
   2550    return "Object was NULL";
   2551  if (obj->trunnel_error_code_)
   2552    return "A set function failed on this object";
   2553  {
   2554    const char *msg;
   2555 
   2556    unsigned idx;
   2557    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->spec); ++idx) {
   2558      if (NULL != (msg = link_specifier_check(TRUNNEL_DYNARRAY_GET(&obj->spec, idx))))
   2559        return msg;
   2560    }
   2561  }
   2562  if (TRUNNEL_DYNARRAY_LEN(&obj->spec) != obj->n_spec)
   2563    return "Length mismatch for spec";
   2564  return NULL;
   2565 }
   2566 
   2567 ssize_t
   2568 link_specifier_list_encoded_len(const link_specifier_list_t *obj)
   2569 {
   2570  ssize_t result = 0;
   2571 
   2572  if (NULL != link_specifier_list_check(obj))
   2573     return -1;
   2574 
   2575 
   2576  /* Length of u8 n_spec */
   2577  result += 1;
   2578 
   2579  /* Length of struct link_specifier spec[n_spec] */
   2580  {
   2581 
   2582    unsigned idx;
   2583    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->spec); ++idx) {
   2584      result += link_specifier_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->spec, idx));
   2585    }
   2586  }
   2587  return result;
   2588 }
   2589 int
   2590 link_specifier_list_clear_errors(link_specifier_list_t *obj)
   2591 {
   2592  int r = obj->trunnel_error_code_;
   2593  obj->trunnel_error_code_ = 0;
   2594  return r;
   2595 }
   2596 ssize_t
   2597 link_specifier_list_encode(uint8_t *output, const size_t avail, const link_specifier_list_t *obj)
   2598 {
   2599  ssize_t result = 0;
   2600  size_t written = 0;
   2601  uint8_t *ptr = output;
   2602  const char *msg;
   2603 #ifdef TRUNNEL_CHECK_ENCODED_LEN
   2604  const ssize_t encoded_len = link_specifier_list_encoded_len(obj);
   2605 #endif
   2606 
   2607  if (NULL != (msg = link_specifier_list_check(obj)))
   2608    goto check_failed;
   2609 
   2610 #ifdef TRUNNEL_CHECK_ENCODED_LEN
   2611  trunnel_assert(encoded_len >= 0);
   2612 #endif
   2613 
   2614  /* Encode u8 n_spec */
   2615  trunnel_assert(written <= avail);
   2616  if (avail - written < 1)
   2617    goto truncated;
   2618  trunnel_set_uint8(ptr, (obj->n_spec));
   2619  written += 1; ptr += 1;
   2620 
   2621  /* Encode struct link_specifier spec[n_spec] */
   2622  {
   2623 
   2624    unsigned idx;
   2625    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->spec); ++idx) {
   2626      trunnel_assert(written <= avail);
   2627      result = link_specifier_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->spec, idx));
   2628      if (result < 0)
   2629        goto fail; /* XXXXXXX !*/
   2630      written += result; ptr += result;
   2631    }
   2632  }
   2633 
   2634 
   2635  trunnel_assert(ptr == output + written);
   2636 #ifdef TRUNNEL_CHECK_ENCODED_LEN
   2637  {
   2638    trunnel_assert(encoded_len >= 0);
   2639    trunnel_assert((size_t)encoded_len == written);
   2640  }
   2641 
   2642 #endif
   2643 
   2644  return written;
   2645 
   2646 truncated:
   2647  result = -2;
   2648  goto fail;
   2649 check_failed:
   2650  (void)msg;
   2651  result = -1;
   2652  goto fail;
   2653 fail:
   2654  trunnel_assert(result < 0);
   2655  return result;
   2656 }
   2657 
   2658 /** As link_specifier_list_parse(), but do not allocate the output
   2659 * object.
   2660 */
   2661 static ssize_t
   2662 link_specifier_list_parse_into(link_specifier_list_t *obj, const uint8_t *input, const size_t len_in)
   2663 {
   2664  const uint8_t *ptr = input;
   2665  size_t remaining = len_in;
   2666  ssize_t result = 0;
   2667  (void)result;
   2668 
   2669  /* Parse u8 n_spec */
   2670  CHECK_REMAINING(1, truncated);
   2671  obj->n_spec = (trunnel_get_uint8(ptr));
   2672  remaining -= 1; ptr += 1;
   2673 
   2674  /* Parse struct link_specifier spec[n_spec] */
   2675  TRUNNEL_DYNARRAY_EXPAND(link_specifier_t *, &obj->spec, obj->n_spec, {});
   2676  {
   2677    link_specifier_t * elt;
   2678    unsigned idx;
   2679    for (idx = 0; idx < obj->n_spec; ++idx) {
   2680      result = link_specifier_parse(&elt, ptr, remaining);
   2681      if (result < 0)
   2682        goto relay_fail;
   2683      trunnel_assert((size_t)result <= remaining);
   2684      remaining -= result; ptr += result;
   2685      TRUNNEL_DYNARRAY_ADD(link_specifier_t *, &obj->spec, elt, {link_specifier_free(elt);});
   2686    }
   2687  }
   2688  trunnel_assert(ptr + remaining == input + len_in);
   2689  return len_in - remaining;
   2690 
   2691 truncated:
   2692  return -2;
   2693 relay_fail:
   2694  trunnel_assert(result < 0);
   2695  return result;
   2696 trunnel_alloc_failed:
   2697  return -1;
   2698 }
   2699 
   2700 ssize_t
   2701 link_specifier_list_parse(link_specifier_list_t **output, const uint8_t *input, const size_t len_in)
   2702 {
   2703  ssize_t result;
   2704  *output = link_specifier_list_new();
   2705  if (NULL == *output)
   2706    return -1;
   2707  result = link_specifier_list_parse_into(*output, input, len_in);
   2708  if (result < 0) {
   2709    link_specifier_list_free(*output);
   2710    *output = NULL;
   2711  }
   2712  return result;
   2713 }