10afa8e06SEd Maste /* 20afa8e06SEd Maste * Copyright (c) 2020 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. 50afa8e06SEd Maste */ 60afa8e06SEd Maste 70afa8e06SEd Maste #include "fido.h" 80afa8e06SEd Maste #include "fido/config.h" 90afa8e06SEd Maste #include "fido/es256.h" 100afa8e06SEd Maste 110afa8e06SEd Maste #define CMD_ENABLE_ENTATTEST 0x01 120afa8e06SEd Maste #define CMD_TOGGLE_ALWAYS_UV 0x02 130afa8e06SEd Maste #define CMD_SET_PIN_MINLEN 0x03 140afa8e06SEd Maste 150afa8e06SEd Maste static int 160afa8e06SEd Maste config_prepare_hmac(uint8_t subcmd, const cbor_item_t *item, fido_blob_t *hmac) 170afa8e06SEd Maste { 180afa8e06SEd Maste uint8_t prefix[32 + 2 * sizeof(uint8_t)], cbor[128]; 190afa8e06SEd Maste size_t cbor_len; 200afa8e06SEd Maste 210afa8e06SEd Maste memset(prefix, 0xff, sizeof(prefix)); 220afa8e06SEd Maste prefix[sizeof(prefix) - 2] = CTAP_CBOR_CONFIG; 230afa8e06SEd Maste prefix[sizeof(prefix) - 1] = subcmd; 240afa8e06SEd Maste 250afa8e06SEd Maste if ((cbor_len = cbor_serialize(item, cbor, sizeof(cbor))) == 0) { 260afa8e06SEd Maste fido_log_debug("%s: cbor_serialize", __func__); 270afa8e06SEd Maste return -1; 280afa8e06SEd Maste } 290afa8e06SEd Maste if ((hmac->ptr = malloc(cbor_len + sizeof(prefix))) == NULL) { 300afa8e06SEd Maste fido_log_debug("%s: malloc", __func__); 310afa8e06SEd Maste return -1; 320afa8e06SEd Maste } 330afa8e06SEd Maste memcpy(hmac->ptr, prefix, sizeof(prefix)); 340afa8e06SEd Maste memcpy(hmac->ptr + sizeof(prefix), cbor, cbor_len); 350afa8e06SEd Maste hmac->len = cbor_len + sizeof(prefix); 360afa8e06SEd Maste 370afa8e06SEd Maste return 0; 380afa8e06SEd Maste } 390afa8e06SEd Maste 400afa8e06SEd Maste static int 410afa8e06SEd Maste config_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **paramv, size_t paramc, 42*f540a430SEd Maste const char *pin, int *ms) 430afa8e06SEd Maste { 440afa8e06SEd Maste cbor_item_t *argv[4]; 450afa8e06SEd Maste es256_pk_t *pk = NULL; 460afa8e06SEd Maste fido_blob_t *ecdh = NULL, f, hmac; 470afa8e06SEd Maste const uint8_t cmd = CTAP_CBOR_CONFIG; 480afa8e06SEd Maste int r = FIDO_ERR_INTERNAL; 490afa8e06SEd Maste 500afa8e06SEd Maste memset(&f, 0, sizeof(f)); 510afa8e06SEd Maste memset(&hmac, 0, sizeof(hmac)); 520afa8e06SEd Maste memset(&argv, 0, sizeof(argv)); 530afa8e06SEd Maste 540afa8e06SEd Maste /* subCommand */ 550afa8e06SEd Maste if ((argv[0] = cbor_build_uint8(subcmd)) == NULL) { 560afa8e06SEd Maste fido_log_debug("%s: cbor encode", __func__); 570afa8e06SEd Maste goto fail; 580afa8e06SEd Maste } 590afa8e06SEd Maste 600afa8e06SEd Maste /* pinProtocol, pinAuth */ 610afa8e06SEd Maste if (pin != NULL || (fido_dev_supports_permissions(dev) && 620afa8e06SEd Maste fido_dev_has_uv(dev))) { 630afa8e06SEd Maste if ((argv[1] = cbor_flatten_vector(paramv, paramc)) == NULL) { 640afa8e06SEd Maste fido_log_debug("%s: cbor_flatten_vector", __func__); 650afa8e06SEd Maste goto fail; 660afa8e06SEd Maste } 670afa8e06SEd Maste if (config_prepare_hmac(subcmd, argv[1], &hmac) < 0) { 680afa8e06SEd Maste fido_log_debug("%s: config_prepare_hmac", __func__); 690afa8e06SEd Maste goto fail; 700afa8e06SEd Maste } 71*f540a430SEd Maste if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) { 720afa8e06SEd Maste fido_log_debug("%s: fido_do_ecdh", __func__); 730afa8e06SEd Maste goto fail; 740afa8e06SEd Maste } 750afa8e06SEd Maste if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin, 76*f540a430SEd Maste NULL, &argv[3], &argv[2], ms)) != FIDO_OK) { 770afa8e06SEd Maste fido_log_debug("%s: cbor_add_uv_params", __func__); 780afa8e06SEd Maste goto fail; 790afa8e06SEd Maste } 800afa8e06SEd Maste } 810afa8e06SEd Maste 820afa8e06SEd Maste /* framing and transmission */ 830afa8e06SEd Maste if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 || 84*f540a430SEd Maste fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { 850afa8e06SEd Maste fido_log_debug("%s: fido_tx", __func__); 860afa8e06SEd Maste r = FIDO_ERR_TX; 870afa8e06SEd Maste goto fail; 880afa8e06SEd Maste } 890afa8e06SEd Maste 900afa8e06SEd Maste r = FIDO_OK; 910afa8e06SEd Maste fail: 920afa8e06SEd Maste cbor_vector_free(argv, nitems(argv)); 930afa8e06SEd Maste es256_pk_free(&pk); 940afa8e06SEd Maste fido_blob_free(&ecdh); 950afa8e06SEd Maste free(f.ptr); 960afa8e06SEd Maste free(hmac.ptr); 970afa8e06SEd Maste 980afa8e06SEd Maste return r; 990afa8e06SEd Maste } 1000afa8e06SEd Maste 1010afa8e06SEd Maste static int 102*f540a430SEd Maste config_enable_entattest_wait(fido_dev_t *dev, const char *pin, int *ms) 1030afa8e06SEd Maste { 1040afa8e06SEd Maste int r; 1050afa8e06SEd Maste 106*f540a430SEd Maste if ((r = config_tx(dev, CMD_ENABLE_ENTATTEST, NULL, 0, pin, 107*f540a430SEd Maste ms)) != FIDO_OK) 1080afa8e06SEd Maste return r; 1090afa8e06SEd Maste 1100afa8e06SEd Maste return fido_rx_cbor_status(dev, ms); 1110afa8e06SEd Maste } 1120afa8e06SEd Maste 1130afa8e06SEd Maste int 1140afa8e06SEd Maste fido_dev_enable_entattest(fido_dev_t *dev, const char *pin) 1150afa8e06SEd Maste { 116*f540a430SEd Maste int ms = dev->timeout_ms; 117*f540a430SEd Maste 118*f540a430SEd Maste return (config_enable_entattest_wait(dev, pin, &ms)); 1190afa8e06SEd Maste } 1200afa8e06SEd Maste 1210afa8e06SEd Maste static int 122*f540a430SEd Maste config_toggle_always_uv_wait(fido_dev_t *dev, const char *pin, int *ms) 1230afa8e06SEd Maste { 1240afa8e06SEd Maste int r; 1250afa8e06SEd Maste 126*f540a430SEd Maste if ((r = config_tx(dev, CMD_TOGGLE_ALWAYS_UV, NULL, 0, pin, 127*f540a430SEd Maste ms)) != FIDO_OK) 1280afa8e06SEd Maste return r; 1290afa8e06SEd Maste 1300afa8e06SEd Maste return (fido_rx_cbor_status(dev, ms)); 1310afa8e06SEd Maste } 1320afa8e06SEd Maste 1330afa8e06SEd Maste int 1340afa8e06SEd Maste fido_dev_toggle_always_uv(fido_dev_t *dev, const char *pin) 1350afa8e06SEd Maste { 136*f540a430SEd Maste int ms = dev->timeout_ms; 137*f540a430SEd Maste 138*f540a430SEd Maste return config_toggle_always_uv_wait(dev, pin, &ms); 1390afa8e06SEd Maste } 1400afa8e06SEd Maste 1410afa8e06SEd Maste static int 142*f540a430SEd Maste config_pin_minlen_tx(fido_dev_t *dev, size_t len, bool force, 143*f540a430SEd Maste const fido_str_array_t *rpid, const char *pin, int *ms) 1440afa8e06SEd Maste { 1450afa8e06SEd Maste cbor_item_t *argv[3]; 1460afa8e06SEd Maste int r; 1470afa8e06SEd Maste 1480afa8e06SEd Maste memset(argv, 0, sizeof(argv)); 1490afa8e06SEd Maste 150*f540a430SEd Maste if ((rpid == NULL && len == 0 && !force) || len > UINT8_MAX) { 1510afa8e06SEd Maste r = FIDO_ERR_INVALID_ARGUMENT; 1520afa8e06SEd Maste goto fail; 1530afa8e06SEd Maste } 1540afa8e06SEd Maste if (len && (argv[0] = cbor_build_uint8((uint8_t)len)) == NULL) { 1550afa8e06SEd Maste fido_log_debug("%s: cbor_encode_uint8", __func__); 1560afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 1570afa8e06SEd Maste goto fail; 1580afa8e06SEd Maste } 159*f540a430SEd Maste if (rpid != NULL && (argv[1] = cbor_encode_str_array(rpid)) == NULL) { 160*f540a430SEd Maste fido_log_debug("%s: cbor_encode_str_array", __func__); 161*f540a430SEd Maste r = FIDO_ERR_INTERNAL; 162*f540a430SEd Maste goto fail; 163*f540a430SEd Maste } 1640afa8e06SEd Maste if (force && (argv[2] = cbor_build_bool(true)) == NULL) { 1650afa8e06SEd Maste fido_log_debug("%s: cbor_build_bool", __func__); 1660afa8e06SEd Maste r = FIDO_ERR_INTERNAL; 1670afa8e06SEd Maste goto fail; 1680afa8e06SEd Maste } 1690afa8e06SEd Maste if ((r = config_tx(dev, CMD_SET_PIN_MINLEN, argv, nitems(argv), 170*f540a430SEd Maste pin, ms)) != FIDO_OK) { 1710afa8e06SEd Maste fido_log_debug("%s: config_tx", __func__); 1720afa8e06SEd Maste goto fail; 1730afa8e06SEd Maste } 1740afa8e06SEd Maste 1750afa8e06SEd Maste fail: 1760afa8e06SEd Maste cbor_vector_free(argv, nitems(argv)); 1770afa8e06SEd Maste 1780afa8e06SEd Maste return r; 1790afa8e06SEd Maste } 1800afa8e06SEd Maste 1810afa8e06SEd Maste static int 182*f540a430SEd Maste config_pin_minlen(fido_dev_t *dev, size_t len, bool force, 183*f540a430SEd Maste const fido_str_array_t *rpid, const char *pin, int *ms) 1840afa8e06SEd Maste { 1850afa8e06SEd Maste int r; 1860afa8e06SEd Maste 187*f540a430SEd Maste if ((r = config_pin_minlen_tx(dev, len, force, rpid, pin, 188*f540a430SEd Maste ms)) != FIDO_OK) 1890afa8e06SEd Maste return r; 1900afa8e06SEd Maste 1910afa8e06SEd Maste return fido_rx_cbor_status(dev, ms); 1920afa8e06SEd Maste } 1930afa8e06SEd Maste 1940afa8e06SEd Maste int 1950afa8e06SEd Maste fido_dev_set_pin_minlen(fido_dev_t *dev, size_t len, const char *pin) 1960afa8e06SEd Maste { 197*f540a430SEd Maste int ms = dev->timeout_ms; 198*f540a430SEd Maste 199*f540a430SEd Maste return config_pin_minlen(dev, len, false, NULL, pin, &ms); 2000afa8e06SEd Maste } 2010afa8e06SEd Maste 2020afa8e06SEd Maste int 2030afa8e06SEd Maste fido_dev_force_pin_change(fido_dev_t *dev, const char *pin) 2040afa8e06SEd Maste { 205*f540a430SEd Maste int ms = dev->timeout_ms; 206*f540a430SEd Maste 207*f540a430SEd Maste return config_pin_minlen(dev, 0, true, NULL, pin, &ms); 208*f540a430SEd Maste } 209*f540a430SEd Maste 210*f540a430SEd Maste int 211*f540a430SEd Maste fido_dev_set_pin_minlen_rpid(fido_dev_t *dev, const char * const *rpid, 212*f540a430SEd Maste size_t n, const char *pin) 213*f540a430SEd Maste { 214*f540a430SEd Maste fido_str_array_t sa; 215*f540a430SEd Maste int ms = dev->timeout_ms; 216*f540a430SEd Maste int r; 217*f540a430SEd Maste 218*f540a430SEd Maste memset(&sa, 0, sizeof(sa)); 219*f540a430SEd Maste if (fido_str_array_pack(&sa, rpid, n) < 0) { 220*f540a430SEd Maste fido_log_debug("%s: fido_str_array_pack", __func__); 221*f540a430SEd Maste r = FIDO_ERR_INTERNAL; 222*f540a430SEd Maste goto fail; 223*f540a430SEd Maste } 224*f540a430SEd Maste r = config_pin_minlen(dev, 0, false, &sa, pin, &ms); 225*f540a430SEd Maste fail: 226*f540a430SEd Maste fido_str_array_free(&sa); 227*f540a430SEd Maste 228*f540a430SEd Maste return r; 2290afa8e06SEd Maste } 230