xref: /freebsd/contrib/libfido2/src/pin.c (revision 2ccfa855)
10afa8e06SEd Maste /*
2*2ccfa855SEd Maste  * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
30afa8e06SEd Maste  * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste  * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste  * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste  */
70afa8e06SEd Maste 
80afa8e06SEd Maste #include <openssl/sha.h>
90afa8e06SEd Maste #include "fido.h"
100afa8e06SEd Maste #include "fido/es256.h"
110afa8e06SEd Maste 
120afa8e06SEd Maste #define CTAP21_UV_TOKEN_PERM_MAKECRED	0x01
130afa8e06SEd Maste #define CTAP21_UV_TOKEN_PERM_ASSERT	0x02
140afa8e06SEd Maste #define CTAP21_UV_TOKEN_PERM_CRED_MGMT	0x04
150afa8e06SEd Maste #define CTAP21_UV_TOKEN_PERM_BIO	0x08
160afa8e06SEd Maste #define CTAP21_UV_TOKEN_PERM_LARGEBLOB	0x10
170afa8e06SEd Maste #define CTAP21_UV_TOKEN_PERM_CONFIG	0x20
180afa8e06SEd Maste 
190afa8e06SEd Maste int
fido_sha256(fido_blob_t * digest,const u_char * data,size_t data_len)200afa8e06SEd Maste fido_sha256(fido_blob_t *digest, const u_char *data, size_t data_len)
210afa8e06SEd Maste {
220afa8e06SEd Maste 	if ((digest->ptr = calloc(1, SHA256_DIGEST_LENGTH)) == NULL)
230afa8e06SEd Maste 		return (-1);
240afa8e06SEd Maste 
250afa8e06SEd Maste 	digest->len = SHA256_DIGEST_LENGTH;
260afa8e06SEd Maste 
270afa8e06SEd Maste 	if (SHA256(data, data_len, digest->ptr) != digest->ptr) {
280afa8e06SEd Maste 		fido_blob_reset(digest);
290afa8e06SEd Maste 		return (-1);
300afa8e06SEd Maste 	}
310afa8e06SEd Maste 
320afa8e06SEd Maste 	return (0);
330afa8e06SEd Maste }
340afa8e06SEd Maste 
350afa8e06SEd Maste static int
pin_sha256_enc(const fido_dev_t * dev,const fido_blob_t * shared,const fido_blob_t * pin,fido_blob_t ** out)360afa8e06SEd Maste pin_sha256_enc(const fido_dev_t *dev, const fido_blob_t *shared,
370afa8e06SEd Maste     const fido_blob_t *pin, fido_blob_t **out)
380afa8e06SEd Maste {
390afa8e06SEd Maste 	fido_blob_t	*ph = NULL;
400afa8e06SEd Maste 	int		 r;
410afa8e06SEd Maste 
420afa8e06SEd Maste 	if ((*out = fido_blob_new()) == NULL ||
430afa8e06SEd Maste 	    (ph = fido_blob_new()) == NULL) {
440afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
450afa8e06SEd Maste 		goto fail;
460afa8e06SEd Maste 	}
470afa8e06SEd Maste 
480afa8e06SEd Maste 	if (fido_sha256(ph, pin->ptr, pin->len) < 0 || ph->len < 16) {
490afa8e06SEd Maste 		fido_log_debug("%s: SHA256", __func__);
500afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
510afa8e06SEd Maste 		goto fail;
520afa8e06SEd Maste 	}
530afa8e06SEd Maste 
540afa8e06SEd Maste 	ph->len = 16; /* first 16 bytes */
550afa8e06SEd Maste 
560afa8e06SEd Maste 	if (aes256_cbc_enc(dev, shared, ph, *out) < 0) {
570afa8e06SEd Maste 		fido_log_debug("%s: aes256_cbc_enc", __func__);
580afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
590afa8e06SEd Maste 		goto fail;
600afa8e06SEd Maste 	}
610afa8e06SEd Maste 
620afa8e06SEd Maste 	r = FIDO_OK;
630afa8e06SEd Maste fail:
640afa8e06SEd Maste 	fido_blob_free(&ph);
650afa8e06SEd Maste 
660afa8e06SEd Maste 	return (r);
670afa8e06SEd Maste }
680afa8e06SEd Maste 
690afa8e06SEd Maste static int
pad64(const char * pin,fido_blob_t ** ppin)700afa8e06SEd Maste pad64(const char *pin, fido_blob_t **ppin)
710afa8e06SEd Maste {
720afa8e06SEd Maste 	size_t	pin_len;
730afa8e06SEd Maste 	size_t	ppin_len;
740afa8e06SEd Maste 
750afa8e06SEd Maste 	pin_len = strlen(pin);
76*2ccfa855SEd Maste 	if (pin_len < 4 || pin_len > 63) {
770afa8e06SEd Maste 		fido_log_debug("%s: invalid pin length", __func__);
780afa8e06SEd Maste 		return (FIDO_ERR_PIN_POLICY_VIOLATION);
790afa8e06SEd Maste 	}
800afa8e06SEd Maste 
810afa8e06SEd Maste 	if ((*ppin = fido_blob_new()) == NULL)
820afa8e06SEd Maste 		return (FIDO_ERR_INTERNAL);
830afa8e06SEd Maste 
840afa8e06SEd Maste 	ppin_len = (pin_len + 63U) & ~63U;
85*2ccfa855SEd Maste 	if (ppin_len < pin_len ||
86*2ccfa855SEd Maste 	    ((*ppin)->ptr = calloc(1, ppin_len)) == NULL) {
870afa8e06SEd Maste 		fido_blob_free(ppin);
880afa8e06SEd Maste 		return (FIDO_ERR_INTERNAL);
890afa8e06SEd Maste 	}
900afa8e06SEd Maste 
910afa8e06SEd Maste 	memcpy((*ppin)->ptr, pin, pin_len);
920afa8e06SEd Maste 	(*ppin)->len = ppin_len;
930afa8e06SEd Maste 
940afa8e06SEd Maste 	return (FIDO_OK);
950afa8e06SEd Maste }
960afa8e06SEd Maste 
970afa8e06SEd Maste static int
pin_pad64_enc(const fido_dev_t * dev,const fido_blob_t * shared,const char * pin,fido_blob_t ** out)980afa8e06SEd Maste pin_pad64_enc(const fido_dev_t *dev, const fido_blob_t *shared,
990afa8e06SEd Maste     const char *pin, fido_blob_t **out)
1000afa8e06SEd Maste {
1010afa8e06SEd Maste 	fido_blob_t *ppin = NULL;
1020afa8e06SEd Maste 	int	     r;
1030afa8e06SEd Maste 
1040afa8e06SEd Maste 	if ((r = pad64(pin, &ppin)) != FIDO_OK) {
1050afa8e06SEd Maste 		fido_log_debug("%s: pad64", __func__);
1060afa8e06SEd Maste 		    goto fail;
1070afa8e06SEd Maste 	}
1080afa8e06SEd Maste 
1090afa8e06SEd Maste 	if ((*out = fido_blob_new()) == NULL) {
1100afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
1110afa8e06SEd Maste 		goto fail;
1120afa8e06SEd Maste 	}
1130afa8e06SEd Maste 
1140afa8e06SEd Maste 	if (aes256_cbc_enc(dev, shared, ppin, *out) < 0) {
1150afa8e06SEd Maste 		fido_log_debug("%s: aes256_cbc_enc", __func__);
1160afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
1170afa8e06SEd Maste 		goto fail;
1180afa8e06SEd Maste 	}
1190afa8e06SEd Maste 
1200afa8e06SEd Maste 	r = FIDO_OK;
1210afa8e06SEd Maste fail:
1220afa8e06SEd Maste 	fido_blob_free(&ppin);
1230afa8e06SEd Maste 
1240afa8e06SEd Maste 	return (r);
1250afa8e06SEd Maste }
1260afa8e06SEd Maste 
1270afa8e06SEd Maste static cbor_item_t *
encode_uv_permission(uint8_t cmd)1280afa8e06SEd Maste encode_uv_permission(uint8_t cmd)
1290afa8e06SEd Maste {
1300afa8e06SEd Maste 	switch (cmd) {
1310afa8e06SEd Maste 	case CTAP_CBOR_ASSERT:
1320afa8e06SEd Maste 		return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_ASSERT));
1330afa8e06SEd Maste 	case CTAP_CBOR_BIO_ENROLL_PRE:
1340afa8e06SEd Maste 		return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_BIO));
1350afa8e06SEd Maste 	case CTAP_CBOR_CONFIG:
1360afa8e06SEd Maste 		return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_CONFIG));
1370afa8e06SEd Maste 	case CTAP_CBOR_MAKECRED:
1380afa8e06SEd Maste 		return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_MAKECRED));
1390afa8e06SEd Maste 	case CTAP_CBOR_CRED_MGMT_PRE:
1400afa8e06SEd Maste 		return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_CRED_MGMT));
1410afa8e06SEd Maste 	case CTAP_CBOR_LARGEBLOB:
1420afa8e06SEd Maste 		return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_LARGEBLOB));
1430afa8e06SEd Maste 	default:
1440afa8e06SEd Maste 		fido_log_debug("%s: cmd 0x%02x", __func__, cmd);
1450afa8e06SEd Maste 		return (NULL);
1460afa8e06SEd Maste 	}
1470afa8e06SEd Maste }
1480afa8e06SEd Maste 
1490afa8e06SEd Maste static int
ctap20_uv_token_tx(fido_dev_t * dev,const char * pin,const fido_blob_t * ecdh,const es256_pk_t * pk,int * ms)1500afa8e06SEd Maste ctap20_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh,
151f540a430SEd Maste     const es256_pk_t *pk, int *ms)
1520afa8e06SEd Maste {
1530afa8e06SEd Maste 	fido_blob_t	 f;
1540afa8e06SEd Maste 	fido_blob_t	*p = NULL;
1550afa8e06SEd Maste 	fido_blob_t	*phe = NULL;
1560afa8e06SEd Maste 	cbor_item_t	*argv[6];
1570afa8e06SEd Maste 	int		 r;
1580afa8e06SEd Maste 
1590afa8e06SEd Maste 	memset(&f, 0, sizeof(f));
1600afa8e06SEd Maste 	memset(argv, 0, sizeof(argv));
1610afa8e06SEd Maste 
1620afa8e06SEd Maste 	if (pin == NULL) {
1630afa8e06SEd Maste 		fido_log_debug("%s: NULL pin", __func__);
1640afa8e06SEd Maste 		r = FIDO_ERR_PIN_REQUIRED;
1650afa8e06SEd Maste 		goto fail;
1660afa8e06SEd Maste 	}
1670afa8e06SEd Maste 
1680afa8e06SEd Maste 	if ((p = fido_blob_new()) == NULL || fido_blob_set(p,
1690afa8e06SEd Maste 	    (const unsigned char *)pin, strlen(pin)) < 0) {
1700afa8e06SEd Maste 		fido_log_debug("%s: fido_blob_set", __func__);
1710afa8e06SEd Maste 		r = FIDO_ERR_INVALID_ARGUMENT;
1720afa8e06SEd Maste 		goto fail;
1730afa8e06SEd Maste 	}
1740afa8e06SEd Maste 
1750afa8e06SEd Maste 	if ((r = pin_sha256_enc(dev, ecdh, p, &phe)) != FIDO_OK) {
1760afa8e06SEd Maste 		fido_log_debug("%s: pin_sha256_enc", __func__);
1770afa8e06SEd Maste 		goto fail;
1780afa8e06SEd Maste 	}
1790afa8e06SEd Maste 
1800afa8e06SEd Maste 	if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
1810afa8e06SEd Maste 	    (argv[1] = cbor_build_uint8(5)) == NULL ||
1820afa8e06SEd Maste 	    (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
1830afa8e06SEd Maste 	    (argv[5] = fido_blob_encode(phe)) == NULL) {
1840afa8e06SEd Maste 		fido_log_debug("%s: cbor encode", __func__);
1850afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
1860afa8e06SEd Maste 		goto fail;
1870afa8e06SEd Maste 	}
1880afa8e06SEd Maste 
1890afa8e06SEd Maste 	if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
190f540a430SEd Maste 	    &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
1910afa8e06SEd Maste 		fido_log_debug("%s: fido_tx", __func__);
1920afa8e06SEd Maste 		r = FIDO_ERR_TX;
1930afa8e06SEd Maste 		goto fail;
1940afa8e06SEd Maste 	}
1950afa8e06SEd Maste 
1960afa8e06SEd Maste 	r = FIDO_OK;
1970afa8e06SEd Maste fail:
1980afa8e06SEd Maste 	cbor_vector_free(argv, nitems(argv));
1990afa8e06SEd Maste 	fido_blob_free(&p);
2000afa8e06SEd Maste 	fido_blob_free(&phe);
2010afa8e06SEd Maste 	free(f.ptr);
2020afa8e06SEd Maste 
2030afa8e06SEd Maste 	return (r);
2040afa8e06SEd Maste }
2050afa8e06SEd Maste 
2060afa8e06SEd Maste static int
ctap21_uv_token_tx(fido_dev_t * dev,const char * pin,const fido_blob_t * ecdh,const es256_pk_t * pk,uint8_t cmd,const char * rpid,int * ms)2070afa8e06SEd Maste ctap21_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh,
208f540a430SEd Maste     const es256_pk_t *pk, uint8_t cmd, const char *rpid, int *ms)
2090afa8e06SEd Maste {
2100afa8e06SEd Maste 	fido_blob_t	 f;
2110afa8e06SEd Maste 	fido_blob_t	*p = NULL;
2120afa8e06SEd Maste 	fido_blob_t	*phe = NULL;
2130afa8e06SEd Maste 	cbor_item_t	*argv[10];
2140afa8e06SEd Maste 	uint8_t		 subcmd;
2150afa8e06SEd Maste 	int		 r;
2160afa8e06SEd Maste 
2170afa8e06SEd Maste 	memset(&f, 0, sizeof(f));
2180afa8e06SEd Maste 	memset(argv, 0, sizeof(argv));
2190afa8e06SEd Maste 
2200afa8e06SEd Maste 	if (pin != NULL) {
2210afa8e06SEd Maste 		if ((p = fido_blob_new()) == NULL || fido_blob_set(p,
2220afa8e06SEd Maste 		    (const unsigned char *)pin, strlen(pin)) < 0) {
2230afa8e06SEd Maste 			fido_log_debug("%s: fido_blob_set", __func__);
2240afa8e06SEd Maste 			r = FIDO_ERR_INVALID_ARGUMENT;
2250afa8e06SEd Maste 			goto fail;
2260afa8e06SEd Maste 		}
2270afa8e06SEd Maste 		if ((r = pin_sha256_enc(dev, ecdh, p, &phe)) != FIDO_OK) {
2280afa8e06SEd Maste 			fido_log_debug("%s: pin_sha256_enc", __func__);
2290afa8e06SEd Maste 			goto fail;
2300afa8e06SEd Maste 		}
2310afa8e06SEd Maste 		subcmd = 9; /* getPinUvAuthTokenUsingPinWithPermissions */
2320afa8e06SEd Maste 	} else {
2330afa8e06SEd Maste 		if (fido_dev_has_uv(dev) == false) {
2340afa8e06SEd Maste 			fido_log_debug("%s: fido_dev_has_uv", __func__);
2350afa8e06SEd Maste 			r = FIDO_ERR_PIN_REQUIRED;
2360afa8e06SEd Maste 			goto fail;
2370afa8e06SEd Maste 		}
2380afa8e06SEd Maste 		subcmd = 6; /* getPinUvAuthTokenUsingUvWithPermissions */
2390afa8e06SEd Maste 	}
2400afa8e06SEd Maste 
2410afa8e06SEd Maste 	if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
2420afa8e06SEd Maste 	    (argv[1] = cbor_build_uint8(subcmd)) == NULL ||
2430afa8e06SEd Maste 	    (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
2440afa8e06SEd Maste 	    (phe != NULL && (argv[5] = fido_blob_encode(phe)) == NULL) ||
2450afa8e06SEd Maste 	    (argv[8] = encode_uv_permission(cmd)) == NULL ||
2460afa8e06SEd Maste 	    (rpid != NULL && (argv[9] = cbor_build_string(rpid)) == NULL)) {
2470afa8e06SEd Maste 		fido_log_debug("%s: cbor encode", __func__);
2480afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
2490afa8e06SEd Maste 		goto fail;
2500afa8e06SEd Maste 	}
2510afa8e06SEd Maste 
2520afa8e06SEd Maste 	if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
253f540a430SEd Maste 	    &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
2540afa8e06SEd Maste 		fido_log_debug("%s:  fido_tx", __func__);
2550afa8e06SEd Maste 		r = FIDO_ERR_TX;
2560afa8e06SEd Maste 		goto fail;
2570afa8e06SEd Maste 	}
2580afa8e06SEd Maste 
2590afa8e06SEd Maste 	r = FIDO_OK;
2600afa8e06SEd Maste fail:
2610afa8e06SEd Maste 	cbor_vector_free(argv, nitems(argv));
2620afa8e06SEd Maste 	fido_blob_free(&p);
2630afa8e06SEd Maste 	fido_blob_free(&phe);
2640afa8e06SEd Maste 	free(f.ptr);
2650afa8e06SEd Maste 
2660afa8e06SEd Maste 	return (r);
2670afa8e06SEd Maste }
2680afa8e06SEd Maste 
2690afa8e06SEd Maste static int
parse_uv_token(const cbor_item_t * key,const cbor_item_t * val,void * arg)2700afa8e06SEd Maste parse_uv_token(const cbor_item_t *key, const cbor_item_t *val, void *arg)
2710afa8e06SEd Maste {
2720afa8e06SEd Maste 	fido_blob_t *token = arg;
2730afa8e06SEd Maste 
2740afa8e06SEd Maste 	if (cbor_isa_uint(key) == false ||
2750afa8e06SEd Maste 	    cbor_int_get_width(key) != CBOR_INT_8 ||
2760afa8e06SEd Maste 	    cbor_get_uint8(key) != 2) {
2770afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
2780afa8e06SEd Maste 		return (0); /* ignore */
2790afa8e06SEd Maste 	}
2800afa8e06SEd Maste 
2810afa8e06SEd Maste 	return (fido_blob_decode(val, token));
2820afa8e06SEd Maste }
2830afa8e06SEd Maste 
2840afa8e06SEd Maste static int
uv_token_rx(fido_dev_t * dev,const fido_blob_t * ecdh,fido_blob_t * token,int * ms)2850afa8e06SEd Maste uv_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, fido_blob_t *token,
286f540a430SEd Maste     int *ms)
2870afa8e06SEd Maste {
2880afa8e06SEd Maste 	fido_blob_t	*aes_token = NULL;
289*2ccfa855SEd Maste 	unsigned char	*msg = NULL;
290*2ccfa855SEd Maste 	int		 msglen;
2910afa8e06SEd Maste 	int		 r;
2920afa8e06SEd Maste 
2930afa8e06SEd Maste 	if ((aes_token = fido_blob_new()) == NULL) {
2940afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
2950afa8e06SEd Maste 		goto fail;
2960afa8e06SEd Maste 	}
2970afa8e06SEd Maste 
298*2ccfa855SEd Maste 	if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
299*2ccfa855SEd Maste 		r = FIDO_ERR_INTERNAL;
300*2ccfa855SEd Maste 		goto fail;
301*2ccfa855SEd Maste 	}
302*2ccfa855SEd Maste 
303*2ccfa855SEd Maste 	if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
3040afa8e06SEd Maste 		fido_log_debug("%s: fido_rx", __func__);
3050afa8e06SEd Maste 		r = FIDO_ERR_RX;
3060afa8e06SEd Maste 		goto fail;
3070afa8e06SEd Maste 	}
3080afa8e06SEd Maste 
309*2ccfa855SEd Maste 	if ((r = cbor_parse_reply(msg, (size_t)msglen, aes_token,
3100afa8e06SEd Maste 	    parse_uv_token)) != FIDO_OK) {
3110afa8e06SEd Maste 		fido_log_debug("%s: parse_uv_token", __func__);
3120afa8e06SEd Maste 		goto fail;
3130afa8e06SEd Maste 	}
3140afa8e06SEd Maste 
3150afa8e06SEd Maste 	if  (aes256_cbc_dec(dev, ecdh, aes_token, token) < 0) {
3160afa8e06SEd Maste 		fido_log_debug("%s: aes256_cbc_dec", __func__);
3170afa8e06SEd Maste 		r = FIDO_ERR_RX;
3180afa8e06SEd Maste 		goto fail;
3190afa8e06SEd Maste 	}
3200afa8e06SEd Maste 
3210afa8e06SEd Maste 	r = FIDO_OK;
3220afa8e06SEd Maste fail:
3230afa8e06SEd Maste 	fido_blob_free(&aes_token);
324*2ccfa855SEd Maste 	freezero(msg, FIDO_MAXMSG);
3250afa8e06SEd Maste 
3260afa8e06SEd Maste 	return (r);
3270afa8e06SEd Maste }
3280afa8e06SEd Maste 
3290afa8e06SEd Maste static int
uv_token_wait(fido_dev_t * dev,uint8_t cmd,const char * pin,const fido_blob_t * ecdh,const es256_pk_t * pk,const char * rpid,fido_blob_t * token,int * ms)3300afa8e06SEd Maste uv_token_wait(fido_dev_t *dev, uint8_t cmd, const char *pin,
3310afa8e06SEd Maste     const fido_blob_t *ecdh, const es256_pk_t *pk, const char *rpid,
332f540a430SEd Maste     fido_blob_t *token, int *ms)
3330afa8e06SEd Maste {
3340afa8e06SEd Maste 	int r;
3350afa8e06SEd Maste 
3360afa8e06SEd Maste 	if (ecdh == NULL || pk == NULL)
3370afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
3380afa8e06SEd Maste 	if (fido_dev_supports_permissions(dev))
339f540a430SEd Maste 		r = ctap21_uv_token_tx(dev, pin, ecdh, pk, cmd, rpid, ms);
3400afa8e06SEd Maste 	else
341f540a430SEd Maste 		r = ctap20_uv_token_tx(dev, pin, ecdh, pk, ms);
3420afa8e06SEd Maste 	if (r != FIDO_OK)
3430afa8e06SEd Maste 		return (r);
3440afa8e06SEd Maste 
3450afa8e06SEd Maste 	return (uv_token_rx(dev, ecdh, token, ms));
3460afa8e06SEd Maste }
3470afa8e06SEd Maste 
3480afa8e06SEd Maste int
fido_dev_get_uv_token(fido_dev_t * dev,uint8_t cmd,const char * pin,const fido_blob_t * ecdh,const es256_pk_t * pk,const char * rpid,fido_blob_t * token,int * ms)3490afa8e06SEd Maste fido_dev_get_uv_token(fido_dev_t *dev, uint8_t cmd, const char *pin,
3500afa8e06SEd Maste     const fido_blob_t *ecdh, const es256_pk_t *pk, const char *rpid,
351f540a430SEd Maste     fido_blob_t *token, int *ms)
3520afa8e06SEd Maste {
353f540a430SEd Maste 	return (uv_token_wait(dev, cmd, pin, ecdh, pk, rpid, token, ms));
3540afa8e06SEd Maste }
3550afa8e06SEd Maste 
3560afa8e06SEd Maste static int
fido_dev_change_pin_tx(fido_dev_t * dev,const char * pin,const char * oldpin,int * ms)357f540a430SEd Maste fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin,
358f540a430SEd Maste     int *ms)
3590afa8e06SEd Maste {
3600afa8e06SEd Maste 	fido_blob_t	 f;
3610afa8e06SEd Maste 	fido_blob_t	*ppine = NULL;
3620afa8e06SEd Maste 	fido_blob_t	*ecdh = NULL;
3630afa8e06SEd Maste 	fido_blob_t	*opin = NULL;
3640afa8e06SEd Maste 	fido_blob_t	*opinhe = NULL;
3650afa8e06SEd Maste 	cbor_item_t	*argv[6];
3660afa8e06SEd Maste 	es256_pk_t	*pk = NULL;
3670afa8e06SEd Maste 	int r;
3680afa8e06SEd Maste 
3690afa8e06SEd Maste 	memset(&f, 0, sizeof(f));
3700afa8e06SEd Maste 	memset(argv, 0, sizeof(argv));
3710afa8e06SEd Maste 
3720afa8e06SEd Maste 	if ((opin = fido_blob_new()) == NULL || fido_blob_set(opin,
3730afa8e06SEd Maste 	    (const unsigned char *)oldpin, strlen(oldpin)) < 0) {
3740afa8e06SEd Maste 		fido_log_debug("%s: fido_blob_set", __func__);
3750afa8e06SEd Maste 		r = FIDO_ERR_INVALID_ARGUMENT;
3760afa8e06SEd Maste 		goto fail;
3770afa8e06SEd Maste 	}
3780afa8e06SEd Maste 
379f540a430SEd Maste 	if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
3800afa8e06SEd Maste 		fido_log_debug("%s: fido_do_ecdh", __func__);
3810afa8e06SEd Maste 		goto fail;
3820afa8e06SEd Maste 	}
3830afa8e06SEd Maste 
3840afa8e06SEd Maste 	/* pad and encrypt new pin */
3850afa8e06SEd Maste 	if ((r = pin_pad64_enc(dev, ecdh, pin, &ppine)) != FIDO_OK) {
3860afa8e06SEd Maste 		fido_log_debug("%s: pin_pad64_enc", __func__);
3870afa8e06SEd Maste 		goto fail;
3880afa8e06SEd Maste 	}
3890afa8e06SEd Maste 
3900afa8e06SEd Maste 	/* hash and encrypt old pin */
3910afa8e06SEd Maste 	if ((r = pin_sha256_enc(dev, ecdh, opin, &opinhe)) != FIDO_OK) {
3920afa8e06SEd Maste 		fido_log_debug("%s: pin_sha256_enc", __func__);
3930afa8e06SEd Maste 		goto fail;
3940afa8e06SEd Maste 	}
3950afa8e06SEd Maste 
3960afa8e06SEd Maste 	if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
3970afa8e06SEd Maste 	    (argv[1] = cbor_build_uint8(4)) == NULL ||
3980afa8e06SEd Maste 	    (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
3990afa8e06SEd Maste 	    (argv[3] = cbor_encode_change_pin_auth(dev, ecdh, ppine, opinhe)) == NULL ||
4000afa8e06SEd Maste 	    (argv[4] = fido_blob_encode(ppine)) == NULL ||
4010afa8e06SEd Maste 	    (argv[5] = fido_blob_encode(opinhe)) == NULL) {
4020afa8e06SEd Maste 		fido_log_debug("%s: cbor encode", __func__);
4030afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
4040afa8e06SEd Maste 		goto fail;
4050afa8e06SEd Maste 	}
4060afa8e06SEd Maste 
4070afa8e06SEd Maste 	if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
408f540a430SEd Maste 	    &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
4090afa8e06SEd Maste 		fido_log_debug("%s: fido_tx", __func__);
4100afa8e06SEd Maste 		r = FIDO_ERR_TX;
4110afa8e06SEd Maste 		goto fail;
4120afa8e06SEd Maste 	}
4130afa8e06SEd Maste 
4140afa8e06SEd Maste 	r = FIDO_OK;
4150afa8e06SEd Maste fail:
4160afa8e06SEd Maste 	cbor_vector_free(argv, nitems(argv));
4170afa8e06SEd Maste 	es256_pk_free(&pk);
4180afa8e06SEd Maste 	fido_blob_free(&ppine);
4190afa8e06SEd Maste 	fido_blob_free(&ecdh);
4200afa8e06SEd Maste 	fido_blob_free(&opin);
4210afa8e06SEd Maste 	fido_blob_free(&opinhe);
4220afa8e06SEd Maste 	free(f.ptr);
4230afa8e06SEd Maste 
4240afa8e06SEd Maste 	return (r);
4250afa8e06SEd Maste 
4260afa8e06SEd Maste }
4270afa8e06SEd Maste 
4280afa8e06SEd Maste static int
fido_dev_set_pin_tx(fido_dev_t * dev,const char * pin,int * ms)429f540a430SEd Maste fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin, int *ms)
4300afa8e06SEd Maste {
4310afa8e06SEd Maste 	fido_blob_t	 f;
4320afa8e06SEd Maste 	fido_blob_t	*ppine = NULL;
4330afa8e06SEd Maste 	fido_blob_t	*ecdh = NULL;
4340afa8e06SEd Maste 	cbor_item_t	*argv[5];
4350afa8e06SEd Maste 	es256_pk_t	*pk = NULL;
4360afa8e06SEd Maste 	int		 r;
4370afa8e06SEd Maste 
4380afa8e06SEd Maste 	memset(&f, 0, sizeof(f));
4390afa8e06SEd Maste 	memset(argv, 0, sizeof(argv));
4400afa8e06SEd Maste 
441f540a430SEd Maste 	if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
4420afa8e06SEd Maste 		fido_log_debug("%s: fido_do_ecdh", __func__);
4430afa8e06SEd Maste 		goto fail;
4440afa8e06SEd Maste 	}
4450afa8e06SEd Maste 
4460afa8e06SEd Maste 	if ((r = pin_pad64_enc(dev, ecdh, pin, &ppine)) != FIDO_OK) {
4470afa8e06SEd Maste 		fido_log_debug("%s: pin_pad64_enc", __func__);
4480afa8e06SEd Maste 		goto fail;
4490afa8e06SEd Maste 	}
4500afa8e06SEd Maste 
4510afa8e06SEd Maste 	if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL ||
4520afa8e06SEd Maste 	    (argv[1] = cbor_build_uint8(3)) == NULL ||
4530afa8e06SEd Maste 	    (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
4540afa8e06SEd Maste 	    (argv[3] = cbor_encode_pin_auth(dev, ecdh, ppine)) == NULL ||
4550afa8e06SEd Maste 	    (argv[4] = fido_blob_encode(ppine)) == NULL) {
4560afa8e06SEd Maste 		fido_log_debug("%s: cbor encode", __func__);
4570afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
4580afa8e06SEd Maste 		goto fail;
4590afa8e06SEd Maste 	}
4600afa8e06SEd Maste 
4610afa8e06SEd Maste 	if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
462f540a430SEd Maste 	    &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
4630afa8e06SEd Maste 		fido_log_debug("%s: fido_tx", __func__);
4640afa8e06SEd Maste 		r = FIDO_ERR_TX;
4650afa8e06SEd Maste 		goto fail;
4660afa8e06SEd Maste 	}
4670afa8e06SEd Maste 
4680afa8e06SEd Maste 	r = FIDO_OK;
4690afa8e06SEd Maste fail:
4700afa8e06SEd Maste 	cbor_vector_free(argv, nitems(argv));
4710afa8e06SEd Maste 	es256_pk_free(&pk);
4720afa8e06SEd Maste 	fido_blob_free(&ppine);
4730afa8e06SEd Maste 	fido_blob_free(&ecdh);
4740afa8e06SEd Maste 	free(f.ptr);
4750afa8e06SEd Maste 
4760afa8e06SEd Maste 	return (r);
4770afa8e06SEd Maste }
4780afa8e06SEd Maste 
4790afa8e06SEd Maste static int
fido_dev_set_pin_wait(fido_dev_t * dev,const char * pin,const char * oldpin,int * ms)4800afa8e06SEd Maste fido_dev_set_pin_wait(fido_dev_t *dev, const char *pin, const char *oldpin,
481f540a430SEd Maste     int *ms)
4820afa8e06SEd Maste {
4830afa8e06SEd Maste 	int r;
4840afa8e06SEd Maste 
4850afa8e06SEd Maste 	if (oldpin != NULL) {
486f540a430SEd Maste 		if ((r = fido_dev_change_pin_tx(dev, pin, oldpin,
487f540a430SEd Maste 		    ms)) != FIDO_OK) {
4880afa8e06SEd Maste 			fido_log_debug("%s: fido_dev_change_pin_tx", __func__);
4890afa8e06SEd Maste 			return (r);
4900afa8e06SEd Maste 		}
4910afa8e06SEd Maste 	} else {
492f540a430SEd Maste 		if ((r = fido_dev_set_pin_tx(dev, pin, ms)) != FIDO_OK) {
4930afa8e06SEd Maste 			fido_log_debug("%s: fido_dev_set_pin_tx", __func__);
4940afa8e06SEd Maste 			return (r);
4950afa8e06SEd Maste 		}
4960afa8e06SEd Maste 	}
4970afa8e06SEd Maste 
4980afa8e06SEd Maste 	if ((r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
4990afa8e06SEd Maste 		fido_log_debug("%s: fido_rx_cbor_status", __func__);
5000afa8e06SEd Maste 		return (r);
5010afa8e06SEd Maste 	}
5020afa8e06SEd Maste 
5030afa8e06SEd Maste 	if (dev->flags & FIDO_DEV_PIN_UNSET) {
5040afa8e06SEd Maste 		dev->flags &= ~FIDO_DEV_PIN_UNSET;
5050afa8e06SEd Maste 		dev->flags |= FIDO_DEV_PIN_SET;
5060afa8e06SEd Maste 	}
5070afa8e06SEd Maste 
5080afa8e06SEd Maste 	return (FIDO_OK);
5090afa8e06SEd Maste }
5100afa8e06SEd Maste 
5110afa8e06SEd Maste int
fido_dev_set_pin(fido_dev_t * dev,const char * pin,const char * oldpin)5120afa8e06SEd Maste fido_dev_set_pin(fido_dev_t *dev, const char *pin, const char *oldpin)
5130afa8e06SEd Maste {
514f540a430SEd Maste 	int ms = dev->timeout_ms;
515f540a430SEd Maste 
516f540a430SEd Maste 	return (fido_dev_set_pin_wait(dev, pin, oldpin, &ms));
5170afa8e06SEd Maste }
5180afa8e06SEd Maste 
5190afa8e06SEd Maste static int
parse_retry_count(const uint8_t keyval,const cbor_item_t * key,const cbor_item_t * val,void * arg)5200afa8e06SEd Maste parse_retry_count(const uint8_t keyval, const cbor_item_t *key,
5210afa8e06SEd Maste     const cbor_item_t *val, void *arg)
5220afa8e06SEd Maste {
5230afa8e06SEd Maste 	int		*retries = arg;
5240afa8e06SEd Maste 	uint64_t	 n;
5250afa8e06SEd Maste 
5260afa8e06SEd Maste 	if (cbor_isa_uint(key) == false ||
5270afa8e06SEd Maste 	    cbor_int_get_width(key) != CBOR_INT_8 ||
5280afa8e06SEd Maste 	    cbor_get_uint8(key) != keyval) {
5290afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
5300afa8e06SEd Maste 		return (0); /* ignore */
5310afa8e06SEd Maste 	}
5320afa8e06SEd Maste 
5330afa8e06SEd Maste 	if (cbor_decode_uint64(val, &n) < 0 || n > INT_MAX) {
5340afa8e06SEd Maste 		fido_log_debug("%s: cbor_decode_uint64", __func__);
5350afa8e06SEd Maste 		return (-1);
5360afa8e06SEd Maste 	}
5370afa8e06SEd Maste 
5380afa8e06SEd Maste 	*retries = (int)n;
5390afa8e06SEd Maste 
5400afa8e06SEd Maste 	return (0);
5410afa8e06SEd Maste }
5420afa8e06SEd Maste 
5430afa8e06SEd Maste static int
parse_pin_retry_count(const cbor_item_t * key,const cbor_item_t * val,void * arg)5440afa8e06SEd Maste parse_pin_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg)
5450afa8e06SEd Maste {
5460afa8e06SEd Maste 	return (parse_retry_count(3, key, val, arg));
5470afa8e06SEd Maste }
5480afa8e06SEd Maste 
5490afa8e06SEd Maste static int
parse_uv_retry_count(const cbor_item_t * key,const cbor_item_t * val,void * arg)5500afa8e06SEd Maste parse_uv_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg)
5510afa8e06SEd Maste {
5520afa8e06SEd Maste 	return (parse_retry_count(5, key, val, arg));
5530afa8e06SEd Maste }
5540afa8e06SEd Maste 
5550afa8e06SEd Maste static int
fido_dev_get_retry_count_tx(fido_dev_t * dev,uint8_t subcmd,int * ms)556f540a430SEd Maste fido_dev_get_retry_count_tx(fido_dev_t *dev, uint8_t subcmd, int *ms)
5570afa8e06SEd Maste {
5580afa8e06SEd Maste 	fido_blob_t	 f;
5590afa8e06SEd Maste 	cbor_item_t	*argv[2];
5600afa8e06SEd Maste 	int		 r;
5610afa8e06SEd Maste 
5620afa8e06SEd Maste 	memset(&f, 0, sizeof(f));
5630afa8e06SEd Maste 	memset(argv, 0, sizeof(argv));
5640afa8e06SEd Maste 
5650afa8e06SEd Maste 	if ((argv[0] = cbor_build_uint8(1)) == NULL ||
5660afa8e06SEd Maste 	    (argv[1] = cbor_build_uint8(subcmd)) == NULL) {
5670afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
5680afa8e06SEd Maste 		goto fail;
5690afa8e06SEd Maste 	}
5700afa8e06SEd Maste 
5710afa8e06SEd Maste 	if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
572f540a430SEd Maste 	    &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
5730afa8e06SEd Maste 		fido_log_debug("%s: fido_tx", __func__);
5740afa8e06SEd Maste 		r = FIDO_ERR_TX;
5750afa8e06SEd Maste 		goto fail;
5760afa8e06SEd Maste 	}
5770afa8e06SEd Maste 
5780afa8e06SEd Maste 	r = FIDO_OK;
5790afa8e06SEd Maste fail:
5800afa8e06SEd Maste 	cbor_vector_free(argv, nitems(argv));
5810afa8e06SEd Maste 	free(f.ptr);
5820afa8e06SEd Maste 
5830afa8e06SEd Maste 	return (r);
5840afa8e06SEd Maste }
5850afa8e06SEd Maste 
5860afa8e06SEd Maste static int
fido_dev_get_pin_retry_count_rx(fido_dev_t * dev,int * retries,int * ms)587f540a430SEd Maste fido_dev_get_pin_retry_count_rx(fido_dev_t *dev, int *retries, int *ms)
5880afa8e06SEd Maste {
589*2ccfa855SEd Maste 	unsigned char	*msg;
590*2ccfa855SEd Maste 	int		 msglen;
5910afa8e06SEd Maste 	int		 r;
5920afa8e06SEd Maste 
5930afa8e06SEd Maste 	*retries = 0;
5940afa8e06SEd Maste 
595*2ccfa855SEd Maste 	if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
596*2ccfa855SEd Maste 		r = FIDO_ERR_INTERNAL;
597*2ccfa855SEd Maste 		goto fail;
5980afa8e06SEd Maste 	}
5990afa8e06SEd Maste 
600*2ccfa855SEd Maste 	if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
601*2ccfa855SEd Maste 		fido_log_debug("%s: fido_rx", __func__);
602*2ccfa855SEd Maste 		r = FIDO_ERR_RX;
603*2ccfa855SEd Maste 		goto fail;
604*2ccfa855SEd Maste 	}
605*2ccfa855SEd Maste 
606*2ccfa855SEd Maste 	if ((r = cbor_parse_reply(msg, (size_t)msglen, retries,
6070afa8e06SEd Maste 	    parse_pin_retry_count)) != FIDO_OK) {
6080afa8e06SEd Maste 		fido_log_debug("%s: parse_pin_retry_count", __func__);
609*2ccfa855SEd Maste 		goto fail;
6100afa8e06SEd Maste 	}
6110afa8e06SEd Maste 
612*2ccfa855SEd Maste 	r = FIDO_OK;
613*2ccfa855SEd Maste fail:
614*2ccfa855SEd Maste 	freezero(msg, FIDO_MAXMSG);
615*2ccfa855SEd Maste 
616*2ccfa855SEd Maste 	return (r);
6170afa8e06SEd Maste }
6180afa8e06SEd Maste 
6190afa8e06SEd Maste static int
fido_dev_get_pin_retry_count_wait(fido_dev_t * dev,int * retries,int * ms)620f540a430SEd Maste fido_dev_get_pin_retry_count_wait(fido_dev_t *dev, int *retries, int *ms)
6210afa8e06SEd Maste {
6220afa8e06SEd Maste 	int r;
6230afa8e06SEd Maste 
624f540a430SEd Maste 	if ((r = fido_dev_get_retry_count_tx(dev, 1, ms)) != FIDO_OK ||
6250afa8e06SEd Maste 	    (r = fido_dev_get_pin_retry_count_rx(dev, retries, ms)) != FIDO_OK)
6260afa8e06SEd Maste 		return (r);
6270afa8e06SEd Maste 
6280afa8e06SEd Maste 	return (FIDO_OK);
6290afa8e06SEd Maste }
6300afa8e06SEd Maste 
6310afa8e06SEd Maste int
fido_dev_get_retry_count(fido_dev_t * dev,int * retries)6320afa8e06SEd Maste fido_dev_get_retry_count(fido_dev_t *dev, int *retries)
6330afa8e06SEd Maste {
634f540a430SEd Maste 	int ms = dev->timeout_ms;
635f540a430SEd Maste 
636f540a430SEd Maste 	return (fido_dev_get_pin_retry_count_wait(dev, retries, &ms));
6370afa8e06SEd Maste }
6380afa8e06SEd Maste 
6390afa8e06SEd Maste static int
fido_dev_get_uv_retry_count_rx(fido_dev_t * dev,int * retries,int * ms)640f540a430SEd Maste fido_dev_get_uv_retry_count_rx(fido_dev_t *dev, int *retries, int *ms)
6410afa8e06SEd Maste {
642*2ccfa855SEd Maste 	unsigned char	*msg;
643*2ccfa855SEd Maste 	int		 msglen;
6440afa8e06SEd Maste 	int		 r;
6450afa8e06SEd Maste 
6460afa8e06SEd Maste 	*retries = 0;
6470afa8e06SEd Maste 
648*2ccfa855SEd Maste 	if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
649*2ccfa855SEd Maste 		r = FIDO_ERR_INTERNAL;
650*2ccfa855SEd Maste 		goto fail;
6510afa8e06SEd Maste 	}
6520afa8e06SEd Maste 
653*2ccfa855SEd Maste 	if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
654*2ccfa855SEd Maste 		fido_log_debug("%s: fido_rx", __func__);
655*2ccfa855SEd Maste 		r = FIDO_ERR_RX;
656*2ccfa855SEd Maste 		goto fail;
657*2ccfa855SEd Maste 	}
658*2ccfa855SEd Maste 
659*2ccfa855SEd Maste 	if ((r = cbor_parse_reply(msg, (size_t)msglen, retries,
6600afa8e06SEd Maste 	    parse_uv_retry_count)) != FIDO_OK) {
6610afa8e06SEd Maste 		fido_log_debug("%s: parse_uv_retry_count", __func__);
662*2ccfa855SEd Maste 		goto fail;
6630afa8e06SEd Maste 	}
6640afa8e06SEd Maste 
665*2ccfa855SEd Maste 	r = FIDO_OK;
666*2ccfa855SEd Maste fail:
667*2ccfa855SEd Maste 	freezero(msg, FIDO_MAXMSG);
668*2ccfa855SEd Maste 
669*2ccfa855SEd Maste 	return (r);
6700afa8e06SEd Maste }
6710afa8e06SEd Maste 
6720afa8e06SEd Maste static int
fido_dev_get_uv_retry_count_wait(fido_dev_t * dev,int * retries,int * ms)673f540a430SEd Maste fido_dev_get_uv_retry_count_wait(fido_dev_t *dev, int *retries, int *ms)
6740afa8e06SEd Maste {
6750afa8e06SEd Maste 	int r;
6760afa8e06SEd Maste 
677f540a430SEd Maste 	if ((r = fido_dev_get_retry_count_tx(dev, 7, ms)) != FIDO_OK ||
6780afa8e06SEd Maste 	    (r = fido_dev_get_uv_retry_count_rx(dev, retries, ms)) != FIDO_OK)
6790afa8e06SEd Maste 		return (r);
6800afa8e06SEd Maste 
6810afa8e06SEd Maste 	return (FIDO_OK);
6820afa8e06SEd Maste }
6830afa8e06SEd Maste 
6840afa8e06SEd Maste int
fido_dev_get_uv_retry_count(fido_dev_t * dev,int * retries)6850afa8e06SEd Maste fido_dev_get_uv_retry_count(fido_dev_t *dev, int *retries)
6860afa8e06SEd Maste {
687f540a430SEd Maste 	int ms = dev->timeout_ms;
688f540a430SEd Maste 
689f540a430SEd Maste 	return (fido_dev_get_uv_retry_count_wait(dev, retries, &ms));
6900afa8e06SEd Maste }
6910afa8e06SEd Maste 
6920afa8e06SEd Maste int
cbor_add_uv_params(fido_dev_t * dev,uint8_t cmd,const fido_blob_t * hmac_data,const es256_pk_t * pk,const fido_blob_t * ecdh,const char * pin,const char * rpid,cbor_item_t ** auth,cbor_item_t ** opt,int * ms)6930afa8e06SEd Maste cbor_add_uv_params(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *hmac_data,
6940afa8e06SEd Maste     const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin,
695f540a430SEd Maste     const char *rpid, cbor_item_t **auth, cbor_item_t **opt, int *ms)
6960afa8e06SEd Maste {
6970afa8e06SEd Maste 	fido_blob_t	*token = NULL;
6980afa8e06SEd Maste 	int		 r;
6990afa8e06SEd Maste 
7000afa8e06SEd Maste 	if ((token = fido_blob_new()) == NULL) {
7010afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
7020afa8e06SEd Maste 		goto fail;
7030afa8e06SEd Maste 	}
7040afa8e06SEd Maste 
7050afa8e06SEd Maste 	if ((r = fido_dev_get_uv_token(dev, cmd, pin, ecdh, pk, rpid,
706f540a430SEd Maste 	    token, ms)) != FIDO_OK) {
7070afa8e06SEd Maste 		fido_log_debug("%s: fido_dev_get_uv_token", __func__);
7080afa8e06SEd Maste 		goto fail;
7090afa8e06SEd Maste 	}
7100afa8e06SEd Maste 
7110afa8e06SEd Maste 	if ((*auth = cbor_encode_pin_auth(dev, token, hmac_data)) == NULL ||
7120afa8e06SEd Maste 	    (*opt = cbor_encode_pin_opt(dev)) == NULL) {
7130afa8e06SEd Maste 		fido_log_debug("%s: cbor encode", __func__);
7140afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
7150afa8e06SEd Maste 		goto fail;
7160afa8e06SEd Maste 	}
7170afa8e06SEd Maste 
7180afa8e06SEd Maste 	r = FIDO_OK;
7190afa8e06SEd Maste fail:
7200afa8e06SEd Maste 	fido_blob_free(&token);
7210afa8e06SEd Maste 
7220afa8e06SEd Maste 	return (r);
7230afa8e06SEd Maste }
724