diff options
Diffstat (limited to 'src/dev.c')
-rw-r--r-- | src/dev.c | 207 |
1 files changed, 202 insertions, 5 deletions
@@ -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 | ||
112 | static void | ||
113 | set_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 | |||
122 | static void | ||
123 | fido_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 | |||
109 | static int | 149 | static int |
110 | fido_dev_open_tx(fido_dev_t *dev, const char *path) | 150 | fido_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); |
208 | fail: | ||
209 | dev->io.close(dev->io_handle); | ||
210 | dev->io_handle = NULL; | ||
211 | |||
212 | return (r); | ||
142 | } | 213 | } |
143 | 214 | ||
144 | static int | 215 | static 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) | |||
303 | int | 377 | int |
304 | fido_dev_cancel(fido_dev_t *dev) | 378 | fido_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 | ||
312 | int | 389 | int |
390 | fido_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; | ||
450 | fail: | ||
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 | |||
460 | int | ||
461 | fido_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 | |||
488 | int | ||
313 | fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) | 489 | fido_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 | ||
627 | bool | ||
628 | fido_dev_supports_pin(const fido_dev_t *dev) | ||
629 | { | ||
630 | return (dev->flags & (FIDO_DEV_PIN_SET|FIDO_DEV_PIN_UNSET)); | ||
631 | } | ||
632 | |||
633 | bool | ||
634 | fido_dev_has_pin(const fido_dev_t *dev) | ||
635 | { | ||
636 | return (dev->flags & FIDO_DEV_PIN_SET); | ||
637 | } | ||
638 | |||
639 | bool | ||
640 | fido_dev_supports_cred_prot(const fido_dev_t *dev) | ||
641 | { | ||
642 | return (dev->flags & FIDO_DEV_CRED_PROT); | ||
643 | } | ||
644 | |||
449 | void | 645 | void |
450 | fido_dev_force_u2f(fido_dev_t *dev) | 646 | fido_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 | ||
455 | void | 652 | void |