195dbdf32Schristos /*
295dbdf32Schristos * Copyright (c) 2020 Yubico AB. All rights reserved.
395dbdf32Schristos * Use of this source code is governed by a BSD-style
495dbdf32Schristos * license that can be found in the LICENSE file.
5*2d40c451Schristos * SPDX-License-Identifier: BSD-2-Clause
695dbdf32Schristos */
795dbdf32Schristos
895dbdf32Schristos #include <assert.h>
995dbdf32Schristos #include <stdint.h>
1095dbdf32Schristos #include <stdio.h>
1195dbdf32Schristos #include <stdlib.h>
1295dbdf32Schristos #include <string.h>
1395dbdf32Schristos
1495dbdf32Schristos #include "mutator_aux.h"
1595dbdf32Schristos #include "wiredata_fido2.h"
1695dbdf32Schristos #include "dummy.h"
1795dbdf32Schristos
1895dbdf32Schristos #include "../openbsd-compat/openbsd-compat.h"
1995dbdf32Schristos
2095dbdf32Schristos /* Parameter set defining a FIDO2 "large blob" operation. */
2195dbdf32Schristos struct param {
2295dbdf32Schristos char pin[MAXSTR];
2395dbdf32Schristos int seed;
2495dbdf32Schristos struct blob key;
2595dbdf32Schristos struct blob get_wiredata;
2695dbdf32Schristos struct blob set_wiredata;
2795dbdf32Schristos };
2895dbdf32Schristos
2995dbdf32Schristos /*
3095dbdf32Schristos * Collection of HID reports from an authenticator issued with a FIDO2
3195dbdf32Schristos * 'authenticatorLargeBlobs' 'get' command.
3295dbdf32Schristos */
3395dbdf32Schristos static const uint8_t dummy_get_wiredata[] = {
3495dbdf32Schristos WIREDATA_CTAP_INIT,
3595dbdf32Schristos WIREDATA_CTAP_CBOR_INFO,
3695dbdf32Schristos WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY
3795dbdf32Schristos };
3895dbdf32Schristos
3995dbdf32Schristos /*
4095dbdf32Schristos * Collection of HID reports from an authenticator issued with a FIDO2
4195dbdf32Schristos * 'authenticatorLargeBlobs' 'set' command.
4295dbdf32Schristos */
4395dbdf32Schristos static const uint8_t dummy_set_wiredata[] = {
4495dbdf32Schristos WIREDATA_CTAP_INIT,
4595dbdf32Schristos WIREDATA_CTAP_CBOR_INFO,
4695dbdf32Schristos WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY,
4795dbdf32Schristos WIREDATA_CTAP_CBOR_AUTHKEY,
4895dbdf32Schristos WIREDATA_CTAP_CBOR_PINTOKEN,
4995dbdf32Schristos WIREDATA_CTAP_CBOR_STATUS
5095dbdf32Schristos };
5195dbdf32Schristos
5295dbdf32Schristos /*
5395dbdf32Schristos * XXX this needs to match the encrypted blob embedded in
5495dbdf32Schristos * WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY.
5595dbdf32Schristos */
5695dbdf32Schristos static const uint8_t dummy_key[] = {
5795dbdf32Schristos 0xa9, 0x1b, 0xc4, 0xdd, 0xfc, 0x9a, 0x93, 0x79,
5895dbdf32Schristos 0x75, 0xba, 0xf7, 0x7f, 0x4d, 0x57, 0xfc, 0xa6,
5995dbdf32Schristos 0xe1, 0xf8, 0x06, 0x43, 0x23, 0x99, 0x51, 0x32,
6095dbdf32Schristos 0xce, 0x6e, 0x19, 0x84, 0x50, 0x13, 0x2d, 0x7b
6195dbdf32Schristos };
6295dbdf32Schristos
6395dbdf32Schristos struct param *
unpack(const uint8_t * ptr,size_t len)6495dbdf32Schristos unpack(const uint8_t *ptr, size_t len)
6595dbdf32Schristos {
6695dbdf32Schristos cbor_item_t *item = NULL, **v;
6795dbdf32Schristos struct cbor_load_result cbor;
6895dbdf32Schristos struct param *p;
6995dbdf32Schristos int ok = -1;
7095dbdf32Schristos
7195dbdf32Schristos if ((p = calloc(1, sizeof(*p))) == NULL ||
7295dbdf32Schristos (item = cbor_load(ptr, len, &cbor)) == NULL ||
7395dbdf32Schristos cbor.read != len ||
7495dbdf32Schristos cbor_isa_array(item) == false ||
7595dbdf32Schristos cbor_array_is_definite(item) == false ||
7695dbdf32Schristos cbor_array_size(item) != 5 ||
7795dbdf32Schristos (v = cbor_array_handle(item)) == NULL)
7895dbdf32Schristos goto fail;
7995dbdf32Schristos
8095dbdf32Schristos if (unpack_int(v[0], &p->seed) < 0 ||
8195dbdf32Schristos unpack_string(v[1], p->pin) < 0 ||
8295dbdf32Schristos unpack_blob(v[2], &p->key) < 0 ||
8395dbdf32Schristos unpack_blob(v[3], &p->get_wiredata) < 0 ||
8495dbdf32Schristos unpack_blob(v[4], &p->set_wiredata) < 0)
8595dbdf32Schristos goto fail;
8695dbdf32Schristos
8795dbdf32Schristos ok = 0;
8895dbdf32Schristos fail:
8995dbdf32Schristos if (ok < 0) {
9095dbdf32Schristos free(p);
9195dbdf32Schristos p = NULL;
9295dbdf32Schristos }
9395dbdf32Schristos
9495dbdf32Schristos if (item)
9595dbdf32Schristos cbor_decref(&item);
9695dbdf32Schristos
9795dbdf32Schristos return p;
9895dbdf32Schristos }
9995dbdf32Schristos
10095dbdf32Schristos size_t
pack(uint8_t * ptr,size_t len,const struct param * p)10195dbdf32Schristos pack(uint8_t *ptr, size_t len, const struct param *p)
10295dbdf32Schristos {
10395dbdf32Schristos cbor_item_t *argv[5], *array = NULL;
10495dbdf32Schristos size_t cbor_alloc_len, cbor_len = 0;
10595dbdf32Schristos unsigned char *cbor = NULL;
10695dbdf32Schristos
10795dbdf32Schristos memset(argv, 0, sizeof(argv));
10895dbdf32Schristos
10995dbdf32Schristos if ((array = cbor_new_definite_array(5)) == NULL ||
11095dbdf32Schristos (argv[0] = pack_int(p->seed)) == NULL ||
11195dbdf32Schristos (argv[1] = pack_string(p->pin)) == NULL ||
11295dbdf32Schristos (argv[2] = pack_blob(&p->key)) == NULL ||
11395dbdf32Schristos (argv[3] = pack_blob(&p->get_wiredata)) == NULL ||
11495dbdf32Schristos (argv[4] = pack_blob(&p->set_wiredata)) == NULL)
11595dbdf32Schristos goto fail;
11695dbdf32Schristos
11795dbdf32Schristos for (size_t i = 0; i < 5; i++)
11895dbdf32Schristos if (cbor_array_push(array, argv[i]) == false)
11995dbdf32Schristos goto fail;
12095dbdf32Schristos
12195dbdf32Schristos if ((cbor_len = cbor_serialize_alloc(array, &cbor,
122*2d40c451Schristos &cbor_alloc_len)) == 0 || cbor_len > len) {
12395dbdf32Schristos cbor_len = 0;
12495dbdf32Schristos goto fail;
12595dbdf32Schristos }
12695dbdf32Schristos
12795dbdf32Schristos memcpy(ptr, cbor, cbor_len);
12895dbdf32Schristos fail:
12995dbdf32Schristos for (size_t i = 0; i < 5; i++)
13095dbdf32Schristos if (argv[i])
13195dbdf32Schristos cbor_decref(&argv[i]);
13295dbdf32Schristos
13395dbdf32Schristos if (array)
13495dbdf32Schristos cbor_decref(&array);
13595dbdf32Schristos
13695dbdf32Schristos free(cbor);
13795dbdf32Schristos
13895dbdf32Schristos return cbor_len;
13995dbdf32Schristos }
14095dbdf32Schristos
14195dbdf32Schristos size_t
pack_dummy(uint8_t * ptr,size_t len)14295dbdf32Schristos pack_dummy(uint8_t *ptr, size_t len)
14395dbdf32Schristos {
14495dbdf32Schristos struct param dummy;
145*2d40c451Schristos uint8_t blob[MAXCORPUS];
14695dbdf32Schristos size_t blob_len;
14795dbdf32Schristos
14895dbdf32Schristos memset(&dummy, 0, sizeof(dummy));
14995dbdf32Schristos
15095dbdf32Schristos strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
15195dbdf32Schristos
15295dbdf32Schristos dummy.get_wiredata.len = sizeof(dummy_get_wiredata);
15395dbdf32Schristos dummy.set_wiredata.len = sizeof(dummy_set_wiredata);
15495dbdf32Schristos dummy.key.len = sizeof(dummy_key);
15595dbdf32Schristos
15695dbdf32Schristos memcpy(&dummy.get_wiredata.body, &dummy_get_wiredata,
15795dbdf32Schristos dummy.get_wiredata.len);
15895dbdf32Schristos memcpy(&dummy.set_wiredata.body, &dummy_set_wiredata,
15995dbdf32Schristos dummy.set_wiredata.len);
16095dbdf32Schristos memcpy(&dummy.key.body, &dummy_key, dummy.key.len);
16195dbdf32Schristos
16295dbdf32Schristos assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
16395dbdf32Schristos
16495dbdf32Schristos if (blob_len > len) {
16595dbdf32Schristos memcpy(ptr, blob, len);
16695dbdf32Schristos return len;
16795dbdf32Schristos }
16895dbdf32Schristos
16995dbdf32Schristos memcpy(ptr, blob, blob_len);
17095dbdf32Schristos
17195dbdf32Schristos return blob_len;
17295dbdf32Schristos }
17395dbdf32Schristos
17495dbdf32Schristos static fido_dev_t *
prepare_dev(void)17595dbdf32Schristos prepare_dev(void)
17695dbdf32Schristos {
17795dbdf32Schristos fido_dev_t *dev;
17895dbdf32Schristos
17995dbdf32Schristos if ((dev = open_dev(0)) == NULL)
18095dbdf32Schristos return NULL;
18195dbdf32Schristos
18295dbdf32Schristos return dev;
18395dbdf32Schristos }
18495dbdf32Schristos
18595dbdf32Schristos static void
get_blob(const struct param * p,int array)18695dbdf32Schristos get_blob(const struct param *p, int array)
18795dbdf32Schristos {
18895dbdf32Schristos fido_dev_t *dev;
18995dbdf32Schristos u_char *ptr = NULL;
19095dbdf32Schristos size_t len = 0;
19195dbdf32Schristos
19295dbdf32Schristos set_wire_data(p->get_wiredata.body, p->get_wiredata.len);
19395dbdf32Schristos
19495dbdf32Schristos if ((dev = prepare_dev()) == NULL)
19595dbdf32Schristos return;
19695dbdf32Schristos
19795dbdf32Schristos if (array)
19895dbdf32Schristos fido_dev_largeblob_get_array(dev, &ptr, &len);
19995dbdf32Schristos else
20095dbdf32Schristos fido_dev_largeblob_get(dev, p->key.body, p->key.len, &ptr, &len);
20195dbdf32Schristos consume(ptr, len);
20295dbdf32Schristos free(ptr);
20395dbdf32Schristos
20495dbdf32Schristos fido_dev_close(dev);
20595dbdf32Schristos fido_dev_free(&dev);
20695dbdf32Schristos }
20795dbdf32Schristos
20895dbdf32Schristos
20995dbdf32Schristos static void
set_blob(const struct param * p,int op)21095dbdf32Schristos set_blob(const struct param *p, int op)
21195dbdf32Schristos {
21295dbdf32Schristos fido_dev_t *dev;
21395dbdf32Schristos const char *pin;
21495dbdf32Schristos
21595dbdf32Schristos set_wire_data(p->set_wiredata.body, p->set_wiredata.len);
21695dbdf32Schristos
21795dbdf32Schristos if ((dev = prepare_dev()) == NULL)
21895dbdf32Schristos return;
21995dbdf32Schristos pin = p->pin;
22095dbdf32Schristos if (strlen(pin) == 0)
22195dbdf32Schristos pin = NULL;
22295dbdf32Schristos
22395dbdf32Schristos switch (op) {
22495dbdf32Schristos case 0:
22595dbdf32Schristos fido_dev_largeblob_remove(dev, p->key.body, p->key.len, pin);
22695dbdf32Schristos break;
22795dbdf32Schristos case 1:
22895dbdf32Schristos /* XXX reuse p->get_wiredata as the blob to be set */
22995dbdf32Schristos fido_dev_largeblob_set(dev, p->key.body, p->key.len,
23095dbdf32Schristos p->get_wiredata.body, p->get_wiredata.len, pin);
23195dbdf32Schristos break;
23295dbdf32Schristos case 2:
23395dbdf32Schristos /* XXX reuse p->get_wiredata as the body of the cbor array */
23495dbdf32Schristos fido_dev_largeblob_set_array(dev, p->get_wiredata.body,
23595dbdf32Schristos p->get_wiredata.len, pin);
23695dbdf32Schristos }
23795dbdf32Schristos
23895dbdf32Schristos fido_dev_close(dev);
23995dbdf32Schristos fido_dev_free(&dev);
24095dbdf32Schristos }
24195dbdf32Schristos
24295dbdf32Schristos void
test(const struct param * p)24395dbdf32Schristos test(const struct param *p)
24495dbdf32Schristos {
24595dbdf32Schristos prng_init((unsigned int)p->seed);
246*2d40c451Schristos fuzz_clock_reset();
24795dbdf32Schristos fido_init(FIDO_DEBUG);
24895dbdf32Schristos fido_set_log_handler(consume_str);
24995dbdf32Schristos
25095dbdf32Schristos get_blob(p, 0);
25195dbdf32Schristos get_blob(p, 1);
25295dbdf32Schristos set_blob(p, 0);
25395dbdf32Schristos set_blob(p, 1);
25495dbdf32Schristos set_blob(p, 2);
25595dbdf32Schristos }
25695dbdf32Schristos
25795dbdf32Schristos void
mutate(struct param * p,unsigned int seed,unsigned int flags)25895dbdf32Schristos mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
25995dbdf32Schristos {
26095dbdf32Schristos if (flags & MUTATE_SEED)
26195dbdf32Schristos p->seed = (int)seed;
26295dbdf32Schristos
26395dbdf32Schristos if (flags & MUTATE_PARAM) {
26495dbdf32Schristos mutate_blob(&p->key);
26595dbdf32Schristos mutate_string(p->pin);
26695dbdf32Schristos }
26795dbdf32Schristos
26895dbdf32Schristos if (flags & MUTATE_WIREDATA) {
26995dbdf32Schristos mutate_blob(&p->get_wiredata);
27095dbdf32Schristos mutate_blob(&p->set_wiredata);
27195dbdf32Schristos }
27295dbdf32Schristos }
273