1 /* 2 * Copyright (c) 2020 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 "large blob" operation. */ 20 struct param { 21 char pin[MAXSTR]; 22 int seed; 23 struct blob key; 24 struct blob get_wiredata; 25 struct blob set_wiredata; 26 }; 27 28 /* 29 * Collection of HID reports from an authenticator issued with a FIDO2 30 * 'authenticatorLargeBlobs' 'get' command. 31 */ 32 static const uint8_t dummy_get_wiredata[] = { 33 WIREDATA_CTAP_INIT, 34 WIREDATA_CTAP_CBOR_INFO, 35 WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY 36 }; 37 38 /* 39 * Collection of HID reports from an authenticator issued with a FIDO2 40 * 'authenticatorLargeBlobs' 'set' command. 41 */ 42 static const uint8_t dummy_set_wiredata[] = { 43 WIREDATA_CTAP_INIT, 44 WIREDATA_CTAP_CBOR_INFO, 45 WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY, 46 WIREDATA_CTAP_CBOR_AUTHKEY, 47 WIREDATA_CTAP_CBOR_PINTOKEN, 48 WIREDATA_CTAP_CBOR_STATUS 49 }; 50 51 /* 52 * XXX this needs to match the encrypted blob embedded in 53 * WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY. 54 */ 55 static const uint8_t dummy_key[] = { 56 0xa9, 0x1b, 0xc4, 0xdd, 0xfc, 0x9a, 0x93, 0x79, 57 0x75, 0xba, 0xf7, 0x7f, 0x4d, 0x57, 0xfc, 0xa6, 58 0xe1, 0xf8, 0x06, 0x43, 0x23, 0x99, 0x51, 0x32, 59 0xce, 0x6e, 0x19, 0x84, 0x50, 0x13, 0x2d, 0x7b 60 }; 61 62 struct param * 63 unpack(const uint8_t *ptr, size_t len) 64 { 65 cbor_item_t *item = NULL, **v; 66 struct cbor_load_result cbor; 67 struct param *p; 68 int ok = -1; 69 70 if ((p = calloc(1, sizeof(*p))) == NULL || 71 (item = cbor_load(ptr, len, &cbor)) == NULL || 72 cbor.read != len || 73 cbor_isa_array(item) == false || 74 cbor_array_is_definite(item) == false || 75 cbor_array_size(item) != 5 || 76 (v = cbor_array_handle(item)) == NULL) 77 goto fail; 78 79 if (unpack_int(v[0], &p->seed) < 0 || 80 unpack_string(v[1], p->pin) < 0 || 81 unpack_blob(v[2], &p->key) < 0 || 82 unpack_blob(v[3], &p->get_wiredata) < 0 || 83 unpack_blob(v[4], &p->set_wiredata) < 0) 84 goto fail; 85 86 ok = 0; 87 fail: 88 if (ok < 0) { 89 free(p); 90 p = NULL; 91 } 92 93 if (item) 94 cbor_decref(&item); 95 96 return p; 97 } 98 99 size_t 100 pack(uint8_t *ptr, size_t len, const struct param *p) 101 { 102 cbor_item_t *argv[5], *array = NULL; 103 size_t cbor_alloc_len, cbor_len = 0; 104 unsigned char *cbor = NULL; 105 106 memset(argv, 0, sizeof(argv)); 107 108 if ((array = cbor_new_definite_array(5)) == NULL || 109 (argv[0] = pack_int(p->seed)) == NULL || 110 (argv[1] = pack_string(p->pin)) == NULL || 111 (argv[2] = pack_blob(&p->key)) == NULL || 112 (argv[3] = pack_blob(&p->get_wiredata)) == NULL || 113 (argv[4] = pack_blob(&p->set_wiredata)) == NULL) 114 goto fail; 115 116 for (size_t i = 0; i < 5; i++) 117 if (cbor_array_push(array, argv[i]) == false) 118 goto fail; 119 120 if ((cbor_len = cbor_serialize_alloc(array, &cbor, 121 &cbor_alloc_len)) > len) { 122 cbor_len = 0; 123 goto fail; 124 } 125 126 memcpy(ptr, cbor, cbor_len); 127 fail: 128 for (size_t i = 0; i < 5; i++) 129 if (argv[i]) 130 cbor_decref(&argv[i]); 131 132 if (array) 133 cbor_decref(&array); 134 135 free(cbor); 136 137 return cbor_len; 138 } 139 140 size_t 141 pack_dummy(uint8_t *ptr, size_t len) 142 { 143 struct param dummy; 144 uint8_t blob[4096]; 145 size_t blob_len; 146 147 memset(&dummy, 0, sizeof(dummy)); 148 149 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); 150 151 dummy.get_wiredata.len = sizeof(dummy_get_wiredata); 152 dummy.set_wiredata.len = sizeof(dummy_set_wiredata); 153 dummy.key.len = sizeof(dummy_key); 154 155 memcpy(&dummy.get_wiredata.body, &dummy_get_wiredata, 156 dummy.get_wiredata.len); 157 memcpy(&dummy.set_wiredata.body, &dummy_set_wiredata, 158 dummy.set_wiredata.len); 159 memcpy(&dummy.key.body, &dummy_key, dummy.key.len); 160 161 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); 162 163 if (blob_len > len) { 164 memcpy(ptr, blob, len); 165 return len; 166 } 167 168 memcpy(ptr, blob, blob_len); 169 170 return blob_len; 171 } 172 173 static fido_dev_t * 174 prepare_dev(void) 175 { 176 fido_dev_t *dev; 177 178 if ((dev = open_dev(0)) == NULL) 179 return NULL; 180 181 return dev; 182 } 183 184 static void 185 get_blob(const struct param *p, int array) 186 { 187 fido_dev_t *dev; 188 u_char *ptr = NULL; 189 size_t len = 0; 190 191 set_wire_data(p->get_wiredata.body, p->get_wiredata.len); 192 193 if ((dev = prepare_dev()) == NULL) 194 return; 195 196 if (array) 197 fido_dev_largeblob_get_array(dev, &ptr, &len); 198 else 199 fido_dev_largeblob_get(dev, p->key.body, p->key.len, &ptr, &len); 200 consume(ptr, len); 201 free(ptr); 202 203 fido_dev_close(dev); 204 fido_dev_free(&dev); 205 } 206 207 208 static void 209 set_blob(const struct param *p, int op) 210 { 211 fido_dev_t *dev; 212 const char *pin; 213 214 set_wire_data(p->set_wiredata.body, p->set_wiredata.len); 215 216 if ((dev = prepare_dev()) == NULL) 217 return; 218 pin = p->pin; 219 if (strlen(pin) == 0) 220 pin = NULL; 221 222 switch (op) { 223 case 0: 224 fido_dev_largeblob_remove(dev, p->key.body, p->key.len, pin); 225 break; 226 case 1: 227 /* XXX reuse p->get_wiredata as the blob to be set */ 228 fido_dev_largeblob_set(dev, p->key.body, p->key.len, 229 p->get_wiredata.body, p->get_wiredata.len, pin); 230 break; 231 case 2: 232 /* XXX reuse p->get_wiredata as the body of the cbor array */ 233 fido_dev_largeblob_set_array(dev, p->get_wiredata.body, 234 p->get_wiredata.len, pin); 235 } 236 237 fido_dev_close(dev); 238 fido_dev_free(&dev); 239 } 240 241 void 242 test(const struct param *p) 243 { 244 prng_init((unsigned int)p->seed); 245 fido_init(FIDO_DEBUG); 246 fido_set_log_handler(consume_str); 247 248 get_blob(p, 0); 249 get_blob(p, 1); 250 set_blob(p, 0); 251 set_blob(p, 1); 252 set_blob(p, 2); 253 } 254 255 void 256 mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN 257 { 258 if (flags & MUTATE_SEED) 259 p->seed = (int)seed; 260 261 if (flags & MUTATE_PARAM) { 262 mutate_blob(&p->key); 263 mutate_string(p->pin); 264 } 265 266 if (flags & MUTATE_WIREDATA) { 267 mutate_blob(&p->get_wiredata); 268 mutate_blob(&p->set_wiredata); 269 } 270 } 271