xref: /freebsd/contrib/libfido2/src/config.c (revision 0afa8e065e14bb8fd338d75690e0238c00167d40)
1*0afa8e06SEd Maste /*
2*0afa8e06SEd Maste  * Copyright (c) 2020 Yubico AB. All rights reserved.
3*0afa8e06SEd Maste  * Use of this source code is governed by a BSD-style
4*0afa8e06SEd Maste  * license that can be found in the LICENSE file.
5*0afa8e06SEd Maste  */
6*0afa8e06SEd Maste 
7*0afa8e06SEd Maste #include "fido.h"
8*0afa8e06SEd Maste #include "fido/config.h"
9*0afa8e06SEd Maste #include "fido/es256.h"
10*0afa8e06SEd Maste 
11*0afa8e06SEd Maste #define CMD_ENABLE_ENTATTEST	0x01
12*0afa8e06SEd Maste #define CMD_TOGGLE_ALWAYS_UV	0x02
13*0afa8e06SEd Maste #define CMD_SET_PIN_MINLEN	0x03
14*0afa8e06SEd Maste 
15*0afa8e06SEd Maste static int
16*0afa8e06SEd Maste config_prepare_hmac(uint8_t subcmd, const cbor_item_t *item, fido_blob_t *hmac)
17*0afa8e06SEd Maste {
18*0afa8e06SEd Maste 	uint8_t prefix[32 + 2 * sizeof(uint8_t)], cbor[128];
19*0afa8e06SEd Maste 	size_t cbor_len;
20*0afa8e06SEd Maste 
21*0afa8e06SEd Maste 	memset(prefix, 0xff, sizeof(prefix));
22*0afa8e06SEd Maste 	prefix[sizeof(prefix) - 2] = CTAP_CBOR_CONFIG;
23*0afa8e06SEd Maste 	prefix[sizeof(prefix) - 1] = subcmd;
24*0afa8e06SEd Maste 
25*0afa8e06SEd Maste 	if ((cbor_len = cbor_serialize(item, cbor, sizeof(cbor))) == 0) {
26*0afa8e06SEd Maste 		fido_log_debug("%s: cbor_serialize", __func__);
27*0afa8e06SEd Maste 		return -1;
28*0afa8e06SEd Maste 	}
29*0afa8e06SEd Maste 	if ((hmac->ptr = malloc(cbor_len + sizeof(prefix))) == NULL) {
30*0afa8e06SEd Maste 		fido_log_debug("%s: malloc", __func__);
31*0afa8e06SEd Maste 		return -1;
32*0afa8e06SEd Maste 	}
33*0afa8e06SEd Maste 	memcpy(hmac->ptr, prefix, sizeof(prefix));
34*0afa8e06SEd Maste 	memcpy(hmac->ptr + sizeof(prefix), cbor, cbor_len);
35*0afa8e06SEd Maste 	hmac->len = cbor_len + sizeof(prefix);
36*0afa8e06SEd Maste 
37*0afa8e06SEd Maste 	return 0;
38*0afa8e06SEd Maste }
39*0afa8e06SEd Maste 
40*0afa8e06SEd Maste static int
41*0afa8e06SEd Maste config_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **paramv, size_t paramc,
42*0afa8e06SEd Maste     const char *pin)
43*0afa8e06SEd Maste {
44*0afa8e06SEd Maste 	cbor_item_t *argv[4];
45*0afa8e06SEd Maste 	es256_pk_t *pk = NULL;
46*0afa8e06SEd Maste 	fido_blob_t *ecdh = NULL, f, hmac;
47*0afa8e06SEd Maste 	const uint8_t cmd = CTAP_CBOR_CONFIG;
48*0afa8e06SEd Maste 	int r = FIDO_ERR_INTERNAL;
49*0afa8e06SEd Maste 
50*0afa8e06SEd Maste 	memset(&f, 0, sizeof(f));
51*0afa8e06SEd Maste 	memset(&hmac, 0, sizeof(hmac));
52*0afa8e06SEd Maste 	memset(&argv, 0, sizeof(argv));
53*0afa8e06SEd Maste 
54*0afa8e06SEd Maste 	/* subCommand */
55*0afa8e06SEd Maste 	if ((argv[0] = cbor_build_uint8(subcmd)) == NULL) {
56*0afa8e06SEd Maste 		fido_log_debug("%s: cbor encode", __func__);
57*0afa8e06SEd Maste 		goto fail;
58*0afa8e06SEd Maste 	}
59*0afa8e06SEd Maste 
60*0afa8e06SEd Maste 	/* pinProtocol, pinAuth */
61*0afa8e06SEd Maste 	if (pin != NULL || (fido_dev_supports_permissions(dev) &&
62*0afa8e06SEd Maste 	    fido_dev_has_uv(dev))) {
63*0afa8e06SEd Maste 		if ((argv[1] = cbor_flatten_vector(paramv, paramc)) == NULL) {
64*0afa8e06SEd Maste 			fido_log_debug("%s: cbor_flatten_vector", __func__);
65*0afa8e06SEd Maste 			goto fail;
66*0afa8e06SEd Maste 		}
67*0afa8e06SEd Maste 		if (config_prepare_hmac(subcmd, argv[1], &hmac) < 0) {
68*0afa8e06SEd Maste 			fido_log_debug("%s: config_prepare_hmac", __func__);
69*0afa8e06SEd Maste 			goto fail;
70*0afa8e06SEd Maste 		}
71*0afa8e06SEd Maste 		if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
72*0afa8e06SEd Maste 			fido_log_debug("%s: fido_do_ecdh", __func__);
73*0afa8e06SEd Maste 			goto fail;
74*0afa8e06SEd Maste 		}
75*0afa8e06SEd Maste 		if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin,
76*0afa8e06SEd Maste 		    NULL, &argv[3], &argv[2])) != FIDO_OK) {
77*0afa8e06SEd Maste 			fido_log_debug("%s: cbor_add_uv_params", __func__);
78*0afa8e06SEd Maste 			goto fail;
79*0afa8e06SEd Maste 		}
80*0afa8e06SEd Maste 	}
81*0afa8e06SEd Maste 
82*0afa8e06SEd Maste 	/* framing and transmission */
83*0afa8e06SEd Maste 	if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
84*0afa8e06SEd Maste 	    fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
85*0afa8e06SEd Maste 		fido_log_debug("%s: fido_tx", __func__);
86*0afa8e06SEd Maste 		r = FIDO_ERR_TX;
87*0afa8e06SEd Maste 		goto fail;
88*0afa8e06SEd Maste 	}
89*0afa8e06SEd Maste 
90*0afa8e06SEd Maste 	r = FIDO_OK;
91*0afa8e06SEd Maste fail:
92*0afa8e06SEd Maste 	cbor_vector_free(argv, nitems(argv));
93*0afa8e06SEd Maste 	es256_pk_free(&pk);
94*0afa8e06SEd Maste 	fido_blob_free(&ecdh);
95*0afa8e06SEd Maste 	free(f.ptr);
96*0afa8e06SEd Maste 	free(hmac.ptr);
97*0afa8e06SEd Maste 
98*0afa8e06SEd Maste 	return r;
99*0afa8e06SEd Maste }
100*0afa8e06SEd Maste 
101*0afa8e06SEd Maste static int
102*0afa8e06SEd Maste config_enable_entattest_wait(fido_dev_t *dev, const char *pin, int ms)
103*0afa8e06SEd Maste {
104*0afa8e06SEd Maste 	int r;
105*0afa8e06SEd Maste 
106*0afa8e06SEd Maste 	if ((r = config_tx(dev, CMD_ENABLE_ENTATTEST, NULL, 0, pin)) != FIDO_OK)
107*0afa8e06SEd Maste 		return r;
108*0afa8e06SEd Maste 
109*0afa8e06SEd Maste 	return fido_rx_cbor_status(dev, ms);
110*0afa8e06SEd Maste }
111*0afa8e06SEd Maste 
112*0afa8e06SEd Maste int
113*0afa8e06SEd Maste fido_dev_enable_entattest(fido_dev_t *dev, const char *pin)
114*0afa8e06SEd Maste {
115*0afa8e06SEd Maste 	return (config_enable_entattest_wait(dev, pin, -1));
116*0afa8e06SEd Maste }
117*0afa8e06SEd Maste 
118*0afa8e06SEd Maste static int
119*0afa8e06SEd Maste config_toggle_always_uv_wait(fido_dev_t *dev, const char *pin, int ms)
120*0afa8e06SEd Maste {
121*0afa8e06SEd Maste 	int r;
122*0afa8e06SEd Maste 
123*0afa8e06SEd Maste 	if ((r = config_tx(dev, CMD_TOGGLE_ALWAYS_UV, NULL, 0, pin)) != FIDO_OK)
124*0afa8e06SEd Maste 		return r;
125*0afa8e06SEd Maste 
126*0afa8e06SEd Maste 	return (fido_rx_cbor_status(dev, ms));
127*0afa8e06SEd Maste }
128*0afa8e06SEd Maste 
129*0afa8e06SEd Maste int
130*0afa8e06SEd Maste fido_dev_toggle_always_uv(fido_dev_t *dev, const char *pin)
131*0afa8e06SEd Maste {
132*0afa8e06SEd Maste 	return config_toggle_always_uv_wait(dev, pin, -1);
133*0afa8e06SEd Maste }
134*0afa8e06SEd Maste 
135*0afa8e06SEd Maste static int
136*0afa8e06SEd Maste config_pin_minlen_tx(fido_dev_t *dev, size_t len, bool force, const char *pin)
137*0afa8e06SEd Maste {
138*0afa8e06SEd Maste 	cbor_item_t *argv[3];
139*0afa8e06SEd Maste 	int r;
140*0afa8e06SEd Maste 
141*0afa8e06SEd Maste 	memset(argv, 0, sizeof(argv));
142*0afa8e06SEd Maste 
143*0afa8e06SEd Maste 	if ((!len && !force) || len > UINT8_MAX) {
144*0afa8e06SEd Maste 		r = FIDO_ERR_INVALID_ARGUMENT;
145*0afa8e06SEd Maste 		goto fail;
146*0afa8e06SEd Maste 	}
147*0afa8e06SEd Maste 	if (len && (argv[0] = cbor_build_uint8((uint8_t)len)) == NULL) {
148*0afa8e06SEd Maste 		fido_log_debug("%s: cbor_encode_uint8", __func__);
149*0afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
150*0afa8e06SEd Maste 		goto fail;
151*0afa8e06SEd Maste 	}
152*0afa8e06SEd Maste 	if (force && (argv[2] = cbor_build_bool(true)) == NULL) {
153*0afa8e06SEd Maste 		fido_log_debug("%s: cbor_build_bool", __func__);
154*0afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
155*0afa8e06SEd Maste 		goto fail;
156*0afa8e06SEd Maste 	}
157*0afa8e06SEd Maste 	if ((r = config_tx(dev, CMD_SET_PIN_MINLEN, argv, nitems(argv),
158*0afa8e06SEd Maste 	    pin)) != FIDO_OK) {
159*0afa8e06SEd Maste 		fido_log_debug("%s: config_tx", __func__);
160*0afa8e06SEd Maste 		goto fail;
161*0afa8e06SEd Maste 	}
162*0afa8e06SEd Maste 
163*0afa8e06SEd Maste fail:
164*0afa8e06SEd Maste 	cbor_vector_free(argv, nitems(argv));
165*0afa8e06SEd Maste 
166*0afa8e06SEd Maste 	return r;
167*0afa8e06SEd Maste }
168*0afa8e06SEd Maste 
169*0afa8e06SEd Maste static int
170*0afa8e06SEd Maste config_pin_minlen(fido_dev_t *dev, size_t len, bool force, const char *pin,
171*0afa8e06SEd Maste     int ms)
172*0afa8e06SEd Maste {
173*0afa8e06SEd Maste 	int r;
174*0afa8e06SEd Maste 
175*0afa8e06SEd Maste 	if ((r = config_pin_minlen_tx(dev, len, force, pin)) != FIDO_OK)
176*0afa8e06SEd Maste 		return r;
177*0afa8e06SEd Maste 
178*0afa8e06SEd Maste 	return fido_rx_cbor_status(dev, ms);
179*0afa8e06SEd Maste }
180*0afa8e06SEd Maste 
181*0afa8e06SEd Maste int
182*0afa8e06SEd Maste fido_dev_set_pin_minlen(fido_dev_t *dev, size_t len, const char *pin)
183*0afa8e06SEd Maste {
184*0afa8e06SEd Maste 	return config_pin_minlen(dev, len, false, pin, -1);
185*0afa8e06SEd Maste }
186*0afa8e06SEd Maste 
187*0afa8e06SEd Maste int
188*0afa8e06SEd Maste fido_dev_force_pin_change(fido_dev_t *dev, const char *pin)
189*0afa8e06SEd Maste {
190*0afa8e06SEd Maste 	return config_pin_minlen(dev, 0, true, pin, -1);
191*0afa8e06SEd Maste }
192