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 <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 "wiredata_u2f.h" 17 #include "dummy.h" 18 19 #include "../openbsd-compat/openbsd-compat.h" 20 21 /* Parameter set defining a FIDO2 get assertion operation. */ 22 struct param { 23 char pin[MAXSTR]; 24 char rp_id[MAXSTR]; 25 int ext; 26 int seed; 27 struct blob cdh; 28 struct blob cred; 29 struct blob es256; 30 struct blob rs256; 31 struct blob eddsa; 32 struct blob wire_data; 33 uint8_t cred_count; 34 uint8_t type; 35 uint8_t opt; 36 uint8_t up; 37 uint8_t uv; 38 }; 39 40 /* 41 * Collection of HID reports from an authenticator issued with a FIDO2 42 * get assertion using the example parameters above. 43 */ 44 static const uint8_t dummy_wire_data_fido[] = { 45 WIREDATA_CTAP_INIT, 46 WIREDATA_CTAP_CBOR_INFO, 47 WIREDATA_CTAP_CBOR_AUTHKEY, 48 WIREDATA_CTAP_CBOR_PINTOKEN, 49 WIREDATA_CTAP_CBOR_ASSERT, 50 }; 51 52 /* 53 * Collection of HID reports from an authenticator issued with a U2F 54 * authentication using the example parameters above. 55 */ 56 static const uint8_t dummy_wire_data_u2f[] = { 57 WIREDATA_CTAP_INIT, 58 WIREDATA_CTAP_U2F_6985, 59 WIREDATA_CTAP_U2F_6985, 60 WIREDATA_CTAP_U2F_6985, 61 WIREDATA_CTAP_U2F_6985, 62 WIREDATA_CTAP_U2F_AUTH, 63 }; 64 65 struct param * 66 unpack(const uint8_t *ptr, size_t len) 67 { 68 cbor_item_t *item = NULL, **v; 69 struct cbor_load_result cbor; 70 struct param *p; 71 int ok = -1; 72 73 if ((p = calloc(1, sizeof(*p))) == NULL || 74 (item = cbor_load(ptr, len, &cbor)) == NULL || 75 cbor.read != len || 76 cbor_isa_array(item) == false || 77 cbor_array_is_definite(item) == false || 78 cbor_array_size(item) != 15 || 79 (v = cbor_array_handle(item)) == NULL) 80 goto fail; 81 82 if (unpack_byte(v[0], &p->uv) < 0 || 83 unpack_byte(v[1], &p->up) < 0 || 84 unpack_byte(v[2], &p->opt) < 0 || 85 unpack_byte(v[3], &p->type) < 0 || 86 unpack_byte(v[4], &p->cred_count) < 0 || 87 unpack_int(v[5], &p->ext) < 0 || 88 unpack_int(v[6], &p->seed) < 0 || 89 unpack_string(v[7], p->rp_id) < 0 || 90 unpack_string(v[8], p->pin) < 0 || 91 unpack_blob(v[9], &p->wire_data) < 0 || 92 unpack_blob(v[10], &p->rs256) < 0 || 93 unpack_blob(v[11], &p->es256) < 0 || 94 unpack_blob(v[12], &p->eddsa) < 0 || 95 unpack_blob(v[13], &p->cred) < 0 || 96 unpack_blob(v[14], &p->cdh) < 0) 97 goto fail; 98 99 ok = 0; 100 fail: 101 if (ok < 0) { 102 free(p); 103 p = NULL; 104 } 105 106 if (item) 107 cbor_decref(&item); 108 109 return p; 110 } 111 112 size_t 113 pack(uint8_t *ptr, size_t len, const struct param *p) 114 { 115 cbor_item_t *argv[15], *array = NULL; 116 size_t cbor_alloc_len, cbor_len = 0; 117 unsigned char *cbor = NULL; 118 119 memset(argv, 0, sizeof(argv)); 120 121 if ((array = cbor_new_definite_array(15)) == NULL || 122 (argv[0] = pack_byte(p->uv)) == NULL || 123 (argv[1] = pack_byte(p->up)) == NULL || 124 (argv[2] = pack_byte(p->opt)) == NULL || 125 (argv[3] = pack_byte(p->type)) == NULL || 126 (argv[4] = pack_byte(p->cred_count)) == NULL || 127 (argv[5] = pack_int(p->ext)) == NULL || 128 (argv[6] = pack_int(p->seed)) == NULL || 129 (argv[7] = pack_string(p->rp_id)) == NULL || 130 (argv[8] = pack_string(p->pin)) == NULL || 131 (argv[9] = pack_blob(&p->wire_data)) == NULL || 132 (argv[10] = pack_blob(&p->rs256)) == NULL || 133 (argv[11] = pack_blob(&p->es256)) == NULL || 134 (argv[12] = pack_blob(&p->eddsa)) == NULL || 135 (argv[13] = pack_blob(&p->cred)) == NULL || 136 (argv[14] = pack_blob(&p->cdh)) == NULL) 137 goto fail; 138 139 for (size_t i = 0; i < 15; i++) 140 if (cbor_array_push(array, argv[i]) == false) 141 goto fail; 142 143 if ((cbor_len = cbor_serialize_alloc(array, &cbor, 144 &cbor_alloc_len)) == 0 || cbor_len > len) { 145 cbor_len = 0; 146 goto fail; 147 } 148 149 memcpy(ptr, cbor, cbor_len); 150 fail: 151 for (size_t i = 0; i < 15; i++) 152 if (argv[i]) 153 cbor_decref(&argv[i]); 154 155 if (array) 156 cbor_decref(&array); 157 158 free(cbor); 159 160 return cbor_len; 161 } 162 163 size_t 164 pack_dummy(uint8_t *ptr, size_t len) 165 { 166 struct param dummy; 167 uint8_t blob[MAXCORPUS]; 168 size_t blob_len; 169 170 memset(&dummy, 0, sizeof(dummy)); 171 172 dummy.type = 1; /* rsa */ 173 dummy.ext = FIDO_EXT_HMAC_SECRET; 174 175 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); 176 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); 177 178 dummy.cred.len = sizeof(dummy_cdh); /* XXX */ 179 dummy.cdh.len = sizeof(dummy_cdh); 180 dummy.es256.len = sizeof(dummy_es256); 181 dummy.rs256.len = sizeof(dummy_rs256); 182 dummy.eddsa.len = sizeof(dummy_eddsa); 183 dummy.wire_data.len = sizeof(dummy_wire_data_fido); 184 185 memcpy(&dummy.cred.body, &dummy_cdh, dummy.cred.len); /* XXX */ 186 memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); 187 memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, 188 dummy.wire_data.len); 189 memcpy(&dummy.es256.body, &dummy_es256, dummy.es256.len); 190 memcpy(&dummy.rs256.body, &dummy_rs256, dummy.rs256.len); 191 memcpy(&dummy.eddsa.body, &dummy_eddsa, dummy.eddsa.len); 192 193 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); 194 195 if (blob_len > len) { 196 memcpy(ptr, blob, len); 197 return len; 198 } 199 200 memcpy(ptr, blob, blob_len); 201 202 return blob_len; 203 } 204 205 static void 206 get_assert(fido_assert_t *assert, uint8_t opt, const struct blob *cdh, 207 const char *rp_id, int ext, uint8_t up, uint8_t uv, const char *pin, 208 uint8_t cred_count, const struct blob *cred) 209 { 210 fido_dev_t *dev; 211 212 if ((dev = open_dev(opt & 2)) == NULL) 213 return; 214 if (opt & 1) 215 fido_dev_force_u2f(dev); 216 if (ext & FIDO_EXT_HMAC_SECRET) 217 fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET); 218 if (ext & FIDO_EXT_CRED_BLOB) 219 fido_assert_set_extensions(assert, FIDO_EXT_CRED_BLOB); 220 if (ext & FIDO_EXT_LARGEBLOB_KEY) 221 fido_assert_set_extensions(assert, FIDO_EXT_LARGEBLOB_KEY); 222 if (up & 1) 223 fido_assert_set_up(assert, FIDO_OPT_TRUE); 224 else if (opt & 1) 225 fido_assert_set_up(assert, FIDO_OPT_FALSE); 226 if (uv & 1) 227 fido_assert_set_uv(assert, FIDO_OPT_TRUE); 228 229 for (uint8_t i = 0; i < cred_count; i++) 230 fido_assert_allow_cred(assert, cred->body, cred->len); 231 232 fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len); 233 fido_assert_set_rp(assert, rp_id); 234 /* XXX reuse cred as hmac salt */ 235 fido_assert_set_hmac_salt(assert, cred->body, cred->len); 236 237 /* repeat memory operations to trigger reallocation paths */ 238 fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len); 239 fido_assert_set_rp(assert, rp_id); 240 fido_assert_set_hmac_salt(assert, cred->body, cred->len); 241 242 if (strlen(pin) == 0) 243 pin = NULL; 244 245 fido_dev_get_assert(dev, assert, (opt & 1) ? NULL : pin); 246 247 fido_dev_cancel(dev); 248 fido_dev_close(dev); 249 fido_dev_free(&dev); 250 } 251 252 static void 253 verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len, 254 const char *rp_id, const unsigned char *authdata_ptr, size_t authdata_len, 255 const unsigned char *sig_ptr, size_t sig_len, uint8_t up, uint8_t uv, 256 int ext, void *pk) 257 { 258 fido_assert_t *assert = NULL; 259 int r; 260 261 if ((assert = fido_assert_new()) == NULL) 262 return; 263 264 fido_assert_set_clientdata_hash(assert, cdh_ptr, cdh_len); 265 fido_assert_set_rp(assert, rp_id); 266 fido_assert_set_count(assert, 1); 267 268 if (fido_assert_set_authdata(assert, 0, authdata_ptr, 269 authdata_len) != FIDO_OK) { 270 fido_assert_set_authdata_raw(assert, 0, authdata_ptr, 271 authdata_len); 272 } 273 274 if (up & 1) 275 fido_assert_set_up(assert, FIDO_OPT_TRUE); 276 if (uv & 1) 277 fido_assert_set_uv(assert, FIDO_OPT_TRUE); 278 279 fido_assert_set_extensions(assert, ext); 280 fido_assert_set_sig(assert, 0, sig_ptr, sig_len); 281 282 /* repeat memory operations to trigger reallocation paths */ 283 if (fido_assert_set_authdata(assert, 0, authdata_ptr, 284 authdata_len) != FIDO_OK) { 285 fido_assert_set_authdata_raw(assert, 0, authdata_ptr, 286 authdata_len); 287 } 288 fido_assert_set_sig(assert, 0, sig_ptr, sig_len); 289 290 r = fido_assert_verify(assert, 0, type, pk); 291 consume(&r, sizeof(r)); 292 293 fido_assert_free(&assert); 294 } 295 296 /* 297 * Do a dummy conversion to exercise es256_pk_from_EVP_PKEY(). 298 */ 299 static void 300 es256_convert(const es256_pk_t *k) 301 { 302 EVP_PKEY *pkey = NULL; 303 es256_pk_t *pk = NULL; 304 int r; 305 306 if ((pkey = es256_pk_to_EVP_PKEY(k)) == NULL || 307 (pk = es256_pk_new()) == NULL) 308 goto out; 309 310 r = es256_pk_from_EVP_PKEY(pk, pkey); 311 consume(&r, sizeof(r)); 312 out: 313 es256_pk_free(&pk); 314 EVP_PKEY_free(pkey); 315 } 316 317 /* 318 * Do a dummy conversion to exercise es384_pk_from_EVP_PKEY(). 319 */ 320 static void 321 es384_convert(const es384_pk_t *k) 322 { 323 EVP_PKEY *pkey = NULL; 324 es384_pk_t *pk = NULL; 325 int r; 326 327 if ((pkey = es384_pk_to_EVP_PKEY(k)) == NULL || 328 (pk = es384_pk_new()) == NULL) 329 goto out; 330 331 r = es384_pk_from_EVP_PKEY(pk, pkey); 332 consume(&r, sizeof(r)); 333 out: 334 es384_pk_free(&pk); 335 EVP_PKEY_free(pkey); 336 } 337 338 /* 339 * Do a dummy conversion to exercise rs256_pk_from_EVP_PKEY(). 340 */ 341 static void 342 rs256_convert(const rs256_pk_t *k) 343 { 344 EVP_PKEY *pkey = NULL; 345 rs256_pk_t *pk = NULL; 346 int r; 347 348 if ((pkey = rs256_pk_to_EVP_PKEY(k)) == NULL || 349 (pk = rs256_pk_new()) == NULL) 350 goto out; 351 352 r = rs256_pk_from_EVP_PKEY(pk, pkey); 353 consume(&r, sizeof(r)); 354 out: 355 rs256_pk_free(&pk); 356 EVP_PKEY_free(pkey); 357 } 358 359 /* 360 * Do a dummy conversion to exercise eddsa_pk_from_EVP_PKEY(). 361 */ 362 static void 363 eddsa_convert(const eddsa_pk_t *k) 364 { 365 EVP_PKEY *pkey = NULL; 366 eddsa_pk_t *pk = NULL; 367 int r; 368 369 if ((pkey = eddsa_pk_to_EVP_PKEY(k)) == NULL || 370 (pk = eddsa_pk_new()) == NULL) 371 goto out; 372 373 r = eddsa_pk_from_EVP_PKEY(pk, pkey); 374 consume(&r, sizeof(r)); 375 out: 376 if (pk) 377 eddsa_pk_free(&pk); 378 if (pkey) 379 EVP_PKEY_free(pkey); 380 } 381 382 void 383 test(const struct param *p) 384 { 385 fido_assert_t *assert = NULL; 386 es256_pk_t *es256_pk = NULL; 387 es384_pk_t *es384_pk = NULL; 388 rs256_pk_t *rs256_pk = NULL; 389 eddsa_pk_t *eddsa_pk = NULL; 390 uint8_t flags; 391 uint32_t sigcount; 392 int cose_alg = 0; 393 void *pk; 394 395 prng_init((unsigned int)p->seed); 396 fuzz_clock_reset(); 397 fido_init(FIDO_DEBUG); 398 fido_set_log_handler(consume_str); 399 400 switch (p->type & 3) { 401 case 0: 402 cose_alg = COSE_ES256; 403 404 if ((es256_pk = es256_pk_new()) == NULL) 405 return; 406 407 es256_pk_from_ptr(es256_pk, p->es256.body, p->es256.len); 408 pk = es256_pk; 409 410 es256_convert(pk); 411 412 break; 413 case 1: 414 cose_alg = COSE_RS256; 415 416 if ((rs256_pk = rs256_pk_new()) == NULL) 417 return; 418 419 rs256_pk_from_ptr(rs256_pk, p->rs256.body, p->rs256.len); 420 pk = rs256_pk; 421 422 rs256_convert(pk); 423 424 break; 425 case 2: 426 cose_alg = COSE_ES384; 427 428 if ((es384_pk = es384_pk_new()) == NULL) 429 return; 430 431 /* XXX reuse p->es256 as es384 */ 432 es384_pk_from_ptr(es384_pk, p->es256.body, p->es256.len); 433 pk = es384_pk; 434 435 es384_convert(pk); 436 437 break; 438 default: 439 cose_alg = COSE_EDDSA; 440 441 if ((eddsa_pk = eddsa_pk_new()) == NULL) 442 return; 443 444 eddsa_pk_from_ptr(eddsa_pk, p->eddsa.body, p->eddsa.len); 445 pk = eddsa_pk; 446 447 eddsa_convert(pk); 448 449 break; 450 } 451 452 if ((assert = fido_assert_new()) == NULL) 453 goto out; 454 455 set_wire_data(p->wire_data.body, p->wire_data.len); 456 457 get_assert(assert, p->opt, &p->cdh, p->rp_id, p->ext, p->up, p->uv, 458 p->pin, p->cred_count, &p->cred); 459 460 /* XXX +1 on purpose */ 461 for (size_t i = 0; i <= fido_assert_count(assert); i++) { 462 verify_assert(cose_alg, 463 fido_assert_clientdata_hash_ptr(assert), 464 fido_assert_clientdata_hash_len(assert), 465 fido_assert_rp_id(assert), 466 fido_assert_authdata_ptr(assert, i), 467 fido_assert_authdata_len(assert, i), 468 fido_assert_sig_ptr(assert, i), 469 fido_assert_sig_len(assert, i), p->up, p->uv, p->ext, pk); 470 consume(fido_assert_id_ptr(assert, i), 471 fido_assert_id_len(assert, i)); 472 consume(fido_assert_user_id_ptr(assert, i), 473 fido_assert_user_id_len(assert, i)); 474 consume(fido_assert_hmac_secret_ptr(assert, i), 475 fido_assert_hmac_secret_len(assert, i)); 476 consume_str(fido_assert_user_icon(assert, i)); 477 consume_str(fido_assert_user_name(assert, i)); 478 consume_str(fido_assert_user_display_name(assert, i)); 479 consume(fido_assert_blob_ptr(assert, i), 480 fido_assert_blob_len(assert, i)); 481 consume(fido_assert_largeblob_key_ptr(assert, i), 482 fido_assert_largeblob_key_len(assert, i)); 483 flags = fido_assert_flags(assert, i); 484 consume(&flags, sizeof(flags)); 485 sigcount = fido_assert_sigcount(assert, i); 486 consume(&sigcount, sizeof(sigcount)); 487 } 488 489 out: 490 es256_pk_free(&es256_pk); 491 es384_pk_free(&es384_pk); 492 rs256_pk_free(&rs256_pk); 493 eddsa_pk_free(&eddsa_pk); 494 495 fido_assert_free(&assert); 496 } 497 498 void 499 mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN 500 { 501 if (flags & MUTATE_SEED) 502 p->seed = (int)seed; 503 504 if (flags & MUTATE_PARAM) { 505 mutate_byte(&p->uv); 506 mutate_byte(&p->up); 507 mutate_byte(&p->opt); 508 mutate_byte(&p->type); 509 mutate_byte(&p->cred_count); 510 mutate_int(&p->ext); 511 mutate_blob(&p->rs256); 512 mutate_blob(&p->es256); 513 mutate_blob(&p->eddsa); 514 mutate_blob(&p->cred); 515 mutate_blob(&p->cdh); 516 mutate_string(p->rp_id); 517 mutate_string(p->pin); 518 } 519 520 if (flags & MUTATE_WIREDATA) { 521 if (p->opt & 1) { 522 p->wire_data.len = sizeof(dummy_wire_data_u2f); 523 memcpy(&p->wire_data.body, &dummy_wire_data_u2f, 524 p->wire_data.len); 525 } else { 526 p->wire_data.len = sizeof(dummy_wire_data_fido); 527 memcpy(&p->wire_data.body, &dummy_wire_data_fido, 528 p->wire_data.len); 529 } 530 mutate_blob(&p->wire_data); 531 } 532 } 533