tor

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

sendme_cell.c (9159B)


      1 /* sendme_cell.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 "sendme_cell.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 sendmecell_deadcode_dummy__ = 0;
     19 #define OR_DEADCODE_DUMMY || sendmecell_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 sendme_cell_t *
     32 sendme_cell_new(void)
     33 {
     34  sendme_cell_t *val = trunnel_calloc(1, sizeof(sendme_cell_t));
     35  if (NULL == val)
     36    return NULL;
     37  val->data_len = 16;
     38  return val;
     39 }
     40 
     41 /** Release all storage held inside 'obj', but do not free 'obj'.
     42 */
     43 static void
     44 sendme_cell_clear(sendme_cell_t *obj)
     45 {
     46  (void) obj;
     47  TRUNNEL_DYNARRAY_WIPE(&obj->data_v1_digest);
     48  TRUNNEL_DYNARRAY_CLEAR(&obj->data_v1_digest);
     49 }
     50 
     51 void
     52 sendme_cell_free(sendme_cell_t *obj)
     53 {
     54  if (obj == NULL)
     55    return;
     56  sendme_cell_clear(obj);
     57  trunnel_memwipe(obj, sizeof(sendme_cell_t));
     58  trunnel_free_(obj);
     59 }
     60 
     61 uint8_t
     62 sendme_cell_get_version(const sendme_cell_t *inp)
     63 {
     64  return inp->version;
     65 }
     66 int
     67 sendme_cell_set_version(sendme_cell_t *inp, uint8_t val)
     68 {
     69  if (! ((val == 0 || val == 1))) {
     70     TRUNNEL_SET_ERROR_CODE(inp);
     71     return -1;
     72  }
     73  inp->version = val;
     74  return 0;
     75 }
     76 uint16_t
     77 sendme_cell_get_data_len(const sendme_cell_t *inp)
     78 {
     79  return inp->data_len;
     80 }
     81 int
     82 sendme_cell_set_data_len(sendme_cell_t *inp, uint16_t val)
     83 {
     84  if (! ((val == 16 || val == 20))) {
     85     TRUNNEL_SET_ERROR_CODE(inp);
     86     return -1;
     87  }
     88  inp->data_len = val;
     89  return 0;
     90 }
     91 size_t
     92 sendme_cell_getlen_data_v1_digest(const sendme_cell_t *inp)
     93 {
     94  return TRUNNEL_DYNARRAY_LEN(&inp->data_v1_digest);
     95 }
     96 
     97 uint8_t
     98 sendme_cell_get_data_v1_digest(sendme_cell_t *inp, size_t idx)
     99 {
    100  return TRUNNEL_DYNARRAY_GET(&inp->data_v1_digest, idx);
    101 }
    102 
    103 uint8_t
    104 sendme_cell_getconst_data_v1_digest(const sendme_cell_t *inp, size_t idx)
    105 {
    106  return sendme_cell_get_data_v1_digest((sendme_cell_t*)inp, idx);
    107 }
    108 int
    109 sendme_cell_set_data_v1_digest(sendme_cell_t *inp, size_t idx, uint8_t elt)
    110 {
    111  TRUNNEL_DYNARRAY_SET(&inp->data_v1_digest, idx, elt);
    112  return 0;
    113 }
    114 int
    115 sendme_cell_add_data_v1_digest(sendme_cell_t *inp, uint8_t elt)
    116 {
    117  TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->data_v1_digest, elt, {});
    118  return 0;
    119 trunnel_alloc_failed:
    120  TRUNNEL_SET_ERROR_CODE(inp);
    121  return -1;
    122 }
    123 
    124 uint8_t *
    125 sendme_cell_getarray_data_v1_digest(sendme_cell_t *inp)
    126 {
    127  return inp->data_v1_digest.elts_;
    128 }
    129 const uint8_t  *
    130 sendme_cell_getconstarray_data_v1_digest(const sendme_cell_t *inp)
    131 {
    132  return (const uint8_t  *)sendme_cell_getarray_data_v1_digest((sendme_cell_t*)inp);
    133 }
    134 int
    135 sendme_cell_setlen_data_v1_digest(sendme_cell_t *inp, size_t newlen)
    136 {
    137  uint8_t *newptr;
    138  newptr = trunnel_dynarray_setlen(&inp->data_v1_digest.allocated_,
    139                 &inp->data_v1_digest.n_, inp->data_v1_digest.elts_, newlen,
    140                 sizeof(inp->data_v1_digest.elts_[0]), (trunnel_free_fn_t) NULL,
    141                 &inp->trunnel_error_code_);
    142  if (newlen != 0 && newptr == NULL)
    143    goto trunnel_alloc_failed;
    144  inp->data_v1_digest.elts_ = newptr;
    145  return 0;
    146 trunnel_alloc_failed:
    147  TRUNNEL_SET_ERROR_CODE(inp);
    148  return -1;
    149 }
    150 const char *
    151 sendme_cell_check(const sendme_cell_t *obj)
    152 {
    153  if (obj == NULL)
    154    return "Object was NULL";
    155  if (obj->trunnel_error_code_)
    156    return "A set function failed on this object";
    157  if (! (obj->version == 0 || obj->version == 1))
    158    return "Integer out of bounds";
    159  if (! (obj->data_len == 16 || obj->data_len == 20))
    160    return "Integer out of bounds";
    161  switch (obj->version) {
    162 
    163    case 0:
    164      break;
    165 
    166    case 1:
    167      break;
    168 
    169    default:
    170        return "Bad tag for union";
    171      break;
    172  }
    173  return NULL;
    174 }
    175 
    176 ssize_t
    177 sendme_cell_encoded_len(const sendme_cell_t *obj)
    178 {
    179  ssize_t result = 0;
    180 
    181  if (NULL != sendme_cell_check(obj))
    182     return -1;
    183 
    184 
    185  /* Length of u8 version IN [0, 1] */
    186  result += 1;
    187 
    188  /* Length of u16 data_len IN [16, 20] */
    189  result += 2;
    190  switch (obj->version) {
    191 
    192    case 0:
    193      break;
    194 
    195    case 1:
    196 
    197      /* Length of u8 data_v1_digest[] */
    198      result += TRUNNEL_DYNARRAY_LEN(&obj->data_v1_digest);
    199      break;
    200 
    201    default:
    202      trunnel_assert(0);
    203      break;
    204  }
    205  return result;
    206 }
    207 int
    208 sendme_cell_clear_errors(sendme_cell_t *obj)
    209 {
    210  int r = obj->trunnel_error_code_;
    211  obj->trunnel_error_code_ = 0;
    212  return r;
    213 }
    214 ssize_t
    215 sendme_cell_encode(uint8_t *output, const size_t avail, const sendme_cell_t *obj)
    216 {
    217  ssize_t result = 0;
    218  size_t written = 0;
    219  uint8_t *ptr = output;
    220  const char *msg;
    221 #ifdef TRUNNEL_CHECK_ENCODED_LEN
    222  const ssize_t encoded_len = sendme_cell_encoded_len(obj);
    223 #endif
    224 
    225  uint8_t *backptr_data_len = NULL;
    226 
    227  if (NULL != (msg = sendme_cell_check(obj)))
    228    goto check_failed;
    229 
    230 #ifdef TRUNNEL_CHECK_ENCODED_LEN
    231  trunnel_assert(encoded_len >= 0);
    232 #endif
    233 
    234  /* Encode u8 version IN [0, 1] */
    235  trunnel_assert(written <= avail);
    236  if (avail - written < 1)
    237    goto truncated;
    238  trunnel_set_uint8(ptr, (obj->version));
    239  written += 1; ptr += 1;
    240 
    241  /* Encode u16 data_len IN [16, 20] */
    242  backptr_data_len = ptr;
    243  trunnel_assert(written <= avail);
    244  if (avail - written < 2)
    245    goto truncated;
    246  trunnel_set_uint16(ptr, trunnel_htons(obj->data_len));
    247  written += 2; ptr += 2;
    248  {
    249    size_t written_before_union = written;
    250 
    251    /* Encode union data[version] */
    252    trunnel_assert(written <= avail);
    253    switch (obj->version) {
    254 
    255      case 0:
    256        break;
    257 
    258      case 1:
    259 
    260        /* Encode u8 data_v1_digest[] */
    261        {
    262          size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->data_v1_digest);
    263          trunnel_assert(written <= avail);
    264          if (avail - written < elt_len)
    265            goto truncated;
    266          if (elt_len)
    267            memcpy(ptr, obj->data_v1_digest.elts_, elt_len);
    268          written += elt_len; ptr += elt_len;
    269        }
    270        break;
    271 
    272      default:
    273        trunnel_assert(0);
    274        break;
    275    }
    276    /* Write the length field back to data_len */
    277    trunnel_assert(written >= written_before_union);
    278 #if UINT16_MAX < SIZE_MAX
    279    if (written - written_before_union > UINT16_MAX)
    280      goto check_failed;
    281 #endif
    282    trunnel_set_uint16(backptr_data_len, trunnel_htons(written - written_before_union));
    283  }
    284 
    285 
    286  trunnel_assert(ptr == output + written);
    287 #ifdef TRUNNEL_CHECK_ENCODED_LEN
    288  {
    289    trunnel_assert(encoded_len >= 0);
    290    trunnel_assert((size_t)encoded_len == written);
    291  }
    292 
    293 #endif
    294 
    295  return written;
    296 
    297 truncated:
    298  result = -2;
    299  goto fail;
    300 check_failed:
    301  (void)msg;
    302  result = -1;
    303  goto fail;
    304 fail:
    305  trunnel_assert(result < 0);
    306  return result;
    307 }
    308 
    309 /** As sendme_cell_parse(), but do not allocate the output object.
    310 */
    311 static ssize_t
    312 sendme_cell_parse_into(sendme_cell_t *obj, const uint8_t *input, const size_t len_in)
    313 {
    314  const uint8_t *ptr = input;
    315  size_t remaining = len_in;
    316  ssize_t result = 0;
    317  (void)result;
    318 
    319  /* Parse u8 version IN [0, 1] */
    320  CHECK_REMAINING(1, truncated);
    321  obj->version = (trunnel_get_uint8(ptr));
    322  remaining -= 1; ptr += 1;
    323  if (! (obj->version == 0 || obj->version == 1))
    324    goto fail;
    325 
    326  /* Parse u16 data_len IN [16, 20] */
    327  CHECK_REMAINING(2, truncated);
    328  obj->data_len = trunnel_ntohs(trunnel_get_uint16(ptr));
    329  remaining -= 2; ptr += 2;
    330  if (! (obj->data_len == 16 || obj->data_len == 20))
    331    goto fail;
    332  {
    333    size_t remaining_after;
    334    CHECK_REMAINING(obj->data_len, truncated);
    335    remaining_after = remaining - obj->data_len;
    336    remaining = obj->data_len;
    337 
    338    /* Parse union data[version] */
    339    switch (obj->version) {
    340 
    341      case 0:
    342        /* Skip to end of union */
    343        ptr += remaining; remaining = 0;
    344        break;
    345 
    346      case 1:
    347 
    348        /* Parse u8 data_v1_digest[] */
    349        TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->data_v1_digest, remaining, {});
    350        obj->data_v1_digest.n_ = remaining;
    351        if (remaining)
    352          memcpy(obj->data_v1_digest.elts_, ptr, remaining);
    353        ptr += remaining; remaining -= remaining;
    354        break;
    355 
    356      default:
    357        goto fail;
    358        break;
    359    }
    360    if (remaining != 0)
    361      goto fail;
    362    remaining = remaining_after;
    363  }
    364  trunnel_assert(ptr + remaining == input + len_in);
    365  return len_in - remaining;
    366 
    367 truncated:
    368  return -2;
    369 trunnel_alloc_failed:
    370  return -1;
    371 fail:
    372  result = -1;
    373  return result;
    374 }
    375 
    376 ssize_t
    377 sendme_cell_parse(sendme_cell_t **output, const uint8_t *input, const size_t len_in)
    378 {
    379  ssize_t result;
    380  *output = sendme_cell_new();
    381  if (NULL == *output)
    382    return -1;
    383  result = sendme_cell_parse_into(*output, input, len_in);
    384  if (result < 0) {
    385    sendme_cell_free(*output);
    386    *output = NULL;
    387  }
    388  return result;
    389 }