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