summaryrefslogtreecommitdiff
path: root/src/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/io.c')
-rw-r--r--src/io.c202
1 files changed, 114 insertions, 88 deletions
diff --git a/src/io.c b/src/io.c
index aa88720..af2f49a 100644
--- a/src/io.c
+++ b/src/io.c
@@ -33,25 +33,40 @@ struct frame {
33#define MIN(x, y) ((x) > (y) ? (y) : (x)) 33#define MIN(x, y) ((x) > (y) ? (y) : (x))
34#endif 34#endif
35 35
36static size_t 36static int
37tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) 37tx_empty(fido_dev_t *d, uint8_t cmd)
38{ 38{
39 struct frame *fp; 39 struct frame *fp;
40 unsigned char pkt[sizeof(*fp) + 1]; 40 unsigned char pkt[sizeof(*fp) + 1];
41 int n; 41 int n;
42 42
43 if (d->io.write == NULL || (cmd & 0x80) == 0) 43 memset(&pkt, 0, sizeof(pkt));
44 return (0); 44 fp = (struct frame *)(pkt + 1);
45 fp->cid = d->cid;
46 fp->body.init.cmd = CTAP_FRAME_INIT | cmd;
47
48 n = d->io.write(d->io_handle, pkt, sizeof(pkt));
49 if (n < 0 || (size_t)n != sizeof(pkt))
50 return (-1);
51
52 return (0);
53}
54
55static size_t
56tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
57{
58 struct frame *fp;
59 unsigned char pkt[sizeof(*fp) + 1];
60 int n;
45 61
46 memset(&pkt, 0, sizeof(pkt)); 62 memset(&pkt, 0, sizeof(pkt));
47 fp = (struct frame *)(pkt + 1); 63 fp = (struct frame *)(pkt + 1);
48 fp->cid = d->cid; 64 fp->cid = d->cid;
49 fp->body.init.cmd = 0x80 | cmd; 65 fp->body.init.cmd = CTAP_FRAME_INIT | cmd;
50 fp->body.init.bcnth = (count >> 8) & 0xff; 66 fp->body.init.bcnth = (count >> 8) & 0xff;
51 fp->body.init.bcntl = count & 0xff; 67 fp->body.init.bcntl = count & 0xff;
52 count = MIN(count, sizeof(fp->body.init.data)); 68 count = MIN(count, sizeof(fp->body.init.data));
53 if (count) 69 memcpy(&fp->body.init.data, buf, count);
54 memcpy(&fp->body.init.data, buf, count);
55 70
56 n = d->io.write(d->io_handle, pkt, sizeof(pkt)); 71 n = d->io.write(d->io_handle, pkt, sizeof(pkt));
57 if (n < 0 || (size_t)n != sizeof(pkt)) 72 if (n < 0 || (size_t)n != sizeof(pkt))
@@ -61,19 +76,16 @@ tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
61} 76}
62 77
63static size_t 78static size_t
64tx_frame(fido_dev_t *d, int seq, const void *buf, size_t count) 79tx_frame(fido_dev_t *d, uint8_t seq, const void *buf, size_t count)
65{ 80{
66 struct frame *fp; 81 struct frame *fp;
67 unsigned char pkt[sizeof(*fp) + 1]; 82 unsigned char pkt[sizeof(*fp) + 1];
68 int n; 83 int n;
69 84
70 if (d->io.write == NULL || seq < 0 || seq > UINT8_MAX)
71 return (0);
72
73 memset(&pkt, 0, sizeof(pkt)); 85 memset(&pkt, 0, sizeof(pkt));
74 fp = (struct frame *)(pkt + 1); 86 fp = (struct frame *)(pkt + 1);
75 fp->cid = d->cid; 87 fp->cid = d->cid;
76 fp->body.cont.seq = (uint8_t)seq; 88 fp->body.cont.seq = seq;
77 count = MIN(count, sizeof(fp->body.cont.data)); 89 count = MIN(count, sizeof(fp->body.cont.data));
78 memcpy(&fp->body.cont.data, buf, count); 90 memcpy(&fp->body.cont.data, buf, count);
79 91
@@ -84,52 +96,56 @@ tx_frame(fido_dev_t *d, int seq, const void *buf, size_t count)
84 return (count); 96 return (count);
85} 97}
86 98
87int 99static int
88fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) 100tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count)
89{ 101{
90 int seq = 0; 102 size_t n, sent;
91 size_t sent;
92
93 fido_log_debug("%s: d=%p, cmd=0x%02x, buf=%p, count=%zu", __func__,
94 (void *)d, cmd, buf, count);
95 fido_log_xxd(buf, count);
96
97 if (d->io_handle == NULL || count > UINT16_MAX) {
98 fido_log_debug("%s: invalid argument (%p, %zu)", __func__,
99 d->io_handle, count);
100 return (-1);
101 }
102 103
103 if ((sent = tx_preamble(d, cmd, buf, count)) == 0) { 104 if ((sent = tx_preamble(d, cmd, buf, count)) == 0) {
104 fido_log_debug("%s: tx_preamble", __func__); 105 fido_log_debug("%s: tx_preamble", __func__);
105 return (-1); 106 return (-1);
106 } 107 }
107 108
108 while (sent < count) { 109 for (uint8_t seq = 0; sent < count; sent += n) {
109 if (seq & 0x80) { 110 if (seq & 0x80) {
110 fido_log_debug("%s: seq & 0x80", __func__); 111 fido_log_debug("%s: seq & 0x80", __func__);
111 return (-1); 112 return (-1);
112 } 113 }
113 const uint8_t *p = (const uint8_t *)buf + sent; 114 if ((n = tx_frame(d, seq++, buf + sent, count - sent)) == 0) {
114 size_t n = tx_frame(d, seq++, p, count - sent);
115 if (n == 0) {
116 fido_log_debug("%s: tx_frame", __func__); 115 fido_log_debug("%s: tx_frame", __func__);
117 return (-1); 116 return (-1);
118 } 117 }
119 sent += n;
120 } 118 }
121 119
122 return (0); 120 return (0);
123} 121}
124 122
123int
124fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
125{
126 fido_log_debug("%s: d=%p, cmd=0x%02x, buf=%p, count=%zu", __func__,
127 (void *)d, cmd, (const void *)buf, count);
128 fido_log_xxd(buf, count);
129
130 if (d->transport.tx != NULL)
131 return (d->transport.tx(d, cmd, buf, count));
132
133 if (d->io_handle == NULL || d->io.write == NULL || count > UINT16_MAX) {
134 fido_log_debug("%s: invalid argument", __func__);
135 return (-1);
136 }
137
138 if (count == 0)
139 return (tx_empty(d, cmd));
140
141 return (tx(d, cmd, buf, count));
142}
143
125static int 144static int
126rx_frame(fido_dev_t *d, struct frame *fp, int ms) 145rx_frame(fido_dev_t *d, struct frame *fp, int ms)
127{ 146{
128 int n; 147 int n;
129 148
130 if (d->io.read == NULL)
131 return (-1);
132
133 n = d->io.read(d->io_handle, (unsigned char *)fp, sizeof(*fp), ms); 149 n = d->io.read(d->io_handle, (unsigned char *)fp, sizeof(*fp), ms);
134 if (n < 0 || (size_t)n != sizeof(*fp)) 150 if (n < 0 || (size_t)n != sizeof(*fp))
135 return (-1); 151 return (-1);
@@ -138,7 +154,7 @@ rx_frame(fido_dev_t *d, struct frame *fp, int ms)
138} 154}
139 155
140static int 156static int
141rx_preamble(fido_dev_t *d, struct frame *fp, int ms) 157rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int ms)
142{ 158{
143 do { 159 do {
144 if (rx_frame(d, fp, ms) < 0) 160 if (rx_frame(d, fp, ms) < 0)
@@ -149,66 +165,57 @@ rx_preamble(fido_dev_t *d, struct frame *fp, int ms)
149 } while (fp->cid == d->cid && 165 } while (fp->cid == d->cid &&
150 fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE)); 166 fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE));
151 167
168 fido_log_debug("%s: initiation frame at %p", __func__, (void *)fp);
169 fido_log_xxd(fp, sizeof(*fp));
170
171#ifdef FIDO_FUZZ
172 fp->body.init.cmd = (CTAP_FRAME_INIT | cmd);
173#endif
174
175 if (fp->cid != d->cid || fp->body.init.cmd != (CTAP_FRAME_INIT | cmd)) {
176 fido_log_debug("%s: cid (0x%x, 0x%x), cmd (0x%02x, 0x%02x)",
177 __func__, fp->cid, d->cid, fp->body.init.cmd, cmd);
178 return (-1);
179 }
180
152 return (0); 181 return (0);
153} 182}
154 183
155int 184static int
156fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms) 185rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
157{ 186{
158 struct frame f; 187 struct frame f;
159 uint16_t r; 188 uint16_t r, payload_len;
160 uint16_t flen;
161 int seq;
162
163 if (d->io_handle == NULL || (cmd & 0x80) == 0) {
164 fido_log_debug("%s: invalid argument (%p, 0x%02x)", __func__,
165 d->io_handle, cmd);
166 return (-1);
167 }
168 189
169 if (rx_preamble(d, &f, ms) < 0) { 190 if (rx_preamble(d, cmd, &f, ms) < 0) {
170 fido_log_debug("%s: rx_preamble", __func__); 191 fido_log_debug("%s: rx_preamble", __func__);
171 return (-1); 192 return (-1);
172 } 193 }
173 194
174 fido_log_debug("%s: initiation frame at %p, len %zu", __func__, 195 payload_len = (f.body.init.bcnth << 8) | f.body.init.bcntl;
175 (void *)&f, sizeof(f)); 196 fido_log_debug("%s: payload_len=%zu", __func__, (size_t)payload_len);
176 fido_log_xxd(&f, sizeof(f));
177 197
178#ifdef FIDO_FUZZ 198 if (count < (size_t)payload_len) {
179 f.cid = d->cid; 199 fido_log_debug("%s: count < payload_len", __func__);
180 f.body.init.cmd = cmd;
181#endif
182
183 if (f.cid != d->cid || f.body.init.cmd != cmd) {
184 fido_log_debug("%s: cid (0x%x, 0x%x), cmd (0x%02x, 0x%02x)",
185 __func__, f.cid, d->cid, f.body.init.cmd, cmd);
186 return (-1); 200 return (-1);
187 } 201 }
188 202
189 flen = (f.body.init.bcnth << 8) | f.body.init.bcntl; 203 if (payload_len < sizeof(f.body.init.data)) {
190 if (count < (size_t)flen) { 204 memcpy(buf, f.body.init.data, payload_len);
191 fido_log_debug("%s: count < flen (%zu, %zu)", __func__, count, 205 return (payload_len);
192 (size_t)flen);
193 return (-1);
194 }
195 if (flen < sizeof(f.body.init.data)) {
196 memcpy(buf, f.body.init.data, flen);
197 return (flen);
198 } 206 }
199 207
200 memcpy(buf, f.body.init.data, sizeof(f.body.init.data)); 208 memcpy(buf, f.body.init.data, sizeof(f.body.init.data));
201 r = sizeof(f.body.init.data); 209 r = sizeof(f.body.init.data);
202 seq = 0;
203 210
204 while ((size_t)r < flen) { 211 for (int seq = 0; (size_t)r < payload_len; seq++) {
205 if (rx_frame(d, &f, ms) < 0) { 212 if (rx_frame(d, &f, ms) < 0) {
206 fido_log_debug("%s: rx_frame", __func__); 213 fido_log_debug("%s: rx_frame", __func__);
207 return (-1); 214 return (-1);
208 } 215 }
209 216
210 fido_log_debug("%s: continuation frame at %p, len %zu", 217 fido_log_debug("%s: continuation frame at %p", __func__,
211 __func__, (void *)&f, sizeof(f)); 218 (void *)&f);
212 fido_log_xxd(&f, sizeof(f)); 219 fido_log_xxd(&f, sizeof(f));
213 220
214#ifdef FIDO_FUZZ 221#ifdef FIDO_FUZZ
@@ -216,38 +223,57 @@ fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms)
216 f.body.cont.seq = seq; 223 f.body.cont.seq = seq;
217#endif 224#endif
218 225
219 if (f.cid != d->cid || f.body.cont.seq != seq++) { 226 if (f.cid != d->cid || f.body.cont.seq != seq) {
220 fido_log_debug("%s: cid (0x%x, 0x%x), seq (%d, %d)", 227 fido_log_debug("%s: cid (0x%x, 0x%x), seq (%d, %d)",
221 __func__, f.cid, d->cid, f.body.cont.seq, seq); 228 __func__, f.cid, d->cid, f.body.cont.seq, seq);
222 return (-1); 229 return (-1);
223 } 230 }
224 231
225 uint8_t *p = (uint8_t *)buf + r; 232 if ((size_t)(payload_len - r) > sizeof(f.body.cont.data)) {
226 233 memcpy(buf + r, f.body.cont.data,
227 if ((size_t)(flen - r) > sizeof(f.body.cont.data)) { 234 sizeof(f.body.cont.data));
228 memcpy(p, f.body.cont.data, sizeof(f.body.cont.data));
229 r += sizeof(f.body.cont.data); 235 r += sizeof(f.body.cont.data);
230 } else { 236 } else {
231 memcpy(p, f.body.cont.data, flen - r); 237 memcpy(buf + r, f.body.cont.data, payload_len - r);
232 r += (flen - r); /* break */ 238 r += (payload_len - r); /* break */
233 } 239 }
234 } 240 }
235 241
236 fido_log_debug("%s: payload at %p, len %zu", __func__, buf, (size_t)r);
237 fido_log_xxd(buf, r);
238
239 return (r); 242 return (r);
240} 243}
241 244
242int 245int
246fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms)
247{
248 int n;
249
250 fido_log_debug("%s: d=%p, cmd=0x%02x, buf=%p, count=%zu, ms=%d",
251 __func__, (void *)d, cmd, (const void *)buf, count, ms);
252
253 if (d->transport.rx != NULL)
254 return (d->transport.rx(d, cmd, buf, count, ms));
255
256 if (d->io_handle == NULL || d->io.read == NULL || count > UINT16_MAX) {
257 fido_log_debug("%s: invalid argument", __func__);
258 return (-1);
259 }
260
261 if ((n = rx(d, cmd, buf, count, ms)) >= 0) {
262 fido_log_debug("%s: buf=%p, len=%d", __func__, (void *)buf, n);
263 fido_log_xxd(buf, n);
264 }
265
266 return (n);
267}
268
269int
243fido_rx_cbor_status(fido_dev_t *d, int ms) 270fido_rx_cbor_status(fido_dev_t *d, int ms)
244{ 271{
245 const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; 272 unsigned char reply[FIDO_MAXMSG];
246 unsigned char reply[2048];
247 int reply_len; 273 int reply_len;
248 274
249 if ((reply_len = fido_rx(d, cmd, &reply, sizeof(reply), ms)) < 0 || 275 if ((reply_len = fido_rx(d, CTAP_CMD_CBOR, &reply, sizeof(reply),
250 (size_t)reply_len < 1) { 276 ms)) < 0 || (size_t)reply_len < 1) {
251 fido_log_debug("%s: fido_rx", __func__); 277 fido_log_debug("%s: fido_rx", __func__);
252 return (FIDO_ERR_RX); 278 return (FIDO_ERR_RX);
253 } 279 }