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 <stdbool.h> 9 #include <stdint.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <stdio.h> 13 14 #include "mutator_aux.h" 15 #include "wiredata_fido2.h" 16 #include "wiredata_u2f.h" 17 #include "dummy.h" 18 19 #include "fido.h" 20 #include "fido/es256.h" 21 #include "fido/rs256.h" 22 #include "fido/eddsa.h" 23 24 #include "../openbsd-compat/openbsd-compat.h" 25 26 #define TAG_U2F 0x01 27 #define TAG_TYPE 0x02 28 #define TAG_CDH 0x03 29 #define TAG_RP_ID 0x04 30 #define TAG_EXT 0x05 31 #define TAG_SEED 0x06 32 #define TAG_UP 0x07 33 #define TAG_UV 0x08 34 #define TAG_WIRE_DATA 0x09 35 #define TAG_CRED_COUNT 0x0a 36 #define TAG_CRED 0x0b 37 #define TAG_ES256 0x0c 38 #define TAG_RS256 0x0d 39 #define TAG_PIN 0x0e 40 #define TAG_EDDSA 0x0f 41 42 /* Parameter set defining a FIDO2 get assertion operation. */ 43 struct param { 44 char pin[MAXSTR]; 45 char rp_id[MAXSTR]; 46 int ext; 47 int seed; 48 struct blob cdh; 49 struct blob cred; 50 struct blob es256; 51 struct blob rs256; 52 struct blob eddsa; 53 struct blob wire_data; 54 uint8_t cred_count; 55 uint8_t type; 56 uint8_t u2f; 57 uint8_t up; 58 uint8_t uv; 59 }; 60 61 /* 62 * Collection of HID reports from an authenticator issued with a FIDO2 63 * get assertion using the example parameters above. 64 */ 65 static const uint8_t dummy_wire_data_fido[] = { 66 WIREDATA_CTAP_INIT, 67 WIREDATA_CTAP_CBOR_INFO, 68 WIREDATA_CTAP_CBOR_AUTHKEY, 69 WIREDATA_CTAP_CBOR_PINTOKEN, 70 WIREDATA_CTAP_CBOR_ASSERT, 71 }; 72 73 /* 74 * Collection of HID reports from an authenticator issued with a U2F 75 * authentication using the example parameters above. 76 */ 77 static const uint8_t dummy_wire_data_u2f[] = { 78 WIREDATA_CTAP_INIT, 79 WIREDATA_CTAP_U2F_6985, 80 WIREDATA_CTAP_U2F_6985, 81 WIREDATA_CTAP_U2F_6985, 82 WIREDATA_CTAP_U2F_6985, 83 WIREDATA_CTAP_U2F_AUTH, 84 }; 85 86 int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 87 size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 88 89 static int 90 unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN 91 { 92 uint8_t **pp = (void *)&ptr; 93 94 if (unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 || 95 unpack_byte(TAG_UP, pp, &len, &p->up) < 0 || 96 unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || 97 unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || 98 unpack_byte(TAG_CRED_COUNT, pp, &len, &p->cred_count) < 0 || 99 unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || 100 unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || 101 unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || 102 unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || 103 unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || 104 unpack_blob(TAG_RS256, pp, &len, &p->rs256) < 0 || 105 unpack_blob(TAG_ES256, pp, &len, &p->es256) < 0 || 106 unpack_blob(TAG_EDDSA, pp, &len, &p->eddsa) < 0 || 107 unpack_blob(TAG_CRED, pp, &len, &p->cred) < 0 || 108 unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0) 109 return (-1); 110 111 return (0); 112 } 113 114 static size_t 115 pack(uint8_t *ptr, size_t len, const struct param *p) 116 { 117 const size_t max = len; 118 119 if (pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 || 120 pack_byte(TAG_UP, &ptr, &len, p->up) < 0 || 121 pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || 122 pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || 123 pack_byte(TAG_CRED_COUNT, &ptr, &len, p->cred_count) < 0 || 124 pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || 125 pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || 126 pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || 127 pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || 128 pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || 129 pack_blob(TAG_RS256, &ptr, &len, &p->rs256) < 0 || 130 pack_blob(TAG_ES256, &ptr, &len, &p->es256) < 0 || 131 pack_blob(TAG_EDDSA, &ptr, &len, &p->eddsa) < 0 || 132 pack_blob(TAG_CRED, &ptr, &len, &p->cred) < 0 || 133 pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0) 134 return (0); 135 136 return (max - len); 137 } 138 139 static size_t 140 input_len(int max) 141 { 142 return (5 * len_byte() + 2 * len_int() + 2 * len_string(max) + 143 6 * len_blob(max)); 144 } 145 146 static void 147 get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh, 148 const char *rp_id, int ext, uint8_t up, uint8_t uv, const char *pin, 149 uint8_t cred_count, struct blob *cred) 150 { 151 fido_dev_t *dev; 152 fido_dev_io_t io; 153 154 memset(&io, 0, sizeof(io)); 155 156 io.open = dev_open; 157 io.close = dev_close; 158 io.read = dev_read; 159 io.write = dev_write; 160 161 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, 162 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { 163 fido_dev_free(&dev); 164 return; 165 } 166 167 if (u2f & 1) 168 fido_dev_force_u2f(dev); 169 170 for (uint8_t i = 0; i < cred_count; i++) 171 fido_assert_allow_cred(assert, cred->body, cred->len); 172 173 fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len); 174 fido_assert_set_rp(assert, rp_id); 175 if (ext & 1) 176 fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET); 177 if (up & 1) 178 fido_assert_set_up(assert, FIDO_OPT_TRUE); 179 if (uv & 1) 180 fido_assert_set_uv(assert, FIDO_OPT_TRUE); 181 /* XXX reuse cred as hmac salt to keep struct param small */ 182 fido_assert_set_hmac_salt(assert, cred->body, cred->len); 183 184 fido_dev_get_assert(dev, assert, u2f & 1 ? NULL : pin); 185 186 fido_dev_cancel(dev); 187 fido_dev_close(dev); 188 fido_dev_free(&dev); 189 } 190 191 static void 192 verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len, 193 const char *rp_id, const unsigned char *authdata_ptr, size_t authdata_len, 194 const unsigned char *sig_ptr, size_t sig_len, uint8_t up, uint8_t uv, 195 int ext, void *pk) 196 { 197 fido_assert_t *assert = NULL; 198 199 if ((assert = fido_assert_new()) == NULL) 200 return; 201 202 fido_assert_set_clientdata_hash(assert, cdh_ptr, cdh_len); 203 fido_assert_set_rp(assert, rp_id); 204 fido_assert_set_count(assert, 1); 205 if (fido_assert_set_authdata(assert, 0, authdata_ptr, 206 authdata_len) != FIDO_OK) { 207 fido_assert_set_authdata_raw(assert, 0, authdata_ptr, 208 authdata_len); 209 } 210 fido_assert_set_extensions(assert, ext); 211 if (up & 1) fido_assert_set_up(assert, FIDO_OPT_TRUE); 212 if (uv & 1) fido_assert_set_uv(assert, FIDO_OPT_TRUE); 213 fido_assert_set_sig(assert, 0, sig_ptr, sig_len); 214 fido_assert_verify(assert, 0, type, pk); 215 216 fido_assert_free(&assert); 217 } 218 219 /* 220 * Do a dummy conversion to exercise rs256_pk_from_RSA(). 221 */ 222 static void 223 rs256_convert(const rs256_pk_t *k) 224 { 225 EVP_PKEY *pkey = NULL; 226 rs256_pk_t *pk = NULL; 227 RSA *rsa = NULL; 228 volatile int r; 229 230 if ((pkey = rs256_pk_to_EVP_PKEY(k)) == NULL || 231 (pk = rs256_pk_new()) == NULL || 232 (rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) 233 goto out; 234 235 r = rs256_pk_from_RSA(pk, rsa); 236 out: 237 if (pk) 238 rs256_pk_free(&pk); 239 if (pkey) 240 EVP_PKEY_free(pkey); 241 } 242 243 /* 244 * Do a dummy conversion to exercise eddsa_pk_from_EVP_PKEY(). 245 */ 246 static void 247 eddsa_convert(const eddsa_pk_t *k) 248 { 249 EVP_PKEY *pkey = NULL; 250 eddsa_pk_t *pk = NULL; 251 volatile int r; 252 253 if ((pkey = eddsa_pk_to_EVP_PKEY(k)) == NULL || 254 (pk = eddsa_pk_new()) == NULL) 255 goto out; 256 257 r = eddsa_pk_from_EVP_PKEY(pk, pkey); 258 out: 259 if (pk) 260 eddsa_pk_free(&pk); 261 if (pkey) 262 EVP_PKEY_free(pkey); 263 } 264 265 int 266 LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 267 { 268 struct param p; 269 fido_assert_t *assert = NULL; 270 es256_pk_t *es256_pk = NULL; 271 rs256_pk_t *rs256_pk = NULL; 272 eddsa_pk_t *eddsa_pk = NULL; 273 uint8_t flags; 274 uint32_t sigcount; 275 int cose_alg = 0; 276 void *pk; 277 278 memset(&p, 0, sizeof(p)); 279 280 if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) || 281 unpack(data, size, &p) < 0) 282 return (0); 283 284 prng_init((unsigned int)p.seed); 285 286 fido_init(FIDO_DEBUG); 287 fido_set_log_handler(consume_str); 288 289 switch (p.type & 3) { 290 case 0: 291 cose_alg = COSE_ES256; 292 293 if ((es256_pk = es256_pk_new()) == NULL) 294 return (0); 295 296 es256_pk_from_ptr(es256_pk, p.es256.body, p.es256.len); 297 pk = es256_pk; 298 299 break; 300 case 1: 301 cose_alg = COSE_RS256; 302 303 if ((rs256_pk = rs256_pk_new()) == NULL) 304 return (0); 305 306 rs256_pk_from_ptr(rs256_pk, p.rs256.body, p.rs256.len); 307 pk = rs256_pk; 308 309 rs256_convert(pk); 310 311 break; 312 default: 313 cose_alg = COSE_EDDSA; 314 315 if ((eddsa_pk = eddsa_pk_new()) == NULL) 316 return (0); 317 318 eddsa_pk_from_ptr(eddsa_pk, p.eddsa.body, p.eddsa.len); 319 pk = eddsa_pk; 320 321 eddsa_convert(pk); 322 323 break; 324 } 325 326 if ((assert = fido_assert_new()) == NULL) 327 goto out; 328 329 set_wire_data(p.wire_data.body, p.wire_data.len); 330 331 get_assert(assert, p.u2f, &p.cdh, p.rp_id, p.ext, p.up, p.uv, p.pin, 332 p.cred_count, &p.cred); 333 334 /* XXX +1 on purpose */ 335 for (size_t i = 0; i <= fido_assert_count(assert); i++) { 336 verify_assert(cose_alg, 337 fido_assert_clientdata_hash_ptr(assert), 338 fido_assert_clientdata_hash_len(assert), 339 fido_assert_rp_id(assert), 340 fido_assert_authdata_ptr(assert, i), 341 fido_assert_authdata_len(assert, i), 342 fido_assert_sig_ptr(assert, i), 343 fido_assert_sig_len(assert, i), p.up, p.uv, p.ext, pk); 344 consume(fido_assert_id_ptr(assert, i), 345 fido_assert_id_len(assert, i)); 346 consume(fido_assert_user_id_ptr(assert, i), 347 fido_assert_user_id_len(assert, i)); 348 consume(fido_assert_hmac_secret_ptr(assert, i), 349 fido_assert_hmac_secret_len(assert, i)); 350 consume(fido_assert_user_icon(assert, i), 351 xstrlen(fido_assert_user_icon(assert, i))); 352 consume(fido_assert_user_name(assert, i), 353 xstrlen(fido_assert_user_name(assert, i))); 354 consume(fido_assert_user_display_name(assert, i), 355 xstrlen(fido_assert_user_display_name(assert, i))); 356 flags = fido_assert_flags(assert, i); 357 consume(&flags, sizeof(flags)); 358 sigcount = fido_assert_sigcount(assert, i); 359 consume(&sigcount, sizeof(sigcount)); 360 } 361 362 out: 363 es256_pk_free(&es256_pk); 364 rs256_pk_free(&rs256_pk); 365 eddsa_pk_free(&eddsa_pk); 366 367 fido_assert_free(&assert); 368 369 return (0); 370 } 371 372 static size_t 373 pack_dummy(uint8_t *ptr, size_t len) 374 { 375 struct param dummy; 376 uint8_t blob[16384]; 377 size_t blob_len; 378 379 memset(&dummy, 0, sizeof(dummy)); 380 381 dummy.type = 1; /* rsa */ 382 dummy.ext = FIDO_EXT_HMAC_SECRET; 383 384 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); 385 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); 386 387 dummy.cred.len = sizeof(dummy_cdh); /* XXX */ 388 dummy.cdh.len = sizeof(dummy_cdh); 389 dummy.es256.len = sizeof(dummy_es256); 390 dummy.rs256.len = sizeof(dummy_rs256); 391 dummy.eddsa.len = sizeof(dummy_eddsa); 392 dummy.wire_data.len = sizeof(dummy_wire_data_fido); 393 394 memcpy(&dummy.cred.body, &dummy_cdh, dummy.cred.len); /* XXX */ 395 memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); 396 memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, 397 dummy.wire_data.len); 398 memcpy(&dummy.es256.body, &dummy_es256, dummy.es256.len); 399 memcpy(&dummy.rs256.body, &dummy_rs256, dummy.rs256.len); 400 memcpy(&dummy.eddsa.body, &dummy_eddsa, dummy.eddsa.len); 401 402 blob_len = pack(blob, sizeof(blob), &dummy); 403 assert(blob_len != 0); 404 405 if (blob_len > len) { 406 memcpy(ptr, blob, len); 407 return (len); 408 } 409 410 memcpy(ptr, blob, blob_len); 411 412 return (blob_len); 413 } 414 415 size_t 416 LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, 417 unsigned int seed) NO_MSAN 418 { 419 struct param p; 420 uint8_t blob[16384]; 421 size_t blob_len; 422 423 (void)seed; 424 425 memset(&p, 0, sizeof(p)); 426 427 if (unpack(data, size, &p) < 0) 428 return (pack_dummy(data, maxsize)); 429 430 mutate_byte(&p.uv); 431 mutate_byte(&p.up); 432 mutate_byte(&p.u2f); 433 mutate_byte(&p.type); 434 mutate_byte(&p.cred_count); 435 436 mutate_int(&p.ext); 437 p.seed = (int)seed; 438 439 if (p.u2f & 1) { 440 p.wire_data.len = sizeof(dummy_wire_data_u2f); 441 memcpy(&p.wire_data.body, &dummy_wire_data_u2f, 442 p.wire_data.len); 443 } else { 444 p.wire_data.len = sizeof(dummy_wire_data_fido); 445 memcpy(&p.wire_data.body, &dummy_wire_data_fido, 446 p.wire_data.len); 447 } 448 449 mutate_blob(&p.wire_data); 450 mutate_blob(&p.rs256); 451 mutate_blob(&p.es256); 452 mutate_blob(&p.eddsa); 453 mutate_blob(&p.cred); 454 mutate_blob(&p.cdh); 455 456 mutate_string(p.rp_id); 457 mutate_string(p.pin); 458 459 blob_len = pack(blob, sizeof(blob), &p); 460 461 if (blob_len == 0 || blob_len > maxsize) 462 return (0); 463 464 memcpy(data, blob, blob_len); 465 466 return (blob_len); 467 } 468