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 }