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