diff --git a/.github/workflows/config_check.yml b/.github/workflows/config_check.yml index 35e66fe1..3af19a5a 100644 --- a/.github/workflows/config_check.yml +++ b/.github/workflows/config_check.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Install Protoc - uses: arduino/setup-protoc@v1 + uses: arduino/setup-protoc@v3 - uses: actions/checkout@v2 - name: Install libpcsc run: sudo apt install -y libpcsclite-dev libusb-1.0-0-dev libudev-dev diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 7e4a2074..146c5719 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Install Protoc - uses: arduino/setup-protoc@v1 + uses: arduino/setup-protoc@v3 - uses: actions/checkout@v2 - name: Install libpcsc run: sudo apt install -y libpcsclite-dev libusb-1.0-0-dev libudev-dev diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d434d1a7..ea9f0070 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Install Protoc - uses: arduino/setup-protoc@v1 + uses: arduino/setup-protoc@v3 - uses: actions/checkout@v2 - name: Build run: cargo build --package=rustica --features=all @@ -25,7 +25,7 @@ jobs: steps: - name: Install Protoc - uses: arduino/setup-protoc@v1 + uses: arduino/setup-protoc@v3 - uses: actions/checkout@v2 - name: Build run: cargo build --package=rustica --features=splunk @@ -35,7 +35,7 @@ jobs: steps: - name: Install Protoc - uses: arduino/setup-protoc@v1 + uses: arduino/setup-protoc@v3 - uses: actions/checkout@v2 - name: Build run: cargo build --package=rustica --features=influx @@ -45,7 +45,7 @@ jobs: steps: - name: Install Protoc - uses: arduino/setup-protoc@v1 + uses: arduino/setup-protoc@v3 - uses: actions/checkout@v2 - name: Build run: cargo build --package=rustica --features=local-db @@ -55,7 +55,7 @@ jobs: steps: - name: Install Protoc - uses: arduino/setup-protoc@v1 + uses: arduino/setup-protoc@v3 - uses: actions/checkout@v2 - name: Build run: cargo build --package=rustica --features=amazon-kms @@ -65,7 +65,7 @@ jobs: steps: - name: Install Protoc - uses: arduino/setup-protoc@v1 + uses: arduino/setup-protoc@v3 - uses: actions/checkout@v2 - name: Build run: cargo build --package=rustica --features="splunk,influx,local-db,amazon-kms" \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 74ad00cd..1e6ccb5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ab_glyph" -version = "0.2.23" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80179d7dd5d7e8c285d67c4a1e652972a92de7475beddfb92028c76463b13225" +checksum = "6f90148830dac590fac7ccfe78ec4a8ea404c60f75a24e16407a71f0f40de775" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -41,7 +41,7 @@ checksum = "134d0acf6acb667c89d3332999b1a5df4edbc8d6113910f392ebb73f2b03bb56" dependencies = [ "accesskit", "accesskit_consumer", - "objc2", + "objc2 0.3.0-beta.3.patch-leaks.3", "once_cell", ] @@ -53,7 +53,7 @@ checksum = "e084cb5168790c0c112626175412dc5ad127083441a8248ae49ddf6725519e83" dependencies = [ "accesskit", "accesskit_consumer", - "async-channel", + "async-channel 1.9.0", "atspi", "futures-lite 1.13.0", "serde", @@ -104,20 +104,33 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aes" -version = "0.8.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if", - "cipher", + "cipher 0.3.0", + "cpufeatures", + "ctr", + "opaque-debug", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher 0.4.4", "cpufeatures", ] [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "once_cell", @@ -127,13 +140,19 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "android-activity" version = "0.4.3" @@ -175,24 +194,22 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" [[package]] name = "arboard" -version = "3.2.1" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac57f2b058a76363e357c056e4f74f1945bf734d37b8b3ef49066c4787dde0fc" +checksum = "9fb4009533e8ff8f1450a5bcbc30f4242a1d34442221f72314bea1f5dc9c7f89" dependencies = [ "clipboard-win", "log", - "objc", - "objc-foundation", - "objc_id", + "objc2 0.5.1", + "objc2-app-kit", + "objc2-foundation", "parking_lot", - "thiserror", - "winapi", "x11rb", ] @@ -229,8 +246,24 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", + "asn1-rs-derive 0.4.0", + "asn1-rs-impl 0.1.0", + "displaydoc", + "nom 7.1.3", + "num-traits", + "rusticata-macros 4.1.0", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d" +dependencies = [ + "asn1-rs-derive 0.5.0", + "asn1-rs-impl 0.2.0", "displaydoc", "nom 7.1.3", "num-traits", @@ -248,7 +281,19 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.109", - "synstructure", + "synstructure 0.12.6", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", + "synstructure 0.13.1", ] [[package]] @@ -262,6 +307,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "asn1_derive" version = "0.14.0" @@ -270,7 +326,7 @@ checksum = "ee4d9abdcc064cc9568bff2599089bb497a7de2c4b59608de35e3380b496617a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] @@ -294,17 +350,29 @@ dependencies = [ "futures-core", ] +[[package]] +name = "async-channel" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d4d23bcc79e27423727b36823d86233aad06dfea531837b038394d11e9928" +dependencies = [ + "concurrent-queue", + "event-listener 5.3.0", + "event-listener-strategy 0.5.2", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-executor" -version = "1.6.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0c4a4f319e45986f347ee47fef8bf5e81c9abc3f6f58dc2391439f30df65f0" +checksum = "b10202063978b3351199d68f8b22c4e47e4b1b822f8d43fd862d5ea8c006b29a" dependencies = [ - "async-lock 2.8.0", "async-task", "concurrent-queue", - "fastrand 2.0.1", - "futures-lite 1.13.0", + "fastrand 2.1.0", + "futures-lite 2.3.0", "slab", ] @@ -342,22 +410,21 @@ dependencies = [ [[package]] name = "async-io" -version = "2.2.0" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9d5715c2d329bf1b4da8d60455b99b187f27ba726df2883799af9af60997" +checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" dependencies = [ - "async-lock 3.0.0", + "async-lock 3.3.0", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.0.1", + "futures-lite 2.3.0", "parking", - "polling 3.3.0", - "rustix 0.38.21", + "polling 3.7.0", + "rustix 0.38.34", "slab", "tracing", - "waker-fn", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -371,12 +438,12 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.0.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e900cdcd39bb94a14487d3f7ef92ca222162e6c7c3fe7cb3550ea75fb486ed" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" dependencies = [ - "event-listener 3.0.1", - "event-listener-strategy", + "event-listener 4.0.3", + "event-listener-strategy 0.4.0", "pin-project-lite", ] @@ -391,39 +458,39 @@ dependencies = [ "async-signal", "blocking", "cfg-if", - "event-listener 3.0.1", + "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.38.21", + "rustix 0.38.34", "windows-sys 0.48.0", ] [[package]] name = "async-recursion" -version = "1.0.5" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] name = "async-signal" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5" +checksum = "afe66191c335039c7bb78f99dc7520b0cbb166b3a1cb33a03f53d8a1c6f2afda" dependencies = [ - "async-io 2.2.0", - "async-lock 2.8.0", + "async-io 2.3.2", + "async-lock 3.3.0", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 0.38.21", + "rustix 0.38.34", "signal-hook-registry", "slab", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -445,24 +512,24 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] name = "async-task" -version = "4.5.0" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] @@ -515,17 +582,44 @@ dependencies = [ "winapi", ] +[[package]] +name = "authenticator" +version = "0.4.0-alpha.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be346361f2602704c3a48d71530df852a59558b9774a144432d91fdfe775f298" +dependencies = [ + "base64 0.21.7", + "bitflags 1.3.2", + "cfg-if", + "core-foundation", + "devd-rs", + "libc", + "libudev", + "log", + "memoffset 0.8.0", + "openssl", + "openssl-sys", + "rand", + "runloop", + "serde", + "serde_bytes", + "serde_cbor", + "serde_json", + "sha2 0.10.8", + "winapi", +] + [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "aws-config" -version = "0.57.1" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7489a72550db3712fe3a0a92068f832d6270ff82f518b84a800af131f99570d7" +checksum = "f2bf00cb9416daab4ce4927c54ebe63c08b9caf4d7b9314b6d7a4a2c5a1afb09" dependencies = [ "aws-credential-types", "aws-http", @@ -541,11 +635,11 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes", - "fastrand 2.0.1", + "fastrand 2.1.0", "hex", "http", "hyper", - "ring 0.17.5", + "ring 0.17.8", "time", "tokio", "tracing", @@ -554,9 +648,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "0.57.1" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80009846d61a0a4f9070d789cf0e64db284cba6984fae3871050d044e6569cd2" +checksum = "cb9073c88dbf12f68ce7d0e149f989627a1d1ae3d2b680459f04ccc29d1cbd0f" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -566,9 +660,9 @@ dependencies = [ [[package]] name = "aws-http" -version = "0.57.1" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e65730b741a5f6422fd338bf6f76b7956b090affeaa045e78fca8c4186e0fd5" +checksum = "24067106d09620cf02d088166cdaedeaca7146d4d499c41b37accecbea11b246" dependencies = [ "aws-smithy-http", "aws-smithy-runtime-api", @@ -583,9 +677,9 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "0.57.1" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2414b96071ae840b97c0cc1d44b248d5607d648593cdf474f3fb5465572898" +checksum = "fc6ee0152c06d073602236a4e94a8c52a327d310c1ecd596570ce795af8777ff" dependencies = [ "aws-credential-types", "aws-http", @@ -595,7 +689,7 @@ dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", - "fastrand 2.0.1", + "fastrand 2.1.0", "http", "percent-encoding", "tracing", @@ -626,9 +720,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "341a5b00567d0f350025501c8fd36e1ca8055744a2d17e351f0b254f84eba48a" +checksum = "2eb8158015232b4596ccef74a205600398e152d704b40b7ec9f486092474d7fa" dependencies = [ "aws-credential-types", "aws-http", @@ -648,9 +742,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbd4bffbd26f66269933bcd26123f2d6860769c0f769b6d3fc10eda025d287d8" +checksum = "36a1493e1c57f173e53621935bfb5b6217376168dbdb4cd459aebcf645924a48" dependencies = [ "aws-credential-types", "aws-http", @@ -670,9 +764,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b1a8ae5c7098502a3e6d4130dbee1e1d3fcb8dc5d65cecab39e01d595f90f6" +checksum = "e032b77f5cd1dd3669d777a38ac08cbf8ec68e29460d4ef5d3e50cffa74ec75a" dependencies = [ "aws-credential-types", "aws-http", @@ -693,9 +787,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "0.57.1" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3347c738e0a8449020877d319cda56da74d6e8aba9fff210720fac66cae3c7f4" +checksum = "64f81a6abc4daab06b53cabf27c54189928893283093e37164ca53aa47488a5b" dependencies = [ "aws-credential-types", "aws-smithy-http", @@ -715,9 +809,9 @@ dependencies = [ [[package]] name = "aws-smithy-async" -version = "0.57.1" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b65a284265d3eec6cc9f1daef2d0cc3b78684b712cb6c7f1d0f665456b7604" +checksum = "dbe53fccd3b10414b9cae63767a15a2789b34e6c6727b6e32b33e8c7998a3e80" dependencies = [ "futures-util", "pin-project-lite", @@ -726,9 +820,9 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.57.1" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715aeb61fb743848d5d398ce6fb1259f5eba5e13dceec5d5064cada1a181d38d" +checksum = "f7972373213d1d6e619c0edc9dda2d6634154e4ed75c5e0b2bf065cd5ec9f0d1" dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", @@ -746,18 +840,18 @@ dependencies = [ [[package]] name = "aws-smithy-json" -version = "0.57.1" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de21d368dcd5cab17033406ea6e7351b091164b208381de837510bd7558c0f30" +checksum = "b6d64d5af16dd585de9ff6c606423c1aaad47c6baa38de41c2beb32ef21c6645" dependencies = [ "aws-smithy-types", ] [[package]] name = "aws-smithy-query" -version = "0.57.1" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5ace389c7e4def130bff7275647481c8d49b867909ca61d5dc9a809b3632f3" +checksum = "7527bf5335154ba1b285479c50b630e44e93d1b4a759eaceb8d0bf9fbc82caa5" dependencies = [ "aws-smithy-types", "urlencoding", @@ -765,16 +859,16 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "0.57.1" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4395310662d10f1847324af5fe43e621922cba03b1aa6d26c21096e18a4e79" +checksum = "839b363adf3b2bdab2742a1f540fec23039ea8bc9ec0f9f61df48470cfe5527b" dependencies = [ "aws-smithy-async", "aws-smithy-http", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", - "fastrand 2.0.1", + "fastrand 2.1.0", "http", "http-body", "hyper", @@ -789,9 +883,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "0.57.1" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e27594c06f5b36e97d18ef26ed693f1d4c7167b9bbb544b3a9bb653f9f7035" +checksum = "f24ecc446e62c3924539e7c18dec8038dba4fdf8718d5c2de62f9d2fecca8ba9" dependencies = [ "aws-smithy-async", "aws-smithy-types", @@ -805,9 +899,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "0.57.1" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d36f1723ed61e82094498e7283510fe21484b73c215c33874c81a84411b5bdc" +checksum = "051de910296522a21178a2ea402ea59027eef4b63f1cef04a0be2bb5e25dea03" dependencies = [ "base64-simd", "bytes", @@ -828,18 +922,18 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.57.1" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68225c8d3e3e6c565a3cf764aa82440837ef15c33d1dd7205e15715444e4b4ad" +checksum = "cb1e3ac22c652662096c8e37a6f9af80c6f3520cab5610b2fe76c725bce18eac" dependencies = [ "xmlparser", ] [[package]] name = "aws-types" -version = "0.57.1" +version = "0.57.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdc27aac60f715bab25f5d758ba5651b80aae791c48e9871ffe298683f00a2b" +checksum = "048bbf1c24cdf4eb1efcdc243388a93a90ebf63979e25fc1c7b8cbd9cb6beb38" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -897,9 +991,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -930,9 +1024,15 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.5" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64-simd" @@ -950,6 +1050,19 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bcrypt-pbkdf" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12621b8e87feb183a6e5dbb315e49026b2229c4398797ee0ae2d1bc00aef41b9" +dependencies = [ + "blowfish", + "crypto-mac", + "pbkdf2 0.8.0", + "sha2 0.9.9", + "zeroize", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -958,9 +1071,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bitvec" @@ -1013,7 +1126,7 @@ version = "0.1.0-beta.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146" dependencies = [ - "objc-sys", + "objc-sys 0.2.0-beta.2", ] [[package]] @@ -1023,49 +1136,67 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42" dependencies = [ "block-sys", - "objc2-encode", + "objc2-encode 2.0.0-pre.2", +] + +[[package]] +name = "block2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ff7d91d3c1d568065b06c899777d1e48dcf76103a672a0adbc238a7f247f1e" +dependencies = [ + "objc2 0.5.1", ] [[package]] name = "blocking" -version = "1.4.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c36a4d0d48574b3dd360b4b7d95cc651d2b6557b6402848a27d4b228a473e2a" +checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" dependencies = [ - "async-channel", - "async-lock 2.8.0", + "async-channel 2.2.1", + "async-lock 3.3.0", "async-task", - "fastrand 2.0.1", "futures-io", - "futures-lite 1.13.0", + "futures-lite 2.3.0", "piper", - "tracing", +] + +[[package]] +name = "blowfish" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe3ff3fc1de48c1ac2e3341c4df38b0d1bfb8fdf04632a187c8b75aaa319a7ab" +dependencies = [ + "byteorder", + "cipher 0.3.0", + "opaque-debug", ] [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] @@ -1076,15 +1207,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bytes-utils" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e47d3a8076e283f3acd27400535992edb3ba4b5bb72f8891ad8fbe7932a7d4b9" +checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" dependencies = [ "bytes", "either", @@ -1110,17 +1241,18 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" dependencies = [ - "cipher", + "cipher 0.4.4", ] [[package]] name = "cc" -version = "1.0.83" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" dependencies = [ "jobserver", "libc", + "once_cell", ] [[package]] @@ -1152,9 +1284,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1162,7 +1294,16 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.48.5", + "windows-targets 0.52.5", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", ] [[package]] @@ -1201,13 +1342,11 @@ dependencies = [ [[package]] name = "clipboard-win" -version = "4.5.0" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362" +checksum = "79f4473f5144e20d9aceaf2972478f06ddf687831eafeeb434fbaf0acc4144ad" dependencies = [ "error-code", - "str-buf", - "winapi", ] [[package]] @@ -1248,9 +1387,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "combine" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", "memchr", @@ -1258,30 +1397,33 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cookie-factory" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" +checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" +dependencies = [ + "futures", +] [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -1289,9 +1431,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "core-graphics" @@ -1308,9 +1450,9 @@ dependencies = [ [[package]] name = "core-graphics-types" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -1319,40 +1461,36 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crypto-bigint" @@ -1376,34 +1514,53 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "ctap-hid-fido2" -version = "3.5.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3726fa3f7f978ce0a222ea73c13490115f95e7a31db3061d7c4c91bea58ea01a" +checksum = "ee6473a333d82796d5b23529fde19386de33820ad19d368402f8e9de780e1723" dependencies = [ - "aes", + "aes 0.8.4", "anyhow", - "base64 0.21.5", + "base64 0.22.1", "byteorder", "cbc", "hex", "hidapi", "num", "pad", - "ring 0.16.20", + "ring 0.17.8", "serde", "serde_cbor", "strum", "strum_macros", - "x509-parser 0.15.1", + "x509-parser 0.16.0", +] + +[[package]] +name = "ctr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +dependencies = [ + "cipher 0.3.0", ] [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "der" @@ -1446,7 +1603,21 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" dependencies = [ - "asn1-rs", + "asn1-rs 0.5.2", + "displaydoc", + "nom 7.1.3", + "num-bigint", + "num-traits", + "rusticata-macros 4.1.0", +] + +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs 0.6.1", "displaydoc", "nom 7.1.3", "num-bigint", @@ -1456,9 +1627,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", ] @@ -1480,14 +1651,24 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" dependencies = [ - "cipher", + "cipher 0.4.4", +] + +[[package]] +name = "devd-rs" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9313f104b590510b46fc01c0a324fc76505c13871454d3c48490468d04c8d395" +dependencies = [ + "libc", + "nom 7.1.3", ] [[package]] name = "diesel" -version = "2.1.3" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2268a214a6f118fce1838edba3d1561cf0e78d8de785475957a580a7f8c69d33" +checksum = "ff236accb9a5069572099f0b350a92e9560e8e63a9b8d546162f4a5e03026bb2" dependencies = [ "diesel_derives", "libsqlite3-sys", @@ -1496,14 +1677,14 @@ dependencies = [ [[package]] name = "diesel_derives" -version = "2.1.2" +version = "2.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8337737574f55a468005a83499da720f20c65586241ffea339db9ecdfd2b44" +checksum = "14701062d6bed917b5c7103bdffaee1e4609279e240488ad24e7bd979ca6866c" dependencies = [ "diesel_table_macro_syntax", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] @@ -1512,7 +1693,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" dependencies = [ - "syn 2.0.39", + "syn 2.0.61", ] [[package]] @@ -1571,7 +1752,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] @@ -1580,14 +1761,14 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.1", + "libloading 0.8.3", ] [[package]] name = "downcast-rs" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "ecdsa" @@ -1685,9 +1866,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "elliptic-curve" @@ -1722,18 +1903,18 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] [[package]] name = "enumflags2" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5998b4f30320c9d93aed72f63af821bfdac50465b75428fce77b48ec482c3939" +checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d" dependencies = [ "enumflags2_derive", "serde", @@ -1741,13 +1922,13 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246" +checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] @@ -1788,23 +1969,19 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "error-code" -version = "2.3.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" -dependencies = [ - "libc", - "str-buf", -] +checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" [[package]] name = "event-listener" @@ -1814,9 +1991,31 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "3.0.1" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cec0252c2afff729ee6f00e903d479fba81784c8e2bd77447673471fdfaea1" +checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" dependencies = [ "concurrent-queue", "parking", @@ -1825,11 +2024,21 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.3.0" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.3", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96b852f1345da36d551b9473fa1e2b1eb5c5195585c6c018118bc92a8d91160" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener 3.0.1", + "event-listener 5.3.0", "pin-project-lite", ] @@ -1844,15 +2053,15 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fdeflate" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d6dafc854908ff5da46ff3f8f473c6984119a2876a383a860246dd7841a868" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" dependencies = [ "simd-adler32", ] @@ -1875,9 +2084,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -1906,9 +2115,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -1919,26 +2128,53 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", + "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-lite" @@ -1957,43 +2193,47 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.0.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ + "fastrand 2.1.0", "futures-core", + "futures-io", + "parking", "pin-project-lite", ] [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", @@ -2017,19 +2257,19 @@ dependencies = [ [[package]] name = "gethostname" -version = "0.2.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" dependencies = [ "libc", - "winapi", + "windows-targets 0.48.5", ] [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -2038,9 +2278,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "gl_generator" @@ -2080,7 +2320,7 @@ dependencies = [ "glutin_glx_sys", "glutin_wgl_sys", "libloading 0.7.4", - "objc2", + "objc2 0.3.0-beta.3.patch-leaks.3", "once_cell", "raw-window-handle", "wayland-sys 0.30.1", @@ -2142,9 +2382,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.21" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -2152,7 +2392,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -2161,9 +2401,9 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "hashbrown" @@ -2173,9 +2413,13 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] [[package]] name = "heck" @@ -2194,9 +2438,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -2218,9 +2462,9 @@ dependencies = [ [[package]] name = "hkdf" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac", ] @@ -2236,18 +2480,18 @@ dependencies = [ [[package]] name = "home" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "http" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f95b9abcae896730d42b78e09c155ed4ddf82c07b4de772c64aee5b2d8b7c150" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -2256,9 +2500,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -2285,9 +2529,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -2300,7 +2544,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2 0.5.7", "tokio", "tower-service", "tracing", @@ -2337,16 +2581,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -2360,9 +2604,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -2370,14 +2614,13 @@ dependencies = [ [[package]] name = "image" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" dependencies = [ "bytemuck", "byteorder", "color_quant", - "num-rational", "num-traits", "png", ] @@ -2394,12 +2637,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.2", + "hashbrown 0.14.5", ] [[package]] @@ -2447,7 +2690,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi 0.3.9", "libc", "windows-sys 0.48.0", ] @@ -2469,9 +2712,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jni" @@ -2497,18 +2740,18 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.65" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -2543,9 +2786,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.150" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libloading" @@ -2559,12 +2802,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-targets 0.52.5", ] [[package]] @@ -2575,36 +2818,55 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libredox" -version = "0.0.1" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "libc", "redox_syscall 0.4.1", ] [[package]] name = "libredox" -version = "0.0.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "libc", - "redox_syscall 0.4.1", ] [[package]] name = "libsqlite3-sys" -version = "0.26.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" +checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" dependencies = [ "pkg-config", "vcpkg", ] +[[package]] +name = "libudev" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea626d3bdf40a1c5aee3bcd4f40826970cae8d80a8fec934c82a63840094dcfe" +dependencies = [ + "libc", + "libudev-sys", +] + +[[package]] +name = "libudev-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" +dependencies = [ + "libc", + "pkg-config", +] + [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -2613,15 +2875,15 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -2629,9 +2891,18 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "lru" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +dependencies = [ + "hashbrown 0.14.5", +] [[package]] name = "mac-notification-sys" @@ -2663,9 +2934,9 @@ checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memmap2" @@ -2694,6 +2965,24 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" @@ -2714,9 +3003,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", "simd-adler32", @@ -2724,9 +3013,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.9" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", @@ -2837,9 +3126,9 @@ dependencies = [ [[package]] name = "notify-rust" -version = "4.9.0" +version = "4.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7b75c8958cb2eab3451538b32db8a7b74006abc33eb2e6a9a56d21e4775c2b" +checksum = "827c5edfa80235ded4ab3fe8e9dc619b4f866ef16fe9b1c6b8a7f8692c0f2226" dependencies = [ "log", "mac-notification-sys", @@ -2860,9 +3149,9 @@ dependencies = [ [[package]] name = "num" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ "num-bigint", "num-complex", @@ -2874,11 +3163,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -2903,28 +3191,33 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -2933,11 +3226,10 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", "num-bigint", "num-integer", "num-traits", @@ -2945,9 +3237,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -2959,7 +3251,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi 0.3.9", "libc", ] @@ -3002,7 +3294,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] @@ -3031,15 +3323,54 @@ version = "0.2.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7" +[[package]] +name = "objc-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da284c198fb9b7b0603f8635185e85fbd5b64ee154b1ed406d489077de2d6d60" + [[package]] name = "objc2" version = "0.3.0-beta.3.patch-leaks.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468" dependencies = [ - "block2", - "objc-sys", - "objc2-encode", + "block2 0.2.0-alpha.6", + "objc-sys 0.2.0-beta.2", + "objc2-encode 2.0.0-pre.2", +] + +[[package]] +name = "objc2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b25e1034d0e636cd84707ccdaa9f81243d399196b8a773946dcffec0401659" +dependencies = [ + "objc-sys 0.3.3", + "objc2-encode 4.0.1", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb79768a710a9a1798848179edb186d1af7e8a8679f369e4b8d201dd2a034047" +dependencies = [ + "block2 0.5.0", + "objc2 0.5.1", + "objc2-core-data", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e092bc42eaf30a08844e6a076938c60751225ec81431ab89f5d1ccd9f958d6c" +dependencies = [ + "block2 0.5.0", + "objc2 0.5.1", + "objc2-foundation", ] [[package]] @@ -3048,7 +3379,23 @@ version = "2.0.0-pre.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512" dependencies = [ - "objc-sys", + "objc-sys 0.2.0-beta.2", +] + +[[package]] +name = "objc2-encode" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88658da63e4cc2c8adb1262902cd6af51094df0488b760d6fd27194269c0950a" + +[[package]] +name = "objc2-foundation" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfaefe14254871ea16c7d88968c0ff14ba554712a20d76421eec52f0a7fb8904" +dependencies = [ + "block2 0.5.0", + "objc2 0.5.1", ] [[package]] @@ -3062,33 +3409,68 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "oid-registry" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" dependencies = [ - "memchr", + "asn1-rs 0.5.2", ] [[package]] name = "oid-registry" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" dependencies = [ - "asn1-rs", + "asn1-rs 0.6.1", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl" +version = "0.10.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] [[package]] name = "openssl-probe" @@ -3096,6 +3478,18 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-sys" +version = "0.9.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "orbclient" version = "0.3.47" @@ -3181,9 +3575,9 @@ checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", @@ -3191,22 +3585,31 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" +dependencies = [ + "crypto-mac", +] [[package]] name = "pbkdf2" @@ -3219,9 +3622,9 @@ dependencies = [ [[package]] name = "pcsc" -version = "2.8.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37cab0be9d04e808a8d8059fa54befcd71dc8b168f9f0c04bdb7e59832abbab4" +checksum = "45ed9d7f816b7d9ce9ddb0062dd2f393b3af31411a95a35411809b4b9116ea08" dependencies = [ "bitflags 1.3.2", "pcsc-sys", @@ -3229,20 +3632,20 @@ dependencies = [ [[package]] name = "pcsc-sys" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b7bfecba2c0f1b5efb0e7caf7533ab1c295024165bcbb066231f60d33e23ea" +checksum = "b09e9ba80f2c4d167f936d27594f7248bca3295921ffbfa44a24b339b6cb7403" dependencies = [ "pkg-config", ] [[package]] name = "pem" -version = "3.0.2" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3163d2912b7c3b52d651a055f2c7eec9ba5cd22d26ef75b8dd3a59980b185923" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" dependencies = [ - "base64 0.21.5", + "base64 0.22.1", "serde", ] @@ -3257,45 +3660,45 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap 2.2.6", ] [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -3310,7 +3713,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" dependencies = [ "atomic-waker", - "fastrand 2.0.1", + "fastrand 2.1.0", "futures-io", ] @@ -3338,15 +3741,15 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "png" -version = "0.17.10" +version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" dependencies = [ "bitflags 1.3.2", "crc32fast", @@ -3373,16 +3776,17 @@ dependencies = [ [[package]] name = "polling" -version = "3.3.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53b6af1f60f36f8c2ac2aad5459d75a5a9b4be1e8cdd40264f315d78193e531" +checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" dependencies = [ "cfg-if", "concurrent-queue", + "hermit-abi 0.3.9", "pin-project-lite", - "rustix 0.38.21", + "rustix 0.38.34", "tracing", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3419,9 +3823,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] @@ -3491,9 +3895,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -3571,22 +3975,31 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", - "libredox 0.0.1", + "libredox 0.1.3", "thiserror", ] [[package]] name = "regex" -version = "1.10.2" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -3596,9 +4009,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -3607,17 +4020,17 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -3639,6 +4052,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", "tokio-rustls", @@ -3679,16 +4093,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.5" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3712,11 +4127,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "runloop" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d79b4b604167921892e84afbbaad9d5ad74e091bf6c511d9dbfb0593f09fabd" + [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc_version" @@ -3729,7 +4150,7 @@ dependencies = [ [[package]] name = "rustica" -version = "0.11.1" +version = "0.12.0" dependencies = [ "asn1", "async-trait", @@ -3745,10 +4166,11 @@ dependencies = [ "hex", "influxdb", "log", + "lru", "prost", "rcgen", "reqwest", - "ring 0.17.5", + "ring 0.17.8", "serde", "serde_json", "sshcerts", @@ -3757,11 +4179,12 @@ dependencies = [ "tonic", "tonic-build", "x509-parser 0.15.1", + "zstd", ] [[package]] name = "rustica-agent" -version = "0.11.1" +version = "0.12.0" dependencies = [ "async-trait", "base64 0.12.3", @@ -3770,7 +4193,7 @@ dependencies = [ "hex", "log", "prost", - "ring 0.17.5", + "ring 0.17.8", "serde", "serde_derive", "sha2 0.9.9", @@ -3781,11 +4204,12 @@ dependencies = [ "tonic-build", "x509-parser 0.15.1", "yubikey", + "zstd", ] [[package]] name = "rustica-agent-cli" -version = "0.11.1" +version = "0.12.0" dependencies = [ "clap", "env_logger", @@ -3793,7 +4217,6 @@ dependencies = [ "log", "notify-rust", "rustica-agent", - "sshcerts", "tokio", "toml 0.7.8", "yubikey", @@ -3801,14 +4224,13 @@ dependencies = [ [[package]] name = "rustica-agent-gui" -version = "0.11.1" +version = "0.12.0" dependencies = [ "base64 0.12.3", "eframe", "hex", "home", "rustica-agent", - "sshcerts", "tokio", "toml 0.5.11", "tracing-subscriber", @@ -3848,25 +4270,25 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "errno", "libc", - "linux-raw-sys 0.4.11", - "windows-sys 0.48.0", + "linux-raw-sys 0.4.13", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.21.8" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring 0.17.5", + "ring 0.17.8", "rustls-webpki", "sct", ] @@ -3889,7 +4311,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", ] [[package]] @@ -3898,21 +4320,21 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.5", + "ring 0.17.8", "untrusted 0.9.0", ] [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -3925,11 +4347,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3950,7 +4372,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.5", + "ring 0.17.8", "untrusted 0.9.0", ] @@ -3992,11 +4414,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.2" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "core-foundation", "core-foundation-sys", "libc", @@ -4005,9 +4427,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", @@ -4015,19 +4437,28 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.192" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" dependencies = [ "serde_derive", ] +[[package]] +name = "serde_bytes" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +dependencies = [ + "serde", +] + [[package]] name = "serde_cbor" version = "0.11.2" @@ -4040,20 +4471,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -4062,20 +4493,20 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] name = "serde_spanned" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ "serde", ] @@ -4138,9 +4569,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -4184,18 +4615,18 @@ dependencies = [ [[package]] name = "slotmap" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" dependencies = [ "version_check", ] [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smithay-client-toolkit" @@ -4238,12 +4669,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -4270,17 +4701,22 @@ dependencies = [ [[package]] name = "sshcerts" -version = "0.12.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7180145a992df0e9705844dc7cddec09eca063a59ab5b8bb9761a3d1a224ce59" +checksum = "752ad8923d32fb5c117b8a9983266e294edc072401133720aa9af3959d63248d" dependencies = [ + "aes 0.7.5", + "authenticator", "base64 0.13.1", + "bcrypt-pbkdf", + "chrono", "ctap-hid-fido2", + "ctr", "der-parser 5.1.2", "minicbor", "num-bigint", "rcgen", - "ring 0.17.5", + "ring 0.17.8", "simple_asn1", "x509", "x509-parser 0.15.1", @@ -4294,12 +4730,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "str-buf" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" - [[package]] name = "strict-num" version = "0.1.1" @@ -4314,28 +4744,28 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.24.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" [[package]] name = "strum_macros" -version = "0.24.3" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" dependencies = [ "heck", "proc-macro2", "quote", "rustversion", - "syn 1.0.109", + "syn 2.0.61", ] [[package]] name = "subtle" -version = "2.5.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" @@ -4350,9 +4780,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" dependencies = [ "proc-macro2", "quote", @@ -4377,6 +4807,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -4416,57 +4857,56 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.1" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand 2.0.1", - "redox_syscall 0.4.1", - "rustix 0.38.21", - "windows-sys 0.48.0", + "fastrand 2.1.0", + "rustix 0.38.34", + "windows-sys 0.52.0", ] [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -4474,12 +4914,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.30" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", + "num-conv", "powerfmt", "serde", "time-core", @@ -4494,10 +4935,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] @@ -4543,9 +4985,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.34.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -4555,7 +4997,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "socket2 0.5.7", "tokio-macros", "windows-sys 0.48.0", ] @@ -4578,7 +5020,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] @@ -4593,9 +5035,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -4604,16 +5046,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -4652,7 +5093,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", @@ -4668,7 +5109,7 @@ dependencies = [ "async-stream", "async-trait", "axum", - "base64 0.21.5", + "base64 0.21.7", "bytes", "futures-core", "futures-util", @@ -4754,7 +5195,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] @@ -4769,9 +5210,9 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ "log", "once_cell", @@ -4780,9 +5221,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "nu-ansi-term", "sharded-slab", @@ -4794,9 +5235,9 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "ttf-parser" @@ -4812,19 +5253,20 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "uds_windows" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" dependencies = [ + "memoffset 0.9.1", "tempfile", "winapi", ] [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -4834,18 +5276,18 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "unicode-xid" @@ -4867,9 +5309,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -4884,9 +5326,9 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "uuid" -version = "1.5.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", ] @@ -4929,9 +5371,9 @@ checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -4954,9 +5396,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.88" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4964,24 +5406,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.88" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.38" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -4991,9 +5433,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.88" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5001,22 +5443,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.88" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.88" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wayland-client" @@ -5105,9 +5547,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.65" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -5115,9 +5557,9 @@ dependencies = [ [[package]] name = "webbrowser" -version = "0.8.12" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b2391658b02c27719fc5a0a73d6e696285138e8b12fba9d4baa70451023c71" +checksum = "db67ae75a9405634f5882791678772c94ff5f16a66535aae186e26aa0841fc8b" dependencies = [ "core-foundation", "home", @@ -5132,9 +5574,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.2" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "which" @@ -5145,7 +5587,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.21", + "rustix 0.38.34", ] [[package]] @@ -5166,20 +5608,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-wsapoll" -version = "0.1.1" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -5205,7 +5638,7 @@ version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ - "windows-core", + "windows-core 0.51.1", "windows-targets 0.48.5", ] @@ -5218,6 +5651,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.5", +] + [[package]] name = "windows-implement" version = "0.48.0" @@ -5258,6 +5700,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -5288,6 +5739,22 @@ dependencies = [ "windows_x86_64_msvc 0.48.5", ] +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -5300,6 +5767,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -5312,6 +5785,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -5324,6 +5803,18 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -5336,6 +5827,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -5348,6 +5845,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -5360,6 +5863,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -5372,6 +5881,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + [[package]] name = "winit" version = "0.28.7" @@ -5389,7 +5904,7 @@ dependencies = [ "log", "mio", "ndk", - "objc2", + "objc2 0.3.0-beta.3.patch-leaks.3", "once_cell", "orbclient", "percent-encoding", @@ -5409,9 +5924,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.5.19" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] @@ -5445,25 +5960,20 @@ dependencies = [ [[package]] name = "x11rb" -version = "0.10.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "592b4883219f345e712b3209c62654ebda0bb50887f330cbd018d0f654bfd507" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" dependencies = [ "gethostname", - "nix 0.24.3", - "winapi", - "winapi-wsapoll", + "rustix 0.38.34", "x11rb-protocol", ] [[package]] name = "x11rb-protocol" -version = "0.10.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56b245751c0ac9db0e006dc812031482784e434630205a93c73cfefcaabeac67" -dependencies = [ - "nix 0.24.3", -] +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] name = "x509" @@ -5481,13 +5991,13 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" dependencies = [ - "asn1-rs", + "asn1-rs 0.5.2", "base64 0.13.1", "data-encoding", "der-parser 8.2.0", "lazy_static", "nom 7.1.3", - "oid-registry", + "oid-registry 0.6.1", "rusticata-macros 4.1.0", "thiserror", "time", @@ -5499,12 +6009,12 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" dependencies = [ - "asn1-rs", + "asn1-rs 0.5.2", "data-encoding", "der-parser 8.2.0", "lazy_static", "nom 7.1.3", - "oid-registry", + "oid-registry 0.6.1", "ring 0.16.20", "rusticata-macros 4.1.0", "thiserror", @@ -5512,29 +6022,43 @@ dependencies = [ ] [[package]] -name = "xcursor" -version = "0.3.4" +name = "x509-parser" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" dependencies = [ + "asn1-rs 0.6.1", + "data-encoding", + "der-parser 9.0.0", + "lazy_static", "nom 7.1.3", + "oid-registry 0.7.0", + "rusticata-macros 4.1.0", + "thiserror", + "time", ] +[[package]] +name = "xcursor" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911" + [[package]] name = "xdg-home" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2769203cd13a0c6015d515be729c526d041e9cf2c0cc478d57faee85f40c6dcd" +checksum = "21e5a325c3cb8398ad6cf859c1135b25dd29e186679cf2da7581d9679f63b38e" dependencies = [ - "nix 0.26.4", + "libc", "winapi", ] [[package]] name = "xml-rs" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" +checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" [[package]] name = "xmlparser" @@ -5571,7 +6095,7 @@ dependencies = [ "num-traits", "p256", "p384", - "pbkdf2", + "pbkdf2 0.11.0", "pcsc", "rand_core", "rsa", @@ -5587,9 +6111,9 @@ dependencies = [ [[package]] name = "zbus" -version = "3.14.1" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31de390a2d872e4cd04edd71b425e29853f786dc99317ed72d73d6fcf5ebb948" +checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" dependencies = [ "async-broadcast", "async-executor", @@ -5628,9 +6152,9 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "3.14.1" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d1794a946878c0e807f55a397187c11fc7a038ba5d868e7db4f3bd7760bc9d" +checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -5642,9 +6166,9 @@ dependencies = [ [[package]] name = "zbus_names" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb80bb776dbda6e23d705cf0123c3b95df99c4ebeaec6c2599d4a5419902b4a9" +checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" dependencies = [ "serde", "static_assertions", @@ -5653,29 +6177,29 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.25" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.25" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", ] [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] @@ -5688,14 +6212,42 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.61", +] + +[[package]] +name = "zstd" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.10+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +dependencies = [ + "cc", + "pkg-config", ] [[package]] name = "zvariant" -version = "3.15.0" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44b291bee0d960c53170780af148dca5fa260a63cdd24f1962fa82e03e53338c" +checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db" dependencies = [ "byteorder", "enumflags2", @@ -5707,9 +6259,9 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "3.15.0" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934d7a7dfc310d6ee06c87ffe88ef4eca7d3e37bb251dece2ef93da8f17d8ecd" +checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" dependencies = [ "proc-macro-crate", "proc-macro2", diff --git a/examples/example.db b/examples/example.db index 3b92911b..01201710 100644 Binary files a/examples/example.db and b/examples/example.db differ diff --git a/examples/rustica_agent_local.toml b/examples/rustica_agent_local.toml index f9a2aca9..63013cbc 100644 --- a/examples/rustica_agent_local.toml +++ b/examples/rustica_agent_local.toml @@ -14,32 +14,33 @@ socket = "/tmp/rustica_socket_dev3" address = "https://localhost:50052" ca_pem = """ -----BEGIN CERTIFICATE----- -MIIBJDCBzAIJAJGDT3qxW0/TMAoGCCqGSM49BAMCMBsxGTAXBgNVBAMMEEVudGVy -cHJpc2VSb290Q0EwHhcNMjIwMTIwMDQwMjA2WhcNMzIwMTE4MDQwMjA2WjAbMRkw -FwYDVQQDDBBFbnRlcnByaXNlUm9vdENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD -QgAErbw3gSqNpSsz75hQxDLkvMA3u4b+wnM9ha+2c6hJ3q3Dv+fpcX43FYoMud4u -o36dlMy3bUXbw5Kd6yGOMu+BfTAKBggqhkjOPQQDAgNHADBEAiBXa5LdA+F/qc73 -56fvs1qMmjOTp8u6haFQ6MVTfOXYRgIgTAr4/kwoxyGSCd0z4Ehgud+J2PClDhad -HaLQ5dcIBw8= +MIIBizCCATGgAwIBAgIUSxuBkb/vlm8p9VQRVlGeC7KWjQswCgYIKoZIzj0EAwIw +GzEZMBcGA1UEAwwQRW50ZXJwcmlzZVJvb3RDQTAeFw0yNDA2MDYwNDA4MThaFw0z +NDA2MDQwNDA4MThaMBsxGTAXBgNVBAMMEEVudGVycHJpc2VSb290Q0EwWTATBgcq +hkjOPQIBBggqhkjOPQMBBwNCAAQhZaDE0x7484SonAR5Ogufm7Qg5CttNfOr6Lk4 +uqmJaUpxNsFJOclZqGUHgIPMfK7qQIU0K8EDD+mxJBIYY2V5o1MwUTAdBgNVHQ4E +FgQUOhiiXYkz9/H/i5F87/PRfqg/6E4wHwYDVR0jBBgwFoAUOhiiXYkz9/H/i5F8 +7/PRfqg/6E4wDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiBm3CqE +bvVHnNt5gd4NDUkJ3ALrp3pzm24UFJU/sRssEgIhAKsSFHVza/vSJ/6KWqvZoogB +DF1DluRk6qknMiXlDjpI -----END CERTIFICATE----- """ mtls_cert = """ -----BEGIN CERTIFICATE----- -MIIBVjCB3KADAgECAghPhuBjlTGcpDAKBggqhkjOPQQDAzAYMRYwFAYDVQQDDA1S -dXN0aWNhQWNjZXNzMB4XDTIzMDUyNjA3MjgzOVoXDTI5MDIyMzA3MjgzOVowEjEQ -MA4GA1UEAwwHb2JlbGlzazBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCTeMGsm -eW8IgcCow/MQh0ELcRL70xHJes8jlWCVbcCkBJzuYoaXHBWsczmzlMfJZ6fiYayF -XY7zeki+b+IukzOjFjAUMBIGA1UdEQQLMAmCB29iZWxpc2swCgYIKoZIzj0EAwMD -aQAwZgIxAIYLibYaxzcbZ0K9IWdIcOhnh8fvDW+Xozp1nU3++mhsASE2cbgzgrx5 -4i5VR4kymwIxAIip2AIVm9k3tMRmkX2nMdnL7wOKR+Hxhe0fdSabWXfvg2gKePjN -SNKgrPKT1OOoMQ== +MIIBQjCB6aADAgECAhUArfRIp1jEPZCLmVbQRzsQrCRcPGAwCgYIKoZIzj0EAwIw +GDEWMBQGA1UEAwwNUnVzdGljYUFjY2VzczAeFw0yNDA2MDYwNDM2NTRaFw0zMDAz +MDcwNDM2NTRaMBIxEDAOBgNVBAMMB29iZWxpc2swWTATBgcqhkjOPQIBBggqhkjO +PQMBBwNCAAQvKOaSK5vGPjbxk/kjAIxbyRFsKb1DSub5L1DFsfg2OlsrNt4/g3Ra +NCSkcA99y25LD5txN1vnAHZOqbACKZIooxYwFDASBgNVHREECzAJggdvYmVsaXNr +MAoGCCqGSM49BAMCA0gAMEUCIAN0yMvU4Keidu14KLV+q4BWG6LR6nIhuiHphA/K +DGfLAiEAnm9/rz+QrR9jLsvf90sWUkXdf3/Yv5KYSIPtH5XUnYM= -----END CERTIFICATE----- """ mtls_key = """ -----BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgQVrtm8rEr9z5f15a -o89ijgIdfH+5kO6FkVPB2fU39U+hRANCAAQk3jBrJnlvCIHAqMPzEIdBC3ES+9MR -yXrPI5VglW3ApASc7mKGlxwVrHM5s5THyWen4mGshV2O83pIvm/iLpMz +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgSFyNGs01I6JPXwpn +Ac1arqHBIvwAAI7tvwFlVp3yO7yhRANCAAQvKOaSK5vGPjbxk/kjAIxbyRFsKb1D +Sub5L1DFsfg2OlsrNt4/g3RaNCSkcA99y25LD5txN1vnAHZOqbACKZIo -----END PRIVATE KEY----- """ diff --git a/examples/rustica_external.toml b/examples/rustica_external.toml index 3c11d8f2..07df0c58 100644 --- a/examples/rustica_external.toml +++ b/examples/rustica_external.toml @@ -141,4 +141,11 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgkTd0C69xWFX9PmVf BeD0ySfG+O0e7p7SXR9xo/enbvahRANCAAQCDYaBVv+bcD6gBy8YxY5p7JRNYyTC UF5oo8pmUycUdA7DWZcL1IDR/lmEBX6uCFTMMqVR4Mk2CTvpQADxHsjz -----END PRIVATE KEY----- -''' \ No newline at end of file +''' + +[allowed_signers] +cache_validity_length.secs = 900 +cache_validity_length.nanos = 0 +lru_rate_limiter_size = 16 +rate_limit_cooldown.secs = 15 +rate_limit_cooldown.nanos = 0 diff --git a/examples/rustica_local_amazonkms.toml b/examples/rustica_local_amazonkms.toml index c30c488e..3031be3b 100644 --- a/examples/rustica_local_amazonkms.toml +++ b/examples/rustica_local_amazonkms.toml @@ -98,3 +98,10 @@ common_name = "RusticaAccess" [authorization."database"] path = "examples/example.db" + +[allowed_signers] +cache_validity_length.secs = 900 +cache_validity_length.nanos = 0 +lru_rate_limiter_size = 16 +rate_limit_cooldown.secs = 15 +rate_limit_cooldown.nanos = 0 diff --git a/examples/rustica_local_multi.toml b/examples/rustica_local_multi.toml index a881d762..8c56dba0 100644 --- a/examples/rustica_local_multi.toml +++ b/examples/rustica_local_multi.toml @@ -115,4 +115,11 @@ algorithm = "ECDSA_SHA_384" [authorization."database"] -path = "examples/example.db" \ No newline at end of file +path = "examples/example.db" + +[allowed_signers] +cache_validity_length.secs = 900 +cache_validity_length.nanos = 0 +lru_rate_limiter_size = 16 +rate_limit_cooldown.secs = 15 +rate_limit_cooldown.nanos = 0 diff --git a/examples/rustica_local_yubikey.toml b/examples/rustica_local_yubikey.toml index 6b5ca760..89d95403 100644 --- a/examples/rustica_local_yubikey.toml +++ b/examples/rustica_local_yubikey.toml @@ -76,4 +76,11 @@ client_certificate_authority_common_name = "RusticaAccess" [logging."stdout"] [authorization."database"] -path = "examples/example.db" \ No newline at end of file +path = "examples/example.db" + +[allowed_signers] +cache_validity_length.secs = 900 +cache_validity_length.nanos = 0 +lru_rate_limiter_size = 16 +rate_limit_cooldown.secs = 15 +rate_limit_cooldown.nanos = 0 diff --git a/proto/author.proto b/proto/author.proto index 3eae3add..88aec819 100644 --- a/proto/author.proto +++ b/proto/author.proto @@ -34,7 +34,20 @@ message AddIdentityDataRequest { message AddIdentityDataResponse {} +message AllowedSigner { + string identity = 1; + string pubkey = 2; +} + +// This call fetches a list of all allowed signers and their signing pubkeys +message AllowedSignersRequest {} + +message AllowedSignersResponse { + repeated AllowedSigner allowed_signers = 1; +} + service Author { rpc Authorize(AuthorizeRequest) returns (AuthorizeResponse); rpc AddIdentityData(AddIdentityDataRequest) returns (AddIdentityDataResponse); -} \ No newline at end of file + rpc GetAllowedSigners(AllowedSignersRequest) returns (AllowedSignersResponse); +} diff --git a/proto/rustica.proto b/proto/rustica.proto index 7cec59f6..4fe0535e 100644 --- a/proto/rustica.proto +++ b/proto/rustica.proto @@ -58,6 +58,7 @@ message RegisterU2FKeyRequest { bytes intermediate = 5; int32 alg = 6; Challenge challenge = 7; + bool u2f_challenge_hashed = 8; } message RegisterU2FKeyResponse {} @@ -83,10 +84,18 @@ message AttestedX509CertificateResponse { int64 error_code = 3; } +// This call fetches a list of all authorized signers and their signing pubkeys +message AllowedSignersRequest {} + +message AllowedSignersResponse { + bytes compressed_allowed_signers = 1; +} + service Rustica { rpc Challenge(ChallengeRequest) returns (ChallengeResponse); rpc Certificate(CertificateRequest) returns (CertificateResponse); rpc RegisterKey(RegisterKeyRequest) returns (RegisterKeyResponse); rpc RegisterU2FKey(RegisterU2FKeyRequest) returns (RegisterU2FKeyResponse); rpc AttestedX509Certificate(AttestedX509CertificateRequest) returns (AttestedX509CertificateResponse); -} \ No newline at end of file + rpc AllowedSigners(AllowedSignersRequest) returns (AllowedSignersResponse); +} diff --git a/resources/create_certs.sh b/resources/create_certs.sh index 329fcbea..904d6f42 100755 --- a/resources/create_certs.sh +++ b/resources/create_certs.sh @@ -88,7 +88,7 @@ openssl req -x509 -new -key ca.key -nodes -days 3650 -out ca.pem -subj '/CN=Ente openssl ecparam -genkey -name prime256v1 -noout -out client_ca.key # Convert EC key format to PKCS#8 key format to comply with ring's key format requirement openssl pkcs8 -topk8 -nocrypt -in client_ca.key -out client_ca_pkcs8.key -openssl req -new -key client_ca.key -x509 -nodes -days 3650 -out client_ca.pem -subj '/CN=EnterpriseClientRootCA' +openssl req -new -key client_ca.key -x509 -nodes -days 3650 -out client_ca.pem -subj '/CN=RusticaAccess' # ------------ Generate Private Keys For Test Infra ------------ # # Generate Rustica Certificates diff --git a/resources/package.sh b/resources/package.sh index 0bcfff48..2cc5ec20 100755 --- a/resources/package.sh +++ b/resources/package.sh @@ -1,26 +1,39 @@ #!/bin/zsh -PACKAGE=rustica-agent -BINARY=rustica-agent +export X86_64_APPLE_DARWIN_OPENSSL_LIB_DIR=/usr/local/Cellar/openssl@3/3.2.0/lib/ +export X86_64_APPLE_DARWIN_OPENSSL_INCLUDE_DIR=/usr/local/Cellar/openssl@3/3.2.0/include/ +export OPENSSL_STATIC=1 + +BINARY=rustica-agent-cli # Remove the old version of the package rm RusticaAgent.pkg RusticaAgentInterim.pkg # Build universal application binary cd .. -cargo build --package ${PACKAGE} --release -cargo build --package ${PACKAGE} --release --target x86_64-apple-darwin +cargo build --bin ${BINARY} --release +cargo build --bin ${BINARY} --release --target x86_64-apple-darwin +mkdir -p resources/root/usr/local/bin/ +lipo -create target/release/${BINARY} target/x86_64-apple-darwin/release/${BINARY} -output resources/root/usr/local/bin/rustica-agent-cli + +cargo build --bin ${BINARY} --release --no-default-features --features "ctap2_hid" +cargo build --bin ${BINARY} --release --no-default-features --features "ctap2_hid" --target x86_64-apple-darwin mkdir -p resources/root/usr/local/bin/ -lipo -create target/release/${BINARY} target/x86_64-apple-darwin/release/${PACKAGE} -output resources/root/usr/local/bin/rustica-agent +lipo -create target/release/${BINARY} target/x86_64-apple-darwin/release/${BINARY} -output resources/root/usr/local/bin/rustica-agent-cli-ctap2 # Codesign the binary codesign --options=runtime --timestamp -f -s "5QY" --identifier "io.confurious.RusticaAgent" resources/root/usr/local/bin/rustica-agent -echo "Built ${BINARY}" +codesign --options=runtime --timestamp -f -s "5QY" --identifier "io.confurious.RusticaAgent" resources/root/usr/local/bin/rustica-agent-ctap2 + + +echo "Done!" + +# Use the below if you need to build a package -# Build the package that installs the application -pkgbuild --sign 5q --root resources/root --identifier io.confurious.RusticaAgent --install-location / --timestamp resources/RusticaAgentInterim.pkg +# # Build the package that installs the application +# pkgbuild --sign 5q --root resources/root --identifier io.confurious.RusticaAgent --install-location / --timestamp resources/RusticaAgentInterim.pkg -# Build the final product -productbuild --sign 5Q --package resources/RusticaAgentInterim.pkg resources/RusticaAgent.pkg +# # Build the final product +# productbuild --sign 5Q --package resources/RusticaAgentInterim.pkg resources/RusticaAgent.pkg -# Clean up artifacts -rm -rf RusticaAgentInterim.pkg root/ +# # Clean up artifacts +# rm -rf RusticaAgentInterim.pkg root/ diff --git a/rustica-agent-cli/Cargo.toml b/rustica-agent-cli/Cargo.toml index 4099275f..9f9dc342 100644 --- a/rustica-agent-cli/Cargo.toml +++ b/rustica-agent-cli/Cargo.toml @@ -1,9 +1,12 @@ [package] name = "rustica-agent-cli" -version = "0.11.1" +version = "0.12.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +default = ["mozilla"] +mozilla = ["rustica-agent/mozilla"] +ctap2_hid = ["rustica-agent/ctap2_hid"] [dependencies] clap = "3.0.5" @@ -11,12 +14,7 @@ env_logger = "0.8.2" hex = "0.4" log = "0.4.13" notify-rust = "4" -rustica-agent = { path = "../rustica-agent" } -sshcerts = { version = "0.12", features = ["yubikey-support", "fido-support"] } -# sshcerts = { path = "../../sshcerts", features = [ -# "yubikey-support", -# "fido-support", -# ] } +rustica-agent = { path = "../rustica-agent", default-features = false } tokio = { version = "1", features = ["full"] } toml = "0.7" yubikey = "0.7" diff --git a/rustica-agent-cli/src/config/allowed_signers.rs b/rustica-agent-cli/src/config/allowed_signers.rs new file mode 100644 index 00000000..7156e295 --- /dev/null +++ b/rustica-agent-cli/src/config/allowed_signers.rs @@ -0,0 +1,21 @@ +use clap::ArgMatches; +use rustica_agent::config::UpdatableConfiguration; + +use super::{ + parse_config_from_args, ConfigurationError, + RusticaAgentAction, +}; + +pub struct GetAllowedSignersConfig { + pub updatable_configuration: UpdatableConfiguration, +} + +pub async fn configure_allowed_signers( + matches: &ArgMatches, +) -> Result { + let updatable_configuration = parse_config_from_args(&matches)?; + + Ok(RusticaAgentAction::GetAllowedSigners(GetAllowedSignersConfig { + updatable_configuration, + })) +} diff --git a/rustica-agent-cli/src/config/gitconfig.rs b/rustica-agent-cli/src/config/gitconfig.rs index 69e68638..9e338bf1 100644 --- a/rustica-agent-cli/src/config/gitconfig.rs +++ b/rustica-agent-cli/src/config/gitconfig.rs @@ -1,6 +1,6 @@ use clap::{Arg, ArgMatches, Command}; use rustica_agent::{get_all_piv_keys, slot_parser, slot_validator}; -use sshcerts::{PrivateKey, PublicKey}; +use rustica_agent::{PrivateKey, PublicKey}; use super::{ConfigurationError, RusticaAgentAction}; diff --git a/rustica-agent-cli/src/config/mod.rs b/rustica-agent-cli/src/config/mod.rs index a8bdf338..b07336b9 100644 --- a/rustica-agent-cli/src/config/mod.rs +++ b/rustica-agent-cli/src/config/mod.rs @@ -7,18 +7,19 @@ mod provisionpiv; mod refresh_attested_x509_certificate; mod register; mod singlemode; +mod allowed_signers; use clap::{Arg, ArgMatches, Command}; use rustica_agent::config::UpdatableConfiguration; -use sshcerts::yubikey::piv::Yubikey; -use sshcerts::{CertType, PrivateKey, PublicKey}; +use rustica_agent::{CertType, PrivateKey, PublicKey, SSHCertsError, Yubikey}; use rustica_agent::*; use std::convert::TryFrom; use std::env; use std::process; +use std::sync::Arc; #[derive(Debug)] pub enum ConfigurationError { @@ -41,7 +42,7 @@ pub enum ConfigurationError { pub struct RunConfig { pub socket_path: String, pub pubkey: PublicKey, - pub handler: Handler, + pub handler: Arc, } pub enum RusticaAgentAction { @@ -54,6 +55,7 @@ pub enum RusticaAgentAction { ListFidoDevices, GitConfig(PublicKey), RefreshAttestedX509(refresh_attested_x509_certificate::RefreshAttestedX509Config), + GetAllowedSigners(allowed_signers::GetAllowedSignersConfig), } impl From for ConfigurationError { @@ -62,8 +64,8 @@ impl From for ConfigurationError { } } -impl From for ConfigurationError { - fn from(_: sshcerts::error::Error) -> Self { +impl From for ConfigurationError { + fn from(_: SSHCertsError) -> Self { ConfigurationError::ParsingError } } @@ -263,6 +265,8 @@ pub async fn configure() -> Result { "Refresh an X509 certificate in a Yubikey slot", )); + let allowed_signers = new_run_agent_subcommand("allowed-signers", "Fetch a list of all signers and their keys"); + let command_configuration = command_configuration .subcommand(immediate_mode) .subcommand(multi_mode) @@ -273,7 +277,8 @@ pub async fn configure() -> Result { .subcommand(list_piv_keys) .subcommand(list_fido_devices) .subcommand(git_config) - .subcommand(refresh_x509); + .subcommand(refresh_x509) + .subcommand(allowed_signers); let mut cc_help = command_configuration.clone(); let matches = command_configuration.get_matches(); @@ -314,11 +319,15 @@ pub async fn configure() -> Result { return gitconfig::configure_git_config(git_config); } - if let Some(x509_config) = matches.subcommand_matches("refresh-x509") { + if let Some(x509_config) = matches.subcommand_matches("refresh-attested-x509") { return refresh_attested_x509_certificate::configure_refresh_x509_certificate(x509_config) .await; } + if let Some(allowed_signers_config) = matches.subcommand_matches("allowed_signers") { + return allowed_signers::configure_allowed_signers(allowed_signers_config).await; + } + cc_help.print_help().unwrap(); Err(ConfigurationError::NoMode) } diff --git a/rustica-agent-cli/src/config/multimode.rs b/rustica-agent-cli/src/config/multimode.rs index 3e1d8056..71595712 100644 --- a/rustica-agent-cli/src/config/multimode.rs +++ b/rustica-agent-cli/src/config/multimode.rs @@ -1,4 +1,5 @@ use std::{collections::HashMap, fs}; +use std::sync::Arc; use rustica_agent::{ get_all_piv_keys, Handler, RusticaAgentLibraryError, Signatory, YubikeyPIVKeyDescriptor, @@ -6,7 +7,7 @@ use rustica_agent::{ }; use clap::{Arg, ArgMatches, Command}; -use sshcerts::{yubikey::piv::Yubikey, PrivateKey, PublicKey}; +use rustica_agent::{PrivateKey, PublicKey, Yubikey}; use crate::config::{ parse_certificate_config_from_args, parse_config_from_args, parse_socket_path_from_args, @@ -169,6 +170,7 @@ pub async fn configure_multimode( certificate_priority: matches.is_present("certificate-priority"), }; + let handler = Arc::new(handler); Ok(RusticaAgentAction::Run(RunConfig { socket_path, pubkey, diff --git a/rustica-agent-cli/src/config/refresh_attested_x509_certificate.rs b/rustica-agent-cli/src/config/refresh_attested_x509_certificate.rs index a3b1ae82..c4132c87 100644 --- a/rustica-agent-cli/src/config/refresh_attested_x509_certificate.rs +++ b/rustica-agent-cli/src/config/refresh_attested_x509_certificate.rs @@ -1,10 +1,10 @@ use std::env; use clap::{Arg, ArgMatches, Command}; +use rustica_agent::Yubikey; use rustica_agent::{ config::UpdatableConfiguration, slot_parser, slot_validator, Signatory, YubikeySigner, }; -use sshcerts::yubikey::piv::Yubikey; use super::{parse_config_from_args, ConfigurationError, RusticaAgentAction}; diff --git a/rustica-agent-cli/src/config/singlemode.rs b/rustica-agent-cli/src/config/singlemode.rs index aea6dd06..b6fb668f 100644 --- a/rustica-agent-cli/src/config/singlemode.rs +++ b/rustica-agent-cli/src/config/singlemode.rs @@ -1,8 +1,11 @@ use std::collections::HashMap; +use std::sync::Arc; use clap::{Arg, ArgMatches, Command}; use rustica_agent::{slot_validator, Handler, Signatory}; +use notify_rust::Notification; + use super::{ get_signatory, parse_certificate_config_from_args, parse_config_from_args, parse_socket_path_from_args, ConfigurationError, RunConfig, RusticaAgentAction, @@ -38,6 +41,17 @@ pub async fn configure_singlemode( } }; + let notification_f = move || { + println!("Trying to send a notification"); + if let Err(e) = Notification::new() + .summary("RusticaAgent") + .body("An application is requesting a signature. Please tap your Yubikey.") + .show() + { + error!("Notification system errored: {e}"); + } + }; + let handler = Handler { updatable_configuration: updatable_configuration.into(), cert: None.into(), @@ -47,10 +61,11 @@ pub async fn configure_singlemode( certificate_options, identities: HashMap::new().into(), piv_identities: HashMap::new(), - notification_function: None, + notification_function: Some(Box::new(notification_f)), certificate_priority: matches.is_present("certificate-priority"), }; + let handler = Arc::new(handler); Ok(RusticaAgentAction::Run(RunConfig { socket_path, pubkey, diff --git a/rustica-agent-cli/src/main.rs b/rustica-agent-cli/src/main.rs index 5953a513..2469c800 100644 --- a/rustica-agent-cli/src/main.rs +++ b/rustica-agent-cli/src/main.rs @@ -3,14 +3,13 @@ extern crate log; mod config; -use notify_rust::Notification; use yubikey::Certificate; use crate::config::RusticaAgentAction; use rustica_agent::rustica::key::U2FAttestation; use rustica_agent::*; -use sshcerts::fido::{generate::generate_new_ssh_key, list_fido_devices}; +use rustica_agent::{generate_new_ssh_key, list_fido_devices}; use tokio::sync::mpsc::channel; use std::fs::File; @@ -140,6 +139,7 @@ async fn main() -> Result<(), Box> { &mut config.updatable_configuration, &mut config.signatory, &config.certificate_options, + &None, ) .await { @@ -156,7 +156,7 @@ async fn main() -> Result<(), Box> { } // Normal operation: Starts RusticaAgent as an SSHAgent and waits to answer // requests from SSH clients. - Ok(RusticaAgentAction::Run(mut config)) => { + Ok(RusticaAgentAction::Run(config)) => { println!("Starting Rustica Agent"); println!("Access Fingerprint: {}", config.pubkey.fingerprint().hash); println!( @@ -164,19 +164,6 @@ async fn main() -> Result<(), Box> { config.socket_path ); - let notification_f = move || { - println!("Trying to send a notification"); - if let Err(e) = Notification::new() - .summary("RusticaAgent") - .body("An application is requesting a signature. Please tap your Yubikey.") - .show() - { - error!("Notification system errored: {e}"); - } - }; - - config.handler.notification_function = Some(Box::new(notification_f)); - let (_sds, shutdown_receiver) = channel(1); Agent::run_with_termination_channel( config.handler, @@ -208,6 +195,18 @@ async fn main() -> Result<(), Box> { Err(e) => println!("Error: {:?}", e), } } + Ok(RusticaAgentAction::GetAllowedSigners(config)) => { + match rustica_agent::get_allowed_signers( + &config.updatable_configuration.get_configuration().servers, + ) + .await + { + Ok(allowed_signers) => { + println!("{}", allowed_signers); + } + Err(e) => return Err(Box::new(e))?, + } + } Err(config::ConfigurationError::NoMode) => (), Err(e) => println!("Error: {:?}", e), }; diff --git a/rustica-agent-gui/Cargo.toml b/rustica-agent-gui/Cargo.toml index 80d1c36d..ef1ce8cf 100644 --- a/rustica-agent-gui/Cargo.toml +++ b/rustica-agent-gui/Cargo.toml @@ -1,21 +1,19 @@ [package] name = "rustica-agent-gui" -version = "0.11.1" +version = "0.12.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +default = ["mozilla"] +mozilla = ["rustica-agent/mozilla"] +ctap2_hid = ["rustica-agent/ctap2_hid"] [dependencies] base64 = "0.12" eframe = "0.22" hex = "0.4" home = "0.5" -rustica-agent = { path = "../rustica-agent" } -sshcerts = { version = "0.12", features = ["yubikey-support", "fido-support"] } -# sshcerts = { path = "../../sshcerts", features = [ -# "yubikey-support", -# "fido-support", -# ] } +rustica-agent = { path = "../rustica-agent", default-features = false } tokio = { version = "1", features = ["full"] } toml = "0.5" tracing-subscriber = "0.3" diff --git a/rustica-agent-gui/src/main.rs b/rustica-agent-gui/src/main.rs index a0397fd8..c4996c96 100644 --- a/rustica-agent-gui/src/main.rs +++ b/rustica-agent-gui/src/main.rs @@ -7,11 +7,11 @@ use eframe::egui::{self, Grid, Sense, TextEdit, Button /*Sense*/}; use egui::ComboBox; use home::home_dir; -use rustica_agent::{Agent, CertificateConfig, Signatory, YubikeyPIVKeyDescriptor, get_all_piv_keys, config::UpdatableConfiguration}; -use sshcerts::{fido::{FidoDeviceDescriptor, list_fido_devices}, PrivateKey, yubikey::piv::Yubikey}; +use rustica_agent::{YubikeyPIVKeyDescriptor, get_all_piv_keys}; +use rustica_agent::{Yubikey}; use tokio::{ runtime::Runtime, - sync::mpsc::{channel, Sender}, + sync::mpsc::Sender, }; #[derive(Debug)] @@ -51,8 +51,8 @@ struct RusticaAgentGui { status: String, new_env_name: String, new_env_content: String, - fido_devices: Vec, - selected_fido_device: Option, + //fido_devices: Vec, + //selected_fido_device: Option, piv_keys: HashMap, YubikeyPIVKeyDescriptorWithUse>, unlock_pin: String, } @@ -101,12 +101,12 @@ fn load_environments() -> Result { None }; - let fido_devices = list_fido_devices(); - let selected_fido_device = if !fido_devices.is_empty() { - Some(0) - } else { - None - }; + // let fido_devices = list_fido_devices(); + // let selected_fido_device = if !fido_devices.is_empty() { + // Some(0) + // } else { + // None + // }; let piv_keys = get_all_piv_keys().unwrap_or_default().into_iter().map(|x| (x.0, YubikeyPIVKeyDescriptorWithUse { descriptor: x.1, @@ -123,8 +123,8 @@ fn load_environments() -> Result { status: String::new(), new_env_name: String::new(), new_env_content: String::new(), - fido_devices, - selected_fido_device, + //fido_devices, + //selected_fido_device, piv_keys, unlock_pin: String::new(), }) @@ -212,20 +212,20 @@ impl eframe::App for RusticaAgentGui { }); ui.horizontal(|ui| { - if let Some(selected_fido_device) = self.selected_fido_device { - ComboBox::from_label("Choose a FIDO key") - .selected_text(format!("{}", &self.fido_devices[selected_fido_device].product_string.clone())) - .show_ui(ui, |ui| { - for i in 0..self.fido_devices.len() { - let value = ui.selectable_value(&mut &self.fido_devices[i], &self.fido_devices[selected_fido_device], &self.fido_devices[i].product_string.clone()); - if value.clicked() { - self.selected_fido_device = Some(i); - } - } - }); - } else { - ui.label("There are no connected FIDO devices"); - }; + // if let Some(selected_fido_device) = self.selected_fido_device { + // ComboBox::from_label("Choose a FIDO key") + // .selected_text(format!("{}", &self.fido_devices[selected_fido_device].product_string.clone())) + // .show_ui(ui, |ui| { + // for i in 0..self.fido_devices.len() { + // let value = ui.selectable_value(&mut &self.fido_devices[i], &self.fido_devices[selected_fido_device], &self.fido_devices[i].product_string.clone()); + // if value.clicked() { + // self.selected_fido_device = Some(i); + // } + // } + // }); + // } else { + // ui.label("There are no connected FIDO devices"); + // }; ui.add(egui::Separator::default()); ui.vertical_centered(|ui| { ui.label("Additional Keys"); @@ -289,66 +289,66 @@ impl eframe::App for RusticaAgentGui { } } if ui.button("Start").clicked() { - match self.selected_fido_device.as_ref() { - Some(fido_device) => { - let updatable_configuration = UpdatableConfiguration::new(&self.environments[*selected_env]); - match updatable_configuration { - Ok(updatable_configuration) => { - let mut private_key = PrivateKey::from_path(key_path).unwrap(); - - private_key.set_device_path(&self.fido_devices[*fido_device].path); - - let pubkey = private_key.pubkey.clone(); - let signatory = Signatory::Direct(private_key.into()); - - let certificate_options = CertificateConfig::from(updatable_configuration.get_configuration().options.clone()); - - let handler = rustica_agent::Handler { - updatable_configuration: updatable_configuration.into(), - cert: None.into(), - pubkey, - signatory, - stale_at: 0.into(), - certificate_options, - identities:HashMap::new().into(), - piv_identities: self.piv_keys.iter().filter_map(|x| if x.1.in_use {Some((x.0.clone(), x.1.descriptor.clone()))} else {None}).collect(), - notification_function: None, - certificate_priority: self.certificate_priority, + // match self.selected_fido_device.as_ref() { + // Some(fido_device) => { + // let updatable_configuration = UpdatableConfiguration::new(&self.environments[*selected_env]); + // match updatable_configuration { + // Ok(updatable_configuration) => { + // let mut private_key = PrivateKey::from_path(key_path).unwrap(); + + // private_key.set_device_path(&self.fido_devices[*fido_device].path); + + // let pubkey = private_key.pubkey.clone(); + // let signatory = Signatory::Direct(private_key.into()); + + // let certificate_options = CertificateConfig::from(updatable_configuration.get_configuration().options.clone()); + + // let handler = rustica_agent::Handler { + // updatable_configuration: updatable_configuration.into(), + // cert: None.into(), + // pubkey, + // signatory, + // stale_at: 0.into(), + // certificate_options, + // identities:HashMap::new().into(), + // piv_identities: self.piv_keys.iter().filter_map(|x| if x.1.in_use {Some((x.0.clone(), x.1.descriptor.clone()))} else {None}).collect(), + // notification_function: None, + // certificate_priority: self.certificate_priority, - }; - - let socket_path = - self.agent_dir.clone().join("rustica-agent.sock"); - - if socket_path.exists() { - if let Err(e) = std::fs::remove_file(&socket_path) { - println!("Couldn't remove old socket file, Rustica might fail to start: {e}"); - } - } - - let socket_path = socket_path.to_string_lossy().to_string(); - - let (sds, sdr) = channel::<()>(1); - self.runtime.spawn(async move { - Agent::run_with_termination_channel( - handler, - socket_path, - Some(sdr), - ) - .await; - }); - - self.shutdown_rustica = Some(sds); - } - Err(e) => { - println!("Could not parse config file: {e}") - } - }; - } - _ => { - self.status = format!("You must have both an environment and FIDO device selected"); - } - } + // }; + + // let socket_path = + // self.agent_dir.clone().join("rustica-agent.sock"); + + // if socket_path.exists() { + // if let Err(e) = std::fs::remove_file(&socket_path) { + // println!("Couldn't remove old socket file, Rustica might fail to start: {e}"); + // } + // } + + // let socket_path = socket_path.to_string_lossy().to_string(); + + // let (sds, sdr) = channel::<()>(1); + // self.runtime.spawn(async move { + // Agent::run_with_termination_channel( + // handler, + // socket_path, + // Some(sdr), + // ) + // .await; + // }); + + // self.shutdown_rustica = Some(sds); + // } + // Err(e) => { + // println!("Could not parse config file: {e}") + // } + // }; + // } + // _ => { + // self.status = format!("You must have both an environment and FIDO device selected"); + // } + // } } }); } else { diff --git a/rustica-agent/Cargo.toml b/rustica-agent/Cargo.toml index 0cbd4693..09f6da59 100644 --- a/rustica-agent/Cargo.toml +++ b/rustica-agent/Cargo.toml @@ -1,9 +1,14 @@ [package] name = "rustica-agent" -version = "0.11.1" +version = "0.12.0" authors = ["Mitchell Grenier "] edition = "2021" +[features] +default = ["mozilla"] +mozilla = ["sshcerts/fido-support-mozilla", "sshcerts/yubikey-support"] +ctap2_hid = ["sshcerts/fido-support", "sshcerts/yubikey-support"] + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] @@ -19,7 +24,7 @@ serde = "1.0.97" serde_derive = "1.0" sha2 = "0.9.2" # For Production -sshcerts = { version = "0.12", features = ["yubikey-support", "fido-support"] } +sshcerts = { version = "0.13.2" } # For Development # sshcerts = { path = "../../sshcerts", features = [ # "yubikey-support", @@ -31,6 +36,9 @@ tonic = { version = "0.9", features = ["tls"] } yubikey = { version = "0.7", features = ["untested"] } x509-parser = { version = "0.15", features = ["verify"] } +# Dependencies for allowed_signers feature +zstd = "0.13.1" + [build-dependencies] tonic-build = "0.9" diff --git a/rustica-agent/src/config/mod.rs b/rustica-agent/src/config/mod.rs index 181ebfc4..d8c7210b 100644 --- a/rustica-agent/src/config/mod.rs +++ b/rustica-agent/src/config/mod.rs @@ -1,8 +1,10 @@ -use std::{fs, path::{Path, PathBuf}}; - -use serde::{Deserialize, Serialize}; +use std::{ + fs, + path::{Path, PathBuf}, +}; use crate::{RusticaAgentLibraryError, RusticaServer}; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Options { diff --git a/rustica-agent/src/ffi.rs b/rustica-agent/src/ffi.rs deleted file mode 100644 index fdc43cbd..00000000 --- a/rustica-agent/src/ffi.rs +++ /dev/null @@ -1,986 +0,0 @@ -pub use crate::sshagent::{error::Error as AgentError, Agent, Identity, Response, SshAgentHandler}; -use crate::{ - config::UpdatableConfiguration, list_yubikey_serials, CertificateConfig, Handler, Signatory, - YubikeyPIVKeyDescriptor, YubikeySigner, -}; - -pub use crate::rustica::{ - key::PIVAttestation, - RefreshError::{ConfigurationError, SigningError}, -}; - -use crate::rustica::key::U2FAttestation; - -use sshcerts::fido::generate::generate_new_ssh_key; -use sshcerts::ssh::PrivateKey; -use sshcerts::yubikey::piv::{AlgorithmId, PinPolicy, RetiredSlotId, SlotId, TouchPolicy, Yubikey}; -use tokio::{ - runtime::Runtime, - sync::mpsc::{channel, Sender}, -}; - -use std::fs::File; -use std::{collections::HashMap, os::unix::prelude::PermissionsExt}; -use std::{convert::TryFrom, slice}; - -// FFI related imports -use std::ffi::{CStr, CString}; -use std::os::raw::{c_char, c_int, c_long}; - -pub struct RusticaAgentInstance { - runtime: Runtime, - shutdown_sender: Sender<()>, -} - -#[no_mangle] -pub unsafe extern "C" fn unlock_yubikey( - yubikey_serial: *const c_int, - pin: *const c_char, - management_key: *const c_char, -) -> c_int { - let mut yk = match Yubikey::open(yubikey_serial as u32) { - Ok(yk) => yk, - Err(e) => { - println!("Could not connect to Yubikey: {e}"); - return -1; - } - }; - - let pin = if !pin.is_null() { - let pin = CStr::from_ptr(pin); - let pin = match pin.to_str() { - Err(_) => return -2, - Ok(s) => s, - }; - pin.to_string() - } else { - return -6; - }; - - let management_key = if !management_key.is_null() { - let management_key = CStr::from_ptr(management_key); - let management_key = match management_key.to_str() { - Err(_) => return -2, - Ok(s) => s, - }; - - match hex::decode(management_key) { - Ok(s) => s, - Err(_) => { - println!("Invalid management key"); - return -3; - } - } - } else { - return -4; - }; - - match yk.unlock(pin.as_bytes(), &management_key) { - Ok(_) => 0, - Err(e) => { - println!("Error unlocking key: {e}"); - return yk.yk.get_pin_retries().map(|x| x as i32).unwrap_or(-9); - } - } -} - -/// Fetch the list of serial numbers for the connected Yubikeys -/// The return from this function must be freed by the caller because we can no longer track it -/// once we return -/// -/// # Safety -/// out_length must be a valid pointer to an 8 byte segment of memory -#[no_mangle] -pub unsafe extern "C" fn list_yubikeys(out_length: *mut c_int) -> *const c_long { - match list_yubikey_serials() { - Ok(serials) => { - let len = serials.len(); - let ptr = serials.as_ptr(); - std::mem::forget(serials); - std::ptr::write(out_length, len as c_int); - - ptr - } - Err(e) => { - println!("{:?}", e); - std::ptr::null_mut() - } - } -} - -/// Free the list of Yubikey Serial Numbers -/// -/// # Safety -/// This function must be passed the raw vector returned by `list_yubikeys` -/// otherwise the behaviour is undefined and will result in a crash. -#[no_mangle] -pub unsafe extern "C" fn free_list_yubikeys(length: c_int, yubikeys: *mut c_long) { - let len = length as usize; - - // Get back our vector. - // Previously we shrank to fit, so capacity == length. - let _ = Vec::from_raw_parts(yubikeys, len, len); -} - -/// The return from this function must be freed by the caller because we can no longer track it -/// once we return -/// -/// # Safety -/// out_length must be a valid pointer to an 8 byte segment of memory -#[no_mangle] -pub unsafe extern "C" fn list_keys( - yubikey_serial: u32, - out_length: *mut c_int, -) -> *mut *mut c_char { - match &mut Yubikey::open(yubikey_serial) { - Ok(yk) => { - let mut keys = vec![]; - for slot in 0x82..0x96_u8 { - let slot = SlotId::Retired(RetiredSlotId::try_from(slot).unwrap()); - if let Ok(subj) = yk.fetch_subject(&slot) { - keys.push(CString::new(format!("{:?} - {}", slot, subj)).unwrap()) - } - } - - let mut out = keys.into_iter().map(|s| s.into_raw()).collect::>(); - out.shrink_to_fit(); - - let len = out.len(); - let ptr = out.as_mut_ptr(); - std::mem::forget(out); - std::ptr::write(out_length, len as c_int); - - // Finally return the data - ptr - } - Err(_) => std::ptr::null_mut(), - } -} - -/// The return from this function must be freed by the caller because we can no longer track it -/// once we return -#[no_mangle] -pub extern "C" fn check_yubikey_slot_provisioned(yubikey_serial: u32, slot_id: u8) -> bool { - match &mut Yubikey::open(yubikey_serial) { - Ok(yk) => match SlotId::try_from(slot_id) { - Ok(slot) => yk.fetch_subject(&slot).is_ok(), - Err(_) => false, - }, - Err(_) => false, - } -} - -/// The return from this function must be freed by the caller because we can no longer track it -/// once we return -#[no_mangle] -pub extern "C" fn check_yubikey_slot_certificate_expiry(yubikey_serial: u32, slot_id: u8) -> u64 { - let (mut yk, slot) = match (Yubikey::open(yubikey_serial), SlotId::try_from(slot_id)) { - (Ok(yk), Ok(slot)) => (yk, slot), - _ => return 0, - }; - - let cert = match yk.fetch_certificate(&slot) { - Ok(cert) => cert, - Err(_) => return 0, - }; - - match x509_parser::parse_x509_certificate(&cert) { - Ok((_, cert)) => cert.tbs_certificate.validity.not_after.timestamp() as u64, - Err(_) => 0, - } -} - -/// Free the list of Yubikey keys -/// -/// # Safety -/// This function must be passed the raw vector returned by `list_keys` -/// otherwise the behaviour is undefined and will result in a crash. -#[no_mangle] -pub unsafe extern "C" fn free_list_keys(length: c_int, keys: *mut *mut c_char) { - let len = length as usize; - - // Get back our vector. - // Previously we shrank to fit, so capacity == length. - let v = Vec::from_raw_parts(keys, len, len); - - // Now drop one string at a time. - for elem in v { - let s = CString::from_raw(elem); - std::mem::drop(s); - } -} - -#[no_mangle] -/// Generate and enroll a new FIDO key with a Rustica backend -/// -/// # Safety -/// All c_char pointers passed to this function must be null terminated C -/// strings or undefined behaviour occurs possibly resulting in corruption -/// or crashes. -pub unsafe extern "C" fn generate_and_enroll_fido( - config_path: *const c_char, - out: *const c_char, - comment: *const c_char, - pin: *const c_char, - device: *const c_char, -) -> bool { - let cf = CStr::from_ptr(config_path); - let config_path = match cf.to_str() { - Err(_) => return false, - Ok(s) => s, - }; - - let updatable_configuration = match UpdatableConfiguration::new(config_path) { - Ok(c) => c, - Err(e) => { - error!("Configuration was invalid: {e}"); - return false; - } - }; - - let out = CStr::from_ptr(out); - let out = match out.to_str() { - Err(_) => return false, - Ok(s) => s, - }; - - let comment = if !comment.is_null() { - let comment = CStr::from_ptr(comment); - let comment = match comment.to_str() { - Err(_) => return false, - Ok(s) => s, - }; - comment.to_string() - } else { - "FFI-RusticaAgent-Generated-Key".to_string() - }; - - let pin = if !pin.is_null() { - let pin = CStr::from_ptr(pin); - let pin = match pin.to_str() { - Err(_) => return false, - Ok(s) => s, - }; - Some(pin.to_string()) - } else { - None - }; - - let device = if !device.is_null() { - let device = CStr::from_ptr(device); - let device = match device.to_str() { - Err(_) => return false, - Ok(s) => s, - }; - Some(device.to_string()) - } else { - None - }; - - let new_fido_key = match generate_new_ssh_key("ssh:", &comment, pin, device) { - Ok(nfk) => nfk, - Err(e) => { - println!("Error: {}", e); - return false; - } - }; - - let runtime = match Runtime::new() { - Ok(rt) => rt, - _ => return false, - }; - - let runtime_handle = runtime.handle().to_owned(); - - let mut signatory = Signatory::Direct(new_fido_key.private_key.clone().into()); - let u2f_attestation = U2FAttestation { - auth_data: new_fido_key.attestation.auth_data, - auth_data_sig: new_fido_key.attestation.auth_data_sig, - intermediate: new_fido_key.attestation.intermediate, - challenge: new_fido_key.attestation.challenge, - alg: new_fido_key.attestation.alg, - }; - - let mut out_file = match File::create(out) { - Ok(f) => f, - Err(e) => { - println!("Error: Could not create keyfile at {}: {}", out, e); - return false; - } - }; - - if let Ok(md) = out_file.metadata() { - let mut permissions = md.permissions(); - permissions.set_mode(0o600); - } else { - println!("Error: Could get file info {}", out); - return false; - }; - - if new_fido_key.private_key.write(&mut out_file).is_err() { - std::fs::remove_file(out).unwrap_or_default(); - println!("Error: Could not write to file. Basically should never happen"); - return false; - }; - - for server in &updatable_configuration.get_configuration().servers { - match server.register_u2f_key(&mut signatory, "ssh:", &u2f_attestation, &runtime_handle) { - Ok(_) => { - println!( - "Key was successfully registered with server: {}", - server.address - ); - return true; - } - Err(e) => { - error!("Key could not be registered. Server said: {}", e); - } - } - } - - std::fs::remove_file(out).unwrap(); - false -} - -/// Generate and enroll a new key on the given yubikey in the given slot -/// -/// # Safety -/// Subject, config_path, and pin must all be valid, null terminated C strings -/// or this functions behaviour is undefined and will result in a crash. -#[no_mangle] -pub unsafe extern "C" fn generate_and_enroll( - yubikey_serial: u32, - slot: u8, - touch_policy: u8, - pin_policy: u8, - subject: *const c_char, - config_path: *const c_char, - pin: *const c_char, - management_key: *const c_char, -) -> bool { - println!("Generating and enrolling a new key!"); - let cf = CStr::from_ptr(config_path); - let config_path = match cf.to_str() { - Err(_) => return false, - Ok(s) => s, - }; - - let updatable_configuration = match UpdatableConfiguration::new(config_path) { - Ok(c) => c, - Err(e) => { - error!("Configuration was invalid: {e}"); - return false; - } - }; - - let pin = CStr::from_ptr(pin); - let management_key = CStr::from_ptr(management_key); - let management_key = hex::decode(&management_key.to_str().unwrap()).unwrap(); - let subject = CStr::from_ptr(subject); - - let alg = AlgorithmId::EccP384; - let slot = SlotId::try_from(slot).unwrap(); - - let touch_policy = match touch_policy { - 0 => TouchPolicy::Never, - 1 => TouchPolicy::Cached, - _ => TouchPolicy::Always, - }; - - let pin_policy = match pin_policy { - 0 => PinPolicy::Never, - 1 => PinPolicy::Once, - _ => PinPolicy::Always, - }; - - let mut yk = Yubikey::open(yubikey_serial).unwrap(); - - if yk - .unlock(pin.to_str().unwrap().as_bytes(), &management_key) - .is_err() - { - println!("Could not unlock key"); - return false; - } - - let key_config = match yk.provision( - &slot, - subject.to_str().unwrap(), - alg, - touch_policy, - pin_policy, - ) { - Ok(_) => { - let certificate = yk.fetch_attestation(&slot); - let intermediate = yk.fetch_certificate(&SlotId::Attestation); - - match (certificate, intermediate) { - (Ok(certificate), Ok(intermediate)) => PIVAttestation { - certificate, - intermediate, - }, - _ => return false, - } - } - Err(_) => return false, - }; - - let mut signatory = Signatory::Yubikey(YubikeySigner { - yk: yk.into(), - slot, - }); - - let runtime = match Runtime::new() { - Ok(rt) => rt, - _ => return false, - }; - - let runtime_handle = runtime.handle().to_owned(); - - for server in &updatable_configuration.get_configuration().servers { - match server.register_key(&mut signatory, &key_config, &runtime_handle) { - Ok(_) => { - println!( - "Key was successfully registered with server: {}", - server.address - ); - return true; - } - Err(e) => { - error!("Key could not be registered. Server said: {}", e); - } - }; - } - - error!("All servers failed to register key"); - false -} - -/// Start a new Rustica instance. Does not return unless Rustica exits. -/// # Safety -/// `config_path` and `socket_path` must be a null terminated C strings -/// or behaviour is undefined and will result in a crash. -#[no_mangle] -pub unsafe extern "C" fn start_direct_rustica_agent( - private_key: *const c_char, - config_path: *const c_char, - socket_path: *const c_char, - pin: *const c_char, - device: *const c_char, - notification_fn: unsafe extern "C" fn() -> (), - authority: *const c_char, - certificate_priority: bool, -) -> *const RusticaAgentInstance { - return start_direct_rustica_agent_with_piv_idents( - private_key, - config_path, - socket_path, - pin, - device, - notification_fn, - authority, - certificate_priority, - std::ptr::null(), - std::ptr::null(), - std::ptr::null(), - 0, - ); -} - -/// Start a new Rustica instance. Does not return unless Rustica exits. -/// # Safety -/// `config_path` and `socket_path` must be a null terminated C strings -/// or behaviour is undefined and will result in a crash. -#[no_mangle] -pub unsafe extern "C" fn start_direct_rustica_agent_with_piv_idents( - private_key: *const c_char, - config_path: *const c_char, - socket_path: *const c_char, - pin: *const c_char, - device: *const c_char, - notification_fn: unsafe extern "C" fn() -> (), - authority: *const c_char, - certificate_priority: bool, - piv_serials: *const c_long, - piv_slots: *const u8, - piv_pins: *const c_long, - piv_key_count: c_int, -) -> *const RusticaAgentInstance { - let _ = env_logger::try_init(); - println!("Starting a new Rustica instance!"); - - let notification_f = move || { - notification_fn(); - }; - - let cf = CStr::from_ptr(config_path); - let config_path = match cf.to_str() { - Err(_) => return std::ptr::null(), - Ok(s) => s, - }; - - let updatable_configuration = match UpdatableConfiguration::new(config_path) { - Ok(c) => c, - Err(e) => { - error!("Configuration was invalid: {e}"); - return std::ptr::null(); - } - }; - - let sp = CStr::from_ptr(socket_path); - let socket_path = match sp.to_str() { - Err(_) => return std::ptr::null(), - Ok(s) => s.to_owned(), - }; - - println!("Socket path: {socket_path}"); - - let authority = CStr::from_ptr(authority); - let authority = match authority.to_str() { - Err(_) => return std::ptr::null(), - Ok(s) => s.to_owned(), - }; - - let private_key = CStr::from_ptr(private_key); - let mut private_key = match private_key.to_str() { - Err(_) => return std::ptr::null(), - Ok(s) => { - if let Ok(p) = PrivateKey::from_string(s) { - p - } else { - return std::ptr::null(); - } - } - }; - - if !pin.is_null() { - let pin = CStr::from_ptr(pin); - let pin = match pin.to_str() { - Err(_) => return std::ptr::null(), - Ok(s) => s.to_owned(), - }; - private_key.set_pin(&pin); - } - - if !device.is_null() { - let device = CStr::from_ptr(device); - let device = match device.to_str() { - Err(_) => return std::ptr::null(), - Ok(s) => s.to_owned(), - }; - - private_key.set_device_path(&device); - } - - let piv_key_count = piv_key_count as usize; - let key_serials: Vec = slice::from_raw_parts(piv_serials, piv_key_count) - .into_iter() - .map(|x| *x as u32) - .collect(); - - let piv_pins: Vec> = slice::from_raw_parts(piv_pins, piv_key_count) - .into_iter() - .map(|x| { - let pin = *x as u32; - if pin != 0 { - Some(pin.to_string()) - } else { - None - } - }) - .collect(); - - let mut key_slots = vec![]; - - for maybe_slot in slice::from_raw_parts(piv_slots, piv_key_count) { - match SlotId::try_from(*maybe_slot) { - Ok(s) => key_slots.push(s), - Err(_) => return std::ptr::null(), - }; - } - - let mut piv_identities = HashMap::new(); - for ((serial, slot), pin) in key_serials - .into_iter() - .zip(key_slots.into_iter()) - .zip(piv_pins.into_iter()) - { - let mut yk = match Yubikey::open(serial) { - Ok(yk) => yk, - Err(_) => return std::ptr::null(), - }; - - let pubkey = match yk.ssh_cert_fetch_pubkey(&slot) { - Ok(pk) => pk, - Err(_) => return std::ptr::null(), - }; - - let subject = yk.fetch_subject(&slot).unwrap_or_default(); - - piv_identities.insert( - pubkey.encode().to_vec(), - YubikeyPIVKeyDescriptor { - public_key: pubkey, - serial, - slot, - pin, - subject, - }, - ); - } - - println!("Fingerprint: {:?}", private_key.pubkey.fingerprint().hash); - - println!("Additional Fingerprints:"); - for key in piv_identities.iter() { - println!("{}", key.1.public_key.fingerprint().hash); - } - - let runtime = match Runtime::new() { - Ok(rt) => rt, - _ => return std::ptr::null(), - }; - - let mut certificate_options = - CertificateConfig::from(updatable_configuration.get_configuration().options.clone()); - certificate_options.authority = authority; - - let handler = Handler { - updatable_configuration: updatable_configuration.into(), - cert: None.into(), - stale_at: 0.into(), - pubkey: private_key.pubkey.clone(), - certificate_options, - signatory: Signatory::Direct(private_key.into()), - identities: HashMap::new().into(), - piv_identities, - notification_function: Some(Box::new(notification_f)), - certificate_priority, - }; - - let (shutdown_sender, shutdown_receiver) = channel::<()>(1); - - runtime.spawn(async move { - Agent::run_with_termination_channel( - handler, - socket_path.to_string(), - Some(shutdown_receiver), - ) - .await; - println!("Rustica Agent has shutdown"); - }); - - let agent_instance = Box::new(RusticaAgentInstance { - runtime, - shutdown_sender, - }); - - let agent_instance_pointer: *const RusticaAgentInstance = Box::leak(agent_instance); - - agent_instance_pointer -} - -#[no_mangle] -pub unsafe extern "C" fn shutdown_rustica_agent(rai: *mut RusticaAgentInstance) -> bool { - let rustica_agent_instance = Box::from_raw(rai); - let shutdown_sender = rustica_agent_instance.shutdown_sender.clone(); - rustica_agent_instance.runtime.spawn(async move { - shutdown_sender.send(()).await.unwrap(); - println!("Sent shutdown message"); - }); - - true -} - -/// Start a new Rustica instance. Does not return unless Rustica exits. -/// # Safety -/// `config_path` and `socket_path` must be a null terminated C strings -/// or behaviour is undefined and will result in a crash. -#[no_mangle] -pub unsafe extern "C" fn start_yubikey_rustica_agent( - yubikey_serial: u32, - slot: u8, - config_path: *const c_char, - socket_path: *const c_char, - notification_fn: unsafe extern "C" fn() -> (), - authority: *const c_char, - certificate_priority: bool, -) -> *const RusticaAgentInstance { - let _ = env_logger::try_init(); - println!("Starting a new Rustica instance!"); - - let notification_f = move || { - notification_fn(); - }; - - let authority = CStr::from_ptr(authority); - let authority = match authority.to_str() { - Err(_) => return std::ptr::null(), - Ok(s) => s.to_owned(), - }; - - let cf = CStr::from_ptr(config_path); - let config_path = match cf.to_str() { - Err(_) => return std::ptr::null(), - Ok(s) => s, - }; - - let updatable_configuration = match UpdatableConfiguration::new(config_path) { - Ok(c) => c, - Err(e) => { - error!("Configuration was invalid: {e}"); - return std::ptr::null(); - } - }; - - let runtime = match Runtime::new() { - Ok(rt) => rt, - _ => return std::ptr::null(), - }; - - let mut certificate_options = - CertificateConfig::from(updatable_configuration.get_configuration().options.clone()); - certificate_options.authority = authority; - - let mut yk = Yubikey::open(yubikey_serial).unwrap(); - let slot = SlotId::try_from(slot).unwrap(); - let pubkey = match yk.ssh_cert_fetch_pubkey(&slot) { - Ok(cert) => cert, - Err(_) => return std::ptr::null(), - }; - - let handler = Handler { - updatable_configuration: updatable_configuration.into(), - cert: None.into(), - stale_at: 0.into(), - pubkey, - certificate_options, - signatory: Signatory::Yubikey(YubikeySigner { - yk: Yubikey::open(yubikey_serial).unwrap().into(), - slot: SlotId::try_from(slot).unwrap(), - }), - identities: HashMap::new().into(), - piv_identities: HashMap::new(), - notification_function: Some(Box::new(notification_f)), - certificate_priority, - }; - - println!("Slot: {:?}", SlotId::try_from(slot)); - - let sp = CStr::from_ptr(socket_path); - let socket_path = match sp.to_str() { - Err(_) => return std::ptr::null(), - Ok(s) => s, - }; - - let (shutdown_sender, shutdown_receiver) = channel::<()>(1); - - runtime.spawn(async move { - Agent::run_with_termination_channel( - handler, - socket_path.to_string(), - Some(shutdown_receiver), - ) - .await; - println!("Rustica Agent has shutdown"); - }); - - let agent_instance = Box::new(RusticaAgentInstance { - runtime, - shutdown_sender, - }); - - let agent_instance_pointer: *const RusticaAgentInstance = Box::leak(agent_instance); - - agent_instance_pointer -} - -/// Fetch a string that will configure a git repository for code -/// signing under the given key -/// # Safety -#[no_mangle] -pub unsafe extern "C" fn ffi_get_git_config_string_from_private_key( - private_key: *const c_char, -) -> *const c_char { - let private_key = CStr::from_ptr(private_key); - let public_key = match private_key.to_str() { - Err(_) => return std::ptr::null(), - Ok(s) => { - if let Ok(p) = PrivateKey::from_string(s) { - p.pubkey.clone() - } else { - return std::ptr::null(); - } - } - }; - - let git_config = match CString::new(crate::git_config_from_public_key(&public_key)) { - Ok(c) => c, - Err(_) => return std::ptr::null(), // Happens if the string contains a null byte. Should never happen but better to handle than not - }; - - git_config.into_raw() -} - -/// Fetch a string that will configure a git repository for code -/// signing under the given key -/// # Safety -#[no_mangle] -pub unsafe extern "C" fn ffi_get_git_config_string_from_serial_and_slot( - serial: u32, - slot: u8, -) -> *const c_char { - let public_key = match &mut Yubikey::open(serial) { - Ok(yk) => { - let slot = match RetiredSlotId::try_from(slot) { - Ok(s) => SlotId::Retired(s), - Err(_) => return std::ptr::null(), - }; - - match yk.ssh_cert_fetch_pubkey(&slot) { - Ok(pk) => pk, - Err(_) => return std::ptr::null(), - } - } - Err(_) => return std::ptr::null(), - }; - - let git_config = match CString::new(crate::git_config_from_public_key(&public_key)) { - Ok(c) => c, - Err(_) => return std::ptr::null(), // Happens if the string contains a null byte. Should never happen but better to handle than not - }; - - git_config.into_raw() -} - -/// Free a string allocated by Rust -#[no_mangle] -pub unsafe extern "C" fn ffi_free_rust_string(string_ptr: *mut c_char) { - drop(CString::from_raw(string_ptr)); -} - -/// Check if the device path will require a pin to generate a new key -/// # Safety -#[no_mangle] -pub unsafe extern "C" fn ffi_does_device_need_pin(device: *const c_char) -> i32 { - let device_path = if !device.is_null() { - let device = CStr::from_ptr(device); - match device.to_str() { - Err(_) => return -1, - Ok(s) => s.to_owned(), - } - } else { - return -1; - }; - - match sshcerts::fido::device_requires_pin(&device_path) { - Ok(true) => return 1, - Ok(false) => return 0, - Err(e) => { - println!("Could not determine if pin is needed: {e}"); - return -1; - } - } -} - -/// Check if the device path will require a pin to generate a new key -/// # Safety -#[no_mangle] -pub unsafe extern "C" fn ffi_device_pin_retries(device: *const c_char) -> i32 { - let device_path = if !device.is_null() { - let device = CStr::from_ptr(device); - match device.to_str() { - Err(_) => return -1, - Ok(s) => s.to_owned(), - } - } else { - return -1; - }; - - match sshcerts::fido::device_pin_retries(&device_path) { - Ok(x) => return x, - Err(e) => { - println!("Could find how many pin retries are available: {e}"); - return -1; - } - } -} - -/// Refresh and load a new certificate onto a yubikey -/// -/// # Safety -/// Subject, config_path, and pin must all be valid, null terminated C strings -/// or this functions behaviour is undefined and will result in a crash. -#[no_mangle] -pub unsafe extern "C" fn ffi_refresh_x509_certificate( - yubikey_serial: u32, - slot: u8, - config_path: *const c_char, - pin: *const c_char, - management_key: *const c_char, -) -> bool { - println!("Refreshing certificate!"); - let cf = CStr::from_ptr(config_path); - let config_path = match cf.to_str() { - Err(_) => return false, - Ok(s) => s, - }; - - let updatable_configuration = match UpdatableConfiguration::new(config_path) { - Ok(c) => c, - Err(e) => { - error!("Configuration was invalid: {e}"); - return false; - } - }; - - let pin = CStr::from_ptr(pin); - let management_key = CStr::from_ptr(management_key); - let management_key = hex::decode(&management_key.to_str().unwrap()).unwrap(); - - let slot = SlotId::try_from(slot).unwrap(); - let mut yk = Yubikey::open(yubikey_serial).unwrap(); - - if yk - .unlock(pin.to_str().unwrap().as_bytes(), &management_key) - .is_err() - { - println!("Could not unlock key"); - return false; - } - - let mut signatory = Signatory::Yubikey(YubikeySigner { - yk: yk.into(), - slot, - }); - - let runtime = match Runtime::new() { - Ok(rt) => rt, - _ => return false, - }; - - let runtime_handle = runtime.handle().to_owned(); - - for server in &updatable_configuration.get_configuration().servers { - match server.refresh_x509_certificate(&mut signatory, &runtime_handle) { - Ok(c) => { - println!("Certificate was issued from server: {}", server.address); - let mut yk = Yubikey::open(yubikey_serial).unwrap(); - yk.unlock(pin.to_str().unwrap().as_bytes(), &management_key) - .unwrap(); - if yk.write_certificate(&slot, &c).is_err() { - error!("Could not write certificate to yubikey"); - return false; - } else { - return true; - } - } - Err(e) => { - error!("Certificate could not be issued. Server said: {}", e); - } - }; - } - - error!("All servers failed to issue a certificate"); - false -} diff --git a/rustica-agent/src/ffi/agent.rs b/rustica-agent/src/ffi/agent.rs new file mode 100644 index 00000000..34580b2f --- /dev/null +++ b/rustica-agent/src/ffi/agent.rs @@ -0,0 +1,450 @@ +pub use crate::sshagent::{error::Error as AgentError, Agent, Identity, Response, SshAgentHandler}; +use crate::{ + config::UpdatableConfiguration, CertificateConfig, Handler, PrivateKey, Signatory, + YubikeyPIVKeyDescriptor, YubikeySigner, +}; + +pub use crate::rustica::{ + key::PIVAttestation, + RefreshError::{ConfigurationError, SigningError}, +}; + +use sshcerts::yubikey::piv::{SlotId, Yubikey}; + +use tokio::{ + runtime::Runtime, + sync::{ + mpsc::{channel, Sender}, + Mutex, + }, +}; + +use std::collections::HashMap; +use std::{convert::TryFrom, slice}; +use std::sync::Arc; + +// FFI related imports +use std::ffi::{CStr, CString}; +use std::os::raw::{c_char, c_int, c_long}; + +pub struct RusticaAgentInstance { + runtime: Runtime, + shutdown_sender: Sender<()>, + handler: Arc, +} + +/// Start a new Rustica instance. Does not return unless Rustica exits. +/// # Safety +/// `config_path` and `socket_path` must be a null terminated C strings +/// or behaviour is undefined and will result in a crash. +#[no_mangle] +pub unsafe extern "C" fn start_direct_rustica_agent( + private_key: *const c_char, + config_path: *const c_char, + socket_path: *const c_char, + pin: *const c_char, + device: *const c_char, + notification_fn: unsafe extern "C" fn() -> (), + authority: *const c_char, + certificate_priority: bool, +) -> *const RusticaAgentInstance { + return start_direct_rustica_agent_with_piv_idents( + private_key, + config_path, + socket_path, + pin, + device, + notification_fn, + authority, + certificate_priority, + std::ptr::null(), + std::ptr::null(), + std::ptr::null(), + 0, + ); +} + +/// Start a new Rustica instance. Does not return unless Rustica exits. +/// # Safety +/// `config_path` and `socket_path` must be a null terminated C strings +/// or behaviour is undefined and will result in a crash. +#[no_mangle] +pub unsafe extern "C" fn start_direct_rustica_agent_with_piv_idents( + private_key: *const c_char, + config_path: *const c_char, + socket_path: *const c_char, + pin: *const c_char, + device: *const c_char, + notification_fn: unsafe extern "C" fn() -> (), + authority: *const c_char, + certificate_priority: bool, + piv_serials: *const c_long, + piv_slots: *const u8, + piv_pins: *const c_long, + piv_key_count: c_int, +) -> *const RusticaAgentInstance { + let _ = env_logger::try_init(); + println!("Starting a new Rustica instance!"); + + let notification_f = move || { + notification_fn(); + }; + + let cf = CStr::from_ptr(config_path); + let config_path = match cf.to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => s, + }; + + let updatable_configuration = match UpdatableConfiguration::new(config_path) { + Ok(c) => c, + Err(e) => { + error!("Configuration was invalid: {e}"); + return std::ptr::null(); + } + }; + + let sp = CStr::from_ptr(socket_path); + let socket_path = match sp.to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => s.to_owned(), + }; + + println!("Socket path: {socket_path}"); + + let authority = CStr::from_ptr(authority); + let authority = match authority.to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => s.to_owned(), + }; + + let private_key = CStr::from_ptr(private_key); + let mut private_key = match private_key.to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => { + if let Ok(p) = PrivateKey::from_string(s) { + p + } else { + return std::ptr::null(); + } + } + }; + + if !pin.is_null() { + let pin = CStr::from_ptr(pin); + let pin = match pin.to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => s.to_owned(), + }; + private_key.set_pin(&pin); + } + + if !device.is_null() { + let device = CStr::from_ptr(device); + let device = match device.to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => s.to_owned(), + }; + + private_key.set_device_path(&device); + } + + let piv_key_count = piv_key_count as usize; + let key_serials: Vec = slice::from_raw_parts(piv_serials, piv_key_count) + .into_iter() + .map(|x| *x as u32) + .collect(); + + let piv_pins: Vec> = slice::from_raw_parts(piv_pins, piv_key_count) + .into_iter() + .map(|x| { + let pin = *x as u32; + if pin != 0 { + Some(pin.to_string()) + } else { + None + } + }) + .collect(); + + let mut key_slots = vec![]; + + for maybe_slot in slice::from_raw_parts(piv_slots, piv_key_count) { + match SlotId::try_from(*maybe_slot) { + Ok(s) => key_slots.push(s), + Err(_) => return std::ptr::null(), + }; + } + + let mut piv_identities = HashMap::new(); + for ((serial, slot), pin) in key_serials + .into_iter() + .zip(key_slots.into_iter()) + .zip(piv_pins.into_iter()) + { + let mut yk = match Yubikey::open(serial) { + Ok(yk) => yk, + Err(_) => return std::ptr::null(), + }; + + let pubkey = match yk.ssh_cert_fetch_pubkey(&slot) { + Ok(pk) => pk, + Err(_) => return std::ptr::null(), + }; + + let subject = yk.fetch_subject(&slot).unwrap_or_default(); + + piv_identities.insert( + pubkey.encode().to_vec(), + YubikeyPIVKeyDescriptor { + public_key: pubkey, + serial, + slot, + pin, + subject, + }, + ); + } + + println!("Fingerprint: {:?}", private_key.pubkey.fingerprint().hash); + + println!("Additional Fingerprints:"); + for key in piv_identities.iter() { + println!("{}", key.1.public_key.fingerprint().hash); + } + + let runtime = match Runtime::new() { + Ok(rt) => rt, + _ => return std::ptr::null(), + }; + + let mut certificate_options = + CertificateConfig::from(updatable_configuration.get_configuration().options.clone()); + certificate_options.authority = authority; + + let handler = Handler { + updatable_configuration: updatable_configuration.into(), + cert: None.into(), + stale_at: 0.into(), + pubkey: private_key.pubkey.clone(), + certificate_options, + signatory: Signatory::Direct(private_key.into()), + identities: HashMap::new().into(), + piv_identities, + notification_function: Some(Box::new(notification_f)), + certificate_priority, + }; + + let (shutdown_sender, shutdown_receiver) = channel::<()>(1); + let handler = Arc::new(handler); + + let runtime_handler = handler.clone(); + runtime.spawn(async move { + Agent::run_with_termination_channel( + runtime_handler, + socket_path.to_string(), + Some(shutdown_receiver), + ) + .await; + println!("Rustica Agent has shutdown"); + }); + + let agent_instance = Box::new(RusticaAgentInstance { + runtime, + shutdown_sender, + handler, + }); + + let agent_instance_pointer: *const RusticaAgentInstance = Box::leak(agent_instance); + + agent_instance_pointer +} + +#[no_mangle] +pub unsafe extern "C" fn shutdown_rustica_agent(rai: *mut RusticaAgentInstance) -> bool { + let rustica_agent_instance = Box::from_raw(rai); + let shutdown_sender = rustica_agent_instance.shutdown_sender.clone(); + rustica_agent_instance.runtime.spawn(async move { + shutdown_sender.send(()).await.unwrap(); + println!("Sent shutdown message"); + }); + + true +} + +/// Start a new Rustica instance. Does not return unless Rustica exits. +/// # Safety +/// `config_path` and `socket_path` must be a null terminated C strings +/// or behaviour is undefined and will result in a crash. +#[no_mangle] +pub unsafe extern "C" fn start_yubikey_rustica_agent( + yubikey_serial: u32, + slot: u8, + config_path: *const c_char, + socket_path: *const c_char, + notification_fn: unsafe extern "C" fn() -> (), + authority: *const c_char, + certificate_priority: bool, +) -> *const RusticaAgentInstance { + let _ = env_logger::try_init(); + println!("Starting a new Rustica instance!"); + + let notification_f = move || { + notification_fn(); + }; + + let authority = CStr::from_ptr(authority); + let authority = match authority.to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => s.to_owned(), + }; + + let cf = CStr::from_ptr(config_path); + let config_path = match cf.to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => s, + }; + + let updatable_configuration = match UpdatableConfiguration::new(config_path) { + Ok(c) => c, + Err(e) => { + error!("Configuration was invalid: {e}"); + return std::ptr::null(); + } + }; + + let runtime = match Runtime::new() { + Ok(rt) => rt, + _ => return std::ptr::null(), + }; + + let mut certificate_options = + CertificateConfig::from(updatable_configuration.get_configuration().options.clone()); + certificate_options.authority = authority; + + let mut yk = Yubikey::open(yubikey_serial).unwrap(); + let slot = SlotId::try_from(slot).unwrap(); + let pubkey = match yk.ssh_cert_fetch_pubkey(&slot) { + Ok(cert) => cert, + Err(_) => return std::ptr::null(), + }; + + let handler = Handler { + updatable_configuration: Mutex::new(updatable_configuration), + cert: None.into(), + stale_at: Mutex::new(0), + pubkey, + certificate_options, + signatory: Signatory::Yubikey(YubikeySigner { + yk: Mutex::new(Yubikey::open(yubikey_serial).unwrap()), + slot: SlotId::try_from(slot).unwrap(), + }), + identities: Mutex::new(HashMap::new()), + piv_identities: HashMap::new(), + notification_function: Some(Box::new(notification_f)), + certificate_priority, + }; + + println!("Slot: {:?}", SlotId::try_from(slot)); + + let sp = CStr::from_ptr(socket_path); + let socket_path = match sp.to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => s, + }; + + let (shutdown_sender, shutdown_receiver) = channel::<()>(1); + + let handler = Arc::new(handler); + + let runtime_handler = handler.clone(); + runtime.spawn(async move { + Agent::run_with_termination_channel( + runtime_handler, + socket_path.to_string(), + Some(shutdown_receiver), + ) + .await; + println!("Rustica Agent has shutdown"); + }); + + let agent_instance = Box::new(RusticaAgentInstance { + runtime, + shutdown_sender, + handler, + }); + + let agent_instance_pointer: *const RusticaAgentInstance = Box::leak(agent_instance); + + agent_instance_pointer +} + +/// Fetch a string that will configure a git repository for code +/// signing under the given key +/// # Safety +#[no_mangle] +pub unsafe extern "C" fn ffi_get_git_config_string_from_private_key( + private_key: *const c_char, +) -> *const c_char { + let private_key = CStr::from_ptr(private_key); + let public_key = match private_key.to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => { + if let Ok(p) = PrivateKey::from_string(s) { + p.pubkey.clone() + } else { + return std::ptr::null(); + } + } + }; + + let git_config = match CString::new(crate::git_config_from_public_key(&public_key)) { + Ok(c) => c, + Err(_) => return std::ptr::null(), // Happens if the string contains a null byte. Should never happen but better to handle than not + }; + + git_config.into_raw() +} + +/// First, fetch the previous cert if present and valid. If cert is still valid, return it. +/// +/// If cached cert is invalid, and if fetch_new_cert_if_needed is: +/// - true: fetch a new cert from server. Return error if the fetch fails. +/// - false: return None. +#[no_mangle] +pub unsafe extern "C" fn ffi_get_certificate(rai: *mut RusticaAgentInstance, fetch_new_cert_if_needed: bool) -> *const c_char { + let rustica_agent_instance = Box::from_raw(rai); + let handler = rustica_agent_instance.handler.clone(); + + let runtime_handle = rustica_agent_instance.runtime.handle(); + let certificate = match handler.get_certificate(runtime_handle, fetch_new_cert_if_needed) { + Ok(Some(v)) => Some(v), + Ok(None) => { + None + }, + Err(e) => { + println!("failed to fetch certificate: {}", e); + None + }, + }; + + // We need to leak here otherwise we will free the RAI + // when we're still using it. Would be nice if Box had Box::into_weak or + // something similar + Box::leak(rustica_agent_instance); + + let certificate = match certificate { + Some(v) => v, + None => return std::ptr::null(), + }; + + let certificate = match CString::new(certificate.to_string()) { + Ok(c) => c, + Err(e) => { + println!("failed to create a new CSTring from serialized cert: {}", e); + return std::ptr::null(); + }, + }; + + certificate.into_raw() +} diff --git a/rustica-agent/src/ffi/allowed_signer.rs b/rustica-agent/src/ffi/allowed_signer.rs new file mode 100644 index 00000000..d0207143 --- /dev/null +++ b/rustica-agent/src/ffi/allowed_signer.rs @@ -0,0 +1,91 @@ +use std::ffi::{c_char, CStr}; +use std::fs::File; +use std::io::Write; + +use crate::config::UpdatableConfiguration; + +use tokio::runtime::Runtime; + +pub enum GetAllowedSignersStatus { + Success = 0, + ConfigurationError = 1, + ParameterError, + InternalError, + AllowedSignersFileError, +} + +/// Request all allowed signers +#[no_mangle] +pub unsafe extern "C" fn ffi_get_allowed_signers( + config_path: *const c_char, + out_path: *const c_char, +) -> i32 { + let cf = CStr::from_ptr(config_path); + let config_path = match cf.to_str() { + Ok(s) => s, + Err(e) => { + error!("Unable to marshall config_path to &str: {e}"); + return GetAllowedSignersStatus::ConfigurationError as i32; + }, + }; + + let updatable_configuration = match UpdatableConfiguration::new(config_path) { + Ok(c) => c, + Err(e) => { + error!("Configuration was invalid: {e}"); + return GetAllowedSignersStatus::ConfigurationError as i32; + }, + }; + + let out_path = CStr::from_ptr(out_path); + let out_path = match out_path.to_str() { + Ok(s) => s, + Err(e) => { + error!("Unable to marshall out_path to &str: {e}"); + return GetAllowedSignersStatus::ParameterError as i32; + }, + }; + + let runtime = match Runtime::new() { + Ok(rt) => rt, + Err(e) => { + error!("Unable to initialize tokio runtime: {e}"); + return GetAllowedSignersStatus::InternalError as i32; + }, + }; + let runtime_handle = runtime.handle().to_owned(); + + let mut out_file = match File::create(out_path) { + Ok(f) => f, + Err(e) => { + error!("Could not create Allowed Signers file at {}: {}", out_path, e); + return GetAllowedSignersStatus::AllowedSignersFileError as i32; + } + }; + + for server in &updatable_configuration.get_configuration().servers { + let allowed_signers = match server.get_allowed_signers(&runtime_handle) { + Ok(data) => { + println!( + "Allowed signers were successfully fetched from server: {}", + server.address + ); + data + } + Err(e) => { + error!("Allowed signers could not be fetched. Server said: {}", e); + continue; + }, + }; + + match out_file.write_all(allowed_signers.as_bytes()) { + Ok(()) => return GetAllowedSignersStatus::Success as i32, + Err(e) => { + error!("Could not write to file {}: {}", out_path, e); + return GetAllowedSignersStatus::AllowedSignersFileError as i32; + }, + } + } + + GetAllowedSignersStatus::InternalError as i32 +} diff --git a/rustica-agent/src/ffi/enrollment.rs b/rustica-agent/src/ffi/enrollment.rs new file mode 100644 index 00000000..278061b9 --- /dev/null +++ b/rustica-agent/src/ffi/enrollment.rs @@ -0,0 +1,292 @@ +use std::ffi::{c_char, CStr}; +use std::os::unix::fs::PermissionsExt; + +use crate::config::UpdatableConfiguration; +use crate::rustica::key::U2FAttestation; +use crate::{PIVAttestation, Signatory, YubikeySigner}; + +use sshcerts::error::Error as SSHCertsError; +use sshcerts::fido::generate::generate_new_ssh_key; +use sshcerts::fido::Error as FidoError; +use sshcerts::yubikey::piv::{AlgorithmId, PinPolicy, SlotId, TouchPolicy, Yubikey}; +use std::fs::File; +use tokio::runtime::Runtime; + +pub enum GenerateAndEnrollStatus { + Success = 0, + ConfigurationError = 1, + ParameterError, + PinRequired, + KeyLocked, + KeyBlocked, + UnknownAttemptsRemaining, + InternalError, + KeyFileError, + KeyRegistrationError, +} + +#[no_mangle] +/// Generate and enroll a new FIDO key with a Rustica backend +/// +/// # Safety +/// All c_char pointers passed to this function must be null terminated C +/// strings or undefined behaviour occurs possibly resulting in corruption +/// or crashes. +/// +/// # Return +/// Returns a GenerateAndEnrollStatus enum cast to i64. +/// If the key fails to generate due to pin, a negative value representing the attempts remaining +/// is returned instead. +pub unsafe extern "C" fn ffi_generate_and_enroll_fido( + config_path: *const c_char, + out: *const c_char, + comment: *const c_char, + pin: *const c_char, + device: *const c_char, +) -> i64 { + let cf = CStr::from_ptr(config_path); + let config_path = match cf.to_str() { + Err(_) => return GenerateAndEnrollStatus::ConfigurationError as i64, + Ok(s) => s, + }; + + let updatable_configuration = match UpdatableConfiguration::new(config_path) { + Ok(c) => c, + Err(e) => { + error!("Configuration was invalid: {e}"); + return GenerateAndEnrollStatus::ConfigurationError as i64; + } + }; + + let out = CStr::from_ptr(out); + let out = match out.to_str() { + Err(_) => return GenerateAndEnrollStatus::ParameterError as i64, + Ok(s) => s, + }; + + let comment = if !comment.is_null() { + let comment = CStr::from_ptr(comment); + let comment = match comment.to_str() { + Err(_) => return GenerateAndEnrollStatus::ParameterError as i64, + Ok(s) => s, + }; + comment.to_string() + } else { + "FFI-RusticaAgent-Generated-Key".to_string() + }; + + let pin = if !pin.is_null() { + let pin = CStr::from_ptr(pin); + let pin = match pin.to_str() { + Err(_) => return GenerateAndEnrollStatus::ParameterError as i64, + Ok(s) => s, + }; + Some(pin.to_string()) + } else { + None + }; + + let device = if !device.is_null() { + let device = CStr::from_ptr(device); + let device = match device.to_str() { + Err(_) => return GenerateAndEnrollStatus::ParameterError as i64, + Ok(s) => s, + }; + Some(device.to_string()) + } else { + None + }; + + let new_fido_key = match generate_new_ssh_key("ssh:", &comment, pin, device) { + Ok(nfk) => nfk, + Err(SSHCertsError::FidoError(FidoError::InvalidPin(Some(attempts)))) => { + if attempts == 0 { + return GenerateAndEnrollStatus::UnknownAttemptsRemaining as i64; + } + return -(attempts as i64); + } + Err(SSHCertsError::FidoError(FidoError::KeyLocked)) => { + return GenerateAndEnrollStatus::KeyLocked as i64 + } + Err(SSHCertsError::FidoError(FidoError::KeyBlocked)) => { + return GenerateAndEnrollStatus::KeyBlocked as i64 + } + Err(SSHCertsError::FidoError(FidoError::PinRequired)) => { + return GenerateAndEnrollStatus::PinRequired as i64 + } + Err(e) => { + error!("Unknown Error: {e}"); + return GenerateAndEnrollStatus::InternalError as i64; + } + }; + + let runtime = match Runtime::new() { + Ok(rt) => rt, + _ => return GenerateAndEnrollStatus::InternalError as i64, + }; + + let runtime_handle = runtime.handle().to_owned(); + + let mut signatory = Signatory::Direct(new_fido_key.private_key.clone().into()); + let u2f_attestation = U2FAttestation { + auth_data: new_fido_key.attestation.auth_data, + auth_data_sig: new_fido_key.attestation.auth_data_sig, + intermediate: new_fido_key.attestation.intermediate, + challenge: new_fido_key.attestation.challenge, + alg: new_fido_key.attestation.alg, + }; + + let mut out_file = match File::create(out) { + Ok(f) => f, + Err(e) => { + error!("Error: Could not create keyfile at {}: {}", out, e); + return GenerateAndEnrollStatus::KeyFileError as i64; + } + }; + + if let Ok(md) = out_file.metadata() { + let mut permissions = md.permissions(); + permissions.set_mode(0o600); + } else { + error!("Error: Could get file info {}", out); + return GenerateAndEnrollStatus::KeyFileError as i64; + }; + + if new_fido_key.private_key.write(&mut out_file).is_err() { + std::fs::remove_file(out).unwrap_or_default(); + error!("Error: Could not write to file. Basically should never happen"); + return GenerateAndEnrollStatus::KeyFileError as i64; + }; + + for server in &updatable_configuration.get_configuration().servers { + match server.register_u2f_key(&mut signatory, "ssh:", &u2f_attestation, &runtime_handle) { + Ok(_) => { + println!( + "Key was successfully registered with server: {}", + server.address + ); + return GenerateAndEnrollStatus::Success as i64; + } + Err(e) => { + error!("Key could not be registered. Server said: {}", e); + } + } + } + + std::fs::remove_file(out).unwrap(); + return GenerateAndEnrollStatus::KeyRegistrationError as i64; +} + +/// Generate and enroll a new key on the given yubikey in the given slot +/// +/// # Safety +/// Subject, config_path, and pin must all be valid, null terminated C strings +/// or this functions behaviour is undefined and will result in a crash. +#[no_mangle] +pub unsafe extern "C" fn generate_and_enroll( + yubikey_serial: u32, + slot: u8, + touch_policy: u8, + pin_policy: u8, + subject: *const c_char, + config_path: *const c_char, + pin: *const c_char, + management_key: *const c_char, +) -> bool { + println!("Generating and enrolling a new key!"); + let cf = CStr::from_ptr(config_path); + let config_path = match cf.to_str() { + Err(_) => return false, + Ok(s) => s, + }; + + let updatable_configuration = match UpdatableConfiguration::new(config_path) { + Ok(c) => c, + Err(e) => { + error!("Configuration was invalid: {e}"); + return false; + } + }; + + let pin = CStr::from_ptr(pin); + let management_key = CStr::from_ptr(management_key); + let management_key = hex::decode(&management_key.to_str().unwrap()).unwrap(); + let subject = CStr::from_ptr(subject); + + let alg = AlgorithmId::EccP384; + let slot = SlotId::try_from(slot).unwrap(); + + let touch_policy = match touch_policy { + 0 => TouchPolicy::Never, + 1 => TouchPolicy::Cached, + _ => TouchPolicy::Always, + }; + + let pin_policy = match pin_policy { + 0 => PinPolicy::Never, + 1 => PinPolicy::Once, + _ => PinPolicy::Always, + }; + + let mut yk = Yubikey::open(yubikey_serial).unwrap(); + + if yk + .unlock(pin.to_str().unwrap().as_bytes(), &management_key) + .is_err() + { + println!("Could not unlock key"); + return false; + } + + let key_config = match yk.provision( + &slot, + subject.to_str().unwrap(), + alg, + touch_policy, + pin_policy, + ) { + Ok(_) => { + let certificate = yk.fetch_attestation(&slot); + let intermediate = yk.fetch_certificate(&SlotId::Attestation); + + match (certificate, intermediate) { + (Ok(certificate), Ok(intermediate)) => PIVAttestation { + certificate, + intermediate, + }, + _ => return false, + } + } + Err(_) => return false, + }; + + let mut signatory = Signatory::Yubikey(YubikeySigner { + yk: yk.into(), + slot, + }); + + let runtime = match Runtime::new() { + Ok(rt) => rt, + _ => return false, + }; + + let runtime_handle = runtime.handle().to_owned(); + + for server in &updatable_configuration.get_configuration().servers { + match server.register_key(&mut signatory, &key_config, &runtime_handle) { + Ok(_) => { + println!( + "Key was successfully registered with server: {}", + server.address + ); + return true; + } + Err(e) => { + error!("Key could not be registered. Server said: {}", e); + } + }; + } + + error!("All servers failed to register key"); + false +} diff --git a/rustica-agent/src/ffi/mod.rs b/rustica-agent/src/ffi/mod.rs new file mode 100644 index 00000000..cd740c3f --- /dev/null +++ b/rustica-agent/src/ffi/mod.rs @@ -0,0 +1,59 @@ +mod agent; +mod enrollment; +mod allowed_signer; +mod signing; +mod utils; +mod yubikey_utils; + +use std::ffi::{c_char, c_long, CStr}; + +/// For functions related to starting (and stopping) RusticaAgent instances +pub use agent::*; + +/// For generating and enrolling keys that will be used with RusticaAgent +pub use enrollment::*; + +/// For fetching all signer SSH keys that were registered +pub use allowed_signer::*; + +/// For functions that handle signing arbitrary data using SSH keys +pub use signing::*; + +/// For functions that handle memory management and other utilities +pub use utils::*; + +/// For functions that handle YubiKey specific functionality (generally PIV) +pub use yubikey_utils::*; + +use crate::config::UpdatableConfiguration; + +#[no_mangle] +/// Read a configuration file and return the expiry time of the primary server (the first one) +pub unsafe extern "C" fn ffi_get_expiry_of_primary_server(config_path: *const c_char) -> c_long { + let cf = CStr::from_ptr(config_path); + let config_path = match cf.to_str() { + Err(_) => return -1, + Ok(s) => s, + }; + + let updatable_configuration = match UpdatableConfiguration::new(config_path) { + Ok(c) => c, + Err(e) => { + error!("Configuration was invalid: {e}"); + return GenerateAndEnrollStatus::ConfigurationError as i64; + } + }; + + let server = match updatable_configuration.get_configuration().servers.first() { + Some(s) => &s.mtls_cert, + None => return -1, + }; + + match x509_parser::pem::parse_x509_pem(server.as_bytes()) { + Err(_) => return -1, + Ok((_, s)) => match s.parse_x509() { + Err(_) => return -2, + Ok(cert) => cert.validity().not_after.timestamp(), + }, + } +} diff --git a/rustica-agent/src/ffi/signing.rs b/rustica-agent/src/ffi/signing.rs new file mode 100644 index 00000000..4cfc116f --- /dev/null +++ b/rustica-agent/src/ffi/signing.rs @@ -0,0 +1,117 @@ +use std::ffi::{c_char, c_uchar, c_ulong, CStr, CString}; + +use sshcerts::{ + ssh::{SshSignature, VerifiedSshSignature}, + PrivateKey, PublicKey, +}; + +#[no_mangle] +/// Take a private key and sign arbitrary data with it under the given namespace. +/// Returns the signature as a string which then needs to be freed. All failures +/// return a null pointer. +pub unsafe extern "C" fn ffi_sign_data( + key_path: *const c_char, + namespace: *const c_char, + data: *const c_uchar, + data_len: c_ulong, +) -> *const c_char { + let key_path = match CStr::from_ptr(key_path).to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => s, + }; + + let private_key = match PrivateKey::from_path(key_path) { + Err(_) => return std::ptr::null(), + Ok(k) => k, + }; + + let namespace = match CStr::from_ptr(namespace).to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => s, + }; + + let data = std::slice::from_raw_parts(data, data_len as usize); + + match VerifiedSshSignature::new_with_private_key(data, namespace, private_key, None) { + Err(_) => return std::ptr::null(), + Ok(signature) => match CString::new(signature.to_string()) { + Err(_) => return std::ptr::null(), + Ok(s) => s.into_raw(), + }, + } +} + +fn parse_allowed_signer<'a>(allowed_signer: &'a str) -> Option<(PublicKey, &'a str)> { + let allowed_signer = allowed_signer.splitn(2, ' ').collect::>(); + if allowed_signer.len() != 2 { + return None; + } + + match PublicKey::from_string(allowed_signer[1]) { + Err(_) => None, + Ok(k) => Some((k, allowed_signer[0])), + } +} + +#[no_mangle] +/// Verify a signature against the given allowed_signers, data, and namespace. +/// Returns the name of the allowed signer which then needs to be freed. All failures +/// return a null pointer. +pub unsafe extern "C" fn ffi_verify_signed_data( + allowed_signers_path: *const c_char, + namespace: *const c_char, + data: *const c_uchar, + data_len: c_ulong, + signature_contents: *const c_char, +) -> *const c_char { + let signature_contents = match CStr::from_ptr(signature_contents).to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => s, + }; + + let ssh_signature = match SshSignature::from_armored_string(&signature_contents) { + Err(_) => return std::ptr::null(), + Ok(s) => s, + }; + + let allowed_signers_path = match CStr::from_ptr(allowed_signers_path).to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => s, + }; + + let allowed_signers = match std::fs::read_to_string(allowed_signers_path) { + Ok(s) => s, + Err(_) => return std::ptr::null(), + }; + + let allowed_signer = allowed_signers + .lines() + .filter_map(parse_allowed_signer) + .filter(|x| ssh_signature.pubkey == x.0) + .next(); + + let allowed_signer = match allowed_signer { + None => return std::ptr::null(), + Some(s) => s, + }; + + let message = std::slice::from_raw_parts(data, data_len as usize); + + let namespace = match CStr::from_ptr(namespace).to_str() { + Err(_) => return std::ptr::null(), + Ok(s) => s, + }; + + match VerifiedSshSignature::from_ssh_signature( + message, + ssh_signature, + namespace, + Some(allowed_signer.0), + ) { + Err(_) => return std::ptr::null(), + Ok(_) => match CString::new(allowed_signer.1) { + Err(_) => return std::ptr::null(), + Ok(s) => s.into_raw(), + }, + } +} diff --git a/rustica-agent/src/ffi/utils.rs b/rustica-agent/src/ffi/utils.rs new file mode 100644 index 00000000..c4824cb1 --- /dev/null +++ b/rustica-agent/src/ffi/utils.rs @@ -0,0 +1,7 @@ +use std::ffi::{c_char, CString}; + +/// Free a string allocated by Rust +#[no_mangle] +pub unsafe extern "C" fn ffi_free_rust_string(string_ptr: *mut c_char) { + drop(CString::from_raw(string_ptr)); +} diff --git a/rustica-agent/src/ffi/yubikey_utils.rs b/rustica-agent/src/ffi/yubikey_utils.rs new file mode 100644 index 00000000..13b94805 --- /dev/null +++ b/rustica-agent/src/ffi/yubikey_utils.rs @@ -0,0 +1,341 @@ +use std::ffi::{c_char, c_int, c_long, CStr, CString}; + +use sshcerts::yubikey::piv::{RetiredSlotId, SlotId, Yubikey}; +use tokio::runtime::Runtime; + +use crate::{config::UpdatableConfiguration, list_yubikey_serials, Signatory, YubikeySigner}; + +/// Check if the device path will require a pin to generate a new key +/// # Safety +#[no_mangle] +pub unsafe extern "C" fn ffi_does_device_need_pin(device: *const c_char) -> i32 { + let device_path = if !device.is_null() { + let device = CStr::from_ptr(device); + match device.to_str() { + Err(_) => return -1, + Ok(s) => s.to_owned(), + } + } else { + return -1; + }; + + match sshcerts::fido::device_requires_pin(&device_path) { + Ok(true) => return 1, + Ok(false) => return 0, + Err(e) => { + println!("Could not determine if pin is needed: {e}"); + return -1; + } + } +} + +/// Check if the device path will require a pin to generate a new key +/// # Safety +#[no_mangle] +pub unsafe extern "C" fn ffi_device_pin_retries(device: *const c_char) -> i32 { + let device_path = if !device.is_null() { + let device = CStr::from_ptr(device); + match device.to_str() { + Err(_) => return -1, + Ok(s) => s.to_owned(), + } + } else { + return -1; + }; + + match sshcerts::fido::device_pin_retries(&device_path) { + Ok(x) => return x, + Err(e) => { + println!("Could find how many pin retries are available: {e}"); + return -1; + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn unlock_yubikey( + yubikey_serial: *const c_int, + pin: *const c_char, + management_key: *const c_char, +) -> c_int { + let mut yk = match Yubikey::open(yubikey_serial as u32) { + Ok(yk) => yk, + Err(e) => { + println!("Could not connect to Yubikey: {e}"); + return -1; + } + }; + + let pin = if !pin.is_null() { + let pin = CStr::from_ptr(pin); + let pin = match pin.to_str() { + Err(_) => return -2, + Ok(s) => s, + }; + pin.to_string() + } else { + return -6; + }; + + let management_key = if !management_key.is_null() { + let management_key = CStr::from_ptr(management_key); + let management_key = match management_key.to_str() { + Err(_) => return -2, + Ok(s) => s, + }; + + match hex::decode(management_key) { + Ok(s) => s, + Err(_) => { + println!("Invalid management key"); + return -3; + } + } + } else { + return -4; + }; + + match yk.unlock(pin.as_bytes(), &management_key) { + Ok(_) => 0, + Err(e) => { + println!("Error unlocking key: {e}"); + return yk.yk.get_pin_retries().map(|x| x as i32).unwrap_or(-9); + } + } +} + +/// Fetch the list of serial numbers for the connected Yubikeys +/// The return from this function must be freed by the caller because we can no longer track it +/// once we return +/// +/// # Safety +/// out_length must be a valid pointer to an 8 byte segment of memory +#[no_mangle] +pub unsafe extern "C" fn list_yubikeys(out_length: *mut c_int) -> *const c_long { + match list_yubikey_serials() { + Ok(serials) => { + let len = serials.len(); + let ptr = serials.as_ptr(); + std::mem::forget(serials); + std::ptr::write(out_length, len as c_int); + + ptr + } + Err(e) => { + println!("{:?}", e); + std::ptr::null_mut() + } + } +} + +/// Free the list of Yubikey Serial Numbers +/// +/// # Safety +/// This function must be passed the raw vector returned by `list_yubikeys` +/// otherwise the behaviour is undefined and will result in a crash. +#[no_mangle] +pub unsafe extern "C" fn free_list_yubikeys(length: c_int, yubikeys: *mut c_long) { + let len = length as usize; + + // Get back our vector. + // Previously we shrank to fit, so capacity == length. + let _ = Vec::from_raw_parts(yubikeys, len, len); +} + +/// The return from this function must be freed by the caller because we can no longer track it +/// once we return +/// +/// # Safety +/// out_length must be a valid pointer to an 8 byte segment of memory +#[no_mangle] +pub unsafe extern "C" fn list_keys( + yubikey_serial: u32, + out_length: *mut c_int, +) -> *mut *mut c_char { + match &mut Yubikey::open(yubikey_serial) { + Ok(yk) => { + let mut keys = vec![]; + for slot in 0x82..0x96_u8 { + let slot = SlotId::Retired(RetiredSlotId::try_from(slot).unwrap()); + if let Ok(subj) = yk.fetch_subject(&slot) { + keys.push(CString::new(format!("{:?} - {}", slot, subj)).unwrap()) + } + } + + let mut out = keys.into_iter().map(|s| s.into_raw()).collect::>(); + out.shrink_to_fit(); + + let len = out.len(); + let ptr = out.as_mut_ptr(); + std::mem::forget(out); + std::ptr::write(out_length, len as c_int); + + // Finally return the data + ptr + } + Err(_) => std::ptr::null_mut(), + } +} + +/// The return from this function must be freed by the caller because we can no longer track it +/// once we return +#[no_mangle] +pub extern "C" fn check_yubikey_slot_provisioned(yubikey_serial: u32, slot_id: u8) -> bool { + match &mut Yubikey::open(yubikey_serial) { + Ok(yk) => match SlotId::try_from(slot_id) { + Ok(slot) => yk.fetch_subject(&slot).is_ok(), + Err(_) => false, + }, + Err(_) => false, + } +} + +/// The return from this function must be freed by the caller because we can no longer track it +/// once we return +#[no_mangle] +pub extern "C" fn check_yubikey_slot_certificate_expiry(yubikey_serial: u32, slot_id: u8) -> u64 { + let (mut yk, slot) = match (Yubikey::open(yubikey_serial), SlotId::try_from(slot_id)) { + (Ok(yk), Ok(slot)) => (yk, slot), + _ => return 0, + }; + + let cert = match yk.fetch_certificate(&slot) { + Ok(cert) => cert, + Err(_) => return 0, + }; + + match x509_parser::parse_x509_certificate(&cert) { + Ok((_, cert)) => cert.tbs_certificate.validity.not_after.timestamp() as u64, + Err(_) => 0, + } +} + +/// Free the list of Yubikey keys +/// +/// # Safety +/// This function must be passed the raw vector returned by `list_keys` +/// otherwise the behaviour is undefined and will result in a crash. +#[no_mangle] +pub unsafe extern "C" fn free_list_keys(length: c_int, keys: *mut *mut c_char) { + let len = length as usize; + + // Get back our vector. + // Previously we shrank to fit, so capacity == length. + let v = Vec::from_raw_parts(keys, len, len); + + // Now drop one string at a time. + for elem in v { + let s = CString::from_raw(elem); + std::mem::drop(s); + } +} + +/// Fetch a string that will configure a git repository for code +/// signing under the given key +/// # Safety +#[no_mangle] +pub unsafe extern "C" fn ffi_get_git_config_string_from_serial_and_slot( + serial: u32, + slot: u8, +) -> *const c_char { + let public_key = match &mut Yubikey::open(serial) { + Ok(yk) => { + let slot = match RetiredSlotId::try_from(slot) { + Ok(s) => SlotId::Retired(s), + Err(_) => return std::ptr::null(), + }; + + match yk.ssh_cert_fetch_pubkey(&slot) { + Ok(pk) => pk, + Err(_) => return std::ptr::null(), + } + } + Err(_) => return std::ptr::null(), + }; + + let git_config = match CString::new(crate::git_config_from_public_key(&public_key)) { + Ok(c) => c, + Err(_) => return std::ptr::null(), // Happens if the string contains a null byte. Should never happen but better to handle than not + }; + + git_config.into_raw() +} + +/// Refresh and load a new certificate onto a yubikey +/// +/// # Safety +/// Subject, config_path, and pin must all be valid, null terminated C strings +/// or this functions behaviour is undefined and will result in a crash. +#[no_mangle] +pub unsafe extern "C" fn ffi_refresh_x509_certificate( + yubikey_serial: u32, + slot: u8, + config_path: *const c_char, + pin: *const c_char, + management_key: *const c_char, +) -> bool { + println!("Refreshing certificate!"); + let cf = CStr::from_ptr(config_path); + let config_path = match cf.to_str() { + Err(_) => return false, + Ok(s) => s, + }; + + let updatable_configuration = match UpdatableConfiguration::new(config_path) { + Ok(c) => c, + Err(e) => { + error!("Configuration was invalid: {e}"); + return false; + } + }; + + let pin = CStr::from_ptr(pin); + let management_key = CStr::from_ptr(management_key); + let management_key = hex::decode(&management_key.to_str().unwrap()).unwrap(); + + let slot = SlotId::try_from(slot).unwrap(); + let mut yk = Yubikey::open(yubikey_serial).unwrap(); + + if yk + .unlock(pin.to_str().unwrap().as_bytes(), &management_key) + .is_err() + { + println!("Could not unlock key"); + return false; + } + + let mut signatory = Signatory::Yubikey(YubikeySigner { + yk: yk.into(), + slot, + }); + + let runtime = match Runtime::new() { + Ok(rt) => rt, + _ => return false, + }; + + let runtime_handle = runtime.handle().to_owned(); + + for server in &updatable_configuration.get_configuration().servers { + match server.refresh_x509_certificate(&mut signatory, &runtime_handle) { + Ok(c) => { + println!("Certificate was issued from server: {}", server.address); + let mut yk = Yubikey::open(yubikey_serial).unwrap(); + yk.unlock(pin.to_str().unwrap().as_bytes(), &management_key) + .unwrap(); + if yk.write_certificate(&slot, &c).is_err() { + error!("Could not write certificate to yubikey"); + return false; + } else { + return true; + } + } + Err(e) => { + error!("Certificate could not be issued. Server said: {}", e); + } + }; + } + + error!("All servers failed to issue a certificate"); + false +} diff --git a/rustica-agent/src/lib.rs b/rustica-agent/src/lib.rs index f4f3305c..7a9f2f3b 100644 --- a/rustica-agent/src/lib.rs +++ b/rustica-agent/src/lib.rs @@ -20,15 +20,21 @@ pub use rustica::{ RefreshError::{ConfigurationError, SigningError}, }; -use sshcerts::ssh::{CertType, Certificate, PrivateKey, PublicKey, SSHCertificateSigner}; -use sshcerts::yubikey::piv::{AlgorithmId, PinPolicy, RetiredSlotId, SlotId, TouchPolicy, Yubikey}; - use std::collections::HashMap; use std::{convert::TryFrom, env}; use std::time::SystemTime; use tokio::sync::Mutex; +use tokio::runtime::Handle; + +pub use sshcerts::{ + error::Error as SSHCertsError, + fido::{generate::generate_new_ssh_key, list_fido_devices}, + ssh::{CertType, SSHCertificateSigner}, + yubikey::piv::{AlgorithmId, PinPolicy, RetiredSlotId, SlotId, TouchPolicy, Yubikey}, + Certificate, PrivateKey, PublicKey, +}; #[derive(Debug)] pub struct CertificateConfig { @@ -84,6 +90,7 @@ pub enum RusticaAgentLibraryError { CouldNotReadConfigurationFile(String), BadConfiguration(String), UnknownConfigurationVersion(u64), + NoServersReturnedAllowedSigners, } impl std::fmt::Display for RusticaAgentLibraryError { @@ -115,6 +122,9 @@ impl std::fmt::Display for RusticaAgentLibraryError { RusticaAgentLibraryError::UnknownConfigurationVersion(e) => { write!(f, "Cannot use configuration version: {e}") } + RusticaAgentLibraryError::NoServersReturnedAllowedSigners => { + write!(f, "All servers failed to return allowed signers when requested") + } } } } @@ -126,7 +136,7 @@ pub struct Handler { /// settings pub updatable_configuration: Mutex, /// A previously issued certificate - pub cert: Mutex>, + pub cert: Mutex>, /// The public key we for the key we are providing a certificate for pub pubkey: PublicKey, /// The signing method for the private part of our public key. This needs to have @@ -189,6 +199,92 @@ impl From> for CertificateConfig { } } +impl Handler { + /// First, fetch the previous cert if present and valid. If cert is still valid, return it. + /// + /// If cached cert is invalid, and if fetch_new_cert_if_needed is: + /// - true: fetch a new cert from server. Return error if the fetch fails. + /// - false: return None. + async fn get_certificate_async(&self, fetch_new_cert_if_needed: bool) -> Result, RusticaAgentLibraryError> { + let timestamp = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(); + + if fetch_new_cert_if_needed { + let mut stale_at = self.stale_at.lock().await; + let mut existing_cert = self.cert.lock().await; + let mut configuration = self.updatable_configuration.lock().await; + + // Fetch a new certificate or use the cached one if it's still valid + // We add 5 to the timestamp to try and ensure by the time the user + // taps their key, the certificate is still valid. This appears to + // primarily be an issue with GitHub pull and push tiers. + let certificate = match (&*existing_cert, timestamp + 5 < *stale_at) { + // In the case we have a certificate and it's not expired. + (Some(cert), true) => { + debug!( + "Using cached certificate which expires in {} seconds", + *stale_at - timestamp + ); + cert.clone() + } + // All other cases require us to fetch a certificate from one + // of the configured servers + _ => { + // Fetch a new certificate from one of the servers + let cert = fetch_new_certificate( + &mut configuration, + &self.signatory, + &self.certificate_options, + &self.notification_function, + ) + .await?; + + // This is ugly doing a mutation in a map + // Look for a better way to do this. + *existing_cert = Some(cert.clone()); + *stale_at = cert.valid_before; + + cert + } + }; + Ok(Some(certificate)) + } else { + let stale_at = self.stale_at.lock().await; + let existing_cert = self.cert.lock().await; + + // Fetch a new certificate or use the cached one if it's still valid + // We add 5 to the timestamp to try and ensure by the time the user + // taps their key, the certificate is still valid. This appears to + // primarily be an issue with GitHub pull and push tiers. + let certificate = match (&*existing_cert, timestamp + 5 < *stale_at) { + // In the case we have a certificate and it's not expired. + (Some(cert), true) => { + debug!( + "Using cached certificate which expires in {} seconds", + *stale_at - timestamp + ); + Some(cert.clone()) + } + // All other cases require us to fetch a certificate from one + // of the configured servers + _ => None + }; + Ok(certificate) + } + } + + /// Fetch the previous cert if present and valid. + /// If no such cert is present, return None. + fn get_certificate(&self, handle: &Handle, fetch_new_cert_if_needed: bool) -> Result, RusticaAgentLibraryError> { + handle.block_on(async { + self.get_certificate_async(fetch_new_cert_if_needed).await + }) + } + +} + #[async_trait] impl SshAgentHandler for Handler { async fn add_identity(&self, private_key: PrivateKey) -> Result { @@ -218,50 +314,13 @@ impl SshAgentHandler for Handler { key_comment: format!("Yubikey Serial: {} Slot: {:?}", x.1.serial, x.1.slot), })); - let timestamp = SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap() - .as_secs(); - - let mut stale_at = self.stale_at.lock().await; - let mut existing_cert = self.cert.lock().await; - let mut configuration = self.updatable_configuration.lock().await; - - // Fetch a new certificate or use the cached one if it's still valid - let certificate = match (&*existing_cert, timestamp < *stale_at) { - // In the case we have a certificate and it's not expired. - (Some(cert), true) => Ok(cert.clone()), - // All other cases require us to fetch a certificate from one - // of the configured servers - _ => { - // Send a notification in case the user is going to need to - // tap their key to prove ownership before receiving their - // certificate - if let Some(f) = &self.notification_function { - f() - } - - // Fetch a new certificate from one of the servers - fetch_new_certificate( - &mut configuration, - &self.signatory, - &self.certificate_options, - ) - .await - .map(|cert| { - let ident = Identity { - key_blob: cert.serialized, - key_comment: cert.comment.unwrap_or_default(), - }; - - // This is ugly doing a mutation in a map - // Look for a better way to do this. - *existing_cert = Some(ident.clone()); - *stale_at = cert.valid_before; - - ident - }) - } + let certificate = match self.get_certificate_async(true).await { + Ok(Some(v)) => Ok(Identity { + key_blob: v.serialized, + key_comment: v.comment.unwrap_or_default(), + }), + Ok(None) => Err(RusticaAgentLibraryError::NoServersReturnedCertificate), + Err(e) => Err(e), }; let key = Identity { @@ -294,7 +353,10 @@ impl SshAgentHandler for Handler { trace!("Sign call"); // Extract the pubkey fingerprint from either the SSH pubkey or the SSH cert - let fingerprint = match (Certificate::from_bytes(&pubkey), PublicKey::from_bytes(&pubkey)) { + let fingerprint = match ( + Certificate::from_bytes(&pubkey), + PublicKey::from_bytes(&pubkey), + ) { (Ok(cert), _) => cert.key.fingerprint(), (_, Ok(pubkey)) => pubkey.fingerprint(), _ => return Err(AgentError::from("Invalid key blob")), @@ -304,15 +366,13 @@ impl SshAgentHandler for Handler { // key is the same process as keys added afterwards, we do this to prevent duplication // of the private key based signing code. // TODO: @obelisk make this better - if let Some(private_key) = - self.identities.lock().await.get(&pubkey).map(|x| x.clone()) - { + if let Some(private_key) = self.identities.lock().await.get(&pubkey).map(|x| x.clone()) { let signature = match private_key.sign(&data) { None => return Err(AgentError::from("Signing Error")), Some(signature) => signature, }; - return Ok(Response::SignResponse { signature }) + return Ok(Response::SignResponse { signature }); } else if let Some(descriptor) = self.piv_identities.get(&pubkey) { let mut yk = Yubikey::open(descriptor.serial).map_err(|e| { println!("Unable to open Yubikey: {e}"); @@ -320,7 +380,10 @@ impl SshAgentHandler for Handler { })?; if let Some(f) = &self.notification_function { + println!("Trying to send a notification"); f() + } else { + println!("No notification function set"); } if let Some(pin) = &descriptor.pin { @@ -361,7 +424,7 @@ impl SshAgentHandler for Handler { Some(signature) => signature, }; - return Ok(Response::SignResponse { signature }) + return Ok(Response::SignResponse { signature }); } else if let Signatory::Yubikey(signer) = &self.signatory { let mut yk = signer.yk.lock().await; // Don't sign requests if the requested key does not match the signatory @@ -393,7 +456,7 @@ impl SshAgentHandler for Handler { return Ok(Response::SignResponse { signature }); } else { return Err(AgentError::from("Signing Error: No Valid Keys")); - }; + } } } @@ -568,9 +631,13 @@ pub async fn fetch_new_certificate( configuration: &mut UpdatableConfiguration, signatory: &Signatory, options: &CertificateConfig, + notification_function: &Option>, ) -> Result { for server in configuration.get_servers_mut() { - match server.refresh_certificate_async(signatory, options).await { + match server + .refresh_certificate_async(signatory, options, notification_function) + .await + { Ok((cert, mtls_credentials)) => { let parsed_cert = Certificate::from_string(&cert.cert) .map_err(|e| RusticaAgentLibraryError::ServerReturnedInvalidCertificate(e))?; @@ -680,3 +747,21 @@ pub async fn register_key( } Err(RusticaAgentLibraryError::NoServersCouldRegisterKey) } + +pub async fn get_allowed_signers( + servers: &[RusticaServer], +) -> Result { + for server in servers.iter() { + match server.get_allowed_signers_async().await { + Ok(allowed_signers) => return Ok(allowed_signers), + Err(e) => { + error!( + "Could not fetch allowed signers from server: {}. Gave error: {}", + server.address, + e.to_string(), + ) + } + } + } + Err(RusticaAgentLibraryError::NoServersReturnedAllowedSigners) +} diff --git a/rustica-agent/src/rustica/allowed_signer.rs b/rustica-agent/src/rustica/allowed_signer.rs new file mode 100644 index 00000000..404ec228 --- /dev/null +++ b/rustica-agent/src/rustica/allowed_signer.rs @@ -0,0 +1,49 @@ +use super::error::RefreshError; +use crate::RusticaServer; + +use super::AllowedSignersRequest; + +use std::io::Read; + +use x509_parser::nom::AsBytes; +use tokio::runtime::Handle; + +impl RusticaServer { + pub async fn get_allowed_signers_async( + &self, + ) -> Result { + let request = AllowedSignersRequest{}; + let request = tonic::Request::new(request); + + let mut client = super::get_rustica_client(&self).await?; + + let response = client.allowed_signers(request).await?; + let response = response.into_inner(); + + // Decode zstd-compressed allowed_signers + let mut allowed_signers_decoder = match zstd::stream::Decoder::new(response.compressed_allowed_signers.as_bytes()) { + Ok(decoder) => decoder, + Err(e) => { + error!("Unable to initialize zstd decoder: {}", e.to_string()); + return Err(RefreshError::UnknownError); + }, + }; + let mut allowed_signers = String::new(); + if let Err(e) = allowed_signers_decoder.read_to_string(&mut allowed_signers) { + error!("Unable to decompress allowed signers: {}", e.to_string()); + return Err(RefreshError::BadAllowedSigners); + } + + Ok(allowed_signers) + } + + pub fn get_allowed_signers( + &self, + handle: &Handle, + ) -> Result { + handle.block_on(async { + self.get_allowed_signers_async() + .await + }) + } +} diff --git a/rustica-agent/src/rustica/cert.rs b/rustica-agent/src/rustica/cert.rs index d5d69e9e..c9f2adc9 100644 --- a/rustica-agent/src/rustica/cert.rs +++ b/rustica-agent/src/rustica/cert.rs @@ -12,8 +12,10 @@ impl RusticaServer { &self, signatory: &Signatory, options: &CertificateConfig, + notification_function: &Option>, ) -> Result<(RusticaCert, Option), RefreshError> { - let (mut client, challenge) = super::complete_rustica_challenge(self, signatory).await?; + let (mut client, challenge) = + super::complete_rustica_challenge(self, signatory, notification_function).await?; let current_timestamp = match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { Ok(ts) => ts.as_secs(), @@ -68,7 +70,11 @@ impl RusticaServer { signatory: &mut Signatory, options: &CertificateConfig, handle: &Handle, + notification_function: &Option>, ) -> Result<(RusticaCert, Option), RefreshError> { - handle.block_on(async { self.refresh_certificate_async(signatory, options).await }) + handle.block_on(async { + self.refresh_certificate_async(signatory, options, notification_function) + .await + }) } } diff --git a/rustica-agent/src/rustica/error.rs b/rustica-agent/src/rustica/error.rs index 343fccc5..cc1c688d 100644 --- a/rustica-agent/src/rustica/error.rs +++ b/rustica-agent/src/rustica/error.rs @@ -17,7 +17,9 @@ pub enum RefreshError { ConfigurationError(String), TransportBadStatus(tonic::Status), BadEncodedData(hex::FromHexError), - RusticaServerError(ServerError) + RusticaServerError(ServerError), + BadAllowedSigners, + UnknownError, } @@ -32,7 +34,9 @@ impl fmt::Display for RefreshError { RefreshError::InvalidUri => write!(f, "Provided address of remote service was invalid"), RefreshError::TransportBadStatus(ref err) => write!(f, "Bad status from server: {}", err), RefreshError::BadEncodedData(ref err) => write!(f, "Bad hex encoding: {}", err), - RefreshError::RusticaServerError(ref err) => write!(f, "Error from server: {}", err.message) + RefreshError::RusticaServerError(ref err) => write!(f, "Error from server: {}", err.message), + RefreshError::BadAllowedSigners => write!(f, "Bad allowed signers data"), + RefreshError::UnknownError => write!(f, "Unknown error occured"), } } } diff --git a/rustica-agent/src/rustica/key.rs b/rustica-agent/src/rustica/key.rs index e42782fb..fc9149c9 100644 --- a/rustica-agent/src/rustica/key.rs +++ b/rustica-agent/src/rustica/key.rs @@ -28,7 +28,8 @@ impl RusticaServer { signatory: &mut Signatory, attestation: &PIVAttestation, ) -> Result<(), RefreshError> { - let (mut client, challenge) = super::complete_rustica_challenge(self, signatory).await?; + let (mut client, challenge) = + super::complete_rustica_challenge(self, signatory, &None).await?; let request = RegisterKeyRequest { certificate: attestation.certificate.clone(), @@ -48,8 +49,7 @@ impl RusticaServer { key: &PIVAttestation, handle: &Handle, ) -> Result<(), RefreshError> { - handle - .block_on(async { self.register_key_async(signatory, key).await }) + handle.block_on(async { self.register_key_async(signatory, key).await }) } pub async fn register_u2f_key_async( @@ -58,7 +58,8 @@ impl RusticaServer { application: &str, attestation: &U2FAttestation, ) -> Result<(), RefreshError> { - let (mut client, challenge) = super::complete_rustica_challenge(self, signatory).await?; + let (mut client, challenge) = + super::complete_rustica_challenge(self, signatory, &None).await?; let request = RegisterU2fKeyRequest { auth_data: attestation.auth_data.clone(), @@ -68,6 +69,7 @@ impl RusticaServer { intermediate: attestation.intermediate.clone(), alg: attestation.alg, challenge: Some(challenge), + u2f_challenge_hashed: true, }; let request = tonic::Request::new(request); diff --git a/rustica-agent/src/rustica/mod.rs b/rustica-agent/src/rustica/mod.rs index 835616ce..6aa47c28 100644 --- a/rustica-agent/src/rustica/mod.rs +++ b/rustica-agent/src/rustica/mod.rs @@ -2,6 +2,7 @@ pub mod cert; pub mod error; pub mod key; pub mod x509; +pub mod allowed_signer; use std::ops::Deref; use std::time::Duration; @@ -12,6 +13,7 @@ pub use rustica_proto::rustica_client::RusticaClient; pub use rustica_proto::{ AttestedX509CertificateRequest, AttestedX509CertificateResponse, CertificateRequest, CertificateResponse, Challenge, ChallengeRequest, RegisterKeyRequest, RegisterU2fKeyRequest, + AllowedSignersRequest, AllowedSignersResponse, }; use sshcerts::ssh::Certificate as SSHCertificate; @@ -58,6 +60,7 @@ pub async fn get_rustica_client( pub async fn complete_rustica_challenge( server: &RusticaServer, signatory: &Signatory, + notification_function: &Option>, ) -> Result<(RusticaClient, Challenge), RefreshError> { let ssh_pubkey = match signatory { Signatory::Yubikey(signer) => { @@ -112,6 +115,12 @@ pub async fn complete_rustica_challenge( return Err(RefreshError::ServerChallengeNotForClientKey); } + // We need to sign the challenge so let's notify the user they + // will need to interact with their device if (if a device is being used) + if let Some(f) = notification_function { + f(); + } + let resigned_certificate = match signatory { Signatory::Yubikey(signer) => { let signature = signer diff --git a/rustica-agent/src/sshagent/agent.rs b/rustica-agent/src/sshagent/agent.rs index dda98588..60b3c057 100644 --- a/rustica-agent/src/sshagent/agent.rs +++ b/rustica-agent/src/sshagent/agent.rs @@ -26,17 +26,17 @@ impl Agent { } } - pub async fn run(handler: T, socket_path: String) { + pub async fn run(handler: Arc, socket_path: String) { return Self::run_with_termination_channel(handler, socket_path, None).await; } pub async fn run_with_termination_channel( - handler: T, + handler: Arc, socket_path: String, term_channel: Option>, ) { let listener = UnixListener::bind(socket_path).unwrap(); - let handler = Arc::new(handler); + let handler = handler.clone(); if let Some(mut term_channel) = term_channel { loop { diff --git a/rustica/Cargo.toml b/rustica/Cargo.toml index 5714b317..e663d288 100644 --- a/rustica/Cargo.toml +++ b/rustica/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustica" -version = "0.11.1" +version = "0.12.0" authors = ["Mitchell Grenier "] edition = "2021" @@ -35,12 +35,17 @@ prost = "0.11" ring = "0.17" serde = { version = "1.0", features = ["derive"] } # For Production -sshcerts = { version = "0.12", default-features = false, features = [ +# sshcerts = { version = "0.12", default-features = false, features = [ +# "fido-lite", +# "x509-support", +# "yubikey-lite", +# ] } +# For Development +sshcerts = { version = "0.13.2", default-features = false, features = [ "fido-lite", "x509-support", "yubikey-lite", ] } -# For Development # sshcerts = { path = "../../sshcerts", default-features = false, features = [ # "fido-lite", # "x509-support", @@ -73,5 +78,9 @@ reqwest = { version = "0.11", default-features = false, features = [ ], optional = true } serde_json = { version = "1.0", optional = true } +# Dependencies for allowed_signers feature +zstd = "0.13.1" +lru = "0.12.3" + [build-dependencies] tonic-build = "0.9" diff --git a/rustica/migrations/2021-03-18-175456_registered-keys/up.sql b/rustica/migrations/2021-03-18-175456_registered-keys/up.sql index b30c2998..a33d6ffe 100644 --- a/rustica/migrations/2021-03-18-175456_registered-keys/up.sql +++ b/rustica/migrations/2021-03-18-175456_registered-keys/up.sql @@ -1,10 +1,17 @@ CREATE TABLE registered_keys ( fingerprint TEXT PRIMARY KEY NOT NULL, - user TEXT NOT NULL, + pubkey TEXT NOT NULL, + user TEXT NOT NULL, pin_policy TEXT NULL, touch_policy TEXT NULL, hsm_serial TEXT NULL, firmware TEXT NULL, attestation_certificate TEXT NULL, - attestation_intermediate TEXT NULL -); \ No newline at end of file + attestation_intermediate TEXT NULL, + auth_data TEXT NULL, + auth_data_signature TEXT NULL, + aaguid TEXT NULL, + challenge TEXT NULL, + alg INTEGER NULL, + application TEXT NULL +); diff --git a/rustica/migrations/2023-04-10-043746_add_x509_by_serial/up.sql b/rustica/migrations/2023-04-10-043746_add_x509_by_serial/up.sql index 5c513423..697adfd0 100644 --- a/rustica/migrations/2023-04-10-043746_add_x509_by_serial/up.sql +++ b/rustica/migrations/2023-04-10-043746_add_x509_by_serial/up.sql @@ -1,7 +1,8 @@ -- Your SQL goes here CREATE TABLE x509_authorizations ( - user TEXT NOT NULL, + user TEXT NOT NULL, hsm_serial TEXT NOT NULL, require_touch BOOLEAN NOT NULL, + authority TEXT NOT NULL, PRIMARY KEY (user, hsm_serial) -); \ No newline at end of file +); diff --git a/rustica/src/auth/database.rs b/rustica/src/auth/database.rs index 152f4473..83a982d2 100644 --- a/rustica/src/auth/database.rs +++ b/rustica/src/auth/database.rs @@ -18,6 +18,8 @@ use super::{ KeyAttestation, X509AuthorizationRequestProperties, X509Authorization, + AllowedSigners, + AllowedSigner, }; use sshcerts::ssh::CertType; @@ -115,6 +117,7 @@ impl LocalDatabase { let mut conn = establish_connection(&self.path); let mut registered_key = models::RegisteredKey { fingerprint: req.fingerprint.clone(), + pubkey: req.pubkey.clone(), user: req.mtls_identities.join(","), firmware: None, hsm_serial: None, @@ -181,7 +184,7 @@ impl LocalDatabase { let authorization: Vec<_> = { use schema::x509_authorizations::dsl::*; - let results = x509_authorizations.filter(user.eq(mtls_user).and(hsm_serial.eq(att_serial.to_string()))) + let results = x509_authorizations.filter(user.eq(mtls_user).and(authority.eq(&auth_props.authority).and(hsm_serial.eq(att_serial.to_string())))) .load::(&mut conn) .expect("Error loading authorized hosts"); @@ -211,4 +214,32 @@ impl LocalDatabase { valid_after: current_time, }) } + + pub fn get_allowed_signers(&self) -> Result { + let mut conn = establish_connection(&self.path); + + let result = { + use schema::registered_keys::dsl::*; + + // Fetch every pubkey and the owner's identity + schema::registered_keys::table + .select((user, pubkey)) + .load(&mut conn) + }; + + if let Err(e) = result { + return Err(AuthorizationError::DatabaseError(format!("{}", e))); + } + + // Get the response from the backend service + let allowed_signers: Vec<(String, String)> = result.unwrap(); + let allowed_signers = allowed_signers.into_iter() + .map(|allowed_signer| AllowedSigner{ + identity: allowed_signer.0, + pubkey: allowed_signer.1, + }) + .collect(); + + Ok(AllowedSigners{ allowed_signers }) + } } diff --git a/rustica/src/auth/database/models.rs b/rustica/src/auth/database/models.rs index 86d2e3e7..994a45aa 100644 --- a/rustica/src/auth/database/models.rs +++ b/rustica/src/auth/database/models.rs @@ -43,6 +43,7 @@ pub struct FingerprintPermission { #[diesel(table_name = registered_keys)] pub struct RegisteredKey { pub fingerprint: String, + pub pubkey: String, pub user: String, pub pin_policy: Option, pub touch_policy: Option, @@ -63,4 +64,5 @@ pub struct X509Authorization { pub user: String, pub hsm_serial: String, pub require_touch: bool, -} \ No newline at end of file + pub authority: String, +} diff --git a/rustica/src/auth/database/schema.rs b/rustica/src/auth/database/schema.rs index a3b75ef8..8072c18c 100644 --- a/rustica/src/auth/database/schema.rs +++ b/rustica/src/auth/database/schema.rs @@ -54,6 +54,7 @@ table! { table! { registered_keys (fingerprint) { fingerprint -> Text, + pubkey -> Text, user -> Text, pin_policy -> Nullable, touch_policy -> Nullable, @@ -75,6 +76,7 @@ table! { user -> Text, hsm_serial -> Text, require_touch -> Bool, + authority -> Text, } } diff --git a/rustica/src/auth/external.rs b/rustica/src/auth/external.rs index ad8b23bc..88743666 100644 --- a/rustica/src/auth/external.rs +++ b/rustica/src/auth/external.rs @@ -1,14 +1,15 @@ -use asn1::{Utf8String}; +use asn1::Utf8String; use author::author_client::AuthorClient; -use author::{AddIdentityDataRequest, AuthorizeRequest}; +use author::{AddIdentityDataRequest, AuthorizeRequest, AllowedSignersRequest}; use rcgen::CustomExtension; use tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity}; use x509_parser::oid_registry::Oid; use super::{ - SshAuthorization, AuthorizationError, SshAuthorizationRequestProperties, KeyAttestation, - RegisterKeyRequestProperties, X509Authorization, X509AuthorizationRequestProperties, + AuthorizationError, KeyAttestation, RegisterKeyRequestProperties, SshAuthorization, + SshAuthorizationRequestProperties, X509Authorization, X509AuthorizationRequestProperties, + AllowedSigners, AllowedSigner, }; use serde::Deserialize; use std::collections::HashMap; @@ -270,9 +271,7 @@ impl AuthServer { auth_props: &X509AuthorizationRequestProperties, ) -> Result { let mut authorization_request = HashMap::new(); - // TODO: This is an anachronistic hold over and should be updated from - // quorum_mtls to rustica_mtls or rustica_x509 - authorization_request.insert(format!("type"), "quorum_mtls".to_string()); + authorization_request.insert(format!("type"), "rustica_mtls".to_string()); authorization_request.insert("authority".to_string(), auth_props.authority.clone()); // Identities @@ -287,7 +286,10 @@ impl AuthServer { ); identities.insert(format!("leaf"), hex::encode(&auth_props.attestation)); - identities.insert(format!("intermediate"), hex::encode(&auth_props.attestation_intermediate)); + identities.insert( + format!("intermediate"), + hex::encode(&auth_props.attestation_intermediate), + ); let request = tonic::Request::new(AuthorizeRequest { identities, @@ -296,12 +298,12 @@ impl AuthServer { let client_identity = Identity::from_pem(self.mtls_cert.as_bytes(), &self.mtls_key.as_bytes()); - + let tls = ClientTlsConfig::new() .domain_name(&self.server) .ca_certificate(Certificate::from_pem(self.ca.as_bytes())) .identity(client_identity); - + let channel = match Channel::from_shared(format!("https://{}:{}", &self.server, &self.port)) { Ok(c) => c, @@ -339,44 +341,62 @@ impl AuthServer { // For all the returned objects that are OIDs, pull them out and // process them. - let extensions = response.iter().filter_map(|entry| { - if let Ok(oid) = Oid::from_str(entry.0.as_str()) { - let oid_ints: Vec = match oid.iter() { - Some(ints) => ints.collect(), - _ => return None, - }; - let entry_bytes = match asn1::write_single(&Utf8String::new(entry.1)) { - Ok(b) => b, - Err(_) => return None, - }; - let ext = CustomExtension::from_oid_content(&oid_ints, entry_bytes); - Some(ext) - } else { - None - } - }).collect(); + let extensions = response + .iter() + .filter_map(|entry| { + if let Ok(oid) = Oid::from_str(entry.0.as_str()) { + let oid_ints: Vec = match oid.iter() { + Some(ints) => ints.collect(), + _ => return None, + }; + let entry_bytes = match asn1::write_single(&Utf8String::new(entry.1)) { + Ok(b) => b, + Err(_) => return None, + }; + let ext = CustomExtension::from_oid_content(&oid_ints, entry_bytes); + Some(ext) + } else { + None + } + }) + .collect(); - let mtls_user = auth_props.mtls_identities.get(0).ok_or(AuthorizationError::AuthorizerError)?; - - let (valid_before, valid_after) = match (response.get("valid_before").map(|x| x.parse::()), response.get("valid_after").map(|x| x.parse::())) { + let mtls_user = auth_props + .mtls_identities + .get(0) + .ok_or(AuthorizationError::AuthorizerError)?; + + let (valid_before, valid_after) = match ( + response.get("valid_before").map(|x| x.parse::()), + response.get("valid_after").map(|x| x.parse::()), + ) { (Some(Ok(vb)), Some(Ok(va))) => (vb, va), (None, None) => { - let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(); + let current_time = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(); (current_time + (3600 * 12), current_time) } - _ => return Err(AuthorizationError::AuthorizerError) + _ => return Err(AuthorizationError::AuthorizerError), }; let serial = match response.get("serial").map(|x| x.parse::()) { Some(Ok(serial)) => serial, Some(Err(_)) => return Err(AuthorizationError::AuthorizerError), - None => 0xFEFEFEFEFE + None => 0xFEFEFEFEFE, }; - + // Success, build the response return Ok(X509Authorization { - authority: auth_props.authority.clone(), - issuer: response.get("issuer").unwrap_or(&"Rustica".to_owned()).to_string(), + authority: response + .get("authority") + .ok_or(AuthorizationError::AuthorizerError)? + .to_string(), + issuer: response + .get("issuer") + .unwrap_or(&"Rustica".to_owned()) + .to_string(), common_name: mtls_user.clone(), sans: vec![mtls_user.clone()], extensions, @@ -385,4 +405,59 @@ impl AuthServer { valid_after, }); } + + pub async fn get_allowed_signers(&self) -> Result { + let request = tonic::Request::new(AllowedSignersRequest {}); + + let client_identity = + Identity::from_pem(self.mtls_cert.as_bytes(), &self.mtls_key.as_bytes()); + + let tls = ClientTlsConfig::new() + .domain_name(&self.server) + .ca_certificate(Certificate::from_pem(self.ca.as_bytes())) + .identity(client_identity); + + let channel = + match Channel::from_shared(format!("https://{}:{}", &self.server, &self.port)) { + Ok(c) => c, + Err(e) => { + error!( + "Could not open a channel to the authorization server: {}", + e + ); + return Err(AuthorizationError::ConnectionFailure); + } + } + .timeout(Duration::from_secs(10)) + .tls_config(tls) + .map_err(|_| AuthorizationError::ConnectionFailure)? + .connect() + .await + .map_err(|_| AuthorizationError::ConnectionFailure)?; + + let mut client = AuthorClient::new(channel); + let response = client.get_allowed_signers(request).await; + + if let Err(e) = response { + error!("Authorization server returned error: {}", e); + if e.code() == tonic::Code::PermissionDenied { + error!("Permission denied from backend"); + return Err(AuthorizationError::AuthorizerError); + } else { + error!("Backend threw an unexpected error"); + return Err(AuthorizationError::AuthorizerError); + } + } + + // Get the response from the backend service + let allowed_signers = response.unwrap().into_inner().allowed_signers; + let allowed_signers = allowed_signers.into_iter() + .map(|allowed_signer| AllowedSigner{ + identity: allowed_signer.identity, + pubkey: allowed_signer.pubkey, + }) + .collect(); + + Ok(AllowedSigners{ allowed_signers }) + } } diff --git a/rustica/src/auth/mod.rs b/rustica/src/auth/mod.rs index 85baf2ef..a5176f60 100644 --- a/rustica/src/auth/mod.rs +++ b/rustica/src/auth/mod.rs @@ -31,7 +31,9 @@ impl std::fmt::Display for AuthorizationError { AuthorizationError::CertType => write!(f, "Not authorized for this certificate type"), AuthorizationError::NotAuthorized => write!(f, "Not authorized"), AuthorizationError::AuthorizerError => write!(f, "Authorization error"), - AuthorizationError::ConnectionFailure => write!(f, "Could not connect to authorization service"), + AuthorizationError::ConnectionFailure => { + write!(f, "Could not connect to authorization service") + } AuthorizationError::DatabaseError(ref m) => write!(f, "Database error: {}", m), AuthorizationError::ExternalError(ref m) => write!(f, "{}", m), } @@ -96,11 +98,24 @@ pub struct X509Authorization { #[derive(Debug)] pub struct RegisterKeyRequestProperties { pub fingerprint: String, + pub pubkey: String, pub mtls_identities: Vec, pub requester_ip: String, pub attestation: Option, } + +#[derive(Debug)] +pub struct AllowedSigner { + pub identity: String, + pub pubkey: String, +} + +#[derive(Debug)] +pub struct AllowedSigners { + pub allowed_signers: Vec, +} + pub enum AuthorizationMechanism { #[cfg(feature = "local-db")] Local(database::LocalDatabase), @@ -108,35 +123,67 @@ pub enum AuthorizationMechanism { } impl AuthorizationMechanism { - pub async fn authorize_ssh_cert(&self, auth_props: &SshAuthorizationRequestProperties) -> Result { + pub async fn authorize_ssh_cert( + &self, + auth_props: &SshAuthorizationRequestProperties, + ) -> Result { match &self { #[cfg(feature = "local-db")] AuthorizationMechanism::Local(local) => local.authorize_ssh_cert(auth_props), - AuthorizationMechanism::External(external) => external.authorize_ssh_cert(auth_props).await, + AuthorizationMechanism::External(external) => { + external.authorize_ssh_cert(auth_props).await + } } } - pub async fn authorize_attested_x509_cert(&self, auth_props: &X509AuthorizationRequestProperties) -> Result { + pub async fn authorize_attested_x509_cert( + &self, + auth_props: &X509AuthorizationRequestProperties, + ) -> Result { match &self { #[cfg(feature = "local-db")] AuthorizationMechanism::Local(local) => local.authorize_attested_x509_cert(auth_props), - AuthorizationMechanism::External(external) => external.authorize_attested_x509_cert(auth_props).await, + AuthorizationMechanism::External(external) => { + external.authorize_attested_x509_cert(auth_props).await + } } } - pub async fn register_key(&self, register_properties: &RegisterKeyRequestProperties) -> Result<(), AuthorizationError> { + pub async fn register_key( + &self, + register_properties: &RegisterKeyRequestProperties, + ) -> Result<(), AuthorizationError> { match &self { #[cfg(feature = "local-db")] AuthorizationMechanism::Local(local) => local.register_key(register_properties), - AuthorizationMechanism::External(external) => external.register_key(register_properties).await, + AuthorizationMechanism::External(external) => { + external.register_key(register_properties).await + } + } + } + + pub async fn get_allowed_signers( + &self, + ) -> Result { + match &self { + #[cfg(feature = "local-db")] + AuthorizationMechanism::Local(local) => local.get_allowed_signers(), + AuthorizationMechanism::External(external) => { + external.get_allowed_signers().await + } } } pub fn info(&self) -> String { match &self { #[cfg(feature = "local-db")] - AuthorizationMechanism::Local(local) => format!("Configured authorizer: Local DB at {}", &local.path), - AuthorizationMechanism::External(external) => format!("Configured authorizer: Remote Service at {}", &external.server), + AuthorizationMechanism::Local(local) => { + format!("Configured authorizer: Local DB at {}", &local.path) + } + AuthorizationMechanism::External(external) => format!( + "Configured authorizer: Remote Service at {}", + &external.server + ), } } } diff --git a/rustica/src/config/mod.rs b/rustica/src/config/mod.rs index a8d11a57..0d1b48a1 100644 --- a/rustica/src/config/mod.rs +++ b/rustica/src/config/mod.rs @@ -1,16 +1,21 @@ use crate::auth::AuthorizationConfiguration; use crate::logging::{Log, LoggingConfiguration}; -use crate::server::RusticaServer; +use crate::server::{AllowedSignersCache, RusticaServer}; use crate::signing::{SigningConfiguration, SigningError}; use clap::{Arg, Command}; use crossbeam_channel::{unbounded, Receiver}; +use lru::LruCache; use ring::{hmac, rand}; use serde::Deserialize; use std::convert::TryInto; use std::net::SocketAddr; +use std::time::Duration; +use std::num::NonZeroUsize; + +use tokio::sync::{RwLock, Mutex}; use sshcerts::{ssh::KeyTypeKind, CertType, PrivateKey}; @@ -21,6 +26,13 @@ pub struct ClientAuthorityConfiguration { pub expiration_renewal_period: u64, } +#[derive(Deserialize)] +pub struct AllowedSignersConfiguration { + pub cache_validity_length: Duration, + pub lru_rate_limiter_size: NonZeroUsize, + pub rate_limit_cooldown: Duration, +} + #[derive(Deserialize)] pub struct Configuration { pub server_cert: String, @@ -32,6 +44,7 @@ pub struct Configuration { pub require_rustica_proof: bool, pub require_attestation_chain: bool, pub logging: LoggingConfiguration, + pub allowed_signers: AllowedSignersConfiguration, } pub struct RusticaSettings { @@ -177,6 +190,13 @@ pub async fn configure() -> Result { "Could not create a PEM from the requested signing system: {e}" ))) })?; + + let allowed_signers_rate_limiter = LruCache::new(config.allowed_signers.lru_rate_limiter_size); + + let allowed_signers_cache = AllowedSignersCache { + compressed_allowed_signers: vec![], + expiry_timestamp: Duration::ZERO, + }; // We're only validating that we can use this configuration so do not start // This happens after we've parsed the config but also confirmed access to @@ -194,6 +214,9 @@ pub async fn configure() -> Result { require_rustica_proof: config.require_rustica_proof, require_attestation_chain: config.require_attestation_chain, client_authority: config.client_authority, + allowed_signers: config.allowed_signers, + allowed_signers_rate_limiter: Mutex::new(allowed_signers_rate_limiter).into(), + allowed_signers_cache: RwLock::new(allowed_signers_cache).into(), }; Ok(RusticaSettings { diff --git a/rustica/src/error.rs b/rustica/src/error.rs index 1a804278..00aa34cf 100644 --- a/rustica/src/error.rs +++ b/rustica/src/error.rs @@ -12,6 +12,10 @@ pub enum RusticaServerError { BadCertOptions = 5, NotAuthorized = 6, BadRequest = 7, + PivClientCertTooBig = 8, + PivIntermediateCertTooBig = 9, + U2fAttestationTooBig = 10, + U2fIntermediateCertTooBig = 11, Unknown = 9001, } @@ -23,4 +27,4 @@ impl From for RusticaServerError { _ => RusticaServerError::Unknown, } } -} \ No newline at end of file +} diff --git a/rustica/src/server.rs b/rustica/src/server.rs index 84677ab1..00a8e7a8 100644 --- a/rustica/src/server.rs +++ b/rustica/src/server.rs @@ -2,7 +2,7 @@ use crate::auth::{ AuthorizationMechanism, RegisterKeyRequestProperties, SshAuthorizationRequestProperties, X509AuthorizationRequestProperties, }; -use crate::config::ClientAuthorityConfiguration; +use crate::config::{AllowedSignersConfiguration, ClientAuthorityConfiguration}; use crate::error::RusticaServerError; use crate::logging::{ CertificateIssued, InternalMessage, KeyInfo, KeyRegistrationFailure, Log, Severity, @@ -11,7 +11,7 @@ use crate::logging::{ use crate::rustica::{ rustica_server::Rustica, CertificateRequest, CertificateResponse, Challenge, ChallengeRequest, ChallengeResponse, RegisterKeyRequest, RegisterKeyResponse, RegisterU2fKeyRequest, - RegisterU2fKeyResponse, + RegisterU2fKeyResponse, AllowedSignersRequest, AllowedSignersResponse, }; use crate::rustica::{AttestedX509CertificateRequest, AttestedX509CertificateResponse}; use crate::signing::SigningMechanism; @@ -24,14 +24,25 @@ use sshcerts::ssh::{CertType, Certificate, PrivateKey, PublicKey}; use ring::hmac; use std::collections::HashMap; +use std::io::Write; use std::time::{Duration, UNIX_EPOCH}; use std::{sync::Arc, time::SystemTime}; use tonic::transport::Certificate as TonicCertificate; use tonic::{Request, Response, Status}; +use tokio::sync::{RwLock, Mutex}; + use x509_parser::der_parser::oid; use x509_parser::prelude::*; +use lru::LruCache; + +pub struct AllowedSignersCache { + // allowed_signers is compressed using zstd + pub compressed_allowed_signers: Vec, + pub expiry_timestamp: Duration, +} + pub struct RusticaServer { pub log_sender: Sender, pub hmac_key: hmac::Key, @@ -41,6 +52,11 @@ pub struct RusticaServer { pub require_rustica_proof: bool, pub require_attestation_chain: bool, pub client_authority: ClientAuthorityConfiguration, + pub allowed_signers: AllowedSignersConfiguration, + // Identity-based rate limiter using LRU cache is needed for the allowed_signers endpoint since the allowed_signers + // payload might be heavy even when compressed + pub allowed_signers_rate_limiter: Arc>>, + pub allowed_signers_cache: Arc>, } struct MtlsCertificateInfo { @@ -336,6 +352,37 @@ fn validate_request( )) } +/// Check that mTLS identity is not rate limited for allowed_signers endpoint +async fn is_rate_limited( + srv: &RusticaServer, + identities: String, + current_time: Duration, +) -> bool { + let rate_limiter = srv.allowed_signers_rate_limiter.clone(); + let mut rate_limiter = rate_limiter.lock().await; + + // LruCache.push returns the previous entry for mtls_identities or the entry that was + // popped due to capacity + let removed_entry = match rate_limiter.push( + identities.clone(), + current_time + srv.allowed_signers.rate_limit_cooldown, + ) { + Some(v) => v, + // If None is returned, then identities is not in the rate_limiter cache + None => return false, + }; + + // If the removed_entry does not belong to identities, then identities is not in the + // rate_limiter cache + if removed_entry.0 != identities { + return false; + } + + // If the removed entry belongs to current mtls_identities, check to see if the last + // request was too recent + current_time < removed_entry.1 +} + #[tonic::async_trait] impl Rustica for RusticaServer { /// Handler when a host is going to make a further request to Rustica @@ -363,6 +410,22 @@ impl Rustica for RusticaServer { Err(_) => return Err(Status::permission_denied("")), }; + // Limit the size of the public key to mitigate DoS + // ED25519 public key strings are 127 chars in length. + // But we will set a reasonably higher upper bound to accommodate other types of + // public keys + if request.pubkey.len() > 1024 { + rustica_warning!( + self, + format!( + "The pubkey size is too large ({} chars) for a challenge request from [{}]", + request.pubkey.len(), + mtls_identities.join(","), + ) + ); + return Err(Status::permission_denied("")); + } + let ssh_pubkey = match PublicKey::from_string(&request.pubkey) { Ok(sshpk) => sshpk, Err(_) => return Err(Status::permission_denied("")), @@ -655,6 +718,7 @@ impl Rustica for RusticaServer { let register_properties = RegisterKeyRequestProperties { fingerprint: fingerprint.clone(), + pubkey: ssh_pubkey.to_string(), mtls_identities: mtls_identities.clone(), requester_ip, attestation, @@ -717,6 +781,7 @@ impl Rustica for RusticaServer { request.alg, &request.u2f_challenge, &request.sk_application, + request.u2f_challenge_hashed, ) { Ok(key) => { // This can only occur if an attestation chain has been provided @@ -759,6 +824,7 @@ impl Rustica for RusticaServer { let register_properties = RegisterKeyRequestProperties { fingerprint: fingerprint.clone(), + pubkey: ssh_pubkey.to_string(), mtls_identities: mtls_identities.clone(), requester_ip, attestation, @@ -780,6 +846,8 @@ impl Rustica for RusticaServer { mtls_identities, }; + println!("Key register error: {}", e); + let _ = self .log_sender .send(Log::KeyRegistrationFailure(KeyRegistrationFailure { @@ -1004,4 +1072,143 @@ impl Rustica for RusticaServer { error_code: 0, })); } + + // Handler used to fetch a list of all signers and their pubkeys + async fn allowed_signers( + &self, + request: Request, + ) -> Result, Status> { + let remote_addr = request.remote_addr().ok_or(Status::permission_denied(""))?; + + let peer = request.peer_certs(); + + let peer = peer.ok_or(Status::permission_denied(""))?; + + // Only support the presenting of a single client certificate + // I've never seen anyone handle multiple ones and since we don't + // need to here, trying to support it will only lead to validation + // issues or inconsistencies. + let cert = if let Some(cert) = peer.get(0) { + cert + } else { + return Err(Status::permission_denied("")); + }; + + let cert_info = match extract_certificate_information(cert) { + Ok(cert_info) => cert_info, + Err(e) => { + rustica_error!(self, format!("Could not validate request: {:?}", e)); + return Err(Status::cancelled("")); + } + }; + + let mtls_identities = cert_info.identities.join(","); + + debug!( + "[{}] from [{}] requested the list of allowed signers", + mtls_identities, + remote_addr, + ); + + // Get current time to check rate limiter and cache expiry + let current_time = match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { + Ok(time) => time, + _ => { + error!("Unable to get the current time"); + return Err(Status::permission_denied("")); + }, + }; + + if is_rate_limited(self, mtls_identities.clone(), current_time).await { + info!( + "[{}] from [{}] is rate limited for allowed_signers call", + mtls_identities, + remote_addr, + ); + return Err(Status::resource_exhausted("")); + } + + // Acquire the read lock to check if the cache expired + let cache = self.allowed_signers_cache.clone(); + { + let cache = cache.read().await; + + // Cache still valid + if current_time <= cache.expiry_timestamp { + let reply = AllowedSignersResponse { + compressed_allowed_signers: cache.compressed_allowed_signers.clone(), + }; + return Ok(Response::new(reply)); + } + } + + // Cache expired. We now need to get the write lock + let mut cache = cache.write().await; + + // It's possible the cache got refreshed while we were waiting on the write lock + // Check again if we need to refresh the cache + + // Cache has been refreshed while we waited on the write lock + if current_time <= cache.expiry_timestamp { + let reply = AllowedSignersResponse { + compressed_allowed_signers: cache.compressed_allowed_signers.clone(), + }; + return Ok(Response::new(reply)); + } + + // Refresh the cache by fetching a new list of signers from the authorizer + let response = match self.authorizer.get_allowed_signers().await { + Ok(response) => response, + Err(e) => { + error!("Failed to call get_allowed_signers on the authorizer: {}", e.to_string()); + return Err(Status::permission_denied("")); + }, + }; + + // Construct the content of allowed signers file in this format + // identity1 pubkey1 + // identity2 pubkey2 + // ... + let allowed_signers: String = response.allowed_signers + .into_iter() + .map(|allowed_signer| format!("{} {}", allowed_signer.identity, allowed_signer.pubkey)) + .collect::>() + .join("\n"); + + // Initialize the encoder to compress allowed_signers + let mut allowed_signers_encoder = match zstd::stream::Encoder::new(Vec::new(), zstd::DEFAULT_COMPRESSION_LEVEL) { + Ok(encoder) => encoder, + Err(e) => { + error!("Failed to initialize zstd encoder: {}", e.to_string()); + return Err(Status::permission_denied("")); + }, + }; + + // Write payload bytes to the compression encoder + if let Err(e) = allowed_signers_encoder.write_all(allowed_signers.as_bytes()) { + error!("Failed to compress allowed_signers: {}", e.to_string()); + return Err(Status::permission_denied("")); + }; + + // Finalize the compression encoding to get the compressed allowed signers payload + let compressed_allowed_signers = match allowed_signers_encoder.finish() { + Ok(data) => data, + Err(e) => { + error!("Failed to complete compressing allowed_signers: {}", e.to_string()); + return Err(Status::permission_denied("")); + }, + }; + + // Update the cache + cache.expiry_timestamp = current_time + self.allowed_signers.cache_validity_length; + cache.compressed_allowed_signers = compressed_allowed_signers; + + info!("Allowed Signers cache was successfully updated"); + + let reply = AllowedSignersResponse { + compressed_allowed_signers: cache.compressed_allowed_signers.clone(), + }; + + Ok(Response::new(reply)) + } } diff --git a/rustica/src/signing/mod.rs b/rustica/src/signing/mod.rs index 8809f876..4213e8cb 100644 --- a/rustica/src/signing/mod.rs +++ b/rustica/src/signing/mod.rs @@ -104,7 +104,6 @@ pub struct SigningMechanism { pub authorities: HashMap>, } - #[derive(Debug)] pub enum SigningError { /// Represents when there was an issue accessing the key material. This @@ -121,7 +120,7 @@ pub enum SigningError { /// expected data #[allow(dead_code)] ParsingError, - UnknownAuthority, + UnknownAuthority(String), DuplicatedKey(String, String), IdenticalUserAndHostKey(String), SignerDoesNotHaveSSHKeys, @@ -134,7 +133,7 @@ impl std::fmt::Display for SigningError { Self::AccessError(e) => write!(f, "Could not access the private key material: {}", e), Self::SigningFailure => write!(f, "The signing operation on the provided certificate failed"), Self::ParsingError => write!(f, "The signature could not be parsed"), - Self::UnknownAuthority => write!(f, "Unknown authority was requested for a signing operation"), + Self::UnknownAuthority(authority) => write!(f, "Unknown authority was requested for a signing operation: {authority}"), Self::DuplicatedKey(a1, a2) => write!(f, "Authorities {a1} and {a2} share at least one key. This is not allowed as it almost always a misconfiguration leading to access that is not correctly restricted"), Self::IdenticalUserAndHostKey(authority) => write!(f, "Authority {authority} has an identical key for both user and host certificates. This is not allowed as it's much safer to use separate keys for both."), Self::SignerDoesNotHaveSSHKeys => write!(f, "Signer was not configured with SSH keys so it cannot create an SSH certificate"), @@ -149,28 +148,39 @@ impl std::fmt::Display for SigningMechanism { for signer in self.authorities.iter() { output.push_str(&format!("Authority: {}\n", signer.0)); - if let Some(fp) = signer.1.get_signer_public_key(CertType::User).map(|x| x.fingerprint().hash) { + if let Some(fp) = signer + .1 + .get_signer_public_key(CertType::User) + .map(|x| x.fingerprint().hash) + { output.push_str(&format!("\tUser CA Fingerprint (SHA256): {fp}\n")); } - if let Some(fp) = signer.1.get_signer_public_key(CertType::Host).map(|x| x.fingerprint().hash) { + if let Some(fp) = signer + .1 + .get_signer_public_key(CertType::Host) + .map(|x| x.fingerprint().hash) + { output.push_str(&format!("\tHost CA Fingerprint (SHA256): {fp}\n")); } - if let Some(attested_x509_authority) = signer.1.get_attested_x509_certificate_authority() { + if let Some(attested_x509_authority) = + signer.1.get_attested_x509_certificate_authority() + { output.push_str(&format!( "\tAttested X509 Certificate Authority:\n{}\n", attested_x509_authority.serialize_pem().unwrap() )); } - if let Some(client_certificate_authority) = signer.1.get_client_certificate_authority() { + if let Some(client_certificate_authority) = signer.1.get_client_certificate_authority() + { output.push_str(&format!( "\tClient Certificate Authority:\n{}\n", client_certificate_authority.serialize_pem().unwrap() )); } - }; + } write!(f, "{}", output) } } @@ -186,7 +196,7 @@ impl SigningMechanism { if let Some(authority) = self.authorities.get(authority) { authority.sign(cert).await } else { - Err(SigningError::UnknownAuthority) + Err(SigningError::UnknownAuthority(authority.to_string())) } } @@ -200,10 +210,12 @@ impl SigningMechanism { let authority = if let Some(authority) = self.authorities.get(authority) { authority } else { - return Err(SigningError::UnknownAuthority) + return Err(SigningError::UnknownAuthority(authority.to_string())); }; - authority.get_signer_public_key(cert_type).ok_or(SigningError::SignerDoesNotHaveSSHKeys) + authority + .get_signer_public_key(cert_type) + .ok_or(SigningError::SignerDoesNotHaveSSHKeys) } /// Return the X509 certificate authority certificate to sign attested X509 requests @@ -214,7 +226,7 @@ impl SigningMechanism { if let Some(authority) = self.authorities.get(authority) { Ok(authority.get_attested_x509_certificate_authority()) } else { - Err(SigningError::UnknownAuthority) + Err(SigningError::UnknownAuthority(authority.to_string())) } } @@ -226,7 +238,7 @@ impl SigningMechanism { if let Some(authority) = self.authorities.get(authority) { Ok(authority.get_client_certificate_authority()) } else { - Err(SigningError::UnknownAuthority) + Err(SigningError::UnknownAuthority(authority.to_string())) } } @@ -238,7 +250,7 @@ impl SigningMechanism { impl SigningConfiguration { pub async fn convert_to_signing_mechanism(self) -> Result { let authorities = self.authority_configurations; - // All of the configured signing authorities + // All of the configured signing authorities let mut converted_authorities = HashMap::new(); // The public key fingerprints we've seen while setting up. @@ -253,9 +265,11 @@ impl SigningConfiguration { // If this has SSH identities configured, make sure they // don't conflict let user_hash = signer - .get_signer_public_key(CertType::User).map(|x| x.fingerprint().hash); + .get_signer_public_key(CertType::User) + .map(|x| x.fingerprint().hash); let host_hash = signer - .get_signer_public_key(CertType::Host).map(|x| x.fingerprint().hash); + .get_signer_public_key(CertType::Host) + .map(|x| x.fingerprint().hash); // If the user is using the same key for user and host // certificate authorities, error and tell them not to do diff --git a/rustica/src/verification.rs b/rustica/src/verification.rs index 17925300..90fb3ca6 100644 --- a/rustica/src/verification.rs +++ b/rustica/src/verification.rs @@ -1,22 +1,44 @@ -use crate::key::{U2fAttestation, PIVAttestation}; use crate::key::{Key, KeyAttestation, PinPolicy, TouchPolicy}; +use crate::key::{PIVAttestation, U2fAttestation}; use crate::error::RusticaServerError; +use ring::digest::{self}; use sshcerts::{ - fido::verification::verify_auth_data, - yubikey::verification::verify_certificate_chain, + fido::verification::verify_auth_data, yubikey::verification::verify_certificate_chain, }; use std::convert::TryFrom; +// For Yubikey 5 Nano: +// - PIV intermediate cert size is approx 800 bytes +// - PIV client cert is approx 700 bytes +// - U2F intermediate cert is approx 800 bytes +// - U2F attestation statement is approx 256 bytes +const CERT_MAX_SIZE: usize = 1024 * 2; // 2 KiB /// Verify a provided yubikey attestation certification and intermediate /// certificate are valid against the Yubico attestation Root CA. -pub fn verify_piv_certificate_chain(client: &[u8], intermediate: &[u8]) -> Result { +pub fn verify_piv_certificate_chain( + client: &[u8], + intermediate: &[u8], +) -> Result { + // Restrict the max size of certificates + // For Yubikey 5 Nano, actual intermediate cert size is approx 800 bytes + if intermediate.len() > CERT_MAX_SIZE { + return Err(RusticaServerError::PivIntermediateCertTooBig); + } + // For Yubikey 5 Nano, actual client cert size is approx 700 bytes + if client.len() > CERT_MAX_SIZE { + return Err(RusticaServerError::PivClientCertTooBig); + } + // Extract the certificate public key and convert to an sshcerts PublicKey - let validated_piv_data = verify_certificate_chain(client, intermediate, None).map_err(|_| RusticaServerError::InvalidKey)?; - let pin_policy = PinPolicy::try_from(validated_piv_data.pin_policy).map_err(|_| RusticaServerError::InvalidKey)?; - let touch_policy = TouchPolicy::try_from(validated_piv_data.touch_policy).map_err(|_| RusticaServerError::InvalidKey)?; + let validated_piv_data = verify_certificate_chain(client, intermediate, None) + .map_err(|_| RusticaServerError::InvalidKey)?; + let pin_policy = PinPolicy::try_from(validated_piv_data.pin_policy) + .map_err(|_| RusticaServerError::InvalidKey)?; + let touch_policy = TouchPolicy::try_from(validated_piv_data.touch_policy) + .map_err(|_| RusticaServerError::InvalidKey)?; Ok(Key { fingerprint: validated_piv_data.public_key.fingerprint().hash, @@ -27,22 +49,63 @@ pub fn verify_piv_certificate_chain(client: &[u8], intermediate: &[u8]) -> Resul touch_policy, certificate: client.to_vec(), intermediate: intermediate.to_vec(), - })) + })), }) } /// Verify a provided U2F attestation, signature, and certificate are valid /// against the Yubico U2F Root CA. -pub fn verify_u2f_certificate_chain(auth_data: &[u8], auth_data_signature: &[u8], intermediate: &[u8], alg: i32, challenge: &[u8], application: &[u8]) -> Result { - let validated_u2f_data = verify_auth_data(auth_data, auth_data_signature, challenge, alg, intermediate, None).map_err(|_| RusticaServerError::InvalidKey)?; - let parsed_application = String::from_utf8(application.to_vec()).map_err(|_| RusticaServerError::InvalidKey)?; - let ssh_public_key = validated_u2f_data.auth_data.ssh_public_key(&parsed_application).map_err(|_| RusticaServerError::InvalidKey)?; +pub fn verify_u2f_certificate_chain( + auth_data: &[u8], + auth_data_signature: &[u8], + intermediate: &[u8], + alg: i32, + challenge: &[u8], + application: &[u8], + u2f_challenge_hashed: bool, +) -> Result { + // Restrict the max size for the attestation data and intermediate certificate + // For Yubikey 5 Nano, actual intermediate cert size is approx 800 bytes + if intermediate.len() > CERT_MAX_SIZE { + return Err(RusticaServerError::U2fIntermediateCertTooBig); + } + // For Yubikey 5 Nano, actual auth_data size is approx 256 bytes + if auth_data.len() > CERT_MAX_SIZE { + return Err(RusticaServerError::U2fAttestationTooBig); + } + + // Take all the provided data and validate it up to the Yubico U2F Root CA + + let challenge = if u2f_challenge_hashed { + challenge.to_vec() + } else { + digest::digest(&digest::SHA256, challenge).as_ref().to_vec() + }; + // Earlier versions of RusticaAgent did not send the u2f_challenge hashed so + // + let validated_u2f_data = verify_auth_data( + auth_data, + auth_data_signature, + &challenge, + alg, + intermediate, + None, + ) + .map_err(|_| RusticaServerError::InvalidKey)?; + let parsed_application = + String::from_utf8(application.to_vec()).map_err(|_| RusticaServerError::InvalidKey)?; + let ssh_public_key = validated_u2f_data + .auth_data + .ssh_public_key(&parsed_application) + .map_err(|_| RusticaServerError::InvalidKey)?; Ok(Key { fingerprint: ssh_public_key.fingerprint().hash, attestation: Some(KeyAttestation::U2f(U2fAttestation { aaguid: hex::encode(validated_u2f_data.auth_data.aaguid), - firmware: validated_u2f_data.firmware.unwrap_or_else(|| "Unknown".to_string()), + firmware: validated_u2f_data + .firmware + .unwrap_or_else(|| "Unknown".to_string()), auth_data: auth_data.to_vec(), auth_data_signature: auth_data_signature.to_vec(), intermediate: intermediate.to_vec(), @@ -51,4 +114,4 @@ pub fn verify_u2f_certificate_chain(auth_data: &[u8], auth_data_signature: &[u8] application: application.to_vec(), })), }) -} \ No newline at end of file +} diff --git a/tests/ssh_server/Dockerfile b/tests/ssh_server/Dockerfile index 718da700..6d901ae1 100644 --- a/tests/ssh_server/Dockerfile +++ b/tests/ssh_server/Dockerfile @@ -9,8 +9,8 @@ RUN chmod 600 /etc/ssh/user-ca.pub RUN service ssh start # User Configuration -RUN useradd -m -d /home/testuser -s /bin/bash -g root -G sudo -u 1000 testuser -USER 1000 +RUN useradd -m -d /home/testuser -s /bin/bash -g root -G sudo -u 1001 testuser +USER 1001 RUN mkdir /home/testuser/.ssh COPY authorized_keys /home/testuser/.ssh/authorized_keys diff --git a/tests/test_configs/rustica_local_file.toml b/tests/test_configs/rustica_local_file.toml index d7419cc4..e8758af3 100644 --- a/tests/test_configs/rustica_local_file.toml +++ b/tests/test_configs/rustica_local_file.toml @@ -23,24 +23,25 @@ require_attestation_chain = true # The certificate presented to connecting clients server_cert = ''' -----BEGIN CERTIFICATE----- -MIIBqjCCAVCgAwIBAgIJAOI2FtcQeixVMAoGCCqGSM49BAMCMBsxGTAXBgNVBAMM -EEVudGVycHJpc2VSb290Q0EwHhcNMjIwMTIwMDQwMjA2WhcNMjQwNDI0MDQwMjA2 -WjAxMRAwDgYDVQQDDAdydXN0aWNhMRAwDgYDVQQKDAdSdXN0aWNhMQswCQYDVQQG -EwJDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAINhoFW/5twPqAHLxjFjmns -lE1jJMJQXmijymZTJxR0DsNZlwvUgNH+WYQFfq4IVMwypVHgyTYJO+lAAPEeyPOj -ZzBlMDUGA1UdIwQuMCyhH6QdMBsxGTAXBgNVBAMMEEVudGVycHJpc2VSb290Q0GC -CQCRg096sVtP0zAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DAUBgNVHREEDTALggls -b2NhbGhvc3QwCgYIKoZIzj0EAwIDSAAwRQIhAMfjW/PMrA9/cCg6O835sr22ZrNk -k/lFOODLqAJPbh3+AiAzeCUyrmxT5VTf6uyFoNT8zMoWSi79rudcdgl+32RqMg== +MIIBvTCCAWSgAwIBAgIUac6/skXLRQCSfqjAd0REJJxOGvwwCgYIKoZIzj0EAwIw +GzEZMBcGA1UEAwwQRW50ZXJwcmlzZVJvb3RDQTAeFw0yNDA2MDYwNDA4MThaFw0y +NjA5MDkwNDA4MThaMDExEDAOBgNVBAMMB3J1c3RpY2ExEDAOBgNVBAoMB1J1c3Rp +Y2ExCzAJBgNVBAYTAkNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEqzdtAcXS +9j3ECPWlucXR0yma0vQUU8PIioV3g7LthqtMTLwZJmtqDlhJE6PZUPdtSALeA6Xt +GxwpOv8sEA2zDaNwMG4wHwYDVR0jBBgwFoAUOhiiXYkz9/H/i5F87/PRfqg/6E4w +CQYDVR0TBAIwADALBgNVHQ8EBAMCBPAwFAYDVR0RBA0wC4IJbG9jYWxob3N0MB0G +A1UdDgQWBBReU9iTPgqopxzmL9s3DLM6HKqb9DAKBggqhkjOPQQDAgNHADBEAiAy +oOcGRjuYhrn89g2PxntRYD5mnBYqgiAmxIy04GpcjgIgQNbAu0KO7vIB3FIicjtJ +ALZO9s3gY1HbIz18rVHKBNk= -----END CERTIFICATE----- ''' # The key for the certificate presented to clients server_key = ''' -----BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgkTd0C69xWFX9PmVf -BeD0ySfG+O0e7p7SXR9xo/enbvahRANCAAQCDYaBVv+bcD6gBy8YxY5p7JRNYyTC -UF5oo8pmUycUdA7DWZcL1IDR/lmEBX6uCFTMMqVR4Mk2CTvpQADxHsjz +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgQbGgAy6FMW/NcVeS +zQCaBCQgK1QA+Xk/6JdJhgoYqQqhRANCAASrN20BxdL2PcQI9aW5xdHTKZrS9BRT +w8iKhXeDsu2Gq0xMvBkma2oOWEkTo9lQ921IAt4Dpe0bHCk6/ywQDbMN -----END PRIVATE KEY----- ''' @@ -96,11 +97,18 @@ ECAwQ= x509_private_key = "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDOLp3ZkQZasW1BKZ+fG3ODQgNThvI7pV38DOEFCz6c+gr8whSiV6EHWT04VrddShehZANiAARKbU0hcFy5+9qqHxGx/FBQb2dh6u+pAYh4ASh7skBkPv5DK/46FH6pvyPp6Gfkp8gagcFsr9nAKbwjkVTtBopuhh45KUM5k4VqIqaNox7g+XCrgG29oVqA5WZpW8DFH2c=" x509_private_key_alg = "p384" -client_certificate_authority_private_key = "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDOLp3ZkQZasW1BKZ+fG3ODQgNThvI7pV38DOEFCz6c+gr8whSiV6EHWT04VrddShehZANiAARKbU0hcFy5+9qqHxGx/FBQb2dh6u+pAYh4ASh7skBkPv5DK/46FH6pvyPp6Gfkp8gagcFsr9nAKbwjkVTtBopuhh45KUM5k4VqIqaNox7g+XCrgG29oVqA5WZpW8DFH2c=" -client_certificate_authority_private_key_algorithm = "p384" +client_certificate_authority_private_key = "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgFEwFOjsK54VOGLVajOMpV6PXEbOHKS8EXIMxRwmLQ/qhRANCAAQ+F90NcFu0EucoggNcbOGI4KP70/Mdb9hMxbd2NYx0DAeEvFiIjP2CI8QV6JgNW32zBKibV2iMtcwEyjMG7bR8" +client_certificate_authority_private_key_algorithm = "p256" client_certificate_authority_common_name = "RusticaAccess" [logging."stdout"] [authorization."database"] -path = "examples/example.db" \ No newline at end of file +path = "examples/example.db" + +[allowed_signers] +cache_validity_length.secs = 900 +cache_validity_length.nanos = 0 +lru_rate_limiter_size = 16 +rate_limit_cooldown.secs = 15 +rate_limit_cooldown.nanos = 0 diff --git a/tests/test_configs/rustica_local_file_alt.toml b/tests/test_configs/rustica_local_file_alt.toml index d65267e0..cfb6be62 100644 --- a/tests/test_configs/rustica_local_file_alt.toml +++ b/tests/test_configs/rustica_local_file_alt.toml @@ -23,24 +23,25 @@ require_attestation_chain = true # The certificate presented to connecting clients server_cert = ''' -----BEGIN CERTIFICATE----- -MIIBqjCCAVCgAwIBAgIJAOI2FtcQeixVMAoGCCqGSM49BAMCMBsxGTAXBgNVBAMM -EEVudGVycHJpc2VSb290Q0EwHhcNMjIwMTIwMDQwMjA2WhcNMjQwNDI0MDQwMjA2 -WjAxMRAwDgYDVQQDDAdydXN0aWNhMRAwDgYDVQQKDAdSdXN0aWNhMQswCQYDVQQG -EwJDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAINhoFW/5twPqAHLxjFjmns -lE1jJMJQXmijymZTJxR0DsNZlwvUgNH+WYQFfq4IVMwypVHgyTYJO+lAAPEeyPOj -ZzBlMDUGA1UdIwQuMCyhH6QdMBsxGTAXBgNVBAMMEEVudGVycHJpc2VSb290Q0GC -CQCRg096sVtP0zAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DAUBgNVHREEDTALggls -b2NhbGhvc3QwCgYIKoZIzj0EAwIDSAAwRQIhAMfjW/PMrA9/cCg6O835sr22ZrNk -k/lFOODLqAJPbh3+AiAzeCUyrmxT5VTf6uyFoNT8zMoWSi79rudcdgl+32RqMg== +MIIBvTCCAWSgAwIBAgIUac6/skXLRQCSfqjAd0REJJxOGvwwCgYIKoZIzj0EAwIw +GzEZMBcGA1UEAwwQRW50ZXJwcmlzZVJvb3RDQTAeFw0yNDA2MDYwNDA4MThaFw0y +NjA5MDkwNDA4MThaMDExEDAOBgNVBAMMB3J1c3RpY2ExEDAOBgNVBAoMB1J1c3Rp +Y2ExCzAJBgNVBAYTAkNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEqzdtAcXS +9j3ECPWlucXR0yma0vQUU8PIioV3g7LthqtMTLwZJmtqDlhJE6PZUPdtSALeA6Xt +GxwpOv8sEA2zDaNwMG4wHwYDVR0jBBgwFoAUOhiiXYkz9/H/i5F87/PRfqg/6E4w +CQYDVR0TBAIwADALBgNVHQ8EBAMCBPAwFAYDVR0RBA0wC4IJbG9jYWxob3N0MB0G +A1UdDgQWBBReU9iTPgqopxzmL9s3DLM6HKqb9DAKBggqhkjOPQQDAgNHADBEAiAy +oOcGRjuYhrn89g2PxntRYD5mnBYqgiAmxIy04GpcjgIgQNbAu0KO7vIB3FIicjtJ +ALZO9s3gY1HbIz18rVHKBNk= -----END CERTIFICATE----- ''' # The key for the certificate presented to clients server_key = ''' -----BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgkTd0C69xWFX9PmVf -BeD0ySfG+O0e7p7SXR9xo/enbvahRANCAAQCDYaBVv+bcD6gBy8YxY5p7JRNYyTC -UF5oo8pmUycUdA7DWZcL1IDR/lmEBX6uCFTMMqVR4Mk2CTvpQADxHsjz +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgQbGgAy6FMW/NcVeS +zQCaBCQgK1QA+Xk/6JdJhgoYqQqhRANCAASrN20BxdL2PcQI9aW5xdHTKZrS9BRT +w8iKhXeDsu2Gq0xMvBkma2oOWEkTo9lQ921IAt4Dpe0bHCk6/ywQDbMN -----END PRIVATE KEY----- ''' @@ -94,13 +95,20 @@ ECAwQ= ''' x509_private_key = "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDOLp3ZkQZasW1BKZ+fG3ODQgNThvI7pV38DOEFCz6c+gr8whSiV6EHWT04VrddShehZANiAARKbU0hcFy5+9qqHxGx/FBQb2dh6u+pAYh4ASh7skBkPv5DK/46FH6pvyPp6Gfkp8gagcFsr9nAKbwjkVTtBopuhh45KUM5k4VqIqaNox7g+XCrgG29oVqA5WZpW8DFH2c=" -x509_private_key_alg = "p384" +x509_private_key_algorithm = "p384" -client_certificate_authority_private_key = "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDOLp3ZkQZasW1BKZ+fG3ODQgNThvI7pV38DOEFCz6c+gr8whSiV6EHWT04VrddShehZANiAARKbU0hcFy5+9qqHxGx/FBQb2dh6u+pAYh4ASh7skBkPv5DK/46FH6pvyPp6Gfkp8gagcFsr9nAKbwjkVTtBopuhh45KUM5k4VqIqaNox7g+XCrgG29oVqA5WZpW8DFH2c=" -client_certificate_authority_private_key_algorithm = "p384" +client_certificate_authority_private_key = "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgFEwFOjsK54VOGLVajOMpV6PXEbOHKS8EXIMxRwmLQ/qhRANCAAQ+F90NcFu0EucoggNcbOGI4KP70/Mdb9hMxbd2NYx0DAeEvFiIjP2CI8QV6JgNW32zBKibV2iMtcwEyjMG7bR8" +client_certificate_authority_private_key_algorithm = "p256" client_certificate_authority_common_name = "RusticaAccess" [logging."stdout"] [authorization."database"] -path = "examples/example.db" \ No newline at end of file +path = "examples/example.db" + +[allowed_signers] +cache_validity_length.secs = 900 +cache_validity_length.nanos = 0 +lru_rate_limiter_size = 16 +rate_limit_cooldown.secs = 300 +rate_limit_cooldown.nanos = 0 diff --git a/tests/test_configs/rustica_local_file_multi.toml b/tests/test_configs/rustica_local_file_multi.toml index c4d6ac5f..a15b79c3 100644 --- a/tests/test_configs/rustica_local_file_multi.toml +++ b/tests/test_configs/rustica_local_file_multi.toml @@ -128,4 +128,11 @@ x509_private_key_alg = "p384" [logging."stdout"] [authorization."database"] -path = "examples/example.db" \ No newline at end of file +path = "examples/example.db" + +[allowed_signers] +cache_validity_length.secs = 900 +cache_validity_length.nanos = 0 +lru_rate_limiter_size = 16 +rate_limit_cooldown.secs = 15 +rate_limit_cooldown.nanos = 0 diff --git a/tests/test_configs/rustica_local_file_with_influx.toml b/tests/test_configs/rustica_local_file_with_influx.toml index cf774635..6d934573 100644 --- a/tests/test_configs/rustica_local_file_with_influx.toml +++ b/tests/test_configs/rustica_local_file_with_influx.toml @@ -110,4 +110,11 @@ user = "influx_user" password = "influx_password" [authorization."database"] -path = "examples/example.db" \ No newline at end of file +path = "examples/example.db" + +[allowed_signers] +cache_validity_length.secs = 900 +cache_validity_length.nanos = 0 +lru_rate_limiter_size = 16 +rate_limit_cooldown.secs = 15 +rate_limit_cooldown.nanos = 0 diff --git a/tests/test_configs/rustica_local_file_with_splunk.toml b/tests/test_configs/rustica_local_file_with_splunk.toml index 2f3c69ac..8d031b1f 100644 --- a/tests/test_configs/rustica_local_file_with_splunk.toml +++ b/tests/test_configs/rustica_local_file_with_splunk.toml @@ -113,4 +113,11 @@ url = "https://http-inputs-examplecompany.splunkcloud.com/services/collector" timeout = 5 [authorization."database"] -path = "examples/example.db" \ No newline at end of file +path = "examples/example.db" + +[allowed_signers] +cache_validity_length.secs = 900 +cache_validity_length.nanos = 0 +lru_rate_limiter_size = 16 +rate_limit_cooldown.secs = 15 +rate_limit_cooldown.nanos = 0 diff --git a/tests/test_configs/rustica_local_file_with_webhook.toml b/tests/test_configs/rustica_local_file_with_webhook.toml index 7773203f..bc28cbf1 100644 --- a/tests/test_configs/rustica_local_file_with_webhook.toml +++ b/tests/test_configs/rustica_local_file_with_webhook.toml @@ -113,4 +113,11 @@ url = "http://localhost:4554/some/webhook/another_long_string_that_can_act_as_a_ timeout = 5 [authorization."database"] -path = "examples/example.db" \ No newline at end of file +path = "examples/example.db" + +[allowed_signers] +cache_validity_length.secs = 900 +cache_validity_length.nanos = 0 +lru_rate_limiter_size = 16 +rate_limit_cooldown.secs = 15 +rate_limit_cooldown.nanos = 0