1 /* 2 * Copyright (c) 2019 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 */ 6 7 #include <assert.h> 8 #include <stdint.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <stdio.h> 12 13 #include "mutator_aux.h" 14 #include "wiredata_fido2.h" 15 #include "dummy.h" 16 17 #include "fido.h" 18 #include "fido/credman.h" 19 20 #include "../openbsd-compat/openbsd-compat.h" 21 22 #define TAG_META_WIRE_DATA 0x01 23 #define TAG_RP_WIRE_DATA 0x02 24 #define TAG_RK_WIRE_DATA 0x03 25 #define TAG_DEL_WIRE_DATA 0x04 26 #define TAG_CRED_ID 0x05 27 #define TAG_PIN 0x06 28 #define TAG_RP_ID 0x07 29 #define TAG_SEED 0x08 30 31 /* Parameter set defining a FIDO2 credential management operation. */ 32 struct param { 33 char pin[MAXSTR]; 34 char rp_id[MAXSTR]; 35 int seed; 36 struct blob cred_id; 37 struct blob del_wire_data; 38 struct blob meta_wire_data; 39 struct blob rk_wire_data; 40 struct blob rp_wire_data; 41 }; 42 43 /* 44 * Collection of HID reports from an authenticator issued with a FIDO2 45 * 'getCredsMetadata' credential management command. 46 */ 47 static const uint8_t dummy_meta_wire_data[] = { 48 WIREDATA_CTAP_INIT, 49 WIREDATA_CTAP_CBOR_INFO, 50 WIREDATA_CTAP_CBOR_AUTHKEY, 51 WIREDATA_CTAP_CBOR_PINTOKEN, 52 WIREDATA_CTAP_CBOR_CREDMAN_META, 53 }; 54 55 /* 56 * Collection of HID reports from an authenticator issued with a FIDO2 57 * 'enumerateRPsBegin' credential management command. 58 */ 59 static const uint8_t dummy_rp_wire_data[] = { 60 WIREDATA_CTAP_INIT, 61 WIREDATA_CTAP_CBOR_INFO, 62 WIREDATA_CTAP_CBOR_AUTHKEY, 63 WIREDATA_CTAP_CBOR_PINTOKEN, 64 WIREDATA_CTAP_CBOR_CREDMAN_RPLIST, 65 }; 66 67 /* 68 * Collection of HID reports from an authenticator issued with a FIDO2 69 * 'enumerateCredentialsBegin' credential management command. 70 */ 71 static const uint8_t dummy_rk_wire_data[] = { 72 WIREDATA_CTAP_INIT, 73 WIREDATA_CTAP_CBOR_INFO, 74 WIREDATA_CTAP_CBOR_AUTHKEY, 75 WIREDATA_CTAP_CBOR_PINTOKEN, 76 WIREDATA_CTAP_CBOR_CREDMAN_RKLIST, 77 }; 78 79 /* 80 * Collection of HID reports from an authenticator issued with a FIDO2 81 * 'deleteCredential' credential management command. 82 */ 83 static const uint8_t dummy_del_wire_data[] = { 84 WIREDATA_CTAP_INIT, 85 WIREDATA_CTAP_CBOR_INFO, 86 WIREDATA_CTAP_CBOR_AUTHKEY, 87 WIREDATA_CTAP_CBOR_PINTOKEN, 88 WIREDATA_CTAP_CBOR_STATUS, 89 }; 90 91 int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 92 size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 93 94 static int 95 unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN 96 { 97 uint8_t **pp = (void *)&ptr; 98 99 if (unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || 100 unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || 101 unpack_blob(TAG_CRED_ID, pp, &len, &p->cred_id) < 0 || 102 unpack_blob(TAG_META_WIRE_DATA, pp, &len, &p->meta_wire_data) < 0 || 103 unpack_blob(TAG_RP_WIRE_DATA, pp, &len, &p->rp_wire_data) < 0 || 104 unpack_blob(TAG_RK_WIRE_DATA, pp, &len, &p->rk_wire_data) < 0 || 105 unpack_blob(TAG_DEL_WIRE_DATA, pp, &len, &p->del_wire_data) < 0 || 106 unpack_int(TAG_SEED, pp, &len, &p->seed) < 0) 107 return (-1); 108 109 return (0); 110 } 111 112 static size_t 113 pack(uint8_t *ptr, size_t len, const struct param *p) 114 { 115 const size_t max = len; 116 117 if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || 118 pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || 119 pack_blob(TAG_CRED_ID, &ptr, &len, &p->cred_id) < 0 || 120 pack_blob(TAG_META_WIRE_DATA, &ptr, &len, &p->meta_wire_data) < 0 || 121 pack_blob(TAG_RP_WIRE_DATA, &ptr, &len, &p->rp_wire_data) < 0 || 122 pack_blob(TAG_RK_WIRE_DATA, &ptr, &len, &p->rk_wire_data) < 0 || 123 pack_blob(TAG_DEL_WIRE_DATA, &ptr, &len, &p->del_wire_data) < 0 || 124 pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) 125 return (0); 126 127 return (max - len); 128 } 129 130 static size_t 131 input_len(int max) 132 { 133 return (2 * len_string(max) + 5 * len_blob(max) + len_int()); 134 } 135 136 static fido_dev_t * 137 prepare_dev() 138 { 139 fido_dev_t *dev; 140 fido_dev_io_t io; 141 142 memset(&io, 0, sizeof(io)); 143 144 io.open = dev_open; 145 io.close = dev_close; 146 io.read = dev_read; 147 io.write = dev_write; 148 149 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, 150 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { 151 fido_dev_free(&dev); 152 return (NULL); 153 } 154 155 return (dev); 156 } 157 158 static void 159 get_metadata(struct param *p) 160 { 161 fido_dev_t *dev; 162 fido_credman_metadata_t *metadata; 163 uint64_t existing; 164 uint64_t remaining; 165 166 set_wire_data(p->meta_wire_data.body, p->meta_wire_data.len); 167 168 if ((dev = prepare_dev()) == NULL) 169 return; 170 171 if ((metadata = fido_credman_metadata_new()) == NULL) { 172 fido_dev_close(dev); 173 fido_dev_free(&dev); 174 return; 175 } 176 177 fido_credman_get_dev_metadata(dev, metadata, p->pin); 178 179 existing = fido_credman_rk_existing(metadata); 180 remaining = fido_credman_rk_remaining(metadata); 181 consume(&existing, sizeof(existing)); 182 consume(&remaining, sizeof(remaining)); 183 184 fido_credman_metadata_free(&metadata); 185 fido_dev_close(dev); 186 fido_dev_free(&dev); 187 } 188 189 static void 190 get_rp_list(struct param *p) 191 { 192 fido_dev_t *dev; 193 fido_credman_rp_t *rp; 194 195 set_wire_data(p->rp_wire_data.body, p->rp_wire_data.len); 196 197 if ((dev = prepare_dev()) == NULL) 198 return; 199 200 if ((rp = fido_credman_rp_new()) == NULL) { 201 fido_dev_close(dev); 202 fido_dev_free(&dev); 203 return; 204 } 205 206 fido_credman_get_dev_rp(dev, rp, p->pin); 207 208 /* +1 on purpose */ 209 for (size_t i = 0; i < fido_credman_rp_count(rp) + 1; i++) { 210 consume(fido_credman_rp_id_hash_ptr(rp, i), 211 fido_credman_rp_id_hash_len(rp, i)); 212 consume(fido_credman_rp_id(rp, i), 213 xstrlen(fido_credman_rp_id(rp, i))); 214 consume(fido_credman_rp_name(rp, i), 215 xstrlen(fido_credman_rp_name(rp, i))); 216 } 217 218 fido_credman_rp_free(&rp); 219 fido_dev_close(dev); 220 fido_dev_free(&dev); 221 } 222 223 static void 224 get_rk_list(struct param *p) 225 { 226 fido_dev_t *dev; 227 fido_credman_rk_t *rk; 228 const fido_cred_t *cred; 229 int type; 230 231 set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len); 232 233 if ((dev = prepare_dev()) == NULL) 234 return; 235 236 if ((rk = fido_credman_rk_new()) == NULL) { 237 fido_dev_close(dev); 238 fido_dev_free(&dev); 239 return; 240 } 241 242 fido_credman_get_dev_rk(dev, p->rp_id, rk, p->pin); 243 244 /* +1 on purpose */ 245 for (size_t i = 0; i < fido_credman_rk_count(rk) + 1; i++) { 246 if ((cred = fido_credman_rk(rk, i)) == NULL) { 247 assert(i >= fido_credman_rk_count(rk)); 248 continue; 249 } 250 type = fido_cred_type(cred); 251 consume(&type, sizeof(type)); 252 consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); 253 consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); 254 consume(fido_cred_user_id_ptr(cred), 255 fido_cred_user_id_len(cred)); 256 consume(fido_cred_user_name(cred), 257 xstrlen(fido_cred_user_name(cred))); 258 consume(fido_cred_display_name(cred), 259 xstrlen(fido_cred_display_name(cred))); 260 } 261 262 fido_credman_rk_free(&rk); 263 fido_dev_close(dev); 264 fido_dev_free(&dev); 265 } 266 267 static void 268 del_rk(struct param *p) 269 { 270 fido_dev_t *dev; 271 272 set_wire_data(p->del_wire_data.body, p->del_wire_data.len); 273 274 if ((dev = prepare_dev()) == NULL) 275 return; 276 277 fido_credman_del_dev_rk(dev, p->cred_id.body, p->cred_id.len, p->pin); 278 fido_dev_close(dev); 279 fido_dev_free(&dev); 280 } 281 282 int 283 LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 284 { 285 struct param p; 286 287 memset(&p, 0, sizeof(p)); 288 289 if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) || 290 unpack(data, size, &p) < 0) 291 return (0); 292 293 prng_init((unsigned int)p.seed); 294 295 fido_init(FIDO_DEBUG); 296 fido_set_log_handler(consume_str); 297 298 get_metadata(&p); 299 get_rp_list(&p); 300 get_rk_list(&p); 301 del_rk(&p); 302 303 return (0); 304 } 305 306 static size_t 307 pack_dummy(uint8_t *ptr, size_t len) 308 { 309 struct param dummy; 310 uint8_t blob[32768]; 311 size_t blob_len; 312 313 memset(&dummy, 0, sizeof(dummy)); 314 315 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); 316 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); 317 318 dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data); 319 dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data); 320 dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data); 321 dummy.del_wire_data.len = sizeof(dummy_del_wire_data); 322 dummy.cred_id.len = sizeof(dummy_cred_id); 323 324 memcpy(&dummy.meta_wire_data.body, &dummy_meta_wire_data, 325 dummy.meta_wire_data.len); 326 memcpy(&dummy.rp_wire_data.body, &dummy_rp_wire_data, 327 dummy.rp_wire_data.len); 328 memcpy(&dummy.rk_wire_data.body, &dummy_rk_wire_data, 329 dummy.rk_wire_data.len); 330 memcpy(&dummy.del_wire_data.body, &dummy_del_wire_data, 331 dummy.del_wire_data.len); 332 memcpy(&dummy.cred_id.body, &dummy_cred_id, dummy.cred_id.len); 333 334 blob_len = pack(blob, sizeof(blob), &dummy); 335 assert(blob_len != 0); 336 337 if (blob_len > len) { 338 memcpy(ptr, blob, len); 339 return (len); 340 } 341 342 memcpy(ptr, blob, blob_len); 343 344 return (blob_len); 345 } 346 347 size_t 348 LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, 349 unsigned int seed) NO_MSAN 350 { 351 struct param p; 352 uint8_t blob[16384]; 353 size_t blob_len; 354 355 memset(&p, 0, sizeof(p)); 356 357 if (unpack(data, size, &p) < 0) 358 return (pack_dummy(data, maxsize)); 359 360 p.seed = (int)seed; 361 362 mutate_blob(&p.cred_id); 363 mutate_blob(&p.meta_wire_data); 364 mutate_blob(&p.rp_wire_data); 365 mutate_blob(&p.rk_wire_data); 366 mutate_blob(&p.del_wire_data); 367 368 mutate_string(p.pin); 369 mutate_string(p.rp_id); 370 371 blob_len = pack(blob, sizeof(blob), &p); 372 373 if (blob_len == 0 || blob_len > maxsize) 374 return (0); 375 376 memcpy(data, blob, blob_len); 377 378 return (blob_len); 379 } 380