diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 12 | ||||
-rw-r--r-- | src/assert.c | 31 | ||||
-rw-r--r-- | src/authkey.c | 10 | ||||
-rw-r--r-- | src/bio.c | 32 | ||||
-rw-r--r-- | src/blob.h | 11 | ||||
-rw-r--r-- | src/cbor.c | 108 | ||||
-rw-r--r-- | src/cred.c | 122 | ||||
-rw-r--r-- | src/credman.c | 34 | ||||
-rw-r--r-- | src/dev.c | 223 | ||||
-rw-r--r-- | src/eddsa.c | 8 | ||||
-rw-r--r-- | src/err.c | 24 | ||||
-rw-r--r-- | src/es256.c | 54 | ||||
-rw-r--r-- | src/export.gnu | 5 | ||||
-rw-r--r-- | src/export.llvm | 5 | ||||
-rw-r--r-- | src/export.msvc | 5 | ||||
-rw-r--r-- | src/extern.h | 32 | ||||
-rw-r--r-- | src/fido.h | 53 | ||||
-rw-r--r-- | src/fido/bio.h | 16 | ||||
-rw-r--r-- | src/fido/credman.h | 16 | ||||
-rw-r--r-- | src/fido/eddsa.h | 14 | ||||
-rw-r--r-- | src/fido/err.h | 8 | ||||
-rw-r--r-- | src/fido/es256.h | 14 | ||||
-rw-r--r-- | src/fido/param.h | 11 | ||||
-rw-r--r-- | src/fido/rs256.h | 14 | ||||
-rw-r--r-- | src/fido/types.h (renamed from src/types.h) | 96 | ||||
-rw-r--r-- | src/hid_hidapi.c | 138 | ||||
-rw-r--r-- | src/hid_linux.c | 14 | ||||
-rw-r--r-- | src/hid_openbsd.c | 8 | ||||
-rw-r--r-- | src/hid_osx.c | 17 | ||||
-rw-r--r-- | src/hid_win.c | 8 | ||||
-rw-r--r-- | src/info.c | 21 | ||||
-rw-r--r-- | src/io.c | 202 | ||||
-rw-r--r-- | src/iso7816.h | 11 | ||||
-rw-r--r-- | src/log.c | 73 | ||||
-rw-r--r-- | src/pin.c | 126 | ||||
-rw-r--r-- | src/reset.c | 5 | ||||
-rw-r--r-- | src/u2f.c | 69 |
37 files changed, 1222 insertions, 428 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 926e7f2..3cf62e8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt | |||
@@ -31,11 +31,14 @@ list(APPEND FIDO_SOURCES | |||
31 | ) | 31 | ) |
32 | 32 | ||
33 | if(FUZZ) | 33 | if(FUZZ) |
34 | list(APPEND FIDO_SOURCES ../fuzz/prng.c) | ||
34 | list(APPEND FIDO_SOURCES ../fuzz/uniform_random.c) | 35 | list(APPEND FIDO_SOURCES ../fuzz/uniform_random.c) |
35 | list(APPEND FIDO_SOURCES ../fuzz/wrap.c) | 36 | list(APPEND FIDO_SOURCES ../fuzz/wrap.c) |
36 | endif() | 37 | endif() |
37 | 38 | ||
38 | if(WIN32) | 39 | if(USE_HIDAPI) |
40 | list(APPEND COMPAT_SOURCES hid_hidapi.c) | ||
41 | elseif(WIN32) | ||
39 | list(APPEND COMPAT_SOURCES hid_win.c) | 42 | list(APPEND COMPAT_SOURCES hid_win.c) |
40 | elseif(APPLE) | 43 | elseif(APPLE) |
41 | list(APPEND COMPAT_SOURCES hid_osx.c) | 44 | list(APPEND COMPAT_SOURCES hid_osx.c) |
@@ -43,6 +46,8 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") | |||
43 | list(APPEND COMPAT_SOURCES hid_linux.c) | 46 | list(APPEND COMPAT_SOURCES hid_linux.c) |
44 | elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") | 47 | elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") |
45 | list(APPEND COMPAT_SOURCES hid_openbsd.c) | 48 | list(APPEND COMPAT_SOURCES hid_openbsd.c) |
49 | else() | ||
50 | message(FATAL_ERROR "please define a hid backend for your platform") | ||
46 | endif() | 51 | endif() |
47 | 52 | ||
48 | list(APPEND COMPAT_SOURCES | 53 | list(APPEND COMPAT_SOURCES |
@@ -50,13 +55,14 @@ list(APPEND COMPAT_SOURCES | |||
50 | ../openbsd-compat/explicit_bzero.c | 55 | ../openbsd-compat/explicit_bzero.c |
51 | ../openbsd-compat/explicit_bzero_win32.c | 56 | ../openbsd-compat/explicit_bzero_win32.c |
52 | ../openbsd-compat/recallocarray.c | 57 | ../openbsd-compat/recallocarray.c |
58 | ../openbsd-compat/strlcat.c | ||
53 | ../openbsd-compat/timingsafe_bcmp.c | 59 | ../openbsd-compat/timingsafe_bcmp.c |
54 | ) | 60 | ) |
55 | 61 | ||
56 | # static library | 62 | # static library |
57 | add_library(fido2 STATIC ${FIDO_SOURCES} ${COMPAT_SOURCES}) | 63 | add_library(fido2 STATIC ${FIDO_SOURCES} ${COMPAT_SOURCES}) |
58 | target_link_libraries(fido2 ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES} | 64 | target_link_libraries(fido2 ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES} |
59 | ${UDEV_LIBRARIES} ${BASE_LIBRARIES}) | 65 | ${UDEV_LIBRARIES} ${BASE_LIBRARIES} ${HIDAPI_LIBRARIES}) |
60 | if(WIN32) | 66 | if(WIN32) |
61 | if (MINGW) | 67 | if (MINGW) |
62 | target_link_libraries(fido2 wsock32 ws2_32 bcrypt setupapi hid) | 68 | target_link_libraries(fido2 wsock32 ws2_32 bcrypt setupapi hid) |
@@ -74,7 +80,7 @@ install(TARGETS fido2 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} | |||
74 | # dynamic library | 80 | # dynamic library |
75 | add_library(fido2_shared SHARED ${FIDO_SOURCES} ${COMPAT_SOURCES}) | 81 | add_library(fido2_shared SHARED ${FIDO_SOURCES} ${COMPAT_SOURCES}) |
76 | target_link_libraries(fido2_shared ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES} | 82 | target_link_libraries(fido2_shared ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES} |
77 | ${UDEV_LIBRARIES} ${BASE_LIBRARIES}) | 83 | ${UDEV_LIBRARIES} ${BASE_LIBRARIES} ${HIDAPI_LIBRARIES}) |
78 | if(WIN32) | 84 | if(WIN32) |
79 | if (MINGW) | 85 | if (MINGW) |
80 | target_link_libraries(fido2_shared wsock32 ws2_32 bcrypt | 86 | target_link_libraries(fido2_shared wsock32 ws2_32 bcrypt |
diff --git a/src/assert.c b/src/assert.c index a21b308..b71d00e 100644 --- a/src/assert.c +++ b/src/assert.c | |||
@@ -152,8 +152,8 @@ fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert, | |||
152 | } | 152 | } |
153 | 153 | ||
154 | /* frame and transmit */ | 154 | /* frame and transmit */ |
155 | if (cbor_build_frame(CTAP_CBOR_ASSERT, argv, 7, &f) < 0 || | 155 | if (cbor_build_frame(CTAP_CBOR_ASSERT, argv, nitems(argv), &f) < 0 || |
156 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | 156 | fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { |
157 | fido_log_debug("%s: fido_tx", __func__); | 157 | fido_log_debug("%s: fido_tx", __func__); |
158 | r = FIDO_ERR_TX; | 158 | r = FIDO_ERR_TX; |
159 | goto fail; | 159 | goto fail; |
@@ -170,14 +170,14 @@ fail: | |||
170 | static int | 170 | static int |
171 | fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) | 171 | fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) |
172 | { | 172 | { |
173 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 173 | unsigned char reply[FIDO_MAXMSG]; |
174 | unsigned char reply[2048]; | ||
175 | int reply_len; | 174 | int reply_len; |
176 | int r; | 175 | int r; |
177 | 176 | ||
178 | fido_assert_reset_rx(assert); | 177 | fido_assert_reset_rx(assert); |
179 | 178 | ||
180 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 179 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
180 | ms)) < 0) { | ||
181 | fido_log_debug("%s: fido_rx", __func__); | 181 | fido_log_debug("%s: fido_rx", __func__); |
182 | return (FIDO_ERR_RX); | 182 | return (FIDO_ERR_RX); |
183 | } | 183 | } |
@@ -211,10 +211,9 @@ fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) | |||
211 | static int | 211 | static int |
212 | fido_get_next_assert_tx(fido_dev_t *dev) | 212 | fido_get_next_assert_tx(fido_dev_t *dev) |
213 | { | 213 | { |
214 | const unsigned char cbor[] = { CTAP_CBOR_NEXT_ASSERT }; | 214 | const unsigned char cbor[] = { CTAP_CBOR_NEXT_ASSERT }; |
215 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
216 | 215 | ||
217 | if (fido_tx(dev, cmd, cbor, sizeof(cbor)) < 0) { | 216 | if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) { |
218 | fido_log_debug("%s: fido_tx", __func__); | 217 | fido_log_debug("%s: fido_tx", __func__); |
219 | return (FIDO_ERR_TX); | 218 | return (FIDO_ERR_TX); |
220 | } | 219 | } |
@@ -225,12 +224,12 @@ fido_get_next_assert_tx(fido_dev_t *dev) | |||
225 | static int | 224 | static int |
226 | fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) | 225 | fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) |
227 | { | 226 | { |
228 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 227 | unsigned char reply[FIDO_MAXMSG]; |
229 | unsigned char reply[2048]; | ||
230 | int reply_len; | 228 | int reply_len; |
231 | int r; | 229 | int r; |
232 | 230 | ||
233 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 231 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
232 | ms)) < 0) { | ||
234 | fido_log_debug("%s: fido_rx", __func__); | 233 | fido_log_debug("%s: fido_rx", __func__); |
235 | return (FIDO_ERR_RX); | 234 | return (FIDO_ERR_RX); |
236 | } | 235 | } |
@@ -363,8 +362,8 @@ check_extensions(int authdata_ext, int ext) | |||
363 | return (0); | 362 | return (0); |
364 | } | 363 | } |
365 | 364 | ||
366 | static int | 365 | int |
367 | get_signed_hash(int cose_alg, fido_blob_t *dgst, const fido_blob_t *clientdata, | 366 | fido_get_signed_hash(int cose_alg, fido_blob_t *dgst, const fido_blob_t *clientdata, |
368 | const fido_blob_t *authdata_cbor) | 367 | const fido_blob_t *authdata_cbor) |
369 | { | 368 | { |
370 | cbor_item_t *item = NULL; | 369 | cbor_item_t *item = NULL; |
@@ -534,7 +533,7 @@ int | |||
534 | fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg, | 533 | fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg, |
535 | const void *pk) | 534 | const void *pk) |
536 | { | 535 | { |
537 | unsigned char buf[1024]; | 536 | unsigned char buf[1024]; /* XXX */ |
538 | fido_blob_t dgst; | 537 | fido_blob_t dgst; |
539 | const fido_assert_stmt *stmt = NULL; | 538 | const fido_assert_stmt *stmt = NULL; |
540 | int ok = -1; | 539 | int ok = -1; |
@@ -579,9 +578,9 @@ fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg, | |||
579 | goto out; | 578 | goto out; |
580 | } | 579 | } |
581 | 580 | ||
582 | if (get_signed_hash(cose_alg, &dgst, &assert->cdh, | 581 | if (fido_get_signed_hash(cose_alg, &dgst, &assert->cdh, |
583 | &stmt->authdata_cbor) < 0) { | 582 | &stmt->authdata_cbor) < 0) { |
584 | fido_log_debug("%s: get_signed_hash", __func__); | 583 | fido_log_debug("%s: fido_get_signed_hash", __func__); |
585 | r = FIDO_ERR_INTERNAL; | 584 | r = FIDO_ERR_INTERNAL; |
586 | goto out; | 585 | goto out; |
587 | } | 586 | } |
diff --git a/src/authkey.c b/src/authkey.c index 9de37f1..83c2564 100644 --- a/src/authkey.c +++ b/src/authkey.c | |||
@@ -43,8 +43,8 @@ fido_dev_authkey_tx(fido_dev_t *dev) | |||
43 | } | 43 | } |
44 | 44 | ||
45 | /* frame and transmit */ | 45 | /* frame and transmit */ |
46 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 2, &f) < 0 || | 46 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), |
47 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | 47 | &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { |
48 | fido_log_debug("%s: fido_tx", __func__); | 48 | fido_log_debug("%s: fido_tx", __func__); |
49 | r = FIDO_ERR_TX; | 49 | r = FIDO_ERR_TX; |
50 | goto fail; | 50 | goto fail; |
@@ -61,8 +61,7 @@ fail: | |||
61 | static int | 61 | static int |
62 | fido_dev_authkey_rx(fido_dev_t *dev, es256_pk_t *authkey, int ms) | 62 | fido_dev_authkey_rx(fido_dev_t *dev, es256_pk_t *authkey, int ms) |
63 | { | 63 | { |
64 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 64 | unsigned char reply[FIDO_MAXMSG]; |
65 | unsigned char reply[2048]; | ||
66 | int reply_len; | 65 | int reply_len; |
67 | 66 | ||
68 | fido_log_debug("%s: dev=%p, authkey=%p, ms=%d", __func__, (void *)dev, | 67 | fido_log_debug("%s: dev=%p, authkey=%p, ms=%d", __func__, (void *)dev, |
@@ -70,7 +69,8 @@ fido_dev_authkey_rx(fido_dev_t *dev, es256_pk_t *authkey, int ms) | |||
70 | 69 | ||
71 | memset(authkey, 0, sizeof(*authkey)); | 70 | memset(authkey, 0, sizeof(*authkey)); |
72 | 71 | ||
73 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 72 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
73 | ms)) < 0) { | ||
74 | fido_log_debug("%s: fido_rx", __func__); | 74 | fido_log_debug("%s: fido_rx", __func__); |
75 | return (FIDO_ERR_RX); | 75 | return (FIDO_ERR_RX); |
76 | } | 76 | } |
@@ -109,8 +109,8 @@ bio_tx(fido_dev_t *dev, uint8_t cmd, cbor_item_t **sub_argv, size_t sub_argc, | |||
109 | } | 109 | } |
110 | 110 | ||
111 | /* framing and transmission */ | 111 | /* framing and transmission */ |
112 | if (cbor_build_frame(CTAP_CBOR_BIO_ENROLL_PRE, argv, 5, &f) < 0 || | 112 | if (cbor_build_frame(CTAP_CBOR_BIO_ENROLL_PRE, argv, nitems(argv), |
113 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | 113 | &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { |
114 | fido_log_debug("%s: fido_tx", __func__); | 114 | fido_log_debug("%s: fido_tx", __func__); |
115 | r = FIDO_ERR_TX; | 115 | r = FIDO_ERR_TX; |
116 | goto fail; | 116 | goto fail; |
@@ -235,14 +235,14 @@ bio_parse_template_array(const cbor_item_t *key, const cbor_item_t *val, | |||
235 | static int | 235 | static int |
236 | bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int ms) | 236 | bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int ms) |
237 | { | 237 | { |
238 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 238 | unsigned char reply[FIDO_MAXMSG]; |
239 | unsigned char reply[2048]; | ||
240 | int reply_len; | 239 | int reply_len; |
241 | int r; | 240 | int r; |
242 | 241 | ||
243 | bio_reset_template_array(ta); | 242 | bio_reset_template_array(ta); |
244 | 243 | ||
245 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 244 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
245 | ms)) < 0) { | ||
246 | fido_log_debug("%s: fido_rx", __func__); | 246 | fido_log_debug("%s: fido_rx", __func__); |
247 | return (FIDO_ERR_RX); | 247 | return (FIDO_ERR_RX); |
248 | } | 248 | } |
@@ -382,8 +382,7 @@ static int | |||
382 | bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t, | 382 | bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t, |
383 | fido_bio_enroll_t *e, int ms) | 383 | fido_bio_enroll_t *e, int ms) |
384 | { | 384 | { |
385 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 385 | unsigned char reply[FIDO_MAXMSG]; |
386 | unsigned char reply[2048]; | ||
387 | int reply_len; | 386 | int reply_len; |
388 | int r; | 387 | int r; |
389 | 388 | ||
@@ -392,7 +391,8 @@ bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t, | |||
392 | e->remaining_samples = 0; | 391 | e->remaining_samples = 0; |
393 | e->last_status = 0; | 392 | e->last_status = 0; |
394 | 393 | ||
395 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 394 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
395 | ms)) < 0) { | ||
396 | fido_log_debug("%s: fido_rx", __func__); | 396 | fido_log_debug("%s: fido_rx", __func__); |
397 | return (FIDO_ERR_RX); | 397 | return (FIDO_ERR_RX); |
398 | } | 398 | } |
@@ -407,7 +407,7 @@ bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t, | |||
407 | fido_log_debug("%s: bio_parse_template_id", __func__); | 407 | fido_log_debug("%s: bio_parse_template_id", __func__); |
408 | return (r); | 408 | return (r); |
409 | } | 409 | } |
410 | 410 | ||
411 | return (FIDO_OK); | 411 | return (FIDO_OK); |
412 | } | 412 | } |
413 | 413 | ||
@@ -482,15 +482,15 @@ fail: | |||
482 | static int | 482 | static int |
483 | bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int ms) | 483 | bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int ms) |
484 | { | 484 | { |
485 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 485 | unsigned char reply[FIDO_MAXMSG]; |
486 | unsigned char reply[2048]; | ||
487 | int reply_len; | 486 | int reply_len; |
488 | int r; | 487 | int r; |
489 | 488 | ||
490 | e->remaining_samples = 0; | 489 | e->remaining_samples = 0; |
491 | e->last_status = 0; | 490 | e->last_status = 0; |
492 | 491 | ||
493 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 492 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
493 | ms)) < 0) { | ||
494 | fido_log_debug("%s: fido_rx", __func__); | 494 | fido_log_debug("%s: fido_rx", __func__); |
495 | return (FIDO_ERR_RX); | 495 | return (FIDO_ERR_RX); |
496 | } | 496 | } |
@@ -500,7 +500,7 @@ bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int ms) | |||
500 | fido_log_debug("%s: bio_parse_enroll_status", __func__); | 500 | fido_log_debug("%s: bio_parse_enroll_status", __func__); |
501 | return (r); | 501 | return (r); |
502 | } | 502 | } |
503 | 503 | ||
504 | return (FIDO_OK); | 504 | return (FIDO_OK); |
505 | } | 505 | } |
506 | 506 | ||
@@ -643,14 +643,14 @@ bio_parse_info(const cbor_item_t *key, const cbor_item_t *val, void *arg) | |||
643 | static int | 643 | static int |
644 | bio_rx_info(fido_dev_t *dev, fido_bio_info_t *i, int ms) | 644 | bio_rx_info(fido_dev_t *dev, fido_bio_info_t *i, int ms) |
645 | { | 645 | { |
646 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 646 | unsigned char reply[FIDO_MAXMSG]; |
647 | unsigned char reply[2048]; | ||
648 | int reply_len; | 647 | int reply_len; |
649 | int r; | 648 | int r; |
650 | 649 | ||
651 | bio_reset_info(i); | 650 | bio_reset_info(i); |
652 | 651 | ||
653 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 652 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
653 | ms)) < 0) { | ||
654 | fido_log_debug("%s: fido_rx", __func__); | 654 | fido_log_debug("%s: fido_rx", __func__); |
655 | return (FIDO_ERR_RX); | 655 | return (FIDO_ERR_RX); |
656 | } | 656 | } |
@@ -7,6 +7,13 @@ | |||
7 | #ifndef _BLOB_H | 7 | #ifndef _BLOB_H |
8 | #define _BLOB_H | 8 | #define _BLOB_H |
9 | 9 | ||
10 | #include <cbor.h> | ||
11 | #include <stdlib.h> | ||
12 | |||
13 | #ifdef __cplusplus | ||
14 | extern "C" { | ||
15 | #endif /* __cplusplus */ | ||
16 | |||
10 | typedef struct fido_blob { | 17 | typedef struct fido_blob { |
11 | unsigned char *ptr; | 18 | unsigned char *ptr; |
12 | size_t len; | 19 | size_t len; |
@@ -25,4 +32,8 @@ int fido_blob_set(fido_blob_t *, const unsigned char *, size_t); | |||
25 | void fido_blob_free(fido_blob_t **); | 32 | void fido_blob_free(fido_blob_t **); |
26 | void fido_free_blob_array(fido_blob_array_t *); | 33 | void fido_free_blob_array(fido_blob_array_t *); |
27 | 34 | ||
35 | #ifdef __cplusplus | ||
36 | } /* extern "C" */ | ||
37 | #endif /* __cplusplus */ | ||
38 | |||
28 | #endif /* !_BLOB_H */ | 39 | #endif /* !_BLOB_H */ |
@@ -314,6 +314,35 @@ fail: | |||
314 | } | 314 | } |
315 | 315 | ||
316 | static int | 316 | static int |
317 | cbor_add_uint8(cbor_item_t *item, const char *key, uint8_t value) | ||
318 | { | ||
319 | struct cbor_pair pair; | ||
320 | int ok = -1; | ||
321 | |||
322 | memset(&pair, 0, sizeof(pair)); | ||
323 | |||
324 | if ((pair.key = cbor_build_string(key)) == NULL || | ||
325 | (pair.value = cbor_build_uint8(value)) == NULL) { | ||
326 | fido_log_debug("%s: cbor_build", __func__); | ||
327 | goto fail; | ||
328 | } | ||
329 | |||
330 | if (!cbor_map_add(item, pair)) { | ||
331 | fido_log_debug("%s: cbor_map_add", __func__); | ||
332 | goto fail; | ||
333 | } | ||
334 | |||
335 | ok = 0; | ||
336 | fail: | ||
337 | if (pair.key) | ||
338 | cbor_decref(&pair.key); | ||
339 | if (pair.value) | ||
340 | cbor_decref(&pair.value); | ||
341 | |||
342 | return (ok); | ||
343 | } | ||
344 | |||
345 | static int | ||
317 | cbor_add_arg(cbor_item_t *item, uint8_t n, cbor_item_t *arg) | 346 | cbor_add_arg(cbor_item_t *item, uint8_t n, cbor_item_t *arg) |
318 | { | 347 | { |
319 | struct cbor_pair pair; | 348 | struct cbor_pair pair; |
@@ -535,19 +564,29 @@ fail: | |||
535 | } | 564 | } |
536 | 565 | ||
537 | cbor_item_t * | 566 | cbor_item_t * |
538 | cbor_encode_extensions(int ext) | 567 | cbor_encode_extensions(const fido_cred_ext_t *ext) |
539 | { | 568 | { |
540 | cbor_item_t *item = NULL; | 569 | cbor_item_t *item = NULL; |
570 | size_t size = 0; | ||
541 | 571 | ||
542 | if (ext == 0 || ext != FIDO_EXT_HMAC_SECRET) | 572 | if (ext->mask & FIDO_EXT_HMAC_SECRET) |
543 | return (NULL); | 573 | size++; |
544 | 574 | if (ext->mask & FIDO_EXT_CRED_PROTECT) | |
545 | if ((item = cbor_new_definite_map(1)) == NULL) | 575 | size++; |
576 | if (size == 0 || (item = cbor_new_definite_map(size)) == NULL) | ||
546 | return (NULL); | 577 | return (NULL); |
547 | 578 | ||
548 | if (cbor_add_bool(item, "hmac-secret", FIDO_OPT_TRUE) < 0) { | 579 | if (ext->mask & FIDO_EXT_HMAC_SECRET) { |
549 | cbor_decref(&item); | 580 | if (cbor_add_bool(item, "hmac-secret", FIDO_OPT_TRUE) < 0) { |
550 | return (NULL); | 581 | cbor_decref(&item); |
582 | return (NULL); | ||
583 | } | ||
584 | } | ||
585 | if (ext->mask & FIDO_EXT_CRED_PROTECT) { | ||
586 | if (cbor_add_uint8(item, "credProtect", ext->prot) < 0) { | ||
587 | cbor_decref(&item); | ||
588 | return (NULL); | ||
589 | } | ||
551 | } | 590 | } |
552 | 591 | ||
553 | return (item); | 592 | return (item); |
@@ -1082,26 +1121,35 @@ fail: | |||
1082 | static int | 1121 | static int |
1083 | decode_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg) | 1122 | decode_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg) |
1084 | { | 1123 | { |
1085 | int *authdata_ext = arg; | 1124 | fido_cred_ext_t *authdata_ext = arg; |
1086 | char *type = NULL; | 1125 | char *type = NULL; |
1087 | int ok = -1; | 1126 | int ok = -1; |
1088 | 1127 | ||
1089 | if (cbor_string_copy(key, &type) < 0 || strcmp(type, "hmac-secret")) { | 1128 | if (cbor_string_copy(key, &type) < 0) { |
1090 | fido_log_debug("%s: cbor type", __func__); | 1129 | fido_log_debug("%s: cbor type", __func__); |
1091 | ok = 0; /* ignore */ | 1130 | ok = 0; /* ignore */ |
1092 | goto out; | 1131 | goto out; |
1093 | } | 1132 | } |
1094 | 1133 | ||
1095 | if (cbor_isa_float_ctrl(val) == false || | 1134 | if (strcmp(type, "hmac-secret") == 0) { |
1096 | cbor_float_get_width(val) != CBOR_FLOAT_0 || | 1135 | if (cbor_isa_float_ctrl(val) == false || |
1097 | cbor_is_bool(val) == false || *authdata_ext != 0) { | 1136 | cbor_float_get_width(val) != CBOR_FLOAT_0 || |
1098 | fido_log_debug("%s: cbor type", __func__); | 1137 | cbor_is_bool(val) == false) { |
1099 | goto out; | 1138 | fido_log_debug("%s: cbor type", __func__); |
1139 | goto out; | ||
1140 | } | ||
1141 | if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE) | ||
1142 | authdata_ext->mask |= FIDO_EXT_HMAC_SECRET; | ||
1143 | } else if (strcmp(type, "credProtect") == 0) { | ||
1144 | if (cbor_isa_uint(val) == false || | ||
1145 | cbor_int_get_width(val) != CBOR_INT_8) { | ||
1146 | fido_log_debug("%s: cbor type", __func__); | ||
1147 | goto out; | ||
1148 | } | ||
1149 | authdata_ext->mask |= FIDO_EXT_CRED_PROTECT; | ||
1150 | authdata_ext->prot = cbor_get_uint8(val); | ||
1100 | } | 1151 | } |
1101 | 1152 | ||
1102 | if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE) | ||
1103 | *authdata_ext |= FIDO_EXT_HMAC_SECRET; | ||
1104 | |||
1105 | ok = 0; | 1153 | ok = 0; |
1106 | out: | 1154 | out: |
1107 | free(type); | 1155 | free(type); |
@@ -1110,7 +1158,8 @@ out: | |||
1110 | } | 1158 | } |
1111 | 1159 | ||
1112 | static int | 1160 | static int |
1113 | decode_extensions(const unsigned char **buf, size_t *len, int *authdata_ext) | 1161 | decode_extensions(const unsigned char **buf, size_t *len, |
1162 | fido_cred_ext_t *authdata_ext) | ||
1114 | { | 1163 | { |
1115 | cbor_item_t *item = NULL; | 1164 | cbor_item_t *item = NULL; |
1116 | struct cbor_load_result cbor; | 1165 | struct cbor_load_result cbor; |
@@ -1118,8 +1167,9 @@ decode_extensions(const unsigned char **buf, size_t *len, int *authdata_ext) | |||
1118 | 1167 | ||
1119 | fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf, | 1168 | fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf, |
1120 | *len); | 1169 | *len); |
1170 | fido_log_xxd(*buf, *len); | ||
1121 | 1171 | ||
1122 | *authdata_ext = 0; | 1172 | memset(authdata_ext, 0, sizeof(*authdata_ext)); |
1123 | 1173 | ||
1124 | if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { | 1174 | if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { |
1125 | fido_log_debug("%s: cbor_load", __func__); | 1175 | fido_log_debug("%s: cbor_load", __func__); |
@@ -1129,7 +1179,6 @@ decode_extensions(const unsigned char **buf, size_t *len, int *authdata_ext) | |||
1129 | 1179 | ||
1130 | if (cbor_isa_map(item) == false || | 1180 | if (cbor_isa_map(item) == false || |
1131 | cbor_map_is_definite(item) == false || | 1181 | cbor_map_is_definite(item) == false || |
1132 | cbor_map_size(item) != 1 || | ||
1133 | cbor_map_iter(item, authdata_ext, decode_extension) < 0) { | 1182 | cbor_map_iter(item, authdata_ext, decode_extension) < 0) { |
1134 | fido_log_debug("%s: cbor type", __func__); | 1183 | fido_log_debug("%s: cbor type", __func__); |
1135 | goto fail; | 1184 | goto fail; |
@@ -1204,7 +1253,7 @@ fail: | |||
1204 | int | 1253 | int |
1205 | cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg, | 1254 | cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg, |
1206 | fido_blob_t *authdata_cbor, fido_authdata_t *authdata, | 1255 | fido_blob_t *authdata_cbor, fido_authdata_t *authdata, |
1207 | fido_attcred_t *attcred, int *authdata_ext) | 1256 | fido_attcred_t *attcred, fido_cred_ext_t *authdata_ext) |
1208 | { | 1257 | { |
1209 | const unsigned char *buf = NULL; | 1258 | const unsigned char *buf = NULL; |
1210 | size_t len; | 1259 | size_t len; |
@@ -1227,6 +1276,7 @@ cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg, | |||
1227 | len = cbor_bytestring_length(item); | 1276 | len = cbor_bytestring_length(item); |
1228 | 1277 | ||
1229 | fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len); | 1278 | fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len); |
1279 | fido_log_xxd(buf, len); | ||
1230 | 1280 | ||
1231 | if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) { | 1281 | if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) { |
1232 | fido_log_debug("%s: fido_buf_read", __func__); | 1282 | fido_log_debug("%s: fido_buf_read", __func__); |
@@ -1316,6 +1366,7 @@ decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) | |||
1316 | { | 1366 | { |
1317 | fido_attstmt_t *attstmt = arg; | 1367 | fido_attstmt_t *attstmt = arg; |
1318 | char *name = NULL; | 1368 | char *name = NULL; |
1369 | int cose_alg = 0; | ||
1319 | int ok = -1; | 1370 | int ok = -1; |
1320 | 1371 | ||
1321 | if (cbor_string_copy(key, &name) < 0) { | 1372 | if (cbor_string_copy(key, &name) < 0) { |
@@ -1326,11 +1377,16 @@ decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) | |||
1326 | 1377 | ||
1327 | if (!strcmp(name, "alg")) { | 1378 | if (!strcmp(name, "alg")) { |
1328 | if (cbor_isa_negint(val) == false || | 1379 | if (cbor_isa_negint(val) == false || |
1329 | cbor_int_get_width(val) != CBOR_INT_8 || | 1380 | cbor_get_int(val) > UINT16_MAX) { |
1330 | cbor_get_uint8(val) != -COSE_ES256 - 1) { | ||
1331 | fido_log_debug("%s: alg", __func__); | 1381 | fido_log_debug("%s: alg", __func__); |
1332 | goto out; | 1382 | goto out; |
1333 | } | 1383 | } |
1384 | if ((cose_alg = -(int)cbor_get_int(val) - 1) != COSE_ES256 && | ||
1385 | cose_alg != COSE_RS256 && cose_alg != COSE_EDDSA) { | ||
1386 | fido_log_debug("%s: unsupported cose_alg=%d", __func__, | ||
1387 | cose_alg); | ||
1388 | goto out; | ||
1389 | } | ||
1334 | } else if (!strcmp(name, "sig")) { | 1390 | } else if (!strcmp(name, "sig")) { |
1335 | if (cbor_bytestring_copy(val, &attstmt->sig.ptr, | 1391 | if (cbor_bytestring_copy(val, &attstmt->sig.ptr, |
1336 | &attstmt->sig.len) < 0) { | 1392 | &attstmt->sig.len) < 0) { |
@@ -76,8 +76,8 @@ fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin) | |||
76 | } | 76 | } |
77 | 77 | ||
78 | /* extensions */ | 78 | /* extensions */ |
79 | if (cred->ext) | 79 | if (cred->ext.mask) |
80 | if ((argv[5] = cbor_encode_extensions(cred->ext)) == NULL) { | 80 | if ((argv[5] = cbor_encode_extensions(&cred->ext)) == NULL) { |
81 | fido_log_debug("%s: cbor_encode_extensions", __func__); | 81 | fido_log_debug("%s: cbor_encode_extensions", __func__); |
82 | r = FIDO_ERR_INTERNAL; | 82 | r = FIDO_ERR_INTERNAL; |
83 | goto fail; | 83 | goto fail; |
@@ -106,8 +106,8 @@ fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin) | |||
106 | } | 106 | } |
107 | 107 | ||
108 | /* framing and transmission */ | 108 | /* framing and transmission */ |
109 | if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, 9, &f) < 0 || | 109 | if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, nitems(argv), &f) < 0 || |
110 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | 110 | fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { |
111 | fido_log_debug("%s: fido_tx", __func__); | 111 | fido_log_debug("%s: fido_tx", __func__); |
112 | r = FIDO_ERR_TX; | 112 | r = FIDO_ERR_TX; |
113 | goto fail; | 113 | goto fail; |
@@ -126,14 +126,14 @@ fail: | |||
126 | static int | 126 | static int |
127 | fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int ms) | 127 | fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int ms) |
128 | { | 128 | { |
129 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 129 | unsigned char reply[FIDO_MAXMSG]; |
130 | unsigned char reply[2048]; | ||
131 | int reply_len; | 130 | int reply_len; |
132 | int r; | 131 | int r; |
133 | 132 | ||
134 | fido_cred_reset_rx(cred); | 133 | fido_cred_reset_rx(cred); |
135 | 134 | ||
136 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 135 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
136 | ms)) < 0) { | ||
137 | fido_log_debug("%s: fido_rx", __func__); | 137 | fido_log_debug("%s: fido_rx", __func__); |
138 | return (FIDO_ERR_RX); | 138 | return (FIDO_ERR_RX); |
139 | } | 139 | } |
@@ -170,7 +170,8 @@ int | |||
170 | fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin) | 170 | fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin) |
171 | { | 171 | { |
172 | if (fido_dev_is_fido2(dev) == false) { | 172 | if (fido_dev_is_fido2(dev) == false) { |
173 | if (pin != NULL || cred->rk == FIDO_OPT_TRUE || cred->ext != 0) | 173 | if (pin != NULL || cred->rk == FIDO_OPT_TRUE || |
174 | cred->ext.mask != 0) | ||
174 | return (FIDO_ERR_UNSUPPORTED_OPTION); | 175 | return (FIDO_ERR_UNSUPPORTED_OPTION); |
175 | return (u2f_register(dev, cred, -1)); | 176 | return (u2f_register(dev, cred, -1)); |
176 | } | 177 | } |
@@ -179,15 +180,9 @@ fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin) | |||
179 | } | 180 | } |
180 | 181 | ||
181 | static int | 182 | static int |
182 | check_extensions(int authdata_ext, int ext) | 183 | check_extensions(const fido_cred_ext_t *authdata_ext, const fido_cred_ext_t *ext) |
183 | { | 184 | { |
184 | if (authdata_ext != ext) { | 185 | return (timingsafe_bcmp(authdata_ext, ext, sizeof(*authdata_ext))); |
185 | fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__, | ||
186 | authdata_ext, ext); | ||
187 | return (-1); | ||
188 | } | ||
189 | |||
190 | return (0); | ||
191 | } | 186 | } |
192 | 187 | ||
193 | int | 188 | int |
@@ -208,48 +203,6 @@ fido_check_rp_id(const char *id, const unsigned char *obtained_hash) | |||
208 | } | 203 | } |
209 | 204 | ||
210 | static int | 205 | static int |
211 | get_signed_hash_packed(fido_blob_t *dgst, const fido_blob_t *clientdata, | ||
212 | const fido_blob_t *authdata_cbor) | ||
213 | { | ||
214 | cbor_item_t *item = NULL; | ||
215 | unsigned char *authdata_ptr = NULL; | ||
216 | size_t authdata_len; | ||
217 | struct cbor_load_result cbor; | ||
218 | SHA256_CTX ctx; | ||
219 | int ok = -1; | ||
220 | |||
221 | if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len, | ||
222 | &cbor)) == NULL) { | ||
223 | fido_log_debug("%s: cbor_load", __func__); | ||
224 | goto fail; | ||
225 | } | ||
226 | |||
227 | if (cbor_isa_bytestring(item) == false || | ||
228 | cbor_bytestring_is_definite(item) == false) { | ||
229 | fido_log_debug("%s: cbor type", __func__); | ||
230 | goto fail; | ||
231 | } | ||
232 | |||
233 | authdata_ptr = cbor_bytestring_handle(item); | ||
234 | authdata_len = cbor_bytestring_length(item); | ||
235 | |||
236 | if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 || | ||
237 | SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 || | ||
238 | SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 || | ||
239 | SHA256_Final(dgst->ptr, &ctx) == 0) { | ||
240 | fido_log_debug("%s: sha256", __func__); | ||
241 | goto fail; | ||
242 | } | ||
243 | |||
244 | ok = 0; | ||
245 | fail: | ||
246 | if (item != NULL) | ||
247 | cbor_decref(&item); | ||
248 | |||
249 | return (ok); | ||
250 | } | ||
251 | |||
252 | static int | ||
253 | get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id, | 206 | get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id, |
254 | size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id, | 207 | size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id, |
255 | const es256_pk_t *pk) | 208 | const es256_pk_t *pk) |
@@ -356,16 +309,16 @@ fido_cred_verify(const fido_cred_t *cred) | |||
356 | goto out; | 309 | goto out; |
357 | } | 310 | } |
358 | 311 | ||
359 | if (check_extensions(cred->authdata_ext, cred->ext) < 0) { | 312 | if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) { |
360 | fido_log_debug("%s: check_extensions", __func__); | 313 | fido_log_debug("%s: check_extensions", __func__); |
361 | r = FIDO_ERR_INVALID_PARAM; | 314 | r = FIDO_ERR_INVALID_PARAM; |
362 | goto out; | 315 | goto out; |
363 | } | 316 | } |
364 | 317 | ||
365 | if (!strcmp(cred->fmt, "packed")) { | 318 | if (!strcmp(cred->fmt, "packed")) { |
366 | if (get_signed_hash_packed(&dgst, &cred->cdh, | 319 | if (fido_get_signed_hash(COSE_ES256, &dgst, &cred->cdh, |
367 | &cred->authdata_cbor) < 0) { | 320 | &cred->authdata_cbor) < 0) { |
368 | fido_log_debug("%s: get_signed_hash_packed", __func__); | 321 | fido_log_debug("%s: fido_get_signed_hash", __func__); |
369 | r = FIDO_ERR_INTERNAL; | 322 | r = FIDO_ERR_INTERNAL; |
370 | goto out; | 323 | goto out; |
371 | } | 324 | } |
@@ -395,7 +348,7 @@ out: | |||
395 | int | 348 | int |
396 | fido_cred_verify_self(const fido_cred_t *cred) | 349 | fido_cred_verify_self(const fido_cred_t *cred) |
397 | { | 350 | { |
398 | unsigned char buf[SHA256_DIGEST_LENGTH]; | 351 | unsigned char buf[1024]; /* XXX */ |
399 | fido_blob_t dgst; | 352 | fido_blob_t dgst; |
400 | int ok = -1; | 353 | int ok = -1; |
401 | int r; | 354 | int r; |
@@ -431,16 +384,16 @@ fido_cred_verify_self(const fido_cred_t *cred) | |||
431 | goto out; | 384 | goto out; |
432 | } | 385 | } |
433 | 386 | ||
434 | if (check_extensions(cred->authdata_ext, cred->ext) < 0) { | 387 | if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) { |
435 | fido_log_debug("%s: check_extensions", __func__); | 388 | fido_log_debug("%s: check_extensions", __func__); |
436 | r = FIDO_ERR_INVALID_PARAM; | 389 | r = FIDO_ERR_INVALID_PARAM; |
437 | goto out; | 390 | goto out; |
438 | } | 391 | } |
439 | 392 | ||
440 | if (!strcmp(cred->fmt, "packed")) { | 393 | if (!strcmp(cred->fmt, "packed")) { |
441 | if (get_signed_hash_packed(&dgst, &cred->cdh, | 394 | if (fido_get_signed_hash(cred->attcred.type, &dgst, &cred->cdh, |
442 | &cred->authdata_cbor) < 0) { | 395 | &cred->authdata_cbor) < 0) { |
443 | fido_log_debug("%s: get_signed_hash_packed", __func__); | 396 | fido_log_debug("%s: fido_get_signed_hash", __func__); |
444 | r = FIDO_ERR_INTERNAL; | 397 | r = FIDO_ERR_INTERNAL; |
445 | goto out; | 398 | goto out; |
446 | } | 399 | } |
@@ -519,9 +472,9 @@ fido_cred_reset_tx(fido_cred_t *cred) | |||
519 | memset(&cred->rp, 0, sizeof(cred->rp)); | 472 | memset(&cred->rp, 0, sizeof(cred->rp)); |
520 | memset(&cred->user, 0, sizeof(cred->user)); | 473 | memset(&cred->user, 0, sizeof(cred->user)); |
521 | memset(&cred->excl, 0, sizeof(cred->excl)); | 474 | memset(&cred->excl, 0, sizeof(cred->excl)); |
475 | memset(&cred->ext, 0, sizeof(cred->ext)); | ||
522 | 476 | ||
523 | cred->type = 0; | 477 | cred->type = 0; |
524 | cred->ext = 0; | ||
525 | cred->rk = FIDO_OPT_OMIT; | 478 | cred->rk = FIDO_OPT_OMIT; |
526 | cred->uv = FIDO_OPT_OMIT; | 479 | cred->uv = FIDO_OPT_OMIT; |
527 | } | 480 | } |
@@ -810,10 +763,14 @@ fail: | |||
810 | int | 763 | int |
811 | fido_cred_set_extensions(fido_cred_t *cred, int ext) | 764 | fido_cred_set_extensions(fido_cred_t *cred, int ext) |
812 | { | 765 | { |
813 | if (ext != 0 && ext != FIDO_EXT_HMAC_SECRET) | 766 | if (ext == 0) |
814 | return (FIDO_ERR_INVALID_ARGUMENT); | 767 | cred->ext.mask = 0; |
815 | 768 | else { | |
816 | cred->ext = ext; | 769 | if (ext != FIDO_EXT_HMAC_SECRET && |
770 | ext != FIDO_EXT_CRED_PROTECT) | ||
771 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
772 | cred->ext.mask |= ext; | ||
773 | } | ||
817 | 774 | ||
818 | return (FIDO_OK); | 775 | return (FIDO_OK); |
819 | } | 776 | } |
@@ -844,6 +801,25 @@ fido_cred_set_uv(fido_cred_t *cred, fido_opt_t uv) | |||
844 | } | 801 | } |
845 | 802 | ||
846 | int | 803 | int |
804 | fido_cred_set_prot(fido_cred_t *cred, int prot) | ||
805 | { | ||
806 | if (prot == 0) { | ||
807 | cred->ext.mask &= ~FIDO_EXT_CRED_PROTECT; | ||
808 | cred->ext.prot = 0; | ||
809 | } else { | ||
810 | if (prot != FIDO_CRED_PROT_UV_OPTIONAL && | ||
811 | prot != FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID && | ||
812 | prot != FIDO_CRED_PROT_UV_REQUIRED) | ||
813 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
814 | |||
815 | cred->ext.mask |= FIDO_EXT_CRED_PROTECT; | ||
816 | cred->ext.prot = prot; | ||
817 | } | ||
818 | |||
819 | return (FIDO_OK); | ||
820 | } | ||
821 | |||
822 | int | ||
847 | fido_cred_set_fmt(fido_cred_t *cred, const char *fmt) | 823 | fido_cred_set_fmt(fido_cred_t *cred, const char *fmt) |
848 | { | 824 | { |
849 | free(cred->fmt); | 825 | free(cred->fmt); |
@@ -991,6 +967,12 @@ fido_cred_id_len(const fido_cred_t *cred) | |||
991 | return (cred->attcred.id.len); | 967 | return (cred->attcred.id.len); |
992 | } | 968 | } |
993 | 969 | ||
970 | int | ||
971 | fido_cred_prot(const fido_cred_t *cred) | ||
972 | { | ||
973 | return (cred->ext.prot); | ||
974 | } | ||
975 | |||
994 | const char * | 976 | const char * |
995 | fido_cred_fmt(const fido_cred_t *cred) | 977 | fido_cred_fmt(const fido_cred_t *cred) |
996 | { | 978 | { |
diff --git a/src/credman.c b/src/credman.c index 76327e5..a382185 100644 --- a/src/credman.c +++ b/src/credman.c | |||
@@ -137,8 +137,8 @@ credman_tx(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *param, | |||
137 | } | 137 | } |
138 | 138 | ||
139 | /* framing and transmission */ | 139 | /* framing and transmission */ |
140 | if (cbor_build_frame(CTAP_CBOR_CRED_MGMT_PRE, argv, 4, &f) < 0 || | 140 | if (cbor_build_frame(CTAP_CBOR_CRED_MGMT_PRE, argv, nitems(argv), |
141 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | 141 | &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { |
142 | fido_log_debug("%s: fido_tx", __func__); | 142 | fido_log_debug("%s: fido_tx", __func__); |
143 | r = FIDO_ERR_TX; | 143 | r = FIDO_ERR_TX; |
144 | goto fail; | 144 | goto fail; |
@@ -181,14 +181,14 @@ credman_parse_metadata(const cbor_item_t *key, const cbor_item_t *val, | |||
181 | static int | 181 | static int |
182 | credman_rx_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, int ms) | 182 | credman_rx_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, int ms) |
183 | { | 183 | { |
184 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 184 | unsigned char reply[FIDO_MAXMSG]; |
185 | unsigned char reply[512]; | ||
186 | int reply_len; | 185 | int reply_len; |
187 | int r; | 186 | int r; |
188 | 187 | ||
189 | memset(metadata, 0, sizeof(*metadata)); | 188 | memset(metadata, 0, sizeof(*metadata)); |
190 | 189 | ||
191 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 190 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
191 | ms)) < 0) { | ||
192 | fido_log_debug("%s: fido_rx", __func__); | 192 | fido_log_debug("%s: fido_rx", __func__); |
193 | return (FIDO_ERR_RX); | 193 | return (FIDO_ERR_RX); |
194 | } | 194 | } |
@@ -300,14 +300,14 @@ credman_parse_rk_count(const cbor_item_t *key, const cbor_item_t *val, | |||
300 | static int | 300 | static int |
301 | credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms) | 301 | credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms) |
302 | { | 302 | { |
303 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 303 | unsigned char reply[FIDO_MAXMSG]; |
304 | unsigned char reply[2048]; | ||
305 | int reply_len; | 304 | int reply_len; |
306 | int r; | 305 | int r; |
307 | 306 | ||
308 | credman_reset_rk(rk); | 307 | credman_reset_rk(rk); |
309 | 308 | ||
310 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 309 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
310 | ms)) < 0) { | ||
311 | fido_log_debug("%s: fido_rx", __func__); | 311 | fido_log_debug("%s: fido_rx", __func__); |
312 | return (FIDO_ERR_RX); | 312 | return (FIDO_ERR_RX); |
313 | } | 313 | } |
@@ -339,12 +339,12 @@ credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms) | |||
339 | static int | 339 | static int |
340 | credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms) | 340 | credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms) |
341 | { | 341 | { |
342 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 342 | unsigned char reply[FIDO_MAXMSG]; |
343 | unsigned char reply[2048]; | ||
344 | int reply_len; | 343 | int reply_len; |
345 | int r; | 344 | int r; |
346 | 345 | ||
347 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 346 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
347 | ms)) < 0) { | ||
348 | fido_log_debug("%s: fido_rx", __func__); | 348 | fido_log_debug("%s: fido_rx", __func__); |
349 | return (FIDO_ERR_RX); | 349 | return (FIDO_ERR_RX); |
350 | } | 350 | } |
@@ -514,14 +514,14 @@ credman_parse_rp_count(const cbor_item_t *key, const cbor_item_t *val, | |||
514 | static int | 514 | static int |
515 | credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms) | 515 | credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms) |
516 | { | 516 | { |
517 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 517 | unsigned char reply[FIDO_MAXMSG]; |
518 | unsigned char reply[2048]; | ||
519 | int reply_len; | 518 | int reply_len; |
520 | int r; | 519 | int r; |
521 | 520 | ||
522 | credman_reset_rp(rp); | 521 | credman_reset_rp(rp); |
523 | 522 | ||
524 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 523 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
524 | ms)) < 0) { | ||
525 | fido_log_debug("%s: fido_rx", __func__); | 525 | fido_log_debug("%s: fido_rx", __func__); |
526 | return (FIDO_ERR_RX); | 526 | return (FIDO_ERR_RX); |
527 | } | 527 | } |
@@ -553,12 +553,12 @@ credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms) | |||
553 | static int | 553 | static int |
554 | credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms) | 554 | credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms) |
555 | { | 555 | { |
556 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 556 | unsigned char reply[FIDO_MAXMSG]; |
557 | unsigned char reply[2048]; | ||
558 | int reply_len; | 557 | int reply_len; |
559 | int r; | 558 | int r; |
560 | 559 | ||
561 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 560 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
561 | ms)) < 0) { | ||
562 | fido_log_debug("%s: fido_rx", __func__); | 562 | fido_log_debug("%s: fido_rx", __func__); |
563 | return (FIDO_ERR_RX); | 563 | return (FIDO_ERR_RX); |
564 | } | 564 | } |
@@ -6,6 +6,9 @@ | |||
6 | 6 | ||
7 | #include <sys/types.h> | 7 | #include <sys/types.h> |
8 | #include <sys/stat.h> | 8 | #include <sys/stat.h> |
9 | #ifdef HAVE_SYS_RANDOM_H | ||
10 | #include <sys/random.h> | ||
11 | #endif | ||
9 | 12 | ||
10 | #include <fcntl.h> | 13 | #include <fcntl.h> |
11 | #include <stdint.h> | 14 | #include <stdint.h> |
@@ -39,7 +42,22 @@ obtain_nonce(uint64_t *nonce) | |||
39 | 42 | ||
40 | return (0); | 43 | return (0); |
41 | } | 44 | } |
42 | #elif defined(HAS_DEV_URANDOM) | 45 | #elif defined(HAVE_ARC4RANDOM_BUF) |
46 | static int | ||
47 | obtain_nonce(uint64_t *nonce) | ||
48 | { | ||
49 | arc4random_buf(nonce, sizeof(*nonce)); | ||
50 | return (0); | ||
51 | } | ||
52 | #elif defined(HAVE_GETRANDOM) | ||
53 | static int | ||
54 | obtain_nonce(uint64_t *nonce) | ||
55 | { | ||
56 | if (getrandom(nonce, sizeof(*nonce), 0) < 0) | ||
57 | return (-1); | ||
58 | return (0); | ||
59 | } | ||
60 | #elif defined(HAVE_DEV_URANDOM) | ||
43 | static int | 61 | static int |
44 | obtain_nonce(uint64_t *nonce) | 62 | obtain_nonce(uint64_t *nonce) |
45 | { | 63 | { |
@@ -64,10 +82,34 @@ fail: | |||
64 | #error "please provide an implementation of obtain_nonce() for your platform" | 82 | #error "please provide an implementation of obtain_nonce() for your platform" |
65 | #endif /* _WIN32 */ | 83 | #endif /* _WIN32 */ |
66 | 84 | ||
85 | #ifndef TLS | ||
86 | #define TLS | ||
87 | #endif | ||
88 | |||
89 | typedef struct dev_manifest_func_node { | ||
90 | dev_manifest_func_t manifest_func; | ||
91 | struct dev_manifest_func_node *next; | ||
92 | } dev_manifest_func_node_t; | ||
93 | |||
94 | static TLS dev_manifest_func_node_t *manifest_funcs = NULL; | ||
95 | |||
96 | static void | ||
97 | find_manifest_func_node(dev_manifest_func_t f, dev_manifest_func_node_t **curr, | ||
98 | dev_manifest_func_node_t **prev) | ||
99 | { | ||
100 | *prev = NULL; | ||
101 | *curr = manifest_funcs; | ||
102 | |||
103 | while (*curr != NULL && (*curr)->manifest_func != f) { | ||
104 | *prev = *curr; | ||
105 | *curr = (*curr)->next; | ||
106 | } | ||
107 | } | ||
108 | |||
67 | static int | 109 | static int |
68 | fido_dev_open_tx(fido_dev_t *dev, const char *path) | 110 | fido_dev_open_tx(fido_dev_t *dev, const char *path) |
69 | { | 111 | { |
70 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_INIT; | 112 | const uint8_t cmd = CTAP_CMD_INIT; |
71 | 113 | ||
72 | if (dev->io_handle != NULL) { | 114 | if (dev->io_handle != NULL) { |
73 | fido_log_debug("%s: handle=%p", __func__, dev->io_handle); | 115 | fido_log_debug("%s: handle=%p", __func__, dev->io_handle); |
@@ -102,11 +144,14 @@ fido_dev_open_tx(fido_dev_t *dev, const char *path) | |||
102 | static int | 144 | static int |
103 | fido_dev_open_rx(fido_dev_t *dev, int ms) | 145 | fido_dev_open_rx(fido_dev_t *dev, int ms) |
104 | { | 146 | { |
105 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_INIT; | 147 | fido_cbor_info_t *info = NULL; |
106 | int n; | 148 | int reply_len; |
149 | int r; | ||
107 | 150 | ||
108 | if ((n = fido_rx(dev, cmd, &dev->attr, sizeof(dev->attr), ms)) < 0) { | 151 | if ((reply_len = fido_rx(dev, CTAP_CMD_INIT, &dev->attr, |
152 | sizeof(dev->attr), ms)) < 0) { | ||
109 | fido_log_debug("%s: fido_rx", __func__); | 153 | fido_log_debug("%s: fido_rx", __func__); |
154 | r = FIDO_ERR_RX; | ||
110 | goto fail; | 155 | goto fail; |
111 | } | 156 | } |
112 | 157 | ||
@@ -114,19 +159,42 @@ fido_dev_open_rx(fido_dev_t *dev, int ms) | |||
114 | dev->attr.nonce = dev->nonce; | 159 | dev->attr.nonce = dev->nonce; |
115 | #endif | 160 | #endif |
116 | 161 | ||
117 | if ((size_t)n != sizeof(dev->attr) || dev->attr.nonce != dev->nonce) { | 162 | if ((size_t)reply_len != sizeof(dev->attr) || |
163 | dev->attr.nonce != dev->nonce) { | ||
118 | fido_log_debug("%s: invalid nonce", __func__); | 164 | fido_log_debug("%s: invalid nonce", __func__); |
165 | r = FIDO_ERR_RX; | ||
119 | goto fail; | 166 | goto fail; |
120 | } | 167 | } |
121 | 168 | ||
122 | dev->cid = dev->attr.cid; | 169 | dev->cid = dev->attr.cid; |
123 | 170 | ||
124 | return (FIDO_OK); | 171 | if (fido_dev_is_fido2(dev)) { |
172 | if ((info = fido_cbor_info_new()) == NULL) { | ||
173 | fido_log_debug("%s: fido_cbor_info_new", __func__); | ||
174 | r = FIDO_ERR_INTERNAL; | ||
175 | goto fail; | ||
176 | } | ||
177 | if (fido_dev_get_cbor_info_wait(dev, info, ms) != FIDO_OK) { | ||
178 | fido_log_debug("%s: falling back to u2f", __func__); | ||
179 | fido_dev_force_u2f(dev); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | if (fido_dev_is_fido2(dev) && info != NULL) { | ||
184 | fido_log_debug("%s: FIDO_MAXMSG=%d, maxmsgsiz=%lu", __func__, | ||
185 | FIDO_MAXMSG, (unsigned long)fido_cbor_info_maxmsgsiz(info)); | ||
186 | } | ||
187 | |||
188 | r = FIDO_OK; | ||
125 | fail: | 189 | fail: |
126 | dev->io.close(dev->io_handle); | 190 | fido_cbor_info_free(&info); |
127 | dev->io_handle = NULL; | 191 | |
192 | if (r != FIDO_OK) { | ||
193 | dev->io.close(dev->io_handle); | ||
194 | dev->io_handle = NULL; | ||
195 | } | ||
128 | 196 | ||
129 | return (FIDO_ERR_RX); | 197 | return (r); |
130 | } | 198 | } |
131 | 199 | ||
132 | static int | 200 | static int |
@@ -142,6 +210,79 @@ fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms) | |||
142 | } | 210 | } |
143 | 211 | ||
144 | int | 212 | int |
213 | fido_dev_register_manifest_func(const dev_manifest_func_t f) | ||
214 | { | ||
215 | dev_manifest_func_node_t *prev, *curr, *n; | ||
216 | |||
217 | find_manifest_func_node(f, &curr, &prev); | ||
218 | if (curr != NULL) | ||
219 | return (FIDO_OK); | ||
220 | |||
221 | if ((n = calloc(1, sizeof(*n))) == NULL) { | ||
222 | fido_log_debug("%s: calloc", __func__); | ||
223 | return (FIDO_ERR_INTERNAL); | ||
224 | } | ||
225 | |||
226 | n->manifest_func = f; | ||
227 | n->next = manifest_funcs; | ||
228 | manifest_funcs = n; | ||
229 | |||
230 | return (FIDO_OK); | ||
231 | } | ||
232 | |||
233 | void | ||
234 | fido_dev_unregister_manifest_func(const dev_manifest_func_t f) | ||
235 | { | ||
236 | dev_manifest_func_node_t *prev, *curr; | ||
237 | |||
238 | find_manifest_func_node(f, &curr, &prev); | ||
239 | if (curr == NULL) | ||
240 | return; | ||
241 | if (prev != NULL) | ||
242 | prev->next = curr->next; | ||
243 | else | ||
244 | manifest_funcs = curr->next; | ||
245 | |||
246 | free(curr); | ||
247 | } | ||
248 | |||
249 | int | ||
250 | fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | ||
251 | { | ||
252 | dev_manifest_func_node_t *curr = NULL; | ||
253 | dev_manifest_func_t m_func; | ||
254 | size_t curr_olen; | ||
255 | int r; | ||
256 | |||
257 | *olen = 0; | ||
258 | |||
259 | if (fido_dev_register_manifest_func(fido_hid_manifest) != FIDO_OK) | ||
260 | return (FIDO_ERR_INTERNAL); | ||
261 | |||
262 | for (curr = manifest_funcs; curr != NULL; curr = curr->next) { | ||
263 | curr_olen = 0; | ||
264 | m_func = curr->manifest_func; | ||
265 | r = m_func(devlist + *olen, ilen - *olen, &curr_olen); | ||
266 | if (r != FIDO_OK) | ||
267 | return (r); | ||
268 | *olen += curr_olen; | ||
269 | if (*olen == ilen) | ||
270 | break; | ||
271 | } | ||
272 | |||
273 | return (FIDO_OK); | ||
274 | } | ||
275 | |||
276 | int | ||
277 | fido_dev_open_with_info(fido_dev_t *dev) | ||
278 | { | ||
279 | if (dev->path == NULL) | ||
280 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
281 | |||
282 | return (fido_dev_open_wait(dev, dev->path, -1)); | ||
283 | } | ||
284 | |||
285 | int | ||
145 | fido_dev_open(fido_dev_t *dev, const char *path) | 286 | fido_dev_open(fido_dev_t *dev, const char *path) |
146 | { | 287 | { |
147 | return (fido_dev_open_wait(dev, path, -1)); | 288 | return (fido_dev_open_wait(dev, path, -1)); |
@@ -162,7 +303,7 @@ fido_dev_close(fido_dev_t *dev) | |||
162 | int | 303 | int |
163 | fido_dev_cancel(fido_dev_t *dev) | 304 | fido_dev_cancel(fido_dev_t *dev) |
164 | { | 305 | { |
165 | if (fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CANCEL, NULL, 0) < 0) | 306 | if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0) |
166 | return (FIDO_ERR_TX); | 307 | return (FIDO_ERR_TX); |
167 | 308 | ||
168 | return (FIDO_OK); | 309 | return (FIDO_OK); |
@@ -172,7 +313,7 @@ int | |||
172 | fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) | 313 | fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) |
173 | { | 314 | { |
174 | if (dev->io_handle != NULL) { | 315 | if (dev->io_handle != NULL) { |
175 | fido_log_debug("%s: NULL handle", __func__); | 316 | fido_log_debug("%s: non-NULL handle", __func__); |
176 | return (FIDO_ERR_INVALID_ARGUMENT); | 317 | return (FIDO_ERR_INVALID_ARGUMENT); |
177 | } | 318 | } |
178 | 319 | ||
@@ -182,10 +323,20 @@ fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) | |||
182 | return (FIDO_ERR_INVALID_ARGUMENT); | 323 | return (FIDO_ERR_INVALID_ARGUMENT); |
183 | } | 324 | } |
184 | 325 | ||
185 | dev->io.open = io->open; | 326 | dev->io = *io; |
186 | dev->io.close = io->close; | 327 | |
187 | dev->io.read = io->read; | 328 | return (FIDO_OK); |
188 | dev->io.write = io->write; | 329 | } |
330 | |||
331 | int | ||
332 | fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t) | ||
333 | { | ||
334 | if (dev->io_handle != NULL) { | ||
335 | fido_log_debug("%s: non-NULL handle", __func__); | ||
336 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
337 | } | ||
338 | |||
339 | dev->transport = *t; | ||
189 | 340 | ||
190 | return (FIDO_OK); | 341 | return (FIDO_OK); |
191 | } | 342 | } |
@@ -200,21 +351,44 @@ fido_init(int flags) | |||
200 | fido_dev_t * | 351 | fido_dev_t * |
201 | fido_dev_new(void) | 352 | fido_dev_new(void) |
202 | { | 353 | { |
203 | fido_dev_t *dev; | 354 | fido_dev_t *dev; |
204 | fido_dev_io_t io; | ||
205 | 355 | ||
206 | if ((dev = calloc(1, sizeof(*dev))) == NULL) | 356 | if ((dev = calloc(1, sizeof(*dev))) == NULL) |
207 | return (NULL); | 357 | return (NULL); |
208 | 358 | ||
209 | dev->cid = CTAP_CID_BROADCAST; | 359 | dev->cid = CTAP_CID_BROADCAST; |
360 | dev->io = (fido_dev_io_t) { | ||
361 | &fido_hid_open, | ||
362 | &fido_hid_close, | ||
363 | &fido_hid_read, | ||
364 | &fido_hid_write, | ||
365 | }; | ||
366 | |||
367 | return (dev); | ||
368 | } | ||
369 | |||
370 | fido_dev_t * | ||
371 | fido_dev_new_with_info(const fido_dev_info_t *di) | ||
372 | { | ||
373 | fido_dev_t *dev; | ||
374 | |||
375 | if ((dev = calloc(1, sizeof(*dev))) == NULL) | ||
376 | return (NULL); | ||
377 | |||
378 | dev->cid = CTAP_CID_BROADCAST; | ||
379 | |||
380 | if (di->io.open == NULL || di->io.close == NULL || | ||
381 | di->io.read == NULL || di->io.write == NULL) { | ||
382 | fido_log_debug("%s: NULL function", __func__); | ||
383 | fido_dev_free(&dev); | ||
384 | return (NULL); | ||
385 | } | ||
210 | 386 | ||
211 | io.open = fido_hid_open; | 387 | dev->io = di->io; |
212 | io.close = fido_hid_close; | 388 | dev->transport = di->transport; |
213 | io.read = fido_hid_read; | ||
214 | io.write = fido_hid_write; | ||
215 | 389 | ||
216 | if (fido_dev_set_io_functions(dev, &io) != FIDO_OK) { | 390 | if ((dev->path = strdup(di->path)) == NULL) { |
217 | fido_log_debug("%s: fido_dev_set_io_functions", __func__); | 391 | fido_log_debug("%s: strdup", __func__); |
218 | fido_dev_free(&dev); | 392 | fido_dev_free(&dev); |
219 | return (NULL); | 393 | return (NULL); |
220 | } | 394 | } |
@@ -230,6 +404,7 @@ fido_dev_free(fido_dev_t **dev_p) | |||
230 | if (dev_p == NULL || (dev = *dev_p) == NULL) | 404 | if (dev_p == NULL || (dev = *dev_p) == NULL) |
231 | return; | 405 | return; |
232 | 406 | ||
407 | free(dev->path); | ||
233 | free(dev); | 408 | free(dev); |
234 | 409 | ||
235 | *dev_p = NULL; | 410 | *dev_p = NULL; |
diff --git a/src/eddsa.c b/src/eddsa.c index 92a0222..44a5563 100644 --- a/src/eddsa.c +++ b/src/eddsa.c | |||
@@ -23,6 +23,8 @@ EVP_PKEY_new_raw_public_key(int type, ENGINE *e, const unsigned char *key, | |||
23 | (void)key; | 23 | (void)key; |
24 | (void)keylen; | 24 | (void)keylen; |
25 | 25 | ||
26 | fido_log_debug("%s: unimplemented", __func__); | ||
27 | |||
26 | return (NULL); | 28 | return (NULL); |
27 | } | 29 | } |
28 | 30 | ||
@@ -34,6 +36,8 @@ EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub, | |||
34 | (void)pub; | 36 | (void)pub; |
35 | (void)len; | 37 | (void)len; |
36 | 38 | ||
39 | fido_log_debug("%s: unimplemented", __func__); | ||
40 | |||
37 | return (0); | 41 | return (0); |
38 | } | 42 | } |
39 | 43 | ||
@@ -47,6 +51,8 @@ EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen, | |||
47 | (void)tbs; | 51 | (void)tbs; |
48 | (void)tbslen; | 52 | (void)tbslen; |
49 | 53 | ||
54 | fido_log_debug("%s: unimplemented", __func__); | ||
55 | |||
50 | return (0); | 56 | return (0); |
51 | } | 57 | } |
52 | #endif /* LIBRESSL_VERSION_NUMBER || OPENSSL_VERSION_NUMBER < 0x10101000L */ | 58 | #endif /* LIBRESSL_VERSION_NUMBER || OPENSSL_VERSION_NUMBER < 0x10101000L */ |
@@ -55,6 +61,8 @@ EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen, | |||
55 | EVP_MD_CTX * | 61 | EVP_MD_CTX * |
56 | EVP_MD_CTX_new(void) | 62 | EVP_MD_CTX_new(void) |
57 | { | 63 | { |
64 | fido_log_debug("%s: unimplemented", __func__); | ||
65 | |||
58 | return (NULL); | 66 | return (NULL); |
59 | } | 67 | } |
60 | 68 | ||
@@ -29,7 +29,7 @@ fido_strerr(int n) | |||
29 | case FIDO_ERR_INVALID_CHANNEL: | 29 | case FIDO_ERR_INVALID_CHANNEL: |
30 | return "FIDO_ERR_INVALID_CHANNEL"; | 30 | return "FIDO_ERR_INVALID_CHANNEL"; |
31 | case FIDO_ERR_CBOR_UNEXPECTED_TYPE: | 31 | case FIDO_ERR_CBOR_UNEXPECTED_TYPE: |
32 | return "FIDO_ERR_UNEXPECTED_TYPE"; | 32 | return "FIDO_ERR_CBOR_UNEXPECTED_TYPE"; |
33 | case FIDO_ERR_INVALID_CBOR: | 33 | case FIDO_ERR_INVALID_CBOR: |
34 | return "FIDO_ERR_INVALID_CBOR"; | 34 | return "FIDO_ERR_INVALID_CBOR"; |
35 | case FIDO_ERR_MISSING_PARAMETER: | 35 | case FIDO_ERR_MISSING_PARAMETER: |
@@ -45,7 +45,7 @@ fido_strerr(int n) | |||
45 | case FIDO_ERR_INVALID_CREDENTIAL: | 45 | case FIDO_ERR_INVALID_CREDENTIAL: |
46 | return "FIDO_ERR_INVALID_CREDENTIAL"; | 46 | return "FIDO_ERR_INVALID_CREDENTIAL"; |
47 | case FIDO_ERR_USER_ACTION_PENDING: | 47 | case FIDO_ERR_USER_ACTION_PENDING: |
48 | return "FIDO_ERR_ACTION_PENDING"; | 48 | return "FIDO_ERR_USER_ACTION_PENDING"; |
49 | case FIDO_ERR_OPERATION_PENDING: | 49 | case FIDO_ERR_OPERATION_PENDING: |
50 | return "FIDO_ERR_OPERATION_PENDING"; | 50 | return "FIDO_ERR_OPERATION_PENDING"; |
51 | case FIDO_ERR_NO_OPERATIONS: | 51 | case FIDO_ERR_NO_OPERATIONS: |
@@ -55,11 +55,11 @@ fido_strerr(int n) | |||
55 | case FIDO_ERR_OPERATION_DENIED: | 55 | case FIDO_ERR_OPERATION_DENIED: |
56 | return "FIDO_ERR_OPERATION_DENIED"; | 56 | return "FIDO_ERR_OPERATION_DENIED"; |
57 | case FIDO_ERR_KEY_STORE_FULL: | 57 | case FIDO_ERR_KEY_STORE_FULL: |
58 | return "FIDO_ERR_STORE_FULL"; | 58 | return "FIDO_ERR_KEY_STORE_FULL"; |
59 | case FIDO_ERR_NOT_BUSY: | 59 | case FIDO_ERR_NOT_BUSY: |
60 | return "FIDO_ERR_NOT_BUSY"; | 60 | return "FIDO_ERR_NOT_BUSY"; |
61 | case FIDO_ERR_NO_OPERATION_PENDING: | 61 | case FIDO_ERR_NO_OPERATION_PENDING: |
62 | return "FIDO_ERR_OPERATION_PENDING"; | 62 | return "FIDO_ERR_NO_OPERATION_PENDING"; |
63 | case FIDO_ERR_UNSUPPORTED_OPTION: | 63 | case FIDO_ERR_UNSUPPORTED_OPTION: |
64 | return "FIDO_ERR_UNSUPPORTED_OPTION"; | 64 | return "FIDO_ERR_UNSUPPORTED_OPTION"; |
65 | case FIDO_ERR_INVALID_OPTION: | 65 | case FIDO_ERR_INVALID_OPTION: |
@@ -69,7 +69,7 @@ fido_strerr(int n) | |||
69 | case FIDO_ERR_NO_CREDENTIALS: | 69 | case FIDO_ERR_NO_CREDENTIALS: |
70 | return "FIDO_ERR_NO_CREDENTIALS"; | 70 | return "FIDO_ERR_NO_CREDENTIALS"; |
71 | case FIDO_ERR_USER_ACTION_TIMEOUT: | 71 | case FIDO_ERR_USER_ACTION_TIMEOUT: |
72 | return "FIDO_ERR_ACTION_TIMEOUT"; | 72 | return "FIDO_ERR_USER_ACTION_TIMEOUT"; |
73 | case FIDO_ERR_NOT_ALLOWED: | 73 | case FIDO_ERR_NOT_ALLOWED: |
74 | return "FIDO_ERR_NOT_ALLOWED"; | 74 | return "FIDO_ERR_NOT_ALLOWED"; |
75 | case FIDO_ERR_PIN_INVALID: | 75 | case FIDO_ERR_PIN_INVALID: |
@@ -77,25 +77,25 @@ fido_strerr(int n) | |||
77 | case FIDO_ERR_PIN_BLOCKED: | 77 | case FIDO_ERR_PIN_BLOCKED: |
78 | return "FIDO_ERR_PIN_BLOCKED"; | 78 | return "FIDO_ERR_PIN_BLOCKED"; |
79 | case FIDO_ERR_PIN_AUTH_INVALID: | 79 | case FIDO_ERR_PIN_AUTH_INVALID: |
80 | return "FIDO_ERR_AUTH_INVALID"; | 80 | return "FIDO_ERR_PIN_AUTH_INVALID"; |
81 | case FIDO_ERR_PIN_AUTH_BLOCKED: | 81 | case FIDO_ERR_PIN_AUTH_BLOCKED: |
82 | return "FIDO_ERR_AUTH_BLOCKED"; | 82 | return "FIDO_ERR_PIN_AUTH_BLOCKED"; |
83 | case FIDO_ERR_PIN_NOT_SET: | 83 | case FIDO_ERR_PIN_NOT_SET: |
84 | return "FIDO_ERR_NOT_SET"; | 84 | return "FIDO_ERR_PIN_NOT_SET"; |
85 | case FIDO_ERR_PIN_REQUIRED: | 85 | case FIDO_ERR_PIN_REQUIRED: |
86 | return "FIDO_ERR_PIN_REQUIRED"; | 86 | return "FIDO_ERR_PIN_REQUIRED"; |
87 | case FIDO_ERR_PIN_POLICY_VIOLATION: | 87 | case FIDO_ERR_PIN_POLICY_VIOLATION: |
88 | return "FIDO_ERR_POLICY_VIOLATION"; | 88 | return "FIDO_ERR_PIN_POLICY_VIOLATION"; |
89 | case FIDO_ERR_PIN_TOKEN_EXPIRED: | 89 | case FIDO_ERR_PIN_TOKEN_EXPIRED: |
90 | return "FIDO_ERR_TOKEN_EXPIRED"; | 90 | return "FIDO_ERR_PIN_TOKEN_EXPIRED"; |
91 | case FIDO_ERR_REQUEST_TOO_LARGE: | 91 | case FIDO_ERR_REQUEST_TOO_LARGE: |
92 | return "FIDO_ERR_TOO_LARGE"; | 92 | return "FIDO_ERR_REQUEST_TOO_LARGE"; |
93 | case FIDO_ERR_ACTION_TIMEOUT: | 93 | case FIDO_ERR_ACTION_TIMEOUT: |
94 | return "FIDO_ERR_ACTION_TIMEOUT"; | 94 | return "FIDO_ERR_ACTION_TIMEOUT"; |
95 | case FIDO_ERR_UP_REQUIRED: | 95 | case FIDO_ERR_UP_REQUIRED: |
96 | return "FIDO_ERR_UP_REQUIRED"; | 96 | return "FIDO_ERR_UP_REQUIRED"; |
97 | case FIDO_ERR_ERR_OTHER: | 97 | case FIDO_ERR_ERR_OTHER: |
98 | return "FIDO_ERR_OTHER"; | 98 | return "FIDO_ERR_ERR_OTHER"; |
99 | case FIDO_ERR_SPEC_LAST: | 99 | case FIDO_ERR_SPEC_LAST: |
100 | return "FIDO_ERR_SPEC_LAST"; | 100 | return "FIDO_ERR_SPEC_LAST"; |
101 | case FIDO_ERR_TX: | 101 | case FIDO_ERR_TX: |
diff --git a/src/es256.c b/src/es256.c index c8fd9f4..020ecaa 100644 --- a/src/es256.c +++ b/src/es256.c | |||
@@ -176,10 +176,15 @@ es256_pk_free(es256_pk_t **pkp) | |||
176 | int | 176 | int |
177 | es256_pk_from_ptr(es256_pk_t *pk, const void *ptr, size_t len) | 177 | es256_pk_from_ptr(es256_pk_t *pk, const void *ptr, size_t len) |
178 | { | 178 | { |
179 | const uint8_t *p = ptr; | ||
180 | |||
179 | if (len < sizeof(*pk)) | 181 | if (len < sizeof(*pk)) |
180 | return (FIDO_ERR_INVALID_ARGUMENT); | 182 | return (FIDO_ERR_INVALID_ARGUMENT); |
181 | 183 | ||
182 | memcpy(pk, ptr, sizeof(*pk)); | 184 | if (len == sizeof(*pk) + 1 && *p == 0x04) |
185 | memcpy(pk, ++p, sizeof(*pk)); /* uncompressed format */ | ||
186 | else | ||
187 | memcpy(pk, ptr, sizeof(*pk)); /* libfido2 x||y format */ | ||
183 | 188 | ||
184 | return (FIDO_OK); | 189 | return (FIDO_OK); |
185 | } | 190 | } |
@@ -262,8 +267,12 @@ es256_pk_to_EVP_PKEY(const es256_pk_t *k) | |||
262 | const int nid = NID_X9_62_prime256v1; | 267 | const int nid = NID_X9_62_prime256v1; |
263 | int ok = -1; | 268 | int ok = -1; |
264 | 269 | ||
265 | if ((bnctx = BN_CTX_new()) == NULL || | 270 | if ((bnctx = BN_CTX_new()) == NULL) |
266 | (x = BN_CTX_get(bnctx)) == NULL || | 271 | goto fail; |
272 | |||
273 | BN_CTX_start(bnctx); | ||
274 | |||
275 | if ((x = BN_CTX_get(bnctx)) == NULL || | ||
267 | (y = BN_CTX_get(bnctx)) == NULL) | 276 | (y = BN_CTX_get(bnctx)) == NULL) |
268 | goto fail; | 277 | goto fail; |
269 | 278 | ||
@@ -296,12 +305,16 @@ es256_pk_to_EVP_PKEY(const es256_pk_t *k) | |||
296 | 305 | ||
297 | ok = 0; | 306 | ok = 0; |
298 | fail: | 307 | fail: |
299 | if (bnctx != NULL) | 308 | if (bnctx != NULL) { |
309 | BN_CTX_end(bnctx); | ||
300 | BN_CTX_free(bnctx); | 310 | BN_CTX_free(bnctx); |
311 | } | ||
312 | |||
301 | if (ec != NULL) | 313 | if (ec != NULL) |
302 | EC_KEY_free(ec); | 314 | EC_KEY_free(ec); |
303 | if (q != NULL) | 315 | if (q != NULL) |
304 | EC_POINT_free(q); | 316 | EC_POINT_free(q); |
317 | |||
305 | if (ok < 0 && pkey != NULL) { | 318 | if (ok < 0 && pkey != NULL) { |
306 | EVP_PKEY_free(pkey); | 319 | EVP_PKEY_free(pkey); |
307 | pkey = NULL; | 320 | pkey = NULL; |
@@ -313,7 +326,7 @@ fail: | |||
313 | int | 326 | int |
314 | es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec) | 327 | es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec) |
315 | { | 328 | { |
316 | BN_CTX *ctx = NULL; | 329 | BN_CTX *bnctx = NULL; |
317 | BIGNUM *x = NULL; | 330 | BIGNUM *x = NULL; |
318 | BIGNUM *y = NULL; | 331 | BIGNUM *y = NULL; |
319 | const EC_POINT *q = NULL; | 332 | const EC_POINT *q = NULL; |
@@ -322,15 +335,17 @@ es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec) | |||
322 | int n; | 335 | int n; |
323 | 336 | ||
324 | if ((q = EC_KEY_get0_public_key(ec)) == NULL || | 337 | if ((q = EC_KEY_get0_public_key(ec)) == NULL || |
325 | (g = EC_KEY_get0_group(ec)) == NULL) | 338 | (g = EC_KEY_get0_group(ec)) == NULL || |
339 | (bnctx = BN_CTX_new()) == NULL) | ||
326 | goto fail; | 340 | goto fail; |
327 | 341 | ||
328 | if ((ctx = BN_CTX_new()) == NULL || | 342 | BN_CTX_start(bnctx); |
329 | (x = BN_CTX_get(ctx)) == NULL || | 343 | |
330 | (y = BN_CTX_get(ctx)) == NULL) | 344 | if ((x = BN_CTX_get(bnctx)) == NULL || |
345 | (y = BN_CTX_get(bnctx)) == NULL) | ||
331 | goto fail; | 346 | goto fail; |
332 | 347 | ||
333 | if (EC_POINT_get_affine_coordinates_GFp(g, q, x, y, ctx) == 0 || | 348 | if (EC_POINT_get_affine_coordinates_GFp(g, q, x, y, bnctx) == 0 || |
334 | (n = BN_num_bytes(x)) < 0 || (size_t)n > sizeof(pk->x) || | 349 | (n = BN_num_bytes(x)) < 0 || (size_t)n > sizeof(pk->x) || |
335 | (n = BN_num_bytes(y)) < 0 || (size_t)n > sizeof(pk->y)) { | 350 | (n = BN_num_bytes(y)) < 0 || (size_t)n > sizeof(pk->y)) { |
336 | fido_log_debug("%s: EC_POINT_get_affine_coordinates_GFp", | 351 | fido_log_debug("%s: EC_POINT_get_affine_coordinates_GFp", |
@@ -346,8 +361,10 @@ es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec) | |||
346 | 361 | ||
347 | ok = FIDO_OK; | 362 | ok = FIDO_OK; |
348 | fail: | 363 | fail: |
349 | if (ctx != NULL) | 364 | if (bnctx != NULL) { |
350 | BN_CTX_free(ctx); | 365 | BN_CTX_end(bnctx); |
366 | BN_CTX_free(bnctx); | ||
367 | } | ||
351 | 368 | ||
352 | return (ok); | 369 | return (ok); |
353 | } | 370 | } |
@@ -362,7 +379,12 @@ es256_sk_to_EVP_PKEY(const es256_sk_t *k) | |||
362 | const int nid = NID_X9_62_prime256v1; | 379 | const int nid = NID_X9_62_prime256v1; |
363 | int ok = -1; | 380 | int ok = -1; |
364 | 381 | ||
365 | if ((bnctx = BN_CTX_new()) == NULL || (d = BN_CTX_get(bnctx)) == NULL || | 382 | if ((bnctx = BN_CTX_new()) == NULL) |
383 | goto fail; | ||
384 | |||
385 | BN_CTX_start(bnctx); | ||
386 | |||
387 | if ((d = BN_CTX_get(bnctx)) == NULL || | ||
366 | BN_bin2bn(k->d, sizeof(k->d), d) == NULL) { | 388 | BN_bin2bn(k->d, sizeof(k->d), d) == NULL) { |
367 | fido_log_debug("%s: BN_bin2bn", __func__); | 389 | fido_log_debug("%s: BN_bin2bn", __func__); |
368 | goto fail; | 390 | goto fail; |
@@ -384,10 +406,14 @@ es256_sk_to_EVP_PKEY(const es256_sk_t *k) | |||
384 | 406 | ||
385 | ok = 0; | 407 | ok = 0; |
386 | fail: | 408 | fail: |
387 | if (bnctx != NULL) | 409 | if (bnctx != NULL) { |
410 | BN_CTX_end(bnctx); | ||
388 | BN_CTX_free(bnctx); | 411 | BN_CTX_free(bnctx); |
412 | } | ||
413 | |||
389 | if (ec != NULL) | 414 | if (ec != NULL) |
390 | EC_KEY_free(ec); | 415 | EC_KEY_free(ec); |
416 | |||
391 | if (ok < 0 && pkey != NULL) { | 417 | if (ok < 0 && pkey != NULL) { |
392 | EVP_PKEY_free(pkey); | 418 | EVP_PKEY_free(pkey); |
393 | pkey = NULL; | 419 | pkey = NULL; |
diff --git a/src/export.gnu b/src/export.gnu index f111e33..cbfa69f 100644 --- a/src/export.gnu +++ b/src/export.gnu | |||
@@ -76,6 +76,7 @@ | |||
76 | fido_cbor_info_extensions_ptr; | 76 | fido_cbor_info_extensions_ptr; |
77 | fido_cbor_info_free; | 77 | fido_cbor_info_free; |
78 | fido_cbor_info_maxmsgsiz; | 78 | fido_cbor_info_maxmsgsiz; |
79 | fido_cbor_info_fwversion; | ||
79 | fido_cbor_info_new; | 80 | fido_cbor_info_new; |
80 | fido_cbor_info_options_len; | 81 | fido_cbor_info_options_len; |
81 | fido_cbor_info_options_name_ptr; | 82 | fido_cbor_info_options_name_ptr; |
@@ -115,6 +116,7 @@ | |||
115 | fido_credman_rp_name; | 116 | fido_credman_rp_name; |
116 | fido_credman_rp_new; | 117 | fido_credman_rp_new; |
117 | fido_cred_new; | 118 | fido_cred_new; |
119 | fido_cred_prot; | ||
118 | fido_cred_pubkey_len; | 120 | fido_cred_pubkey_len; |
119 | fido_cred_pubkey_ptr; | 121 | fido_cred_pubkey_ptr; |
120 | fido_cred_rp_id; | 122 | fido_cred_rp_id; |
@@ -125,6 +127,7 @@ | |||
125 | fido_cred_set_extensions; | 127 | fido_cred_set_extensions; |
126 | fido_cred_set_fmt; | 128 | fido_cred_set_fmt; |
127 | fido_cred_set_options; | 129 | fido_cred_set_options; |
130 | fido_cred_set_prot; | ||
128 | fido_cred_set_rk; | 131 | fido_cred_set_rk; |
129 | fido_cred_set_rp; | 132 | fido_cred_set_rp; |
130 | fido_cred_set_sig; | 133 | fido_cred_set_sig; |
@@ -171,7 +174,9 @@ | |||
171 | fido_dev_reset; | 174 | fido_dev_reset; |
172 | fido_dev_set_io_functions; | 175 | fido_dev_set_io_functions; |
173 | fido_dev_set_pin; | 176 | fido_dev_set_pin; |
177 | fido_dev_set_transport_functions; | ||
174 | fido_init; | 178 | fido_init; |
179 | fido_set_log_handler; | ||
175 | fido_strerr; | 180 | fido_strerr; |
176 | rs256_pk_free; | 181 | rs256_pk_free; |
177 | rs256_pk_from_ptr; | 182 | rs256_pk_from_ptr; |
diff --git a/src/export.llvm b/src/export.llvm index ef99a26..abde2e9 100644 --- a/src/export.llvm +++ b/src/export.llvm | |||
@@ -74,6 +74,7 @@ _fido_cbor_info_extensions_len | |||
74 | _fido_cbor_info_extensions_ptr | 74 | _fido_cbor_info_extensions_ptr |
75 | _fido_cbor_info_free | 75 | _fido_cbor_info_free |
76 | _fido_cbor_info_maxmsgsiz | 76 | _fido_cbor_info_maxmsgsiz |
77 | _fido_cbor_info_fwversion | ||
77 | _fido_cbor_info_new | 78 | _fido_cbor_info_new |
78 | _fido_cbor_info_options_len | 79 | _fido_cbor_info_options_len |
79 | _fido_cbor_info_options_name_ptr | 80 | _fido_cbor_info_options_name_ptr |
@@ -113,6 +114,7 @@ _fido_credman_rp_id_hash_ptr | |||
113 | _fido_credman_rp_name | 114 | _fido_credman_rp_name |
114 | _fido_credman_rp_new | 115 | _fido_credman_rp_new |
115 | _fido_cred_new | 116 | _fido_cred_new |
117 | _fido_cred_prot | ||
116 | _fido_cred_pubkey_len | 118 | _fido_cred_pubkey_len |
117 | _fido_cred_pubkey_ptr | 119 | _fido_cred_pubkey_ptr |
118 | _fido_cred_rp_id | 120 | _fido_cred_rp_id |
@@ -123,6 +125,7 @@ _fido_cred_set_clientdata_hash | |||
123 | _fido_cred_set_extensions | 125 | _fido_cred_set_extensions |
124 | _fido_cred_set_fmt | 126 | _fido_cred_set_fmt |
125 | _fido_cred_set_options | 127 | _fido_cred_set_options |
128 | _fido_cred_set_prot | ||
126 | _fido_cred_set_rk | 129 | _fido_cred_set_rk |
127 | _fido_cred_set_rp | 130 | _fido_cred_set_rp |
128 | _fido_cred_set_sig | 131 | _fido_cred_set_sig |
@@ -169,7 +172,9 @@ _fido_dev_protocol | |||
169 | _fido_dev_reset | 172 | _fido_dev_reset |
170 | _fido_dev_set_io_functions | 173 | _fido_dev_set_io_functions |
171 | _fido_dev_set_pin | 174 | _fido_dev_set_pin |
175 | _fido_dev_set_transport_functions | ||
172 | _fido_init | 176 | _fido_init |
177 | _fido_set_log_handler | ||
173 | _fido_strerr | 178 | _fido_strerr |
174 | _rs256_pk_free | 179 | _rs256_pk_free |
175 | _rs256_pk_from_ptr | 180 | _rs256_pk_from_ptr |
diff --git a/src/export.msvc b/src/export.msvc index ff5425a..06ec69a 100644 --- a/src/export.msvc +++ b/src/export.msvc | |||
@@ -75,6 +75,7 @@ fido_cbor_info_extensions_len | |||
75 | fido_cbor_info_extensions_ptr | 75 | fido_cbor_info_extensions_ptr |
76 | fido_cbor_info_free | 76 | fido_cbor_info_free |
77 | fido_cbor_info_maxmsgsiz | 77 | fido_cbor_info_maxmsgsiz |
78 | fido_cbor_info_fwversion | ||
78 | fido_cbor_info_new | 79 | fido_cbor_info_new |
79 | fido_cbor_info_options_len | 80 | fido_cbor_info_options_len |
80 | fido_cbor_info_options_name_ptr | 81 | fido_cbor_info_options_name_ptr |
@@ -114,6 +115,7 @@ fido_credman_rp_id_hash_ptr | |||
114 | fido_credman_rp_name | 115 | fido_credman_rp_name |
115 | fido_credman_rp_new | 116 | fido_credman_rp_new |
116 | fido_cred_new | 117 | fido_cred_new |
118 | fido_cred_prot | ||
117 | fido_cred_pubkey_len | 119 | fido_cred_pubkey_len |
118 | fido_cred_pubkey_ptr | 120 | fido_cred_pubkey_ptr |
119 | fido_cred_rp_id | 121 | fido_cred_rp_id |
@@ -124,6 +126,7 @@ fido_cred_set_clientdata_hash | |||
124 | fido_cred_set_extensions | 126 | fido_cred_set_extensions |
125 | fido_cred_set_fmt | 127 | fido_cred_set_fmt |
126 | fido_cred_set_options | 128 | fido_cred_set_options |
129 | fido_cred_set_prot | ||
127 | fido_cred_set_rk | 130 | fido_cred_set_rk |
128 | fido_cred_set_rp | 131 | fido_cred_set_rp |
129 | fido_cred_set_sig | 132 | fido_cred_set_sig |
@@ -170,7 +173,9 @@ fido_dev_protocol | |||
170 | fido_dev_reset | 173 | fido_dev_reset |
171 | fido_dev_set_io_functions | 174 | fido_dev_set_io_functions |
172 | fido_dev_set_pin | 175 | fido_dev_set_pin |
176 | fido_dev_set_transport_functions | ||
173 | fido_init | 177 | fido_init |
178 | fido_set_log_handler | ||
174 | fido_strerr | 179 | fido_strerr |
175 | rs256_pk_free | 180 | rs256_pk_free |
176 | rs256_pk_from_ptr | 181 | rs256_pk_from_ptr |
diff --git a/src/extern.h b/src/extern.h index c35af58..fc0a49d 100644 --- a/src/extern.h +++ b/src/extern.h | |||
@@ -7,6 +7,15 @@ | |||
7 | #ifndef _EXTERN_H | 7 | #ifndef _EXTERN_H |
8 | #define _EXTERN_H | 8 | #define _EXTERN_H |
9 | 9 | ||
10 | #include <stdint.h> | ||
11 | |||
12 | #include "fido/types.h" | ||
13 | #include "blob.h" | ||
14 | |||
15 | #ifdef __cplusplus | ||
16 | extern "C" { | ||
17 | #endif /* __cplusplus */ | ||
18 | |||
10 | /* aes256 */ | 19 | /* aes256 */ |
11 | int aes256_cbc_dec(const fido_blob_t *, const fido_blob_t *, fido_blob_t *); | 20 | int aes256_cbc_dec(const fido_blob_t *, const fido_blob_t *, fido_blob_t *); |
12 | int aes256_cbc_enc(const fido_blob_t *, const fido_blob_t *, fido_blob_t *); | 21 | int aes256_cbc_enc(const fido_blob_t *, const fido_blob_t *, fido_blob_t *); |
@@ -16,7 +25,7 @@ cbor_item_t *cbor_flatten_vector(cbor_item_t **, size_t); | |||
16 | cbor_item_t *cbor_encode_assert_options(fido_opt_t, fido_opt_t); | 25 | cbor_item_t *cbor_encode_assert_options(fido_opt_t, fido_opt_t); |
17 | cbor_item_t *cbor_encode_change_pin_auth(const fido_blob_t *, | 26 | cbor_item_t *cbor_encode_change_pin_auth(const fido_blob_t *, |
18 | const fido_blob_t *, const fido_blob_t *); | 27 | const fido_blob_t *, const fido_blob_t *); |
19 | cbor_item_t *cbor_encode_extensions(int); | 28 | cbor_item_t *cbor_encode_extensions(const fido_cred_ext_t *); |
20 | cbor_item_t *cbor_encode_hmac_secret_param(const fido_blob_t *, | 29 | cbor_item_t *cbor_encode_hmac_secret_param(const fido_blob_t *, |
21 | const es256_pk_t *, const fido_blob_t *); | 30 | const es256_pk_t *, const fido_blob_t *); |
22 | cbor_item_t *cbor_encode_options(fido_opt_t, fido_opt_t); | 31 | cbor_item_t *cbor_encode_options(fido_opt_t, fido_opt_t); |
@@ -35,7 +44,7 @@ cbor_item_t *es256_pk_encode(const es256_pk_t *, int); | |||
35 | /* cbor decoding functions */ | 44 | /* cbor decoding functions */ |
36 | int cbor_decode_attstmt(const cbor_item_t *, fido_attstmt_t *); | 45 | int cbor_decode_attstmt(const cbor_item_t *, fido_attstmt_t *); |
37 | int cbor_decode_cred_authdata(const cbor_item_t *, int, fido_blob_t *, | 46 | int cbor_decode_cred_authdata(const cbor_item_t *, int, fido_blob_t *, |
38 | fido_authdata_t *, fido_attcred_t *, int *); | 47 | fido_authdata_t *, fido_attcred_t *, fido_cred_ext_t *); |
39 | int cbor_decode_assert_authdata(const cbor_item_t *, fido_blob_t *, | 48 | int cbor_decode_assert_authdata(const cbor_item_t *, fido_blob_t *, |
40 | fido_authdata_t *, int *, fido_blob_t *); | 49 | fido_authdata_t *, int *, fido_blob_t *); |
41 | int cbor_decode_cred_id(const cbor_item_t *, fido_blob_t *); | 50 | int cbor_decode_cred_id(const cbor_item_t *, fido_blob_t *); |
@@ -77,8 +86,8 @@ int fido_buf_write(unsigned char **, size_t *, const void *, size_t); | |||
77 | /* hid i/o */ | 86 | /* hid i/o */ |
78 | void *fido_hid_open(const char *); | 87 | void *fido_hid_open(const char *); |
79 | void fido_hid_close(void *); | 88 | void fido_hid_close(void *); |
80 | int fido_hid_read(void *, unsigned char *, size_t, int); | 89 | int fido_hid_read(void *, unsigned char *, size_t, int); |
81 | int fido_hid_write(void *, const unsigned char *, size_t); | 90 | int fido_hid_write(void *, const unsigned char *, size_t); |
82 | 91 | ||
83 | /* generic i/o */ | 92 | /* generic i/o */ |
84 | int fido_rx_cbor_status(fido_dev_t *, int); | 93 | int fido_rx_cbor_status(fido_dev_t *, int); |
@@ -109,6 +118,7 @@ int u2f_authenticate(fido_dev_t *, fido_assert_t *, int); | |||
109 | 118 | ||
110 | /* unexposed fido ops */ | 119 | /* unexposed fido ops */ |
111 | int fido_dev_authkey(fido_dev_t *, es256_pk_t *); | 120 | int fido_dev_authkey(fido_dev_t *, es256_pk_t *); |
121 | int fido_dev_get_cbor_info_wait(fido_dev_t *, fido_cbor_info_t *, int); | ||
112 | int fido_dev_get_pin_token(fido_dev_t *, const char *, const fido_blob_t *, | 122 | int fido_dev_get_pin_token(fido_dev_t *, const char *, const fido_blob_t *, |
113 | const es256_pk_t *, fido_blob_t *); | 123 | const es256_pk_t *, fido_blob_t *); |
114 | int fido_do_ecdh(fido_dev_t *, es256_pk_t **, fido_blob_t **); | 124 | int fido_do_ecdh(fido_dev_t *, es256_pk_t **, fido_blob_t **); |
@@ -128,5 +138,19 @@ int fido_verify_sig_rs256(const fido_blob_t *, const rs256_pk_t *, | |||
128 | const fido_blob_t *); | 138 | const fido_blob_t *); |
129 | int fido_verify_sig_eddsa(const fido_blob_t *, const eddsa_pk_t *, | 139 | int fido_verify_sig_eddsa(const fido_blob_t *, const eddsa_pk_t *, |
130 | const fido_blob_t *); | 140 | const fido_blob_t *); |
141 | int fido_get_signed_hash(int, fido_blob_t *, const fido_blob_t *, | ||
142 | const fido_blob_t *); | ||
143 | |||
144 | /* hid device manifest */ | ||
145 | int fido_hid_manifest(fido_dev_info_t *, size_t, size_t *); | ||
146 | |||
147 | /* device manifest registration */ | ||
148 | typedef int (*dev_manifest_func_t)(fido_dev_info_t *, size_t, size_t *); | ||
149 | int fido_dev_register_manifest_func(const dev_manifest_func_t); | ||
150 | void fido_dev_unregister_manifest_func(const dev_manifest_func_t); | ||
151 | |||
152 | #ifdef __cplusplus | ||
153 | } /* extern "C" */ | ||
154 | #endif /* __cplusplus */ | ||
131 | 155 | ||
132 | #endif /* !_EXTERN_H */ | 156 | #endif /* !_EXTERN_H */ |
@@ -14,24 +14,6 @@ | |||
14 | #include <stdint.h> | 14 | #include <stdint.h> |
15 | #include <stdlib.h> | 15 | #include <stdlib.h> |
16 | 16 | ||
17 | typedef void *fido_dev_io_open_t(const char *); | ||
18 | typedef void fido_dev_io_close_t(void *); | ||
19 | typedef int fido_dev_io_read_t(void *, unsigned char *, size_t, int); | ||
20 | typedef int fido_dev_io_write_t(void *, const unsigned char *, size_t); | ||
21 | |||
22 | typedef struct fido_dev_io { | ||
23 | fido_dev_io_open_t *open; | ||
24 | fido_dev_io_close_t *close; | ||
25 | fido_dev_io_read_t *read; | ||
26 | fido_dev_io_write_t *write; | ||
27 | } fido_dev_io_t; | ||
28 | |||
29 | typedef enum { | ||
30 | FIDO_OPT_OMIT = 0, /* use authenticator's default */ | ||
31 | FIDO_OPT_FALSE, /* explicitly set option to false */ | ||
32 | FIDO_OPT_TRUE, /* explicitly set option to true */ | ||
33 | } fido_opt_t; | ||
34 | |||
35 | #ifdef _FIDO_INTERNAL | 17 | #ifdef _FIDO_INTERNAL |
36 | #include <cbor.h> | 18 | #include <cbor.h> |
37 | #include <limits.h> | 19 | #include <limits.h> |
@@ -39,28 +21,21 @@ typedef enum { | |||
39 | #include "blob.h" | 21 | #include "blob.h" |
40 | #include "../openbsd-compat/openbsd-compat.h" | 22 | #include "../openbsd-compat/openbsd-compat.h" |
41 | #include "iso7816.h" | 23 | #include "iso7816.h" |
42 | #include "types.h" | ||
43 | #include "extern.h" | 24 | #include "extern.h" |
44 | #endif | 25 | #endif |
45 | 26 | ||
46 | #include "fido/err.h" | 27 | #include "fido/err.h" |
47 | #include "fido/param.h" | 28 | #include "fido/param.h" |
29 | #include "fido/types.h" | ||
48 | 30 | ||
49 | #ifndef _FIDO_INTERNAL | 31 | #ifdef __cplusplus |
50 | typedef struct fido_assert fido_assert_t; | 32 | extern "C" { |
51 | typedef struct fido_cbor_info fido_cbor_info_t; | 33 | #endif /* __cplusplus */ |
52 | typedef struct fido_cred fido_cred_t; | ||
53 | typedef struct fido_dev fido_dev_t; | ||
54 | typedef struct fido_dev_info fido_dev_info_t; | ||
55 | typedef struct es256_pk es256_pk_t; | ||
56 | typedef struct es256_sk es256_sk_t; | ||
57 | typedef struct rs256_pk rs256_pk_t; | ||
58 | typedef struct eddsa_pk eddsa_pk_t; | ||
59 | #endif | ||
60 | 34 | ||
61 | fido_assert_t *fido_assert_new(void); | 35 | fido_assert_t *fido_assert_new(void); |
62 | fido_cred_t *fido_cred_new(void); | 36 | fido_cred_t *fido_cred_new(void); |
63 | fido_dev_t *fido_dev_new(void); | 37 | fido_dev_t *fido_dev_new(void); |
38 | fido_dev_t *fido_dev_new_with_info(const fido_dev_info_t *); | ||
64 | fido_dev_info_t *fido_dev_info_new(size_t); | 39 | fido_dev_info_t *fido_dev_info_new(size_t); |
65 | fido_cbor_info_t *fido_cbor_info_new(void); | 40 | fido_cbor_info_t *fido_cbor_info_new(void); |
66 | 41 | ||
@@ -76,6 +51,7 @@ void fido_dev_info_free(fido_dev_info_t **, size_t); | |||
76 | #define FIDO_DEBUG 0x01 | 51 | #define FIDO_DEBUG 0x01 |
77 | 52 | ||
78 | void fido_init(int); | 53 | void fido_init(int); |
54 | void fido_set_log_handler(fido_log_handler_t *); | ||
79 | 55 | ||
80 | const unsigned char *fido_assert_authdata_ptr(const fido_assert_t *, size_t); | 56 | const unsigned char *fido_assert_authdata_ptr(const fido_assert_t *, size_t); |
81 | const unsigned char *fido_assert_clientdata_hash_ptr(const fido_assert_t *); | 57 | const unsigned char *fido_assert_clientdata_hash_ptr(const fido_assert_t *); |
@@ -121,19 +97,23 @@ int fido_assert_set_clientdata_hash(fido_assert_t *, const unsigned char *, | |||
121 | int fido_assert_set_count(fido_assert_t *, size_t); | 97 | int fido_assert_set_count(fido_assert_t *, size_t); |
122 | int fido_assert_set_extensions(fido_assert_t *, int); | 98 | int fido_assert_set_extensions(fido_assert_t *, int); |
123 | int fido_assert_set_hmac_salt(fido_assert_t *, const unsigned char *, size_t); | 99 | int fido_assert_set_hmac_salt(fido_assert_t *, const unsigned char *, size_t); |
124 | int fido_assert_set_options(fido_assert_t *, bool, bool) __attribute__((__deprecated__)); | 100 | int fido_assert_set_options(fido_assert_t *, bool, bool) |
101 | __attribute__((__deprecated__("use fido_assert_set_up/fido_assert_set_uv"))); | ||
125 | int fido_assert_set_rp(fido_assert_t *, const char *); | 102 | int fido_assert_set_rp(fido_assert_t *, const char *); |
126 | int fido_assert_set_up(fido_assert_t *, fido_opt_t); | 103 | int fido_assert_set_up(fido_assert_t *, fido_opt_t); |
127 | int fido_assert_set_uv(fido_assert_t *, fido_opt_t); | 104 | int fido_assert_set_uv(fido_assert_t *, fido_opt_t); |
128 | int fido_assert_set_sig(fido_assert_t *, size_t, const unsigned char *, size_t); | 105 | int fido_assert_set_sig(fido_assert_t *, size_t, const unsigned char *, size_t); |
129 | int fido_assert_verify(const fido_assert_t *, size_t, int, const void *); | 106 | int fido_assert_verify(const fido_assert_t *, size_t, int, const void *); |
130 | int fido_cred_exclude(fido_cred_t *, const unsigned char *, size_t); | 107 | int fido_cred_exclude(fido_cred_t *, const unsigned char *, size_t); |
108 | int fido_cred_prot(const fido_cred_t *); | ||
131 | int fido_cred_set_authdata(fido_cred_t *, const unsigned char *, size_t); | 109 | int fido_cred_set_authdata(fido_cred_t *, const unsigned char *, size_t); |
132 | int fido_cred_set_authdata_raw(fido_cred_t *, const unsigned char *, size_t); | 110 | int fido_cred_set_authdata_raw(fido_cred_t *, const unsigned char *, size_t); |
133 | int fido_cred_set_clientdata_hash(fido_cred_t *, const unsigned char *, size_t); | 111 | int fido_cred_set_clientdata_hash(fido_cred_t *, const unsigned char *, size_t); |
134 | int fido_cred_set_extensions(fido_cred_t *, int); | 112 | int fido_cred_set_extensions(fido_cred_t *, int); |
135 | int fido_cred_set_fmt(fido_cred_t *, const char *); | 113 | int fido_cred_set_fmt(fido_cred_t *, const char *); |
136 | int fido_cred_set_options(fido_cred_t *, bool, bool) __attribute__((__deprecated__)); | 114 | int fido_cred_set_options(fido_cred_t *, bool, bool) |
115 | __attribute__((__deprecated__("use fido_cred_set_rk/fido_cred_set_uv"))); | ||
116 | int fido_cred_set_prot(fido_cred_t *, int); | ||
137 | int fido_cred_set_rk(fido_cred_t *, fido_opt_t); | 117 | int fido_cred_set_rk(fido_cred_t *, fido_opt_t); |
138 | int fido_cred_set_rp(fido_cred_t *, const char *, const char *); | 118 | int fido_cred_set_rp(fido_cred_t *, const char *, const char *); |
139 | int fido_cred_set_sig(fido_cred_t *, const unsigned char *, size_t); | 119 | int fido_cred_set_sig(fido_cred_t *, const unsigned char *, size_t); |
@@ -152,10 +132,12 @@ int fido_dev_get_cbor_info(fido_dev_t *, fido_cbor_info_t *); | |||
152 | int fido_dev_get_retry_count(fido_dev_t *, int *); | 132 | int fido_dev_get_retry_count(fido_dev_t *, int *); |
153 | int fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *); | 133 | int fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *); |
154 | int fido_dev_make_cred(fido_dev_t *, fido_cred_t *, const char *); | 134 | int fido_dev_make_cred(fido_dev_t *, fido_cred_t *, const char *); |
135 | int fido_dev_open_with_info(fido_dev_t *); | ||
155 | int fido_dev_open(fido_dev_t *, const char *); | 136 | int fido_dev_open(fido_dev_t *, const char *); |
156 | int fido_dev_reset(fido_dev_t *); | 137 | int fido_dev_reset(fido_dev_t *); |
157 | int fido_dev_set_io_functions(fido_dev_t *, const fido_dev_io_t *); | 138 | int fido_dev_set_io_functions(fido_dev_t *, const fido_dev_io_t *); |
158 | int fido_dev_set_pin(fido_dev_t *, const char *, const char *); | 139 | int fido_dev_set_pin(fido_dev_t *, const char *, const char *); |
140 | int fido_dev_set_transport_functions(fido_dev_t *, const fido_dev_transport_t *); | ||
159 | 141 | ||
160 | size_t fido_assert_authdata_len(const fido_assert_t *, size_t); | 142 | size_t fido_assert_authdata_len(const fido_assert_t *, size_t); |
161 | size_t fido_assert_clientdata_hash_len(const fido_assert_t *); | 143 | size_t fido_assert_clientdata_hash_len(const fido_assert_t *); |
@@ -178,7 +160,7 @@ size_t fido_cred_sig_len(const fido_cred_t *); | |||
178 | size_t fido_cred_x5c_len(const fido_cred_t *); | 160 | size_t fido_cred_x5c_len(const fido_cred_t *); |
179 | 161 | ||
180 | uint8_t fido_assert_flags(const fido_assert_t *, size_t); | 162 | uint8_t fido_assert_flags(const fido_assert_t *, size_t); |
181 | uint32_t fido_assert_sigcount(const fido_assert_t *, size_t); | 163 | uint32_t fido_assert_sigcount(const fido_assert_t *, size_t); |
182 | uint8_t fido_cred_flags(const fido_cred_t *); | 164 | uint8_t fido_cred_flags(const fido_cred_t *); |
183 | uint8_t fido_dev_protocol(const fido_dev_t *); | 165 | uint8_t fido_dev_protocol(const fido_dev_t *); |
184 | uint8_t fido_dev_major(const fido_dev_t *); | 166 | uint8_t fido_dev_major(const fido_dev_t *); |
@@ -188,7 +170,12 @@ uint8_t fido_dev_flags(const fido_dev_t *); | |||
188 | int16_t fido_dev_info_vendor(const fido_dev_info_t *); | 170 | int16_t fido_dev_info_vendor(const fido_dev_info_t *); |
189 | int16_t fido_dev_info_product(const fido_dev_info_t *); | 171 | int16_t fido_dev_info_product(const fido_dev_info_t *); |
190 | uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *); | 172 | uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *); |
173 | uint64_t fido_cbor_info_fwversion(const fido_cbor_info_t *); | ||
191 | 174 | ||
192 | bool fido_dev_is_fido2(const fido_dev_t *); | 175 | bool fido_dev_is_fido2(const fido_dev_t *); |
193 | 176 | ||
177 | #ifdef __cplusplus | ||
178 | } /* extern "C" */ | ||
179 | #endif /* __cplusplus */ | ||
180 | |||
194 | #endif /* !_FIDO_H */ | 181 | #endif /* !_FIDO_H */ |
diff --git a/src/fido/bio.h b/src/fido/bio.h index 31dffe4..afe9ca4 100644 --- a/src/fido/bio.h +++ b/src/fido/bio.h | |||
@@ -10,8 +10,20 @@ | |||
10 | #include <stdint.h> | 10 | #include <stdint.h> |
11 | #include <stdlib.h> | 11 | #include <stdlib.h> |
12 | 12 | ||
13 | #ifdef _FIDO_INTERNAL | ||
14 | #include "blob.h" | ||
13 | #include "fido/err.h" | 15 | #include "fido/err.h" |
14 | #include "fido/param.h" | 16 | #include "fido/param.h" |
17 | #include "fido/types.h" | ||
18 | #else | ||
19 | #include <fido.h> | ||
20 | #include <fido/err.h> | ||
21 | #include <fido/param.h> | ||
22 | #endif | ||
23 | |||
24 | #ifdef __cplusplus | ||
25 | extern "C" { | ||
26 | #endif /* __cplusplus */ | ||
15 | 27 | ||
16 | #ifdef _FIDO_INTERNAL | 28 | #ifdef _FIDO_INTERNAL |
17 | struct fido_bio_template { | 29 | struct fido_bio_template { |
@@ -92,4 +104,8 @@ void fido_bio_info_free(fido_bio_info_t **); | |||
92 | void fido_bio_template_array_free(fido_bio_template_array_t **); | 104 | void fido_bio_template_array_free(fido_bio_template_array_t **); |
93 | void fido_bio_template_free(fido_bio_template_t **); | 105 | void fido_bio_template_free(fido_bio_template_t **); |
94 | 106 | ||
107 | #ifdef __cplusplus | ||
108 | } /* extern "C" */ | ||
109 | #endif /* __cplusplus */ | ||
110 | |||
95 | #endif /* !_FIDO_BIO_H */ | 111 | #endif /* !_FIDO_BIO_H */ |
diff --git a/src/fido/credman.h b/src/fido/credman.h index 1c7cafe..eaffd65 100644 --- a/src/fido/credman.h +++ b/src/fido/credman.h | |||
@@ -10,8 +10,20 @@ | |||
10 | #include <stdint.h> | 10 | #include <stdint.h> |
11 | #include <stdlib.h> | 11 | #include <stdlib.h> |
12 | 12 | ||
13 | #ifdef _FIDO_INTERNAL | ||
14 | #include "blob.h" | ||
13 | #include "fido/err.h" | 15 | #include "fido/err.h" |
14 | #include "fido/param.h" | 16 | #include "fido/param.h" |
17 | #include "fido/types.h" | ||
18 | #else | ||
19 | #include <fido.h> | ||
20 | #include <fido/err.h> | ||
21 | #include <fido/param.h> | ||
22 | #endif | ||
23 | |||
24 | #ifdef __cplusplus | ||
25 | extern "C" { | ||
26 | #endif /* __cplusplus */ | ||
15 | 27 | ||
16 | #ifdef _FIDO_INTERNAL | 28 | #ifdef _FIDO_INTERNAL |
17 | struct fido_credman_metadata { | 29 | struct fido_credman_metadata { |
@@ -71,4 +83,8 @@ void fido_credman_metadata_free(fido_credman_metadata_t **); | |||
71 | void fido_credman_rk_free(fido_credman_rk_t **); | 83 | void fido_credman_rk_free(fido_credman_rk_t **); |
72 | void fido_credman_rp_free(fido_credman_rp_t **); | 84 | void fido_credman_rp_free(fido_credman_rp_t **); |
73 | 85 | ||
86 | #ifdef __cplusplus | ||
87 | } /* extern "C" */ | ||
88 | #endif /* __cplusplus */ | ||
89 | |||
74 | #endif /* !_FIDO_CREDMAN_H */ | 90 | #endif /* !_FIDO_CREDMAN_H */ |
diff --git a/src/fido/eddsa.h b/src/fido/eddsa.h index 9de272d..4a81017 100644 --- a/src/fido/eddsa.h +++ b/src/fido/eddsa.h | |||
@@ -12,6 +12,16 @@ | |||
12 | #include <stdint.h> | 12 | #include <stdint.h> |
13 | #include <stdlib.h> | 13 | #include <stdlib.h> |
14 | 14 | ||
15 | #ifdef _FIDO_INTERNAL | ||
16 | #include "types.h" | ||
17 | #else | ||
18 | #include <fido.h> | ||
19 | #endif | ||
20 | |||
21 | #ifdef __cplusplus | ||
22 | extern "C" { | ||
23 | #endif /* __cplusplus */ | ||
24 | |||
15 | eddsa_pk_t *eddsa_pk_new(void); | 25 | eddsa_pk_t *eddsa_pk_new(void); |
16 | void eddsa_pk_free(eddsa_pk_t **); | 26 | void eddsa_pk_free(eddsa_pk_t **); |
17 | EVP_PKEY *eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *); | 27 | EVP_PKEY *eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *); |
@@ -37,4 +47,8 @@ void EVP_MD_CTX_free(EVP_MD_CTX *); | |||
37 | 47 | ||
38 | #endif /* _FIDO_INTERNAL */ | 48 | #endif /* _FIDO_INTERNAL */ |
39 | 49 | ||
50 | #ifdef __cplusplus | ||
51 | } /* extern "C" */ | ||
52 | #endif /* __cplusplus */ | ||
53 | |||
40 | #endif /* !_FIDO_EDDSA_H */ | 54 | #endif /* !_FIDO_EDDSA_H */ |
diff --git a/src/fido/err.h b/src/fido/err.h index 11f52bc..d7453fc 100644 --- a/src/fido/err.h +++ b/src/fido/err.h | |||
@@ -64,6 +64,14 @@ | |||
64 | #define FIDO_ERR_USER_PRESENCE_REQUIRED -8 | 64 | #define FIDO_ERR_USER_PRESENCE_REQUIRED -8 |
65 | #define FIDO_ERR_INTERNAL -9 | 65 | #define FIDO_ERR_INTERNAL -9 |
66 | 66 | ||
67 | #ifdef __cplusplus | ||
68 | extern "C" { | ||
69 | #endif /* __cplusplus */ | ||
70 | |||
67 | const char *fido_strerr(int); | 71 | const char *fido_strerr(int); |
68 | 72 | ||
73 | #ifdef __cplusplus | ||
74 | } /* extern "C" */ | ||
75 | #endif /* __cplusplus */ | ||
76 | |||
69 | #endif /* _FIDO_ERR_H */ | 77 | #endif /* _FIDO_ERR_H */ |
diff --git a/src/fido/es256.h b/src/fido/es256.h index d3d13dd..80f4db3 100644 --- a/src/fido/es256.h +++ b/src/fido/es256.h | |||
@@ -12,6 +12,16 @@ | |||
12 | #include <stdint.h> | 12 | #include <stdint.h> |
13 | #include <stdlib.h> | 13 | #include <stdlib.h> |
14 | 14 | ||
15 | #ifdef _FIDO_INTERNAL | ||
16 | #include "types.h" | ||
17 | #else | ||
18 | #include <fido.h> | ||
19 | #endif | ||
20 | |||
21 | #ifdef __cplusplus | ||
22 | extern "C" { | ||
23 | #endif /* __cplusplus */ | ||
24 | |||
15 | es256_pk_t *es256_pk_new(void); | 25 | es256_pk_t *es256_pk_new(void); |
16 | void es256_pk_free(es256_pk_t **); | 26 | void es256_pk_free(es256_pk_t **); |
17 | EVP_PKEY *es256_pk_to_EVP_PKEY(const es256_pk_t *); | 27 | EVP_PKEY *es256_pk_to_EVP_PKEY(const es256_pk_t *); |
@@ -31,4 +41,8 @@ int es256_pk_set_x(es256_pk_t *, const unsigned char *); | |||
31 | int es256_pk_set_y(es256_pk_t *, const unsigned char *); | 41 | int es256_pk_set_y(es256_pk_t *, const unsigned char *); |
32 | #endif | 42 | #endif |
33 | 43 | ||
44 | #ifdef __cplusplus | ||
45 | } /* extern "C" */ | ||
46 | #endif /* __cplusplus */ | ||
47 | |||
34 | #endif /* !_FIDO_ES256_H */ | 48 | #endif /* !_FIDO_ES256_H */ |
diff --git a/src/fido/param.h b/src/fido/param.h index 9e12ac6..7d3c0cc 100644 --- a/src/fido/param.h +++ b/src/fido/param.h | |||
@@ -58,6 +58,11 @@ | |||
58 | #define FIDO_RANDOM_DEV "/dev/urandom" | 58 | #define FIDO_RANDOM_DEV "/dev/urandom" |
59 | #endif | 59 | #endif |
60 | 60 | ||
61 | /* Maximum message size in bytes. */ | ||
62 | #ifndef FIDO_MAXMSG | ||
63 | #define FIDO_MAXMSG 1200 | ||
64 | #endif | ||
65 | |||
61 | /* CTAP capability bits. */ | 66 | /* CTAP capability bits. */ |
62 | #define FIDO_CAP_WINK 0x01 /* if set, device supports CTAP_CMD_WINK */ | 67 | #define FIDO_CAP_WINK 0x01 /* if set, device supports CTAP_CMD_WINK */ |
63 | #define FIDO_CAP_CBOR 0x04 /* if set, device supports CTAP_CMD_CBOR */ | 68 | #define FIDO_CAP_CBOR 0x04 /* if set, device supports CTAP_CMD_CBOR */ |
@@ -80,5 +85,11 @@ | |||
80 | 85 | ||
81 | /* Supported extensions. */ | 86 | /* Supported extensions. */ |
82 | #define FIDO_EXT_HMAC_SECRET 0x01 | 87 | #define FIDO_EXT_HMAC_SECRET 0x01 |
88 | #define FIDO_EXT_CRED_PROTECT 0x02 | ||
89 | |||
90 | /* Supported credential protection policies. */ | ||
91 | #define FIDO_CRED_PROT_UV_OPTIONAL 0x01 | ||
92 | #define FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID 0x02 | ||
93 | #define FIDO_CRED_PROT_UV_REQUIRED 0x03 | ||
83 | 94 | ||
84 | #endif /* !_FIDO_PARAM_H */ | 95 | #endif /* !_FIDO_PARAM_H */ |
diff --git a/src/fido/rs256.h b/src/fido/rs256.h index d2fa162..2b08d59 100644 --- a/src/fido/rs256.h +++ b/src/fido/rs256.h | |||
@@ -12,6 +12,16 @@ | |||
12 | #include <stdint.h> | 12 | #include <stdint.h> |
13 | #include <stdlib.h> | 13 | #include <stdlib.h> |
14 | 14 | ||
15 | #ifdef _FIDO_INTERNAL | ||
16 | #include "types.h" | ||
17 | #else | ||
18 | #include <fido.h> | ||
19 | #endif | ||
20 | |||
21 | #ifdef __cplusplus | ||
22 | extern "C" { | ||
23 | #endif /* __cplusplus */ | ||
24 | |||
15 | rs256_pk_t *rs256_pk_new(void); | 25 | rs256_pk_t *rs256_pk_new(void); |
16 | void rs256_pk_free(rs256_pk_t **); | 26 | void rs256_pk_free(rs256_pk_t **); |
17 | EVP_PKEY *rs256_pk_to_EVP_PKEY(const rs256_pk_t *); | 27 | EVP_PKEY *rs256_pk_to_EVP_PKEY(const rs256_pk_t *); |
@@ -19,4 +29,8 @@ EVP_PKEY *rs256_pk_to_EVP_PKEY(const rs256_pk_t *); | |||
19 | int rs256_pk_from_RSA(rs256_pk_t *, const RSA *); | 29 | int rs256_pk_from_RSA(rs256_pk_t *, const RSA *); |
20 | int rs256_pk_from_ptr(rs256_pk_t *, const void *, size_t); | 30 | int rs256_pk_from_ptr(rs256_pk_t *, const void *, size_t); |
21 | 31 | ||
32 | #ifdef __cplusplus | ||
33 | } /* extern "C" */ | ||
34 | #endif /* __cplusplus */ | ||
35 | |||
22 | #endif /* !_FIDO_RS256_H */ | 36 | #endif /* !_FIDO_RS256_H */ |
diff --git a/src/types.h b/src/fido/types.h index 42ed1b7..5df5e36 100644 --- a/src/types.h +++ b/src/fido/types.h | |||
@@ -4,10 +4,48 @@ | |||
4 | * license that can be found in the LICENSE file. | 4 | * license that can be found in the LICENSE file. |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #ifndef _TYPES_H | 7 | #ifndef _FIDO_TYPES_H |
8 | #define _TYPES_H | 8 | #define _FIDO_TYPES_H |
9 | 9 | ||
10 | #include <stddef.h> | ||
11 | #include <stdint.h> | ||
12 | |||
13 | #ifdef __cplusplus | ||
14 | extern "C" { | ||
15 | #endif /* __cplusplus */ | ||
16 | |||
17 | struct fido_dev; | ||
18 | |||
19 | typedef void *fido_dev_io_open_t(const char *); | ||
20 | typedef void fido_dev_io_close_t(void *); | ||
21 | typedef int fido_dev_io_read_t(void *, unsigned char *, size_t, int); | ||
22 | typedef int fido_dev_io_write_t(void *, const unsigned char *, size_t); | ||
23 | typedef int fido_dev_rx_t(struct fido_dev *, uint8_t, unsigned char *, size_t, int); | ||
24 | typedef int fido_dev_tx_t(struct fido_dev *, uint8_t, const unsigned char *, size_t); | ||
25 | |||
26 | typedef struct fido_dev_io { | ||
27 | fido_dev_io_open_t *open; | ||
28 | fido_dev_io_close_t *close; | ||
29 | fido_dev_io_read_t *read; | ||
30 | fido_dev_io_write_t *write; | ||
31 | } fido_dev_io_t; | ||
32 | |||
33 | typedef struct fido_dev_transport { | ||
34 | fido_dev_rx_t *rx; | ||
35 | fido_dev_tx_t *tx; | ||
36 | } fido_dev_transport_t; | ||
37 | |||
38 | typedef enum { | ||
39 | FIDO_OPT_OMIT = 0, /* use authenticator's default */ | ||
40 | FIDO_OPT_FALSE, /* explicitly set option to false */ | ||
41 | FIDO_OPT_TRUE, /* explicitly set option to true */ | ||
42 | } fido_opt_t; | ||
43 | |||
44 | typedef void fido_log_handler_t(const char *); | ||
45 | |||
46 | #ifdef _FIDO_INTERNAL | ||
10 | #include "packed.h" | 47 | #include "packed.h" |
48 | #include "blob.h" | ||
11 | 49 | ||
12 | /* COSE ES256 (ECDSA over P-256 with SHA-256) public key */ | 50 | /* COSE ES256 (ECDSA over P-256 with SHA-256) public key */ |
13 | typedef struct es256_pk { | 51 | typedef struct es256_pk { |
@@ -74,6 +112,11 @@ typedef struct fido_user { | |||
74 | char *display_name; /* required */ | 112 | char *display_name; /* required */ |
75 | } fido_user_t; | 113 | } fido_user_t; |
76 | 114 | ||
115 | typedef struct fido_cred_ext { | ||
116 | int mask; /* enabled extensions */ | ||
117 | int prot; /* protection policy */ | ||
118 | } fido_cred_ext_t; | ||
119 | |||
77 | typedef struct fido_cred { | 120 | typedef struct fido_cred { |
78 | fido_blob_t cdh; /* client data hash */ | 121 | fido_blob_t cdh; /* client data hash */ |
79 | fido_rp_t rp; /* relying party */ | 122 | fido_rp_t rp; /* relying party */ |
@@ -81,10 +124,10 @@ typedef struct fido_cred { | |||
81 | fido_blob_array_t excl; /* list of credential ids to exclude */ | 124 | fido_blob_array_t excl; /* list of credential ids to exclude */ |
82 | fido_opt_t rk; /* resident key */ | 125 | fido_opt_t rk; /* resident key */ |
83 | fido_opt_t uv; /* user verification */ | 126 | fido_opt_t uv; /* user verification */ |
84 | int ext; /* enabled extensions */ | 127 | fido_cred_ext_t ext; /* extensions */ |
85 | int type; /* cose algorithm */ | 128 | int type; /* cose algorithm */ |
86 | char *fmt; /* credential format */ | 129 | char *fmt; /* credential format */ |
87 | int authdata_ext; /* decoded extensions */ | 130 | fido_cred_ext_t authdata_ext; /* decoded extensions */ |
88 | fido_blob_t authdata_cbor; /* raw cbor payload */ | 131 | fido_blob_t authdata_cbor; /* raw cbor payload */ |
89 | fido_authdata_t authdata; /* decoded authdata payload */ | 132 | fido_authdata_t authdata; /* decoded authdata payload */ |
90 | fido_attcred_t attcred; /* returned credential (key + id) */ | 133 | fido_attcred_t attcred; /* returned credential (key + id) */ |
@@ -138,14 +181,17 @@ typedef struct fido_cbor_info { | |||
138 | fido_opt_array_t options; /* list of supported options */ | 181 | fido_opt_array_t options; /* list of supported options */ |
139 | uint64_t maxmsgsiz; /* maximum message size */ | 182 | uint64_t maxmsgsiz; /* maximum message size */ |
140 | fido_byte_array_t protocols; /* supported pin protocols */ | 183 | fido_byte_array_t protocols; /* supported pin protocols */ |
184 | uint64_t fwversion; /* firmware version */ | ||
141 | } fido_cbor_info_t; | 185 | } fido_cbor_info_t; |
142 | 186 | ||
143 | typedef struct fido_dev_info { | 187 | typedef struct fido_dev_info { |
144 | char *path; /* device path */ | 188 | char *path; /* device path */ |
145 | int16_t vendor_id; /* 2-byte vendor id */ | 189 | int16_t vendor_id; /* 2-byte vendor id */ |
146 | int16_t product_id; /* 2-byte product id */ | 190 | int16_t product_id; /* 2-byte product id */ |
147 | char *manufacturer; /* manufacturer string */ | 191 | char *manufacturer; /* manufacturer string */ |
148 | char *product; /* product string */ | 192 | char *product; /* product string */ |
193 | fido_dev_io_t io; /* i/o functions */ | ||
194 | fido_dev_transport_t transport; /* transport functions */ | ||
149 | } fido_dev_info_t; | 195 | } fido_dev_info_t; |
150 | 196 | ||
151 | PACKED_TYPE(fido_ctap_info_t, | 197 | PACKED_TYPE(fido_ctap_info_t, |
@@ -161,11 +207,29 @@ struct fido_ctap_info { | |||
161 | }) | 207 | }) |
162 | 208 | ||
163 | typedef struct fido_dev { | 209 | typedef struct fido_dev { |
164 | uint64_t nonce; /* issued nonce */ | 210 | uint64_t nonce; /* issued nonce */ |
165 | fido_ctap_info_t attr; /* device attributes */ | 211 | fido_ctap_info_t attr; /* device attributes */ |
166 | uint32_t cid; /* assigned channel id */ | 212 | uint32_t cid; /* assigned channel id */ |
167 | void *io_handle; /* abstract i/o handle */ | 213 | char *path; /* device path */ |
168 | fido_dev_io_t io; /* i/o functions & data */ | 214 | void *io_handle; /* abstract i/o handle */ |
215 | fido_dev_io_t io; /* i/o functions */ | ||
216 | fido_dev_transport_t transport; /* transport functions */ | ||
169 | } fido_dev_t; | 217 | } fido_dev_t; |
170 | 218 | ||
171 | #endif /* !_TYPES_H */ | 219 | #else |
220 | typedef struct fido_assert fido_assert_t; | ||
221 | typedef struct fido_cbor_info fido_cbor_info_t; | ||
222 | typedef struct fido_cred fido_cred_t; | ||
223 | typedef struct fido_dev fido_dev_t; | ||
224 | typedef struct fido_dev_info fido_dev_info_t; | ||
225 | typedef struct es256_pk es256_pk_t; | ||
226 | typedef struct es256_sk es256_sk_t; | ||
227 | typedef struct rs256_pk rs256_pk_t; | ||
228 | typedef struct eddsa_pk eddsa_pk_t; | ||
229 | #endif /* _FIDO_INTERNAL */ | ||
230 | |||
231 | #ifdef __cplusplus | ||
232 | } /* extern "C" */ | ||
233 | #endif /* __cplusplus */ | ||
234 | |||
235 | #endif /* !_FIDO_TYPES_H */ | ||
diff --git a/src/hid_hidapi.c b/src/hid_hidapi.c new file mode 100644 index 0000000..915621f --- /dev/null +++ b/src/hid_hidapi.c | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2019 Google LLC. 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. | ||
5 | */ | ||
6 | |||
7 | #include <hidapi/hidapi.h> | ||
8 | |||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | #include <wchar.h> | ||
12 | |||
13 | #include "fido.h" | ||
14 | |||
15 | static size_t | ||
16 | fido_wcslen(const wchar_t *wcs) | ||
17 | { | ||
18 | size_t l = 0; | ||
19 | while (*wcs++ != L'\0') | ||
20 | l++; | ||
21 | return l; | ||
22 | } | ||
23 | |||
24 | static char * | ||
25 | wcs_to_cs(const wchar_t *wcs) | ||
26 | { | ||
27 | char *cs; | ||
28 | size_t i; | ||
29 | |||
30 | if (wcs == NULL || (cs = calloc(fido_wcslen(wcs) + 1, 1)) == NULL) | ||
31 | return NULL; | ||
32 | |||
33 | for (i = 0; i < fido_wcslen(wcs); i++) { | ||
34 | if (wcs[i] >= 128) { | ||
35 | /* give up on parsing non-ASCII text */ | ||
36 | free(cs); | ||
37 | return strdup("hidapi device"); | ||
38 | } | ||
39 | cs[i] = (char)wcs[i]; | ||
40 | } | ||
41 | |||
42 | return cs; | ||
43 | } | ||
44 | |||
45 | static int | ||
46 | copy_info(fido_dev_info_t *di, const struct hid_device_info *d) | ||
47 | { | ||
48 | memset(di, 0, sizeof(*di)); | ||
49 | |||
50 | if (d->path != NULL) | ||
51 | di->path = strdup(d->path); | ||
52 | else | ||
53 | di->path = strdup(""); | ||
54 | |||
55 | if (d->manufacturer_string != NULL) | ||
56 | di->manufacturer = wcs_to_cs(d->manufacturer_string); | ||
57 | else | ||
58 | di->manufacturer = strdup(""); | ||
59 | |||
60 | if (d->product_string != NULL) | ||
61 | di->product = wcs_to_cs(d->product_string); | ||
62 | else | ||
63 | di->product = strdup(""); | ||
64 | |||
65 | if (di->path == NULL || | ||
66 | di->manufacturer == NULL || | ||
67 | di->product == NULL) { | ||
68 | free(di->path); | ||
69 | free(di->manufacturer); | ||
70 | free(di->product); | ||
71 | return -1; | ||
72 | } | ||
73 | |||
74 | di->product_id = d->product_id; | ||
75 | di->vendor_id = d->vendor_id; | ||
76 | di->io = (fido_dev_io_t) { | ||
77 | &fido_hid_open, | ||
78 | &fido_hid_close, | ||
79 | &fido_hid_read, | ||
80 | &fido_hid_write, | ||
81 | }; | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | void * | ||
87 | fido_hid_open(const char *path) | ||
88 | { | ||
89 | return hid_open_path(path); | ||
90 | } | ||
91 | |||
92 | void | ||
93 | fido_hid_close(void *hid_dev_handle) | ||
94 | { | ||
95 | hid_close(hid_dev_handle); | ||
96 | } | ||
97 | |||
98 | int | ||
99 | fido_hid_read(void *hid_dev_handle, unsigned char *buf, size_t len, int ms) | ||
100 | { | ||
101 | return hid_read_timeout(hid_dev_handle, buf, len, ms); | ||
102 | } | ||
103 | |||
104 | int | ||
105 | fido_hid_write(void *hid_dev_handle, const unsigned char *buf, size_t len) | ||
106 | { | ||
107 | return hid_write(hid_dev_handle, buf, len); | ||
108 | } | ||
109 | |||
110 | int | ||
111 | fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | ||
112 | { | ||
113 | struct hid_device_info *hdi; | ||
114 | |||
115 | *olen = 0; | ||
116 | |||
117 | if (ilen == 0) | ||
118 | return FIDO_OK; /* nothing to do */ | ||
119 | if (devlist == NULL) | ||
120 | return FIDO_ERR_INVALID_ARGUMENT; | ||
121 | if ((hdi = hid_enumerate(0, 0)) == NULL) | ||
122 | return FIDO_OK; /* nothing to do */ | ||
123 | |||
124 | for (struct hid_device_info *d = hdi; d != NULL; d = d->next) { | ||
125 | #if defined(_WIN32) || defined(__APPLE__) | ||
126 | if (d->usage_page != 0xf1d0) | ||
127 | continue; | ||
128 | #endif | ||
129 | if (copy_info(&devlist[*olen], d) == 0) { | ||
130 | if (++(*olen) == ilen) | ||
131 | break; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | hid_free_enumeration(hdi); | ||
136 | |||
137 | return FIDO_OK; | ||
138 | } | ||
diff --git a/src/hid_linux.c b/src/hid_linux.c index c7cabc9..99c5afb 100644 --- a/src/hid_linux.c +++ b/src/hid_linux.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <libudev.h> | 13 | #include <libudev.h> |
14 | #include <string.h> | 14 | #include <string.h> |
15 | #include <unistd.h> | 15 | #include <unistd.h> |
16 | #include <errno.h> | ||
16 | 17 | ||
17 | #include "fido.h" | 18 | #include "fido.h" |
18 | 19 | ||
@@ -98,7 +99,6 @@ get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page, | |||
98 | static int | 99 | static int |
99 | get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd) | 100 | get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd) |
100 | { | 101 | { |
101 | int r; | ||
102 | int s = -1; | 102 | int s = -1; |
103 | int fd; | 103 | int fd; |
104 | int ok = -1; | 104 | int ok = -1; |
@@ -108,7 +108,7 @@ get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd) | |||
108 | return (-1); | 108 | return (-1); |
109 | } | 109 | } |
110 | 110 | ||
111 | if ((r = ioctl(fd, HIDIOCGRDESCSIZE, &s)) < 0 || s < 0 || | 111 | if (ioctl(fd, HIDIOCGRDESCSIZE, &s) < 0 || s < 0 || |
112 | (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) { | 112 | (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) { |
113 | fido_log_debug("%s: ioctl HIDIOCGRDESCSIZE", __func__); | 113 | fido_log_debug("%s: ioctl HIDIOCGRDESCSIZE", __func__); |
114 | goto fail; | 114 | goto fail; |
@@ -116,7 +116,7 @@ get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd) | |||
116 | 116 | ||
117 | hrd->size = s; | 117 | hrd->size = s; |
118 | 118 | ||
119 | if ((r = ioctl(fd, HIDIOCGRDESC, hrd)) < 0) { | 119 | if (ioctl(fd, HIDIOCGRDESC, hrd) < 0) { |
120 | fido_log_debug("%s: ioctl HIDIOCGRDESC", __func__); | 120 | fido_log_debug("%s: ioctl HIDIOCGRDESC", __func__); |
121 | goto fail; | 121 | goto fail; |
122 | } | 122 | } |
@@ -240,7 +240,7 @@ fail: | |||
240 | } | 240 | } |
241 | 241 | ||
242 | int | 242 | int |
243 | fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | 243 | fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) |
244 | { | 244 | { |
245 | struct udev *udev = NULL; | 245 | struct udev *udev = NULL; |
246 | struct udev_enumerate *udev_enum = NULL; | 246 | struct udev_enumerate *udev_enum = NULL; |
@@ -267,6 +267,12 @@ fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | |||
267 | 267 | ||
268 | udev_list_entry_foreach(udev_entry, udev_list) { | 268 | udev_list_entry_foreach(udev_entry, udev_list) { |
269 | if (copy_info(&devlist[*olen], udev, udev_entry) == 0) { | 269 | if (copy_info(&devlist[*olen], udev, udev_entry) == 0) { |
270 | devlist[*olen].io = (fido_dev_io_t) { | ||
271 | fido_hid_open, | ||
272 | fido_hid_close, | ||
273 | fido_hid_read, | ||
274 | fido_hid_write, | ||
275 | }; | ||
270 | if (++(*olen) == ilen) | 276 | if (++(*olen) == ilen) |
271 | break; | 277 | break; |
272 | } | 278 | } |
diff --git a/src/hid_openbsd.c b/src/hid_openbsd.c index 8b92bd6..2b31dba 100644 --- a/src/hid_openbsd.c +++ b/src/hid_openbsd.c | |||
@@ -29,7 +29,7 @@ struct hid_openbsd { | |||
29 | }; | 29 | }; |
30 | 30 | ||
31 | int | 31 | int |
32 | fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | 32 | fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) |
33 | { | 33 | { |
34 | size_t i; | 34 | size_t i; |
35 | char path[64]; | 35 | char path[64]; |
@@ -101,6 +101,12 @@ fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | |||
101 | 101 | ||
102 | di = &devlist[*olen]; | 102 | di = &devlist[*olen]; |
103 | memset(di, 0, sizeof(*di)); | 103 | memset(di, 0, sizeof(*di)); |
104 | di->io = (fido_dev_io_t) { | ||
105 | fido_hid_open, | ||
106 | fido_hid_close, | ||
107 | fido_hid_read, | ||
108 | fido_hid_write, | ||
109 | }; | ||
104 | if ((di->path = strdup(path)) == NULL || | 110 | if ((di->path = strdup(path)) == NULL || |
105 | (di->manufacturer = strdup(udi.udi_vendor)) == NULL || | 111 | (di->manufacturer = strdup(udi.udi_vendor)) == NULL || |
106 | (di->product = strdup(udi.udi_product)) == NULL) { | 112 | (di->product = strdup(udi.udi_product)) == NULL) { |
diff --git a/src/hid_osx.c b/src/hid_osx.c index b705b43..5c40747 100644 --- a/src/hid_osx.c +++ b/src/hid_osx.c | |||
@@ -197,7 +197,7 @@ copy_info(fido_dev_info_t *di, IOHIDDeviceRef dev) | |||
197 | } | 197 | } |
198 | 198 | ||
199 | int | 199 | int |
200 | fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | 200 | fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) |
201 | { | 201 | { |
202 | IOHIDManagerRef manager = NULL; | 202 | IOHIDManagerRef manager = NULL; |
203 | CFSetRef devset = NULL; | 203 | CFSetRef devset = NULL; |
@@ -240,6 +240,12 @@ fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | |||
240 | 240 | ||
241 | for (CFIndex i = 0; i < devcnt; i++) { | 241 | for (CFIndex i = 0; i < devcnt; i++) { |
242 | if (copy_info(&devlist[*olen], devs[i]) == 0) { | 242 | if (copy_info(&devlist[*olen], devs[i]) == 0) { |
243 | devlist[*olen].io = (fido_dev_io_t) { | ||
244 | fido_hid_open, | ||
245 | fido_hid_close, | ||
246 | fido_hid_read, | ||
247 | fido_hid_write, | ||
248 | }; | ||
243 | if (++(*olen) == ilen) | 249 | if (++(*olen) == ilen) |
244 | break; | 250 | break; |
245 | } | 251 | } |
@@ -378,15 +384,18 @@ fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) | |||
378 | IOHIDDeviceScheduleWithRunLoop(dev->ref, CFRunLoopGetCurrent(), | 384 | IOHIDDeviceScheduleWithRunLoop(dev->ref, CFRunLoopGetCurrent(), |
379 | dev->loop_id); | 385 | dev->loop_id); |
380 | 386 | ||
381 | do | 387 | r = CFRunLoopRunInMode(dev->loop_id, 0.3, true); |
382 | r = CFRunLoopRunInMode(dev->loop_id, 0.003, true); | ||
383 | while (r != kCFRunLoopRunHandledSource); | ||
384 | 388 | ||
385 | IOHIDDeviceRegisterInputReportCallback(dev->ref, buf, len, NULL, NULL); | 389 | IOHIDDeviceRegisterInputReportCallback(dev->ref, buf, len, NULL, NULL); |
386 | IOHIDDeviceRegisterRemovalCallback(dev->ref, NULL, NULL); | 390 | IOHIDDeviceRegisterRemovalCallback(dev->ref, NULL, NULL); |
387 | IOHIDDeviceUnscheduleFromRunLoop(dev->ref, CFRunLoopGetCurrent(), | 391 | IOHIDDeviceUnscheduleFromRunLoop(dev->ref, CFRunLoopGetCurrent(), |
388 | dev->loop_id); | 392 | dev->loop_id); |
389 | 393 | ||
394 | if (r != kCFRunLoopRunHandledSource) { | ||
395 | fido_log_debug("%s: CFRunLoopRunInMode=%d", __func__, (int)r); | ||
396 | return (-1); | ||
397 | } | ||
398 | |||
390 | return (REPORT_LEN - 1); | 399 | return (REPORT_LEN - 1); |
391 | } | 400 | } |
392 | 401 | ||
diff --git a/src/hid_win.c b/src/hid_win.c index 6d93778..f970589 100644 --- a/src/hid_win.c +++ b/src/hid_win.c | |||
@@ -172,7 +172,7 @@ fail: | |||
172 | } | 172 | } |
173 | 173 | ||
174 | int | 174 | int |
175 | fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | 175 | fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) |
176 | { | 176 | { |
177 | GUID hid_guid = GUID_DEVINTERFACE_HID; | 177 | GUID hid_guid = GUID_DEVINTERFACE_HID; |
178 | HDEVINFO devinfo = INVALID_HANDLE_VALUE; | 178 | HDEVINFO devinfo = INVALID_HANDLE_VALUE; |
@@ -234,6 +234,12 @@ fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | |||
234 | } | 234 | } |
235 | 235 | ||
236 | if (copy_info(&devlist[*olen], ifdetail->DevicePath) == 0) { | 236 | if (copy_info(&devlist[*olen], ifdetail->DevicePath) == 0) { |
237 | devlist[*olen].io = (fido_dev_io_t) { | ||
238 | fido_hid_open, | ||
239 | fido_hid_close, | ||
240 | fido_hid_read, | ||
241 | fido_hid_write, | ||
242 | }; | ||
237 | if (++(*olen) == ilen) | 243 | if (++(*olen) == ilen) |
238 | break; | 244 | break; |
239 | } | 245 | } |
@@ -217,6 +217,8 @@ parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg) | |||
217 | return (cbor_decode_uint64(val, &ci->maxmsgsiz)); | 217 | return (cbor_decode_uint64(val, &ci->maxmsgsiz)); |
218 | case 6: /* pinProtocols */ | 218 | case 6: /* pinProtocols */ |
219 | return (decode_protocols(val, &ci->protocols)); | 219 | return (decode_protocols(val, &ci->protocols)); |
220 | case 14: /* fwVersion */ | ||
221 | return (cbor_decode_uint64(val, &ci->fwversion)); | ||
220 | default: /* ignore */ | 222 | default: /* ignore */ |
221 | fido_log_debug("%s: cbor type", __func__); | 223 | fido_log_debug("%s: cbor type", __func__); |
222 | return (0); | 224 | return (0); |
@@ -226,12 +228,11 @@ parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg) | |||
226 | static int | 228 | static int |
227 | fido_dev_get_cbor_info_tx(fido_dev_t *dev) | 229 | fido_dev_get_cbor_info_tx(fido_dev_t *dev) |
228 | { | 230 | { |
229 | const unsigned char cbor[] = { CTAP_CBOR_GETINFO }; | 231 | const unsigned char cbor[] = { CTAP_CBOR_GETINFO }; |
230 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
231 | 232 | ||
232 | fido_log_debug("%s: dev=%p", __func__, (void *)dev); | 233 | fido_log_debug("%s: dev=%p", __func__, (void *)dev); |
233 | 234 | ||
234 | if (fido_tx(dev, cmd, cbor, sizeof(cbor)) < 0) { | 235 | if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) { |
235 | fido_log_debug("%s: fido_tx", __func__); | 236 | fido_log_debug("%s: fido_tx", __func__); |
236 | return (FIDO_ERR_TX); | 237 | return (FIDO_ERR_TX); |
237 | } | 238 | } |
@@ -242,8 +243,7 @@ fido_dev_get_cbor_info_tx(fido_dev_t *dev) | |||
242 | static int | 243 | static int |
243 | fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) | 244 | fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) |
244 | { | 245 | { |
245 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 246 | unsigned char reply[FIDO_MAXMSG]; |
246 | unsigned char reply[512]; | ||
247 | int reply_len; | 247 | int reply_len; |
248 | 248 | ||
249 | fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev, | 249 | fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev, |
@@ -251,7 +251,8 @@ fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) | |||
251 | 251 | ||
252 | memset(ci, 0, sizeof(*ci)); | 252 | memset(ci, 0, sizeof(*ci)); |
253 | 253 | ||
254 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 254 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
255 | ms)) < 0) { | ||
255 | fido_log_debug("%s: fido_rx", __func__); | 256 | fido_log_debug("%s: fido_rx", __func__); |
256 | return (FIDO_ERR_RX); | 257 | return (FIDO_ERR_RX); |
257 | } | 258 | } |
@@ -260,7 +261,7 @@ fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) | |||
260 | parse_reply_element)); | 261 | parse_reply_element)); |
261 | } | 262 | } |
262 | 263 | ||
263 | static int | 264 | int |
264 | fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) | 265 | fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) |
265 | { | 266 | { |
266 | int r; | 267 | int r; |
@@ -397,6 +398,12 @@ fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci) | |||
397 | return (ci->maxmsgsiz); | 398 | return (ci->maxmsgsiz); |
398 | } | 399 | } |
399 | 400 | ||
401 | uint64_t | ||
402 | fido_cbor_info_fwversion(const fido_cbor_info_t *ci) | ||
403 | { | ||
404 | return (ci->fwversion); | ||
405 | } | ||
406 | |||
400 | const uint8_t * | 407 | const uint8_t * |
401 | fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci) | 408 | fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci) |
402 | { | 409 | { |
@@ -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 | ||
36 | static size_t | 36 | static int |
37 | tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) | 37 | tx_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 | |||
55 | static size_t | ||
56 | tx_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 | ||
63 | static size_t | 78 | static size_t |
64 | tx_frame(fido_dev_t *d, int seq, const void *buf, size_t count) | 79 | tx_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 | ||
87 | int | 99 | static int |
88 | fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) | 100 | tx(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 | ||
123 | int | ||
124 | fido_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 | |||
125 | static int | 144 | static int |
126 | rx_frame(fido_dev_t *d, struct frame *fp, int ms) | 145 | rx_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 | ||
140 | static int | 156 | static int |
141 | rx_preamble(fido_dev_t *d, struct frame *fp, int ms) | 157 | rx_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 | ||
155 | int | 184 | static int |
156 | fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms) | 185 | rx(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 | ||
242 | int | 245 | int |
246 | fido_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 | |||
269 | int | ||
243 | fido_rx_cbor_status(fido_dev_t *d, int ms) | 270 | fido_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 | } |
diff --git a/src/iso7816.h b/src/iso7816.h index 426cd97..563243f 100644 --- a/src/iso7816.h +++ b/src/iso7816.h | |||
@@ -7,8 +7,15 @@ | |||
7 | #ifndef _ISO7816_H | 7 | #ifndef _ISO7816_H |
8 | #define _ISO7816_H | 8 | #define _ISO7816_H |
9 | 9 | ||
10 | #include <stdint.h> | ||
11 | #include <stdlib.h> | ||
12 | |||
10 | #include "packed.h" | 13 | #include "packed.h" |
11 | 14 | ||
15 | #ifdef __cplusplus | ||
16 | extern "C" { | ||
17 | #endif /* __cplusplus */ | ||
18 | |||
12 | PACKED_TYPE(iso7816_header_t, | 19 | PACKED_TYPE(iso7816_header_t, |
13 | struct iso7816_header { | 20 | struct iso7816_header { |
14 | uint8_t cla; | 21 | uint8_t cla; |
@@ -35,4 +42,8 @@ iso7816_apdu_t *iso7816_new(uint8_t, uint8_t, uint16_t); | |||
35 | size_t iso7816_len(const iso7816_apdu_t *); | 42 | size_t iso7816_len(const iso7816_apdu_t *); |
36 | void iso7816_free(iso7816_apdu_t **); | 43 | void iso7816_free(iso7816_apdu_t **); |
37 | 44 | ||
45 | #ifdef __cplusplus | ||
46 | } /* extern "C" */ | ||
47 | #endif /* __cplusplus */ | ||
48 | |||
38 | #endif /* !_ISO7816_H */ | 49 | #endif /* !_ISO7816_H */ |
@@ -7,57 +7,86 @@ | |||
7 | #include <stdarg.h> | 7 | #include <stdarg.h> |
8 | #include <stdio.h> | 8 | #include <stdio.h> |
9 | #include <stdlib.h> | 9 | #include <stdlib.h> |
10 | #include <string.h> | ||
11 | |||
10 | #include "fido.h" | 12 | #include "fido.h" |
11 | 13 | ||
12 | #ifndef FIDO_NO_DIAGNOSTIC | 14 | #ifndef FIDO_NO_DIAGNOSTIC |
13 | 15 | ||
16 | #define XXDLEN 32 | ||
17 | #define XXDROW 128 | ||
18 | #define LINELEN 256 | ||
19 | |||
14 | #ifndef TLS | 20 | #ifndef TLS |
15 | #define TLS | 21 | #define TLS |
16 | #endif | 22 | #endif |
17 | 23 | ||
18 | static TLS int logging; | 24 | static TLS int logging; |
25 | static TLS fido_log_handler_t *log_handler; | ||
26 | |||
27 | static void | ||
28 | log_on_stderr(const char *str) | ||
29 | { | ||
30 | fprintf(stderr, "%s", str); | ||
31 | } | ||
19 | 32 | ||
20 | void | 33 | void |
21 | fido_log_init(void) | 34 | fido_log_init(void) |
22 | { | 35 | { |
23 | logging = 1; | 36 | logging = 1; |
37 | log_handler = log_on_stderr; | ||
24 | } | 38 | } |
25 | 39 | ||
26 | void | 40 | void |
27 | fido_log_xxd(const void *buf, size_t count) | 41 | fido_log_debug(const char *fmt, ...) |
28 | { | 42 | { |
29 | const uint8_t *ptr = buf; | 43 | char line[LINELEN]; |
30 | size_t i; | 44 | va_list ap; |
45 | int r; | ||
31 | 46 | ||
32 | if (!logging) | 47 | if (!logging || log_handler == NULL) |
33 | return; | 48 | return; |
34 | 49 | ||
35 | fprintf(stderr, " "); | 50 | va_start(ap, fmt); |
36 | 51 | r = vsnprintf(line, sizeof(line) - 1, fmt, ap); | |
37 | for (i = 0; i < count; i++) { | 52 | va_end(ap); |
38 | fprintf(stderr, "%02x ", *ptr++); | 53 | if (r < 0 || (size_t)r >= sizeof(line) - 1) |
39 | if ((i + 1) % 16 == 0 && i + 1 < count) | 54 | return; |
40 | fprintf(stderr, "\n "); | 55 | strlcat(line, "\n", sizeof(line)); |
41 | } | 56 | log_handler(line); |
42 | |||
43 | fprintf(stderr, "\n"); | ||
44 | fflush(stderr); | ||
45 | } | 57 | } |
46 | 58 | ||
47 | void | 59 | void |
48 | fido_log_debug(const char *fmt, ...) | 60 | fido_log_xxd(const void *buf, size_t count) |
49 | { | 61 | { |
50 | va_list ap; | 62 | const uint8_t *ptr = buf; |
63 | char row[XXDROW]; | ||
64 | char xxd[XXDLEN]; | ||
51 | 65 | ||
52 | if (!logging) | 66 | if (!logging || log_handler == NULL || count == 0) |
53 | return; | 67 | return; |
54 | 68 | ||
55 | va_start(ap, fmt); | 69 | *row = '\0'; |
56 | vfprintf(stderr, fmt, ap); | ||
57 | va_end(ap); | ||
58 | 70 | ||
59 | fprintf(stderr, "\n"); | 71 | for (size_t i = 0; i < count; i++) { |
60 | fflush(stderr); | 72 | *xxd = '\0'; |
73 | if (i % 16 == 0) | ||
74 | snprintf(xxd, sizeof(xxd), "%04zu: %02x", i, *ptr++); | ||
75 | else | ||
76 | snprintf(xxd, sizeof(xxd), " %02x", *ptr++); | ||
77 | strlcat(row, xxd, sizeof(row)); | ||
78 | if (i % 16 == 15 || i == count - 1) { | ||
79 | fido_log_debug("%s", row); | ||
80 | *row = '\0'; | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | |||
85 | void | ||
86 | fido_set_log_handler(fido_log_handler_t *handler) | ||
87 | { | ||
88 | if (handler != NULL) | ||
89 | log_handler = handler; | ||
61 | } | 90 | } |
62 | 91 | ||
63 | #endif /* !FIDO_NO_DIAGNOSTIC */ | 92 | #endif /* !FIDO_NO_DIAGNOSTIC */ |
@@ -5,6 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <string.h> | 7 | #include <string.h> |
8 | |||
8 | #include "fido.h" | 9 | #include "fido.h" |
9 | #include "fido/es256.h" | 10 | #include "fido/es256.h" |
10 | 11 | ||
@@ -23,6 +24,14 @@ parse_pintoken(const cbor_item_t *key, const cbor_item_t *val, void *arg) | |||
23 | return (fido_blob_decode(val, token)); | 24 | return (fido_blob_decode(val, token)); |
24 | } | 25 | } |
25 | 26 | ||
27 | #ifdef FIDO_UVTOKEN | ||
28 | static int | ||
29 | parse_uvtoken(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
30 | { | ||
31 | return (parse_pintoken(key, val, arg)); | ||
32 | } | ||
33 | #endif /* FIDO_UVTOKEN */ | ||
34 | |||
26 | static int | 35 | static int |
27 | fido_dev_get_pin_token_tx(fido_dev_t *dev, const char *pin, | 36 | fido_dev_get_pin_token_tx(fido_dev_t *dev, const char *pin, |
28 | const fido_blob_t *ecdh, const es256_pk_t *pk) | 37 | const fido_blob_t *ecdh, const es256_pk_t *pk) |
@@ -51,8 +60,8 @@ fido_dev_get_pin_token_tx(fido_dev_t *dev, const char *pin, | |||
51 | goto fail; | 60 | goto fail; |
52 | } | 61 | } |
53 | 62 | ||
54 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 6, &f) < 0 || | 63 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), |
55 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | 64 | &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { |
56 | fido_log_debug("%s: fido_tx", __func__); | 65 | fido_log_debug("%s: fido_tx", __func__); |
57 | r = FIDO_ERR_TX; | 66 | r = FIDO_ERR_TX; |
58 | goto fail; | 67 | goto fail; |
@@ -67,13 +76,47 @@ fail: | |||
67 | return (r); | 76 | return (r); |
68 | } | 77 | } |
69 | 78 | ||
79 | #ifdef FIDO_UVTOKEN | ||
80 | static int | ||
81 | fido_dev_get_uv_token_tx(fido_dev_t *dev, const es256_pk_t *pk) | ||
82 | { | ||
83 | fido_blob_t f; | ||
84 | cbor_item_t *argv[3]; | ||
85 | int r; | ||
86 | |||
87 | memset(&f, 0, sizeof(f)); | ||
88 | memset(argv, 0, sizeof(argv)); | ||
89 | |||
90 | if ((argv[0] = cbor_build_uint8(1)) == NULL || | ||
91 | (argv[1] = cbor_build_uint8(6)) == NULL || | ||
92 | (argv[2] = es256_pk_encode(pk, 0)) == NULL) { | ||
93 | fido_log_debug("%s: cbor encode", __func__); | ||
94 | r = FIDO_ERR_INTERNAL; | ||
95 | goto fail; | ||
96 | } | ||
97 | |||
98 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), | ||
99 | &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | ||
100 | fido_log_debug("%s: fido_tx", __func__); | ||
101 | r = FIDO_ERR_TX; | ||
102 | goto fail; | ||
103 | } | ||
104 | |||
105 | r = FIDO_OK; | ||
106 | fail: | ||
107 | cbor_vector_free(argv, nitems(argv)); | ||
108 | free(f.ptr); | ||
109 | |||
110 | return (r); | ||
111 | } | ||
112 | #endif /* FIDO_UVTOKEN */ | ||
113 | |||
70 | static int | 114 | static int |
71 | fido_dev_get_pin_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, | 115 | fido_dev_get_pin_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, |
72 | fido_blob_t *token, int ms) | 116 | fido_blob_t *token, int ms) |
73 | { | 117 | { |
74 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
75 | fido_blob_t *aes_token = NULL; | 118 | fido_blob_t *aes_token = NULL; |
76 | unsigned char reply[2048]; | 119 | unsigned char reply[FIDO_MAXMSG]; |
77 | int reply_len; | 120 | int reply_len; |
78 | int r; | 121 | int r; |
79 | 122 | ||
@@ -82,7 +125,8 @@ fido_dev_get_pin_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, | |||
82 | goto fail; | 125 | goto fail; |
83 | } | 126 | } |
84 | 127 | ||
85 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 128 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
129 | ms)) < 0) { | ||
86 | fido_log_debug("%s: fido_rx", __func__); | 130 | fido_log_debug("%s: fido_rx", __func__); |
87 | r = FIDO_ERR_RX; | 131 | r = FIDO_ERR_RX; |
88 | goto fail; | 132 | goto fail; |
@@ -107,15 +151,69 @@ fail: | |||
107 | return (r); | 151 | return (r); |
108 | } | 152 | } |
109 | 153 | ||
154 | #ifdef FIDO_UVTOKEN | ||
155 | static int | ||
156 | fido_dev_get_uv_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, | ||
157 | fido_blob_t *token, int ms) | ||
158 | { | ||
159 | fido_blob_t *aes_token = NULL; | ||
160 | unsigned char reply[FIDO_MAXMSG]; | ||
161 | int reply_len; | ||
162 | int r; | ||
163 | |||
164 | if ((aes_token = fido_blob_new()) == NULL) { | ||
165 | r = FIDO_ERR_INTERNAL; | ||
166 | goto fail; | ||
167 | } | ||
168 | |||
169 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), | ||
170 | ms)) < 0) { | ||
171 | fido_log_debug("%s: fido_rx", __func__); | ||
172 | r = FIDO_ERR_RX; | ||
173 | goto fail; | ||
174 | } | ||
175 | |||
176 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, aes_token, | ||
177 | parse_uvtoken)) != FIDO_OK) { | ||
178 | fido_log_debug("%s: parse_uvtoken", __func__); | ||
179 | goto fail; | ||
180 | } | ||
181 | |||
182 | if (aes256_cbc_dec(ecdh, aes_token, token) < 0) { | ||
183 | fido_log_debug("%s: aes256_cbc_dec", __func__); | ||
184 | r = FIDO_ERR_RX; | ||
185 | goto fail; | ||
186 | } | ||
187 | |||
188 | r = FIDO_OK; | ||
189 | fail: | ||
190 | fido_blob_free(&aes_token); | ||
191 | |||
192 | return (r); | ||
193 | } | ||
194 | #endif /* FIDO_UVTOKEN */ | ||
195 | |||
110 | static int | 196 | static int |
111 | fido_dev_get_pin_token_wait(fido_dev_t *dev, const char *pin, | 197 | fido_dev_get_pin_token_wait(fido_dev_t *dev, const char *pin, |
112 | const fido_blob_t *ecdh, const es256_pk_t *pk, fido_blob_t *token, int ms) | 198 | const fido_blob_t *ecdh, const es256_pk_t *pk, fido_blob_t *token, int ms) |
113 | { | 199 | { |
114 | int r; | 200 | int r; |
115 | 201 | ||
202 | #ifdef FIDO_UVTOKEN | ||
203 | if (getenv("FIDO_UVTOKEN") != NULL) { | ||
204 | if ((r = fido_dev_get_uv_token_tx(dev, pk)) != FIDO_OK || | ||
205 | (r = fido_dev_get_uv_token_rx(dev, ecdh, token, ms)) != FIDO_OK) | ||
206 | return (r); | ||
207 | } else { | ||
208 | if ((r = fido_dev_get_pin_token_tx(dev, pin, ecdh, pk)) != FIDO_OK || | ||
209 | (r = fido_dev_get_pin_token_rx(dev, ecdh, token, ms)) != FIDO_OK) | ||
210 | return (r); | ||
211 | } | ||
212 | #else | ||
116 | if ((r = fido_dev_get_pin_token_tx(dev, pin, ecdh, pk)) != FIDO_OK || | 213 | if ((r = fido_dev_get_pin_token_tx(dev, pin, ecdh, pk)) != FIDO_OK || |
117 | (r = fido_dev_get_pin_token_rx(dev, ecdh, token, ms)) != FIDO_OK) | 214 | (r = fido_dev_get_pin_token_rx(dev, ecdh, token, ms)) != FIDO_OK) |
118 | return (r); | 215 | return (r); |
216 | #endif | ||
119 | 217 | ||
120 | return (FIDO_OK); | 218 | return (FIDO_OK); |
121 | } | 219 | } |
@@ -196,8 +294,8 @@ fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin) | |||
196 | goto fail; | 294 | goto fail; |
197 | } | 295 | } |
198 | 296 | ||
199 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 6, &f) < 0 || | 297 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), |
200 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | 298 | &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { |
201 | fido_log_debug("%s: fido_tx", __func__); | 299 | fido_log_debug("%s: fido_tx", __func__); |
202 | r = FIDO_ERR_TX; | 300 | r = FIDO_ERR_TX; |
203 | goto fail; | 301 | goto fail; |
@@ -249,8 +347,8 @@ fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin) | |||
249 | goto fail; | 347 | goto fail; |
250 | } | 348 | } |
251 | 349 | ||
252 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 5, &f) < 0 || | 350 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), |
253 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | 351 | &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { |
254 | fido_log_debug("%s: fido_tx", __func__); | 352 | fido_log_debug("%s: fido_tx", __func__); |
255 | r = FIDO_ERR_TX; | 353 | r = FIDO_ERR_TX; |
256 | goto fail; | 354 | goto fail; |
@@ -338,8 +436,8 @@ fido_dev_get_retry_count_tx(fido_dev_t *dev) | |||
338 | goto fail; | 436 | goto fail; |
339 | } | 437 | } |
340 | 438 | ||
341 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 2, &f) < 0 || | 439 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), |
342 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | 440 | &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { |
343 | fido_log_debug("%s: fido_tx", __func__); | 441 | fido_log_debug("%s: fido_tx", __func__); |
344 | r = FIDO_ERR_TX; | 442 | r = FIDO_ERR_TX; |
345 | goto fail; | 443 | goto fail; |
@@ -356,14 +454,14 @@ fail: | |||
356 | static int | 454 | static int |
357 | fido_dev_get_retry_count_rx(fido_dev_t *dev, int *retries, int ms) | 455 | fido_dev_get_retry_count_rx(fido_dev_t *dev, int *retries, int ms) |
358 | { | 456 | { |
359 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | 457 | unsigned char reply[FIDO_MAXMSG]; |
360 | unsigned char reply[512]; | ||
361 | int reply_len; | 458 | int reply_len; |
362 | int r; | 459 | int r; |
363 | 460 | ||
364 | *retries = 0; | 461 | *retries = 0; |
365 | 462 | ||
366 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | 463 | if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), |
464 | ms)) < 0) { | ||
367 | fido_log_debug("%s: fido_rx", __func__); | 465 | fido_log_debug("%s: fido_rx", __func__); |
368 | return (FIDO_ERR_RX); | 466 | return (FIDO_ERR_RX); |
369 | } | 467 | } |
diff --git a/src/reset.c b/src/reset.c index 4b2c88a..ebda1cd 100644 --- a/src/reset.c +++ b/src/reset.c | |||
@@ -10,10 +10,9 @@ | |||
10 | static int | 10 | static int |
11 | fido_dev_reset_tx(fido_dev_t *dev) | 11 | fido_dev_reset_tx(fido_dev_t *dev) |
12 | { | 12 | { |
13 | const unsigned char cbor[] = { CTAP_CBOR_RESET }; | 13 | const unsigned char cbor[] = { CTAP_CBOR_RESET }; |
14 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
15 | 14 | ||
16 | if (fido_tx(dev, cmd, cbor, sizeof(cbor)) < 0) { | 15 | if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) { |
17 | fido_log_debug("%s: fido_tx", __func__); | 16 | fido_log_debug("%s: fido_tx", __func__); |
18 | return (FIDO_ERR_TX); | 17 | return (FIDO_ERR_TX); |
19 | } | 18 | } |
@@ -125,11 +125,10 @@ authdata_fake(const char *rp_id, uint8_t flags, uint32_t sigcount, | |||
125 | static int | 125 | static int |
126 | send_dummy_register(fido_dev_t *dev, int ms) | 126 | send_dummy_register(fido_dev_t *dev, int ms) |
127 | { | 127 | { |
128 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG; | ||
129 | iso7816_apdu_t *apdu = NULL; | 128 | iso7816_apdu_t *apdu = NULL; |
130 | unsigned char challenge[SHA256_DIGEST_LENGTH]; | 129 | unsigned char challenge[SHA256_DIGEST_LENGTH]; |
131 | unsigned char application[SHA256_DIGEST_LENGTH]; | 130 | unsigned char application[SHA256_DIGEST_LENGTH]; |
132 | unsigned char reply[2048]; | 131 | unsigned char reply[FIDO_MAXMSG]; |
133 | int r; | 132 | int r; |
134 | 133 | ||
135 | #ifdef FIDO_FUZZ | 134 | #ifdef FIDO_FUZZ |
@@ -150,13 +149,13 @@ send_dummy_register(fido_dev_t *dev, int ms) | |||
150 | } | 149 | } |
151 | 150 | ||
152 | do { | 151 | do { |
153 | if (fido_tx(dev, cmd, iso7816_ptr(apdu), | 152 | if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), |
154 | iso7816_len(apdu)) < 0) { | 153 | iso7816_len(apdu)) < 0) { |
155 | fido_log_debug("%s: fido_tx", __func__); | 154 | fido_log_debug("%s: fido_tx", __func__); |
156 | r = FIDO_ERR_TX; | 155 | r = FIDO_ERR_TX; |
157 | goto fail; | 156 | goto fail; |
158 | } | 157 | } |
159 | if (fido_rx(dev, cmd, &reply, sizeof(reply), ms) < 2) { | 158 | if (fido_rx(dev, CTAP_CMD_MSG, &reply, sizeof(reply), ms) < 2) { |
160 | fido_log_debug("%s: fido_rx", __func__); | 159 | fido_log_debug("%s: fido_rx", __func__); |
161 | r = FIDO_ERR_RX; | 160 | r = FIDO_ERR_RX; |
162 | goto fail; | 161 | goto fail; |
@@ -179,11 +178,10 @@ static int | |||
179 | key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id, | 178 | key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id, |
180 | int *found, int ms) | 179 | int *found, int ms) |
181 | { | 180 | { |
182 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG; | ||
183 | iso7816_apdu_t *apdu = NULL; | 181 | iso7816_apdu_t *apdu = NULL; |
184 | unsigned char challenge[SHA256_DIGEST_LENGTH]; | 182 | unsigned char challenge[SHA256_DIGEST_LENGTH]; |
185 | unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; | 183 | unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; |
186 | unsigned char reply[8]; | 184 | unsigned char reply[FIDO_MAXMSG]; |
187 | uint8_t key_id_len; | 185 | uint8_t key_id_len; |
188 | int r; | 186 | int r; |
189 | 187 | ||
@@ -217,12 +215,13 @@ key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id, | |||
217 | goto fail; | 215 | goto fail; |
218 | } | 216 | } |
219 | 217 | ||
220 | if (fido_tx(dev, cmd, iso7816_ptr(apdu), iso7816_len(apdu)) < 0) { | 218 | if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), |
219 | iso7816_len(apdu)) < 0) { | ||
221 | fido_log_debug("%s: fido_tx", __func__); | 220 | fido_log_debug("%s: fido_tx", __func__); |
222 | r = FIDO_ERR_TX; | 221 | r = FIDO_ERR_TX; |
223 | goto fail; | 222 | goto fail; |
224 | } | 223 | } |
225 | if (fido_rx(dev, cmd, &reply, sizeof(reply), ms) != 2) { | 224 | if (fido_rx(dev, CTAP_CMD_MSG, &reply, sizeof(reply), ms) != 2) { |
226 | fido_log_debug("%s: fido_rx", __func__); | 225 | fido_log_debug("%s: fido_rx", __func__); |
227 | r = FIDO_ERR_RX; | 226 | r = FIDO_ERR_RX; |
228 | goto fail; | 227 | goto fail; |
@@ -285,10 +284,9 @@ static int | |||
285 | do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id, | 284 | do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id, |
286 | const fido_blob_t *key_id, fido_blob_t *sig, fido_blob_t *ad, int ms) | 285 | const fido_blob_t *key_id, fido_blob_t *sig, fido_blob_t *ad, int ms) |
287 | { | 286 | { |
288 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG; | ||
289 | iso7816_apdu_t *apdu = NULL; | 287 | iso7816_apdu_t *apdu = NULL; |
290 | unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; | 288 | unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; |
291 | unsigned char reply[128]; | 289 | unsigned char reply[FIDO_MAXMSG]; |
292 | int reply_len; | 290 | int reply_len; |
293 | uint8_t key_id_len; | 291 | uint8_t key_id_len; |
294 | int r; | 292 | int r; |
@@ -326,14 +324,14 @@ do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id, | |||
326 | } | 324 | } |
327 | 325 | ||
328 | do { | 326 | do { |
329 | if (fido_tx(dev, cmd, iso7816_ptr(apdu), | 327 | if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), |
330 | iso7816_len(apdu)) < 0) { | 328 | iso7816_len(apdu)) < 0) { |
331 | fido_log_debug("%s: fido_tx", __func__); | 329 | fido_log_debug("%s: fido_tx", __func__); |
332 | r = FIDO_ERR_TX; | 330 | r = FIDO_ERR_TX; |
333 | goto fail; | 331 | goto fail; |
334 | } | 332 | } |
335 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), | 333 | if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, &reply, |
336 | ms)) < 2) { | 334 | sizeof(reply), ms)) < 2) { |
337 | fido_log_debug("%s: fido_rx", __func__); | 335 | fido_log_debug("%s: fido_rx", __func__); |
338 | r = FIDO_ERR_RX; | 336 | r = FIDO_ERR_RX; |
339 | goto fail; | 337 | goto fail; |
@@ -575,10 +573,9 @@ fail: | |||
575 | int | 573 | int |
576 | u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms) | 574 | u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms) |
577 | { | 575 | { |
578 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG; | ||
579 | iso7816_apdu_t *apdu = NULL; | 576 | iso7816_apdu_t *apdu = NULL; |
580 | unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; | 577 | unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; |
581 | unsigned char reply[2048]; | 578 | unsigned char reply[FIDO_MAXMSG]; |
582 | int reply_len; | 579 | int reply_len; |
583 | int found; | 580 | int found; |
584 | int r; | 581 | int r; |
@@ -634,14 +631,14 @@ u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms) | |||
634 | } | 631 | } |
635 | 632 | ||
636 | do { | 633 | do { |
637 | if (fido_tx(dev, cmd, iso7816_ptr(apdu), | 634 | if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), |
638 | iso7816_len(apdu)) < 0) { | 635 | iso7816_len(apdu)) < 0) { |
639 | fido_log_debug("%s: fido_tx", __func__); | 636 | fido_log_debug("%s: fido_tx", __func__); |
640 | r = FIDO_ERR_TX; | 637 | r = FIDO_ERR_TX; |
641 | goto fail; | 638 | goto fail; |
642 | } | 639 | } |
643 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), | 640 | if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, &reply, |
644 | ms)) < 2) { | 641 | sizeof(reply), ms)) < 2) { |
645 | fido_log_debug("%s: fido_rx", __func__); | 642 | fido_log_debug("%s: fido_rx", __func__); |
646 | r = FIDO_ERR_RX; | 643 | r = FIDO_ERR_RX; |
647 | goto fail; | 644 | goto fail; |
@@ -687,6 +684,12 @@ u2f_authenticate_single(fido_dev_t *dev, const fido_blob_t *key_id, | |||
687 | goto fail; | 684 | goto fail; |
688 | } | 685 | } |
689 | 686 | ||
687 | if (fido_blob_set(&fa->stmt[idx].id, key_id->ptr, key_id->len) < 0) { | ||
688 | fido_log_debug("%s: fido_blob_set", __func__); | ||
689 | r = FIDO_ERR_INTERNAL; | ||
690 | goto fail; | ||
691 | } | ||
692 | |||
690 | if (fa->up == FIDO_OPT_FALSE) { | 693 | if (fa->up == FIDO_OPT_FALSE) { |
691 | fido_log_debug("%s: checking for key existence only", __func__); | 694 | fido_log_debug("%s: checking for key existence only", __func__); |
692 | r = FIDO_ERR_USER_PRESENCE_REQUIRED; | 695 | r = FIDO_ERR_USER_PRESENCE_REQUIRED; |
@@ -699,8 +702,7 @@ u2f_authenticate_single(fido_dev_t *dev, const fido_blob_t *key_id, | |||
699 | goto fail; | 702 | goto fail; |
700 | } | 703 | } |
701 | 704 | ||
702 | if (fido_blob_set(&fa->stmt[idx].id, key_id->ptr, key_id->len) < 0 || | 705 | if (fido_assert_set_authdata(fa, idx, ad.ptr, ad.len) != FIDO_OK || |
703 | fido_assert_set_authdata(fa, idx, ad.ptr, ad.len) != FIDO_OK || | ||
704 | fido_assert_set_sig(fa, idx, sig.ptr, sig.len) != FIDO_OK) { | 706 | fido_assert_set_sig(fa, idx, sig.ptr, sig.len) != FIDO_OK) { |
705 | fido_log_debug("%s: fido_assert_set", __func__); | 707 | fido_log_debug("%s: fido_assert_set", __func__); |
706 | r = FIDO_ERR_INTERNAL; | 708 | r = FIDO_ERR_INTERNAL; |
@@ -724,6 +726,7 @@ fail: | |||
724 | int | 726 | int |
725 | u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms) | 727 | u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms) |
726 | { | 728 | { |
729 | int nfound = 0; | ||
727 | int nauth_ok = 0; | 730 | int nauth_ok = 0; |
728 | int r; | 731 | int r; |
729 | 732 | ||
@@ -739,20 +742,30 @@ u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms) | |||
739 | } | 742 | } |
740 | 743 | ||
741 | for (size_t i = 0; i < fa->allow_list.len; i++) { | 744 | for (size_t i = 0; i < fa->allow_list.len; i++) { |
742 | if ((r = u2f_authenticate_single(dev, &fa->allow_list.ptr[i], | 745 | switch ((r = u2f_authenticate_single(dev, |
743 | fa, nauth_ok, ms)) == FIDO_OK) { | 746 | &fa->allow_list.ptr[i], fa, nfound, ms))) { |
747 | case FIDO_OK: | ||
744 | nauth_ok++; | 748 | nauth_ok++; |
745 | } else if (r != FIDO_ERR_CREDENTIAL_EXCLUDED) { | 749 | /* FALLTHROUGH */ |
746 | fido_log_debug("%s: u2f_authenticate_single", __func__); | 750 | case FIDO_ERR_USER_PRESENCE_REQUIRED: |
747 | return (r); | 751 | nfound++; |
752 | break; | ||
753 | default: | ||
754 | if (r != FIDO_ERR_CREDENTIAL_EXCLUDED) { | ||
755 | fido_log_debug("%s: u2f_authenticate_single", | ||
756 | __func__); | ||
757 | return (r); | ||
758 | } | ||
759 | /* ignore credentials that don't exist */ | ||
748 | } | 760 | } |
749 | /* ignore credentials that don't exist */ | ||
750 | } | 761 | } |
751 | 762 | ||
752 | fa->stmt_len = nauth_ok; | 763 | fa->stmt_len = nfound; |
753 | 764 | ||
754 | if (nauth_ok == 0) | 765 | if (nfound == 0) |
755 | return (FIDO_ERR_NO_CREDENTIALS); | 766 | return (FIDO_ERR_NO_CREDENTIALS); |
767 | if (nauth_ok == 0) | ||
768 | return (FIDO_ERR_USER_PRESENCE_REQUIRED); | ||
756 | 769 | ||
757 | return (FIDO_OK); | 770 | return (FIDO_OK); |
758 | } | 771 | } |