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