1 /* 2 * Copyright (c) 2019-2022 Yubico AB. All rights reserved. 3 * Use of this source code is governed by a BSD-style 4 * license that can be found in the LICENSE file. 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8 #include <assert.h> 9 #include <cbor.h> 10 #include <errno.h> 11 #include <stddef.h> 12 #include <stdint.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 #include "mutator_aux.h" 18 19 int fido_nfc_rx(fido_dev_t *, uint8_t, unsigned char *, size_t, int); 20 int fido_nfc_tx(fido_dev_t *, uint8_t, const unsigned char *, size_t); 21 size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t); 22 23 extern int prng_up; 24 static const uint8_t *wire_data_ptr = NULL; 25 static size_t wire_data_len = 0; 26 27 void 28 consume(const void *body, size_t len) 29 { 30 const volatile uint8_t *ptr = body; 31 volatile uint8_t x = 0; 32 33 #ifdef WITH_MSAN 34 __msan_check_mem_is_initialized(body, len); 35 #endif 36 37 while (len--) 38 x ^= *ptr++; 39 40 (void)x; 41 } 42 43 void 44 consume_str(const char *str) 45 { 46 if (str != NULL) 47 consume(str, strlen(str) + 1); 48 } 49 50 int 51 unpack_int(cbor_item_t *item, int *v) 52 { 53 if (cbor_is_int(item) == false || 54 cbor_int_get_width(item) != CBOR_INT_64) 55 return -1; 56 57 if (cbor_isa_uint(item)) 58 *v = (int)cbor_get_uint64(item); 59 else 60 *v = (int)(-cbor_get_uint64(item) - 1); 61 62 return 0; 63 } 64 65 int 66 unpack_string(cbor_item_t *item, char *v) 67 { 68 size_t len; 69 70 if (cbor_isa_bytestring(item) == false || 71 (len = cbor_bytestring_length(item)) >= MAXSTR) 72 return -1; 73 74 memcpy(v, cbor_bytestring_handle(item), len); 75 v[len] = '\0'; 76 77 return 0; 78 } 79 80 int 81 unpack_byte(cbor_item_t *item, uint8_t *v) 82 { 83 if (cbor_isa_uint(item) == false || 84 cbor_int_get_width(item) != CBOR_INT_8) 85 return -1; 86 87 *v = cbor_get_uint8(item); 88 89 return 0; 90 } 91 92 int 93 unpack_blob(cbor_item_t *item, struct blob *v) 94 { 95 if (cbor_isa_bytestring(item) == false || 96 (v->len = cbor_bytestring_length(item)) > sizeof(v->body)) 97 return -1; 98 99 memcpy(v->body, cbor_bytestring_handle(item), v->len); 100 101 return 0; 102 } 103 104 cbor_item_t * 105 pack_int(int v) NO_MSAN 106 { 107 if (v < 0) 108 return cbor_build_negint64((uint64_t)(-(int64_t)v - 1)); 109 else 110 return cbor_build_uint64((uint64_t)v); 111 } 112 113 cbor_item_t * 114 pack_string(const char *v) NO_MSAN 115 { 116 if (strlen(v) >= MAXSTR) 117 return NULL; 118 119 return cbor_build_bytestring((const unsigned char *)v, strlen(v)); 120 } 121 122 cbor_item_t * 123 pack_byte(uint8_t v) NO_MSAN 124 { 125 return cbor_build_uint8(v); 126 } 127 128 cbor_item_t * 129 pack_blob(const struct blob *v) NO_MSAN 130 { 131 return cbor_build_bytestring(v->body, v->len); 132 } 133 134 void 135 mutate_byte(uint8_t *b) 136 { 137 LLVMFuzzerMutate(b, sizeof(*b), sizeof(*b)); 138 } 139 140 void 141 mutate_int(int *i) 142 { 143 LLVMFuzzerMutate((uint8_t *)i, sizeof(*i), sizeof(*i)); 144 } 145 146 void 147 mutate_blob(struct blob *blob) 148 { 149 blob->len = LLVMFuzzerMutate((uint8_t *)blob->body, blob->len, 150 sizeof(blob->body)); 151 } 152 153 void 154 mutate_string(char *s) 155 { 156 size_t n; 157 158 n = LLVMFuzzerMutate((uint8_t *)s, strlen(s), MAXSTR - 1); 159 s[n] = '\0'; 160 } 161 162 static int 163 buf_read(unsigned char *ptr, size_t len, int ms) 164 { 165 size_t n; 166 167 (void)ms; 168 169 if (prng_up && uniform_random(400) < 1) { 170 errno = EIO; 171 return -1; 172 } 173 174 if (wire_data_len < len) 175 n = wire_data_len; 176 else 177 n = len; 178 179 memcpy(ptr, wire_data_ptr, n); 180 181 wire_data_ptr += n; 182 wire_data_len -= n; 183 184 return (int)n; 185 } 186 187 static int 188 buf_write(const unsigned char *ptr, size_t len) 189 { 190 consume(ptr, len); 191 192 if (prng_up && uniform_random(400) < 1) { 193 errno = EIO; 194 return -1; 195 } 196 197 return (int)len; 198 } 199 200 static void * 201 hid_open(const char *path) 202 { 203 (void)path; 204 205 return (void *)HID_DEV_HANDLE; 206 } 207 208 static void 209 hid_close(void *handle) 210 { 211 assert(handle == (void *)HID_DEV_HANDLE); 212 } 213 214 static int 215 hid_read(void *handle, unsigned char *ptr, size_t len, int ms) 216 { 217 assert(handle == (void *)HID_DEV_HANDLE); 218 assert(len >= CTAP_MIN_REPORT_LEN && len <= CTAP_MAX_REPORT_LEN); 219 220 return buf_read(ptr, len, ms); 221 } 222 223 static int 224 hid_write(void *handle, const unsigned char *ptr, size_t len) 225 { 226 assert(handle == (void *)HID_DEV_HANDLE); 227 assert(len >= CTAP_MIN_REPORT_LEN + 1 && 228 len <= CTAP_MAX_REPORT_LEN + 1); 229 230 return buf_write(ptr, len); 231 } 232 233 static void * 234 nfc_open(const char *path) 235 { 236 (void)path; 237 238 return (void *)NFC_DEV_HANDLE; 239 } 240 241 static void 242 nfc_close(void *handle) 243 { 244 assert(handle == (void *)NFC_DEV_HANDLE); 245 } 246 247 int 248 nfc_read(void *handle, unsigned char *ptr, size_t len, int ms) 249 { 250 assert(handle == (void *)NFC_DEV_HANDLE); 251 assert(len > 0 && len <= 264); 252 253 return buf_read(ptr, len, ms); 254 } 255 256 int 257 nfc_write(void *handle, const unsigned char *ptr, size_t len) 258 { 259 assert(handle == (void *)NFC_DEV_HANDLE); 260 assert(len > 0 && len <= 256 + 2); 261 262 return buf_write(ptr, len); 263 } 264 265 ssize_t 266 fd_read(int fd, void *ptr, size_t len) 267 { 268 assert(fd != -1); 269 270 return buf_read(ptr, len, -1); 271 } 272 273 ssize_t 274 fd_write(int fd, const void *ptr, size_t len) 275 { 276 assert(fd != -1); 277 278 return buf_write(ptr, len); 279 } 280 281 fido_dev_t * 282 open_dev(int nfc) 283 { 284 fido_dev_t *dev; 285 fido_dev_io_t io; 286 fido_dev_transport_t t; 287 288 memset(&io, 0, sizeof(io)); 289 memset(&t, 0, sizeof(t)); 290 291 if ((dev = fido_dev_new()) == NULL) 292 return NULL; 293 294 if (nfc) { 295 io.open = nfc_open; 296 io.close = nfc_close; 297 io.read = nfc_read; 298 io.write = nfc_write; 299 } else { 300 io.open = hid_open; 301 io.close = hid_close; 302 io.read = hid_read; 303 io.write = hid_write; 304 } 305 306 if (fido_dev_set_io_functions(dev, &io) != FIDO_OK) 307 goto fail; 308 309 if (nfc) { 310 t.rx = fido_nfc_rx; 311 t.tx = fido_nfc_tx; 312 if (fido_dev_set_transport_functions(dev, &t) != FIDO_OK) 313 goto fail; 314 } 315 316 if (fido_dev_set_timeout(dev, 300) != FIDO_OK || 317 fido_dev_open(dev, "nodev") != FIDO_OK) 318 goto fail; 319 320 return dev; 321 fail: 322 fido_dev_free(&dev); 323 324 return NULL; 325 } 326 327 void 328 set_wire_data(const uint8_t *ptr, size_t len) 329 { 330 wire_data_ptr = ptr; 331 wire_data_len = len; 332 } 333