diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b50c3d79..b00a7164 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,15 +11,22 @@ env: jobs: build: - runs-on: ubuntu-latest strategy: matrix: - platform: - - ubuntu-latest - - macos-latest - toolchain: - - stable - - 1.65.0 # MSRV + include: + - platform: ubuntu-latest + toolchain: stable + deps: sudo apt-get install libpcsclite-dev + - platform: macos-latest + toolchain: stable + deps: true + - platform: ubuntu-latest + toolchain: 1.65.0 # MSRV + deps: sudo apt-get install libpcsclite-dev + - platform: macos-latest + toolchain: 1.65.0 # MSRV + deps: true + runs-on: ${{ matrix.platform }} steps: - uses: actions/checkout@v1 - name: cache .cargo/registry @@ -41,14 +48,15 @@ jobs: with: toolchain: ${{ matrix.toolchain }} override: true + - run: ${{ matrix.deps }} - run: cargo build --release - run: cargo build --release --no-default-features - run: cargo build --release --no-default-features --features=passwords - run: cargo build --release --features=usb + - run: cargo build --release --features=yubihsm-auth - run: cargo build --benches test: - runs-on: ubuntu-latest strategy: matrix: platform: @@ -57,6 +65,7 @@ jobs: toolchain: - stable - 1.65.0 # MSRV + runs-on: ${{ matrix.platform }} steps: - uses: actions/checkout@v1 - name: cache .cargo/registry @@ -103,6 +112,7 @@ jobs: toolchain: 1.65.0 # MSRV components: clippy override: true + - run: sudo apt-get install libpcsclite-dev - uses: actions-rs/cargo@v1 with: command: clippy diff --git a/Cargo.lock b/Cargo.lock index bda6e3b6..a0f907aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,12 +23,60 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "ascii" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" +[[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 0.3.20", +] + +[[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.104", + "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.104", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -41,12 +89,24 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "base64ct" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.2.1" @@ -71,6 +131,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8" + [[package]] name = "byteorder" version = "1.4.3" @@ -110,6 +176,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits", + "time 0.1.45", + "wasm-bindgen", + "winapi", +] + [[package]] name = "chunked_transfer" version = "1.4.0" @@ -137,12 +218,34 @@ dependencies = [ "digest", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "const-oid" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" +[[package]] +name = "cookie-factory" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + [[package]] name = "cpufeatures" version = "0.2.5" @@ -199,6 +302,56 @@ dependencies = [ "zeroize", ] +[[package]] +name = "cxx" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn 2.0.15", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "data-encoding" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" + [[package]] name = "dbl" version = "0.3.2" @@ -219,6 +372,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "des" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" +dependencies = [ + "cipher", +] + [[package]] name = "digest" version = "0.10.6" @@ -231,6 +407,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "displaydoc" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.104", +] + [[package]] name = "ecdsa" version = "0.16.6" @@ -280,6 +467,7 @@ dependencies = [ "ff", "generic-array", "group", + "hkdf", "pem-rfc7468", "pkcs8", "rand_core", @@ -323,7 +511,7 @@ checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] @@ -337,6 +525,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + [[package]] name = "hmac" version = "0.12.1" @@ -352,6 +549,30 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "iana-time-zone" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "inout" version = "0.1.3" @@ -368,6 +589,15 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "k256" version = "0.13.1" @@ -421,6 +651,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + [[package]] name = "log" version = "0.4.17" @@ -430,6 +669,39 @@ 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-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-bigint-dig" version = "0.8.2" @@ -443,6 +715,7 @@ dependencies = [ "num-iter", "num-traits", "rand", + "serde", "smallvec", "zeroize", ] @@ -478,6 +751,15 @@ dependencies = [ "libm 0.2.6", ] +[[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" @@ -528,6 +810,25 @@ dependencies = [ "hmac", ] +[[package]] +name = "pcsc" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37cab0be9d04e808a8d8059fa54befcd71dc8b168f9f0c04bdb7e59832abbab4" +dependencies = [ + "bitflags 1.3.2", + "pcsc-sys", +] + +[[package]] +name = "pcsc-sys" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b7bfecba2c0f1b5efb0e7caf7533ab1c295024165bcbb066231f60d33e23ea" +dependencies = [ + "pkg-config", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -587,9 +888,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -609,6 +910,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ + "libc", "rand_chacha", "rand_core", ] @@ -673,12 +975,27 @@ dependencies = [ "libusb1-sys", ] +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "ryu" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +[[package]] +name = "scratch" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" + [[package]] name = "sec1" version = "0.7.1" @@ -693,24 +1010,33 @@ dependencies = [ "zeroize", ] +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + [[package]] name = "serde" -version = "1.0.148" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.148" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn 1.0.104", + "syn 2.0.15", ] [[package]] @@ -724,6 +1050,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.6" @@ -798,9 +1135,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.3" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8234ae35e70582bfa0f1fedffa6daa248e41dd045310b19800c4a36382c8f60" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" dependencies = [ "proc-macro2", "quote", @@ -819,6 +1156,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.40" @@ -836,7 +1182,18 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.3", + "syn 2.0.15", +] + +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", ] [[package]] @@ -845,6 +1202,7 @@ version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ + "itoa", "serde", "time-core", "time-macros", @@ -889,6 +1247,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +[[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" @@ -901,6 +1265,7 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" dependencies = [ + "getrandom", "serde", ] @@ -916,18 +1281,203 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 1.0.104", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.104", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +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 = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "x509" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3cec94c3999f31341553f358ef55f65fc031291a022cd42ec0ce7219560c76" +dependencies = [ + "chrono", + "cookie-factory", +] + +[[package]] +name = "x509-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +dependencies = [ + "asn1-rs", + "base64", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror", + "time 0.3.20", +] + [[package]] name = "yubihsm" version = "0.42.0" dependencies = [ "aes", - "bitflags", + "bitflags 2.2.1", "cbc", "ccm", "cmac", @@ -951,9 +1501,43 @@ dependencies = [ "signature", "subtle", "thiserror", - "time", + "time 0.3.20", "tiny_http", "uuid", + "yubikey", + "zeroize", +] + +[[package]] +name = "yubikey" +version = "0.8.0-pre.0" +source = "git+https://github.com/baloo/yubikey.rs?branch=baloo/yubihsm-auth#b9da47164043d34b7dc0574185fac4c266d06f21" +dependencies = [ + "base16ct", + "chrono", + "cookie-factory", + "der-parser", + "des", + "elliptic-curve", + "hmac", + "log", + "nom", + "num-bigint-dig", + "num-integer", + "num-traits", + "p256", + "p384", + "pbkdf2", + "pcsc", + "rand_core", + "rsa", + "secrecy", + "sha1", + "sha2", + "subtle", + "uuid", + "x509", + "x509-parser", "zeroize", ] diff --git a/Cargo.toml b/Cargo.toml index 49f9ab21..f8f2c20b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ serde_json = { version = "1", optional = true } rusb = { version = "0.9", optional = true } sha2 = { version = "0.10", optional = true } tiny_http = { version = "0.12", optional = true } +yubikey = { git = "https://github.com/baloo/yubikey.rs", branch = "baloo/yubihsm-auth", optional = true } [dev-dependencies] ed25519-dalek = "=2.0.0-rc.2" @@ -63,6 +64,7 @@ secp256k1 = ["k256"] setup = ["passwords", "serde_json", "uuid/serde"] untested = ["sha2"] usb = ["rusb"] +yubihsm-auth = ["yubikey"] [package.metadata.docs.rs] all-features = true diff --git a/src/client.rs b/src/client.rs index 310f15f2..c3cfb9d4 100644 --- a/src/client.rs +++ b/src/client.rs @@ -43,6 +43,9 @@ use std::{ #[cfg(feature = "passwords")] use std::{thread, time::SystemTime}; +#[cfg(feature = "yubihsm-auth")] +use crate::session::PendingSession; + #[cfg(feature = "untested")] use { crate::{ @@ -106,6 +109,20 @@ impl Client { Ok(client) } + /// Open session with YubiHSM Auth scheme + #[cfg(feature = "yubihsm-auth")] + pub fn yubihsm_auth( + connector: Connector, + authentication_key_id: object::Id, + host_challenge: session::securechannel::Challenge, + ) -> Result { + let timeout = session::Timeout::default(); + + let session = + PendingSession::new(connector, timeout, authentication_key_id, host_challenge)?; + Ok(session) + } + /// Borrow this client's YubiHSM connector (which is `Clone`able) pub fn connector(&self) -> &Connector { &self.connector @@ -1130,3 +1147,15 @@ impl Client { .0) } } + +impl From for Client { + fn from(session: Session) -> Self { + let connector = session.connector(); + let session = Arc::new(Mutex::new(Some(session))); + Self { + connector, + session, + credentials: None, + } + } +} diff --git a/src/session.rs b/src/session.rs index 6bd14231..883c4c7d 100644 --- a/src/session.rs +++ b/src/session.rs @@ -17,6 +17,7 @@ pub use self::{ error::{Error, ErrorKind}, guard::Guard, id::Id, + securechannel::{Challenge, Context, SessionKeys}, timeout::Timeout, }; @@ -30,6 +31,9 @@ use crate::{ }; use std::time::{Duration, Instant}; +#[cfg(feature = "yubihsm-auth")] +use crate::object; + /// Timeout fuzz factor: to avoid races/skew with the YubiHSM's clock, /// we consider sessions to be timed out slightly earlier than the actual /// timeout. This should (hopefully) ensure we always time out first, @@ -37,6 +41,98 @@ use std::time::{Duration, Instant}; /// than opaque "lost connection to HSM"-style errors. const TIMEOUT_FUZZ_FACTOR: Duration = Duration::from_secs(1); +/// Session created on the device for which we do not +/// have credentials for yet. +/// +/// This is used for YubiHSM Auth scheme support. +#[cfg(feature = "yubihsm-auth")] +pub struct PendingSession { + ///// HSM Public key + //card_public_key: PublicKey, + /// Connector which communicates with the HSM (HTTP or USB) + connector: Connector, + + /// Session creation timestamp + created_at: Instant, + + /// Timestamp when this session was last active + last_active: Instant, + + /// Inactivity timeout for this session + timeout: Timeout, + + /// Challenge generate by the HSM. + hsm_challenge: Challenge, + + /// ID for this session + id: Id, + + context: Context, +} + +#[cfg(feature = "yubihsm-auth")] +impl PendingSession { + /// Creates a new session with the device. + pub fn new( + connector: Connector, + timeout: Timeout, + authentication_key_id: object::Id, + host_challenge: Challenge, + ) -> Result { + let (id, session_response) = + SecureChannel::create(&connector, authentication_key_id, host_challenge)?; + + let hsm_challenge = session_response.card_challenge; + let context = Context::from_challenges(host_challenge, hsm_challenge); + + let created_at = Instant::now(); + let last_active = Instant::now(); + + Ok(PendingSession { + id, + connector, + created_at, + last_active, + timeout, + context, + hsm_challenge, + }) + } + + /// Create the session with the provided session keys + pub fn realize(self, session_keys: SessionKeys) -> Result { + let secure_channel = Some(SecureChannel::with_session_keys( + self.id, + self.context, + session_keys, + )); + + let mut session = Session { + id: self.id, + secure_channel, + connector: self.connector, + created_at: self.created_at, + last_active: self.last_active, + timeout: self.timeout, + }; + + let response = session.start_authenticate()?; + session.finish_authenticate_session(&response)?; + + Ok(session) + } + + /// Return the challenge emitted by the HSM when opening the session + pub fn get_challenge(&self) -> Challenge { + self.hsm_challenge + } + + /// Return the id of the session + pub fn id(&self) -> Id { + self.id + } +} + /// Authenticated and encrypted (SCP03) `Session` with the HSM. A `Session` is /// needed to perform any command. /// @@ -247,13 +343,9 @@ impl Session { credentials.authentication_key_id ); - let command = self.secure_channel()?.authenticate_session()?; - let response = self.send_message(command)?; + let response = self.start_authenticate()?; - if let Err(e) = self - .secure_channel()? - .finish_authenticate_session(&response) - { + if let Err(e) = self.finish_authenticate_session(&response) { session_error!( self, "failed={:?} key={} err={:?}", @@ -269,10 +361,26 @@ impl Session { Ok(()) } + /// Send the message to the card to start authentication + fn start_authenticate(&mut self) -> Result { + let command = self.secure_channel()?.authenticate_session()?; + self.send_message(command) + } + + /// Read authenticate session message from the card + fn finish_authenticate_session(&mut self, response: &response::Message) -> Result<(), Error> { + self.secure_channel()?.finish_authenticate_session(response) + } + /// Get the underlying channel or return an error fn secure_channel(&mut self) -> Result<&mut SecureChannel, Error> { self.secure_channel .as_mut() .ok_or_else(|| format_err!(ErrorKind::ClosedError, "session is already closed").into()) } + + /// Get the underlying connector used by this session + pub(crate) fn connector(&self) -> Connector { + self.connector.clone() + } } diff --git a/src/session/securechannel.rs b/src/session/securechannel.rs index 05c2e146..95dc3ea1 100644 --- a/src/session/securechannel.rs +++ b/src/session/securechannel.rs @@ -24,9 +24,9 @@ mod cryptogram; mod kdf; mod mac; +pub use self::{challenge::Challenge, context::Context}; pub(crate) use self::{ - challenge::{Challenge, CHALLENGE_SIZE}, - context::Context, + challenge::CHALLENGE_SIZE, cryptogram::{Cryptogram, CRYPTOGRAM_SIZE}, mac::Mac, }; @@ -35,7 +35,7 @@ use crate::{ authentication::{self, Credentials}, command, connector::Connector, - device, response, + device, object, response, serialization::deserialize, session::{self, ErrorKind}, }; @@ -47,6 +47,7 @@ use aes::{ Aes128, }; use cmac::{digest::Mac as _, Cmac}; +use serde::Serialize; use subtle::ConstantTimeEq; use zeroize::{Zeroize, Zeroizing}; @@ -70,6 +71,42 @@ const AES_BLOCK_SIZE: usize = 16; type Aes128CbcEnc = cbc::Encryptor; type Aes128CbcDec = cbc::Decryptor; +/// SCP03 AES Session Keys +#[derive(Serialize)] +pub struct SessionKeys { + /// Session encryption key (S-ENC) + pub enc_key: [u8; KEY_SIZE], + + /// Session Command MAC key (S-MAC) + pub mac_key: [u8; KEY_SIZE], + + /// Session Respose MAC key (S-RMAC) + pub rmac_key: [u8; KEY_SIZE], +} + +impl Zeroize for SessionKeys { + fn zeroize(&mut self) { + self.enc_key.zeroize(); + self.mac_key.zeroize(); + self.rmac_key.zeroize(); + } +} + +#[cfg(feature = "yubihsm-auth")] +impl From for SessionKeys { + fn from(keys: yubikey::hsmauth::SessionKeys) -> Self { + let enc_key = *keys.enc_key; + let mac_key = *keys.mac_key; + let rmac_key = *keys.rmac_key; + + Self { + enc_key, + mac_key, + rmac_key, + } + } +} + /// SCP03 Secure Channel pub(crate) struct SecureChannel { /// ID of this channel (a.k.a. session ID) @@ -85,14 +122,8 @@ pub(crate) struct SecureChannel { /// Context (card + host challenges) context: Context, - /// Session encryption key (S-ENC) - enc_key: [u8; KEY_SIZE], - - /// Session Command MAC key (S-MAC) - mac_key: [u8; KEY_SIZE], - - /// Session Respose MAC key (S-RMAC) - rmac_key: [u8; KEY_SIZE], + /// Session keys + session_keys: SessionKeys, /// Chaining value to be included when computing MACs mac_chaining_value: [u8; Mac::BYTE_SIZE * 2], @@ -107,45 +138,8 @@ impl SecureChannel { ) -> Result { let host_challenge = Challenge::new(); - let command_message = command::Message::from(&CreateSessionCommand { - authentication_key_id: credentials.authentication_key_id, - host_challenge, - }); - - let uuid = command_message.uuid; - let response_body = connector.send_message(uuid, command_message.into())?; - let response_message = response::Message::parse(response_body)?; - - if response_message.is_err() { - match device::ErrorKind::from_response_message(&response_message) { - Some(device::ErrorKind::ObjectNotFound) => fail!( - ErrorKind::AuthenticationError, - "auth key not found: 0x{:04x}", - credentials.authentication_key_id - ), - Some(kind) => return Err(kind.into()), - None => fail!( - ErrorKind::ResponseError, - "HSM error: {:?}", - response_message.code - ), - } - } - - if response_message.command().unwrap() != command::Code::CreateSession { - fail!( - ErrorKind::ProtocolError, - "command type mismatch: expected {:?}, got {:?}", - command::Code::CreateSession, - response_message.command().unwrap() - ); - } - - let id = response_message - .session_id - .ok_or_else(|| format_err!(ErrorKind::CreateFailed, "no session ID in response"))?; - - let session_response: CreateSessionResponse = deserialize(response_message.data.as_ref())?; + let (id, session_response) = + Self::create(connector, credentials.authentication_key_id, host_challenge)?; // Derive session keys from the combination of host and card challenges. // If either of them are incorrect (indicating a key mismatch) it will @@ -185,6 +179,20 @@ impl SecureChannel { let enc_key = derive_key(authentication_key.enc_key(), 0b100, &context); let mac_key = derive_key(authentication_key.mac_key(), 0b110, &context); let rmac_key = derive_key(authentication_key.mac_key(), 0b111, &context); + + let session_keys = SessionKeys { + enc_key, + mac_key, + rmac_key, + }; + Self::with_session_keys(id, context, session_keys) + } + + pub(crate) fn with_session_keys( + id: session::Id, + context: Context, + session_keys: SessionKeys, + ) -> Self { let mac_chaining_value = [0u8; Mac::BYTE_SIZE * 2]; Self { @@ -192,13 +200,62 @@ impl SecureChannel { counter: 0, security_level: SecurityLevel::None, context, - enc_key, - mac_key, - rmac_key, + session_keys, mac_chaining_value, } } + /// Open a SecureChannel with the HSM. This will not complete authentication. + /// + /// This will return the session id as well as the card challenge. + pub(crate) fn create( + connector: &Connector, + authentication_key_id: object::Id, + host_challenge: Challenge, + ) -> Result<(session::Id, CreateSessionResponse), session::Error> { + let command_message = command::Message::from(&CreateSessionCommand { + authentication_key_id, //: credentials.authentication_key_id, + host_challenge, + }); + + let uuid = command_message.uuid; + let response_body = connector.send_message(uuid, command_message.into())?; + let response_message = response::Message::parse(response_body)?; + + if response_message.is_err() { + match device::ErrorKind::from_response_message(&response_message) { + Some(device::ErrorKind::ObjectNotFound) => fail!( + ErrorKind::AuthenticationError, + "auth key not found: 0x{:04x}", + authentication_key_id + ), + Some(kind) => return Err(kind.into()), + None => fail!( + ErrorKind::ResponseError, + "HSM error: {:?}", + response_message.code + ), + } + } + + if response_message.command().unwrap() != command::Code::CreateSession { + fail!( + ErrorKind::ProtocolError, + "command type mismatch: expected {:?}, got {:?}", + command::Code::CreateSession, + response_message.command().unwrap() + ); + } + + let id = response_message + .session_id + .ok_or_else(|| format_err!(ErrorKind::CreateFailed, "no session ID in response"))?; + + let session_response: CreateSessionResponse = deserialize(response_message.data.as_ref())?; + + Ok((id, session_response)) + } + /// Get the channel (i.e. session) ID pub fn id(&self) -> session::Id { self.id @@ -207,14 +264,24 @@ impl SecureChannel { /// Calculate the card's cryptogram for this session pub fn card_cryptogram(&self) -> Cryptogram { let mut result_bytes = Zeroizing::new([0u8; CRYPTOGRAM_SIZE]); - kdf::derive(&self.mac_key, 0, &self.context, result_bytes.as_mut()); + kdf::derive( + &self.session_keys.mac_key, + 0, + &self.context, + result_bytes.as_mut(), + ); Cryptogram::from_slice(result_bytes.as_ref()) } /// Calculate the host's cryptogram for this session pub fn host_cryptogram(&self) -> Cryptogram { let mut result_bytes = Zeroizing::new([0u8; CRYPTOGRAM_SIZE]); - kdf::derive(&self.mac_key, 1, &self.context, result_bytes.as_mut()); + kdf::derive( + &self.session_keys.mac_key, + 1, + &self.context, + result_bytes.as_mut(), + ); Cryptogram::from_slice(result_bytes.as_ref()) } @@ -233,7 +300,8 @@ impl SecureChannel { ); } - let mut mac = as KeyInit>::new_from_slice(self.mac_key.as_ref()).unwrap(); + let mut mac = + as KeyInit>::new_from_slice(self.session_keys.mac_key.as_ref()).unwrap(); mac.update(&self.mac_chaining_value); mac.update(&[command_type.to_u8()]); @@ -298,7 +366,7 @@ impl SecureChannel { // Provide space at the end of the vec for the padding message.extend_from_slice(&[0u8; AES_BLOCK_SIZE]); - let cipher = Aes128::new_from_slice(&self.enc_key).unwrap(); + let cipher = Aes128::new_from_slice(&self.session_keys.enc_key).unwrap(); let icv = compute_icv(&cipher, self.counter); let cbc_encryptor = Aes128CbcEnc::inner_iv_init(cipher, &icv); let ciphertext = cbc_encryptor @@ -315,7 +383,7 @@ impl SecureChannel { ) -> Result { assert_eq!(self.security_level, SecurityLevel::Authenticated); - let cipher = Aes128::new_from_slice(&self.enc_key).unwrap(); + let cipher = Aes128::new_from_slice(&self.session_keys.enc_key).unwrap(); let icv = compute_icv(&cipher, self.counter); self.verify_response_mac(&encrypted_response)?; @@ -364,7 +432,8 @@ impl SecureChannel { ); } - let mut mac = as KeyInit>::new_from_slice(self.rmac_key.as_ref()).unwrap(); + let mut mac = + as KeyInit>::new_from_slice(self.session_keys.rmac_key.as_ref()).unwrap(); mac.update(&self.mac_chaining_value); mac.update(&[response.code.to_u8()]); @@ -441,12 +510,12 @@ impl SecureChannel { ) -> Result { assert_eq!(self.security_level, SecurityLevel::Authenticated); - let cipher = Aes128::new_from_slice(&self.enc_key).unwrap(); + let cipher = Aes128::new_from_slice(&self.session_keys.enc_key).unwrap(); let icv = compute_icv(&cipher, self.counter); self.verify_command_mac(&encrypted_command)?; - let cipher = Aes128::new_from_slice(&self.enc_key).unwrap(); + let cipher = Aes128::new_from_slice(&self.session_keys.enc_key).unwrap(); let cbc_decryptor = Aes128CbcDec::inner_iv_init(cipher, &icv); let mut command_data = encrypted_command.data; @@ -479,7 +548,8 @@ impl SecureChannel { command.session_id ); - let mut mac = as KeyInit>::new_from_slice(self.mac_key.as_ref()).unwrap(); + let mut mac = + as KeyInit>::new_from_slice(self.session_keys.mac_key.as_ref()).unwrap(); mac.update(&self.mac_chaining_value); mac.update(&[command.command_type.to_u8()]); @@ -519,7 +589,7 @@ impl SecureChannel { // Provide space at the end of the vec for the padding message.extend_from_slice(&[0u8; AES_BLOCK_SIZE]); - let cipher = Aes128::new_from_slice(&self.enc_key).unwrap(); + let cipher = Aes128::new_from_slice(&self.session_keys.enc_key).unwrap(); let icv = compute_icv(&cipher, self.counter); let cbc_encryptor = Aes128CbcEnc::inner_iv_init(cipher, &icv); @@ -548,7 +618,8 @@ impl SecureChannel { assert_eq!(self.security_level, SecurityLevel::Authenticated); let body = response_data.into(); - let mut mac = as KeyInit>::new_from_slice(self.rmac_key.as_ref()).unwrap(); + let mut mac = + as KeyInit>::new_from_slice(self.session_keys.rmac_key.as_ref()).unwrap(); mac.update(&self.mac_chaining_value); mac.update(&[code.to_u8()]); @@ -584,9 +655,7 @@ impl SecureChannel { /// Terminate the session fn terminate(&mut self) { self.security_level = SecurityLevel::Terminated; - self.enc_key.zeroize(); - self.mac_key.zeroize(); - self.rmac_key.zeroize(); + self.session_keys.zeroize(); } } diff --git a/src/session/securechannel/challenge.rs b/src/session/securechannel/challenge.rs index dc03c4ee..3069bb8f 100644 --- a/src/session/securechannel/challenge.rs +++ b/src/session/securechannel/challenge.rs @@ -3,6 +3,9 @@ use rand_core::{OsRng, RngCore}; use serde::{Deserialize, Serialize}; +#[cfg(feature = "yubihsm-auth")] +use crate::session::error::{Error, ErrorKind}; + /// Size of a challenge message pub const CHALLENGE_SIZE: usize = 8; @@ -35,4 +38,41 @@ impl Challenge { pub fn as_slice(&self) -> &[u8] { &self.0 } + + /// Creates `Challenge` from a `yubikey::hsmauth::Challenge`. + /// + /// `YubiKey` firmware 5.4.3 will generate an empty challenge, this will + /// generate one from RNG if we're provided an empty challenge + // Note(baloo): because of the side-effect described above, this is not + // made a regular From. + #[cfg(feature = "yubihsm-auth")] + pub fn from_yubikey_challenge(yc: yubikey::hsmauth::Challenge) -> Self { + if yc.is_empty() { + Self::new() + } else { + let mut challenge = [0u8; CHALLENGE_SIZE]; + challenge.copy_from_slice(yc.as_slice()); + Challenge(challenge) + } + } +} + +#[cfg(feature = "yubihsm-auth")] +impl TryFrom for yubikey::hsmauth::Challenge { + type Error = Error; + + fn try_from(c: Challenge) -> Result { + let mut challenge = yubikey::hsmauth::Challenge::default(); + challenge + .copy_from_slice(c.as_slice()) + .map_err(|e| Error::from(ErrorKind::ProtocolError.context(e)))?; + + Ok(challenge) + } +} + +impl Default for Challenge { + fn default() -> Self { + Self::new() + } } diff --git a/src/session/securechannel/context.rs b/src/session/securechannel/context.rs index 1a50769c..e84a34d1 100644 --- a/src/session/securechannel/context.rs +++ b/src/session/securechannel/context.rs @@ -22,3 +22,10 @@ impl Context { &self.0 } } + +#[cfg(feature = "yubihsm-auth")] +impl From for yubikey::hsmauth::Context { + fn from(context: Context) -> Self { + Self::from_buf(context.0) + } +}