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 */ 6 7 #include <assert.h> 8 #include <stdint.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 13 #include "mutator_aux.h" 14 #include "wiredata_fido2.h" 15 #include "wiredata_u2f.h" 16 #include "dummy.h" 17 18 #include "../openbsd-compat/openbsd-compat.h" 19 20 /* Parameter set defining a FIDO2 make credential operation. */ 21 struct param { 22 char pin[MAXSTR]; 23 char rp_id[MAXSTR]; 24 char rp_name[MAXSTR]; 25 char user_icon[MAXSTR]; 26 char user_name[MAXSTR]; 27 char user_nick[MAXSTR]; 28 int ext; 29 int seed; 30 struct blob cdh; 31 struct blob excl_cred; 32 struct blob user_id; 33 struct blob wire_data; 34 uint8_t excl_count; 35 uint8_t rk; 36 uint8_t type; 37 uint8_t opt; 38 uint8_t uv; 39 }; 40 41 /* 42 * Collection of HID reports from an authenticator issued with a FIDO2 43 * make credential using the example parameters above. 44 */ 45 static const uint8_t dummy_wire_data_fido[] = { 46 WIREDATA_CTAP_INIT, 47 WIREDATA_CTAP_CBOR_INFO, 48 WIREDATA_CTAP_CBOR_AUTHKEY, 49 WIREDATA_CTAP_CBOR_PINTOKEN, 50 WIREDATA_CTAP_KEEPALIVE, 51 WIREDATA_CTAP_KEEPALIVE, 52 WIREDATA_CTAP_KEEPALIVE, 53 WIREDATA_CTAP_CBOR_CRED, 54 }; 55 56 /* 57 * Collection of HID reports from an authenticator issued with a U2F 58 * registration using the example parameters above. 59 */ 60 static const uint8_t dummy_wire_data_u2f[] = { 61 WIREDATA_CTAP_INIT, 62 WIREDATA_CTAP_U2F_6985, 63 WIREDATA_CTAP_U2F_6985, 64 WIREDATA_CTAP_U2F_6985, 65 WIREDATA_CTAP_U2F_6985, 66 WIREDATA_CTAP_U2F_6985, 67 WIREDATA_CTAP_U2F_REGISTER, 68 }; 69 70 struct param * 71 unpack(const uint8_t *ptr, size_t len) 72 { 73 cbor_item_t *item = NULL, **v; 74 struct cbor_load_result cbor; 75 struct param *p; 76 int ok = -1; 77 78 if ((p = calloc(1, sizeof(*p))) == NULL || 79 (item = cbor_load(ptr, len, &cbor)) == NULL || 80 cbor.read != len || 81 cbor_isa_array(item) == false || 82 cbor_array_is_definite(item) == false || 83 cbor_array_size(item) != 17 || 84 (v = cbor_array_handle(item)) == NULL) 85 goto fail; 86 87 if (unpack_byte(v[0], &p->rk) < 0 || 88 unpack_byte(v[1], &p->type) < 0 || 89 unpack_byte(v[2], &p->opt) < 0 || 90 unpack_byte(v[3], &p->uv) < 0 || 91 unpack_byte(v[4], &p->excl_count) < 0 || 92 unpack_int(v[5], &p->ext) < 0 || 93 unpack_int(v[6], &p->seed) < 0 || 94 unpack_string(v[7], p->pin) < 0 || 95 unpack_string(v[8], p->rp_id) < 0 || 96 unpack_string(v[9], p->rp_name) < 0 || 97 unpack_string(v[10], p->user_icon) < 0 || 98 unpack_string(v[11], p->user_name) < 0 || 99 unpack_string(v[12], p->user_nick) < 0 || 100 unpack_blob(v[13], &p->cdh) < 0 || 101 unpack_blob(v[14], &p->user_id) < 0 || 102 unpack_blob(v[15], &p->wire_data) < 0 || 103 unpack_blob(v[16], &p->excl_cred) < 0) 104 goto fail; 105 106 ok = 0; 107 fail: 108 if (ok < 0) { 109 free(p); 110 p = NULL; 111 } 112 113 if (item) 114 cbor_decref(&item); 115 116 return p; 117 } 118 119 size_t 120 pack(uint8_t *ptr, size_t len, const struct param *p) 121 { 122 cbor_item_t *argv[17], *array = NULL; 123 size_t cbor_alloc_len, cbor_len = 0; 124 unsigned char *cbor = NULL; 125 126 memset(argv, 0, sizeof(argv)); 127 128 if ((array = cbor_new_definite_array(17)) == NULL || 129 (argv[0] = pack_byte(p->rk)) == NULL || 130 (argv[1] = pack_byte(p->type)) == NULL || 131 (argv[2] = pack_byte(p->opt)) == NULL || 132 (argv[3] = pack_byte(p->uv)) == NULL || 133 (argv[4] = pack_byte(p->excl_count)) == NULL || 134 (argv[5] = pack_int(p->ext)) == NULL || 135 (argv[6] = pack_int(p->seed)) == NULL || 136 (argv[7] = pack_string(p->pin)) == NULL || 137 (argv[8] = pack_string(p->rp_id)) == NULL || 138 (argv[9] = pack_string(p->rp_name)) == NULL || 139 (argv[10] = pack_string(p->user_icon)) == NULL || 140 (argv[11] = pack_string(p->user_name)) == NULL || 141 (argv[12] = pack_string(p->user_nick)) == NULL || 142 (argv[13] = pack_blob(&p->cdh)) == NULL || 143 (argv[14] = pack_blob(&p->user_id)) == NULL || 144 (argv[15] = pack_blob(&p->wire_data)) == NULL || 145 (argv[16] = pack_blob(&p->excl_cred)) == NULL) 146 goto fail; 147 148 for (size_t i = 0; i < 17; i++) 149 if (cbor_array_push(array, argv[i]) == false) 150 goto fail; 151 152 if ((cbor_len = cbor_serialize_alloc(array, &cbor, 153 &cbor_alloc_len)) > len) { 154 cbor_len = 0; 155 goto fail; 156 } 157 158 memcpy(ptr, cbor, cbor_len); 159 fail: 160 for (size_t i = 0; i < 17; i++) 161 if (argv[i]) 162 cbor_decref(&argv[i]); 163 164 if (array) 165 cbor_decref(&array); 166 167 free(cbor); 168 169 return cbor_len; 170 } 171 172 size_t 173 pack_dummy(uint8_t *ptr, size_t len) 174 { 175 struct param dummy; 176 uint8_t blob[4096]; 177 size_t blob_len; 178 179 memset(&dummy, 0, sizeof(dummy)); 180 181 dummy.type = 1; 182 dummy.ext = FIDO_EXT_HMAC_SECRET; 183 184 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); 185 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); 186 strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name)); 187 strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon)); 188 strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name)); 189 strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick)); 190 191 dummy.cdh.len = sizeof(dummy_cdh); 192 dummy.user_id.len = sizeof(dummy_user_id); 193 dummy.wire_data.len = sizeof(dummy_wire_data_fido); 194 195 memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); 196 memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len); 197 memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, 198 dummy.wire_data.len); 199 200 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); 201 202 if (blob_len > len) { 203 memcpy(ptr, blob, len); 204 return len; 205 } 206 207 memcpy(ptr, blob, blob_len); 208 209 return blob_len; 210 } 211 212 static void 213 make_cred(fido_cred_t *cred, uint8_t opt, int type, const struct blob *cdh, 214 const char *rp_id, const char *rp_name, const struct blob *user_id, 215 const char *user_name, const char *user_nick, const char *user_icon, 216 int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count, 217 const struct blob *excl_cred) 218 { 219 fido_dev_t *dev; 220 221 if ((dev = open_dev(opt & 2)) == NULL) 222 return; 223 if (opt & 1) 224 fido_dev_force_u2f(dev); 225 226 for (uint8_t i = 0; i < excl_count; i++) 227 fido_cred_exclude(cred, excl_cred->body, excl_cred->len); 228 229 fido_cred_set_type(cred, type); 230 fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len); 231 fido_cred_set_rp(cred, rp_id, rp_name); 232 fido_cred_set_user(cred, user_id->body, user_id->len, user_name, 233 user_nick, user_icon); 234 235 if (ext & FIDO_EXT_HMAC_SECRET) 236 fido_cred_set_extensions(cred, FIDO_EXT_HMAC_SECRET); 237 if (ext & FIDO_EXT_CRED_BLOB) 238 fido_cred_set_blob(cred, user_id->body, user_id->len); 239 if (ext & FIDO_EXT_LARGEBLOB_KEY) 240 fido_cred_set_extensions(cred, FIDO_EXT_LARGEBLOB_KEY); 241 if (ext & FIDO_EXT_MINPINLEN) 242 fido_cred_set_pin_minlen(cred, strlen(pin)); 243 244 if (rk & 1) 245 fido_cred_set_rk(cred, FIDO_OPT_TRUE); 246 if (uv & 1) 247 fido_cred_set_uv(cred, FIDO_OPT_TRUE); 248 if (user_id->len) 249 fido_cred_set_prot(cred, user_id->body[0] & 0x03); 250 251 /* repeat memory operations to trigger reallocation paths */ 252 fido_cred_set_type(cred, type); 253 fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len); 254 fido_cred_set_rp(cred, rp_id, rp_name); 255 fido_cred_set_user(cred, user_id->body, user_id->len, user_name, 256 user_nick, user_icon); 257 258 if (strlen(pin) == 0) 259 pin = NULL; 260 261 fido_dev_make_cred(dev, cred, (opt & 1) ? NULL : pin); 262 263 fido_dev_cancel(dev); 264 fido_dev_close(dev); 265 fido_dev_free(&dev); 266 } 267 268 static void 269 verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, 270 const char *rp_id, const char *rp_name, const unsigned char *authdata_ptr, 271 size_t authdata_len, const unsigned char *authdata_raw_ptr, 272 size_t authdata_raw_len, int ext, uint8_t rk, uint8_t uv, 273 const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr, 274 size_t sig_len, const unsigned char *attstmt_ptr, size_t attstmt_len, 275 const char *fmt, int prot, size_t minpinlen) 276 { 277 fido_cred_t *cred; 278 uint8_t flags; 279 uint32_t sigcount; 280 int r; 281 282 if ((cred = fido_cred_new()) == NULL) 283 return; 284 285 fido_cred_set_type(cred, type); 286 fido_cred_set_clientdata_hash(cred, cdh_ptr, cdh_len); 287 fido_cred_set_rp(cred, rp_id, rp_name); 288 consume(authdata_ptr, authdata_len); 289 consume(authdata_raw_ptr, authdata_raw_len); 290 consume(x5c_ptr, x5c_len); 291 consume(sig_ptr, sig_len); 292 consume(attstmt_ptr, attstmt_len); 293 if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK) 294 fido_cred_set_authdata_raw(cred, authdata_raw_ptr, 295 authdata_raw_len); 296 fido_cred_set_extensions(cred, ext); 297 if (fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len) != FIDO_OK) { 298 fido_cred_set_x509(cred, x5c_ptr, x5c_len); 299 fido_cred_set_sig(cred, sig_ptr, sig_len); 300 } 301 fido_cred_set_prot(cred, prot); 302 fido_cred_set_pin_minlen(cred, minpinlen); 303 304 if (rk & 1) 305 fido_cred_set_rk(cred, FIDO_OPT_TRUE); 306 if (uv & 1) 307 fido_cred_set_uv(cred, FIDO_OPT_TRUE); 308 if (fmt) 309 fido_cred_set_fmt(cred, fmt); 310 311 /* repeat memory operations to trigger reallocation paths */ 312 if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK) 313 fido_cred_set_authdata_raw(cred, authdata_raw_ptr, 314 authdata_raw_len); 315 if (fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len) != FIDO_OK) { 316 fido_cred_set_x509(cred, x5c_ptr, x5c_len); 317 fido_cred_set_sig(cred, sig_ptr, sig_len); 318 } 319 fido_cred_set_x509(cred, x5c_ptr, x5c_len); 320 fido_cred_set_sig(cred, sig_ptr, sig_len); 321 322 r = fido_cred_verify(cred); 323 consume(&r, sizeof(r)); 324 r = fido_cred_verify_self(cred); 325 consume(&r, sizeof(r)); 326 327 consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); 328 consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); 329 consume(fido_cred_aaguid_ptr(cred), fido_cred_aaguid_len(cred)); 330 consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred)); 331 consume_str(fido_cred_user_name(cred)); 332 consume_str(fido_cred_display_name(cred)); 333 consume(fido_cred_largeblob_key_ptr(cred), 334 fido_cred_largeblob_key_len(cred)); 335 336 flags = fido_cred_flags(cred); 337 consume(&flags, sizeof(flags)); 338 sigcount = fido_cred_sigcount(cred); 339 consume(&sigcount, sizeof(sigcount)); 340 type = fido_cred_type(cred); 341 consume(&type, sizeof(type)); 342 minpinlen = fido_cred_pin_minlen(cred); 343 consume(&minpinlen, sizeof(minpinlen)); 344 345 fido_cred_free(&cred); 346 } 347 348 static void 349 test_cred(const struct param *p) 350 { 351 fido_cred_t *cred = NULL; 352 int cose_alg = 0; 353 354 if ((cred = fido_cred_new()) == NULL) 355 return; 356 357 switch (p->type & 3) { 358 case 0: 359 cose_alg = COSE_ES256; 360 break; 361 case 1: 362 cose_alg = COSE_RS256; 363 break; 364 default: 365 cose_alg = COSE_EDDSA; 366 break; 367 } 368 369 set_wire_data(p->wire_data.body, p->wire_data.len); 370 371 make_cred(cred, p->opt, cose_alg, &p->cdh, p->rp_id, p->rp_name, 372 &p->user_id, p->user_name, p->user_nick, p->user_icon, p->ext, 373 p->rk, p->uv, p->pin, p->excl_count, &p->excl_cred); 374 375 verify_cred(cose_alg, 376 fido_cred_clientdata_hash_ptr(cred), 377 fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred), 378 fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred), 379 fido_cred_authdata_len(cred), fido_cred_authdata_raw_ptr(cred), 380 fido_cred_authdata_raw_len(cred), p->ext, p->rk, p->uv, 381 fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), 382 fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), 383 fido_cred_attstmt_ptr(cred), fido_cred_attstmt_len(cred), 384 fido_cred_fmt(cred), fido_cred_prot(cred), 385 fido_cred_pin_minlen(cred)); 386 387 fido_cred_free(&cred); 388 } 389 390 static void 391 test_touch(const struct param *p) 392 { 393 fido_dev_t *dev; 394 int r; 395 int touched; 396 397 set_wire_data(p->wire_data.body, p->wire_data.len); 398 399 if ((dev = open_dev(p->opt & 2)) == NULL) 400 return; 401 if (p->opt & 1) 402 fido_dev_force_u2f(dev); 403 404 r = fido_dev_get_touch_begin(dev); 405 consume_str(fido_strerr(r)); 406 r = fido_dev_get_touch_status(dev, &touched, -1); 407 consume_str(fido_strerr(r)); 408 consume(&touched, sizeof(touched)); 409 410 fido_dev_cancel(dev); 411 fido_dev_close(dev); 412 fido_dev_free(&dev); 413 } 414 415 static void 416 test_misc(const struct param *p) 417 { 418 fido_cred_t *cred = NULL; 419 420 if ((cred = fido_cred_new()) == NULL) 421 return; 422 423 /* reuse user id as credential id */ 424 fido_cred_set_id(cred, p->user_id.body, p->user_id.len); 425 consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); 426 fido_cred_free(&cred); 427 } 428 429 void 430 test(const struct param *p) 431 { 432 prng_init((unsigned int)p->seed); 433 fuzz_clock_reset(); 434 fido_init(FIDO_DEBUG); 435 fido_set_log_handler(consume_str); 436 437 test_cred(p); 438 test_touch(p); 439 test_misc(p); 440 } 441 442 void 443 mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN 444 { 445 if (flags & MUTATE_SEED) 446 p->seed = (int)seed; 447 448 if (flags & MUTATE_PARAM) { 449 mutate_byte(&p->rk); 450 mutate_byte(&p->type); 451 mutate_byte(&p->opt); 452 mutate_byte(&p->uv); 453 mutate_byte(&p->excl_count); 454 mutate_int(&p->ext); 455 mutate_blob(&p->cdh); 456 mutate_blob(&p->user_id); 457 mutate_blob(&p->excl_cred); 458 mutate_string(p->pin); 459 mutate_string(p->user_icon); 460 mutate_string(p->user_name); 461 mutate_string(p->user_nick); 462 mutate_string(p->rp_id); 463 mutate_string(p->rp_name); 464 } 465 466 if (flags & MUTATE_WIREDATA) { 467 if (p->opt & 1) { 468 p->wire_data.len = sizeof(dummy_wire_data_u2f); 469 memcpy(&p->wire_data.body, &dummy_wire_data_u2f, 470 p->wire_data.len); 471 } else { 472 p->wire_data.len = sizeof(dummy_wire_data_fido); 473 memcpy(&p->wire_data.body, &dummy_wire_data_fido, 474 p->wire_data.len); 475 } 476 mutate_blob(&p->wire_data); 477 } 478 } 479