1 /* 2 * Copyright (C) 2020 Yubico AB - See COPYING 3 */ 4 #include <string.h> 5 #include <stdlib.h> 6 #include <stdint.h> 7 #include <stdio.h> 8 #include <sys/types.h> 9 #include <sys/stat.h> 10 #include <unistd.h> 11 12 #include "fuzz/fuzz.h" 13 #include "util.c" 14 #include "b64.c" 15 16 static void cleanup(device_t *devs, unsigned int n_devs) { 17 for (unsigned int i = 0; i < n_devs; i++) { 18 free(devs[i].keyHandle); 19 free(devs[i].publicKey); 20 free(devs[i].coseType); 21 free(devs[i].attributes); 22 devs[i].keyHandle = NULL; 23 devs[i].publicKey = NULL; 24 devs[i].coseType = NULL; 25 devs[i].attributes = NULL; 26 } 27 } 28 29 #define DEV_MAX_SIZE 10 30 31 int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 32 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 33 char buf[DEVSIZE * DEV_MAX_SIZE]; /* DEVSIZE * cfg.max_size */ 34 device_t devs[12] = {0}; 35 unsigned int n_devs = 12; 36 FILE *fp = NULL; 37 size_t fp_len = 0; 38 size_t offset = 0; 39 char username[256] = {0}; 40 size_t username_len = 0; 41 uint8_t ssh_format = 1; 42 cfg_t cfg = {0}; 43 cfg.max_devs = DEV_MAX_SIZE; 44 45 /* first 6 byte decides which parser we should call, if 46 * we want to run with debug and also sets the initial seed */ 47 if (size < 6) { 48 return -1; 49 } 50 /* do not always run with debug, only 8/255 times */ 51 if (data[offset++] < 9) { 52 cfg.debug = 1; 53 } 54 55 /* predictable random for this seed */ 56 prng_init((uint32_t) data[offset] << 24 | (uint32_t) data[offset + 1] << 16 | 57 (uint32_t) data[offset + 2] << 8 | (uint32_t) data[offset + 3]); 58 offset += 4; 59 60 /* choose which format parser to run, even == native, odd == ssh */ 61 if (data[offset++] % 2) { 62 ssh_format = 0; 63 /* native format, get a random username first */ 64 if (size < 7) { 65 return -1; 66 } 67 username_len = data[offset++]; 68 if (username_len > (size - offset)) { 69 username_len = (size - offset); 70 } 71 memcpy(username, &data[offset], username_len); 72 offset += username_len; 73 } 74 75 fp_len = size - offset; 76 fp = tmpfile(); 77 if (fp == NULL || (fwrite(&data[offset], 1, fp_len, fp)) != fp_len) { 78 fprintf(stderr, "failed to create file for parser: %s\n", strerror(errno)); 79 if (fp != NULL) { 80 fclose(fp); 81 } 82 return -1; 83 } 84 (void) fseek(fp, 0L, SEEK_SET); 85 86 if (ssh_format) { 87 parse_ssh_format(&cfg, buf, sizeof(buf), fp, size, devs, &n_devs); 88 } else { 89 parse_native_format(&cfg, username, buf, fp, devs, &n_devs); 90 } 91 92 cleanup(devs, n_devs); 93 94 fclose(fp); 95 96 return 0; 97 } 98