summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt12
-rw-r--r--src/assert.c31
-rw-r--r--src/authkey.c10
-rw-r--r--src/bio.c32
-rw-r--r--src/blob.h11
-rw-r--r--src/cbor.c108
-rw-r--r--src/cred.c122
-rw-r--r--src/credman.c34
-rw-r--r--src/dev.c223
-rw-r--r--src/eddsa.c8
-rw-r--r--src/err.c24
-rw-r--r--src/es256.c54
-rw-r--r--src/export.gnu5
-rw-r--r--src/export.llvm5
-rw-r--r--src/export.msvc5
-rw-r--r--src/extern.h32
-rw-r--r--src/fido.h53
-rw-r--r--src/fido/bio.h16
-rw-r--r--src/fido/credman.h16
-rw-r--r--src/fido/eddsa.h14
-rw-r--r--src/fido/err.h8
-rw-r--r--src/fido/es256.h14
-rw-r--r--src/fido/param.h11
-rw-r--r--src/fido/rs256.h14
-rw-r--r--src/fido/types.h (renamed from src/types.h)96
-rw-r--r--src/hid_hidapi.c138
-rw-r--r--src/hid_linux.c14
-rw-r--r--src/hid_openbsd.c8
-rw-r--r--src/hid_osx.c17
-rw-r--r--src/hid_win.c8
-rw-r--r--src/info.c21
-rw-r--r--src/io.c202
-rw-r--r--src/iso7816.h11
-rw-r--r--src/log.c73
-rw-r--r--src/pin.c126
-rw-r--r--src/reset.c5
-rw-r--r--src/u2f.c69
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
33if(FUZZ) 33if(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)
36endif() 37endif()
37 38
38if(WIN32) 39if(USE_HIDAPI)
40 list(APPEND COMPAT_SOURCES hid_hidapi.c)
41elseif(WIN32)
39 list(APPEND COMPAT_SOURCES hid_win.c) 42 list(APPEND COMPAT_SOURCES hid_win.c)
40elseif(APPLE) 43elseif(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)
44elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") 47elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
45 list(APPEND COMPAT_SOURCES hid_openbsd.c) 48 list(APPEND COMPAT_SOURCES hid_openbsd.c)
49else()
50 message(FATAL_ERROR "please define a hid backend for your platform")
46endif() 51endif()
47 52
48list(APPEND COMPAT_SOURCES 53list(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
57add_library(fido2 STATIC ${FIDO_SOURCES} ${COMPAT_SOURCES}) 63add_library(fido2 STATIC ${FIDO_SOURCES} ${COMPAT_SOURCES})
58target_link_libraries(fido2 ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES} 64target_link_libraries(fido2 ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES}
59 ${UDEV_LIBRARIES} ${BASE_LIBRARIES}) 65 ${UDEV_LIBRARIES} ${BASE_LIBRARIES} ${HIDAPI_LIBRARIES})
60if(WIN32) 66if(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
75add_library(fido2_shared SHARED ${FIDO_SOURCES} ${COMPAT_SOURCES}) 81add_library(fido2_shared SHARED ${FIDO_SOURCES} ${COMPAT_SOURCES})
76target_link_libraries(fido2_shared ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES} 82target_link_libraries(fido2_shared ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES}
77 ${UDEV_LIBRARIES} ${BASE_LIBRARIES}) 83 ${UDEV_LIBRARIES} ${BASE_LIBRARIES} ${HIDAPI_LIBRARIES})
78if(WIN32) 84if(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:
170static int 170static int
171fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) 171fido_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)
211static int 211static int
212fido_get_next_assert_tx(fido_dev_t *dev) 212fido_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)
225static int 224static int
226fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) 225fido_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
366static int 365int
367get_signed_hash(int cose_alg, fido_blob_t *dgst, const fido_blob_t *clientdata, 366fido_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
534fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg, 533fido_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:
61static int 61static int
62fido_dev_authkey_rx(fido_dev_t *dev, es256_pk_t *authkey, int ms) 62fido_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 }
diff --git a/src/bio.c b/src/bio.c
index 74814b9..c1032d8 100644
--- a/src/bio.c
+++ b/src/bio.c
@@ -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,
235static int 235static int
236bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int ms) 236bio_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
382bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t, 382bio_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:
482static int 482static int
483bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int ms) 483bio_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)
643static int 643static int
644bio_rx_info(fido_dev_t *dev, fido_bio_info_t *i, int ms) 644bio_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 }
diff --git a/src/blob.h b/src/blob.h
index 24fdc23..9e98d03 100644
--- a/src/blob.h
+++ b/src/blob.h
@@ -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
14extern "C" {
15#endif /* __cplusplus */
16
10typedef struct fido_blob { 17typedef 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);
25void fido_blob_free(fido_blob_t **); 32void fido_blob_free(fido_blob_t **);
26void fido_free_blob_array(fido_blob_array_t *); 33void 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 */
diff --git a/src/cbor.c b/src/cbor.c
index 3e03592..3928325 100644
--- a/src/cbor.c
+++ b/src/cbor.c
@@ -314,6 +314,35 @@ fail:
314} 314}
315 315
316static int 316static int
317cbor_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;
336fail:
337 if (pair.key)
338 cbor_decref(&pair.key);
339 if (pair.value)
340 cbor_decref(&pair.value);
341
342 return (ok);
343}
344
345static int
317cbor_add_arg(cbor_item_t *item, uint8_t n, cbor_item_t *arg) 346cbor_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
537cbor_item_t * 566cbor_item_t *
538cbor_encode_extensions(int ext) 567cbor_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:
1082static int 1121static int
1083decode_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg) 1122decode_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;
1106out: 1154out:
1107 free(type); 1155 free(type);
@@ -1110,7 +1158,8 @@ out:
1110} 1158}
1111 1159
1112static int 1160static int
1113decode_extensions(const unsigned char **buf, size_t *len, int *authdata_ext) 1161decode_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:
1204int 1253int
1205cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg, 1254cbor_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) {
diff --git a/src/cred.c b/src/cred.c
index c4e1edb..4ecbba8 100644
--- a/src/cred.c
+++ b/src/cred.c
@@ -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:
126static int 126static int
127fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int ms) 127fido_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
170fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin) 170fido_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
181static int 182static int
182check_extensions(int authdata_ext, int ext) 183check_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
193int 188int
@@ -208,48 +203,6 @@ fido_check_rp_id(const char *id, const unsigned char *obtained_hash)
208} 203}
209 204
210static int 205static int
211get_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;
245fail:
246 if (item != NULL)
247 cbor_decref(&item);
248
249 return (ok);
250}
251
252static int
253get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id, 206get_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:
395int 348int
396fido_cred_verify_self(const fido_cred_t *cred) 349fido_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:
810int 763int
811fido_cred_set_extensions(fido_cred_t *cred, int ext) 764fido_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
846int 803int
804fido_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
822int
847fido_cred_set_fmt(fido_cred_t *cred, const char *fmt) 823fido_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
970int
971fido_cred_prot(const fido_cred_t *cred)
972{
973 return (cred->ext.prot);
974}
975
994const char * 976const char *
995fido_cred_fmt(const fido_cred_t *cred) 977fido_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,
181static int 181static int
182credman_rx_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, int ms) 182credman_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,
300static int 300static int
301credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms) 301credman_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)
339static int 339static int
340credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms) 340credman_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,
514static int 514static int
515credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms) 515credman_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)
553static int 553static int
554credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms) 554credman_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 }
diff --git a/src/dev.c b/src/dev.c
index d0efac7..51b9935 100644
--- a/src/dev.c
+++ b/src/dev.c
@@ -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)
46static int
47obtain_nonce(uint64_t *nonce)
48{
49 arc4random_buf(nonce, sizeof(*nonce));
50 return (0);
51}
52#elif defined(HAVE_GETRANDOM)
53static int
54obtain_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)
43static int 61static int
44obtain_nonce(uint64_t *nonce) 62obtain_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
89typedef 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
94static TLS dev_manifest_func_node_t *manifest_funcs = NULL;
95
96static void
97find_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
67static int 109static int
68fido_dev_open_tx(fido_dev_t *dev, const char *path) 110fido_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)
102static int 144static int
103fido_dev_open_rx(fido_dev_t *dev, int ms) 145fido_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;
125fail: 189fail:
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
132static int 200static int
@@ -142,6 +210,79 @@ fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms)
142} 210}
143 211
144int 212int
213fido_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
233void
234fido_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
249int
250fido_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
276int
277fido_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
285int
145fido_dev_open(fido_dev_t *dev, const char *path) 286fido_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)
162int 303int
163fido_dev_cancel(fido_dev_t *dev) 304fido_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
172fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) 313fido_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
331int
332fido_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)
200fido_dev_t * 351fido_dev_t *
201fido_dev_new(void) 352fido_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
370fido_dev_t *
371fido_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,
55EVP_MD_CTX * 61EVP_MD_CTX *
56EVP_MD_CTX_new(void) 62EVP_MD_CTX_new(void)
57{ 63{
64 fido_log_debug("%s: unimplemented", __func__);
65
58 return (NULL); 66 return (NULL);
59} 67}
60 68
diff --git a/src/err.c b/src/err.c
index 5d3efd4..6261bfc 100644
--- a/src/err.c
+++ b/src/err.c
@@ -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)
176int 176int
177es256_pk_from_ptr(es256_pk_t *pk, const void *ptr, size_t len) 177es256_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;
298fail: 307fail:
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:
313int 326int
314es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec) 327es256_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;
348fail: 363fail:
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;
386fail: 408fail:
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
75fido_cbor_info_extensions_ptr 75fido_cbor_info_extensions_ptr
76fido_cbor_info_free 76fido_cbor_info_free
77fido_cbor_info_maxmsgsiz 77fido_cbor_info_maxmsgsiz
78fido_cbor_info_fwversion
78fido_cbor_info_new 79fido_cbor_info_new
79fido_cbor_info_options_len 80fido_cbor_info_options_len
80fido_cbor_info_options_name_ptr 81fido_cbor_info_options_name_ptr
@@ -114,6 +115,7 @@ fido_credman_rp_id_hash_ptr
114fido_credman_rp_name 115fido_credman_rp_name
115fido_credman_rp_new 116fido_credman_rp_new
116fido_cred_new 117fido_cred_new
118fido_cred_prot
117fido_cred_pubkey_len 119fido_cred_pubkey_len
118fido_cred_pubkey_ptr 120fido_cred_pubkey_ptr
119fido_cred_rp_id 121fido_cred_rp_id
@@ -124,6 +126,7 @@ fido_cred_set_clientdata_hash
124fido_cred_set_extensions 126fido_cred_set_extensions
125fido_cred_set_fmt 127fido_cred_set_fmt
126fido_cred_set_options 128fido_cred_set_options
129fido_cred_set_prot
127fido_cred_set_rk 130fido_cred_set_rk
128fido_cred_set_rp 131fido_cred_set_rp
129fido_cred_set_sig 132fido_cred_set_sig
@@ -170,7 +173,9 @@ fido_dev_protocol
170fido_dev_reset 173fido_dev_reset
171fido_dev_set_io_functions 174fido_dev_set_io_functions
172fido_dev_set_pin 175fido_dev_set_pin
176fido_dev_set_transport_functions
173fido_init 177fido_init
178fido_set_log_handler
174fido_strerr 179fido_strerr
175rs256_pk_free 180rs256_pk_free
176rs256_pk_from_ptr 181rs256_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
16extern "C" {
17#endif /* __cplusplus */
18
10/* aes256 */ 19/* aes256 */
11int aes256_cbc_dec(const fido_blob_t *, const fido_blob_t *, fido_blob_t *); 20int aes256_cbc_dec(const fido_blob_t *, const fido_blob_t *, fido_blob_t *);
12int aes256_cbc_enc(const fido_blob_t *, const fido_blob_t *, fido_blob_t *); 21int 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);
16cbor_item_t *cbor_encode_assert_options(fido_opt_t, fido_opt_t); 25cbor_item_t *cbor_encode_assert_options(fido_opt_t, fido_opt_t);
17cbor_item_t *cbor_encode_change_pin_auth(const fido_blob_t *, 26cbor_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 *);
19cbor_item_t *cbor_encode_extensions(int); 28cbor_item_t *cbor_encode_extensions(const fido_cred_ext_t *);
20cbor_item_t *cbor_encode_hmac_secret_param(const fido_blob_t *, 29cbor_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 *);
22cbor_item_t *cbor_encode_options(fido_opt_t, fido_opt_t); 31cbor_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 */
36int cbor_decode_attstmt(const cbor_item_t *, fido_attstmt_t *); 45int cbor_decode_attstmt(const cbor_item_t *, fido_attstmt_t *);
37int cbor_decode_cred_authdata(const cbor_item_t *, int, fido_blob_t *, 46int 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 *);
39int cbor_decode_assert_authdata(const cbor_item_t *, fido_blob_t *, 48int 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 *);
41int cbor_decode_cred_id(const cbor_item_t *, fido_blob_t *); 50int 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 */
78void *fido_hid_open(const char *); 87void *fido_hid_open(const char *);
79void fido_hid_close(void *); 88void fido_hid_close(void *);
80int fido_hid_read(void *, unsigned char *, size_t, int); 89int fido_hid_read(void *, unsigned char *, size_t, int);
81int fido_hid_write(void *, const unsigned char *, size_t); 90int fido_hid_write(void *, const unsigned char *, size_t);
82 91
83/* generic i/o */ 92/* generic i/o */
84int fido_rx_cbor_status(fido_dev_t *, int); 93int 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 */
111int fido_dev_authkey(fido_dev_t *, es256_pk_t *); 120int fido_dev_authkey(fido_dev_t *, es256_pk_t *);
121int fido_dev_get_cbor_info_wait(fido_dev_t *, fido_cbor_info_t *, int);
112int fido_dev_get_pin_token(fido_dev_t *, const char *, const fido_blob_t *, 122int 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 *);
114int fido_do_ecdh(fido_dev_t *, es256_pk_t **, fido_blob_t **); 124int 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 *);
129int fido_verify_sig_eddsa(const fido_blob_t *, const eddsa_pk_t *, 139int fido_verify_sig_eddsa(const fido_blob_t *, const eddsa_pk_t *,
130 const fido_blob_t *); 140 const fido_blob_t *);
141int fido_get_signed_hash(int, fido_blob_t *, const fido_blob_t *,
142 const fido_blob_t *);
143
144/* hid device manifest */
145int fido_hid_manifest(fido_dev_info_t *, size_t, size_t *);
146
147/* device manifest registration */
148typedef int (*dev_manifest_func_t)(fido_dev_info_t *, size_t, size_t *);
149int fido_dev_register_manifest_func(const dev_manifest_func_t);
150void 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 */
diff --git a/src/fido.h b/src/fido.h
index f85a41a..e41de89 100644
--- a/src/fido.h
+++ b/src/fido.h
@@ -14,24 +14,6 @@
14#include <stdint.h> 14#include <stdint.h>
15#include <stdlib.h> 15#include <stdlib.h>
16 16
17typedef void *fido_dev_io_open_t(const char *);
18typedef void fido_dev_io_close_t(void *);
19typedef int fido_dev_io_read_t(void *, unsigned char *, size_t, int);
20typedef int fido_dev_io_write_t(void *, const unsigned char *, size_t);
21
22typedef 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
29typedef 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
50typedef struct fido_assert fido_assert_t; 32extern "C" {
51typedef struct fido_cbor_info fido_cbor_info_t; 33#endif /* __cplusplus */
52typedef struct fido_cred fido_cred_t;
53typedef struct fido_dev fido_dev_t;
54typedef struct fido_dev_info fido_dev_info_t;
55typedef struct es256_pk es256_pk_t;
56typedef struct es256_sk es256_sk_t;
57typedef struct rs256_pk rs256_pk_t;
58typedef struct eddsa_pk eddsa_pk_t;
59#endif
60 34
61fido_assert_t *fido_assert_new(void); 35fido_assert_t *fido_assert_new(void);
62fido_cred_t *fido_cred_new(void); 36fido_cred_t *fido_cred_new(void);
63fido_dev_t *fido_dev_new(void); 37fido_dev_t *fido_dev_new(void);
38fido_dev_t *fido_dev_new_with_info(const fido_dev_info_t *);
64fido_dev_info_t *fido_dev_info_new(size_t); 39fido_dev_info_t *fido_dev_info_new(size_t);
65fido_cbor_info_t *fido_cbor_info_new(void); 40fido_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
78void fido_init(int); 53void fido_init(int);
54void fido_set_log_handler(fido_log_handler_t *);
79 55
80const unsigned char *fido_assert_authdata_ptr(const fido_assert_t *, size_t); 56const unsigned char *fido_assert_authdata_ptr(const fido_assert_t *, size_t);
81const unsigned char *fido_assert_clientdata_hash_ptr(const fido_assert_t *); 57const 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 *,
121int fido_assert_set_count(fido_assert_t *, size_t); 97int fido_assert_set_count(fido_assert_t *, size_t);
122int fido_assert_set_extensions(fido_assert_t *, int); 98int fido_assert_set_extensions(fido_assert_t *, int);
123int fido_assert_set_hmac_salt(fido_assert_t *, const unsigned char *, size_t); 99int fido_assert_set_hmac_salt(fido_assert_t *, const unsigned char *, size_t);
124int fido_assert_set_options(fido_assert_t *, bool, bool) __attribute__((__deprecated__)); 100int fido_assert_set_options(fido_assert_t *, bool, bool)
101 __attribute__((__deprecated__("use fido_assert_set_up/fido_assert_set_uv")));
125int fido_assert_set_rp(fido_assert_t *, const char *); 102int fido_assert_set_rp(fido_assert_t *, const char *);
126int fido_assert_set_up(fido_assert_t *, fido_opt_t); 103int fido_assert_set_up(fido_assert_t *, fido_opt_t);
127int fido_assert_set_uv(fido_assert_t *, fido_opt_t); 104int fido_assert_set_uv(fido_assert_t *, fido_opt_t);
128int fido_assert_set_sig(fido_assert_t *, size_t, const unsigned char *, size_t); 105int fido_assert_set_sig(fido_assert_t *, size_t, const unsigned char *, size_t);
129int fido_assert_verify(const fido_assert_t *, size_t, int, const void *); 106int fido_assert_verify(const fido_assert_t *, size_t, int, const void *);
130int fido_cred_exclude(fido_cred_t *, const unsigned char *, size_t); 107int fido_cred_exclude(fido_cred_t *, const unsigned char *, size_t);
108int fido_cred_prot(const fido_cred_t *);
131int fido_cred_set_authdata(fido_cred_t *, const unsigned char *, size_t); 109int fido_cred_set_authdata(fido_cred_t *, const unsigned char *, size_t);
132int fido_cred_set_authdata_raw(fido_cred_t *, const unsigned char *, size_t); 110int fido_cred_set_authdata_raw(fido_cred_t *, const unsigned char *, size_t);
133int fido_cred_set_clientdata_hash(fido_cred_t *, const unsigned char *, size_t); 111int fido_cred_set_clientdata_hash(fido_cred_t *, const unsigned char *, size_t);
134int fido_cred_set_extensions(fido_cred_t *, int); 112int fido_cred_set_extensions(fido_cred_t *, int);
135int fido_cred_set_fmt(fido_cred_t *, const char *); 113int fido_cred_set_fmt(fido_cred_t *, const char *);
136int fido_cred_set_options(fido_cred_t *, bool, bool) __attribute__((__deprecated__)); 114int fido_cred_set_options(fido_cred_t *, bool, bool)
115 __attribute__((__deprecated__("use fido_cred_set_rk/fido_cred_set_uv")));
116int fido_cred_set_prot(fido_cred_t *, int);
137int fido_cred_set_rk(fido_cred_t *, fido_opt_t); 117int fido_cred_set_rk(fido_cred_t *, fido_opt_t);
138int fido_cred_set_rp(fido_cred_t *, const char *, const char *); 118int fido_cred_set_rp(fido_cred_t *, const char *, const char *);
139int fido_cred_set_sig(fido_cred_t *, const unsigned char *, size_t); 119int 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 *);
152int fido_dev_get_retry_count(fido_dev_t *, int *); 132int fido_dev_get_retry_count(fido_dev_t *, int *);
153int fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *); 133int fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *);
154int fido_dev_make_cred(fido_dev_t *, fido_cred_t *, const char *); 134int fido_dev_make_cred(fido_dev_t *, fido_cred_t *, const char *);
135int fido_dev_open_with_info(fido_dev_t *);
155int fido_dev_open(fido_dev_t *, const char *); 136int fido_dev_open(fido_dev_t *, const char *);
156int fido_dev_reset(fido_dev_t *); 137int fido_dev_reset(fido_dev_t *);
157int fido_dev_set_io_functions(fido_dev_t *, const fido_dev_io_t *); 138int fido_dev_set_io_functions(fido_dev_t *, const fido_dev_io_t *);
158int fido_dev_set_pin(fido_dev_t *, const char *, const char *); 139int fido_dev_set_pin(fido_dev_t *, const char *, const char *);
140int fido_dev_set_transport_functions(fido_dev_t *, const fido_dev_transport_t *);
159 141
160size_t fido_assert_authdata_len(const fido_assert_t *, size_t); 142size_t fido_assert_authdata_len(const fido_assert_t *, size_t);
161size_t fido_assert_clientdata_hash_len(const fido_assert_t *); 143size_t fido_assert_clientdata_hash_len(const fido_assert_t *);
@@ -178,7 +160,7 @@ size_t fido_cred_sig_len(const fido_cred_t *);
178size_t fido_cred_x5c_len(const fido_cred_t *); 160size_t fido_cred_x5c_len(const fido_cred_t *);
179 161
180uint8_t fido_assert_flags(const fido_assert_t *, size_t); 162uint8_t fido_assert_flags(const fido_assert_t *, size_t);
181uint32_t fido_assert_sigcount(const fido_assert_t *, size_t); 163uint32_t fido_assert_sigcount(const fido_assert_t *, size_t);
182uint8_t fido_cred_flags(const fido_cred_t *); 164uint8_t fido_cred_flags(const fido_cred_t *);
183uint8_t fido_dev_protocol(const fido_dev_t *); 165uint8_t fido_dev_protocol(const fido_dev_t *);
184uint8_t fido_dev_major(const fido_dev_t *); 166uint8_t fido_dev_major(const fido_dev_t *);
@@ -188,7 +170,12 @@ uint8_t fido_dev_flags(const fido_dev_t *);
188int16_t fido_dev_info_vendor(const fido_dev_info_t *); 170int16_t fido_dev_info_vendor(const fido_dev_info_t *);
189int16_t fido_dev_info_product(const fido_dev_info_t *); 171int16_t fido_dev_info_product(const fido_dev_info_t *);
190uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *); 172uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *);
173uint64_t fido_cbor_info_fwversion(const fido_cbor_info_t *);
191 174
192bool fido_dev_is_fido2(const fido_dev_t *); 175bool 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
25extern "C" {
26#endif /* __cplusplus */
15 27
16#ifdef _FIDO_INTERNAL 28#ifdef _FIDO_INTERNAL
17struct fido_bio_template { 29struct fido_bio_template {
@@ -92,4 +104,8 @@ void fido_bio_info_free(fido_bio_info_t **);
92void fido_bio_template_array_free(fido_bio_template_array_t **); 104void fido_bio_template_array_free(fido_bio_template_array_t **);
93void fido_bio_template_free(fido_bio_template_t **); 105void 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
25extern "C" {
26#endif /* __cplusplus */
15 27
16#ifdef _FIDO_INTERNAL 28#ifdef _FIDO_INTERNAL
17struct fido_credman_metadata { 29struct fido_credman_metadata {
@@ -71,4 +83,8 @@ void fido_credman_metadata_free(fido_credman_metadata_t **);
71void fido_credman_rk_free(fido_credman_rk_t **); 83void fido_credman_rk_free(fido_credman_rk_t **);
72void fido_credman_rp_free(fido_credman_rp_t **); 84void 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
22extern "C" {
23#endif /* __cplusplus */
24
15eddsa_pk_t *eddsa_pk_new(void); 25eddsa_pk_t *eddsa_pk_new(void);
16void eddsa_pk_free(eddsa_pk_t **); 26void eddsa_pk_free(eddsa_pk_t **);
17EVP_PKEY *eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *); 27EVP_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
68extern "C" {
69#endif /* __cplusplus */
70
67const char *fido_strerr(int); 71const 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
22extern "C" {
23#endif /* __cplusplus */
24
15es256_pk_t *es256_pk_new(void); 25es256_pk_t *es256_pk_new(void);
16void es256_pk_free(es256_pk_t **); 26void es256_pk_free(es256_pk_t **);
17EVP_PKEY *es256_pk_to_EVP_PKEY(const es256_pk_t *); 27EVP_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 *);
31int es256_pk_set_y(es256_pk_t *, const unsigned char *); 41int 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
22extern "C" {
23#endif /* __cplusplus */
24
15rs256_pk_t *rs256_pk_new(void); 25rs256_pk_t *rs256_pk_new(void);
16void rs256_pk_free(rs256_pk_t **); 26void rs256_pk_free(rs256_pk_t **);
17EVP_PKEY *rs256_pk_to_EVP_PKEY(const rs256_pk_t *); 27EVP_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 *);
19int rs256_pk_from_RSA(rs256_pk_t *, const RSA *); 29int rs256_pk_from_RSA(rs256_pk_t *, const RSA *);
20int rs256_pk_from_ptr(rs256_pk_t *, const void *, size_t); 30int 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
14extern "C" {
15#endif /* __cplusplus */
16
17struct fido_dev;
18
19typedef void *fido_dev_io_open_t(const char *);
20typedef void fido_dev_io_close_t(void *);
21typedef int fido_dev_io_read_t(void *, unsigned char *, size_t, int);
22typedef int fido_dev_io_write_t(void *, const unsigned char *, size_t);
23typedef int fido_dev_rx_t(struct fido_dev *, uint8_t, unsigned char *, size_t, int);
24typedef int fido_dev_tx_t(struct fido_dev *, uint8_t, const unsigned char *, size_t);
25
26typedef 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
33typedef struct fido_dev_transport {
34 fido_dev_rx_t *rx;
35 fido_dev_tx_t *tx;
36} fido_dev_transport_t;
37
38typedef 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
44typedef 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 */
13typedef struct es256_pk { 51typedef 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
115typedef struct fido_cred_ext {
116 int mask; /* enabled extensions */
117 int prot; /* protection policy */
118} fido_cred_ext_t;
119
77typedef struct fido_cred { 120typedef 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
143typedef struct fido_dev_info { 187typedef 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
151PACKED_TYPE(fido_ctap_info_t, 197PACKED_TYPE(fido_ctap_info_t,
@@ -161,11 +207,29 @@ struct fido_ctap_info {
161}) 207})
162 208
163typedef struct fido_dev { 209typedef 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
220typedef struct fido_assert fido_assert_t;
221typedef struct fido_cbor_info fido_cbor_info_t;
222typedef struct fido_cred fido_cred_t;
223typedef struct fido_dev fido_dev_t;
224typedef struct fido_dev_info fido_dev_info_t;
225typedef struct es256_pk es256_pk_t;
226typedef struct es256_sk es256_sk_t;
227typedef struct rs256_pk rs256_pk_t;
228typedef 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
15static size_t
16fido_wcslen(const wchar_t *wcs)
17{
18 size_t l = 0;
19 while (*wcs++ != L'\0')
20 l++;
21 return l;
22}
23
24static char *
25wcs_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
45static int
46copy_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
86void *
87fido_hid_open(const char *path)
88{
89 return hid_open_path(path);
90}
91
92void
93fido_hid_close(void *hid_dev_handle)
94{
95 hid_close(hid_dev_handle);
96}
97
98int
99fido_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
104int
105fido_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
110int
111fido_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,
98static int 99static int
99get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd) 100get_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
242int 242int
243fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) 243fido_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
31int 31int
32fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) 32fido_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
199int 199int
200fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) 200fido_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
174int 174int
175fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) 175fido_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 }
diff --git a/src/info.c b/src/info.c
index e896503..8e256fa 100644
--- a/src/info.c
+++ b/src/info.c
@@ -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)
226static int 228static int
227fido_dev_get_cbor_info_tx(fido_dev_t *dev) 229fido_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)
242static int 243static int
243fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) 244fido_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
263static int 264int
264fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) 265fido_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
401uint64_t
402fido_cbor_info_fwversion(const fido_cbor_info_t *ci)
403{
404 return (ci->fwversion);
405}
406
400const uint8_t * 407const uint8_t *
401fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci) 408fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci)
402{ 409{
diff --git a/src/io.c b/src/io.c
index aa88720..af2f49a 100644
--- a/src/io.c
+++ b/src/io.c
@@ -33,25 +33,40 @@ struct frame {
33#define MIN(x, y) ((x) > (y) ? (y) : (x)) 33#define MIN(x, y) ((x) > (y) ? (y) : (x))
34#endif 34#endif
35 35
36static size_t 36static int
37tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) 37tx_empty(fido_dev_t *d, uint8_t cmd)
38{ 38{
39 struct frame *fp; 39 struct frame *fp;
40 unsigned char pkt[sizeof(*fp) + 1]; 40 unsigned char pkt[sizeof(*fp) + 1];
41 int n; 41 int n;
42 42
43 if (d->io.write == NULL || (cmd & 0x80) == 0) 43 memset(&pkt, 0, sizeof(pkt));
44 return (0); 44 fp = (struct frame *)(pkt + 1);
45 fp->cid = d->cid;
46 fp->body.init.cmd = CTAP_FRAME_INIT | cmd;
47
48 n = d->io.write(d->io_handle, pkt, sizeof(pkt));
49 if (n < 0 || (size_t)n != sizeof(pkt))
50 return (-1);
51
52 return (0);
53}
54
55static size_t
56tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
57{
58 struct frame *fp;
59 unsigned char pkt[sizeof(*fp) + 1];
60 int n;
45 61
46 memset(&pkt, 0, sizeof(pkt)); 62 memset(&pkt, 0, sizeof(pkt));
47 fp = (struct frame *)(pkt + 1); 63 fp = (struct frame *)(pkt + 1);
48 fp->cid = d->cid; 64 fp->cid = d->cid;
49 fp->body.init.cmd = 0x80 | cmd; 65 fp->body.init.cmd = CTAP_FRAME_INIT | cmd;
50 fp->body.init.bcnth = (count >> 8) & 0xff; 66 fp->body.init.bcnth = (count >> 8) & 0xff;
51 fp->body.init.bcntl = count & 0xff; 67 fp->body.init.bcntl = count & 0xff;
52 count = MIN(count, sizeof(fp->body.init.data)); 68 count = MIN(count, sizeof(fp->body.init.data));
53 if (count) 69 memcpy(&fp->body.init.data, buf, count);
54 memcpy(&fp->body.init.data, buf, count);
55 70
56 n = d->io.write(d->io_handle, pkt, sizeof(pkt)); 71 n = d->io.write(d->io_handle, pkt, sizeof(pkt));
57 if (n < 0 || (size_t)n != sizeof(pkt)) 72 if (n < 0 || (size_t)n != sizeof(pkt))
@@ -61,19 +76,16 @@ tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
61} 76}
62 77
63static size_t 78static size_t
64tx_frame(fido_dev_t *d, int seq, const void *buf, size_t count) 79tx_frame(fido_dev_t *d, uint8_t seq, const void *buf, size_t count)
65{ 80{
66 struct frame *fp; 81 struct frame *fp;
67 unsigned char pkt[sizeof(*fp) + 1]; 82 unsigned char pkt[sizeof(*fp) + 1];
68 int n; 83 int n;
69 84
70 if (d->io.write == NULL || seq < 0 || seq > UINT8_MAX)
71 return (0);
72
73 memset(&pkt, 0, sizeof(pkt)); 85 memset(&pkt, 0, sizeof(pkt));
74 fp = (struct frame *)(pkt + 1); 86 fp = (struct frame *)(pkt + 1);
75 fp->cid = d->cid; 87 fp->cid = d->cid;
76 fp->body.cont.seq = (uint8_t)seq; 88 fp->body.cont.seq = seq;
77 count = MIN(count, sizeof(fp->body.cont.data)); 89 count = MIN(count, sizeof(fp->body.cont.data));
78 memcpy(&fp->body.cont.data, buf, count); 90 memcpy(&fp->body.cont.data, buf, count);
79 91
@@ -84,52 +96,56 @@ tx_frame(fido_dev_t *d, int seq, const void *buf, size_t count)
84 return (count); 96 return (count);
85} 97}
86 98
87int 99static int
88fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) 100tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count)
89{ 101{
90 int seq = 0; 102 size_t n, sent;
91 size_t sent;
92
93 fido_log_debug("%s: d=%p, cmd=0x%02x, buf=%p, count=%zu", __func__,
94 (void *)d, cmd, buf, count);
95 fido_log_xxd(buf, count);
96
97 if (d->io_handle == NULL || count > UINT16_MAX) {
98 fido_log_debug("%s: invalid argument (%p, %zu)", __func__,
99 d->io_handle, count);
100 return (-1);
101 }
102 103
103 if ((sent = tx_preamble(d, cmd, buf, count)) == 0) { 104 if ((sent = tx_preamble(d, cmd, buf, count)) == 0) {
104 fido_log_debug("%s: tx_preamble", __func__); 105 fido_log_debug("%s: tx_preamble", __func__);
105 return (-1); 106 return (-1);
106 } 107 }
107 108
108 while (sent < count) { 109 for (uint8_t seq = 0; sent < count; sent += n) {
109 if (seq & 0x80) { 110 if (seq & 0x80) {
110 fido_log_debug("%s: seq & 0x80", __func__); 111 fido_log_debug("%s: seq & 0x80", __func__);
111 return (-1); 112 return (-1);
112 } 113 }
113 const uint8_t *p = (const uint8_t *)buf + sent; 114 if ((n = tx_frame(d, seq++, buf + sent, count - sent)) == 0) {
114 size_t n = tx_frame(d, seq++, p, count - sent);
115 if (n == 0) {
116 fido_log_debug("%s: tx_frame", __func__); 115 fido_log_debug("%s: tx_frame", __func__);
117 return (-1); 116 return (-1);
118 } 117 }
119 sent += n;
120 } 118 }
121 119
122 return (0); 120 return (0);
123} 121}
124 122
123int
124fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
125{
126 fido_log_debug("%s: d=%p, cmd=0x%02x, buf=%p, count=%zu", __func__,
127 (void *)d, cmd, (const void *)buf, count);
128 fido_log_xxd(buf, count);
129
130 if (d->transport.tx != NULL)
131 return (d->transport.tx(d, cmd, buf, count));
132
133 if (d->io_handle == NULL || d->io.write == NULL || count > UINT16_MAX) {
134 fido_log_debug("%s: invalid argument", __func__);
135 return (-1);
136 }
137
138 if (count == 0)
139 return (tx_empty(d, cmd));
140
141 return (tx(d, cmd, buf, count));
142}
143
125static int 144static int
126rx_frame(fido_dev_t *d, struct frame *fp, int ms) 145rx_frame(fido_dev_t *d, struct frame *fp, int ms)
127{ 146{
128 int n; 147 int n;
129 148
130 if (d->io.read == NULL)
131 return (-1);
132
133 n = d->io.read(d->io_handle, (unsigned char *)fp, sizeof(*fp), ms); 149 n = d->io.read(d->io_handle, (unsigned char *)fp, sizeof(*fp), ms);
134 if (n < 0 || (size_t)n != sizeof(*fp)) 150 if (n < 0 || (size_t)n != sizeof(*fp))
135 return (-1); 151 return (-1);
@@ -138,7 +154,7 @@ rx_frame(fido_dev_t *d, struct frame *fp, int ms)
138} 154}
139 155
140static int 156static int
141rx_preamble(fido_dev_t *d, struct frame *fp, int ms) 157rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int ms)
142{ 158{
143 do { 159 do {
144 if (rx_frame(d, fp, ms) < 0) 160 if (rx_frame(d, fp, ms) < 0)
@@ -149,66 +165,57 @@ rx_preamble(fido_dev_t *d, struct frame *fp, int ms)
149 } while (fp->cid == d->cid && 165 } while (fp->cid == d->cid &&
150 fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE)); 166 fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE));
151 167
168 fido_log_debug("%s: initiation frame at %p", __func__, (void *)fp);
169 fido_log_xxd(fp, sizeof(*fp));
170
171#ifdef FIDO_FUZZ
172 fp->body.init.cmd = (CTAP_FRAME_INIT | cmd);
173#endif
174
175 if (fp->cid != d->cid || fp->body.init.cmd != (CTAP_FRAME_INIT | cmd)) {
176 fido_log_debug("%s: cid (0x%x, 0x%x), cmd (0x%02x, 0x%02x)",
177 __func__, fp->cid, d->cid, fp->body.init.cmd, cmd);
178 return (-1);
179 }
180
152 return (0); 181 return (0);
153} 182}
154 183
155int 184static int
156fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms) 185rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
157{ 186{
158 struct frame f; 187 struct frame f;
159 uint16_t r; 188 uint16_t r, payload_len;
160 uint16_t flen;
161 int seq;
162
163 if (d->io_handle == NULL || (cmd & 0x80) == 0) {
164 fido_log_debug("%s: invalid argument (%p, 0x%02x)", __func__,
165 d->io_handle, cmd);
166 return (-1);
167 }
168 189
169 if (rx_preamble(d, &f, ms) < 0) { 190 if (rx_preamble(d, cmd, &f, ms) < 0) {
170 fido_log_debug("%s: rx_preamble", __func__); 191 fido_log_debug("%s: rx_preamble", __func__);
171 return (-1); 192 return (-1);
172 } 193 }
173 194
174 fido_log_debug("%s: initiation frame at %p, len %zu", __func__, 195 payload_len = (f.body.init.bcnth << 8) | f.body.init.bcntl;
175 (void *)&f, sizeof(f)); 196 fido_log_debug("%s: payload_len=%zu", __func__, (size_t)payload_len);
176 fido_log_xxd(&f, sizeof(f));
177 197
178#ifdef FIDO_FUZZ 198 if (count < (size_t)payload_len) {
179 f.cid = d->cid; 199 fido_log_debug("%s: count < payload_len", __func__);
180 f.body.init.cmd = cmd;
181#endif
182
183 if (f.cid != d->cid || f.body.init.cmd != cmd) {
184 fido_log_debug("%s: cid (0x%x, 0x%x), cmd (0x%02x, 0x%02x)",
185 __func__, f.cid, d->cid, f.body.init.cmd, cmd);
186 return (-1); 200 return (-1);
187 } 201 }
188 202
189 flen = (f.body.init.bcnth << 8) | f.body.init.bcntl; 203 if (payload_len < sizeof(f.body.init.data)) {
190 if (count < (size_t)flen) { 204 memcpy(buf, f.body.init.data, payload_len);
191 fido_log_debug("%s: count < flen (%zu, %zu)", __func__, count, 205 return (payload_len);
192 (size_t)flen);
193 return (-1);
194 }
195 if (flen < sizeof(f.body.init.data)) {
196 memcpy(buf, f.body.init.data, flen);
197 return (flen);
198 } 206 }
199 207
200 memcpy(buf, f.body.init.data, sizeof(f.body.init.data)); 208 memcpy(buf, f.body.init.data, sizeof(f.body.init.data));
201 r = sizeof(f.body.init.data); 209 r = sizeof(f.body.init.data);
202 seq = 0;
203 210
204 while ((size_t)r < flen) { 211 for (int seq = 0; (size_t)r < payload_len; seq++) {
205 if (rx_frame(d, &f, ms) < 0) { 212 if (rx_frame(d, &f, ms) < 0) {
206 fido_log_debug("%s: rx_frame", __func__); 213 fido_log_debug("%s: rx_frame", __func__);
207 return (-1); 214 return (-1);
208 } 215 }
209 216
210 fido_log_debug("%s: continuation frame at %p, len %zu", 217 fido_log_debug("%s: continuation frame at %p", __func__,
211 __func__, (void *)&f, sizeof(f)); 218 (void *)&f);
212 fido_log_xxd(&f, sizeof(f)); 219 fido_log_xxd(&f, sizeof(f));
213 220
214#ifdef FIDO_FUZZ 221#ifdef FIDO_FUZZ
@@ -216,38 +223,57 @@ fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms)
216 f.body.cont.seq = seq; 223 f.body.cont.seq = seq;
217#endif 224#endif
218 225
219 if (f.cid != d->cid || f.body.cont.seq != seq++) { 226 if (f.cid != d->cid || f.body.cont.seq != seq) {
220 fido_log_debug("%s: cid (0x%x, 0x%x), seq (%d, %d)", 227 fido_log_debug("%s: cid (0x%x, 0x%x), seq (%d, %d)",
221 __func__, f.cid, d->cid, f.body.cont.seq, seq); 228 __func__, f.cid, d->cid, f.body.cont.seq, seq);
222 return (-1); 229 return (-1);
223 } 230 }
224 231
225 uint8_t *p = (uint8_t *)buf + r; 232 if ((size_t)(payload_len - r) > sizeof(f.body.cont.data)) {
226 233 memcpy(buf + r, f.body.cont.data,
227 if ((size_t)(flen - r) > sizeof(f.body.cont.data)) { 234 sizeof(f.body.cont.data));
228 memcpy(p, f.body.cont.data, sizeof(f.body.cont.data));
229 r += sizeof(f.body.cont.data); 235 r += sizeof(f.body.cont.data);
230 } else { 236 } else {
231 memcpy(p, f.body.cont.data, flen - r); 237 memcpy(buf + r, f.body.cont.data, payload_len - r);
232 r += (flen - r); /* break */ 238 r += (payload_len - r); /* break */
233 } 239 }
234 } 240 }
235 241
236 fido_log_debug("%s: payload at %p, len %zu", __func__, buf, (size_t)r);
237 fido_log_xxd(buf, r);
238
239 return (r); 242 return (r);
240} 243}
241 244
242int 245int
246fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms)
247{
248 int n;
249
250 fido_log_debug("%s: d=%p, cmd=0x%02x, buf=%p, count=%zu, ms=%d",
251 __func__, (void *)d, cmd, (const void *)buf, count, ms);
252
253 if (d->transport.rx != NULL)
254 return (d->transport.rx(d, cmd, buf, count, ms));
255
256 if (d->io_handle == NULL || d->io.read == NULL || count > UINT16_MAX) {
257 fido_log_debug("%s: invalid argument", __func__);
258 return (-1);
259 }
260
261 if ((n = rx(d, cmd, buf, count, ms)) >= 0) {
262 fido_log_debug("%s: buf=%p, len=%d", __func__, (void *)buf, n);
263 fido_log_xxd(buf, n);
264 }
265
266 return (n);
267}
268
269int
243fido_rx_cbor_status(fido_dev_t *d, int ms) 270fido_rx_cbor_status(fido_dev_t *d, int ms)
244{ 271{
245 const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; 272 unsigned char reply[FIDO_MAXMSG];
246 unsigned char reply[2048];
247 int reply_len; 273 int reply_len;
248 274
249 if ((reply_len = fido_rx(d, cmd, &reply, sizeof(reply), ms)) < 0 || 275 if ((reply_len = fido_rx(d, CTAP_CMD_CBOR, &reply, sizeof(reply),
250 (size_t)reply_len < 1) { 276 ms)) < 0 || (size_t)reply_len < 1) {
251 fido_log_debug("%s: fido_rx", __func__); 277 fido_log_debug("%s: fido_rx", __func__);
252 return (FIDO_ERR_RX); 278 return (FIDO_ERR_RX);
253 } 279 }
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
16extern "C" {
17#endif /* __cplusplus */
18
12PACKED_TYPE(iso7816_header_t, 19PACKED_TYPE(iso7816_header_t,
13struct iso7816_header { 20struct 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);
35size_t iso7816_len(const iso7816_apdu_t *); 42size_t iso7816_len(const iso7816_apdu_t *);
36void iso7816_free(iso7816_apdu_t **); 43void 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 */
diff --git a/src/log.c b/src/log.c
index 982bdb7..d6f0934 100644
--- a/src/log.c
+++ b/src/log.c
@@ -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
18static TLS int logging; 24static TLS int logging;
25static TLS fido_log_handler_t *log_handler;
26
27static void
28log_on_stderr(const char *str)
29{
30 fprintf(stderr, "%s", str);
31}
19 32
20void 33void
21fido_log_init(void) 34fido_log_init(void)
22{ 35{
23 logging = 1; 36 logging = 1;
37 log_handler = log_on_stderr;
24} 38}
25 39
26void 40void
27fido_log_xxd(const void *buf, size_t count) 41fido_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
47void 59void
48fido_log_debug(const char *fmt, ...) 60fido_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
85void
86fido_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 */
diff --git a/src/pin.c b/src/pin.c
index 1ed555c..36acbe4 100644
--- a/src/pin.c
+++ b/src/pin.c
@@ -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
28static int
29parse_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
26static int 35static int
27fido_dev_get_pin_token_tx(fido_dev_t *dev, const char *pin, 36fido_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
80static int
81fido_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;
106fail:
107 cbor_vector_free(argv, nitems(argv));
108 free(f.ptr);
109
110 return (r);
111}
112#endif /* FIDO_UVTOKEN */
113
70static int 114static int
71fido_dev_get_pin_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, 115fido_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
155static int
156fido_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;
189fail:
190 fido_blob_free(&aes_token);
191
192 return (r);
193}
194#endif /* FIDO_UVTOKEN */
195
110static int 196static int
111fido_dev_get_pin_token_wait(fido_dev_t *dev, const char *pin, 197fido_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:
356static int 454static int
357fido_dev_get_retry_count_rx(fido_dev_t *dev, int *retries, int ms) 455fido_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 @@
10static int 10static int
11fido_dev_reset_tx(fido_dev_t *dev) 11fido_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 }
diff --git a/src/u2f.c b/src/u2f.c
index 82b289f..19a959d 100644
--- a/src/u2f.c
+++ b/src/u2f.c
@@ -125,11 +125,10 @@ authdata_fake(const char *rp_id, uint8_t flags, uint32_t sigcount,
125static int 125static int
126send_dummy_register(fido_dev_t *dev, int ms) 126send_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
179key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id, 178key_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
285do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id, 284do_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:
575int 573int
576u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms) 574u2f_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:
724int 726int
725u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms) 727u2f_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}