summaryrefslogtreecommitdiff
path: root/src/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dev.c')
-rw-r--r--src/dev.c207
1 files changed, 202 insertions, 5 deletions
diff --git a/src/dev.c b/src/dev.c
index 51b9935..3463ae4 100644
--- a/src/dev.c
+++ b/src/dev.c
@@ -10,6 +10,8 @@
10#include <sys/random.h> 10#include <sys/random.h>
11#endif 11#endif
12 12
13#include <openssl/sha.h>
14
13#include <fcntl.h> 15#include <fcntl.h>
14#include <stdint.h> 16#include <stdint.h>
15#include <stdlib.h> 17#include <stdlib.h>
@@ -106,10 +108,49 @@ find_manifest_func_node(dev_manifest_func_t f, dev_manifest_func_node_t **curr,
106 } 108 }
107} 109}
108 110
111#ifdef FIDO_FUZZ
112static void
113set_random_report_len(fido_dev_t *dev)
114{
115 dev->rx_len = CTAP_MIN_REPORT_LEN +
116 uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
117 dev->tx_len = CTAP_MIN_REPORT_LEN +
118 uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
119}
120#endif
121
122static void
123fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
124{
125 char * const *ptr;
126 const bool *val;
127 size_t len;
128
129 ptr = fido_cbor_info_extensions_ptr(info);
130 len = fido_cbor_info_extensions_len(info);
131
132 for (size_t i = 0; i < len; i++)
133 if (strcmp(ptr[i], "credProtect") == 0)
134 dev->flags |= FIDO_DEV_CRED_PROT;
135
136 ptr = fido_cbor_info_options_name_ptr(info);
137 val = fido_cbor_info_options_value_ptr(info);
138 len = fido_cbor_info_options_len(info);
139
140 for (size_t i = 0; i < len; i++)
141 if (strcmp(ptr[i], "clientPin") == 0) {
142 if (val[i] == true)
143 dev->flags |= FIDO_DEV_PIN_SET;
144 else
145 dev->flags |= FIDO_DEV_PIN_UNSET;
146 }
147}
148
109static int 149static int
110fido_dev_open_tx(fido_dev_t *dev, const char *path) 150fido_dev_open_tx(fido_dev_t *dev, const char *path)
111{ 151{
112 const uint8_t cmd = CTAP_CMD_INIT; 152 const uint8_t cmd = CTAP_CMD_INIT;
153 int r;
113 154
114 if (dev->io_handle != NULL) { 155 if (dev->io_handle != NULL) {
115 fido_log_debug("%s: handle=%p", __func__, dev->io_handle); 156 fido_log_debug("%s: handle=%p", __func__, dev->io_handle);
@@ -131,14 +172,44 @@ fido_dev_open_tx(fido_dev_t *dev, const char *path)
131 return (FIDO_ERR_INTERNAL); 172 return (FIDO_ERR_INTERNAL);
132 } 173 }
133 174
175 if (dev->io_own) {
176 dev->rx_len = CTAP_MAX_REPORT_LEN;
177 dev->tx_len = CTAP_MAX_REPORT_LEN;
178 } else {
179 dev->rx_len = fido_hid_report_in_len(dev->io_handle);
180 dev->tx_len = fido_hid_report_out_len(dev->io_handle);
181 }
182
183#ifdef FIDO_FUZZ
184 set_random_report_len(dev);
185#endif
186
187 if (dev->rx_len < CTAP_MIN_REPORT_LEN ||
188 dev->rx_len > CTAP_MAX_REPORT_LEN) {
189 fido_log_debug("%s: invalid rx_len %zu", __func__, dev->rx_len);
190 r = FIDO_ERR_RX;
191 goto fail;
192 }
193
194 if (dev->tx_len < CTAP_MIN_REPORT_LEN ||
195 dev->tx_len > CTAP_MAX_REPORT_LEN) {
196 fido_log_debug("%s: invalid tx_len %zu", __func__, dev->tx_len);
197 r = FIDO_ERR_TX;
198 goto fail;
199 }
200
134 if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) { 201 if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) {
135 fido_log_debug("%s: fido_tx", __func__); 202 fido_log_debug("%s: fido_tx", __func__);
136 dev->io.close(dev->io_handle); 203 r = FIDO_ERR_TX;
137 dev->io_handle = NULL; 204 goto fail;
138 return (FIDO_ERR_TX);
139 } 205 }
140 206
141 return (FIDO_OK); 207 return (FIDO_OK);
208fail:
209 dev->io.close(dev->io_handle);
210 dev->io_handle = NULL;
211
212 return (r);
142} 213}
143 214
144static int 215static int
@@ -166,6 +237,7 @@ fido_dev_open_rx(fido_dev_t *dev, int ms)
166 goto fail; 237 goto fail;
167 } 238 }
168 239
240 dev->flags = 0;
169 dev->cid = dev->attr.cid; 241 dev->cid = dev->attr.cid;
170 242
171 if (fido_dev_is_fido2(dev)) { 243 if (fido_dev_is_fido2(dev)) {
@@ -177,6 +249,8 @@ fido_dev_open_rx(fido_dev_t *dev, int ms)
177 if (fido_dev_get_cbor_info_wait(dev, info, ms) != FIDO_OK) { 249 if (fido_dev_get_cbor_info_wait(dev, info, ms) != FIDO_OK) {
178 fido_log_debug("%s: falling back to u2f", __func__); 250 fido_log_debug("%s: falling back to u2f", __func__);
179 fido_dev_force_u2f(dev); 251 fido_dev_force_u2f(dev);
252 } else {
253 fido_dev_set_flags(dev, info);
180 } 254 }
181 } 255 }
182 256
@@ -303,6 +377,9 @@ fido_dev_close(fido_dev_t *dev)
303int 377int
304fido_dev_cancel(fido_dev_t *dev) 378fido_dev_cancel(fido_dev_t *dev)
305{ 379{
380 if (fido_dev_is_fido2(dev) == false)
381 return (FIDO_ERR_INVALID_ARGUMENT);
382
306 if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0) 383 if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0)
307 return (FIDO_ERR_TX); 384 return (FIDO_ERR_TX);
308 385
@@ -310,6 +387,105 @@ fido_dev_cancel(fido_dev_t *dev)
310} 387}
311 388
312int 389int
390fido_dev_get_touch_begin(fido_dev_t *dev)
391{
392 fido_blob_t f;
393 cbor_item_t *argv[9];
394 const char *clientdata = FIDO_DUMMY_CLIENTDATA;
395 const uint8_t user_id = FIDO_DUMMY_USER_ID;
396 unsigned char cdh[SHA256_DIGEST_LENGTH];
397 fido_rp_t rp;
398 fido_user_t user;
399 int r = FIDO_ERR_INTERNAL;
400
401 memset(&f, 0, sizeof(f));
402 memset(argv, 0, sizeof(argv));
403 memset(cdh, 0, sizeof(cdh));
404 memset(&rp, 0, sizeof(rp));
405 memset(&user, 0, sizeof(user));
406
407 if (fido_dev_is_fido2(dev) == false)
408 return (u2f_get_touch_begin(dev));
409
410 if (SHA256((const void *)clientdata, strlen(clientdata), cdh) != cdh) {
411 fido_log_debug("%s: sha256", __func__);
412 return (FIDO_ERR_INTERNAL);
413 }
414
415 if ((rp.id = strdup(FIDO_DUMMY_RP_ID)) == NULL ||
416 (user.name = strdup(FIDO_DUMMY_USER_NAME)) == NULL) {
417 fido_log_debug("%s: strdup", __func__);
418 goto fail;
419 }
420
421 if (fido_blob_set(&user.id, &user_id, sizeof(user_id)) < 0) {
422 fido_log_debug("%s: fido_blob_set", __func__);
423 goto fail;
424 }
425
426 if ((argv[0] = cbor_build_bytestring(cdh, sizeof(cdh))) == NULL ||
427 (argv[1] = cbor_encode_rp_entity(&rp)) == NULL ||
428 (argv[2] = cbor_encode_user_entity(&user)) == NULL ||
429 (argv[3] = cbor_encode_pubkey_param(COSE_ES256)) == NULL) {
430 fido_log_debug("%s: cbor encode", __func__);
431 goto fail;
432 }
433
434 if (fido_dev_supports_pin(dev)) {
435 if ((argv[7] = cbor_new_definite_bytestring()) == NULL ||
436 (argv[8] = cbor_encode_pin_opt()) == NULL) {
437 fido_log_debug("%s: cbor encode", __func__);
438 goto fail;
439 }
440 }
441
442 if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, nitems(argv), &f) < 0 ||
443 fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
444 fido_log_debug("%s: fido_tx", __func__);
445 r = FIDO_ERR_TX;
446 goto fail;
447 }
448
449 r = FIDO_OK;
450fail:
451 cbor_vector_free(argv, nitems(argv));
452 free(f.ptr);
453 free(rp.id);
454 free(user.name);
455 free(user.id.ptr);
456
457 return (r);
458}
459
460int
461fido_dev_get_touch_status(fido_dev_t *dev, int *touched, int ms)
462{
463 int r;
464
465 *touched = 0;
466
467 if (fido_dev_is_fido2(dev) == false)
468 return (u2f_get_touch_status(dev, touched, ms));
469
470 switch ((r = fido_rx_cbor_status(dev, ms))) {
471 case FIDO_ERR_PIN_AUTH_INVALID:
472 case FIDO_ERR_PIN_INVALID:
473 case FIDO_ERR_PIN_NOT_SET:
474 case FIDO_ERR_SUCCESS:
475 *touched = 1;
476 break;
477 case FIDO_ERR_RX:
478 /* ignore */
479 break;
480 default:
481 fido_log_debug("%s: fido_rx_cbor_status", __func__);
482 return (r);
483 }
484
485 return (FIDO_OK);
486}
487
488int
313fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) 489fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
314{ 490{
315 if (dev->io_handle != NULL) { 491 if (dev->io_handle != NULL) {
@@ -324,6 +500,7 @@ fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
324 } 500 }
325 501
326 dev->io = *io; 502 dev->io = *io;
503 dev->io_own = true;
327 504
328 return (FIDO_OK); 505 return (FIDO_OK);
329} 506}
@@ -337,6 +514,7 @@ fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t)
337 } 514 }
338 515
339 dev->transport = *t; 516 dev->transport = *t;
517 dev->io_own = true;
340 518
341 return (FIDO_OK); 519 return (FIDO_OK);
342} 520}
@@ -446,10 +624,29 @@ fido_dev_is_fido2(const fido_dev_t *dev)
446 return (dev->attr.flags & FIDO_CAP_CBOR); 624 return (dev->attr.flags & FIDO_CAP_CBOR);
447} 625}
448 626
627bool
628fido_dev_supports_pin(const fido_dev_t *dev)
629{
630 return (dev->flags & (FIDO_DEV_PIN_SET|FIDO_DEV_PIN_UNSET));
631}
632
633bool
634fido_dev_has_pin(const fido_dev_t *dev)
635{
636 return (dev->flags & FIDO_DEV_PIN_SET);
637}
638
639bool
640fido_dev_supports_cred_prot(const fido_dev_t *dev)
641{
642 return (dev->flags & FIDO_DEV_CRED_PROT);
643}
644
449void 645void
450fido_dev_force_u2f(fido_dev_t *dev) 646fido_dev_force_u2f(fido_dev_t *dev)
451{ 647{
452 dev->attr.flags &= ~FIDO_CAP_CBOR; 648 dev->attr.flags &= (uint8_t)~FIDO_CAP_CBOR;
649 dev->flags = 0;
453} 650}
454 651
455void 652void