10afa8e06SEd Maste /* 20afa8e06SEd Maste * Copyright (c) 2018 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 "packed.h" 90afa8e06SEd Maste 100afa8e06SEd Maste PACKED_TYPE(frame_t, 110afa8e06SEd Maste struct frame { 120afa8e06SEd Maste uint32_t cid; /* channel id */ 130afa8e06SEd Maste union { 140afa8e06SEd Maste uint8_t type; 150afa8e06SEd Maste struct { 160afa8e06SEd Maste uint8_t cmd; 170afa8e06SEd Maste uint8_t bcnth; 180afa8e06SEd Maste uint8_t bcntl; 190afa8e06SEd Maste uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_INIT_HEADER_LEN]; 200afa8e06SEd Maste } init; 210afa8e06SEd Maste struct { 220afa8e06SEd Maste uint8_t seq; 230afa8e06SEd Maste uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_CONT_HEADER_LEN]; 240afa8e06SEd Maste } cont; 250afa8e06SEd Maste } body; 260afa8e06SEd Maste }) 270afa8e06SEd Maste 280afa8e06SEd Maste #ifndef MIN 290afa8e06SEd Maste #define MIN(x, y) ((x) > (y) ? (y) : (x)) 300afa8e06SEd Maste #endif 310afa8e06SEd Maste 320afa8e06SEd Maste static int 33*f540a430SEd Maste tx_pkt(fido_dev_t *d, const void *pkt, size_t len, int *ms) 34*f540a430SEd Maste { 35*f540a430SEd Maste struct timespec ts; 36*f540a430SEd Maste int n; 37*f540a430SEd Maste 38*f540a430SEd Maste if (fido_time_now(&ts) != 0) 39*f540a430SEd Maste return (-1); 40*f540a430SEd Maste 41*f540a430SEd Maste n = d->io.write(d->io_handle, pkt, len); 42*f540a430SEd Maste 43*f540a430SEd Maste if (fido_time_delta(&ts, ms) != 0) 44*f540a430SEd Maste return (-1); 45*f540a430SEd Maste 46*f540a430SEd Maste return (n); 47*f540a430SEd Maste } 48*f540a430SEd Maste 49*f540a430SEd Maste static int 50*f540a430SEd Maste tx_empty(fido_dev_t *d, uint8_t cmd, int *ms) 510afa8e06SEd Maste { 520afa8e06SEd Maste struct frame *fp; 530afa8e06SEd Maste unsigned char pkt[sizeof(*fp) + 1]; 540afa8e06SEd Maste const size_t len = d->tx_len + 1; 550afa8e06SEd Maste int n; 560afa8e06SEd Maste 570afa8e06SEd Maste memset(&pkt, 0, sizeof(pkt)); 580afa8e06SEd Maste fp = (struct frame *)(pkt + 1); 590afa8e06SEd Maste fp->cid = d->cid; 600afa8e06SEd Maste fp->body.init.cmd = CTAP_FRAME_INIT | cmd; 610afa8e06SEd Maste 62*f540a430SEd Maste if (len > sizeof(pkt) || (n = tx_pkt(d, pkt, len, ms)) < 0 || 63*f540a430SEd Maste (size_t)n != len) 640afa8e06SEd Maste return (-1); 650afa8e06SEd Maste 660afa8e06SEd Maste return (0); 670afa8e06SEd Maste } 680afa8e06SEd Maste 690afa8e06SEd Maste static size_t 70*f540a430SEd Maste tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count, int *ms) 710afa8e06SEd Maste { 720afa8e06SEd Maste struct frame *fp; 730afa8e06SEd Maste unsigned char pkt[sizeof(*fp) + 1]; 740afa8e06SEd Maste const size_t len = d->tx_len + 1; 750afa8e06SEd Maste int n; 760afa8e06SEd Maste 770afa8e06SEd Maste if (d->tx_len - CTAP_INIT_HEADER_LEN > sizeof(fp->body.init.data)) 780afa8e06SEd Maste return (0); 790afa8e06SEd Maste 800afa8e06SEd Maste memset(&pkt, 0, sizeof(pkt)); 810afa8e06SEd Maste fp = (struct frame *)(pkt + 1); 820afa8e06SEd Maste fp->cid = d->cid; 830afa8e06SEd Maste fp->body.init.cmd = CTAP_FRAME_INIT | cmd; 840afa8e06SEd Maste fp->body.init.bcnth = (count >> 8) & 0xff; 850afa8e06SEd Maste fp->body.init.bcntl = count & 0xff; 860afa8e06SEd Maste count = MIN(count, d->tx_len - CTAP_INIT_HEADER_LEN); 870afa8e06SEd Maste memcpy(&fp->body.init.data, buf, count); 880afa8e06SEd Maste 89*f540a430SEd Maste if (len > sizeof(pkt) || (n = tx_pkt(d, pkt, len, ms)) < 0 || 90*f540a430SEd Maste (size_t)n != len) 910afa8e06SEd Maste return (0); 920afa8e06SEd Maste 930afa8e06SEd Maste return (count); 940afa8e06SEd Maste } 950afa8e06SEd Maste 960afa8e06SEd Maste static size_t 97*f540a430SEd Maste tx_frame(fido_dev_t *d, uint8_t seq, const void *buf, size_t count, int *ms) 980afa8e06SEd Maste { 990afa8e06SEd Maste struct frame *fp; 1000afa8e06SEd Maste unsigned char pkt[sizeof(*fp) + 1]; 1010afa8e06SEd Maste const size_t len = d->tx_len + 1; 1020afa8e06SEd Maste int n; 1030afa8e06SEd Maste 1040afa8e06SEd Maste if (d->tx_len - CTAP_CONT_HEADER_LEN > sizeof(fp->body.cont.data)) 1050afa8e06SEd Maste return (0); 1060afa8e06SEd Maste 1070afa8e06SEd Maste memset(&pkt, 0, sizeof(pkt)); 1080afa8e06SEd Maste fp = (struct frame *)(pkt + 1); 1090afa8e06SEd Maste fp->cid = d->cid; 1100afa8e06SEd Maste fp->body.cont.seq = seq; 1110afa8e06SEd Maste count = MIN(count, d->tx_len - CTAP_CONT_HEADER_LEN); 1120afa8e06SEd Maste memcpy(&fp->body.cont.data, buf, count); 1130afa8e06SEd Maste 114*f540a430SEd Maste if (len > sizeof(pkt) || (n = tx_pkt(d, pkt, len, ms)) < 0 || 115*f540a430SEd Maste (size_t)n != len) 1160afa8e06SEd Maste return (0); 1170afa8e06SEd Maste 1180afa8e06SEd Maste return (count); 1190afa8e06SEd Maste } 1200afa8e06SEd Maste 1210afa8e06SEd Maste static int 122*f540a430SEd Maste tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count, int *ms) 1230afa8e06SEd Maste { 1240afa8e06SEd Maste size_t n, sent; 1250afa8e06SEd Maste 126*f540a430SEd Maste if ((sent = tx_preamble(d, cmd, buf, count, ms)) == 0) { 1270afa8e06SEd Maste fido_log_debug("%s: tx_preamble", __func__); 1280afa8e06SEd Maste return (-1); 1290afa8e06SEd Maste } 1300afa8e06SEd Maste 1310afa8e06SEd Maste for (uint8_t seq = 0; sent < count; sent += n) { 1320afa8e06SEd Maste if (seq & 0x80) { 1330afa8e06SEd Maste fido_log_debug("%s: seq & 0x80", __func__); 1340afa8e06SEd Maste return (-1); 1350afa8e06SEd Maste } 136*f540a430SEd Maste if ((n = tx_frame(d, seq++, buf + sent, count - sent, 137*f540a430SEd Maste ms)) == 0) { 1380afa8e06SEd Maste fido_log_debug("%s: tx_frame", __func__); 1390afa8e06SEd Maste return (-1); 1400afa8e06SEd Maste } 1410afa8e06SEd Maste } 1420afa8e06SEd Maste 1430afa8e06SEd Maste return (0); 1440afa8e06SEd Maste } 1450afa8e06SEd Maste 146*f540a430SEd Maste static int 147*f540a430SEd Maste transport_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count, int *ms) 148*f540a430SEd Maste { 149*f540a430SEd Maste struct timespec ts; 150*f540a430SEd Maste int n; 151*f540a430SEd Maste 152*f540a430SEd Maste if (fido_time_now(&ts) != 0) 153*f540a430SEd Maste return (-1); 154*f540a430SEd Maste 155*f540a430SEd Maste n = d->transport.tx(d, cmd, buf, count); 156*f540a430SEd Maste 157*f540a430SEd Maste if (fido_time_delta(&ts, ms) != 0) 158*f540a430SEd Maste return (-1); 159*f540a430SEd Maste 160*f540a430SEd Maste return (n); 161*f540a430SEd Maste } 162*f540a430SEd Maste 1630afa8e06SEd Maste int 164*f540a430SEd Maste fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count, int *ms) 1650afa8e06SEd Maste { 1660afa8e06SEd Maste fido_log_debug("%s: dev=%p, cmd=0x%02x", __func__, (void *)d, cmd); 1670afa8e06SEd Maste fido_log_xxd(buf, count, "%s", __func__); 1680afa8e06SEd Maste 1690afa8e06SEd Maste if (d->transport.tx != NULL) 170*f540a430SEd Maste return (transport_tx(d, cmd, buf, count, ms)); 1710afa8e06SEd Maste if (d->io_handle == NULL || d->io.write == NULL || count > UINT16_MAX) { 1720afa8e06SEd Maste fido_log_debug("%s: invalid argument", __func__); 1730afa8e06SEd Maste return (-1); 1740afa8e06SEd Maste } 1750afa8e06SEd Maste 176*f540a430SEd Maste return (count == 0 ? tx_empty(d, cmd, ms) : tx(d, cmd, buf, count, ms)); 1770afa8e06SEd Maste } 1780afa8e06SEd Maste 1790afa8e06SEd Maste static int 180*f540a430SEd Maste rx_frame(fido_dev_t *d, struct frame *fp, int *ms) 1810afa8e06SEd Maste { 182*f540a430SEd Maste struct timespec ts; 1830afa8e06SEd Maste int n; 1840afa8e06SEd Maste 1850afa8e06SEd Maste memset(fp, 0, sizeof(*fp)); 1860afa8e06SEd Maste 187*f540a430SEd Maste if (fido_time_now(&ts) != 0) 1880afa8e06SEd Maste return (-1); 1890afa8e06SEd Maste 190*f540a430SEd Maste if (d->rx_len > sizeof(*fp) || (n = d->io.read(d->io_handle, 191*f540a430SEd Maste (unsigned char *)fp, d->rx_len, *ms)) < 0 || (size_t)n != d->rx_len) 192*f540a430SEd Maste return (-1); 193*f540a430SEd Maste 194*f540a430SEd Maste return (fido_time_delta(&ts, ms)); 1950afa8e06SEd Maste } 1960afa8e06SEd Maste 1970afa8e06SEd Maste static int 198*f540a430SEd Maste rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int *ms) 1990afa8e06SEd Maste { 2000afa8e06SEd Maste do { 2010afa8e06SEd Maste if (rx_frame(d, fp, ms) < 0) 2020afa8e06SEd Maste return (-1); 2030afa8e06SEd Maste #ifdef FIDO_FUZZ 2040afa8e06SEd Maste fp->cid = d->cid; 2050afa8e06SEd Maste #endif 2060afa8e06SEd Maste } while (fp->cid != d->cid || (fp->cid == d->cid && 2070afa8e06SEd Maste fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE))); 2080afa8e06SEd Maste 2090afa8e06SEd Maste if (d->rx_len > sizeof(*fp)) 2100afa8e06SEd Maste return (-1); 2110afa8e06SEd Maste 2120afa8e06SEd Maste fido_log_xxd(fp, d->rx_len, "%s", __func__); 2130afa8e06SEd Maste #ifdef FIDO_FUZZ 2140afa8e06SEd Maste fp->body.init.cmd = (CTAP_FRAME_INIT | cmd); 2150afa8e06SEd Maste #endif 2160afa8e06SEd Maste 2170afa8e06SEd Maste if (fp->cid != d->cid || fp->body.init.cmd != (CTAP_FRAME_INIT | cmd)) { 2180afa8e06SEd Maste fido_log_debug("%s: cid (0x%x, 0x%x), cmd (0x%02x, 0x%02x)", 2190afa8e06SEd Maste __func__, fp->cid, d->cid, fp->body.init.cmd, cmd); 2200afa8e06SEd Maste return (-1); 2210afa8e06SEd Maste } 2220afa8e06SEd Maste 2230afa8e06SEd Maste return (0); 2240afa8e06SEd Maste } 2250afa8e06SEd Maste 2260afa8e06SEd Maste static int 227*f540a430SEd Maste rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int *ms) 2280afa8e06SEd Maste { 2290afa8e06SEd Maste struct frame f; 2300afa8e06SEd Maste size_t r, payload_len, init_data_len, cont_data_len; 2310afa8e06SEd Maste 2320afa8e06SEd Maste if (d->rx_len <= CTAP_INIT_HEADER_LEN || 2330afa8e06SEd Maste d->rx_len <= CTAP_CONT_HEADER_LEN) 2340afa8e06SEd Maste return (-1); 2350afa8e06SEd Maste 2360afa8e06SEd Maste init_data_len = d->rx_len - CTAP_INIT_HEADER_LEN; 2370afa8e06SEd Maste cont_data_len = d->rx_len - CTAP_CONT_HEADER_LEN; 2380afa8e06SEd Maste 2390afa8e06SEd Maste if (init_data_len > sizeof(f.body.init.data) || 2400afa8e06SEd Maste cont_data_len > sizeof(f.body.cont.data)) 2410afa8e06SEd Maste return (-1); 2420afa8e06SEd Maste 2430afa8e06SEd Maste if (rx_preamble(d, cmd, &f, ms) < 0) { 2440afa8e06SEd Maste fido_log_debug("%s: rx_preamble", __func__); 2450afa8e06SEd Maste return (-1); 2460afa8e06SEd Maste } 2470afa8e06SEd Maste 2480afa8e06SEd Maste payload_len = (size_t)((f.body.init.bcnth << 8) | f.body.init.bcntl); 2490afa8e06SEd Maste fido_log_debug("%s: payload_len=%zu", __func__, payload_len); 2500afa8e06SEd Maste 2510afa8e06SEd Maste if (count < payload_len) { 2520afa8e06SEd Maste fido_log_debug("%s: count < payload_len", __func__); 2530afa8e06SEd Maste return (-1); 2540afa8e06SEd Maste } 2550afa8e06SEd Maste 2560afa8e06SEd Maste if (payload_len < init_data_len) { 2570afa8e06SEd Maste memcpy(buf, f.body.init.data, payload_len); 2580afa8e06SEd Maste return ((int)payload_len); 2590afa8e06SEd Maste } 2600afa8e06SEd Maste 2610afa8e06SEd Maste memcpy(buf, f.body.init.data, init_data_len); 2620afa8e06SEd Maste r = init_data_len; 2630afa8e06SEd Maste 2640afa8e06SEd Maste for (int seq = 0; r < payload_len; seq++) { 2650afa8e06SEd Maste if (rx_frame(d, &f, ms) < 0) { 2660afa8e06SEd Maste fido_log_debug("%s: rx_frame", __func__); 2670afa8e06SEd Maste return (-1); 2680afa8e06SEd Maste } 2690afa8e06SEd Maste 2700afa8e06SEd Maste fido_log_xxd(&f, d->rx_len, "%s", __func__); 2710afa8e06SEd Maste #ifdef FIDO_FUZZ 2720afa8e06SEd Maste f.cid = d->cid; 2730afa8e06SEd Maste f.body.cont.seq = (uint8_t)seq; 2740afa8e06SEd Maste #endif 2750afa8e06SEd Maste 2760afa8e06SEd Maste if (f.cid != d->cid || f.body.cont.seq != seq) { 2770afa8e06SEd Maste fido_log_debug("%s: cid (0x%x, 0x%x), seq (%d, %d)", 2780afa8e06SEd Maste __func__, f.cid, d->cid, f.body.cont.seq, seq); 2790afa8e06SEd Maste return (-1); 2800afa8e06SEd Maste } 2810afa8e06SEd Maste 2820afa8e06SEd Maste if (payload_len - r > cont_data_len) { 2830afa8e06SEd Maste memcpy(buf + r, f.body.cont.data, cont_data_len); 2840afa8e06SEd Maste r += cont_data_len; 2850afa8e06SEd Maste } else { 2860afa8e06SEd Maste memcpy(buf + r, f.body.cont.data, payload_len - r); 2870afa8e06SEd Maste r += payload_len - r; /* break */ 2880afa8e06SEd Maste } 2890afa8e06SEd Maste } 2900afa8e06SEd Maste 2910afa8e06SEd Maste return ((int)r); 2920afa8e06SEd Maste } 2930afa8e06SEd Maste 294*f540a430SEd Maste static int 295*f540a430SEd Maste transport_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int *ms) 296*f540a430SEd Maste { 297*f540a430SEd Maste struct timespec ts; 298*f540a430SEd Maste int n; 299*f540a430SEd Maste 300*f540a430SEd Maste if (fido_time_now(&ts) != 0) 301*f540a430SEd Maste return (-1); 302*f540a430SEd Maste 303*f540a430SEd Maste n = d->transport.rx(d, cmd, buf, count, *ms); 304*f540a430SEd Maste 305*f540a430SEd Maste if (fido_time_delta(&ts, ms) != 0) 306*f540a430SEd Maste return (-1); 307*f540a430SEd Maste 308*f540a430SEd Maste return (n); 309*f540a430SEd Maste } 310*f540a430SEd Maste 3110afa8e06SEd Maste int 312*f540a430SEd Maste fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int *ms) 3130afa8e06SEd Maste { 3140afa8e06SEd Maste int n; 3150afa8e06SEd Maste 3160afa8e06SEd Maste fido_log_debug("%s: dev=%p, cmd=0x%02x, ms=%d", __func__, (void *)d, 317*f540a430SEd Maste cmd, *ms); 3180afa8e06SEd Maste 3190afa8e06SEd Maste if (d->transport.rx != NULL) 320*f540a430SEd Maste return (transport_rx(d, cmd, buf, count, ms)); 3210afa8e06SEd Maste if (d->io_handle == NULL || d->io.read == NULL || count > UINT16_MAX) { 3220afa8e06SEd Maste fido_log_debug("%s: invalid argument", __func__); 3230afa8e06SEd Maste return (-1); 3240afa8e06SEd Maste } 3250afa8e06SEd Maste if ((n = rx(d, cmd, buf, count, ms)) >= 0) 3260afa8e06SEd Maste fido_log_xxd(buf, (size_t)n, "%s", __func__); 3270afa8e06SEd Maste 3280afa8e06SEd Maste return (n); 3290afa8e06SEd Maste } 3300afa8e06SEd Maste 3310afa8e06SEd Maste int 332*f540a430SEd Maste fido_rx_cbor_status(fido_dev_t *d, int *ms) 3330afa8e06SEd Maste { 3340afa8e06SEd Maste unsigned char reply[FIDO_MAXMSG]; 3350afa8e06SEd Maste int reply_len; 3360afa8e06SEd Maste 3370afa8e06SEd Maste if ((reply_len = fido_rx(d, CTAP_CMD_CBOR, &reply, sizeof(reply), 3380afa8e06SEd Maste ms)) < 0 || (size_t)reply_len < 1) { 3390afa8e06SEd Maste fido_log_debug("%s: fido_rx", __func__); 3400afa8e06SEd Maste return (FIDO_ERR_RX); 3410afa8e06SEd Maste } 3420afa8e06SEd Maste 3430afa8e06SEd Maste return (reply[0]); 3440afa8e06SEd Maste } 345