Nick Zana 12 months ago
parent 0fb2487154
commit cf792b97cb
No known key found for this signature in database
GPG Key ID: 936524EE913D6538

610
Cargo.lock generated

@ -2,68 +2,6 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aes"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "anyhow"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
[[package]]
name = "asn1-rs"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0"
dependencies = [
"asn1-rs-derive",
"asn1-rs-impl",
"displaydoc",
"nom",
"num-traits",
"rusticata-macros",
"thiserror",
"time",
]
[[package]]
name = "asn1-rs-derive"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
"synstructure",
]
[[package]]
name = "asn1-rs-impl"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base64"
version = "0.21.0"
@ -71,19 +9,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
[[package]]
name = "block-padding"
version = "0.3.3"
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
dependencies = [
"generic-array",
]
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bounded-integer"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc54ef154ce8654be9ee10ed33106bdfd5bff6ee7735c25a160af2290ea938ab"
dependencies = [
"serde",
]
[[package]]
name = "bounded-vec"
@ -95,27 +33,6 @@ dependencies = [
"thiserror",
]
[[package]]
name = "bumpalo"
version = "3.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cbc"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
dependencies = [
"cipher",
]
[[package]]
name = "cc"
version = "1.0.79"
@ -155,22 +72,6 @@ dependencies = [
"half",
]
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
]
[[package]]
name = "cookie-factory"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b"
[[package]]
name = "coset"
version = "0.3.4"
@ -181,95 +82,41 @@ dependencies = [
"ciborium-io",
]
[[package]]
name = "cpufeatures"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58"
dependencies = [
"libc",
]
[[package]]
name = "credential-management-proto"
version = "0.1.0"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "ctap-hid-fido2"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3726fa3f7f978ce0a222ea73c13490115f95e7a31db3061d7c4c91bea58ea01a"
dependencies = [
"aes",
"anyhow",
"base64",
"byteorder",
"cbc",
"hex",
"hidapi",
"num",
"pad",
"ring",
"serde",
"serde_cbor",
"strum",
"strum_macros",
"x509-parser",
]
[[package]]
name = "ctap2-proto"
version = "0.1.0"
dependencies = [
"bounded-integer",
"bounded-vec",
"cookie-factory",
"coset",
"ctap-hid-fido2",
"fido-common",
"nom",
"serde",
]
[[package]]
name = "data-encoding"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
[[package]]
name = "der-parser"
version = "8.2.0"
name = "ctaphid"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e"
checksum = "aa622743e1747e48d25170854b552b3ddc753125a39a6732e57c5c7a5ff7fe11"
dependencies = [
"asn1-rs",
"displaydoc",
"nom",
"num-bigint",
"num-traits",
"rusticata-macros",
"ctaphid-types",
"hex",
"log",
"rand_core",
"tap",
]
[[package]]
name = "displaydoc"
version = "0.2.4"
name = "ctaphid-types"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
checksum = "4714cdd86d5134532b9decaa6774db0a6851ecd07e96a2f239332ae1f3239350"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.15",
"bitflags",
]
[[package]]
@ -277,17 +124,20 @@ name = "fido-common"
version = "0.1.0"
dependencies = [
"bounded-vec",
"ciborium",
"coset",
"serde",
]
[[package]]
name = "generic-array"
version = "0.14.7"
name = "getrandom"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
dependencies = [
"typenum",
"version_check",
"cfg-if",
"libc",
"wasi",
]
[[package]]
@ -296,18 +146,24 @@ version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hid-ctap2-proto"
version = "0.1.0"
dependencies = [
"ciborium",
"ciborium-io",
"ctap2-proto",
"ctaphid",
"hidapi",
"serde",
]
[[package]]
name = "hidapi"
version = "1.5.0"
@ -320,37 +176,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "inout"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
dependencies = [
"block-padding",
"generic-array",
]
[[package]]
name = "itoa"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "js-sys"
version = "0.3.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.144"
@ -366,128 +191,6 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "num"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
dependencies = [
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "oid-registry"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff"
dependencies = [
"asn1-rs",
]
[[package]]
name = "once_cell"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
name = "pad"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3"
dependencies = [
"unicode-width",
]
[[package]]
name = "pkg-config"
version = "0.3.27"
@ -513,99 +216,32 @@ dependencies = [
]
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "rusticata-macros"
version = "4.1.0"
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"nom",
"getrandom",
]
[[package]]
name = "rustversion"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
[[package]]
name = "serde"
version = "1.0.162"
version = "1.0.163"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6"
checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_cbor"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
dependencies = [
"half",
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.162"
version = "1.0.163"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6"
checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.15",
]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "strum"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
[[package]]
name = "strum_macros"
version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn 1.0.109",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
"syn",
]
[[package]]
@ -620,16 +256,10 @@ dependencies = [
]
[[package]]
name = "synstructure"
version = "0.12.6"
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
"unicode-xid",
]
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "thiserror"
@ -648,42 +278,9 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.15",
]
[[package]]
name = "time"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc"
dependencies = [
"itoa",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
[[package]]
name = "time-macros"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
dependencies = [
"time-core",
"syn",
]
[[package]]
name = "typenum"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "unicode-ident"
version = "1.0.8"
@ -691,92 +288,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
name = "unicode-width"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "unicode-xid"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "untrusted"
version = "0.7.1"
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasm-bindgen"
version = "0.2.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.15",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.15",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb"
[[package]]
name = "web-sys"
version = "0.3.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16b5f940c7edfdc6d12126d98c9ef4d1b3d470011c47c76a6581df47ad9ba721"
dependencies = [
"js-sys",
"wasm-bindgen",
]
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "webauthn3-proto"
@ -809,20 +324,3 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "x509-parser"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab0c2f54ae1d92f4fcb99c0b7ccf0b1e3451cbd395e5f115ccbdbcb18d4f634"
dependencies = [
"asn1-rs",
"data-encoding",
"der-parser",
"lazy_static",
"nom",
"oid-registry",
"rusticata-macros",
"thiserror",
"time",
]

@ -7,7 +7,7 @@ edition = "2021"
[dependencies]
fido-common = { path = "../fido-common" }
bounded-integer = { version = "0.5.3", features = ["types", "std"] }
bounded-integer = { version = "0.5.3", features = ["types", "std", "serde1"] }
bounded-vec = "0.7.1"
coset = "0.3.3"
serde = { version = "1.0", features = ["derive"], optional = true }

@ -0,0 +1,187 @@
use std::collections::BTreeMap;
use std::ops::Deref;
use ctap2_proto::extensions;
use ctap2_proto::prelude::*;
use ctap2_proto::Ctap2_2Authenticator;
extern crate ctap2_proto;
struct FidoKey(ctap_hid_fido2::FidoKeyHid);
impl Deref for FidoKey {
type Target = ctap_hid_fido2::FidoKeyHid;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Ctap2_2Authenticator for FidoKey {
fn make_credential(&mut self, request: make::Request) -> Result<make::Response, make::Error> {
let args = MakeCredentialArgsBuilder::new(
&request.relying_party.id,
request.client_data_hash.as_ref(),
)
.build();
let attestation = match self.make_credential_with_args(&args) {
Ok(attestation) => attestation,
Err(e) => {
todo!("unhandled error: {e}") // anyhow::Error requires manually
// mapping
}
};
let format = if !attestation.flags_attested_credential_data_included {
FormatIdentifier::None
} else {
unimplemented!("do not support attestation yet")
};
let authenticator_data = attestation.auth_data.as_slice().try_into().unwrap();
let unsigned_extension_outputs: BTreeMap<_, _> = attestation
.extensions
.into_iter()
.filter_map(|extension| -> Option<(extensions::Identifier, Vec<u8>)> {
match extension {
CredentialExtension::CredBlob(_) => {
todo!()
}
CredentialExtension::CredProtect(_) => {
todo!()
}
CredentialExtension::HmacSecret(_) => {
todo!()
}
CredentialExtension::LargeBlobKey(_) => {
todo!()
}
CredentialExtension::MinPinLength(_) => {
todo!()
}
}
})
.collect();
let unsigned_extension_outputs = if !unsigned_extension_outputs.is_empty() {
Some(unsigned_extension_outputs)
} else {
None
};
Ok(make::Response {
format,
authenticator_data,
enterprise_attestation: None,
large_blob_key: None,
unsigned_extension_outputs,
})
}
fn get_assertion(request: get::Request) -> Result<get::Response, get::Error> {
todo!()
}
fn get_info(&self) -> device::Info {
todo!()
}
fn client_pin(request: client_pin::Request) -> Result<client_pin::Response, client_pin::Error> {
todo!()
}
fn reset() -> Result<(), reset::Error> {
todo!()
}
fn selection() -> Result<(), ctap2_proto::authenticator::selection::Error> {
todo!()
}
}
use ctap_hid_fido2::fidokey::CredentialExtension;
use ctap_hid_fido2::{
fidokey::{GetAssertionArgsBuilder, MakeCredentialArgsBuilder},
verifier, Cfg, FidoKeyHidFactory,
};
use fido_common::attestation::FormatIdentifier;
fn main() {
let rpid = "reg-auth-example-app";
let pin = get_input_with_message("input PIN:");
println!("Register");
// create `challenge`
let challenge = verifier::create_challenge();
// create `MakeCredentialArgs`
let make_credential_args = MakeCredentialArgsBuilder::new(rpid, &challenge)
.pin(&pin)
.build();
let mut cfg = Cfg::init();
cfg.enable_log = false;
// create `FidoKeyHid`
let device = FidoKeyHidFactory::create(&cfg).unwrap();
if device.get_info().unwrap().force_pin_change {
device.set_new_pin("1234").unwrap();
}
// get `Attestation` Object
let attestation = device
.make_credential_with_args(&make_credential_args)
.unwrap();
println!("- Register Success");
// verify `Attestation` Object
let verify_result = verifier::verify_attestation(rpid, &challenge, &attestation);
if !verify_result.is_success {
println!("- ! Verify Failed");
return;
}
// store Credential Id and Publickey
let userdata_credential_id = verify_result.credential_id;
let userdata_credential_public_key = verify_result.credential_public_key;
println!("Authenticate");
// create `challenge`
let challenge = verifier::create_challenge();
// create `GetAssertionArgs`
let get_assertion_args = GetAssertionArgsBuilder::new(rpid, &challenge)
.pin(&pin)
.credential_id(&userdata_credential_id)
.build();
// get `Assertion` Object
let assertions = device.get_assertion_with_args(&get_assertion_args).unwrap();
println!("- Authenticate Success");
// verify `Assertion` Object
if !verifier::verify_assertion(
rpid,
&userdata_credential_public_key,
&challenge,
&assertions[0],
) {
println!("- ! Verify Assertion Failed");
}
}
pub fn get_input() -> String {
let mut word = String::new();
std::io::stdin().read_line(&mut word).ok();
return word.trim().to_string();
}
pub fn get_input_with_message(message: &str) -> String {
println!("{}", message);
let input = get_input();
println!();
input
}

@ -0,0 +1,266 @@
#![feature(let_chains)]
extern crate ctap2_proto;
<<<<<<< Updated upstream
use std::collections::HashMap;
=======
use std::collections::BTreeMap;
>>>>>>> Stashed changes
use bounded_vec::BoundedVec;
use ctap2_proto::authenticator::Sha256Hash;
// Recommended
use ctap2_proto::prelude::*;
use ctap2_proto::{
authenticator,
prelude::{
client_pin::AuthProtocolVersion,
device::{Aaguid, Version},
},
};
use fido_common::credential::public_key::{RelyingPartyEntity, UserEntity};
use fido_common::{
attestation,
credential::{self, public_key::Parameters},
registry::algorithms::Signature,
Transport,
};
const AAGUID: Aaguid = Aaguid::from(*b"\xed\xeeZow\xdc\xf5\xadZ\xe3\xd7\xb8\xf5\xf6\xf7\xd7");
const VERSION: usize = 1;
const SUPPORTED_AUTH_PROTOCOL_VERSIONS: [AuthProtocolVersion; 1] = [AuthProtocolVersion::Two];
const SUPPORTED_PUBLIC_KEY_ALGORITHMS: [Parameters; 1] = [Parameters {
credential_type: credential::Type::PublicKey,
algorithm: Signature::Ed25519EddsaSha512Raw,
}];
struct VirtualAuthenticator<R, W>
where
R: std::io::Read + Send,
W: std::io::Write + Send,
{
pin: Option<Vec<u8>>,
input: R,
output: W,
}
enum Presence {
Present,
NotPresent,
}
impl<R, W> VirtualAuthenticator<R, W>
where
R: std::io::Read + Send,
W: std::io::Write + Send,
{
fn verify_presence(reader: &mut R, writer: &mut W) -> Result<Presence, std::io::Error> {
write!(writer, "Allow this operation? [Y/n]:")?;
let mut input = <[u8; 1]>::default();
reader.read_exact(&mut input)?;
writeln!(writer)?;
if input[0] == b'Y' {
Ok(Presence::Present)
} else {
Ok(Presence::NotPresent)
}
}
}
impl<R, W> Ctap2_2Authenticator for VirtualAuthenticator<R, W>
where
R: std::io::Read + Send,
W: std::io::Write + Send,
{
fn make_credential(&mut self, request: make::Request) -> Result<make::Response, make::Error> {
// If authenticator supports either pinUvAuthToken or clientPin features and the
// platform sends a zero length pinUvAuthParam:
if let Some(options) = self.get_info().options &&
(options.contains_key(&device::OptionId::PinUvAuthToken) || options.contains_key(&device::OptionId::ClientPin)) && request.pin_uv_auth_param.len() == 0
{
// Request evidence of user interaction in an authenticator-specific way (e.g., flash
// the LED light).
// If the user declines permission, or the operation times out, then end the operation
// by returning CTAP2_ERR_OPERATION_DENIED.
let Ok(Presence::Present) = Self::verify_presence(&mut self.input, &mut self.output) else {
return Err(make::Error::OperationDenied);
};
// If evidence of user interaction is provided in this step then return either
// CTAP2_ERR_PIN_NOT_SET if PIN is not set or CTAP2_ERR_PIN_INVALID if PIN has been
// set.
if self.pin.is_some() {
return Err(make::Error::PinInvalid);
} else {
return Err(make::Error::PinNotSet);
}
}
// If the pinUvAuthParam parameter is present:
debug_assert!(request.pin_uv_auth_param.len() > 0);
// If the pinUvAuthProtocol parameters value is not supported, return
// CTAP1_ERR_INVALID_PARAMETER error.
// If the pinUvAuthProtocol parameter is absent, return
// CTAP2_ERR_MISSING_PARAMETER error.
let Some(auth_protocol_version) = request.pin_uv_auth_protocol_version else { return Err(make::Error::MissingParameter) };
if !SUPPORTED_AUTH_PROTOCOL_VERSIONS.contains(&auth_protocol_version) {
return Err(make::Error::InvalidParameter);
}
// Filter out any invalid or unsupported params, then take the first valid one.
// TODO: The following NOTE from the specs refers to the following loop, however
// this loop only iterates over the algorithms until a match is found.
//
// The only risk I can imagine is enumerating the supported algorithms of the
// authenticator, which doesn't seem that important to protect against.
//
// NOTE: This loop chooses the first occurrence of an algorithm identifier
// supported by this authenticator but always iterates over every
// element of pubKeyCredParams to validate them.
// Validate pubKeyCredParams with the following steps:
// 1. For each element of pubKeyCredParams:
let Some(public_key_algorithm) = request.public_key_credential_params.into_iter().filter(|params| {
// TODO: Ensure that invalid params are unrepresentable
// If the element is missing required members, including members that are mandatory
// only for the specific type, then return an error, for example
// CTAP2_ERR_INVALID_CBOR.
// TODO: What would it mean for a credential to have the wrong type?
// If the values of any known members have the wrong type then return an error, for
// example CTAP2_ERR_CBOR_UNEXPECTED_TYPE.
// If the element specifies an algorithm that is supported by the authenticator, and no
// algorithm has yet been chosen by this loop, then let the algorithm specified by the
// current element be the chosen algorithm.
return SUPPORTED_PUBLIC_KEY_ALGORITHMS.contains(params);
}).next() else {
// If the loop completes and no algorithm was chosen then return
// CTAP2_ERR_UNSUPPORTED_ALGORITHM.
return Err(make::Error::UnsupportedAlgorithm);
};
// No attestation
let format = attestation::FormatIdentifier::None;
// No enterprise attestation
let enterprise_attestation = None;
// If the "uv" option is absent, let the "uv" option be treated as being present
// with the value false. (This is the default)
let mut user_verification = false;
let mut discoverable_credential = false;
let mut user_presence = true;
let authenticator_data = authenticator::Data {
relying_party_id_hash: todo!(),
user_is_present: todo!(),
user_is_verified: todo!(),
signature_counter: todo!(),
attested_credential_data: todo!(),
extensions: None,
};
if let Some(req_options) = request.options {
// If the pinUvAuthParam is present, let the "uv" option be treated as being
// present with the value false.
if let Some(true) = req_options.get(&make::OptionKey::UserVerification) {}
}
Ok(make::Response {
format,
authenticator_data,
enterprise_attestation,
large_blob_key: None,
unsigned_extension_outputs: None,
})
}
fn get_assertion(request: get::Request) -> Result<get::Response, get::Error> {
todo!()
}
fn get_info(&self) -> device::Info {
device::Info {
versions: [Version::Fido2_1].into_iter().collect(),
extensions: None,
aaguid: AAGUID,
options: None,
max_message_size: None,
pin_uv_auth_protocols: Some(SUPPORTED_AUTH_PROTOCOL_VERSIONS.into()),
max_credential_count_in_list: None,
max_credential_id_length: None,
transports: Some([Transport::Internal].into_iter().collect()),
algorithms: Some(SUPPORTED_PUBLIC_KEY_ALGORITHMS.into()),
max_serialized_large_blob_array_size: None,
force_pin_change: Some(self.pin.is_none()),
min_pin_length: None,
firmware_version: Some(VERSION),
max_cred_blob_length: None,
max_rpids_for_set_min_pin_length: None,
preferred_platform_uv_attempts: None,
uv_modality: None,
certifications: None,
remaining_discoverable_credentials: None,
vendor_prototype_config_commands: None,
}
}
fn client_pin(request: client_pin::Request) -> Result<client_pin::Response, client_pin::Error> {
todo!()
}
fn reset() -> Result<(), reset::Error> {
todo!()
}
fn selection() -> Result<(), selection::Error> {
todo!()
}
}
fn main() {
let pin = None;
let authenticator = VirtualAuthenticator {
pin,
input: std::io::stdin(),
output: std::io::stdout(),
};
let client_data_hash = Sha256Hash([0; 32]);
let relying_party = RelyingPartyEntity {
id: "example.com".into(),
name: Some("Example Inc.".into()),
};
let user_entity = UserEntity {
id: BoundedVec::from_vec([1u8; 64].into()).unwrap(),
name: Some("user@example.com".into()),
display_name: Some("Example User".into()),
};
// Get authenticator info
let info = authenticator.get_info();
// Make a new discoverable credential
let options = HashMap::from([
(make::OptionKey::UserVerification, true),
(make::OptionKey::Discoverable, true),
(make::OptionKey::UserPresence, false),
]);
let request = make::Request {
client_data_hash: &client_data_hash,
relying_party: &relying_party,
user: &user_entity,
public_key_credential_params: &SUPPORTED_PUBLIC_KEY_ALGORITHMS,
exclude_list: None,
extensions: None,
options: Some(&options),
pin_uv_auth_param: (),
pin_uv_auth_protocol_version: (),
enterprise_attestation: None,
};
authenticator.make_credential(request);
}

@ -1,8 +1,11 @@
use bounded_integer::BoundedUsize;
use std::collections::BTreeSet;
use bounded_integer::BoundedUsize;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum AuthProtocolVersion {
One,
Two,

@ -5,6 +5,9 @@ use crate::{
use fido_common::{attestation, credential::public_key};
use std::collections::{BTreeMap, HashMap};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub enum Error {
OperationDenied,
PinNotSet,
@ -25,6 +28,7 @@ pub enum Error {
/// > The following option keys are defined for use in
/// > `authenticatorMakeCredential`'s `options` parameter.
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum OptionKey {
/// > Specifies whether this credential is to be discoverable or
/// > not.
@ -41,6 +45,7 @@ pub enum OptionKey {
/// Input parameters for [`Ctap2Device::make_credential`] operation.
#[derive(Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct Request<'a> {
/// > Hash of the ClientData contextual binding specified by host.
pub client_data_hash: &'a Sha256Hash,
@ -84,6 +89,7 @@ pub struct Request<'a> {
pub enterprise_attestation: Option<attestation::enterprise::Kind>,
}
#[cfg_attr(feature = "serde", derive(Deserialize))]
pub struct Response {
pub format: fido_common::attestation::FormatIdentifier,
pub authenticator_data: authenticator::Data,

@ -8,8 +8,12 @@ use std::collections::{BTreeMap, BTreeSet};
use std::num::NonZeroUsize;
use std::usize;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
/// A usize with a minimum value of N
#[derive(PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct UsizeN<const N: usize>(bounded_integer::BoundedUsize<N, { usize::MAX }>);
/// > data type byte string and identifying the authenticator model, i.e.
@ -18,6 +22,7 @@ pub struct UsizeN<const N: usize>(bounded_integer::BoundedUsize<N, { usize::MAX
pub type Aaguid = [u8; 16];
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Version {
Fido2_1,
Fido2_0,
@ -32,6 +37,8 @@ pub enum Version {
/// > `AAGUID` via appropriate methods. Platforms may alter their behaviour
/// > based on these hints such as selecting a PIN protocol or `credProtect`
/// > level.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Certification {
/// > The [FIPS140-2] Cryptographic-Module-Validation-Program overall
/// > certification level.
@ -44,6 +51,8 @@ pub enum Certification {
}
#[repr(usize)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum FipsCryptoValidation2Level {
Level1 = 1,
Level2 = 2,
@ -52,6 +61,8 @@ pub enum FipsCryptoValidation2Level {
}
#[repr(usize)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum FipsCryptoValidation3Level {
Level1 = 1,
Level2 = 2,
@ -60,6 +71,8 @@ pub enum FipsCryptoValidation3Level {
}
#[repr(usize)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum FipsPhysicalCryptoValidation2Level {
Level1 = 1,
Level2 = 2,
@ -68,6 +81,8 @@ pub enum FipsPhysicalCryptoValidation2Level {
}
#[repr(usize)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum FipsPhysicalCryptoValidation3Level {
Level1 = 1,
Level2 = 2,
@ -78,6 +93,8 @@ pub enum FipsPhysicalCryptoValidation3Level {
/// > Common Criteria Evaluation Assurance Level [CC1V3-1R5]. This is a integer
/// > from 1 to 7. The intermediate-plus levels are not represented.
#[repr(usize)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum CommonCriterialLevel {
EAL1 = 1,
EAL2 = 2,
@ -92,6 +109,8 @@ pub enum CommonCriterialLevel {
/// > numbered levels are mapped to the odd numbers, with the plus levels mapped
/// > to the even numbers e.g., level 3+ is mapped to 6.
#[repr(usize)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum FidoLevel {
L1 = 1,
L1Plus = 2,
@ -103,6 +122,7 @@ pub enum FidoLevel {
/// These options describe properties of a CTAP device.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum OptionId {
/// > Indicates that the device is attached to the client and therefore
/// > cant be removed and used on another client.
@ -182,6 +202,8 @@ pub enum OptionId {
/// > list of its supported protocol versions and extensions, its AAGUID, and
/// > other aspects of its overall capabilities. Platforms should use this
/// > information to tailor their command parameters choices.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug)]
pub struct Info {
/// > List of supported CTAP versions.
pub versions: BTreeSet<Version>,

@ -7,8 +7,9 @@ edition = "2021"
[dependencies]
bounded-vec = { version = "0.7.1", features = ["serde"] }
ciborium = { version = "0.2.1", default-features = false, optional = true }
coset = { version = "0.3.4", default-features = false }
serde = { version = "1", features = ["derive"], optional = true }
[features]
serde = ["dep:serde", "bounded-vec/serde"]
serde = ["dep:serde", "bounded-vec/serde", "dep:ciborium"]

@ -1,3 +1,4 @@
use serde::ser::Serializer;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
@ -71,8 +72,12 @@ pub enum FormatIdentifier {
}
pub mod enterprise {
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[repr(usize)]
#[derive(Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Kind {
/// > In this case, an enterprise attestation capable authenticator, on
/// > which enterprise attestation is enabled, upon receiving the
@ -97,14 +102,41 @@ pub mod enterprise {
}
}
use coset::CborSerializable;
/// > Attested credential data is a variable-length byte array added to the
/// > authenticator data when generating an attestation object for a given
/// > credential.
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct CredentialData {
/// > The AAGUID of the authenticator.
pub aaguid: [u8; 16],
/// The ID of the credential.
pub id: Vec<u8>,
/// The public key of the credential.
#[cfg_attr(
feature = "serde",
serde(
deserialize_with = "deserialize_coset_key",
serialize_with = "serialize_cose_key"
)
)]
pub public_key: coset::CoseKey,
}
pub fn serialize_cose_key<S: Serializer>(key: &coset::CoseKey, s: S) -> Result<S::Ok, S::Error> {
use serde::ser::Error;
let bytes = key
.clone()
.to_vec()
.map_err(|e| Error::custom(e.to_string()))?;
s.serialize_bytes(&bytes)
}
#[cfg(feature = "serde")]
fn deserialize_coset_key<'de, D>(deserializer: D) -> Result<coset::CoseKey, D::Error>
where
D: serde::de::Deserializer<'de>,
{
todo!()
}

@ -1,6 +1,9 @@
use crate::{attestation, extensions, Sha256Hash};
use std::collections::BTreeMap;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub enum Flags {}
/// > The authenticator data structure encodes contextual bindings made by the
@ -13,6 +16,7 @@ pub enum Flags {}
/// > software, connected to the client over a secure channel. In both cases,
/// > the Relying Party receives the authenticator data in the same format, and
/// > uses its knowledge of the authenticator to make trust decisions.
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct Data {
/// > SHA-256 hash of the RP ID the credential is scoped to.
pub relying_party_id_hash: Sha256Hash,
@ -42,9 +46,6 @@ impl TryFrom<&[u8]> for Data {
}
}
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
/// > Authenticators may implement various transports for communicating with
/// > clients. This enumeration defines hints as to how clients might
/// > communicate with a particular authenticator in order to obtain an

@ -1,3 +1,6 @@
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
/// > Extensions are identified by a string, called an extension identifier,
/// > chosen by the extension author.
/// >
@ -18,7 +21,8 @@
/// > Extensions that may exist in multiple versions should take care to include
/// > a version in their identifier. In effect, different versions are thus
/// > treated as different extensions, e.g., `myCompany_extension_01`
#[derive(PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Identifier {
AppId,
TransactionAuthSimple,

@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
/// > representation (in quotes), which is used in the authoritative metadata
/// > for FIDO authenticators.
#[repr(u32)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum UserVerify {
/// > This flag MUST be set if the authenticator is able to confirm user

@ -0,0 +1,16 @@
[package]
name = "hid-ctap2-proto"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
ciborium = "0.2.1"
ciborium-io = "0.2.1"
ctap2-proto = { path = "../ctap2-proto", features = ["serde"] }
ctaphid = { version = "0.3.1", default_features = false }
serde = "1.0.163"
[dev-dependencies]
hidapi = { version = "^1.2.6", default-features = false, features = ["linux-shared-hidraw"] }

@ -0,0 +1,185 @@
use ctap2_proto::{prelude::*, Ctap2_2Authenticator};
use ctaphid::types::Command;
pub struct Device<D: ctaphid::HidDevice>(ctaphid::Device<D>);
impl<D: ctaphid::HidDevice> Device<D> {
fn send_raw(&self, command: Command, bytes: &[u8]) -> Result<Vec<u8>, ctaphid::error::Error> {
self.0.ctap2(command.into(), bytes)
}
fn send<Req, Res>(&self, req: Req) -> Result<Res, ctaphid::error::Error>
where
Req: serde::Serialize,
Res: for<'de> serde::Deserialize<'de>,
{
let command = Command::Cbor;
let mut data: Vec<u8> = Vec::new();
ciborium::ser::into_writer(&req, &mut data).map_err(|e| match e {
ciborium::ser::Error::Io(_) => ctaphid::error::RequestError::IncompleteWrite,
ciborium::ser::Error::Value(desc) => {
ctaphid::error::RequestError::PacketSendingFailed(desc.into())
}
})?;
let response = self.0.ctap2(command.into(), &data)?;
match ciborium::de::from_reader(response.as_slice()) {
Ok(res) => Ok(res),
Err(e) => match e {
ciborium::de::Error::Io(_) => todo!(),
ciborium::de::Error::Syntax(_) => todo!(),
ciborium::de::Error::Semantic(_, _) => todo!(),
ciborium::de::Error::RecursionLimitExceeded => todo!(),
},
}
}
}
impl<D> Ctap2_2Authenticator for Device<D>
where
D: ctaphid::HidDevice,
{
fn make_credential(&mut self, request: make::Request) -> Result<make::Response, make::Error> {
// TODO: How the heck am i supposed to handle errors???
self.send(&request).map_err(|e| match e {
ctaphid::error::Error::CommandError(e) => match e {
ctaphid::error::CommandError::CborError(_) => todo!(),
ctaphid::error::CommandError::InvalidPingData => todo!(),
ctaphid::error::CommandError::NotSupported(_) => todo!(),
},
ctaphid::error::Error::RequestError(e) => match e {
ctaphid::error::RequestError::IncompleteWrite => todo!(),
ctaphid::error::RequestError::MessageFragmentationFailed(_) => todo!(),
ctaphid::error::RequestError::PacketSendingFailed(_) => todo!(),
ctaphid::error::RequestError::PacketSerializationFailed(_) => todo!(),
},
ctaphid::error::Error::ResponseError(e) => match e {
ctaphid::error::ResponseError::CommandFailed(_) => todo!(),
ctaphid::error::ResponseError::MessageDefragmentationFailed(_) => todo!(),
ctaphid::error::ResponseError::PacketParsingFailed(_) => todo!(),
ctaphid::error::ResponseError::PacketReceivingFailed(_) => todo!(),
ctaphid::error::ResponseError::Timeout => todo!(),
ctaphid::error::ResponseError::MissingErrorCode => todo!(),
ctaphid::error::ResponseError::UnexpectedCommand { expected, actual } => todo!(),
ctaphid::error::ResponseError::UnexpectedKeepAlive(_) => todo!(),
ctaphid::error::ResponseError::UnexpectedResponseData(_) => todo!(),
},
})
}
fn get_assertion(request: get::Request) -> Result<get::Response, get::Error> {
todo!()
}
fn get_info(&self) -> device::Info {
let info = self.send_raw(Command::Cbor, &[1u8, 4]).unwrap();
println!("info: {info:#?}");
let info: device::Info =
ciborium::de::from_reader::<device::Info, _>(info.as_slice()).unwrap();
info
}
fn client_pin(request: client_pin::Request) -> Result<client_pin::Response, client_pin::Error> {
todo!()
}
fn reset() -> Result<(), reset::Error> {
todo!()
}
fn selection() -> Result<(), ctap2_proto::authenticator::selection::Error> {
todo!()
}
}
#[cfg(test)]
mod tests {
use std::ffi::CStr;
use ctap2_proto::Ctap2_2Authenticator;
use ctaphid::{
error::{RequestError, ResponseError},
types::Command,
};
struct HidDevice(hidapi::HidDevice);
#[derive(Debug)]
struct HidDeviceInfoMy(hidapi::DeviceInfo);
impl ctaphid::HidDeviceInfo for HidDeviceInfoMy {
fn vendor_id(&self) -> u16 {
hidapi::DeviceInfo::vendor_id(&self.0)
}
fn product_id(&self) -> u16 {
hidapi::DeviceInfo::product_id(&self.0)
}
fn path(&self) -> std::borrow::Cow<'_, str> {
let cstr: &CStr = hidapi::DeviceInfo::path(&self.0);
let s = cstr.to_str().unwrap();
std::borrow::Cow::from(s)
}
}
impl ctaphid::HidDevice for HidDevice {
type Info = HidDeviceInfoMy;
fn send(&self, data: &[u8]) -> Result<(), ctaphid::error::RequestError> {
println!("sending bytes: {data:#?}");
hidapi::HidDevice::write(&self.0, data)
.map_err(|e| RequestError::PacketSendingFailed(e.into()))?;
Ok(())
}
fn receive<'a>(
&self,
buffer: &'a mut [u8],
timeout: Option<std::time::Duration>,
) -> Result<&'a [u8], ctaphid::error::ResponseError> {
println!("reading bytes");
let duration = if let Some(timeout) = timeout {
i32::try_from(timeout.as_millis())
.map_err(|err| ResponseError::PacketReceivingFailed(err.into()))?
} else {
-1
};
let n = self
.0
.read_timeout(buffer, duration)
.map_err(|err| ResponseError::PacketReceivingFailed(err.into()))?;
if n == buffer.len() {
Ok(&buffer[1..n])
} else if n == 0 {
Err(ResponseError::Timeout)
} else {
Ok(&buffer[..n])
}
}
}
#[test]
fn get_info() {
let hidapi = hidapi::HidApi::new().unwrap();
let devices = hidapi.device_list();
for device_info in devices {
let hid_device = hidapi::DeviceInfo::open_device(&device_info, &hidapi);
let hid_device = match hid_device {
Ok(hid_device) => hid_device,
Err(e) => {
println!("error: {e:#?}");
continue;
}
};
let device = HidDevice(hid_device);
let device =
ctaphid::Device::new(device, HidDeviceInfoMy(device_info.to_owned())).unwrap();
let device = super::Device(device);
println!("info: {:#?}", device.0.ctap2(Command::Cbor.into(), &[]));
}
assert!(false);
}
#[test]
fn quickstart() {}
}
Loading…
Cancel
Save