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