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 #define TAG_U2F 0x01 22 #define TAG_TYPE 0x02 23 #define TAG_CDH 0x03 24 #define TAG_RP_ID 0x04 25 #define TAG_RP_NAME 0x05 26 #define TAG_USER_ID 0x06 27 #define TAG_USER_NAME 0x07 28 #define TAG_USER_NICK 0x08 29 #define TAG_USER_ICON 0x09 30 #define TAG_EXT 0x0a 31 #define TAG_SEED 0x0b 32 #define TAG_RK 0x0c 33 #define TAG_UV 0x0d 34 #define TAG_PIN 0x0e 35 #define TAG_WIRE_DATA 0x0f 36 #define TAG_EXCL_COUNT 0x10 37 #define TAG_EXCL_CRED 0x11 38 39 /* Parameter set defining a FIDO2 make credential operation. */ 40 struct param { 41 char pin[MAXSTR]; 42 char rp_id[MAXSTR]; 43 char rp_name[MAXSTR]; 44 char user_icon[MAXSTR]; 45 char user_name[MAXSTR]; 46 char user_nick[MAXSTR]; 47 int ext; 48 int seed; 49 struct blob cdh; 50 struct blob excl_cred; 51 struct blob user_id; 52 struct blob wire_data; 53 uint8_t excl_count; 54 uint8_t rk; 55 uint8_t type; 56 uint8_t u2f; 57 uint8_t uv; 58 }; 59 60 /* 61 * Collection of HID reports from an authenticator issued with a FIDO2 62 * make credential using the example parameters above. 63 */ 64 static const uint8_t dummy_wire_data_fido[] = { 65 WIREDATA_CTAP_INIT, 66 WIREDATA_CTAP_CBOR_INFO, 67 WIREDATA_CTAP_CBOR_AUTHKEY, 68 WIREDATA_CTAP_CBOR_PINTOKEN, 69 WIREDATA_CTAP_KEEPALIVE, 70 WIREDATA_CTAP_KEEPALIVE, 71 WIREDATA_CTAP_KEEPALIVE, 72 WIREDATA_CTAP_CBOR_CRED, 73 }; 74 75 /* 76 * Collection of HID reports from an authenticator issued with a U2F 77 * registration using the example parameters above. 78 */ 79 static const uint8_t dummy_wire_data_u2f[] = { 80 WIREDATA_CTAP_INIT, 81 WIREDATA_CTAP_U2F_6985, 82 WIREDATA_CTAP_U2F_6985, 83 WIREDATA_CTAP_U2F_6985, 84 WIREDATA_CTAP_U2F_6985, 85 WIREDATA_CTAP_U2F_6985, 86 WIREDATA_CTAP_U2F_REGISTER, 87 }; 88 89 int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 90 size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 91 92 static int 93 unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN 94 { 95 uint8_t **pp = (void *)&ptr; 96 97 if (unpack_byte(TAG_RK, pp, &len, &p->rk) < 0 || 98 unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || 99 unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || 100 unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 || 101 unpack_byte(TAG_EXCL_COUNT, pp, &len, &p->excl_count) < 0 || 102 unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || 103 unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || 104 unpack_string(TAG_RP_NAME, pp, &len, p->rp_name) < 0 || 105 unpack_string(TAG_USER_ICON, pp, &len, p->user_icon) < 0 || 106 unpack_string(TAG_USER_NAME, pp, &len, p->user_name) < 0 || 107 unpack_string(TAG_USER_NICK, pp, &len, p->user_nick) < 0 || 108 unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || 109 unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || 110 unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0 || 111 unpack_blob(TAG_USER_ID, pp, &len, &p->user_id) < 0 || 112 unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || 113 unpack_blob(TAG_EXCL_CRED, pp, &len, &p->excl_cred) < 0) 114 return (-1); 115 116 return (0); 117 } 118 119 static size_t 120 pack(uint8_t *ptr, size_t len, const struct param *p) 121 { 122 const size_t max = len; 123 124 if (pack_byte(TAG_RK, &ptr, &len, p->rk) < 0 || 125 pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || 126 pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || 127 pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 || 128 pack_byte(TAG_EXCL_COUNT, &ptr, &len, p->excl_count) < 0 || 129 pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || 130 pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || 131 pack_string(TAG_RP_NAME, &ptr, &len, p->rp_name) < 0 || 132 pack_string(TAG_USER_ICON, &ptr, &len, p->user_icon) < 0 || 133 pack_string(TAG_USER_NAME, &ptr, &len, p->user_name) < 0 || 134 pack_string(TAG_USER_NICK, &ptr, &len, p->user_nick) < 0 || 135 pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || 136 pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || 137 pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0 || 138 pack_blob(TAG_USER_ID, &ptr, &len, &p->user_id) < 0 || 139 pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || 140 pack_blob(TAG_EXCL_CRED, &ptr, &len, &p->excl_cred) < 0) 141 return (0); 142 143 return (max - len); 144 } 145 146 static size_t 147 input_len(int max) 148 { 149 return (5 * len_byte() + 6 * len_string(max) + 2 * len_int() + 150 4 * len_blob(max)); 151 } 152 153 static void 154 make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh, 155 const char *rp_id, const char *rp_name, struct blob *user_id, 156 const char *user_name, const char *user_nick, const char *user_icon, 157 int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count, 158 struct blob *excl_cred) 159 { 160 fido_dev_t *dev; 161 fido_dev_io_t io; 162 163 memset(&io, 0, sizeof(io)); 164 165 io.open = dev_open; 166 io.close = dev_close; 167 io.read = dev_read; 168 io.write = dev_write; 169 170 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, 171 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { 172 fido_dev_free(&dev); 173 return; 174 } 175 176 if (u2f & 1) 177 fido_dev_force_u2f(dev); 178 179 for (uint8_t i = 0; i < excl_count; i++) 180 fido_cred_exclude(cred, excl_cred->body, excl_cred->len); 181 182 fido_cred_set_type(cred, type); 183 fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len); 184 fido_cred_set_rp(cred, rp_id, rp_name); 185 fido_cred_set_user(cred, user_id->body, user_id->len, user_name, 186 user_nick, user_icon); 187 fido_cred_set_extensions(cred, ext); 188 if (rk & 1) 189 fido_cred_set_rk(cred, FIDO_OPT_TRUE); 190 if (uv & 1) 191 fido_cred_set_uv(cred, FIDO_OPT_TRUE); 192 if (user_id->len) 193 fido_cred_set_prot(cred, user_id->body[0] & 0x03); 194 195 fido_dev_make_cred(dev, cred, u2f & 1 ? NULL : pin); 196 197 fido_dev_cancel(dev); 198 fido_dev_close(dev); 199 fido_dev_free(&dev); 200 } 201 202 static void 203 verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, 204 const char *rp_id, const char *rp_name, const unsigned char *authdata_ptr, 205 size_t authdata_len, int ext, uint8_t rk, uint8_t uv, 206 const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr, 207 size_t sig_len, const char *fmt, int prot) 208 { 209 fido_cred_t *cred; 210 uint8_t flags; 211 212 if ((cred = fido_cred_new()) == NULL) 213 return; 214 215 fido_cred_set_type(cred, type); 216 fido_cred_set_clientdata_hash(cred, cdh_ptr, cdh_len); 217 fido_cred_set_rp(cred, rp_id, rp_name); 218 if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK) 219 fido_cred_set_authdata_raw(cred, authdata_ptr, authdata_len); 220 fido_cred_set_extensions(cred, ext); 221 fido_cred_set_x509(cred, x5c_ptr, x5c_len); 222 fido_cred_set_sig(cred, sig_ptr, sig_len); 223 fido_cred_set_prot(cred, prot); 224 225 if (rk & 1) 226 fido_cred_set_rk(cred, FIDO_OPT_TRUE); 227 if (uv & 1) 228 fido_cred_set_uv(cred, FIDO_OPT_TRUE); 229 if (fmt) 230 fido_cred_set_fmt(cred, fmt); 231 232 fido_cred_verify(cred); 233 fido_cred_verify_self(cred); 234 235 consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); 236 consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); 237 consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred)); 238 consume(fido_cred_user_name(cred), xstrlen(fido_cred_user_name(cred))); 239 consume(fido_cred_display_name(cred), 240 xstrlen(fido_cred_display_name(cred))); 241 242 flags = fido_cred_flags(cred); 243 consume(&flags, sizeof(flags)); 244 type = fido_cred_type(cred); 245 consume(&type, sizeof(type)); 246 247 fido_cred_free(&cred); 248 } 249 250 int 251 LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 252 { 253 struct param p; 254 fido_cred_t *cred = NULL; 255 int cose_alg = 0; 256 257 memset(&p, 0, sizeof(p)); 258 259 if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) || 260 unpack(data, size, &p) < 0) 261 return (0); 262 263 prng_init((unsigned int)p.seed); 264 265 fido_init(FIDO_DEBUG); 266 fido_set_log_handler(consume_str); 267 268 if ((cred = fido_cred_new()) == NULL) 269 return (0); 270 271 set_wire_data(p.wire_data.body, p.wire_data.len); 272 273 switch (p.type & 3) { 274 case 0: 275 cose_alg = COSE_ES256; 276 break; 277 case 1: 278 cose_alg = COSE_RS256; 279 break; 280 default: 281 cose_alg = COSE_EDDSA; 282 break; 283 } 284 285 make_cred(cred, p.u2f, cose_alg, &p.cdh, p.rp_id, p.rp_name, 286 &p.user_id, p.user_name, p.user_nick, p.user_icon, p.ext, p.rk, 287 p.uv, p.pin, p.excl_count, &p.excl_cred); 288 289 verify_cred(cose_alg, 290 fido_cred_clientdata_hash_ptr(cred), 291 fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred), 292 fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred), 293 fido_cred_authdata_len(cred), p.ext, p.rk, p.uv, 294 fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), 295 fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), 296 fido_cred_fmt(cred), fido_cred_prot(cred)); 297 298 fido_cred_free(&cred); 299 300 return (0); 301 } 302 303 static size_t 304 pack_dummy(uint8_t *ptr, size_t len) 305 { 306 struct param dummy; 307 uint8_t blob[16384]; 308 size_t blob_len; 309 310 memset(&dummy, 0, sizeof(dummy)); 311 312 dummy.type = 1; 313 dummy.ext = FIDO_EXT_HMAC_SECRET; 314 315 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); 316 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); 317 strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name)); 318 strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon)); 319 strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name)); 320 strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick)); 321 322 dummy.cdh.len = sizeof(dummy_cdh); 323 dummy.user_id.len = sizeof(dummy_user_id); 324 dummy.wire_data.len = sizeof(dummy_wire_data_fido); 325 326 memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); 327 memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len); 328 memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, 329 dummy.wire_data.len); 330 331 blob_len = pack(blob, sizeof(blob), &dummy); 332 assert(blob_len != 0); 333 334 if (blob_len > len) { 335 memcpy(ptr, blob, len); 336 return (len); 337 } 338 339 memcpy(ptr, blob, blob_len); 340 341 return (blob_len); 342 } 343 344 size_t 345 LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, 346 unsigned int seed) NO_MSAN 347 { 348 struct param p; 349 uint8_t blob[16384]; 350 size_t blob_len; 351 352 memset(&p, 0, sizeof(p)); 353 354 if (unpack(data, size, &p) < 0) 355 return (pack_dummy(data, maxsize)); 356 357 mutate_byte(&p.rk); 358 mutate_byte(&p.type); 359 mutate_byte(&p.u2f); 360 mutate_byte(&p.uv); 361 mutate_byte(&p.excl_count); 362 363 mutate_int(&p.ext); 364 p.seed = (int)seed; 365 366 mutate_blob(&p.cdh); 367 mutate_blob(&p.user_id); 368 369 if (p.u2f & 1) { 370 p.wire_data.len = sizeof(dummy_wire_data_u2f); 371 memcpy(&p.wire_data.body, &dummy_wire_data_u2f, 372 p.wire_data.len); 373 } else { 374 p.wire_data.len = sizeof(dummy_wire_data_fido); 375 memcpy(&p.wire_data.body, &dummy_wire_data_fido, 376 p.wire_data.len); 377 } 378 379 mutate_blob(&p.wire_data); 380 mutate_blob(&p.excl_cred); 381 382 mutate_string(p.pin); 383 mutate_string(p.user_icon); 384 mutate_string(p.user_name); 385 mutate_string(p.user_nick); 386 mutate_string(p.rp_id); 387 mutate_string(p.rp_name); 388 389 blob_len = pack(blob, sizeof(blob), &p); 390 391 if (blob_len == 0 || blob_len > maxsize) 392 return (0); 393 394 memcpy(data, blob, blob_len); 395 396 return (blob_len); 397 } 398