2 * Copyright (c) 2018 Yubico AB. All rights reserved.
3 * Use of this source code is governed by a BSD-style
4 * license that can be found in the LICENSE file.
12 uint32_t cid; /* channel id */
19 uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_INIT_HEADER_LEN];
23 uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_CONT_HEADER_LEN];
29 #define MIN(x, y) ((x) > (y) ? (y) : (x))
33 tx_empty(fido_dev_t *d, uint8_t cmd)
36 unsigned char pkt[sizeof(*fp) + 1];
37 const size_t len = d->tx_len + 1;
40 memset(&pkt, 0, sizeof(pkt));
41 fp = (struct frame *)(pkt + 1);
43 fp->body.init.cmd = CTAP_FRAME_INIT | cmd;
45 if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
46 len)) < 0 || (size_t)n != len)
53 tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
56 unsigned char pkt[sizeof(*fp) + 1];
57 const size_t len = d->tx_len + 1;
60 if (d->tx_len - CTAP_INIT_HEADER_LEN > sizeof(fp->body.init.data))
63 memset(&pkt, 0, sizeof(pkt));
64 fp = (struct frame *)(pkt + 1);
66 fp->body.init.cmd = CTAP_FRAME_INIT | cmd;
67 fp->body.init.bcnth = (count >> 8) & 0xff;
68 fp->body.init.bcntl = count & 0xff;
69 count = MIN(count, d->tx_len - CTAP_INIT_HEADER_LEN);
70 memcpy(&fp->body.init.data, buf, count);
72 if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
73 len)) < 0 || (size_t)n != len)
80 tx_frame(fido_dev_t *d, uint8_t seq, const void *buf, size_t count)
83 unsigned char pkt[sizeof(*fp) + 1];
84 const size_t len = d->tx_len + 1;
87 if (d->tx_len - CTAP_CONT_HEADER_LEN > sizeof(fp->body.cont.data))
90 memset(&pkt, 0, sizeof(pkt));
91 fp = (struct frame *)(pkt + 1);
93 fp->body.cont.seq = seq;
94 count = MIN(count, d->tx_len - CTAP_CONT_HEADER_LEN);
95 memcpy(&fp->body.cont.data, buf, count);
97 if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
98 len)) < 0 || (size_t)n != len)
105 tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count)
109 if ((sent = tx_preamble(d, cmd, buf, count)) == 0) {
110 fido_log_debug("%s: tx_preamble", __func__);
114 for (uint8_t seq = 0; sent < count; sent += n) {
116 fido_log_debug("%s: seq & 0x80", __func__);
119 if ((n = tx_frame(d, seq++, buf + sent, count - sent)) == 0) {
120 fido_log_debug("%s: tx_frame", __func__);
129 fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
131 fido_log_debug("%s: dev=%p, cmd=0x%02x", __func__, (void *)d, cmd);
132 fido_log_xxd(buf, count, "%s", __func__);
134 if (d->transport.tx != NULL)
135 return (d->transport.tx(d, cmd, buf, count));
136 if (d->io_handle == NULL || d->io.write == NULL || count > UINT16_MAX) {
137 fido_log_debug("%s: invalid argument", __func__);
141 return (count == 0 ? tx_empty(d, cmd) : tx(d, cmd, buf, count));
145 rx_frame(fido_dev_t *d, struct frame *fp, int ms)
149 memset(fp, 0, sizeof(*fp));
151 if (d->rx_len > sizeof(*fp) || (n = d->io.read(d->io_handle,
152 (unsigned char *)fp, d->rx_len, ms)) < 0 || (size_t)n != d->rx_len)
159 rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int ms)
162 if (rx_frame(d, fp, ms) < 0)
167 } while (fp->cid != d->cid || (fp->cid == d->cid &&
168 fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE)));
170 if (d->rx_len > sizeof(*fp))
173 fido_log_xxd(fp, d->rx_len, "%s", __func__);
175 fp->body.init.cmd = (CTAP_FRAME_INIT | cmd);
178 if (fp->cid != d->cid || fp->body.init.cmd != (CTAP_FRAME_INIT | cmd)) {
179 fido_log_debug("%s: cid (0x%x, 0x%x), cmd (0x%02x, 0x%02x)",
180 __func__, fp->cid, d->cid, fp->body.init.cmd, cmd);
188 rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
191 size_t r, payload_len, init_data_len, cont_data_len;
193 if (d->rx_len <= CTAP_INIT_HEADER_LEN ||
194 d->rx_len <= CTAP_CONT_HEADER_LEN)
197 init_data_len = d->rx_len - CTAP_INIT_HEADER_LEN;
198 cont_data_len = d->rx_len - CTAP_CONT_HEADER_LEN;
200 if (init_data_len > sizeof(f.body.init.data) ||
201 cont_data_len > sizeof(f.body.cont.data))
204 if (rx_preamble(d, cmd, &f, ms) < 0) {
205 fido_log_debug("%s: rx_preamble", __func__);
209 payload_len = (size_t)((f.body.init.bcnth << 8) | f.body.init.bcntl);
210 fido_log_debug("%s: payload_len=%zu", __func__, payload_len);
212 if (count < payload_len) {
213 fido_log_debug("%s: count < payload_len", __func__);
217 if (payload_len < init_data_len) {
218 memcpy(buf, f.body.init.data, payload_len);
219 return ((int)payload_len);
222 memcpy(buf, f.body.init.data, init_data_len);
225 for (int seq = 0; r < payload_len; seq++) {
226 if (rx_frame(d, &f, ms) < 0) {
227 fido_log_debug("%s: rx_frame", __func__);
231 fido_log_xxd(&f, d->rx_len, "%s", __func__);
234 f.body.cont.seq = (uint8_t)seq;
237 if (f.cid != d->cid || f.body.cont.seq != seq) {
238 fido_log_debug("%s: cid (0x%x, 0x%x), seq (%d, %d)",
239 __func__, f.cid, d->cid, f.body.cont.seq, seq);
243 if (payload_len - r > cont_data_len) {
244 memcpy(buf + r, f.body.cont.data, cont_data_len);
247 memcpy(buf + r, f.body.cont.data, payload_len - r);
248 r += payload_len - r; /* break */
256 fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms)
260 fido_log_debug("%s: dev=%p, cmd=0x%02x, ms=%d", __func__, (void *)d,
263 if (d->transport.rx != NULL)
264 return (d->transport.rx(d, cmd, buf, count, ms));
265 if (d->io_handle == NULL || d->io.read == NULL || count > UINT16_MAX) {
266 fido_log_debug("%s: invalid argument", __func__);
269 if ((n = rx(d, cmd, buf, count, ms)) >= 0)
270 fido_log_xxd(buf, (size_t)n, "%s", __func__);
276 fido_rx_cbor_status(fido_dev_t *d, int ms)
278 unsigned char reply[FIDO_MAXMSG];
281 if ((reply_len = fido_rx(d, CTAP_CMD_CBOR, &reply, sizeof(reply),
282 ms)) < 0 || (size_t)reply_len < 1) {
283 fido_log_debug("%s: fido_rx", __func__);
284 return (FIDO_ERR_RX);