1*0afa8e06SEd Maste /* 2*0afa8e06SEd Maste * Copyright (c) 2018 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 "packed.h" 9*0afa8e06SEd Maste 10*0afa8e06SEd Maste PACKED_TYPE(frame_t, 11*0afa8e06SEd Maste struct frame { 12*0afa8e06SEd Maste uint32_t cid; /* channel id */ 13*0afa8e06SEd Maste union { 14*0afa8e06SEd Maste uint8_t type; 15*0afa8e06SEd Maste struct { 16*0afa8e06SEd Maste uint8_t cmd; 17*0afa8e06SEd Maste uint8_t bcnth; 18*0afa8e06SEd Maste uint8_t bcntl; 19*0afa8e06SEd Maste uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_INIT_HEADER_LEN]; 20*0afa8e06SEd Maste } init; 21*0afa8e06SEd Maste struct { 22*0afa8e06SEd Maste uint8_t seq; 23*0afa8e06SEd Maste uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_CONT_HEADER_LEN]; 24*0afa8e06SEd Maste } cont; 25*0afa8e06SEd Maste } body; 26*0afa8e06SEd Maste }) 27*0afa8e06SEd Maste 28*0afa8e06SEd Maste #ifndef MIN 29*0afa8e06SEd Maste #define MIN(x, y) ((x) > (y) ? (y) : (x)) 30*0afa8e06SEd Maste #endif 31*0afa8e06SEd Maste 32*0afa8e06SEd Maste static int 33*0afa8e06SEd Maste tx_empty(fido_dev_t *d, uint8_t cmd) 34*0afa8e06SEd Maste { 35*0afa8e06SEd Maste struct frame *fp; 36*0afa8e06SEd Maste unsigned char pkt[sizeof(*fp) + 1]; 37*0afa8e06SEd Maste const size_t len = d->tx_len + 1; 38*0afa8e06SEd Maste int n; 39*0afa8e06SEd Maste 40*0afa8e06SEd Maste memset(&pkt, 0, sizeof(pkt)); 41*0afa8e06SEd Maste fp = (struct frame *)(pkt + 1); 42*0afa8e06SEd Maste fp->cid = d->cid; 43*0afa8e06SEd Maste fp->body.init.cmd = CTAP_FRAME_INIT | cmd; 44*0afa8e06SEd Maste 45*0afa8e06SEd Maste if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt, 46*0afa8e06SEd Maste len)) < 0 || (size_t)n != len) 47*0afa8e06SEd Maste return (-1); 48*0afa8e06SEd Maste 49*0afa8e06SEd Maste return (0); 50*0afa8e06SEd Maste } 51*0afa8e06SEd Maste 52*0afa8e06SEd Maste static size_t 53*0afa8e06SEd Maste tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) 54*0afa8e06SEd Maste { 55*0afa8e06SEd Maste struct frame *fp; 56*0afa8e06SEd Maste unsigned char pkt[sizeof(*fp) + 1]; 57*0afa8e06SEd Maste const size_t len = d->tx_len + 1; 58*0afa8e06SEd Maste int n; 59*0afa8e06SEd Maste 60*0afa8e06SEd Maste if (d->tx_len - CTAP_INIT_HEADER_LEN > sizeof(fp->body.init.data)) 61*0afa8e06SEd Maste return (0); 62*0afa8e06SEd Maste 63*0afa8e06SEd Maste memset(&pkt, 0, sizeof(pkt)); 64*0afa8e06SEd Maste fp = (struct frame *)(pkt + 1); 65*0afa8e06SEd Maste fp->cid = d->cid; 66*0afa8e06SEd Maste fp->body.init.cmd = CTAP_FRAME_INIT | cmd; 67*0afa8e06SEd Maste fp->body.init.bcnth = (count >> 8) & 0xff; 68*0afa8e06SEd Maste fp->body.init.bcntl = count & 0xff; 69*0afa8e06SEd Maste count = MIN(count, d->tx_len - CTAP_INIT_HEADER_LEN); 70*0afa8e06SEd Maste memcpy(&fp->body.init.data, buf, count); 71*0afa8e06SEd Maste 72*0afa8e06SEd Maste if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt, 73*0afa8e06SEd Maste len)) < 0 || (size_t)n != len) 74*0afa8e06SEd Maste return (0); 75*0afa8e06SEd Maste 76*0afa8e06SEd Maste return (count); 77*0afa8e06SEd Maste } 78*0afa8e06SEd Maste 79*0afa8e06SEd Maste static size_t 80*0afa8e06SEd Maste tx_frame(fido_dev_t *d, uint8_t seq, const void *buf, size_t count) 81*0afa8e06SEd Maste { 82*0afa8e06SEd Maste struct frame *fp; 83*0afa8e06SEd Maste unsigned char pkt[sizeof(*fp) + 1]; 84*0afa8e06SEd Maste const size_t len = d->tx_len + 1; 85*0afa8e06SEd Maste int n; 86*0afa8e06SEd Maste 87*0afa8e06SEd Maste if (d->tx_len - CTAP_CONT_HEADER_LEN > sizeof(fp->body.cont.data)) 88*0afa8e06SEd Maste return (0); 89*0afa8e06SEd Maste 90*0afa8e06SEd Maste memset(&pkt, 0, sizeof(pkt)); 91*0afa8e06SEd Maste fp = (struct frame *)(pkt + 1); 92*0afa8e06SEd Maste fp->cid = d->cid; 93*0afa8e06SEd Maste fp->body.cont.seq = seq; 94*0afa8e06SEd Maste count = MIN(count, d->tx_len - CTAP_CONT_HEADER_LEN); 95*0afa8e06SEd Maste memcpy(&fp->body.cont.data, buf, count); 96*0afa8e06SEd Maste 97*0afa8e06SEd Maste if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt, 98*0afa8e06SEd Maste len)) < 0 || (size_t)n != len) 99*0afa8e06SEd Maste return (0); 100*0afa8e06SEd Maste 101*0afa8e06SEd Maste return (count); 102*0afa8e06SEd Maste } 103*0afa8e06SEd Maste 104*0afa8e06SEd Maste static int 105*0afa8e06SEd Maste tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count) 106*0afa8e06SEd Maste { 107*0afa8e06SEd Maste size_t n, sent; 108*0afa8e06SEd Maste 109*0afa8e06SEd Maste if ((sent = tx_preamble(d, cmd, buf, count)) == 0) { 110*0afa8e06SEd Maste fido_log_debug("%s: tx_preamble", __func__); 111*0afa8e06SEd Maste return (-1); 112*0afa8e06SEd Maste } 113*0afa8e06SEd Maste 114*0afa8e06SEd Maste for (uint8_t seq = 0; sent < count; sent += n) { 115*0afa8e06SEd Maste if (seq & 0x80) { 116*0afa8e06SEd Maste fido_log_debug("%s: seq & 0x80", __func__); 117*0afa8e06SEd Maste return (-1); 118*0afa8e06SEd Maste } 119*0afa8e06SEd Maste if ((n = tx_frame(d, seq++, buf + sent, count - sent)) == 0) { 120*0afa8e06SEd Maste fido_log_debug("%s: tx_frame", __func__); 121*0afa8e06SEd Maste return (-1); 122*0afa8e06SEd Maste } 123*0afa8e06SEd Maste } 124*0afa8e06SEd Maste 125*0afa8e06SEd Maste return (0); 126*0afa8e06SEd Maste } 127*0afa8e06SEd Maste 128*0afa8e06SEd Maste int 129*0afa8e06SEd Maste fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) 130*0afa8e06SEd Maste { 131*0afa8e06SEd Maste fido_log_debug("%s: dev=%p, cmd=0x%02x", __func__, (void *)d, cmd); 132*0afa8e06SEd Maste fido_log_xxd(buf, count, "%s", __func__); 133*0afa8e06SEd Maste 134*0afa8e06SEd Maste if (d->transport.tx != NULL) 135*0afa8e06SEd Maste return (d->transport.tx(d, cmd, buf, count)); 136*0afa8e06SEd Maste if (d->io_handle == NULL || d->io.write == NULL || count > UINT16_MAX) { 137*0afa8e06SEd Maste fido_log_debug("%s: invalid argument", __func__); 138*0afa8e06SEd Maste return (-1); 139*0afa8e06SEd Maste } 140*0afa8e06SEd Maste 141*0afa8e06SEd Maste return (count == 0 ? tx_empty(d, cmd) : tx(d, cmd, buf, count)); 142*0afa8e06SEd Maste } 143*0afa8e06SEd Maste 144*0afa8e06SEd Maste static int 145*0afa8e06SEd Maste rx_frame(fido_dev_t *d, struct frame *fp, int ms) 146*0afa8e06SEd Maste { 147*0afa8e06SEd Maste int n; 148*0afa8e06SEd Maste 149*0afa8e06SEd Maste memset(fp, 0, sizeof(*fp)); 150*0afa8e06SEd Maste 151*0afa8e06SEd Maste if (d->rx_len > sizeof(*fp) || (n = d->io.read(d->io_handle, 152*0afa8e06SEd Maste (unsigned char *)fp, d->rx_len, ms)) < 0 || (size_t)n != d->rx_len) 153*0afa8e06SEd Maste return (-1); 154*0afa8e06SEd Maste 155*0afa8e06SEd Maste return (0); 156*0afa8e06SEd Maste } 157*0afa8e06SEd Maste 158*0afa8e06SEd Maste static int 159*0afa8e06SEd Maste rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int ms) 160*0afa8e06SEd Maste { 161*0afa8e06SEd Maste do { 162*0afa8e06SEd Maste if (rx_frame(d, fp, ms) < 0) 163*0afa8e06SEd Maste return (-1); 164*0afa8e06SEd Maste #ifdef FIDO_FUZZ 165*0afa8e06SEd Maste fp->cid = d->cid; 166*0afa8e06SEd Maste #endif 167*0afa8e06SEd Maste } while (fp->cid != d->cid || (fp->cid == d->cid && 168*0afa8e06SEd Maste fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE))); 169*0afa8e06SEd Maste 170*0afa8e06SEd Maste if (d->rx_len > sizeof(*fp)) 171*0afa8e06SEd Maste return (-1); 172*0afa8e06SEd Maste 173*0afa8e06SEd Maste fido_log_xxd(fp, d->rx_len, "%s", __func__); 174*0afa8e06SEd Maste #ifdef FIDO_FUZZ 175*0afa8e06SEd Maste fp->body.init.cmd = (CTAP_FRAME_INIT | cmd); 176*0afa8e06SEd Maste #endif 177*0afa8e06SEd Maste 178*0afa8e06SEd Maste if (fp->cid != d->cid || fp->body.init.cmd != (CTAP_FRAME_INIT | cmd)) { 179*0afa8e06SEd Maste fido_log_debug("%s: cid (0x%x, 0x%x), cmd (0x%02x, 0x%02x)", 180*0afa8e06SEd Maste __func__, fp->cid, d->cid, fp->body.init.cmd, cmd); 181*0afa8e06SEd Maste return (-1); 182*0afa8e06SEd Maste } 183*0afa8e06SEd Maste 184*0afa8e06SEd Maste return (0); 185*0afa8e06SEd Maste } 186*0afa8e06SEd Maste 187*0afa8e06SEd Maste static int 188*0afa8e06SEd Maste rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms) 189*0afa8e06SEd Maste { 190*0afa8e06SEd Maste struct frame f; 191*0afa8e06SEd Maste size_t r, payload_len, init_data_len, cont_data_len; 192*0afa8e06SEd Maste 193*0afa8e06SEd Maste if (d->rx_len <= CTAP_INIT_HEADER_LEN || 194*0afa8e06SEd Maste d->rx_len <= CTAP_CONT_HEADER_LEN) 195*0afa8e06SEd Maste return (-1); 196*0afa8e06SEd Maste 197*0afa8e06SEd Maste init_data_len = d->rx_len - CTAP_INIT_HEADER_LEN; 198*0afa8e06SEd Maste cont_data_len = d->rx_len - CTAP_CONT_HEADER_LEN; 199*0afa8e06SEd Maste 200*0afa8e06SEd Maste if (init_data_len > sizeof(f.body.init.data) || 201*0afa8e06SEd Maste cont_data_len > sizeof(f.body.cont.data)) 202*0afa8e06SEd Maste return (-1); 203*0afa8e06SEd Maste 204*0afa8e06SEd Maste if (rx_preamble(d, cmd, &f, ms) < 0) { 205*0afa8e06SEd Maste fido_log_debug("%s: rx_preamble", __func__); 206*0afa8e06SEd Maste return (-1); 207*0afa8e06SEd Maste } 208*0afa8e06SEd Maste 209*0afa8e06SEd Maste payload_len = (size_t)((f.body.init.bcnth << 8) | f.body.init.bcntl); 210*0afa8e06SEd Maste fido_log_debug("%s: payload_len=%zu", __func__, payload_len); 211*0afa8e06SEd Maste 212*0afa8e06SEd Maste if (count < payload_len) { 213*0afa8e06SEd Maste fido_log_debug("%s: count < payload_len", __func__); 214*0afa8e06SEd Maste return (-1); 215*0afa8e06SEd Maste } 216*0afa8e06SEd Maste 217*0afa8e06SEd Maste if (payload_len < init_data_len) { 218*0afa8e06SEd Maste memcpy(buf, f.body.init.data, payload_len); 219*0afa8e06SEd Maste return ((int)payload_len); 220*0afa8e06SEd Maste } 221*0afa8e06SEd Maste 222*0afa8e06SEd Maste memcpy(buf, f.body.init.data, init_data_len); 223*0afa8e06SEd Maste r = init_data_len; 224*0afa8e06SEd Maste 225*0afa8e06SEd Maste for (int seq = 0; r < payload_len; seq++) { 226*0afa8e06SEd Maste if (rx_frame(d, &f, ms) < 0) { 227*0afa8e06SEd Maste fido_log_debug("%s: rx_frame", __func__); 228*0afa8e06SEd Maste return (-1); 229*0afa8e06SEd Maste } 230*0afa8e06SEd Maste 231*0afa8e06SEd Maste fido_log_xxd(&f, d->rx_len, "%s", __func__); 232*0afa8e06SEd Maste #ifdef FIDO_FUZZ 233*0afa8e06SEd Maste f.cid = d->cid; 234*0afa8e06SEd Maste f.body.cont.seq = (uint8_t)seq; 235*0afa8e06SEd Maste #endif 236*0afa8e06SEd Maste 237*0afa8e06SEd Maste if (f.cid != d->cid || f.body.cont.seq != seq) { 238*0afa8e06SEd Maste fido_log_debug("%s: cid (0x%x, 0x%x), seq (%d, %d)", 239*0afa8e06SEd Maste __func__, f.cid, d->cid, f.body.cont.seq, seq); 240*0afa8e06SEd Maste return (-1); 241*0afa8e06SEd Maste } 242*0afa8e06SEd Maste 243*0afa8e06SEd Maste if (payload_len - r > cont_data_len) { 244*0afa8e06SEd Maste memcpy(buf + r, f.body.cont.data, cont_data_len); 245*0afa8e06SEd Maste r += cont_data_len; 246*0afa8e06SEd Maste } else { 247*0afa8e06SEd Maste memcpy(buf + r, f.body.cont.data, payload_len - r); 248*0afa8e06SEd Maste r += payload_len - r; /* break */ 249*0afa8e06SEd Maste } 250*0afa8e06SEd Maste } 251*0afa8e06SEd Maste 252*0afa8e06SEd Maste return ((int)r); 253*0afa8e06SEd Maste } 254*0afa8e06SEd Maste 255*0afa8e06SEd Maste int 256*0afa8e06SEd Maste fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms) 257*0afa8e06SEd Maste { 258*0afa8e06SEd Maste int n; 259*0afa8e06SEd Maste 260*0afa8e06SEd Maste fido_log_debug("%s: dev=%p, cmd=0x%02x, ms=%d", __func__, (void *)d, 261*0afa8e06SEd Maste cmd, ms); 262*0afa8e06SEd Maste 263*0afa8e06SEd Maste if (d->transport.rx != NULL) 264*0afa8e06SEd Maste return (d->transport.rx(d, cmd, buf, count, ms)); 265*0afa8e06SEd Maste if (d->io_handle == NULL || d->io.read == NULL || count > UINT16_MAX) { 266*0afa8e06SEd Maste fido_log_debug("%s: invalid argument", __func__); 267*0afa8e06SEd Maste return (-1); 268*0afa8e06SEd Maste } 269*0afa8e06SEd Maste if ((n = rx(d, cmd, buf, count, ms)) >= 0) 270*0afa8e06SEd Maste fido_log_xxd(buf, (size_t)n, "%s", __func__); 271*0afa8e06SEd Maste 272*0afa8e06SEd Maste return (n); 273*0afa8e06SEd Maste } 274*0afa8e06SEd Maste 275*0afa8e06SEd Maste int 276*0afa8e06SEd Maste fido_rx_cbor_status(fido_dev_t *d, int ms) 277*0afa8e06SEd Maste { 278*0afa8e06SEd Maste unsigned char reply[FIDO_MAXMSG]; 279*0afa8e06SEd Maste int reply_len; 280*0afa8e06SEd Maste 281*0afa8e06SEd Maste if ((reply_len = fido_rx(d, CTAP_CMD_CBOR, &reply, sizeof(reply), 282*0afa8e06SEd Maste ms)) < 0 || (size_t)reply_len < 1) { 283*0afa8e06SEd Maste fido_log_debug("%s: fido_rx", __func__); 284*0afa8e06SEd Maste return (FIDO_ERR_RX); 285*0afa8e06SEd Maste } 286*0afa8e06SEd Maste 287*0afa8e06SEd Maste return (reply[0]); 288*0afa8e06SEd Maste } 289