diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 393f5deb..00000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,8 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Enmeshed Issue Tracker - url: https://github.com/nmshd/feedback/issues - about: Open bug reports and feature requests. - - name: Enmeshed Discussions - url: https://github.com/nmshd/feedback/discussions - about: Share your feedback with the Enmeshed team. diff --git a/.github/mergify.yml b/.github/mergify.yml deleted file mode 100644 index da9e0090..00000000 --- a/.github/mergify.yml +++ /dev/null @@ -1,6 +0,0 @@ -pull_request_rules: - - name: update pull request - conditions: - - label!=wip - actions: - update: diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 36002547..00000000 --- a/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -/target -/.VSCodeCounter -/*code-workspace -/.cargo -*.bak diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index da9294b4..00000000 --- a/.prettierrc +++ /dev/null @@ -1,16 +0,0 @@ -{ - "endOfLine": "lf", - "printWidth": 180, - "tabWidth": 4, - "trailingComma": "none", - "semi": true, - "arrowParens": "always", - "overrides": [ - { - "files": ["*.yaml", "*.yml"], - "options": { - "tabWidth": 2 - } - } - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 95c24da2..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "[jsonc]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[json]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[javascript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[typescript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[yaml]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[markdown]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "editor.formatOnSave": true, - "editor.formatOnPaste": true, - "files.autoSave": "off", - "html.format.wrapAttributes": "preserve-aligned", - "xmlTools.splitAttributesOnFormat": true, - "xmlTools.enforcePrettySelfClosingTagOnFormat": true, - "editor.codeActionsOnSave": { - "source.organizeImports": "explicit" - }, - "files.eol": "\n" -} diff --git a/Cargo.lock b/Cargo.lock index 1ddd42e3..61cb4636 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,31 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "1.1.3" @@ -11,11 +36,31 @@ dependencies = [ "memchr", ] +[[package]] +name = "android_log-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85965b6739a430150bdd138e2374a98af0c3ee0d030b3bb7fc3bddff58d0102e" + [[package]] name = "anyhow" -version = "1.0.83" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "apple-secure-enclave-bindings" +version = "0.1.0" +dependencies = [ + "swift-bridge", + "swift-bridge-build", +] + +[[package]] +name = "arrayref" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "async-channel" @@ -35,16 +80,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", - "event-listener-strategy 0.5.2", + "event-listener-strategy", "futures-core", "pin-project-lite", ] [[package]] name = "async-executor" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b10202063978b3351199d68f8b22c4e47e4b1b822f8d43fd862d5ea8c006b29a" +checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" dependencies = [ "async-task", "concurrent-queue", @@ -61,8 +106,8 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.3.1", "async-executor", - "async-io 2.3.2", - "async-lock 3.3.0", + "async-io 2.3.3", + "async-lock 3.4.0", "blocking", "futures-lite 2.3.0", "once_cell", @@ -84,23 +129,23 @@ dependencies = [ "polling 2.8.0", "rustix 0.37.27", "slab", - "socket2", + "socket2 0.4.10", "waker-fn", ] [[package]] name = "async-io" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" dependencies = [ - "async-lock 3.3.0", + "async-lock 3.4.0", "cfg-if", "concurrent-queue", "futures-io", "futures-lite 2.3.0", "parking", - "polling 3.7.0", + "polling 3.7.1", "rustix 0.38.34", "slab", "tracing", @@ -118,12 +163,12 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 4.0.3", - "event-listener-strategy 0.4.0", + "event-listener 5.3.1", + "event-listener-strategy", "pin-project-lite", ] @@ -167,9 +212,24 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "backtrace" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] [[package]] name = "base16ct" @@ -183,6 +243,12 @@ 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 = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64ct" version = "1.6.0" @@ -218,12 +284,11 @@ dependencies = [ [[package]] name = "blocking" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ "async-channel 2.3.1", - "async-lock 3.3.0", "async-task", "futures-io", "futures-lite 2.3.0", @@ -242,11 +307,23 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + [[package]] name = "cc" -version = "1.0.92" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" + +[[package]] +name = "cesu8" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfg-if" @@ -264,6 +341,16 @@ dependencies = [ "inout", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -279,6 +366,22 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + [[package]] name = "cpufeatures" version = "0.2.12" @@ -290,18 +393,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-bigint" @@ -330,21 +433,98 @@ name = "crypto-layer" version = "0.1.0" dependencies = [ "anyhow", + "apple-secure-enclave-bindings", + "arrayref", "async-std", + "base64 0.22.1", + "ed25519-dalek", "futures", + "libloading", "nitrokey", "once_cell", + "openssl", + "rand", + "regex", + "reqwest", + "robusta_jni", "serde", "serde_json", + "sodiumoxide", "test-case", + "tokio", "tracing", + "tracing-android", "tracing-appender", "tracing-subscriber", "tss-esapi", "windows", + "x25519-dalek", "yubikey", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "platforms", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + [[package]] name = "der" version = "0.7.9" @@ -366,7 +546,7 @@ checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.66", ] [[package]] @@ -399,6 +579,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "displaydoc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "ecdsa" version = "0.16.9" @@ -409,10 +600,43 @@ dependencies = [ "digest", "elliptic-curve", "rfc6979", - "signature", + "signature 2.2.0", "spki", ] +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature 1.6.4", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature 2.2.0", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519 2.2.3", + "serde", + "sha2", + "subtle", + "zeroize", +] + [[package]] name = "elliptic-curve" version = "0.13.8" @@ -434,26 +658,41 @@ dependencies = [ "zeroize", ] +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + [[package]] name = "enumflags2" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d" +checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" dependencies = [ "enumflags2_derive", ] [[package]] name = "enumflags2_derive" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" +checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.66", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.9" @@ -472,43 +711,22 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[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" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", "pin-project-lite", ] -[[package]] -name = "event-listener-strategy" -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 = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener 5.3.0", + "event-listener 5.3.1", "pin-project-lite", ] @@ -537,12 +755,48 @@ dependencies = [ "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "flagset" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdeb3aa5e95cf9aabc17f060cfa0ced7b83f042390760ca53bf09df9968acaa1" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "futures" version = "0.3.30" @@ -627,7 +881,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.66", ] [[package]] @@ -684,15 +938,21 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + [[package]] name = "gloo-timers" version = "0.2.6" @@ -716,6 +976,31 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hermit-abi" version = "0.3.9" @@ -747,90 +1032,396 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f558a64ac9af88b5ba400d99b579451af0d39c6d360980045b91aac966d705e2" [[package]] -name = "inout" -version = "0.1.3" +name = "http" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ - "generic-array", + "bytes", + "fnv", + "itoa", ] [[package]] -name = "instant" -version = "0.1.12" +name = "http-body" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ - "cfg-if", + "bytes", + "http", ] [[package]] -name = "io-lifetimes" -version = "1.0.11" +name = "http-body-util" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.48.0", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", ] [[package]] -name = "itoa" -version = "1.0.11" +name = "httparse" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d0e7a4dd27b9476dc40cb050d3632d3bba3a70ddbff012285f7f8559a1e7e545" [[package]] -name = "js-sys" -version = "0.3.69" +name = "hyper" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" dependencies = [ - "wasm-bindgen", + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", ] [[package]] -name = "kv-log-macro" -version = "1.0.7" +name = "hyper-tls" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ - "log", + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "hyper-util" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" dependencies = [ - "spin", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2 0.5.7", + "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] -name = "libc" -version = "0.2.153" +name = "icu_collections" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] [[package]] -name = "libm" -version = "0.2.8" +name = "icu_locid" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] [[package]] -name = "linux-raw-sys" -version = "0.3.8" +name = "icu_locid_transform" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] [[package]] -name = "linux-raw-sys" -version = "0.4.13" +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f8ac670d7422d7f76b32e17a5db556510825b29ec9154f235977c9caba61036" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4716a3a0933a1d01c2f72450e89596eb51dd34ef3c211ccd875acdf1f8fe47ed" +dependencies = [ + "icu_normalizer", + "icu_properties", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libloading" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +dependencies = [ + "cfg-if", + "windows-targets 0.52.5", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libsodium-sys" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "6b779387cd56adfbc02ea4a668e704f729be8d6a6abd2c27ca5ee537849a92fd" +dependencies = [ + "cc", + "libc", + "pkg-config", + "walkdir", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] [[package]] name = "log" @@ -843,19 +1434,12 @@ dependencies = [ [[package]] name = "mbox" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9efb73102e7bed0647af358182fba033b32c9c57a744cdff05ea2c0f8a1e9c2e" +checksum = "26d142aeadbc4e8c679fc6d93fbe7efe1c021fa7d80629e615915b519e3bc6de" dependencies = [ "libc", - "once_cell", - "pest", - "proc-macro2", - "rustc_version", "stable_deref_trait", - "syn 1.0.107", - "thiserror", - "ucd-trie", ] [[package]] @@ -864,12 +1448,55 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nitrokey" version = "0.9.0" @@ -943,7 +1570,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.66", ] [[package]] @@ -957,9 +1584,9 @@ dependencies = [ [[package]] name = "num-iter" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -968,14 +1595,33 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +dependencies = [ + "memchr", +] + [[package]] name = "oid" version = "0.2.1" @@ -987,9 +1633,53 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.14.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[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 = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "openssl-probe" +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 = "overload" @@ -1027,6 +1717,35 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.5", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pbkdf2" version = "0.12.2" @@ -1049,9 +1768,9 @@ 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", ] @@ -1066,13 +1785,10 @@ dependencies = [ ] [[package]] -name = "pest" -version = "2.1.3" +name = "percent-encoding" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "picky-asn1" @@ -1102,13 +1818,33 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c5f20f71a68499ff32310f418a6fad8816eac1a2859ed3f0c5c741389dd6208" dependencies = [ - "base64", + "base64 0.21.7", "oid", "picky-asn1", "picky-asn1-der", "serde", ] +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1123,9 +1859,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464db0c665917b13ebb5d453ccdec4add5658ee1adc7affc7677615356a8afaf" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" dependencies = [ "atomic-waker", "fastrand 2.1.0", @@ -1159,6 +1895,12 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "platforms" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" + [[package]] name = "polling" version = "2.8.0" @@ -1177,9 +1919,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" +checksum = "5e6a007746f34ed64099e88783b0ae369eaa3da6392868ba262e2af9b8fbaea1" dependencies = [ "cfg-if", "concurrent-queue", @@ -1211,20 +1953,43 @@ dependencies = [ "elliptic-curve", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" -version = "1.0.65" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92de25114670a878b1261c79c9f8f729fb97e95bac93f6312f583c60dd6a1dfe" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.30" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5907a1b7c277254a8b15170f6e7c97cfa60ee7872a3217663bb81151e48184bb" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1265,14 +2030,23 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.14", + "getrandom 0.2.15", +] + +[[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 = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", @@ -1282,9 +2056,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -1293,9 +2067,51 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "reqwest" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] [[package]] name = "rfc6979" @@ -1307,6 +2123,33 @@ dependencies = [ "subtle", ] +[[package]] +name = "robusta-codegen" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb512b451472948a204452dfad582bdc48d69caacdd3b1b4571d5e3f11707f3" +dependencies = [ + "Inflector", + "darling", + "proc-macro-error", + "proc-macro2", + "quote", + "rand", + "syn 1.0.109", +] + +[[package]] +name = "robusta_jni" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c080146e0cc733697fe500413871142af91bd879641205c2febbe5f982f304e3" +dependencies = [ + "jni", + "paste", + "robusta-codegen", + "static_assertions", +] + [[package]] name = "rsa" version = "0.9.6" @@ -1322,17 +2165,23 @@ dependencies = [ "pkcs8", "rand_core 0.6.4", "sha2", - "signature", + "signature 2.2.0", "spki", "subtle", "zeroize", ] +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + [[package]] name = "rustc_version" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ "semver", ] @@ -1360,15 +2209,55 @@ dependencies = [ "bitflags 2.5.0", "errno", "libc", - "linux-raw-sys 0.4.13", + "linux-raw-sys 0.4.14", "windows-sys 0.52.0", ] +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sec1" @@ -1394,28 +2283,39 @@ dependencies = [ ] [[package]] -name = "semver" -version = "0.11.0" +name = "security-framework" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "semver-parser", + "bitflags 2.5.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", ] [[package]] -name = "semver-parser" -version = "0.10.2" +name = "security-framework-sys" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ - "pest", + "core-foundation-sys", + "libc", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" -version = "1.0.193" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] @@ -1431,21 +2331,33 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.66", ] [[package]] name = "serde_json" -version = "1.0.109" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ + "form_urlencoded", "itoa", "ryu", "serde", @@ -1479,9 +2391,24 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ - "lazy_static", + "lazy_static", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", ] +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + [[package]] name = "signature" version = "2.2.0" @@ -1517,6 +2444,28 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "sodiumoxide" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e26be3acb6c2d9a7aac28482586a7856436af4cfe7100031d219de2d2ecb0028" +dependencies = [ + "ed25519 1.5.3", + "libc", + "libsodium-sys", + "serde", +] + [[package]] name = "spin" version = "0.5.2" @@ -1539,17 +2488,74 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "subtle" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +[[package]] +name = "swift-bridge" +version = "0.1.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6180c668892926e0bc19d75a81b0ee2fdce3ab15ff062a61b3ce9b4d562eac1b" +dependencies = [ + "swift-bridge-build", + "swift-bridge-macro", +] + +[[package]] +name = "swift-bridge-build" +version = "0.1.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b8256d2d8c35795afeab117528f5e42b2706ca29b20f768929d458c7f245fdd" +dependencies = [ + "proc-macro2", + "swift-bridge-ir", + "syn 1.0.109", + "tempfile", +] + +[[package]] +name = "swift-bridge-ir" +version = "0.1.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28407ee88b57fac3e8c9314a0eefb1f63a3743cb0beef4b8d93189d5d8ce0f1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "swift-bridge-macro" +version = "0.1.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e69ec9898b591cfcf473a584e98b54517400dcc67b0d3f8fdf2a099ce7971e3a" +dependencies = [ + "proc-macro2", + "quote", + "swift-bridge-ir", + "syn 1.0.109", +] + [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -1558,21 +2564,71 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.32" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[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.66", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "target-lexicon" version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand 2.1.0", + "rustix 0.38.34", + "windows-sys 0.52.0", +] + [[package]] name = "test-case" version = "3.3.1" @@ -1591,7 +2647,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.66", ] [[package]] @@ -1602,28 +2658,28 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.66", "test-case-core", ] [[package]] name = "thiserror" -version = "1.0.39" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.39" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", + "syn 2.0.66", ] [[package]] @@ -1638,9 +2694,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.34" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", @@ -1659,14 +2715,24 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ "num-conv", "time-core", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tls_codec" version = "0.4.1" @@ -1685,9 +2751,89 @@ checksum = "8d9ef545650e79f30233c0003bcc2504d7efac6dad25fca40744de773fe2049c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.66", +] + +[[package]] +name = "tokio" +version = "1.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.7", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", ] +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + [[package]] name = "tracing" version = "0.1.40" @@ -1700,6 +2846,17 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-android" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12612be8f868a09c0ceae7113ff26afe79d81a24473a393cb9120ece162e86c0" +dependencies = [ + "android_log-sys", + "tracing", + "tracing-subscriber", +] + [[package]] name = "tracing-appender" version = "0.2.3" @@ -1720,7 +2877,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.66", ] [[package]] @@ -1758,15 +2915,21 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "tss-esapi" -version = "7.5.0" +version = "7.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d36722a0888ff29225d11ea205f10319d6cb4d072ef3c91bf3509f7f476d89e3" +checksum = "a9ba6594ded739cb539f8ffcd3713f6c21d4525c47314bbc6de15c0cd251aedf" dependencies = [ "bitfield", "enumflags2", - "getrandom 0.2.14", + "getrandom 0.2.15", "hostname-validator", "log", "mbox", @@ -1797,25 +2960,42 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "ucd-trie" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c" - [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "url" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "uuid" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ - "getrandom 0.2.14", + "getrandom 0.2.15", ] [[package]] @@ -1830,6 +3010,12 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -1842,6 +3028,25 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -1875,7 +3080,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -1909,7 +3114,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1946,6 +3151,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -1954,9 +3168,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.56.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" dependencies = [ "windows-core", "windows-targets 0.52.5", @@ -1964,9 +3178,9 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.56.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ "windows-implement", "windows-interface", @@ -1976,31 +3190,31 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.56.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.66", ] [[package]] name = "windows-interface" -version = "0.56.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.66", ] [[package]] name = "windows-result" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" dependencies = [ "windows-targets 0.52.5", ] @@ -2144,6 +3358,40 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core 0.6.4", + "serde", + "zeroize", +] + [[package]] name = "x509-cert" version = "0.2.5" @@ -2153,11 +3401,35 @@ dependencies = [ "const-oid", "der", "sha1", - "signature", + "signature 2.2.0", "spki", "tls_codec", ] +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", + "synstructure", +] + [[package]] name = "yubikey" version = "0.8.0" @@ -2184,18 +3456,39 @@ dependencies = [ "secrecy", "sha1", "sha2", - "signature", + "signature 2.2.0", "subtle", "uuid", "x509-cert", "zeroize", ] +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", + "synstructure", +] + [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] @@ -2208,5 +3501,27 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.66", +] + +[[package]] +name = "zerovec" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", ] diff --git a/Cargo.toml b/Cargo.toml index 28009807..3c6ba5d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,10 +3,9 @@ name = "crypto-layer" version = "0.1.0" edition = "2021" license = "MIT" -crate-type = ["staticlib"] [lib] -crate-type = ["cdylib"] +crate-type = ["cdylib", "lib"] [profile.dev] debug-assertions = true @@ -24,12 +23,15 @@ debug = false strip = "symbols" [features] -android = [] +nks = ["core", "x25519-dalek", "hcvault"] +android = ["robusta_jni", "libloading", "tracing-android", "x25519-dalek"] debug = [] hsm = [] ffi = [] +hcvault = [] +core = [] linux = ["tpm", "tss-esapi"] -macos = [] +macos = ["tpm"] nitro = ["hsm", "nitrokey"] std = [] tpm = [] @@ -42,7 +44,7 @@ async-std = "*" futures = "*" nitrokey = { version = "0.9.0", optional = true } once_cell = "1.14.0" -windows = { version = "0.56.0", features = ["Win32_Security_Tpm", "Security_Cryptography_Core", "Win32_Security_Cryptography"], optional = true } +windows = { version = "0.57.0", features = ["Win32_Security_Tpm", "Security_Cryptography_Core", "Win32_Security_Cryptography"], optional = true } tss-esapi = { version = "7.5.0", optional = true } serde = { version = "*", features = ["derive"] } serde_json = "1.0.109" @@ -50,6 +52,20 @@ tracing = { version = "0.1.40", features = ["std", "log"] } tracing-subscriber = "0.3.18" tracing-appender = "0.2.3" yubikey = { version = "0.8.0", optional = true } +reqwest = { version = "0.12.4", features = ["json"] } +tokio = { version = "1", features = ["full"] } +openssl = "0.10.64" +base64 = "0.22.1" +ed25519-dalek = "2.1.1" +arrayref = "0.3.7" +sodiumoxide = "0.2.7" +rand = "0.8.5" +x25519-dalek = { version = "2.0.1", features = ["static_secrets"], optional = true } +robusta_jni = { version = "0.2", optional = true } +libloading = { version = "0.8.3", optional = true } +tracing-android = { version = "0.2.0", optional = true } +apple-secure-enclave-bindings = {version = "0.1.0", path="./src/tpm/macos/swift_rust_wrapper"} +regex = "1.10.4" [dev-dependencies] test-case = "*" diff --git a/README.md b/README.md index 1e81de27..8063fc56 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,35 @@ Not fully implemented yet The Crypto Layer is a comprehensive and flexible cryptographic library designed to provide a unified interface for various cryptographic operations and algorithms. It offers a wide range of functionalities, including encryption, decryption, signing, signature verification, and hashing, while supporting both symmetric and asymmetric cryptography. +## Running Tests for NKS + +Firstly, you need to have a Hashicorp Vault server and the backend server running. +You can find instructions and code [here](https://github.com/cep-sose2024/rhein_sec) +Then you need to clone this directory and run the following commands: + +1. **Open your terminal.** +2. **Navigate to the root directory of the project using the `cd` command. Replace `path/to/your/project` with the actual path to your project:** + ```bash + cd path/to/the/project + ``` +3. **Add `default = ["nks"]` to the `features` section in your `Cargo.toml` file. This will enable the `nks` feature by default when you run your tests.** + ```toml + [features] + default = ["nks"] + ``` +4. **To execute the `provider_handle_tests`, run the following command:** + ```bash + cargo test --features hcvault tests::nks::provider_handle_tests -- --nocapture --test-threads=1 + ``` +5. **After the `provider_handle_tests` have finished running, you can execute the `key_handle_tests` with the following command:** + ```bash + cargo test --features hcvault tests::nks::key_handle_tests -- --nocapture --test-threads=1 + ``` +6. **Please note that the `--nocapture` flag is used to display any print statements in the console, and `--test-threads=1` is used to run the tests sequentially.** + +Please also note that with every execution of a provider_handle_test, a token.json is being created in the root directory of the project. +This file is used to store the token for the Hashicorp Vault server. +It is recommended to delete this file after the tests have been executed because otherwise keys will not be created because keys with the given names already exist. ## Features - **Encryption Algorithms**: Supports a variety of encryption algorithms, including: diff --git a/src/common/error.rs b/src/common/error.rs index 789163da..0bfb6c36 100644 --- a/src/common/error.rs +++ b/src/common/error.rs @@ -20,6 +20,9 @@ pub enum SecurityModuleError { #[cfg(feature = "tpm")] /// Error originating from a Trusted Platform Module (TPM). Tpm(TpmError), + #[cfg(feature = "nks")] + /// Error originating from a Network Key Storage (NKS). + NksError, /// Error that occurred during the signing operation. /// /// This variant contains a descriptive error message. @@ -40,6 +43,12 @@ pub enum SecurityModuleError { /// /// This variant contains a descriptive error message. InitializationError(String), + KeyError, + UnsupportedAlgorithm, + VerificationFailed, + InvalidSignature, + InvalidPublicKey, + SigningFailed, } impl fmt::Display for SecurityModuleError { @@ -72,6 +81,14 @@ impl fmt::Display for SecurityModuleError { SecurityModuleError::InitializationError(ref error_msg) => { write!(f, "Initialization error: {}", error_msg) } + SecurityModuleError::KeyError => write!(f, "Key error"), + SecurityModuleError::UnsupportedAlgorithm => write!(f, "Unsupported algorithm"), + SecurityModuleError::VerificationFailed => write!(f, "Verification failed"), + SecurityModuleError::InvalidSignature => write!(f, "Invalid signature"), + SecurityModuleError::InvalidPublicKey => write!(f, "Invalid public key"), + SecurityModuleError::SigningFailed => write!(f, "Invalid public key"), + #[cfg(feature = "nks")] + SecurityModuleError::NksError => write!(f, "Key error"), } } } @@ -96,6 +113,14 @@ impl std::error::Error for SecurityModuleError { SecurityModuleError::EncryptionError(_) => None, SecurityModuleError::SignatureVerificationError(_) => None, SecurityModuleError::InitializationError(_) => None, + SecurityModuleError::KeyError => None, + SecurityModuleError::UnsupportedAlgorithm => None, + SecurityModuleError::VerificationFailed => None, + SecurityModuleError::InvalidSignature => None, + SecurityModuleError::InvalidPublicKey => None, + #[cfg(feature = "nks")] + SecurityModuleError::NksError => None, + SecurityModuleError::SigningFailed => None, } } } diff --git a/src/common/factory.rs b/src/common/factory.rs index 6dd7d448..8d119ef3 100644 --- a/src/common/factory.rs +++ b/src/common/factory.rs @@ -24,6 +24,9 @@ pub enum SecurityModule { Hsm(HsmType), #[cfg(feature = "tpm")] Tpm(TpmType), + #[cfg(feature = "nks")] + Nks, + } /// Provides conversion from a string slice to a `SecurityModule` variant. @@ -133,6 +136,8 @@ impl SecModule { #[cfg(feature = "tpm")] SecurityModule::Tpm(tpm_type) => Some(TpmInstance::create_instance(key_id, tpm_type)), // _ => unimplemented!(), + #[cfg(feature = "nks")] + SecurityModule::Nks => Some(Arc::new(Mutex::new(crate::nks::hcvault::NksProvider::new(key_id)))), } } } diff --git a/src/common/traits/module_provider.rs b/src/common/traits/module_provider.rs index 50cc035b..86e42fe6 100644 --- a/src/common/traits/module_provider.rs +++ b/src/common/traits/module_provider.rs @@ -1,6 +1,6 @@ -use super::{key_handle::KeyHandle, module_provider_config::ProviderConfig}; +use super::key_handle::KeyHandle; use crate::common::error::SecurityModuleError; -use std::fmt::Debug; +use std::{any::Any, fmt::Debug}; /// Defines the interface for a security module provider. /// @@ -26,11 +26,8 @@ pub trait Provider: Send + Sync + KeyHandle + Debug { /// /// A `Result` that, on success, contains `Ok(())`, indicating that the key was created successfully. /// On failure, it returns a `SecurityModuleError`. - fn create_key( - &mut self, - key_id: &str, - config: Box, - ) -> Result<(), SecurityModuleError>; + fn create_key(&mut self, key_id: &str, config: Box) + -> Result<(), SecurityModuleError>; /// Loads an existing cryptographic key identified by `key_id`. /// @@ -46,11 +43,7 @@ pub trait Provider: Send + Sync + KeyHandle + Debug { /// /// A `Result` that, on success, contains `Ok(())`, indicating that the key was loaded successfully. /// On failure, it returns a `SecurityModuleError`. - fn load_key( - &mut self, - key_id: &str, - config: Box, - ) -> Result<(), SecurityModuleError>; + fn load_key(&mut self, key_id: &str, config: Box) -> Result<(), SecurityModuleError>; /// Initializes the security module and returns a handle for further operations. /// diff --git a/src/ffi/provider.rs b/src/ffi/provider.rs index 17d679a7..a58e5a89 100644 --- a/src/ffi/provider.rs +++ b/src/ffi/provider.rs @@ -5,6 +5,7 @@ use crate::{ tpm::TpmConfig, }; use std::{ + any::Any, ffi::{c_void, CStr}, os::raw::c_char, sync::{Arc, Mutex}, @@ -46,10 +47,9 @@ pub unsafe extern "C" fn initialize_module(provider_ffi: *mut ProviderFFI) -> i3 } } - #[no_mangle] pub extern "C" fn config_new() -> *mut c_void { - let config: Box = Box::new(TpmConfig::default()); + let config: Box = Box::::default(); let ptr: *mut dyn ProviderConfig = Box::into_raw(config); ptr as *mut c_void } @@ -88,10 +88,9 @@ pub unsafe extern "C" fn create_key( }; // Cast the void pointer back to Box - let config: Box = { + let config: Box = { // Convert it back to a Box to properly handle the ownership - let boxed_config: Box> = - Box::from_raw(config as *mut Box); + let boxed_config: Box> = Box::from_raw(config as *mut Box); *boxed_config }; @@ -123,10 +122,9 @@ pub unsafe extern "C" fn load_key( }; // Cast the void pointer back to Box - let config: Box = { + let config: Box = { // Convert it back to a Box to properly handle the ownership - let boxed_config: Box> = - Box::from_raw(config as *mut Box); + let boxed_config: Box> = Box::from_raw(config as *mut Box); *boxed_config }; diff --git a/src/lib.rs b/src/lib.rs index 975c4027..898d5a89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,8 @@ pub mod hsm; mod tests; #[cfg(feature = "tpm")] pub mod tpm; +#[cfg(feature = "nks")] +pub mod nks; pub use common::{error::SecurityModuleError, factory::SecModules}; #[cfg(feature = "ffi")] diff --git a/src/nks/core/error.rs b/src/nks/core/error.rs new file mode 100644 index 00000000..92747c87 --- /dev/null +++ b/src/nks/core/error.rs @@ -0,0 +1,58 @@ +use std::fmt::{Display, Formatter, Result}; + +/// Represents errors that can occur when interacting with a Network Key Storage (nks). +/// +/// This enum encapsulates different types of errors that may arise during nks operations, +/// including I/O errors, HashiCorp Vault API errors, initialization errors, and unsupported operations. +/// It is designed to provide a clear and descriptive representation of the error, facilitating +/// error handling and logging. +#[derive(Debug)] +#[repr(C)] +pub enum NksError { + /// Error related to I/O operations, wrapping a `std::io::Error`. + Io(std::io::Error), + /// Error occurring during nks initialization, containing an error message. + InitializationError(String), + /// Error indicating that an attempted operation is unsupported, containing a description. + UnsupportedOperation(String), +} + +impl Display for NksError { + /// Formats the `NksError` for display. + /// + /// This method provides a user-friendly description of the error based on the variant of `NksError`. + /// + /// # Arguments + /// + /// * `f` - A mutable reference to a `fmt::Formatter`. + /// + /// # Returns + /// + /// A `fmt::Result` indicating the success or failure of the formatting. + /// + /// # Variants + /// + /// * `NksError::Io(ref err)` - Formats as `"Communication error: {err}"`. + /// * `NksError::InitializationError(ref msg)` - Formats as `"Authentication error: {msg}"`. + /// * `NksError::UnsupportedOperation(ref msg)` - Formats as `"Device-specific error: {msg}"`. + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + match *self { + NksError::Io(ref err) => write!(f, "Communication error: {}", err), + NksError::InitializationError(ref msg) => write!(f, "Authentication error: {}", msg), + NksError::UnsupportedOperation(ref msg) => write!(f, "Device-specific error: {}", msg), + } + } +} + +/// Enables `NksError` to be treated as a trait object for any error (`dyn std::error::Error`). +/// +/// This implementation allows for compatibility with Rust's standard error handling mechanisms, +/// facilitating the propagation and inspection of errors through the `source` method. +impl std::error::Error for NksError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + NksError::Io(ref err) => Some(err), + _ => None, + } + } +} diff --git a/src/nks/core/instance.rs b/src/nks/core/instance.rs new file mode 100644 index 00000000..b3c43e5d --- /dev/null +++ b/src/nks/core/instance.rs @@ -0,0 +1,85 @@ +//TODO use CAL once it can compile +//use crate::common::traits::module_provider::Provider; +#[cfg(feature = "hcvault")] +use crate::nks::hcvault::NksProvider; +use std::sync::{Arc, Mutex}; +use crate::common::traits::module_provider::Provider; + +/// Represents the different environments where a Network Key Storage (nks) can operate. +/// +/// This enum is designed to distinguish between various Network Key Storages, like HashiCorp Vault. +/// It provides a unified way to handle nks operations across different platforms. +#[repr(C)] +#[derive(Eq, Hash, PartialEq, Clone, Debug)] +pub enum NksType { + /// Represents the nks environment on HashiCorp Vault platforms. + #[cfg(feature = "hcvault")] + HCVault, + /// Represents an unsupported or unknown nks environment. + None, +} + +/// Provides a default `NksType` based on the compile-time target operating system. +/// +/// This implementation enables automatic selection of the nks type most appropriate +/// for the current target Network Key Storage, facilitating platform-agnostic nks handling. +impl Default for NksType { + #[allow(unreachable_code)] + fn default() -> Self { + + #[cfg(feature = "hcvault")] + return NksType::HCVault; + + NksType::None + } +} + +/// Enables conversion from a string slice to a `NksType`. +/// +/// This implementation allows for dynamic nks type determination based on string values, +/// useful for configuration or runtime environment specification. +impl From<&str> for NksType { + fn from(s: &str) -> Self { + match s { + #[cfg(feature = "hcvault")] + "HCVault" => NksType::HCVault, + _ => panic!("Unsupported NksType"), + } + } +} + +/// Manages instances of nks providers based on the specified `NksType`. +/// +/// This structure is responsible for creating and encapsulating a nks provider instance, +/// allowing for nks operations such as key management and cryptographic functions +/// to be performed in a platform-specific manner. +#[repr(C)] +pub struct NksInstance { + name: String, + instance: Box, +} + +/// Facilitates the creation and management of nks provider instances. +impl NksInstance { + /// Creates a new nks provider instance based on the specified `NksType`. + /// + /// This method abstracts over the differences between nks implementations across + /// various platforms, providing a unified interface for nks operations. + /// + /// # Arguments + /// * `key_id` - A unique identifier for the nks key. + /// * `nks_type` - A reference to the `NksType` indicating the environment of the nks. + /// + /// # Returns + /// An `Arc` encapsulating the created nks provider instance. + pub fn create_instance(key_id: String, tpm_type: &NksType) -> Arc> { + match tpm_type { + #[cfg(feature = "hcvault")] + NksType::HCVault => { + let instance = NksProvider::new(key_id); + Arc::new(Mutex::new(instance)) + } + NksType::None => todo!(), + } + } +} diff --git a/src/nks/core/mod.rs b/src/nks/core/mod.rs new file mode 100644 index 00000000..f7ddcb46 --- /dev/null +++ b/src/nks/core/mod.rs @@ -0,0 +1,2 @@ +pub mod error; +pub mod instance; diff --git a/src/nks/hcvault/key_handle.rs b/src/nks/hcvault/key_handle.rs new file mode 100644 index 00000000..ee5187d1 --- /dev/null +++ b/src/nks/hcvault/key_handle.rs @@ -0,0 +1,695 @@ +use arrayref::array_ref; +use base64::prelude::BASE64_STANDARD; +use base64::Engine; +use ed25519_dalek::{Signature, Signer as EdSigner, SigningKey, Verifier, VerifyingKey}; +use openssl::base64 as openssl_base64; +use openssl::hash::MessageDigest; +use openssl::pkey::PKey; +use openssl::rsa::{Padding, Rsa}; +use openssl::sign::{Signer as RSASigner, Verifier as RSAVerifier}; +use openssl::symm::{Cipher, Crypter, Mode}; +use rand::Rng; +use sodiumoxide::crypto::box_; +use x25519_dalek::{StaticSecret as X25519StaticSecret, StaticSecret}; + +use crate::common::crypto::algorithms::encryption::{ + BlockCiphers, EccCurves, EccSchemeAlgorithm, SymmetricMode, +}; +use crate::common::crypto::algorithms::hashes::*; +use crate::common::crypto::algorithms::KeyBits; +use crate::common::{ + crypto::algorithms::encryption::AsymmetricEncryption, error::SecurityModuleError, + traits::key_handle::KeyHandle, +}; +use crate::nks::NksConfig; +use crate::SecurityModuleError::InitializationError; + +use super::NksProvider; + +impl KeyHandle for NksProvider { + /// Signs the given data using the configured key and algorithm. + /// + /// # Arguments + /// + /// * `_data` - A slice of bytes representing the data to be signed. + /// + /// # Returns + /// + /// A `Result` containing the signature as a `Vec` on success, or a `SecurityModuleError` on failure. + #[tracing::instrument] + fn sign_data(&self, _data: &[u8]) -> Result, SecurityModuleError> { + if let Some(nks_config) = self + .config + .as_ref() + .unwrap() + .as_any() + .downcast_ref::() + { + let key_algorithm = &nks_config.key_algorithm; + let data = _data; + let hash = nks_config.hash; + + if self.private_key.is_empty() || data.is_empty() { + return Err(InitializationError("Private key is empty".to_string())); + } else { + match key_algorithm { + Some(AsymmetricEncryption::Rsa(..)) => { + // RSA signing method + let private_key_pem = self.private_key.as_bytes(); + let rsa = Rsa::private_key_from_pem(private_key_pem) + .map_err(|_| SecurityModuleError::KeyError)?; + let pkey = + PKey::from_rsa(rsa).map_err(|_| SecurityModuleError::KeyError)?; + // Create the signer based on the hash algorithm + let mut signer = match hash { + Hash::Sha1 => RSASigner::new(MessageDigest::sha1(), &pkey), + Hash::Sha2(Sha2Bits::Sha224) => { + RSASigner::new(MessageDigest::sha224(), &pkey) + } + Hash::Sha2(Sha2Bits::Sha256) => { + RSASigner::new(MessageDigest::sha256(), &pkey) + } + Hash::Sha2(Sha2Bits::Sha384) => { + RSASigner::new(MessageDigest::sha384(), &pkey) + } + Hash::Sha2(Sha2Bits::Sha512) => { + RSASigner::new(MessageDigest::sha512(), &pkey) + } + Hash::Sha3(Sha3Bits::Sha3_224) => { + RSASigner::new(MessageDigest::sha3_224(), &pkey) + } + Hash::Sha3(Sha3Bits::Sha3_256) => { + RSASigner::new(MessageDigest::sha3_256(), &pkey) + } + Hash::Sha3(Sha3Bits::Sha3_384) => { + RSASigner::new(MessageDigest::sha3_384(), &pkey) + } + Hash::Sha3(Sha3Bits::Sha3_512) => { + RSASigner::new(MessageDigest::sha3_512(), &pkey) + } + Hash::Md5 => RSASigner::new(MessageDigest::md5(), &pkey), + Hash::Ripemd160 => RSASigner::new(MessageDigest::ripemd160(), &pkey), + //Md2 and Md4 are not supported by openssl crate + _ => return Err(SecurityModuleError::UnsupportedAlgorithm), + } + .map_err(|_| SecurityModuleError::SigningFailed)?; + signer + .update(data) + .map_err(|_| SecurityModuleError::SigningFailed)?; + signer + .sign_to_vec() + .map_err(|_| SecurityModuleError::SigningFailed) + } + Some(AsymmetricEncryption::Ecc(EccSchemeAlgorithm::EcDsa( + EccCurves::Curve25519, + ))) => { + // ECC signing method + let static_secret = decode_base64_private_key(self.private_key.as_str()); + let signing_key = SigningKey::from_bytes(&static_secret.to_bytes()); + let signature_sig = signing_key.sign(data); + Ok(signature_sig.to_vec()) + } + _ => Err(SecurityModuleError::UnsupportedAlgorithm), + } + } + } else { + println!("Failed to downcast to NksConfig"); + Err(SecurityModuleError::NksError) + } + } + + /// Decrypts the given encrypted data using the configured key and algorithm. + /// + /// # Arguments + /// + /// * `_encrypted_data` - A slice of bytes representing the encrypted data. + /// + /// # Returns + /// + /// A `Result` containing the decrypted data as a `Vec` on success, or a `SecurityModuleError` on failure. + #[tracing::instrument] + fn decrypt_data(&self, _encrypted_data: &[u8]) -> Result, SecurityModuleError> { + let config = self + .config + .as_ref() + .unwrap() + .as_any() + .downcast_ref::() + .unwrap(); + + let key_algorithm = config.key_algorithm; + let key_algorithm_sym = config.key_algorithm_sym; + let encrypted_data = _encrypted_data; + + if self.private_key.is_empty() || encrypted_data.is_empty() { + return Err(InitializationError( + "Private key or encrypted data is empty".to_string(), + )); + } else { + match &key_algorithm { + Some(AsymmetricEncryption::Rsa(..)) => { + // RSA decryption method + let rsa = Rsa::private_key_from_pem(self.private_key.as_bytes()) + .map_err(|_| SecurityModuleError::KeyError)?; + let mut decrypted_data = vec![0; rsa.size() as usize]; + rsa.private_decrypt(encrypted_data, &mut decrypted_data, Padding::PKCS1) + .map_err(|_| { + SecurityModuleError::DecryptionError( + "RSA decryption failed".to_string(), + ) + })?; + let last_non_zero_pos = + decrypted_data.iter().rposition(|&x| x != 0).unwrap_or(0) + 1; + + let (decrypted_data, _) = decrypted_data.split_at(last_non_zero_pos); + + Ok(decrypted_data.to_vec()) + } + Some(AsymmetricEncryption::Ecc(..)) => { + let public_key_bytes = BASE64_STANDARD + .decode(self.public_key.as_bytes()) + .expect("Invalid public key base64"); + let private_key_bytes = BASE64_STANDARD + .decode(self.private_key.as_bytes()) + .expect("Invalid private key base64"); + + let public_key = + box_::PublicKey::from_slice(&public_key_bytes).expect("Invalid public key"); + let private_key = box_::SecretKey::from_slice(&private_key_bytes) + .expect("Invalid private key"); + + // Split the encrypted data into the nonce and the encrypted message + let (nonce_bytes, encrypted_message) = + _encrypted_data.split_at(box_::NONCEBYTES); + let nonce = box_::Nonce::from_slice(nonce_bytes).expect("Invalid nonce"); + + // Decrypt the message + let decrypted_message = + box_::open(encrypted_message, &nonce, &public_key, &private_key).map_err( + |_| { + SecurityModuleError::DecryptionError( + "Decryption failed".to_string(), + ) + }, + )?; + + Ok(decrypted_message) + } + None => match &key_algorithm_sym { + Some(BlockCiphers::Aes(mode, length)) => { + // AES decryption method + match mode { + SymmetricMode::Gcm => { + // AES GCM decryption + // Create the cipher based on the key length + let cipher = match length { + KeyBits::Bits128 => Cipher::aes_128_gcm(), + KeyBits::Bits192 => Cipher::aes_192_gcm(), + KeyBits::Bits256 => Cipher::aes_256_gcm(), + _ => return Err(SecurityModuleError::UnsupportedAlgorithm), + }; + let key = openssl_base64::decode_block(&self.private_key).unwrap(); + + // Split the encrypted data into the nonce, encrypted message, and tag + let nonce_end_index = 12; // Nonce is 12 bytes + let tag_start_index = _encrypted_data.len() - 16; // Tag is 16 bytes + let (nonce_and_encrypted_data, tag) = + _encrypted_data.split_at(tag_start_index); + let (nonce, encrypted_data) = + nonce_and_encrypted_data.split_at(nonce_end_index); + + // Initialize the crypter + let mut crypter = + Crypter::new(cipher, Mode::Decrypt, &key, Some(nonce)).unwrap(); + crypter.set_tag(tag).unwrap(); + + // Create a buffer for the decrypted data + let mut decrypted_data = + vec![0; encrypted_data.len() + cipher.block_size()]; + + // Decrypt the data + let count = + crypter.update(encrypted_data, &mut decrypted_data).unwrap(); + let rest = crypter.finalize(&mut decrypted_data[count..]).unwrap(); + + // Truncate the decrypted data to remove any extra bytes + decrypted_data.truncate(count + rest); + + Ok(decrypted_data) + } + SymmetricMode::Ecb => { + // AES ECB decryption + let cipher = match length { + KeyBits::Bits128 => Cipher::aes_128_ecb(), + KeyBits::Bits192 => Cipher::aes_192_ecb(), + KeyBits::Bits256 => Cipher::aes_256_ecb(), + _ => return Err(SecurityModuleError::UnsupportedAlgorithm), + }; + let key = openssl_base64::decode_block(&self.private_key).unwrap(); + let mut crypter = + Crypter::new(cipher, Mode::Decrypt, &key, None).unwrap(); + crypter.pad(true); + let mut decrypted_data = + vec![0; _encrypted_data.len() + cipher.block_size()]; + let count = crypter + .update(_encrypted_data, &mut decrypted_data) + .unwrap(); + let rest = crypter.finalize(&mut decrypted_data[count..]).unwrap(); + decrypted_data.truncate(count + rest); + Ok(decrypted_data) + } + SymmetricMode::Cbc => { + let cipher = match length { + KeyBits::Bits128 => Cipher::aes_128_cbc(), + KeyBits::Bits192 => Cipher::aes_192_cbc(), + KeyBits::Bits256 => Cipher::aes_256_cbc(), + _ => return Err(SecurityModuleError::UnsupportedAlgorithm), + }; + let key = openssl_base64::decode_block(&self.private_key).unwrap(); + let (iv, encrypted_data) = + _encrypted_data.split_at(cipher.iv_len().unwrap()); + let mut crypter = + Crypter::new(cipher, Mode::Decrypt, &key, Some(iv)).unwrap(); + crypter.pad(true); + let mut decrypted_data = + vec![0; encrypted_data.len() + cipher.block_size()]; + let count = + crypter.update(encrypted_data, &mut decrypted_data).unwrap(); + let rest = crypter.finalize(&mut decrypted_data[count..]).unwrap(); + decrypted_data.truncate(count + rest); + Ok(decrypted_data) + } + SymmetricMode::Cfb => { + let cipher = match length { + KeyBits::Bits128 => Cipher::aes_128_cfb1(), + KeyBits::Bits192 => Cipher::aes_192_cfb1(), + KeyBits::Bits256 => Cipher::aes_256_cfb1(), + _ => return Err(SecurityModuleError::UnsupportedAlgorithm), + }; + let key = openssl_base64::decode_block(&self.private_key).unwrap(); + let (iv, encrypted_data) = + _encrypted_data.split_at(cipher.iv_len().unwrap()); + let mut crypter = + Crypter::new(cipher, Mode::Decrypt, &key, Some(iv)).unwrap(); + let mut decrypted_data = + vec![0; encrypted_data.len() + cipher.block_size()]; + let count = + crypter.update(encrypted_data, &mut decrypted_data).unwrap(); + let rest = crypter.finalize(&mut decrypted_data[count..]).unwrap(); + decrypted_data.truncate(count + rest); + Ok(decrypted_data) + } + SymmetricMode::Ofb => { + let cipher = match length { + KeyBits::Bits128 => Cipher::aes_128_ofb(), + KeyBits::Bits192 => Cipher::aes_192_ofb(), + KeyBits::Bits256 => Cipher::aes_256_ofb(), + _ => return Err(SecurityModuleError::UnsupportedAlgorithm), + }; + let key = openssl_base64::decode_block(&self.private_key).unwrap(); + let (iv, encrypted_data) = + _encrypted_data.split_at(cipher.iv_len().unwrap()); + let mut crypter = + Crypter::new(cipher, Mode::Decrypt, &key, Some(iv)).unwrap(); + let mut decrypted_data = + vec![0; encrypted_data.len() + cipher.block_size()]; + let count = + crypter.update(encrypted_data, &mut decrypted_data).unwrap(); + let rest = crypter.finalize(&mut decrypted_data[count..]).unwrap(); + decrypted_data.truncate(count + rest); + Ok(decrypted_data) + } + SymmetricMode::Ctr => { + let cipher = match length { + KeyBits::Bits128 => Cipher::aes_128_ctr(), + KeyBits::Bits192 => Cipher::aes_192_ctr(), + KeyBits::Bits256 => Cipher::aes_256_ctr(), + _ => return Err(SecurityModuleError::UnsupportedAlgorithm), + }; + let key = openssl_base64::decode_block(&self.private_key).unwrap(); + let (iv, encrypted_data) = + _encrypted_data.split_at(cipher.iv_len().unwrap()); + let mut crypter = + Crypter::new(cipher, Mode::Decrypt, &key, Some(iv)).unwrap(); + let mut decrypted_data = + vec![0; encrypted_data.len() + cipher.block_size()]; + let count = + crypter.update(encrypted_data, &mut decrypted_data).unwrap(); + let rest = crypter.finalize(&mut decrypted_data[count..]).unwrap(); + decrypted_data.truncate(count + rest); + Ok(decrypted_data) + } + _ => Err(SecurityModuleError::UnsupportedAlgorithm), + } + } + _ => Err(SecurityModuleError::UnsupportedAlgorithm), + }, + } + } + } + + /// Encrypts the given data using the configured key and algorithm. + /// + /// # Arguments + /// + /// * `_data` - A slice of bytes representing the data to be encrypted. + /// + /// # Returns + /// + /// A `Result` containing the encrypted data as a `Vec` on success, or a `SecurityModuleError` on failure. + #[tracing::instrument] + fn encrypt_data(&self, _data: &[u8]) -> Result, SecurityModuleError> { + let config = self + .config + .as_ref() + .unwrap() + .as_any() + .downcast_ref::() + .unwrap(); + + let key_algorithm = config.key_algorithm; + let key_algorithm_sym = config.key_algorithm_sym; + let data = _data; + + if self.private_key.is_empty() || data.is_empty() { + return Err(InitializationError( + "Private key or data is empty".to_string(), + )); + } else { + match &key_algorithm { + Some(AsymmetricEncryption::Rsa(..)) => { + // RSA encryption method + let rsa = Rsa::public_key_from_pem(self.public_key.as_bytes()) + .map_err(|_| SecurityModuleError::KeyError)?; + let mut encrypted_data = vec![0; rsa.size() as usize]; + rsa.public_encrypt(data, &mut encrypted_data, Padding::PKCS1) + .map_err(|_| { + SecurityModuleError::EncryptionError( + "RSA encryption failed".to_string(), + ) + })?; + Ok(encrypted_data) + } + Some(AsymmetricEncryption::Ecc(..)) => { + let public_key_bytes = BASE64_STANDARD + .decode(self.public_key.as_bytes()) + .expect("Invalid public key base64"); + let private_key_bytes = BASE64_STANDARD + .decode(self.private_key.as_bytes()) + .expect("Invalid private key base64"); + + let public_key = + box_::PublicKey::from_slice(&public_key_bytes).expect("Invalid public key"); + let private_key = box_::SecretKey::from_slice(&private_key_bytes) + .expect("Invalid private key"); + + let nonce = box_::gen_nonce(); + let encrypted_message = box_::seal(data, &nonce, &public_key, &private_key); + + // Concatenate the nonce and the encrypted message into a single Vec + let mut result = + Vec::with_capacity(nonce.as_ref().len() + encrypted_message.len()); + result.extend_from_slice(nonce.as_ref()); + result.extend_from_slice(&encrypted_message); + Ok(result) + } + None => match &key_algorithm_sym { + Some(BlockCiphers::Aes(mode, length)) => { + // AES encryption method + match mode { + SymmetricMode::Gcm => { + // AES GCM encryption + // Create the cipher based on the key length + let cipher = match length { + KeyBits::Bits128 => Cipher::aes_128_gcm(), + KeyBits::Bits192 => Cipher::aes_192_gcm(), + KeyBits::Bits256 => Cipher::aes_256_gcm(), + _ => return Err(SecurityModuleError::UnsupportedAlgorithm), + }; + let key = openssl_base64::decode_block(&self.private_key).unwrap(); + + // Generate a random nonce + let mut rng = rand::thread_rng(); + let nonce: [u8; 12] = rng.gen(); + + // Initialize the result vector with the nonce + let mut result = Vec::new(); + result.extend_from_slice(&nonce); + + // Initialize the crypter + let mut crypter = + Crypter::new(cipher, Mode::Encrypt, &key, Some(&nonce)) + .unwrap(); + + // Create a buffer for the encrypted data + let mut encrypted_data = vec![0; _data.len() + cipher.block_size()]; + + // Encrypt the data + let count = crypter.update(_data, &mut encrypted_data).unwrap(); + let rest = crypter.finalize(&mut encrypted_data[count..]).unwrap(); + + // Truncate the encrypted data to remove any extra bytes + encrypted_data.truncate(count + rest); + + // Get the tag from the crypter + let mut tag = vec![0; 16]; + crypter.get_tag(&mut tag).unwrap(); + + // Add the encrypted data and the tag to the result + result.extend_from_slice(&encrypted_data); + result.extend_from_slice(&tag); + + Ok(result) + } + SymmetricMode::Ecb => { + // AES ECB encryption + let cipher = match length { + KeyBits::Bits128 => Cipher::aes_128_ecb(), + KeyBits::Bits192 => Cipher::aes_192_ecb(), + KeyBits::Bits256 => Cipher::aes_256_ecb(), + _ => return Err(SecurityModuleError::UnsupportedAlgorithm), + }; + let key = openssl_base64::decode_block(&self.private_key).unwrap(); + let mut crypter = + Crypter::new(cipher, Mode::Encrypt, &key, None).unwrap(); + crypter.pad(true); // Enable padding + let mut encrypted_data = vec![0; _data.len() + cipher.block_size()]; + let count = crypter.update(_data, &mut encrypted_data).unwrap(); + let rest = crypter.finalize(&mut encrypted_data[count..]).unwrap(); + encrypted_data.truncate(count + rest); + Ok(encrypted_data) + } + SymmetricMode::Cbc => { + let cipher = match length { + KeyBits::Bits128 => Cipher::aes_128_cbc(), + KeyBits::Bits192 => Cipher::aes_192_cbc(), + KeyBits::Bits256 => Cipher::aes_256_cbc(), + _ => return Err(SecurityModuleError::UnsupportedAlgorithm), + }; + let key = openssl_base64::decode_block(&self.private_key).unwrap(); + let iv_len = cipher.iv_len().unwrap(); + let mut iv = vec![0; iv_len]; + openssl::rand::rand_bytes(&mut iv).unwrap(); + let mut crypter = + Crypter::new(cipher, Mode::Encrypt, &key, Some(&iv)).unwrap(); + crypter.pad(true); + let mut encrypted_data = vec![0; _data.len() + cipher.block_size()]; + let count = crypter.update(_data, &mut encrypted_data).unwrap(); + let rest = crypter.finalize(&mut encrypted_data[count..]).unwrap(); + encrypted_data.truncate(count + rest); + let mut result = iv; + result.extend(encrypted_data); + Ok(result) + } + SymmetricMode::Cfb => { + let cipher = match length { + KeyBits::Bits128 => Cipher::aes_128_cfb1(), + KeyBits::Bits192 => Cipher::aes_192_cfb1(), + KeyBits::Bits256 => Cipher::aes_256_cfb1(), + _ => return Err(SecurityModuleError::UnsupportedAlgorithm), + }; + let key = openssl_base64::decode_block(&self.private_key).unwrap(); + let mut iv = vec![0; cipher.iv_len().unwrap()]; + openssl::rand::rand_bytes(&mut iv).unwrap(); + let mut crypter = + Crypter::new(cipher, Mode::Encrypt, &key, Some(&iv)).unwrap(); + let mut encrypted_data = vec![0; _data.len() + cipher.block_size()]; + let count = crypter.update(_data, &mut encrypted_data).unwrap(); + let rest = crypter.finalize(&mut encrypted_data[count..]).unwrap(); + encrypted_data.truncate(count + rest); + let mut result = iv; + result.extend(encrypted_data); + Ok(result) + } + SymmetricMode::Ofb => { + let cipher = match length { + KeyBits::Bits128 => Cipher::aes_128_ofb(), + KeyBits::Bits192 => Cipher::aes_192_ofb(), + KeyBits::Bits256 => Cipher::aes_256_ofb(), + _ => return Err(SecurityModuleError::UnsupportedAlgorithm), + }; + let key = openssl_base64::decode_block(&self.private_key).unwrap(); + let mut iv = vec![0; cipher.iv_len().unwrap()]; + openssl::rand::rand_bytes(&mut iv).unwrap(); + let mut crypter = + Crypter::new(cipher, Mode::Encrypt, &key, Some(&iv)).unwrap(); + let mut encrypted_data = vec![0; _data.len() + cipher.block_size()]; + let count = crypter.update(_data, &mut encrypted_data).unwrap(); + let rest = crypter.finalize(&mut encrypted_data[count..]).unwrap(); + encrypted_data.truncate(count + rest); + let mut result = iv; + result.extend(encrypted_data); + Ok(result) + } + SymmetricMode::Ctr => { + let cipher = match length { + KeyBits::Bits128 => Cipher::aes_128_ctr(), + KeyBits::Bits192 => Cipher::aes_192_ctr(), + KeyBits::Bits256 => Cipher::aes_256_ctr(), + _ => return Err(SecurityModuleError::UnsupportedAlgorithm), + }; + let key = openssl_base64::decode_block(&self.private_key).unwrap(); + let mut iv = vec![0; cipher.iv_len().unwrap()]; + openssl::rand::rand_bytes(&mut iv).unwrap(); + let mut crypter = + Crypter::new(cipher, Mode::Encrypt, &key, Some(&iv)).unwrap(); + let mut encrypted_data = vec![0; _data.len() + cipher.block_size()]; + let count = crypter.update(_data, &mut encrypted_data).unwrap(); + let rest = crypter.finalize(&mut encrypted_data[count..]).unwrap(); + encrypted_data.truncate(count + rest); + let mut result = iv; + result.extend(encrypted_data); + Ok(result) + } + _ => Err(SecurityModuleError::UnsupportedAlgorithm), + } + } + _ => Err(SecurityModuleError::UnsupportedAlgorithm), + }, + } + } + } + + /// Verifies the given signature against the provided data using the configured key and algorithm. + /// + /// # Arguments + /// + /// * `_data` - A slice of bytes representing the data that was signed. + /// * `_signature` - A slice of bytes representing the signature to be verified. + /// + /// # Returns + /// + /// A `Result` containing `true` if the signature is valid, `false` if it is invalid, or a `SecurityModuleError` on failure. + #[tracing::instrument] + fn verify_signature( + &self, + _data: &[u8], + _signature: &[u8], + ) -> Result { + if let Some(nks_config) = self + .config + .as_ref() + .unwrap() + .as_any() + .downcast_ref::() + { + let key_algorithm = &nks_config.key_algorithm; + let data = _data; + let signature = _signature; + let hash = nks_config.hash; + + if self.public_key.is_empty() || data.is_empty() || signature.is_empty() { + return Err(InitializationError( + "Public key, data or signature is empty".to_string(), + )); + } else { + match key_algorithm { + Some(AsymmetricEncryption::Rsa(..)) => { + // RSA signature verification method + let public_key_pem = self.public_key.as_bytes(); + let rsa = Rsa::public_key_from_pem(public_key_pem) + .map_err(|_| SecurityModuleError::KeyError)?; + let pkey = + PKey::from_rsa(rsa).map_err(|_| SecurityModuleError::KeyError)?; + let mut verifier = match hash { + Hash::Sha1 => RSAVerifier::new(MessageDigest::sha1(), &pkey), + Hash::Sha2(Sha2Bits::Sha224) => { + RSAVerifier::new(MessageDigest::sha224(), &pkey) + } + Hash::Sha2(Sha2Bits::Sha256) => { + RSAVerifier::new(MessageDigest::sha256(), &pkey) + } + Hash::Sha2(Sha2Bits::Sha384) => { + RSAVerifier::new(MessageDigest::sha384(), &pkey) + } + Hash::Sha2(Sha2Bits::Sha512) => { + RSAVerifier::new(MessageDigest::sha512(), &pkey) + } + Hash::Sha3(Sha3Bits::Sha3_224) => { + RSAVerifier::new(MessageDigest::sha3_224(), &pkey) + } + Hash::Sha3(Sha3Bits::Sha3_256) => { + RSAVerifier::new(MessageDigest::sha3_256(), &pkey) + } + Hash::Sha3(Sha3Bits::Sha3_384) => { + RSAVerifier::new(MessageDigest::sha3_384(), &pkey) + } + Hash::Sha3(Sha3Bits::Sha3_512) => { + RSAVerifier::new(MessageDigest::sha3_512(), &pkey) + } + Hash::Md5 => RSAVerifier::new(MessageDigest::md5(), &pkey), + Hash::Ripemd160 => RSAVerifier::new(MessageDigest::ripemd160(), &pkey), + //Md2 and Md4 are not supported by openssl crate + _ => return Err(SecurityModuleError::UnsupportedAlgorithm), + } + .map_err(|_| SecurityModuleError::SigningFailed)?; + verifier + .update(data) + .map_err(|_| SecurityModuleError::VerificationFailed)?; + Ok(verifier + .verify(signature) + .map_err(|_| SecurityModuleError::VerificationFailed)?) + } + Some(AsymmetricEncryption::Ecc(..)) => { + // ECC signature verification method + let signature_sig = Signature::from_slice(signature) + .map_err(|_| SecurityModuleError::InvalidSignature)?; + let public_key_bytes = BASE64_STANDARD + .decode(&self.public_key) + .map_err(|_| SecurityModuleError::InvalidPublicKey)?; + let verifying_result = VerifyingKey::from_bytes( + <&[u8; 32]>::try_from(public_key_bytes.as_slice()) + .map_err(|_| SecurityModuleError::InvalidPublicKey)?, + ); + match verifying_result { + Ok(verifying_key) => { + Ok(verifying_key.verify(data, &signature_sig).is_ok()) + } + Err(_) => Err(SecurityModuleError::VerificationFailed), + } + } + None => Err(SecurityModuleError::UnsupportedAlgorithm), + } + } + } else { + println!("Failed to downcast to NksConfig"); + Err(SecurityModuleError::NksError) + } + } +} + +/// Decodes a base64-encoded private key. +/// +/// # Arguments +/// +/// * `private_key_base64` - A string slice representing the base64-encoded private key. +/// +/// # Returns +/// +/// A `StaticSecret` representing the decoded private key. +pub fn decode_base64_private_key(private_key_base64: &str) -> StaticSecret { + let private_key_bytes = BASE64_STANDARD + .decode(private_key_base64.as_bytes()) + .expect("Invalid private key base64"); + X25519StaticSecret::from(*array_ref![private_key_bytes, 0, 32]) +} diff --git a/src/nks/hcvault/mod.rs b/src/nks/hcvault/mod.rs new file mode 100644 index 00000000..9c27c90b --- /dev/null +++ b/src/nks/hcvault/mod.rs @@ -0,0 +1,54 @@ +//TODO use CAL once it can compile +// use crate::common::crypto::{ +// algorithms::{ +// encryption::{ +// AsymmetricEncryption, BlockCiphers, EccCurves, EccSchemeAlgorithm, SymmetricMode, +// }, +// hashes::{Hash, Sha2Bits, Sha3Bits}, +// KeyBits, +// }, +// KeyUsage, +// }; +use std::sync::Arc; + +use crate::common::traits::module_provider_config::ProviderConfig; + +pub mod key_handle; +pub mod provider; + +/// A nks-based cryptographic provider for managing cryptographic keys and performing +/// cryptographic operations. +/// +/// This provider leverages the Network Key Storage (nks) to interact with a network +/// module for operations like signing, encryption, and decryption. It provides a secure and +/// network-backed implementation of cryptographic operations. +#[derive(Clone, Debug)] +#[repr(C)] +pub struct NksProvider { + //TODO implement NksProvider struct + + /// A unique identifier for the cryptographic key managed by this provider. + key_id: String, + pub(crate) config: Option>, + pub(super) secrets_json: Option, + public_key: String, + private_key: String, +} + +impl NksProvider { + /// Constructs a new `NksProvider`. + /// + /// # Arguments + /// + /// * `key_id` - A string identifier for the cryptographic key to be managed by this provider. + /// * `config` - The configuration for the NksProvider. + pub fn new(key_id: String) -> Self { + Self { + key_id, + config: None, + secrets_json: None, + public_key: String::new(), + private_key: String::new(), + } + } +} \ No newline at end of file diff --git a/src/nks/hcvault/provider.rs b/src/nks/hcvault/provider.rs new file mode 100644 index 00000000..7beecde2 --- /dev/null +++ b/src/nks/hcvault/provider.rs @@ -0,0 +1,581 @@ +use super::NksProvider; +use reqwest::Url; +use serde_json::{json, Value}; +use std::any::Any; +use std::fs; +use std::fs::File; +use std::io::Read; +use std::path::Path; +use std::str::FromStr; +use std::string::String; +use tokio::runtime::Runtime; +use tracing::instrument; + +use crate::common::crypto::algorithms::encryption::{ + BlockCiphers, EccCurves, EccSchemeAlgorithm, SymmetricMode, +}; +use crate::common::crypto::algorithms::KeyBits; +use crate::common::traits::module_provider_config::ProviderConfig; +use crate::common::{ + crypto::algorithms::encryption::AsymmetricEncryption, error::SecurityModuleError, + traits::module_provider::Provider, +}; +use crate::nks::NksConfig; + +/// Implements the `Provider` trait, providing cryptographic operations utilizing a nks. +impl Provider for NksProvider { + /// Creates a new cryptographic key identified by `key_id` within the NksProvider. + /// + /// This function generates a new cryptographic key within the NksProvider, using the settings + /// specified in the `config` parameter. The key is made persistent and associated with the provided `key_id`. + /// + /// # Arguments + /// + /// * `key_id` - A string slice that uniquely identifies the key to be created. + /// * `config` - A Box containing a `ProviderConfig` object that specifies the settings for the key. + /// + /// # Returns + /// + /// A `Result` that, on success, contains `Ok(())`, indicating that the key was created successfully. + /// On failure, it returns a `SecurityModuleError`. + /// + /// # Example + /// + /// ```ignore + /// let config = get_config("rsa").unwrap(); + /// provider.create_key("test_rsa_key", Box::new(config.clone())).expect("Failed to create RSA key"); + /// ``` + #[instrument] + fn create_key( + &mut self, + key_id: &str, + config: Box, + ) -> Result<(), SecurityModuleError> { + let mut key_length: Option = None; + let mut cyphertype: Option = None; + let config = config + .downcast_ref::() + .ok_or(SecurityModuleError::NksError)?; + if let Some(nks_config) = config.as_any().downcast_ref::() { + let runtime = Runtime::new().unwrap(); + let get_and_save_keypair_result = runtime.block_on(get_and_save_key_pair( + &nks_config.nks_token.clone(), + key_id, + match &nks_config.key_algorithm { + Some(AsymmetricEncryption::Rsa(rsa)) => { + key_length = Some(*rsa); + "rsa" + } + Some(AsymmetricEncryption::Ecc(EccSchemeAlgorithm::EcDh( + EccCurves::Curve25519, + ))) => "ecdh", + Some(AsymmetricEncryption::Ecc(_)) => "ecdsa", + None => match &nks_config.key_algorithm_sym { + Some(BlockCiphers::Aes(mode, length)) => { + key_length = Some(*length); + cyphertype = Some(match mode { + SymmetricMode::Cbc => "Cbc".to_string(), + SymmetricMode::Cfb => "Cfb".to_string(), + SymmetricMode::Ctr => "Ctr".to_string(), + SymmetricMode::Ecb => "Ecb".to_string(), + SymmetricMode::Ofb => "Ofb".to_string(), + SymmetricMode::Gcm => "Gcm".to_string(), + SymmetricMode::Ccm => "Ccm".to_string(), + }); + "aes" + } + _ => "none", + }, + }, + key_length, + Url::parse(&nks_config.nks_address).unwrap(), + cyphertype, + )); + match key_length { + Some(kb) => println!("XXXXX Key length: {}", u32::from(kb)), + None => println!("XXXXX Key length: None"), + } + match get_and_save_keypair_result { + Ok((result_string, new_token)) => { + println!("Key pair generated and saved successfully."); + self.secrets_json = Some(result_string.parse().unwrap()); + //safe token to config + let config = NksConfig::new( + new_token.clone(), + nks_config.nks_address.clone(), + nks_config.key_algorithm, + nks_config.hash, + nks_config.key_usages.clone(), + nks_config.key_algorithm_sym, + ); + self.config = Some(config); + //save token in token.json for persistence + let token_data = json!({ + "user_token": new_token.clone() + }); + fs::write("token.json", token_data.to_string()) + .expect("Error writing to token.json"); + Ok(()) + } + Err(err) => { + println!("Failed to generate and save key pair: {}", err); + Err(SecurityModuleError::NksError) + } + } + } else { + println!("Failed to downcast to NksConfig"); + Err(SecurityModuleError::NksError) + } + } + + /// Loads an existing cryptographic key identified by `key_id` from the NksProvider. + /// + /// This function retrieves an existing cryptographic key from the NksProvider, using the settings + /// specified in the `config` parameter. The key is associated with the provided `key_id`. + /// + /// # Arguments + /// + /// * `key_id` - A string slice that uniquely identifies the key to be loaded. + /// * `config` - A Box containing a `ProviderConfig` object that specifies the settings for the key. + /// + /// # Returns + /// + /// A `Result` that, on success, contains `Ok(())`, indicating that the key was loaded successfully. + /// On failure, it returns a `SecurityModuleError`. + /// + /// # Example + /// + /// ```ignore + /// let config = get_config("rsa").unwrap(); + /// provider.load_key("test_rsa_key", Box::new(config.clone())).expect("Failed to load RSA key"); + /// ``` + #[instrument] + fn load_key(&mut self, key_id: &str, _config: Box) -> Result<(), SecurityModuleError> { + // Check if secrets_json is None + if let Some(secrets_json) = &self.secrets_json { + // Iterate over the secrets_json object + if let Some(keys) = secrets_json.get("keys") { + for key in keys.as_array().unwrap() { + // Check if the key_id matches + if key.get("id").unwrap().as_str().unwrap() == key_id { + // Set the public_key and private_key + self.public_key = + key.get("publicKey").unwrap().as_str().unwrap().to_string(); + self.private_key = + key.get("privateKey").unwrap().as_str().unwrap().to_string(); + println!("Public Key: {}", self.public_key); + println!("Private Key: {}", self.private_key); + return Ok(()); + } + } + } + } else { + println!("Secrets JSON is empty"); + return Err(SecurityModuleError::NksError); + } + + // If no matching key is found, return an error + println!("Key '{}' not found in secrets_json", key_id); + Err(SecurityModuleError::NksError) + } + + /// Initializes the NksProvider module and prepares it for further cryptographic operations. + /// + /// This function sets up the NksProvider context by loading the configuration, establishing a connection with the Nks server, + /// and retrieving the current secrets. It should be called before performing any other operations with the NksProvider. + /// + /// # Returns + /// + /// A `Result` that, on success, contains `Ok(())`, indicating that the module was initialized successfully. + /// On failure, it returns a `SecurityModuleError`. + /// + /// # Example + /// + /// ```ignore + /// provider.initialize_module().expect("Failed to initialize module"); + /// ``` + #[instrument] + fn initialize_module(&mut self) -> Result<(), SecurityModuleError> { + if let Some(nks_config) = self + .config + .as_ref() + .unwrap() + .as_any() + .downcast_ref::() + { + //get address and token from config + let nks_address_str = nks_config.nks_address.clone(); + let nks_address = Some(Url::from_str(nks_address_str.as_str()).unwrap()); + let mut nks_token = nks_config.nks_token.clone(); + if nks_token.is_empty() { + println!("Token field in config is empty. checking for token.json..."); + // Check if token file exists + let tokens_file_path = Box::new(Path::new("token.json")); // Adjust the path as needed + if Path::new(&*tokens_file_path).exists() { + println!("Tokens file exists."); + nks_token = get_user_token_from_file().unwrap(); + } else { + println!("Token file does not exist. Generating token..."); + // Token field empty and no token in token.json, generate token using API + let runtime = Runtime::new().unwrap(); + let nks_address = nks_address.clone().ok_or(SecurityModuleError::NksError)?; + match runtime.block_on(get_token(nks_address.clone())) { + Ok(token) => { + nks_token = token; + } + Err(err) => { + println!("Failed to get tokens from API: {}", err); + return Err(SecurityModuleError::NksError); + } + } + } + } + //store current secrets + let runtime = Runtime::new().unwrap(); + match runtime.block_on(get_secrets(nks_token.as_str(), &nks_address_str)) { + Ok((secrets_json, new_token)) => { + self.secrets_json = Some(secrets_json.parse().unwrap()); + nks_token = new_token; + } + Err(err) => { + println!("Failed to get secrets: {}", err); + return Err(SecurityModuleError::NksError); + } + } + //safe token to config + let config = NksConfig::new( + nks_token.clone(), + nks_config.nks_address.clone(), + nks_config.key_algorithm, + nks_config.hash, + nks_config.key_usages.clone(), + nks_config.key_algorithm_sym, + ); + self.config = Some(config); + //save token in token.json for persistence + let token_data = json!({ + "user_token": nks_token.clone() + }); + fs::write("token.json", token_data.to_string()).expect("Error writing to token.json"); + println!("Nks initialized successfully."); + Ok(()) + } else { + println!("Failed to downcast to NksConfig"); + Err(SecurityModuleError::NksError) + } + } +} + +/// Retrieves the user token from the `token.json` file. +/// +/// This function opens the `token.json` file and reads its contents. It then parses the contents as JSON and retrieves the `user_token` field. +/// +/// # Returns +/// +/// An `Option` that, if the file exists and the `user_token` field is found, contains the user token as a `String`. +/// If the file does not exist, or the `user_token` field is not found, it returns `None`. +/// +/// # Example +/// +/// ```ignore +/// let user_token = get_user_token_from_file(); +/// if let Some(token) = user_token { +/// println!("User token: {}", token); +/// } else { +/// println!("User token not found"); +/// } +/// ``` +fn get_user_token_from_file() -> Option { + let mut file = File::open("token.json").ok()?; + let mut contents = String::new(); + file.read_to_string(&mut contents).ok()?; + + let json: Value = serde_json::from_str(&contents).ok()?; + + if let Some(user_token) = json["user_token"].as_str() { + Some(user_token.to_string()) + } else { + println!("user_token not found or invalid format."); + Some("no valid token".to_string()) + } +} + +/// Retrieves a user token from the NksProvider. +/// +/// This asynchronous function sends a GET request to the NksProvider's `getToken` endpoint. +/// It then parses the JSON response and retrieves the `token` field. +/// +/// # Arguments +/// +/// * `nks_address` - A `Url` that specifies the address of the NksProvider. +/// +/// # Returns +/// +/// A `Result` that, on success, contains an `Ok(String)`, which is the user token as a `String`. +/// On failure, it returns an `Err` with a `Box`. +/// +/// # Example +/// +/// ```ignore +/// let nks_address = Url::parse("https://nks.example.com").unwrap(); +/// let runtime = Runtime::new().unwrap(); +/// match runtime.block_on(get_token(nks_address)) { +/// Ok(token) => println!("User token: {}", token), +/// Err(err) => println!("Failed to get token: {}", err), +/// } +/// ``` +async fn get_token(nks_address: Url) -> anyhow::Result> { + let api_url = nks_address.join("getToken"); + let response: Value = reqwest::Client::builder() + .danger_accept_invalid_certs(true) + .build() + .unwrap() + .get(api_url.unwrap()) + .header("accept", "*/*") + .send() + .await? + .json() + .await?; + + if let Some(user_token) = response.get("token") { + if let Some(user_token_str) = user_token.as_str() { + return Ok(user_token_str.to_string()); + } + } + println!("The response does not contain a 'token' field"); + Ok(String::new()) +} + +/// Generates a new key pair and saves it in the NksProvider. +/// +/// This asynchronous function sends a POST request to the NksProvider's `generateAndSaveKeyPair` endpoint. +/// It then parses the JSON response and retrieves the `data` field which contains the generated key pair and the `newToken` field which contains the updated token. +/// +/// # Arguments +/// +/// * `token` - A string slice that represents the user token. +/// * `key_name` - A string slice that represents the name of the key to be generated. +/// * `key_type` - A string slice that represents the type of the key to be generated. The accepted values are "rsa", "ecdsa" and "ecdh". +/// * `nks_address` - A `Url` that specifies the address of the NksProvider. +/// +/// # Returns +/// +/// A `Result` that, on success, contains an `Ok((String, String))`, where the first string is the JSON representation of the generated key pair and the second string is the updated token. +/// On failure, it returns an `Err` with a `Box`. +/// +/// # Example +/// +/// ```ignore +/// let nks_address = Url::parse("https://nks.example.com").unwrap(); +/// let runtime = Runtime::new().unwrap(); +/// match runtime.block_on(get_and_save_key_pair("user_token", "key_name", "rsa", nks_address)) { +/// Ok((key_pair, new_token)) => { +/// println!("Key pair: {}", key_pair); +/// println!("New token: {}", new_token); +/// }, +/// Err(err) => println!("Failed to generate and save key pair: {}", err), +/// } +/// ``` +async fn get_and_save_key_pair( + token: &str, + key_name: &str, + key_type: &str, + key_length: Option, + nks_address: Url, + cyphertype: Option, +) -> Result<(String, String), Box> { + let key_length_u32 = key_length.map(u32::from); + let cyphertype_str = cyphertype.unwrap_or_default(); + let response = get_and_save_key_pair_request( + token, + key_name, + key_type, + nks_address, + key_length_u32, + &cyphertype_str, + ) + .await?; + + let status = response.status(); // Clone the status here + let response_text = response.text().await?; + if !status.is_success() { + let response_json: Value = serde_json::from_str(&response_text)?; + println!("Response JSON: {}", response_json); + if let Some(message) = response_json.get("message") { + if message.as_str().unwrap() == format!("Key with ID {} already exists.", key_name) { + return Err(format!("A key with name {} already exists.", key_name).into()); + } + if let Some(new_token) = response_json.get("newToken") { + let token_data = json!({ + "user_token": new_token.as_str().unwrap() + }); + fs::write("token.json", token_data.to_string()) + .expect("Error writing to token.json"); + return Err(format!( + "Server returned status code: {}. Message: {}", + status, + message.as_str().unwrap() + ) + .into()); + } + } else { + return Err(format!("Server returned status code: {}", status).into()); + } + } + let response_json: Value = serde_json::from_str(&response_text)?; + + let data = response_json + .get("data") + .ok_or("Data field not found in the response")?; + + let data_str = serde_json::to_string_pretty(data)?; + + let user_token = response_json + .get("newToken") + .unwrap() + .as_str() + .unwrap() + .to_string(); + + Ok((data_str, user_token)) +} + +/// Sends a request to the Nks server to generate and save a cryptographic key pair. +/// +/// This asynchronous function builds an HTTP client, constructs a JSON request body, +/// and sends a POST request to the Nks server to generate and save a cryptographic key pair. +/// The request includes the token for authentication, the key name, key type, and optionally the key length. +/// +/// # Arguments +/// +/// * `token` - A reference to the Nks token string used for authentication. +/// * `key_name` - A string slice that uniquely identifies the key to be created. +/// * `key_type` - A string slice representing the cryptographic algorithm to be used (e.g., "rsa"). +/// * `nks_address` - A `Url` object representing the address of the Nks server. +/// * `length` - An optional `Option` representing the length of the key (e.g., 2048 bits for RSA). +/// +/// # Returns +/// +/// A `Result` that, on success, contains a `reqwest::Response` object representing the server's response. +/// On failure, it returns a boxed `dyn std::error::Error`. +/// +/// # Example +/// +/// ```ignore +/// let response = get_and_save_key_pair_request(&token, "test_rsa_key", "rsa", nks_address, Some(2048)) +/// .await +/// .expect("Failed to send key pair generation request"); +/// ``` +/// +/// # Errors +/// +/// This function will return an error if: +/// - The HTTP client cannot be built. +/// - The API URL cannot be joined with the endpoint. +/// - The request cannot be sent successfully. +/// +/// The function uses `reqwest` for HTTP communication and handles any errors that may arise during the process. +async fn get_and_save_key_pair_request( + token: &str, + key_name: &str, + key_type: &str, + nks_address: Url, + length: Option, + cyphertype: &str, +) -> Result> { + let client = reqwest::Client::builder() + .danger_accept_invalid_certs(true) + .build()?; + let request_body = match length { + Some(len) => json!({ + "token": token, + "name": key_name, + "type": key_type, + "length": len, + "ciphertype": cyphertype + }), + None => json!({ + "token": token, + "name": key_name, + "type": key_type, + "ciphertype": cyphertype + }), + }; + let api_url = nks_address.join("generateAndSaveKeyPair"); + let response = client + .post(api_url.unwrap()) + .header("accept", "*/*") + .header("Content-Type", "application/json-patch+json") + .json(&request_body) + .send() + .await?; + Ok(response) +} + +/// Retrieves the secrets from the NksProvider. +/// +/// This asynchronous function sends a POST request to the NksProvider's `getSecrets` endpoint. +/// It then parses the JSON response and retrieves the `data` field which contains the secrets and the `newToken` field which contains the updated token. +/// +/// # Arguments +/// +/// * `token` - A string slice that represents the user token. +/// * `nks_address_str` - A string slice that specifies the address of the NksProvider. +/// +/// # Returns +/// +/// A `Result` that, on success, contains an `Ok((String, String))`, where the first string is the JSON representation of the secrets and the second string is the updated token. +/// On failure, it returns an `Err` with a `Box`. +/// +/// # Example +/// +/// ```ignore +/// let nks_address_str = "https://nks.example.com"; +/// let runtime = Runtime::new().unwrap(); +/// match runtime.block_on(get_secrets("user_token", nks_address_str)) { +/// Ok((secrets, new_token)) => { +/// println!("Secrets: {}", secrets); +/// println!("New token: {}", new_token); +/// }, +/// Err(err) => println!("Failed to get secrets: {}", err), +/// } +/// ``` +async fn get_secrets( + token: &str, + nks_address_str: &str, +) -> anyhow::Result<(String, String), Box> { + let client = reqwest::Client::builder() + .danger_accept_invalid_certs(true) + .build()?; + let body = json!({ + "token": token + }); + + let response: Value = client + .post(format!("{}getSecrets", nks_address_str)) + .header("accept", "*/*") + .header("Content-Type", "application/json-patch+json") + .json(&body) + .send() + .await? + .json() + .await?; + + //save new token + let user_token = response + .get("newToken") + .unwrap() + .as_str() + .unwrap() + .to_string(); + + // Extract the data field from the response + let data = response + .get("data") + .ok_or("Data field not found in the response")?; + + // Convert the data field back to a string + let data_str = serde_json::to_string_pretty(data)?; + + Ok((data_str, user_token)) +} diff --git a/src/nks/mod.rs b/src/nks/mod.rs new file mode 100644 index 00000000..e78b1833 --- /dev/null +++ b/src/nks/mod.rs @@ -0,0 +1,66 @@ +use crate::common::crypto::algorithms::encryption::{AsymmetricEncryption, BlockCiphers}; +use crate::common::crypto::algorithms::hashes::Hash; +use crate::common::crypto::KeyUsage; +use crate::common::traits::module_provider_config::ProviderConfig; +use std::any::Any; +use std::sync::Arc; + +#[cfg(feature = "core")] +pub mod core; +#[cfg(feature = "hcvault")] +pub mod hcvault; + +/// Configuration for NKS (Network Key Storage). +#[derive(Debug, Clone)] +pub struct NksConfig { + /// The NKS token used for authentication. + pub nks_token: String, + /// The address of the Nks server. + pub nks_address: String, + /// The algorithm used for asymmetric encryption. + pub key_algorithm: Option, + /// The hash algorithm to be used. + pub hash: Hash, + /// A list of key usages specifying the intended use of the keys. + pub key_usages: Vec, + pub key_algorithm_sym: Option, +} + +impl ProviderConfig for NksConfig { + /// Returns a reference to `self` as a trait object. + fn as_any(&self) -> &dyn Any { + self + } +} + +impl NksConfig { + /// Creates a new `NksConfig` instance wrapped in an `Arc`. + /// + /// # Parameters + /// - `nks_token`: A string representing the NKS token. + /// - `nks_address`: A string representing the address of the NKS server. + /// - `key_algorithm`: The asymmetric encryption algorithm to be used. + /// - `hash`: The hash algorithm to be used. + /// - `key_usages`: A vector of `KeyUsage` enums specifying the intended use of the keys. + /// + /// # Returns + /// An `Arc` containing the `NksConfig` instance. + #[allow(clippy::new_ret_no_self)] + pub fn new( + nks_token: String, + nks_address: String, + key_algorithm_asym: Option, + hash: Hash, + key_usages: Vec, + key_algorithm_sym: Option, + ) -> Arc { + Arc::new(Self { + nks_token, + nks_address, + key_algorithm: key_algorithm_asym, + hash, + key_usages, + key_algorithm_sym, + }) + } +} diff --git a/src/tests/common/traits/key_handle.rs b/src/tests/common/traits/key_handle.rs index 5d1c4584..90a953ae 100644 --- a/src/tests/common/traits/key_handle.rs +++ b/src/tests/common/traits/key_handle.rs @@ -1,4 +1,8 @@ -use crate::{ +#[cfg(feature = "hsm")] +use crate::hsm::core::instance::HsmType; +#[cfg(feature = "tpm")] +use crate::tpm::core::instance::TpmType; +/*use crate::{ common::{ crypto::{ algorithms::{ @@ -13,170 +17,180 @@ use crate::{ }, factory::SecurityModule, }, - hsm::core::instance::HsmType, tests::common::traits::setup_security_module, - tpm::{core::instance::TpmType, TpmConfig}, }; -use test_case::test_matrix; - -#[test_matrix( - [SecurityModule::Tpm(TpmType::Linux), - SecurityModule::Tpm(TpmType::Windows), - SecurityModule::Hsm(HsmType::NitroKey)] -)] -fn test_sign_and_verify_rsa(module: SecurityModule) { - let provider = setup_security_module(module); - - let config = TpmConfig::new( - AsymmetricEncryption::Rsa(KeyBits::Bits4096), - BlockCiphers::Aes(SymmetricMode::Gcm, KeyBits::Bits512), - Hash::Sha2(Sha2Bits::Sha256), - vec![KeyUsage::SignEncrypt, KeyUsage::ClientAuth], - ); - - provider - .lock() - .unwrap() - .initialize_module() - .expect("Failed to initialize module"); - provider - .lock() - .unwrap() - .create_key("test_rsa_key", config) - .expect("Failed to create RSA key"); - - let data = b"Hello, World!"; - let signature = provider - .lock() - .unwrap() - .sign_data(data) - .expect("Failed to sign data"); - - assert!(provider - .lock() - .unwrap() - .verify_signature(data, &signature) - .unwrap()); -} - -#[test_matrix( - [SecurityModule::Tpm(TpmType::Linux), - SecurityModule::Tpm(TpmType::Windows), - SecurityModule::Hsm(HsmType::NitroKey)] -)] -fn test_sign_and_verify_ecdsa(module: SecurityModule) { - let provider = setup_security_module(module); - - let config = TpmConfig::new( - AsymmetricEncryption::Ecc(EccSchemeAlgorithm::EcDsa(EccCurves::Curve25519)), - BlockCiphers::Aes(SymmetricMode::Gcm, KeyBits::Bits512), - Hash::Sha2(Sha2Bits::Sha256), - vec![KeyUsage::SignEncrypt, KeyUsage::ClientAuth], - ); - - provider - .lock() - .unwrap() - .initialize_module() - .expect("Failed to initialize module"); - provider - .lock() - .unwrap() - .create_key("test_ecdsa_key", config) - .expect("Failed to create ECDSA key"); - - let data = b"Hello, World!"; - let signature = provider - .lock() - .unwrap() - .sign_data(data) - .expect("Failed to sign data"); - - assert!(provider - .lock() - .unwrap() - .verify_signature(data, &signature) - .unwrap()); -} - -#[test_matrix( - [SecurityModule::Tpm(TpmType::Linux), - SecurityModule::Tpm(TpmType::Windows), - SecurityModule::Hsm(HsmType::NitroKey)] -)] -fn test_encrypt_and_decrypt_rsa(module: SecurityModule) { - let provider = setup_security_module(module); - - let config = TpmConfig::new( - AsymmetricEncryption::Rsa(KeyBits::Bits4096), - BlockCiphers::Aes(SymmetricMode::Gcm, KeyBits::Bits512), - Hash::Sha2(Sha2Bits::Sha256), - vec![KeyUsage::Decrypt, KeyUsage::SignEncrypt], - ); - - provider - .lock() - .unwrap() - .initialize_module() - .expect("Failed to initialize module"); - provider - .lock() - .unwrap() - .create_key("test_rsa_key", config) - .expect("Failed to create RSA key"); - - let data = b"Hello, World!"; - let encrypted_data = provider - .lock() - .unwrap() - .encrypt_data(data) - .expect("Failed to encrypt data"); - let decrypted_data = provider - .lock() - .unwrap() - .decrypt_data(&encrypted_data) - .expect("Failed to decrypt data"); - - assert_eq!(data, decrypted_data.as_slice()); -} - -#[test_matrix( - [SecurityModule::Tpm(TpmType::Linux), - SecurityModule::Tpm(TpmType::Windows), - SecurityModule::Hsm(HsmType::NitroKey)] -)] -fn test_encrypt_and_decrypt_ecdh(module: SecurityModule) { - let provider = setup_security_module(module); - - let config = TpmConfig::new( - AsymmetricEncryption::Ecc(EccSchemeAlgorithm::EcDh(EccCurves::Curve25519)), - BlockCiphers::Aes(SymmetricMode::Gcm, KeyBits::Bits512), - Hash::Sha2(Sha2Bits::Sha256), - vec![KeyUsage::SignEncrypt, KeyUsage::Decrypt], - ); - - provider - .lock() - .unwrap() - .initialize_module() - .expect("Failed to initialize module"); - provider - .lock() - .unwrap() - .create_key("test_ecdh_key", config) - .expect("Failed to create ECDH key"); - - let data = b"Hello, World!"; - let encrypted_data = provider - .lock() - .unwrap() - .encrypt_data(data) - .expect("Failed to encrypt data"); - let decrypted_data = provider - .lock() - .unwrap() - .decrypt_data(&encrypted_data) - .expect("Failed to decrypt data"); - - assert_eq!(data, decrypted_data.as_slice()); -} +use test_case::test_matrix;*/ +// +// // #[test_matrix( +// // [SecurityModule::Tpm(TpmType::Linux), +// // SecurityModule::Tpm(TpmType::Windows), +// // SecurityModule::Hsm(HsmType::NitroKey)] +// // )] +// #[test_matrix( +// [SecurityModule::Nks] +// )] +// fn test_sign_and_verify_rsa(module: SecurityModule) { +// let provider = setup_security_module(module); +// +// let config = TpmConfig::new( +// AsymmetricEncryption::Rsa(KeyBits::Bits4096), +// BlockCiphers::Aes(SymmetricMode::Gcm, KeyBits::Bits512), +// Hash::Sha2(Sha2Bits::Sha256), +// vec![KeyUsage::SignEncrypt, KeyUsage::ClientAuth], +// ); +// +// provider +// .lock() +// .unwrap() +// .initialize_module() +// .expect("Failed to initialize module"); +// provider +// .lock() +// .unwrap() +// .create_key("test_rsa_key", config) +// .expect("Failed to create RSA key"); +// +// let data = b"Hello, World!"; +// let signature = provider +// .lock() +// .unwrap() +// .sign_data(data) +// .expect("Failed to sign data"); +// +// assert!(provider +// .lock() +// .unwrap() +// .verify_signature(data, &signature) +// .unwrap()); +// } +// +// // #[test_matrix( +// // [SecurityModule::Tpm(TpmType::Linux), +// // SecurityModule::Tpm(TpmType::Windows), +// // SecurityModule::Hsm(HsmType::NitroKey)] +// // )] +// #[test_matrix( +// [SecurityModule::Nks] +// )] +// fn test_sign_and_verify_ecdsa(module: SecurityModule) { +// let provider = setup_security_module(module); +// +// let config = TpmConfig::new( +// AsymmetricEncryption::Ecc(EccSchemeAlgorithm::EcDsa(EccCurves::Curve25519)), +// BlockCiphers::Aes(SymmetricMode::Gcm, KeyBits::Bits512), +// Hash::Sha2(Sha2Bits::Sha256), +// vec![KeyUsage::SignEncrypt, KeyUsage::ClientAuth], +// ); +// +// provider +// .lock() +// .unwrap() +// .initialize_module() +// .expect("Failed to initialize module"); +// provider +// .lock() +// .unwrap() +// .create_key("test_ecdsa_key", config) +// .expect("Failed to create ECDSA key"); +// +// let data = b"Hello, World!"; +// let signature = provider +// .lock() +// .unwrap() +// .sign_data(data) +// .expect("Failed to sign data"); +// +// assert!(provider +// .lock() +// .unwrap() +// .verify_signature(data, &signature) +// .unwrap()); +// } +// +// // #[test_matrix( +// // [SecurityModule::Tpm(TpmType::Linux), +// // SecurityModule::Tpm(TpmType::Windows), +// // SecurityModule::Hsm(HsmType::NitroKey)] +// // )] +// #[test_matrix( +// [SecurityModule::Nks] +// )] +// fn test_encrypt_and_decrypt_rsa(module: SecurityModule) { +// let provider = setup_security_module(module); +// +// let config = TpmConfig::new( +// AsymmetricEncryption::Rsa(KeyBits::Bits4096), +// BlockCiphers::Aes(SymmetricMode::Gcm, KeyBits::Bits512), +// Hash::Sha2(Sha2Bits::Sha256), +// vec![KeyUsage::Decrypt, KeyUsage::SignEncrypt], +// ); +// +// provider +// .lock() +// .unwrap() +// .initialize_module() +// .expect("Failed to initialize module"); +// provider +// .lock() +// .unwrap() +// .create_key("test_rsa_key", config) +// .expect("Failed to create RSA key"); +// +// let data = b"Hello, World!"; +// let encrypted_data = provider +// .lock() +// .unwrap() +// .encrypt_data(data) +// .expect("Failed to encrypt data"); +// let decrypted_data = provider +// .lock() +// .unwrap() +// .decrypt_data(&encrypted_data) +// .expect("Failed to decrypt data"); +// +// assert_eq!(data, decrypted_data.as_slice()); +// } +// +// // #[test_matrix( +// // [SecurityModule::Tpm(TpmType::Linux), +// // SecurityModule::Tpm(TpmType::Windows), +// // SecurityModule::Hsm(HsmType::NitroKey)] +// // )] +// #[test_matrix( +// [SecurityModule::Nks] +// )] +// fn test_encrypt_and_decrypt_ecdh(module: SecurityModule) { +// let provider = setup_security_module(module); +// +// let config = TpmConfig::new( +// AsymmetricEncryption::Ecc(EccSchemeAlgorithm::EcDh(EccCurves::Curve25519)), +// BlockCiphers::Aes(SymmetricMode::Gcm, KeyBits::Bits512), +// Hash::Sha2(Sha2Bits::Sha256), +// vec![KeyUsage::SignEncrypt, KeyUsage::Decrypt], +// ); +// +// provider +// .lock() +// .unwrap() +// .initialize_module() +// .expect("Failed to initialize module"); +// provider +// .lock() +// .unwrap() +// .create_key("test_ecdh_key", config) +// .expect("Failed to create ECDH key"); +// +// let data = b"Hello, World!"; +// let encrypted_data = provider +// .lock() +// .unwrap() +// .encrypt_data(data) +// .expect("Failed to encrypt data"); +// let decrypted_data = provider +// .lock() +// .unwrap() +// .decrypt_data(&encrypted_data) +// .expect("Failed to decrypt data"); +// +// assert_eq!(data, decrypted_data.as_slice()); +// } diff --git a/src/tests/common/traits/mod.rs b/src/tests/common/traits/mod.rs index ef36d0a7..fd907b57 100644 --- a/src/tests/common/traits/mod.rs +++ b/src/tests/common/traits/mod.rs @@ -59,7 +59,10 @@ fn setup_security_module(module: SecurityModule) -> Arc> { ) .unwrap(), TpmType::None => unimplemented!(), + TpmType::Android(_) => unimplemented!(), }, + #[cfg(feature = "nks")] + SecurityModule::Nks => unimplemented!(), // _ => unimplemented!(), } } diff --git a/src/tests/common/traits/module_provider.rs b/src/tests/common/traits/module_provider.rs index 5b4cba30..c2d8a5bd 100644 --- a/src/tests/common/traits/module_provider.rs +++ b/src/tests/common/traits/module_provider.rs @@ -1,83 +1,91 @@ -use super::setup_security_module; -use crate::{ - common::{ - crypto::{ - algorithms::{ - encryption::{AsymmetricEncryption, BlockCiphers, SymmetricMode}, - hashes::{Hash, Sha2Bits}, - KeyBits, - }, - KeyUsage, +/*use super::setup_security_module; +use crate::common::{ + crypto::{ + algorithms::{ + encryption::{AsymmetricEncryption, BlockCiphers, SymmetricMode}, + hashes::{Hash, Sha2Bits}, + KeyBits, }, - factory::SecurityModule, + KeyUsage, }, - hsm::core::instance::HsmType, - tpm::{core::instance::TpmType, TpmConfig}, + factory::SecurityModule, }; use test_case::test_matrix; +#[cfg(feature = "hsm")] +use crate::hsm::core::instance::HsmType; +#[cfg(feature = "tpm")] +use crate::tpm::{core::instance::TpmType, TpmConfig}; + +// #[test_matrix( +// [SecurityModule::Tpm(TpmType::Linux), +// SecurityModule::Tpm(TpmType::Windows), +// SecurityModule::Hsm(HsmType::NitroKey)] +// )] #[test_matrix( - [SecurityModule::Tpm(TpmType::Linux), - SecurityModule::Tpm(TpmType::Windows), - SecurityModule::Hsm(HsmType::NitroKey)] + [SecurityModule::Nks] )] fn test_create_rsa_key(module: SecurityModule) { - let provider = setup_security_module(module); - - let config = TpmConfig::new( - AsymmetricEncryption::Rsa(KeyBits::Bits4096), - BlockCiphers::Aes(SymmetricMode::Gcm, KeyBits::Bits512), - Hash::Sha2(Sha2Bits::Sha256), - vec![ - KeyUsage::SignEncrypt, - KeyUsage::ClientAuth, - KeyUsage::SignEncrypt, - KeyUsage::CreateX509, - ], - ); - - providerw - .lock() - .unwrap() - .initialize_module() - .expect("Failed to initialize module"); - - provider - .lock() - .unwrap() - .create_key("test_rsa_key", config) - .expect("Failed to create RSA key"); + // let provider = setup_security_module(module); + // + // let config = TpmConfig::new( + // AsymmetricEncryption::Rsa(KeyBits::Bits4096), + // BlockCiphers::Aes(SymmetricMode::Gcm, KeyBits::Bits512), + // Hash::Sha2(Sha2Bits::Sha256), + // vec![ + // KeyUsage::SignEncrypt, + // KeyUsage::ClientAuth, + // KeyUsage::SignEncrypt, + // KeyUsage::CreateX509, + // ], + // ); + // + // provider + // .lock() + // .unwrap() + // .initialize_module() + // .expect("Failed to initialize module"); + // + // provider + // .lock() + // .unwrap() + // .create_key("test_rsa_key", config) + // .expect("Failed to create RSA key"); } +// #[test_matrix( +// [SecurityModule::Tpm(TpmType::Linux), +// SecurityModule::Tpm(TpmType::Windows), +// SecurityModule::Hsm(HsmType::NitroKey)] +// )] #[test_matrix( - [SecurityModule::Tpm(TpmType::Linux), - SecurityModule::Tpm(TpmType::Windows), - SecurityModule::Hsm(HsmType::NitroKey)] + [SecurityModule::Nks] )] fn test_load_rsa_key(module: SecurityModule) { - let provider = setup_security_module(module); - - let config = TpmConfig::new( - AsymmetricEncryption::Rsa(KeyBits::Bits4096), - BlockCiphers::Aes(SymmetricMode::Gcm, KeyBits::Bits512), - Hash::Sha2(Sha2Bits::Sha256), - vec![ - KeyUsage::SignEncrypt, - KeyUsage::ClientAuth, - KeyUsage::SignEncrypt, - KeyUsage::CreateX509, - ], - ); - - provider - .lock() - .unwrap() - .initialize_module() - .expect("Failed to initialize module"); - - provider - .lock() - .unwrap() - .load_key("test_rsa_key", config) - .expect("Failed to load RSA key"); + // let provider = setup_security_module(module); + // + // let config = TpmConfig::new( + // AsymmetricEncryption::Rsa(KeyBits::Bits4096), + // BlockCiphers::Aes(SymmetricMode::Gcm, KeyBits::Bits512), + // Hash::Sha2(Sha2Bits::Sha256), + // vec![ + // KeyUsage::SignEncrypt, + // KeyUsage::ClientAuth, + // KeyUsage::SignEncrypt, + // KeyUsage::CreateX509, + // ], + // ); + // + // provider + // .lock() + // .unwrap() + // .initialize_module() + // .expect("Failed to initialize module"); + // + // provider + // .lock() + // .unwrap() + // .load_key("test_rsa_key", config) + // .expect("Failed to load RSA key"); } +*/ \ No newline at end of file diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 38e784e3..6fecee41 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,3 +1,10 @@ pub mod common; + +#[cfg(feature = "hsm")] pub mod hsm; + +#[cfg(feature = "tpm")] mod tpm; + +#[cfg(feature = "nks")] +mod nks; diff --git a/src/tests/nks/key_handle_tests.rs b/src/tests/nks/key_handle_tests.rs new file mode 100644 index 00000000..e416870f --- /dev/null +++ b/src/tests/nks/key_handle_tests.rs @@ -0,0 +1,169 @@ +#[allow(unused_imports)] +use crate::{ + common::{ + crypto::{ + algorithms::{ + encryption::{AsymmetricEncryption, BlockCiphers, EccCurves, EccSchemeAlgorithm}, + hashes::Hash, + }, + KeyUsage, + }, + traits::{key_handle::KeyHandle, module_provider::Provider}, + }, + // tpm::linux::TpmProvider, +}; +use crate::common::crypto::algorithms::encryption::SymmetricMode; +use crate::common::crypto::algorithms::KeyBits; + +use crate::nks::hcvault::NksProvider; +use crate::nks::NksConfig; + +#[test] +fn test_sign_and_verify_rsa() { + let mut provider = NksProvider::new("test_key".to_string()); + provider.config = Some(crate::tests::nks::provider_handle_tests::get_config("rsa", None, None).unwrap()); + provider + .initialize_module() + .expect("Failed to initialize module"); + + if let Some(nks_config) = provider.config.as_ref().unwrap().as_any().downcast_ref::() { + provider + .load_key("test_rsa_key", Box::new(nks_config.clone())) + .expect("Failed to load RSA key"); + } else { + println!("Failed to downcast to NksConfig"); + } + let data = b"Hello, World!"; + let signature = provider.sign_data(data).expect( + "Failed to sign data", + ); + assert!(provider.verify_signature(data, &signature).unwrap()); +} + +#[test] +fn test_sign_and_verify_ecdsa() { + let mut provider = NksProvider::new("test_key".to_string()); + provider.config = Some(crate::tests::nks::provider_handle_tests::get_config("ecdsa", None, None).unwrap()); + provider + .initialize_module() + .expect("Failed to initialize module"); + + let nks_config = provider.config.as_ref().unwrap().as_any().downcast_ref::().cloned(); + + if let Some(nks_config) = nks_config { + provider + .load_key("test_ecdsa_key", Box::new(nks_config.clone())) + .expect("Failed to load ECDSA key"); + } else { + println!("Failed to downcast to NksConfig"); + } + let data = b"Hello, World!"; + let signature = provider.sign_data(data).expect( + "Failed to sign data", + ); + assert!(provider.verify_signature(data, &signature).unwrap()); +} + +#[test] +fn test_encrypt_and_decrypt_rsa() { + let mut provider = NksProvider::new("test_key".to_string()); + + provider.config = Some(crate::tests::nks::provider_handle_tests::get_config("rsa", None, None).unwrap()); + + provider + .initialize_module() + .expect("Failed to initialize module"); + + if let Some(nks_config) = provider.config.as_ref().unwrap().as_any().downcast_ref::() { + provider + .load_key("test_rsa_key", Box::new(nks_config.clone())) + .expect("Failed to load RSA key"); + } else { + println!("Failed to downcast to NksConfig"); + } + + + let data = b"Hello, World!"; + let encrypted_data = provider.encrypt_data(data).expect("Failed to encrypt data"); + let decrypted_data = provider + .decrypt_data(&encrypted_data) + .expect("Failed to decrypt data"); + assert_eq!(data, decrypted_data.as_slice()) +} + +#[test] +fn test_encrypt_and_decrypt_ecdh() { + let mut provider = NksProvider::new("ecdh".to_string()); + + provider.config = Some(crate::tests::nks::provider_handle_tests::get_config("ecdh", None, None).unwrap()); + + provider + .initialize_module() + .expect("Failed to initialize module"); + + if let Some(nks_config) = provider.config.as_ref().unwrap().as_any().downcast_ref::() { + provider + .load_key("test_ecdh_key", Box::new(nks_config.clone())) + .expect("Failed to load ecdh key"); + } else { + println!("Failed to downcast to NksConfig"); + } + + + let data = b"Hello, World!"; + let encrypted_data = provider.encrypt_data(data).expect("Failed to encrypt data"); + let decrypted_data = provider + .decrypt_data(&encrypted_data) + .expect("Failed to decrypt data"); + assert_eq!(data, decrypted_data.as_slice()) +} + +#[test] +fn test_encrypt_and_decrypt_aes_gcm() { + test_encrypt_and_decrypt_aes(SymmetricMode::Gcm, &[KeyBits::Bits128, KeyBits::Bits192, KeyBits::Bits256]); +} + +#[test] +fn test_encrypt_and_decrypt_aes_ecb() { + test_encrypt_and_decrypt_aes(SymmetricMode::Ecb, &[KeyBits::Bits128, KeyBits::Bits192, KeyBits::Bits256]); +} + +#[test] +fn test_encrypt_and_decrypt_aes_cbc() { + test_encrypt_and_decrypt_aes(SymmetricMode::Cbc, &[KeyBits::Bits128, KeyBits::Bits192, KeyBits::Bits256]); +} + +#[test] +fn test_encrypt_and_decrypt_aes_cfb() { + test_encrypt_and_decrypt_aes(SymmetricMode::Cfb, &[KeyBits::Bits128, KeyBits::Bits192, KeyBits::Bits256]); +} + +#[test] +fn test_encrypt_and_decrypt_aes_ofb() { + test_encrypt_and_decrypt_aes(SymmetricMode::Ofb, &[KeyBits::Bits128, KeyBits::Bits192, KeyBits::Bits256]); +} + +#[test] +fn test_encrypt_and_decrypt_aes_ctr() { + test_encrypt_and_decrypt_aes(SymmetricMode::Ctr, &[KeyBits::Bits128, KeyBits::Bits192, KeyBits::Bits256]); +} + +fn test_encrypt_and_decrypt_aes(mode: SymmetricMode, key_sizes: &[KeyBits]) { + for &key_size in key_sizes { + let mut provider = NksProvider::new(format!("aes_{}", mode as u8)); + provider.config = Some(crate::tests::nks::provider_handle_tests::get_config("aes", Some(key_size), Some(mode)).unwrap()); + provider.initialize_module().expect("Failed to initialize module"); + + if let Some(nks_config) = provider.config.as_ref().unwrap().as_any().downcast_ref::() { + provider.load_key(&format!("test_aes_key_{}_{}", mode as u8, key_size as u8), Box::new(nks_config.clone())) + .expect("Failed to load AES key"); + } else { + println!("Failed to downcast to NksConfig"); + } + + let data = b"Hello, World!"; + let encrypted_data = provider.encrypt_data(data).expect("Failed to encrypt data"); + let decrypted_data = provider.decrypt_data(&encrypted_data).expect("Failed to decrypt data"); + assert_eq!(data, decrypted_data.as_slice()) + } +} diff --git a/src/tests/nks/mod.rs b/src/tests/nks/mod.rs new file mode 100644 index 00000000..dbd68575 --- /dev/null +++ b/src/tests/nks/mod.rs @@ -0,0 +1,2 @@ +mod key_handle_tests; +mod provider_handle_tests; diff --git a/src/tests/nks/provider_handle_tests.rs b/src/tests/nks/provider_handle_tests.rs new file mode 100644 index 00000000..34304101 --- /dev/null +++ b/src/tests/nks/provider_handle_tests.rs @@ -0,0 +1,245 @@ +use std::sync::Arc; +use crate::{ + common::{ + crypto::{ + algorithms::{ + encryption::{AsymmetricEncryption, EccCurves, EccSchemeAlgorithm}, + hashes::Hash, + }, + KeyUsage, + }, + traits::module_provider::Provider, + }, + nks::hcvault::NksProvider, +}; +use crate::common::crypto::algorithms::encryption::{BlockCiphers, SymmetricMode}; +use crate::common::crypto::algorithms::hashes::Sha2Bits; +use crate::common::crypto::algorithms::KeyBits; +use crate::common::traits::module_provider_config::ProviderConfig; +use crate::nks::NksConfig; + +#[test] +fn test_create_rsa_key() { + let mut provider = NksProvider::new("test_key".to_string()); + + provider.config = Some(get_config("rsa", None, None).unwrap()); + + provider + .initialize_module() + .expect("Failed to initialize module"); + + if let Some(nks_config) = provider.config.as_ref().unwrap().as_any().downcast_ref::() { + provider + .create_key("test_rsa_key", Box::new(nks_config.clone())) + .expect("Failed to create RSA key"); + } else { + println!("Failed to downcast to NksConfig"); + } +} + +#[test] +fn test_create_ecdsa_key() { + let mut provider = NksProvider::new("test_key".to_string()); + + provider.config = Some(get_config("ecdsa", None, None).unwrap()); + + provider + .initialize_module() + .expect("Failed to initialize module"); + + if let Some(nks_config) = provider.config.as_ref().unwrap().as_any().downcast_ref::() { + provider + .create_key("test_ecdsa_key", Box::new(nks_config.clone())) + .expect("Failed to create ECDSA key"); + } else { + println!("Failed to downcast to NksConfig"); + } +} + +#[test] +fn test_create_ecdh_key() { + let mut provider = NksProvider::new("test_key".to_string()); + + provider.config = Some(get_config("ecdh", None, None).unwrap()); + + provider + .initialize_module() + .expect("Failed to initialize module"); + + if let Some(nks_config) = provider.config.as_ref().unwrap().as_any().downcast_ref::() { + provider + .create_key("test_ecdh_key", Box::new(nks_config.clone())) + .expect("Failed to create ECDH key"); + } else { + println!("Failed to downcast to NksConfig"); + } +} + +#[test] +fn test_create_aes_key() { + for &key_size in &[KeyBits::Bits128, KeyBits::Bits192, KeyBits::Bits256] { + for &aes_mode in &[SymmetricMode::Gcm, SymmetricMode::Ecb, SymmetricMode::Cbc, SymmetricMode::Ctr, SymmetricMode::Cfb, SymmetricMode::Ofb] { + let mut provider = NksProvider::new("test_key".to_string()); + + provider.config = Some(get_config("aes", Some(key_size), Some(aes_mode)).unwrap()); + + provider + .initialize_module() + .expect("Failed to initialize module"); + + if let Some(nks_config) = provider.config.as_ref().unwrap().as_any().downcast_ref::() { + provider + .create_key(&format!("test_aes_key_{}_{}", aes_mode as u8, key_size as u8), Box::new(nks_config.clone())) + .expect("Failed to create AES key"); + } else { + println!("Failed to downcast to NksConfig"); + } + } + } +} + +#[test] +fn test_load_rsa_key() { + let mut provider = NksProvider::new("test_key".to_string()); + + provider.config = Some(get_config("rsa", None, None).unwrap()); + + provider + .initialize_module() + .expect("Failed to initialize module"); + + if let Some(nks_config) = provider.config.as_ref().unwrap().as_any().downcast_ref::() { + provider + .load_key("test_rsa_key", Box::new(nks_config.clone())) + .expect("Failed to load RSA key"); + } else { + println!("Failed to downcast to NksConfig"); + } +} + +#[test] +fn test_load_ecdsa_key() { + let mut provider = NksProvider::new("test_key".to_string()); + + provider.config = Some(get_config("ecdsa", None, None).unwrap()); + + provider + .initialize_module() + .expect("Failed to initialize module"); + + if let Some(nks_config) = provider.config.as_ref().unwrap().as_any().downcast_ref::() { + provider + .load_key("test_ecdsa_key", Box::new(nks_config.clone())) + .expect("Failed to load ECDSA key"); + } else { + println!("Failed to downcast to NksConfig"); + } +} + +#[test] +fn test_load_ecdh_key() { + let mut provider = NksProvider::new("test_key".to_string()); + + provider.config = Some(get_config("ecdh", None, None).unwrap()); + + provider + .initialize_module() + .expect("Failed to initialize module"); + + if let Some(nks_config) = provider.config.as_ref().unwrap().as_any().downcast_ref::() { + provider + .load_key("test_ecdh_key", Box::new(nks_config.clone())) + .expect("Failed to load ECDH key"); + } else { + println!("Failed to downcast to NksConfig"); + } +} + +#[test] +fn test_load_aes_key() { + for &key_size in &[KeyBits::Bits128, KeyBits::Bits192, KeyBits::Bits256] { + for &aes_mode in &[SymmetricMode::Gcm, SymmetricMode::Ecb, SymmetricMode::Cbc, SymmetricMode::Ctr, SymmetricMode::Cfb, SymmetricMode::Ofb] { + let mut provider = NksProvider::new("test_key".to_string()); + + provider.config = Some(get_config("aes", Some(key_size), Some(aes_mode)).unwrap()); + + provider + .initialize_module() + .expect("Failed to initialize module"); + + if let Some(nks_config) = provider.config.as_ref().unwrap().as_any().downcast_ref::() { + provider + .load_key(&format!("test_aes_key_{}_{}", aes_mode as u8, key_size as u8), Box::new(nks_config.clone())) + .expect("Failed to load AES key"); + } else { + println!("Failed to downcast to NksConfig"); + } + } + } +} + +/// Returns a configuration object for the NksProvider based on the provided key type. +/// +/// This function creates a new NksConfig object with predefined settings for the +/// asymmetric encryption algorithm, hash algorithm, and key usages. The specific settings +/// are determined by the `key_type` parameter. +/// +/// # Arguments +/// +/// * `key_type` - A string slice that specifies the type of the key. The accepted values are "rsa", "ecdsa", and "ecdh". +/// +/// # Returns +/// +/// An `Option` that, on success, contains an `Arc` to a `ProviderConfig` object. If the `key_type` is not recognized, it returns `None`. +/// +/// # Example +/// +/// ``` +// let config = get_config("rsa").unwrap(); +/// ``` +pub fn get_config(key_type: &str, key_size: Option, aes_mode: Option) -> Option> { + match key_type { + "rsa" => Some(NksConfig::new( + "".to_string(), + "https://localhost:5000/".to_string(), + Option::from(AsymmetricEncryption::Rsa(2048.into())), + Hash::Sha2(256.into()), + vec![ + KeyUsage::ClientAuth, + KeyUsage::Decrypt, + KeyUsage::SignEncrypt, + KeyUsage::CreateX509, + ], + None, + )), + "ecdsa" => Some(NksConfig::new( + "".to_string(), + "https://localhost:5000/".to_string(), + Option::from(AsymmetricEncryption::Ecc(EccSchemeAlgorithm::EcDsa(EccCurves::Curve25519))), + Hash::Sha2(Sha2Bits::Sha256), + vec![KeyUsage::SignEncrypt, KeyUsage::ClientAuth], + None, + )), + "ecdh" => Some(NksConfig::new( + "".to_string(), + "https://localhost:5000/".to_string(), + Option::from(AsymmetricEncryption::Ecc(EccSchemeAlgorithm::EcDh(EccCurves::Curve25519))), + Hash::Sha2(384.into()), + vec![KeyUsage::Decrypt], + None, + )), + "aes" => { + let key_size = key_size.unwrap_or(KeyBits::Bits256); // Default to 256 bits if no size is provided + let aes_mode = aes_mode.unwrap_or(SymmetricMode::Gcm); // Default to GCM mode if no mode is provided + Some(NksConfig::new( + "".to_string(), + "https://localhost:5000/".to_string(), + None, + Hash::Sha2(256.into()), + vec![KeyUsage::Decrypt], + Some(BlockCiphers::Aes(aes_mode, key_size)), + )) + }, + _ => None, + } +} diff --git a/src/tests/tpm/android/mod.rs b/src/tests/tpm/android/mod.rs new file mode 100644 index 00000000..644727a4 --- /dev/null +++ b/src/tests/tpm/android/mod.rs @@ -0,0 +1,643 @@ +use crate::common::crypto::{algorithms, KeyUsage}; +use crate::common::factory::SecModules; +use crate::common::factory::SecurityModule; +use crate::tpm::android::*; +use crate::tpm::core::instance::AndroidTpmType; +use crate::tpm::core::instance::TpmType; +use robusta_jni::convert::IntoJavaValue; + +#[test] +fn initializ_module_test1() { + assert_eq!(true, true); +} + +#[test] +fn initializ_module_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + None, + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider.initialize_module().unwrap(); +} +/* +#[test] +fn key_creation_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("2320").unwrap(); +} + +#[test] +fn key_load_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("2322").unwrap(); + provider.load_key("2322").unwrap(); +} + +/* +----------------TESTING different KeyBits------------------------ +*/ + +#[test] +fn key_creation_bit_128_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits128); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("23128").unwrap(); +} + +#[test] +fn key_creation_bit_192_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits192); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("23192").unwrap(); +} + +#[test] +fn key_creation_bit_256_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits256); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("23256").unwrap(); +} + +#[test] +fn key_creation_bit_512_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits512); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("23512").unwrap(); +} + +#[test] +fn key_creation_bit_1024_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("231024").unwrap(); +} + +#[test] +fn key_creation_bit_2048_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits2048); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("232048").unwrap(); +} + +#[test] +fn key_creation_bit_3072_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits3072); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("233072").unwrap(); +} + +#[test] +fn key_creation_bit_4096_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits4096); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("234096").unwrap(); +} + +#[test] +fn key_creation_bit_8192_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits8192); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("238192").unwrap(); +} + +/* + +---------------------TESTING Hashes------------------- + +*/ + +#[test] +fn key_creation_hash_md2_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Md2; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("231025").unwrap(); +} + +#[test] +fn key_creation_hash_md4_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Md4; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("231026").unwrap(); +} + +#[test] +fn key_creation_hash_md5_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Md5; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("231027").unwrap(); +} + +/* + +------------Testing KeyUsages-------------- + +*/ + +#[test] +fn key_creation_hash_ripemd160_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Ripemd160; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("231028").unwrap(); +} + +#[test] +fn key_creation_keyusage_clientauth_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::ClientAuth]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("231029").unwrap(); +} + +#[test] +fn key_creation_keyusage_decrypt_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::Decrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("231030").unwrap(); +} + +#[test] +fn key_creation_keyusage_createx509_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::CreateX509]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + provider.create_key("231031").unwrap(); +} + +/* + +---------------Sign Data------------------ + +*/ + +#[test] +fn sign_data_1_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + + let data = b"testing"; + + provider.sign_data(data); +} + +#[test] +fn sign_data_2_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + + let data = b"h"; + + provider.sign_data(data); +} + +//How to expect a fail?? +#[test] +fn sign_data_3_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + + let data = b""; + + provider.sign_data(data); +} + +//How to expect a fail?? +#[test] +fn sign_data_4_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + + let data = b"overflowing"; + + provider.sign_data(data); +} + +//Test different Key Ids => 0? + +#[test] +fn verify_signature_1_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + + let data = b"test"; + + let signature = provider.sign_data(data).unwrap(); + + //Convert Vec to list u8 + + let mut signature_list: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; + + for (place, element) in signature_list.iter_mut().zip(signature.into_iter()) { + unsafe { std::ptr::write(place, element) }; + } + let verified = provider + .verify_signature(data, &signature_list) + .unwrap_or_default(); + + assert_eq!(true, verified); +} + +#[test] +fn verify_signature_2_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + + let data = b"testingX"; + + let signature = provider.sign_data(data).unwrap(); + + //Convert Vec to list u8 + + let mut signature_list: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; + + for (place, element) in signature_list.iter_mut().zip(signature.into_iter()) { + unsafe { std::ptr::write(place, element) }; + } + let verified = provider + .verify_signature(data, &signature_list) + .unwrap_or_default(); + + assert_eq!(true, verified); +} + +#[test] +fn verify_signature_3_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + + let data = b"H"; + + let signature = provider.sign_data(data).unwrap(); + + //Convert Vec to list u8 + + let mut signature_list: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; + + for (place, element) in signature_list.iter_mut().zip(signature.into_iter()) { + unsafe { std::ptr::write(place, element) }; + } + let verified = provider + .verify_signature(data, &signature_list) + .unwrap_or_default(); + + assert_eq!(true, verified); +} + +#[test] +fn verify_signature_4_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); + + let data = b""; + + let signature = provider.sign_data(data).unwrap(); + + let mut signature_list: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; + + for (place, element) in signature_list.iter_mut().zip(signature.into_iter()) { + unsafe { std::ptr::write(place, element) }; + } + let verified = provider + .verify_signature(data, &signature_list) + .unwrap_or_default(); + + assert_eq!(false, verified); +} + +#[test] +fn encrypt_data_1_test() { + let security_module = SecModules::get_instance( + "2323".to_string(), + SecurityModule::Tpm(TpmType::Android(AndroidTpmType::Keystore)), + ); + + let x = security_module.unwrap(); + let mut provider = x.lock().unwrap(); + let key_algorithm = + algorithms::encryption::AsymmetricEncryption::Rsa(algorithms::KeyBits::Bits1024); + let hash = algorithms::hashes::Hash::Sha1; + let key_usages = vec![KeyUsage::SignEncrypt]; + provider + .initialize_module(key_algorithm, None, Some(hash), key_usages) + .unwrap(); +} +*/ diff --git a/src/tests/tpm/mod.rs b/src/tests/tpm/mod.rs index 9e77b87c..ac82731e 100644 --- a/src/tests/tpm/mod.rs +++ b/src/tests/tpm/mod.rs @@ -2,3 +2,5 @@ mod linux; #[cfg(feature = "win")] mod win; +#[cfg(feature = "android")] +mod android; diff --git a/src/tpm/android/android_logger.rs b/src/tpm/android/android_logger.rs new file mode 100644 index 00000000..457db609 --- /dev/null +++ b/src/tpm/android/android_logger.rs @@ -0,0 +1,14 @@ +use tracing_subscriber::{layer::SubscriberExt, Registry}; + +use crate::common::traits::log_config::LogConfig; + +#[derive(Debug)] +pub struct DefaultAndroidLogger; + +impl LogConfig for DefaultAndroidLogger { + fn setup_logging(&self) { + let subscriber = Registry::default().with(tracing_android::layer("RUST").unwrap()); + tracing::subscriber::set_global_default(subscriber) + .expect("setting default subscriber failed"); + } +} diff --git a/src/tpm/android/config.rs b/src/tpm/android/config.rs new file mode 100644 index 00000000..98f7d523 --- /dev/null +++ b/src/tpm/android/config.rs @@ -0,0 +1,44 @@ +use std::any::Any; + +use robusta_jni::jni::JavaVM; + +use crate::common::{ + crypto::{ + algorithms::encryption::{AsymmetricEncryption, BlockCiphers}, + algorithms::hashes::Hash, + KeyUsage, + }, + traits::module_provider_config::ProviderConfig, +}; + +#[derive(Debug, Clone, Copy)] +pub enum EncryptionMode { + Sym(BlockCiphers), + ASym { + algo: AsymmetricEncryption, + digest: Hash, + }, +} + +pub struct AndroidConfig { + pub mode: EncryptionMode, + pub key_usages: Vec, + pub hardware_backed: bool, + pub vm: Option, +} + +impl std::fmt::Debug for AndroidConfig { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("AndroidProvider") + .field("mode", &self.mode) + .field("key_usages", &self.key_usages) + .field("hardware_backed", &self.hardware_backed) + .finish() + } +} + +impl ProviderConfig for AndroidConfig { + fn as_any(&self) -> &dyn Any { + self + } +} diff --git a/src/tpm/android/error.rs b/src/tpm/android/error.rs new file mode 100644 index 00000000..92682c07 --- /dev/null +++ b/src/tpm/android/error.rs @@ -0,0 +1,62 @@ +use crate::tpm::core::error::{ToTpmError, TpmError}; + +use super::wrapper; + +#[derive(Debug)] +pub(crate) struct JavaException(String); + +impl std::fmt::Display for JavaException { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Java Exception: {}", self.0) + } +} + +impl std::error::Error for JavaException {} + +/// This allows converting the JNI result into a `TpmError` result. +impl ToTpmError for robusta_jni::jni::errors::Result { + /// Converts the JNI result into a `TpmError` result. + /// If a Java exception was thrown, it retrieves the exception message and puts it into the error. + /// If no exception was thrown, it returns the JNI error as the `TpmError`. + fn err_internal(self) -> Result { + match self { + Ok(v) => Ok(v), + Err(e) => { + // check if a java exception was thrown + let vm = + wrapper::get_java_vm().map_err(|e| TpmError::InternalError(Box::new(e)))?; + let env = vm + .get_env() + .map_err(|e| TpmError::InternalError(Box::new(e)))?; + if env + .exception_check() + .map_err(|e| TpmError::InternalError(Box::new(e)))? + { + // get the exception message and put it into the error + env.exception_describe() + .map_err(|e| TpmError::InternalError(Box::new(e)))?; + let ex = env + .exception_occurred() + .map_err(|e| TpmError::InternalError(Box::new(e)))?; + env.exception_clear() + .map_err(|e| TpmError::InternalError(Box::new(e)))?; + let message = env + .call_method(ex, "getMessage", "()Ljava/lang/String;", &[]) + .and_then(|v| v.l()) + .map_err(|e| TpmError::InternalError(Box::new(e)))?; + + let message = env + .get_string(Into::into(message)) + .map_err(|e| TpmError::InternalError(Box::new(e)))? + .to_str() + .map_err(|e| TpmError::InternalError(Box::new(e)))? + .to_string(); + Err(TpmError::InternalError(Box::new(JavaException(message)))) + } else { + // there was no exception, return the jni error + Err(TpmError::InternalError(Box::new(e))) + } + } + } + } +} diff --git a/src/tpm/android/mod.rs b/src/tpm/android/mod.rs index 07d47505..f79a155d 100644 --- a/src/tpm/android/mod.rs +++ b/src/tpm/android/mod.rs @@ -1 +1,580 @@ +pub mod android_logger; +pub mod config; +pub(crate) mod error; pub mod knox; +pub(crate) mod utils; +pub(crate) mod wrapper; + +use std::any::Any; + +use robusta_jni::jni::objects::JObject; +use tracing::{debug, info, instrument}; +use utils::{ + get_algorithm, get_cipher_mode, get_digest, get_iv_len, get_key_size, get_padding, + get_signature_algorithm, get_signature_padding, get_sym_block_mode, load_iv, store_iv, +}; +use wrapper::key_generation::iv_parameter_spec::jni::IvParameterSpec; + +use crate::common::crypto::KeyUsage; +use crate::common::error::SecurityModuleError; +use crate::common::traits::key_handle::KeyHandle; +use crate::common::{ + crypto::algorithms::encryption::{AsymmetricEncryption, BlockCiphers}, + traits::module_provider::Provider, +}; +use crate::tpm::android::config::AndroidConfig; +use crate::tpm::android::wrapper::key_store::key_store::jni::KeyStore; +use crate::tpm::android::wrapper::key_store::signature::jni::Signature; +use crate::tpm::core::error::ToTpmError; +use crate::tpm::core::error::TpmError; + +const ANDROID_KEYSTORE: &str = "AndroidKeyStore"; + +/// A TPM-based cryptographic provider for managing cryptographic keys and performing +/// cryptographic operations in an Android environment. +/// +/// This provider uses the Android Keystore API to interact +/// with the Trusted Execution Environment (TEE), or the devices Secure Element(Like the Titan M chip in a Google Pixel) +/// for operations like signing, encryption, and decryption. +/// It provides a secure and hardware-backed solution for managing cryptographic keys and performing +/// cryptographic operations on Android. +#[derive(Debug)] +pub(crate) struct AndroidProvider { + key_id: String, + config: Option, +} + +impl AndroidProvider { + /// Constructs a new `AndroidProvider`. + /// + /// # Arguments + /// + /// * `key_id` - A string identifier for the cryptographic key to be managed by this provider. + /// * `config` - Configuration + /// + /// # Returns + /// + /// A new instance of `AndroidProvider` with the specified `key_id`. + #[instrument] + pub fn new(key_id: String) -> Self { + Self { + key_id, + config: None, + } + } + + fn apply_config(&mut self, config: AndroidConfig) -> Result<(), SecurityModuleError> { + // TODO: verify config + self.config = Some(config); + Ok(()) + } +} + +/// Implementation of the `Provider` trait for the Android platform. +/// +/// This struct provides methods for key generation, key loading, and module initialization +/// specific to Android. +impl Provider for AndroidProvider { + /// Generates a key with the parameters specified when the module was initialized. + /// + /// The key is generated using the Android Keystore API and is stored securely in the device's + /// Trusted Execution Environment (TEE) or Secure Element. It first attempts to generate a key + /// withing the devices StrongBox (Secure Element), and if that fails, because it is not available, + /// it falls back to the TEE. We have to do this because the KeyStore does not automatically select + /// the highest security level available. + /// + /// # Java Example + /// + /// ```java + /// KeyPairGenerator kpg = KeyPairGenerator.getInstance( + /// KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore"); + /// kpg.initialize(new KeyGenParameterSpec.Builder( + /// alias, + /// KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) + /// .setDigests(KeyProperties.DIGEST_SHA256, + /// KeyProperties.DIGEST_SHA512) + /// .build()); + /// KeyPair kp = kpg.generateKeyPair(); + /// ``` + /// + /// # Arguments + /// + /// * `key_id` - The identifier for the key. + /// + /// # Returns + /// + /// Returns `Ok(())` if the key generation is successful, otherwise returns an error of type `SecurityModuleError`. + #[instrument] + fn create_key( + &mut self, + key_id: &str, + config: Box, + ) -> Result<(), SecurityModuleError> { + info!("generating key! {}", key_id); + + // load config + let config = *config + .downcast::() + .map_err(|_| SecurityModuleError::InitializationError("Wrong Config".to_owned()))?; + + let env = config + .vm + .as_ref() + .expect("cannot happen, already checked") + .get_env() + .map_err(|_| { + TpmError::InitializationError( + "Could not get java environment, this should never happen".to_owned(), + ) + })?; + + // build up key specs + let mut kps_builder = + wrapper::key_generation::builder::Builder::new(&env, key_id.to_owned(), 1 | 2 | 4 | 8) + .err_internal()?; + + match config.mode { + config::EncryptionMode::Sym(cipher) => { + match cipher { + BlockCiphers::Aes(mode, size) => { + kps_builder = kps_builder + .set_block_modes(&env, vec![get_sym_block_mode(mode)?]) + .err_internal()? + .set_encryption_paddings(&env, vec![get_padding(config.mode)?]) + .err_internal()? + .set_key_size(&env, Into::::into(size) as i32) + .err_internal()?; + } + BlockCiphers::Des => { + kps_builder = kps_builder + .set_block_modes(&env, vec!["CBC".to_owned()]) + .err_internal()? + .set_encryption_paddings(&env, vec![get_padding(config.mode)?]) + .err_internal()?; + } + BlockCiphers::TripleDes(_) + | BlockCiphers::Rc2(_) + | BlockCiphers::Camellia(_, _) => { + Err(TpmError::UnsupportedOperation("not supported".to_owned()))? + } + }; + kps_builder = kps_builder + .set_is_strongbox_backed(&env, config.hardware_backed) + .err_internal()?; + + let kps = kps_builder.build(&env).err_internal()?; + + let kg = wrapper::key_generation::key_generator::jni::KeyGenerator::getInstance( + &env, + get_algorithm(config.mode)?, + ANDROID_KEYSTORE.to_owned(), + ) + .err_internal()?; + kg.init(&env, kps.raw.as_obj()).err_internal()?; + + kg.generateKey(&env).err_internal()?; + } + config::EncryptionMode::ASym { algo, digest } => { + match algo { + AsymmetricEncryption::Rsa(_key_bits) => { + kps_builder = kps_builder + .set_digests(&env, vec![get_digest(digest)?]) + .err_internal()? + .set_signature_paddings(&env, vec![get_signature_padding()?]) + .err_internal()? + .set_encryption_paddings(&env, vec![get_padding(config.mode)?]) + .err_internal()? + .set_key_size(&env, get_key_size(algo)? as i32) + .err_internal()?; + } + AsymmetricEncryption::Ecc(_scheme) => { + kps_builder = kps_builder + .set_digests(&env, vec![get_digest(digest)?]) + .err_internal()?; + } + }; + kps_builder = kps_builder + .set_is_strongbox_backed(&env, config.hardware_backed) + .err_internal()?; + + let kps = kps_builder.build(&env).err_internal()?; + + let kpg = wrapper::key_generation::key_pair_generator::jni::KeyPairGenerator::getInstance( + &env, + get_algorithm(config.mode)?, + ANDROID_KEYSTORE.to_owned(), + ) + .err_internal()?; + + kpg.initialize(&env, kps.raw.as_obj()).err_internal()?; + + kpg.generateKeyPair(&env).err_internal()?; + } + } + + debug!("key generated"); + self.apply_config(config)?; + + Ok(()) + } + + /// Loads a key with the specified `key_id`. + /// + /// # Arguments + /// + /// * `key_id` - The identifier for the key. + /// + /// # Returns + /// + /// Returns `Ok(())` if the key loading is successful, otherwise returns an error of type `SecurityModuleError`. + #[instrument] + fn load_key(&mut self, key_id: &str, config: Box) -> Result<(), SecurityModuleError> { + key_id.clone_into(&mut self.key_id); + + // load config + let config = *config + .downcast::() + .map_err(|_| SecurityModuleError::InitializationError("Wrong Config".to_owned()))?; + self.apply_config(config)?; + + Ok(()) + } + + /// Initializes the module with the specified parameters. + /// + /// # Arguments + /// + /// * `key_algorithm` - The asymmetric encryption algorithm to be used. + /// * `sym_algorithm` - The block cipher algorithm to be used (optional). + /// * `hash` - The hash algorithm to be used (optional). + /// * `key_usages` - The list of key usages. + /// + /// # Returns + /// + /// Returns `Ok(())` if the module initialization is successful, otherwise returns an error of type `SecurityModuleError`. + #[instrument] + fn initialize_module(&mut self) -> Result<(), SecurityModuleError> { + Ok(()) + } +} + +/// Implementation of the `KeyHandle` trait for the `AndroidProvider` struct. +/// All of the functions in this KeyHandle are basically re-implementations +/// of the equivalent Java functions in the Android KeyStore API. +impl KeyHandle for AndroidProvider { + /// Signs the given data using the Android KeyStore. + /// + /// # Arguments + /// + /// * `data` - Byte array of data to be signed. + /// + /// # Java Example + /// + /// ```java + /// KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); + /// ks.load(null); + /// KeyStore.Entry entry = ks.getEntry(alias, null); + /// if (!(entry instanceof PrivateKeyEntry)) { + /// Log.w(TAG, "Not an instance of a PrivateKeyEntry"); + /// return null; + /// } + /// Signature s = Signature.getInstance("SHA256withECDSA"); + /// s.initSign(((PrivateKeyEntry) entry).getPrivateKey()); + /// s.update(data); + /// byte[] signature = s.sign(); + /// ``` + /// + /// # Returns + /// + /// Returns a `Result` containing the signed data as a `Vec` if successful, or a `SecurityModuleError` if an error occurs. + #[instrument] + fn sign_data(&self, data: &[u8]) -> Result, SecurityModuleError> { + // check that signing is allowed + let config = self + .config + .as_ref() + .ok_or(SecurityModuleError::InitializationError( + "Module is not initialized".to_owned(), + ))?; + + if !config.key_usages.contains(&KeyUsage::SignEncrypt) { + return Err(TpmError::UnsupportedOperation( + "KeyUsage::SignEncrypt was not provided".to_owned(), + ) + .into()); + } + + let env = config + .vm + .as_ref() + .ok_or_else(|| TpmError::InitializationError("Module is not initialized".to_owned()))? + .get_env() + .map_err(|_| { + TpmError::InitializationError( + "Could not get java environment, this should never happen".to_owned(), + ) + })?; + + let key_store = KeyStore::getInstance(&env, ANDROID_KEYSTORE.to_string()).err_internal()?; + key_store.load(&env, None).err_internal()?; + + let private_key = key_store + .getKey(&env, self.key_id.clone(), JObject::null()) + .err_internal()?; + + let signature_algorithm = get_signature_algorithm(config.mode)?; + debug!("Signature Algorithm: {}", signature_algorithm); + + let s = Signature::getInstance(&env, signature_algorithm.to_string()).err_internal()?; + + s.initSign(&env, private_key.raw.as_obj()).err_internal()?; + + let data_bytes = data.to_vec().into_boxed_slice(); + + s.update(&env, data_bytes).err_internal()?; + debug!("Signature Init: {}", s.toString(&env).unwrap()); + + let output = s.sign(&env).err_internal()?; + + Ok(output) + } + + /// Decrypts the given encrypted data using the Android KeyStore. + /// + /// # Arguments + /// + /// * `encrypted_data` - The encrypted data to be decrypted. + /// + /// # Java Example + /// + /// ```java + /// KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE); + /// keyStore.load(null); + /// PrivateKey privateKey = (PrivateKey) keyStore.getKey(KEYNAME, null); + /// PublicKey publicKey = keyStore.getCertificate(KEYNAME).getPublicKey(); + /// Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + /// cipher.init(Cipher.DECRYPT_MODE, privateKey); + /// byte[] decrypted = cipher.doFinal(encrypted); + /// ``` + /// + /// # Returns + /// + /// Returns a `Result` containing the decrypted data as a `Vec` if successful, or a `SecurityModuleError` if an error occurs. + #[instrument] + fn decrypt_data(&self, encrypted_data: &[u8]) -> Result, SecurityModuleError> { + info!("decrypting data"); + + let config = self + .config + .as_ref() + .ok_or(SecurityModuleError::InitializationError( + "Module is not initialized".to_owned(), + ))?; + + let env = config + .vm + .as_ref() + .ok_or_else(|| TpmError::InitializationError("Module is not initialized".to_owned()))? + .get_env() + .map_err(|_| { + TpmError::InitializationError( + "Could not get java environment, this should never happen".to_owned(), + ) + })?; + + let cipher_mode = get_cipher_mode(config.mode)?; + + let key_store = KeyStore::getInstance(&env, ANDROID_KEYSTORE.to_owned()).err_internal()?; + key_store.load(&env, None).err_internal()?; + + let cipher = wrapper::key_store::cipher::jni::Cipher::getInstance(&env, cipher_mode) + .err_internal()?; + + let decrypted = match config.mode { + config::EncryptionMode::Sym(cipher_mode) => { + let key = key_store + .getKey(&env, self.key_id.to_owned(), JObject::null()) + .err_internal()?; + + let (data, iv) = load_iv(encrypted_data, get_iv_len(cipher_mode)?); + let iv_spec = IvParameterSpec::new(&env, &iv).err_internal()?; + cipher + .init2(&env, 2, key, iv_spec.raw.as_obj()) + .err_internal()?; + + cipher.doFinal(&env, data).err_internal()? + } + config::EncryptionMode::ASym { algo: _, digest: _ } => { + let key = key_store + .getCertificate(&env, self.key_id.to_owned()) + .err_internal()? + .getPublicKey(&env) + .err_internal()?; + cipher.init(&env, 2, key.raw.as_obj()).err_internal()?; + + cipher + .doFinal(&env, encrypted_data.to_vec()) + .err_internal()? + } + }; + + debug!("decrypted data: {:?}", decrypted); + Ok(decrypted) + } + + /// Encrypts the given data using the Android KeyStore. + /// + /// # Arguments + /// + /// * `data` - The data to be encrypted. + /// + /// # Java Example + /// + /// ```java + /// KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE); + /// keyStore.load(null); + /// PrivateKey privateKey = (PrivateKey) keyStore.getKey(KEYNAME, null); + /// PublicKey publicKey = keyStore.getCertificate(KEYNAME).getPublicKey(); + /// Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + /// byte[] encrypted; + /// cipher.init(Cipher.ENCRYPT_MODE, publicKey); + /// encrypted = cipher.doFinal(text.getBytes()); + /// ``` + /// + /// # Returns + /// + /// Returns a `Result` containing the encrypted data as a `Vec` if successful, or a `SecurityModuleError` if an error occurs. + #[instrument] + fn encrypt_data(&self, data: &[u8]) -> Result, SecurityModuleError> { + info!("encrypting"); + + let config = self + .config + .as_ref() + .ok_or(SecurityModuleError::InitializationError( + "Module is not initialized".to_owned(), + ))?; + + let env = config + .vm + .as_ref() + .ok_or_else(|| TpmError::InitializationError("Module is not initialized".to_owned()))? + .get_env() + .map_err(|_| { + TpmError::InitializationError( + "Could not get java environment, this should never happen".to_owned(), + ) + })?; + + info!("before getInstance"); + + let key_store = KeyStore::getInstance(&env, ANDROID_KEYSTORE.to_owned()).err_internal()?; + info!("after getInstance"); + key_store.load(&env, None).err_internal()?; + info!("after load"); + + let cipher = wrapper::key_store::cipher::jni::Cipher::getInstance( + &env, + get_cipher_mode(config.mode)?, + ) + .err_internal()?; + + // symetric encryption needs an IV + let encrypted = match config.mode { + config::EncryptionMode::Sym(_) => { + let key = key_store + .getKey(&env, self.key_id.to_owned(), JObject::null()) + .err_internal()?; + cipher.init(&env, 1, key.raw.as_obj()).err_internal()?; + let iv = cipher.getIV(&env).err_internal()?; + let encrypted = cipher.doFinal(&env, data.to_vec()).err_internal()?; + store_iv(encrypted, iv) + } + config::EncryptionMode::ASym { algo: _, digest: _ } => { + let key = key_store + .getCertificate(&env, self.key_id.to_owned()) + .err_internal()? + .getPublicKey(&env) + .err_internal()?; + cipher.init(&env, 1, key.raw.as_obj()).err_internal()?; + cipher.doFinal(&env, data.to_vec()).err_internal()? + } + }; + + debug!("encrypted: {:?}", encrypted); + Ok(encrypted) + } + + /// Verifies the signature of the given data using the Android KeyStore. + /// + /// # Arguments + /// + /// * `data` - The data whose signature needs to be verified. + /// * `signature` - The signature to be verified. + /// + /// # Java Example + /// + /// ```java + /// KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); + /// ks.load(null); + /// KeyStore.Entry entry = ks.getEntry(alias, null); + /// if (!(entry instanceof PrivateKeyEntry)) { + /// Log.w(TAG, "Not an instance of a PrivateKeyEntry"); + /// return false; + /// } + /// Signature s = Signature.getInstance("SHA256withECDSA"); + /// s.initVerify(((PrivateKeyEntry) entry).getCertificate()); + /// s.update(data); + /// boolean valid = s.verify(signature); + /// ``` + /// + /// # Returns + /// + /// Returns a `Result` containing `true` if the signature is valid, `false` otherwise, or a `SecurityModuleError` if an error occurs. + #[instrument] + fn verify_signature(&self, data: &[u8], signature: &[u8]) -> Result { + info!("verifiying"); + + let config = self + .config + .as_ref() + .ok_or(SecurityModuleError::InitializationError( + "Module is not initialized".to_owned(), + ))?; + + let env = config + .vm + .as_ref() + .ok_or_else(|| TpmError::InitializationError("Module is not initialized".to_owned()))? + .get_env() + .map_err(|_| { + TpmError::InitializationError( + "Could not get java environment, this should never happen".to_owned(), + ) + })?; + + let key_store = KeyStore::getInstance(&env, ANDROID_KEYSTORE.to_string()).err_internal()?; + key_store.load(&env, None).err_internal()?; + + let signature_algorithm = get_signature_algorithm(config.mode)?; + debug!("Signature Algorithm: {}", signature_algorithm); + + let s = Signature::getInstance(&env, signature_algorithm.to_string()).err_internal()?; + + let cert = key_store + .getCertificate(&env, self.key_id.clone()) + .err_internal()?; + + s.initVerify(&env, cert).err_internal()?; + debug!("Signature Init: {}", s.toString(&env).unwrap()); + + let data_bytes = data.to_vec().into_boxed_slice(); + s.update(&env, data_bytes).err_internal()?; + + let signature_boxed = signature.to_vec().into_boxed_slice(); + let output = s.verify(&env, signature_boxed).err_internal()?; + debug!("Signature verified: {:?}", output); + + Ok(output) + } +} diff --git a/src/tpm/android/utils.rs b/src/tpm/android/utils.rs new file mode 100644 index 00000000..c13d8bef --- /dev/null +++ b/src/tpm/android/utils.rs @@ -0,0 +1,227 @@ +#![allow(dead_code)] + +use crate::{ + common::{ + crypto::algorithms::{ + encryption::{AsymmetricEncryption, BlockCiphers, SymmetricMode}, + hashes::{Hash, Sha2Bits}, + }, + error::SecurityModuleError, + }, + tpm::core::error::TpmError, +}; + +use super::config::EncryptionMode; + +pub fn get_algorithm(enc: EncryptionMode) -> Result { + Ok(match enc { + EncryptionMode::Sym(algo) => match algo { + BlockCiphers::Aes(_, _) => "AES", + BlockCiphers::TripleDes(_) => "DESede", + BlockCiphers::Des | BlockCiphers::Rc2(_) | BlockCiphers::Camellia(_, _) => { + Err(TpmError::UnsupportedOperation("not supported".to_owned()))? + } + }, + EncryptionMode::ASym { algo, digest: _ } => match algo { + AsymmetricEncryption::Rsa(_) => "RSA", + AsymmetricEncryption::Ecc(_) => "EC", + }, + } + .to_owned()) +} + +pub fn get_cipher_mode(e_mode: EncryptionMode) -> Result { + match e_mode { + EncryptionMode::Sym(cipher) => match cipher { + BlockCiphers::Aes(mode, _) => Ok(format!( + "AES/{}/{}", + get_sym_block_mode(mode)?, + get_padding(e_mode)? + )), + BlockCiphers::TripleDes(_) => { + Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + BlockCiphers::Des => Ok("DES".to_owned()), + BlockCiphers::Rc2(_) => { + Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + BlockCiphers::Camellia(_, _) => { + Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + }, + EncryptionMode::ASym { algo, digest: _ } => match algo { + AsymmetricEncryption::Rsa(_) => Ok(format!("RSA/ECB/{}", get_padding(e_mode)?)), + AsymmetricEncryption::Ecc(_) => { + Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + }, + } +} + +pub fn get_sym_block_mode(mode: SymmetricMode) -> Result { + Ok(match mode { + SymmetricMode::Gcm => "GCM", + SymmetricMode::Ecb => "ECB", + SymmetricMode::Cbc => "CBC", + SymmetricMode::Ctr => "CTR", + SymmetricMode::Cfb | SymmetricMode::Ofb | SymmetricMode::Ccm => { + Err(TpmError::UnsupportedOperation( + "Only GCM, ECB, CBC and CTR as blockmodes supported".to_owned(), + ))? + } + } + .to_owned()) +} + +pub fn get_padding(mode: EncryptionMode) -> Result { + Ok(match mode { + EncryptionMode::Sym(BlockCiphers::Aes(_, _)) => "PKCS7Padding", + EncryptionMode::ASym { algo: _, digest: _ } => "PKCS1Padding", + _ => "NoPadding", + } + .to_owned()) +} + +pub fn get_signature_padding() -> Result { + Ok("PKCS1".to_owned()) +} + +pub fn get_digest(digest: Hash) -> Result { + match digest { + Hash::Sha1 => Ok("SHA-1".to_owned()), + Hash::Sha2(size) => match size { + Sha2Bits::Sha224 => Ok("SHA-224".to_owned()), + Sha2Bits::Sha256 => Ok("SHA-256".to_owned()), + Sha2Bits::Sha384 => Ok("SHA-384".to_owned()), + Sha2Bits::Sha512 => Ok("SHA-512".to_owned()), + Sha2Bits::Sha512_224 | Sha2Bits::Sha512_256 => { + Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + }, + Hash::Md5 => Ok("MD5".to_owned()), + Hash::Sha3(_) | Hash::Md2 | Hash::Md4 | Hash::Ripemd160 => { + Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + } +} + +pub fn get_hash_name(hash: Hash) -> Result { + match hash { + Hash::Sha1 => Ok("SHA1".to_owned()), + Hash::Sha2(size) => match size { + Sha2Bits::Sha224 => Ok("SHA224".to_owned()), + Sha2Bits::Sha256 => Ok("SHA256".to_owned()), + Sha2Bits::Sha384 => Ok("SHA384".to_owned()), + Sha2Bits::Sha512 => Ok("SHA512".to_owned()), + Sha2Bits::Sha512_224 | Sha2Bits::Sha512_256 => { + Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + }, + Hash::Md5 => Ok("MD5".to_owned()), + Hash::Sha3(_) | Hash::Md2 | Hash::Md4 | Hash::Ripemd160 => { + Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + } +} + +pub fn get_key_size(algo: AsymmetricEncryption) -> Result { + match algo { + AsymmetricEncryption::Rsa(size) => Ok(Into::::into(size)), + AsymmetricEncryption::Ecc(_) => { + Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + } +} + +pub fn get_curve(algo: AsymmetricEncryption) -> Result { + match algo { + AsymmetricEncryption::Rsa(_) => { + Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + AsymmetricEncryption::Ecc(scheme) => { + let curve = match scheme { + crate::common::crypto::algorithms::encryption::EccSchemeAlgorithm::EcDsa(v) => v, + crate::common::crypto::algorithms::encryption::EccSchemeAlgorithm::EcDh(v) => v, + crate::common::crypto::algorithms::encryption::EccSchemeAlgorithm::EcDaa(v) => v, + crate::common::crypto::algorithms::encryption::EccSchemeAlgorithm::Sm2(v) => v, + crate::common::crypto::algorithms::encryption::EccSchemeAlgorithm::EcSchnorr(v) => { + v + } + crate::common::crypto::algorithms::encryption::EccSchemeAlgorithm::EcMqv(v) => v, + crate::common::crypto::algorithms::encryption::EccSchemeAlgorithm::Null => { + return Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + }; + Ok(match curve { + crate::common::crypto::algorithms::encryption::EccCurves::P256 => "secp256r1", + crate::common::crypto::algorithms::encryption::EccCurves::P384 => "secp384r1", + crate::common::crypto::algorithms::encryption::EccCurves::P521 => "secp521r1", + crate::common::crypto::algorithms::encryption::EccCurves::Secp256k1 => "secp256k1", + crate::common::crypto::algorithms::encryption::EccCurves::BrainpoolP256r1 => { + "brainpoolP256r1" + } + crate::common::crypto::algorithms::encryption::EccCurves::BrainpoolP384r1 => { + "brainpoolP384r1" + } + crate::common::crypto::algorithms::encryption::EccCurves::BrainpoolP512r1 => { + "brainpoolP512r1" + } + crate::common::crypto::algorithms::encryption::EccCurves::BrainpoolP638 => { + return Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + crate::common::crypto::algorithms::encryption::EccCurves::Curve25519 => "X25519", + crate::common::crypto::algorithms::encryption::EccCurves::Curve448 => "X448", + crate::common::crypto::algorithms::encryption::EccCurves::Frp256v1 => { + return Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + } + .to_owned()) + } + } +} + +pub fn get_signature_algorithm(mode: EncryptionMode) -> Result { + match mode { + EncryptionMode::Sym(_) => { + Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + EncryptionMode::ASym { algo, digest } => { + let part1 = match algo { + AsymmetricEncryption::Rsa(_) => "RSA", + AsymmetricEncryption::Ecc(_) => "ECDSA", + }; + let part2 = get_hash_name(digest)?; + + Ok(format!("{part2}with{part1}")) + } + } +} + +pub fn get_iv_len(cipher: BlockCiphers) -> Result { + Ok(match cipher { + BlockCiphers::Aes(mode, _) => match mode { + SymmetricMode::Gcm => 12, + SymmetricMode::Ccm => 16, + SymmetricMode::Ecb => 16, + SymmetricMode::Cbc => 16, + SymmetricMode::Cfb => 16, + SymmetricMode::Ofb => 16, + SymmetricMode::Ctr => 16, + }, + BlockCiphers::TripleDes(_) => 8, + BlockCiphers::Des | BlockCiphers::Rc2(_) | BlockCiphers::Camellia(_, _) => { + return Err(TpmError::UnsupportedOperation("not supported".to_owned()).into()) + } + }) +} + +pub fn store_iv(mut data: Vec, mut iv: Vec) -> Vec { + iv.append(&mut data); + iv +} + +pub fn load_iv(data: &[u8], iv_size: usize) -> (Vec, Vec) { + let iv = Vec::from(&data[0..iv_size]); + let data = Vec::from(&data[iv_size..]); + (data, iv) +} diff --git a/src/tpm/android/wrapper/key_generation/builder.rs b/src/tpm/android/wrapper/key_generation/builder.rs new file mode 100644 index 00000000..55bbe54b --- /dev/null +++ b/src/tpm/android/wrapper/key_generation/builder.rs @@ -0,0 +1,276 @@ +use crate::tpm::android::wrapper::key_generation::key_gen_parameter_spec::jni::KeyGenParameterSpec; + +use robusta_jni::jni::errors::Result as JniResult; +use robusta_jni::jni::objects::{AutoLocal, JObject, JValue}; +use robusta_jni::jni::sys::jsize; +use robusta_jni::jni::JNIEnv; + +/// Builder for creating `KeyGenParameterSpec` objects. +/// This class is an inner class of `KeyGenParameterSpec`. For that reason, it could not +/// be implemented using the help of `robusta_jni`. `robusta_jni` does not support inner classes. +pub struct Builder<'env: 'borrow, 'borrow> { + raw: AutoLocal<'env, 'borrow>, +} + +impl<'env: 'borrow, 'borrow> Builder<'env, 'borrow> { + /// Creates a new `Builder` instance. + /// + /// # Arguments + /// + /// * `env` - The JNI environment. + /// * `keystore_alias` - The alias for the keystore. + /// * `purposes` - The purposes for which the key can be used. + /// + /// # Returns + /// + /// A `JniResult` containing the new `Builder` instance. + pub fn new( + env: &'borrow JNIEnv<'env>, + keystore_alias: String, + purposes: i32, + ) -> JniResult { + let class = env.find_class("android/security/keystore/KeyGenParameterSpec$Builder")?; + let jstring_keystore_alias = env.new_string(keystore_alias)?; + let args = [Into::into(jstring_keystore_alias), JValue::from(purposes)]; + let obj = env.new_object(class, "(Ljava/lang/String;I)V", &args)?; + Ok(Self { + raw: AutoLocal::new(env, Into::::into(obj)), + }) + } + + /// Sets the digests for the key. + /// + /// # Arguments + /// + /// * `self` - The `Builder` instance. + /// * `env` - The JNI environment. + /// * `digests` - The digests to set. + /// + /// # Returns + /// + /// A `JniResult` containing the updated `Builder` instance. + pub fn set_digests( + mut self, + env: &'borrow JNIEnv<'env>, + digests: Vec, + ) -> JniResult { + let string_class = env.find_class("java/lang/String")?; + let digest_array = + env.new_object_array(digests.len() as jsize, string_class, JObject::null())?; + for (i, digest) in digests.iter().enumerate() { + let jstring_digest = env.new_string(digest)?; + env.set_object_array_element(digest_array, i as jsize, jstring_digest)?; + } + + let result = env.call_method( + self.raw.as_obj(), + "setDigests", + "([Ljava/lang/String;)Landroid/security/keystore/KeyGenParameterSpec$Builder;", + &[digest_array.into()], + )?; + self.raw = AutoLocal::new(env, result.l()?); + Ok(self) + } + + /// Sets the encryption paddings for the key. + /// + /// # Arguments + /// + /// * `self` - The `Builder` instance. + /// * `env` - The JNI environment. + /// * `paddings` - The encryption paddings to set. + /// + /// # Returns + /// + /// A `JniResult` containing the updated `Builder` instance. + pub fn set_encryption_paddings( + mut self, + env: &'borrow JNIEnv<'env>, + paddings: Vec, + ) -> JniResult { + let string_class = env.find_class("java/lang/String")?; + let padding_array = + env.new_object_array(paddings.len() as jsize, string_class, JObject::null())?; + for (i, padding) in paddings.iter().enumerate() { + let jstring_padding = env.new_string(padding)?; + env.set_object_array_element(padding_array, i as jsize, jstring_padding)?; + } + + let result = env.call_method( + self.raw.as_obj(), + "setEncryptionPaddings", + "([Ljava/lang/String;)Landroid/security/keystore/KeyGenParameterSpec$Builder;", + &[padding_array.into()], + )?; + self.raw = AutoLocal::new(env, result.l()?); + Ok(self) + } + + /// Sets the signature paddings for the key. + /// + /// # Arguments + /// + /// * `self` - The `Builder` instance. + /// * `env` - The JNI environment. + /// * `paddings` - The signature paddings to set. + /// + /// # Returns + /// + /// A `JniResult` containing the updated `Builder` instance. + pub fn set_signature_paddings( + mut self, + env: &'borrow JNIEnv<'env>, + paddings: Vec, + ) -> JniResult { + let string_class = env.find_class("java/lang/String")?; + let padding_array = + env.new_object_array(paddings.len() as jsize, string_class, JObject::null())?; + for (i, padding) in paddings.iter().enumerate() { + let jstring_padding = env.new_string(padding)?; + env.set_object_array_element(padding_array, i as jsize, jstring_padding)?; + } + + let result = env.call_method( + self.raw.as_obj(), + "setSignaturePaddings", + "([Ljava/lang/String;)Landroid/security/keystore/KeyGenParameterSpec$Builder;", + &[padding_array.into()], + )?; + self.raw = AutoLocal::new(env, result.l()?); + Ok(self) + } + + /// Sets the block modes for the key. + /// + /// # Arguments + /// + /// * `self` - The `Builder` instance. + /// * `env` - The JNI environment. + /// * `block_modes` - The block modes to set. + /// + /// # Returns + /// + /// A `JniResult` containing the updated `Builder` instance. + pub fn set_block_modes( + mut self, + env: &'borrow JNIEnv<'env>, + block_modes: Vec, + ) -> JniResult { + let string_class = env.find_class("java/lang/String")?; + let block_mode_array = + env.new_object_array(block_modes.len() as jsize, string_class, JObject::null())?; + for (i, block_mode) in block_modes.iter().enumerate() { + let jstring_block_mode = env.new_string(block_mode)?; + env.set_object_array_element(block_mode_array, i as jsize, jstring_block_mode)?; + } + + let result = env.call_method( + self.raw.as_obj(), + "setBlockModes", + "([Ljava/lang/String;)Landroid/security/keystore/KeyGenParameterSpec$Builder;", + &[block_mode_array.into()], + )?; + self.raw = AutoLocal::new(env, result.l()?); + Ok(self) + } + + /// Sets the key size for the key. + /// + /// # Arguments + /// + /// * `self` - The `Builder` instance. + /// * `env` - The JNI environment. + /// * `key_size` - The key size to set. + /// + /// # Returns + /// + /// A `JniResult` containing the updated `Builder` instance. + pub fn set_key_size(mut self, env: &'borrow JNIEnv<'env>, key_size: i32) -> JniResult { + let result = env.call_method( + self.raw.as_obj(), + "setKeySize", + "(I)Landroid/security/keystore/KeyGenParameterSpec$Builder;", + &[JValue::Int(key_size)], + )?; + self.raw = AutoLocal::new(env, result.l()?); + Ok(self) + } + + /// Sets the algorithm parameter specification for the key. + /// + /// # Arguments + /// + /// * `self` - The `Builder` instance. + /// * `env` - The JNI environment. + /// * `spec` - The algorithm parameter specification to set. + /// + /// # Returns + /// + /// A `JniResult` containing the updated `Builder` instance. + #[allow(dead_code)] + pub fn set_algorithm_parameter_spec( + mut self, + env: &'borrow JNIEnv<'env>, + spec: JObject, + ) -> JniResult { + let result = env.call_method( + self.raw.as_obj(), + "setAlgorithmParameterSpec", + "(Ljavax/crypto/spec/AlgorithmParameterSpec;)Landroid/security/keystore/KeyGenParameterSpec$Builder;", + &[JValue::Object(spec)], + )?; + self.raw = AutoLocal::new(env, result.l()?); + Ok(self) + } + + /// Sets whether the key is backed by a strongbox. + /// + /// # Arguments + /// + /// * `self` - The `Builder` instance. + /// * `env` - The JNI environment. + /// * `is_strongbox_backed` - Whether the key is strongbox backed. + /// + /// # Returns + /// + /// A `JniResult` containing the updated `Builder` instance. + pub fn set_is_strongbox_backed( + mut self, + env: &'borrow JNIEnv<'env>, + is_strongbox_backed: bool, + ) -> JniResult { + let result = env.call_method( + self.raw.as_obj(), + "setIsStrongBoxBacked", + "(Z)Landroid/security/keystore/KeyGenParameterSpec$Builder;", + &[JValue::Bool(is_strongbox_backed.into())], + )?; + self.raw = AutoLocal::new(env, result.l()?); + Ok(self) + } + + /// Builds the `KeyGenParameterSpec` object. + /// + /// # Arguments + /// + /// * `self` - The `Builder` instance. + /// * `env` - The JNI environment. + /// + /// # Returns + /// + /// A `JniResult` containing the built `KeyGenParameterSpec` object. + pub fn build( + self, + env: &'borrow JNIEnv<'env>, + ) -> JniResult> { + let result = env.call_method( + self.raw.as_obj(), + "build", + "()Landroid/security/keystore/KeyGenParameterSpec;", + &[], + )?; + Ok(KeyGenParameterSpec { + raw: AutoLocal::new(env, result.l()?), + }) + } +} diff --git a/src/tpm/android/wrapper/key_generation/iv_parameter_spec.rs b/src/tpm/android/wrapper/key_generation/iv_parameter_spec.rs new file mode 100644 index 00000000..f529d48f --- /dev/null +++ b/src/tpm/android/wrapper/key_generation/iv_parameter_spec.rs @@ -0,0 +1,42 @@ +use robusta_jni::bridge; + +#[bridge] +pub mod jni { + use robusta_jni::jni::errors::Result as JniResult; + use robusta_jni::{ + convert::{IntoJavaValue, Signature, TryFromJavaValue, TryIntoJavaValue}, + jni::{ + objects::{AutoLocal, JObject}, + JNIEnv, + }, + }; + + #[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(javax.crypto.spec)] + pub struct IvParameterSpec<'env: 'borrow, 'borrow> { + #[instance] + pub raw: AutoLocal<'env, 'borrow>, + } + + impl<'env: 'borrow, 'borrow> IvParameterSpec<'env, 'borrow> { + /// Creates a new `IvParameterSpec` instance. + /// + /// # Arguments + /// + /// * `env` - The JNI environment. + /// * `iv` - The IV. + /// + /// # Returns + /// + /// A `JniResult` containing the new `IvParameterSpec` instance. + pub fn new(env: &'borrow JNIEnv<'env>, iv: &[u8]) -> JniResult { + let class = env.find_class("javax/crypto/spec/IvParameterSpec")?; + let array = env.byte_array_from_slice(iv)?; + let args = [Into::into(array)]; + let obj = env.new_object(class, "([B)V", &args)?; + Ok(Self { + raw: AutoLocal::new(env, Into::::into(obj)), + }) + } + } +} diff --git a/src/tpm/android/wrapper/key_generation/key.rs b/src/tpm/android/wrapper/key_generation/key.rs new file mode 100644 index 00000000..cefbe246 --- /dev/null +++ b/src/tpm/android/wrapper/key_generation/key.rs @@ -0,0 +1,57 @@ +use robusta_jni::bridge; + +#[bridge] +/// This module contains the JNI bindings for key generation in Android. +pub mod jni { + use robusta_jni::{ + convert::{IntoJavaValue, Signature, TryFromJavaValue, TryIntoJavaValue}, + jni::{errors::Result as JniResult, objects::AutoLocal, JNIEnv}, + }; + + /// Represents a key in Java's `java.security` package. + #[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(java.security)] + pub struct Key<'env: 'borrow, 'borrow> { + #[instance] + pub raw: AutoLocal<'env, 'borrow>, + } + + #[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(javax.crypto)] + pub struct SecretKey<'env: 'borrow, 'borrow> { + #[instance] + pub raw: AutoLocal<'env, 'borrow>, + } + + /// Represents a public key in Java's `java.security` package. + #[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(java.security)] + pub struct PublicKey<'env: 'borrow, 'borrow> { + #[instance] + pub raw: AutoLocal<'env, 'borrow>, + } + + impl<'env: 'borrow, 'borrow> PublicKey<'env, 'borrow> { + /// Converts the public key to its string representation. + pub extern "java" fn toString(&self, _env: &JNIEnv) -> JniResult {} + + /// Retrieves the algorithm used by the public key. + pub extern "java" fn getAlgorithm(&self, _env: &JNIEnv) -> JniResult {} + } + + /// Represents a private key in Java's `java.security` package. + #[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(java.security)] + pub struct PrivateKey<'env: 'borrow, 'borrow> { + #[instance] + pub raw: AutoLocal<'env, 'borrow>, + } + + impl<'env: 'borrow, 'borrow> PrivateKey<'env, 'borrow> { + /// Converts the private key to its string representation. + pub extern "java" fn toString(&self, _env: &JNIEnv) -> JniResult {} + + /// Retrieves the algorithm used by the private key. + pub extern "java" fn getAlgorithm(&self, _env: &JNIEnv) -> JniResult {} + } +} diff --git a/src/tpm/android/wrapper/key_generation/key_gen_parameter_spec.rs b/src/tpm/android/wrapper/key_generation/key_gen_parameter_spec.rs new file mode 100644 index 00000000..1bf683a4 --- /dev/null +++ b/src/tpm/android/wrapper/key_generation/key_gen_parameter_spec.rs @@ -0,0 +1,44 @@ +use robusta_jni::bridge; + +#[bridge] +/// This module contains the JNI bindings for the KeyGenParameterSpec struct/class. +pub mod jni { + use robusta_jni::{ + convert::{IntoJavaValue, Signature, TryFromJavaValue, TryIntoJavaValue}, + jni::{errors::Result as JniResult, objects::AutoLocal, JNIEnv}, + }; + + /// Represents the KeyGenParameterSpec struct in the android.security.keystore package. + #[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(android.security.keystore)] + pub struct KeyGenParameterSpec<'env: 'borrow, 'borrow> { + #[instance] + pub raw: AutoLocal<'env, 'borrow>, + } + + impl<'env: 'borrow, 'borrow> KeyGenParameterSpec<'env, 'borrow> { + /// Retrieves the supported digest algorithms for the key generation. + /// + /// # Arguments + /// + /// * `env` - The JNI environment. + /// + /// # Returns + /// + /// A Result containing a vector of strings representing the supported digest algorithms, + /// or an error if the JNI call fails. + pub extern "java" fn getDigests(&self, env: &JNIEnv) -> JniResult> {} + + /// Checks if the key generation is backed by a StrongBox. + /// + /// # Arguments + /// + /// * `env` - The JNI environment. + /// + /// # Returns + /// + /// A Result containing a boolean value indicating whether the key generation is backed by a StrongBox, + /// or an error if the JNI call fails. + pub extern "java" fn isStrongBoxBacked(&self, env: &JNIEnv) -> JniResult {} + } +} diff --git a/src/tpm/android/wrapper/key_generation/key_generator.rs b/src/tpm/android/wrapper/key_generation/key_generator.rs new file mode 100644 index 00000000..f200c7b8 --- /dev/null +++ b/src/tpm/android/wrapper/key_generation/key_generator.rs @@ -0,0 +1,39 @@ +use robusta_jni::bridge; + +#[bridge] +pub mod jni { + use crate::tpm::android::wrapper::key_generation::key::jni::SecretKey; + use robusta_jni::{ + convert::{IntoJavaValue, Signature, TryFromJavaValue, TryIntoJavaValue}, + jni::{ + errors::Result as JniResult, + objects::{AutoLocal, JObject}, + JNIEnv, + }, + }; + + #[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(javax.crypto)] + pub struct KeyGenerator<'env: 'borrow, 'borrow> { + #[instance] + pub raw: AutoLocal<'env, 'borrow>, + } + + impl<'env: 'borrow, 'borrow> KeyGenerator<'env, 'borrow> { + pub extern "java" fn getInstance( + env: &'borrow JNIEnv<'env>, + algorithm: String, + provider: String, + ) -> JniResult { + } + + pub extern "java" fn init( + &self, + env: &JNIEnv, + #[input_type("Ljava/security/spec/AlgorithmParameterSpec;")] params: JObject, + ) -> JniResult<()> { + } + + pub extern "java" fn generateKey(&self, _env: &'borrow JNIEnv) -> JniResult {} + } +} diff --git a/src/tpm/android/wrapper/key_generation/key_pair.rs b/src/tpm/android/wrapper/key_generation/key_pair.rs new file mode 100644 index 00000000..b8934478 --- /dev/null +++ b/src/tpm/android/wrapper/key_generation/key_pair.rs @@ -0,0 +1,30 @@ +use robusta_jni::bridge; + +#[bridge] +/// This module contains the JNI bindings for the `KeyPair` struct used in Android TPM key generation. +pub mod jni { + use crate::tpm::android::wrapper::key_generation::key::jni::{PrivateKey, PublicKey}; + use robusta_jni::{ + convert::{IntoJavaValue, Signature, TryFromJavaValue, TryIntoJavaValue}, + jni::{errors::Result as JniResult, objects::AutoLocal, JNIEnv}, + }; + + /// Represents a Java `KeyPair` object. + #[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(java.security)] + pub struct KeyPair<'env: 'borrow, 'borrow> { + #[instance] + pub raw: AutoLocal<'env, 'borrow>, + } + + impl<'env: 'borrow, 'borrow> KeyPair<'env, 'borrow> { + /// Returns a string representation of the `KeyPair` object. + pub extern "java" fn toString(&self, _env: &JNIEnv) -> JniResult {} + + /// Returns the public key associated with the `KeyPair` object. + pub extern "java" fn getPublic(&self, _env: &'borrow JNIEnv) -> JniResult {} + + /// Returns the private key associated with the `KeyPair` object. + pub extern "java" fn getPrivate(&self, _env: &'borrow JNIEnv) -> JniResult {} + } +} diff --git a/src/tpm/android/wrapper/key_generation/key_pair_generator.rs b/src/tpm/android/wrapper/key_generation/key_pair_generator.rs new file mode 100644 index 00000000..67671a14 --- /dev/null +++ b/src/tpm/android/wrapper/key_generation/key_pair_generator.rs @@ -0,0 +1,104 @@ +use robusta_jni::bridge; + +#[bridge] +/// This module contains the JNI bindings for the `KeyPairGenerator` class in the Android TPM wrapper. +pub mod jni { + use crate::tpm::android::wrapper::key_generation::key_pair::jni::KeyPair; + use robusta_jni::{ + convert::{IntoJavaValue, Signature, TryFromJavaValue, TryIntoJavaValue}, + jni::{ + errors::Result as JniResult, + objects::{AutoLocal, JObject}, + JNIEnv, + }, + }; + + /// Represents a Java `KeyPairGenerator` object. + #[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(java.security)] + pub struct KeyPairGenerator<'env: 'borrow, 'borrow> { + #[instance] + pub raw: AutoLocal<'env, 'borrow>, + } + + impl<'env: 'borrow, 'borrow> KeyPairGenerator<'env, 'borrow> { + /// Returns an instance of `KeyPairGenerator` for the specified algorithm and provider. + /// + /// # Arguments + /// + /// * `env` - The JNI environment. + /// * `algorithm` - The name of the algorithm. + /// * `provider` - The name of the provider. + /// + /// # Returns + /// + /// Returns a `JniResult` containing the `KeyPairGenerator` instance. + pub extern "java" fn getInstance( + env: &'borrow JNIEnv<'env>, + algorithm: String, + provider: String, + ) -> JniResult { + } + + /// Returns a string representation of the `KeyPairGenerator` object. + /// + /// # Arguments + /// + /// * `_env` - The JNI environment. + /// + /// # Returns + /// + /// Returns a `JniResult` containing the string representation. + pub extern "java" fn toString(&self, _env: &JNIEnv) -> JniResult {} + + /// Returns the algorithm name associated with the `KeyPairGenerator` object. + /// + /// # Arguments + /// + /// * `_env` - The JNI environment. + /// + /// # Returns + /// + /// Returns a `JniResult` containing the algorithm name. + pub extern "java" fn getAlgorithm(&self, _env: &JNIEnv) -> JniResult {} + + /// Initializes the `KeyPairGenerator` object with the specified algorithm parameters. + /// + /// Initializes the key pair generator using the specified parameter set and the SecureRandom + /// implementation of the highest-priority installed provider as the source of randomness. + /// (If none of the installed providers supply an implementation of SecureRandom, a system-provided source of randomness is used.) + /// + /// Could not be implemented using `robusta_jni` because the params parameter is the class + /// AlgorithmParameterSpec. AlgorithmParameterSpec is an interface and we need to pass an object + /// of type KeyGenParameterSpec. This causes the signatures to not match, meaning the jni call fails. + /// # Arguments + /// + /// * `env` - The JNI environment. + /// * `params` - The algorithm parameter specification. + /// + /// # Returns + /// + /// Returns a `JniResult` indicating success or failure. + pub extern "java" fn initialize( + &self, + env: &JNIEnv, + #[input_type("Ljava/security/spec/AlgorithmParameterSpec;")] params: JObject, + ) -> JniResult<()> { + } + + /// Generates a key pair using the `KeyPairGenerator` object. + /// + /// If this KeyPairGenerator has not been initialized explicitly, provider-specific defaults + /// will be used for the size and other (algorithm-specific) values of the generated keys. + /// This will generate a new key pair every time it is called. + /// + /// # Arguments + /// + /// * `_env` - The JNI environment. + /// + /// # Returns + /// + /// Returns a `JniResult` containing the generated `KeyPair`. + pub extern "java" fn generateKeyPair(&self, _env: &'borrow JNIEnv) -> JniResult {} + } +} diff --git a/src/tpm/android/wrapper/key_generation/mod.rs b/src/tpm/android/wrapper/key_generation/mod.rs new file mode 100644 index 00000000..6feaf8e4 --- /dev/null +++ b/src/tpm/android/wrapper/key_generation/mod.rs @@ -0,0 +1,10 @@ +#![allow(clippy::needless_borrow)] + +pub mod builder; +pub mod iv_parameter_spec; +pub mod key; +pub mod key_gen_parameter_spec; +pub mod key_generator; +pub mod key_pair; +pub mod key_pair_generator; +pub mod secure_random; diff --git a/src/tpm/android/wrapper/key_generation/secure_random.rs b/src/tpm/android/wrapper/key_generation/secure_random.rs new file mode 100644 index 00000000..8a762a7b --- /dev/null +++ b/src/tpm/android/wrapper/key_generation/secure_random.rs @@ -0,0 +1,30 @@ +use robusta_jni::bridge; + +#[bridge] +/// This module contains the JNI bindings for the `SecureRandom` class in the `java.security` package. +/// This might not even be necessary. The `SecureRandom` is automatically generated by `KeyPairGenerator.initialize` +pub mod jni { + use robusta_jni::{ + convert::{IntoJavaValue, Signature, TryFromJavaValue, TryIntoJavaValue}, + jni::errors::Result as JniResult, + jni::objects::AutoLocal, + jni::JNIEnv, + }; + + /// Represents the `SecureRandom` class in Java. + #[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(java.security)] + pub struct SecureRandom<'env: 'borrow, 'borrow> { + #[instance] + pub raw: AutoLocal<'env, 'borrow>, + } + + impl<'env: 'borrow, 'borrow> SecureRandom<'env, 'borrow> { + /// Constructs a new `SecureRandom` instance. + #[constructor] + pub extern "java" fn new(env: &'borrow JNIEnv<'env>) -> JniResult {} + + /// Returns the algorithm name of the `SecureRandom` instance. + pub extern "java" fn getAlgorithm(&self, env: &JNIEnv<'env>) -> JniResult {} + } +} diff --git a/src/tpm/android/wrapper/key_store/cipher.rs b/src/tpm/android/wrapper/key_store/cipher.rs new file mode 100644 index 00000000..ee58dcec --- /dev/null +++ b/src/tpm/android/wrapper/key_store/cipher.rs @@ -0,0 +1,116 @@ +use robusta_jni::bridge; + +#[bridge] +/// This module contains the JNI bindings for the Cipher class in the javax.crypto package. +pub mod jni { + use crate::tpm::android::wrapper::key_generation::key::jni::Key; + use robusta_jni::{ + convert::{IntoJavaValue, Signature, TryFromJavaValue, TryIntoJavaValue}, + jni::{ + errors::Result as JniResult, + objects::{AutoLocal, JObject, JValue}, + sys::jbyteArray, + JNIEnv, + }, + }; + + /// Represents a Cipher object in Java. + #[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(javax.crypto)] + pub struct Cipher<'env: 'borrow, 'borrow> { + #[instance] + pub raw: AutoLocal<'env, 'borrow>, + } + + impl<'env: 'borrow, 'borrow> Cipher<'env, 'borrow> { + /// Creates a new instance of the Cipher class. + /// + /// # Arguments + /// + /// * `env` - The JNIEnv object. + /// * `transformation` - the name of the transformation, e.g., DES/CBC/PKCS5Padding. See the Cipher section in the Java Cryptography Architecture Standard Algorithm Name Documentation for information about standard transformation names. + /// + /// # Returns + /// + /// Returns a Cipher object that implements the specified transformation. + pub extern "java" fn getInstance( + env: &'borrow JNIEnv<'env>, + transformation: String, + ) -> JniResult { + } + + /// Initializes the Cipher object with the specified operation mode and key. + /// + /// # Arguments + /// + /// * `env` - The JNIEnv object. + /// * `opmode` - The operation mode. + /// * `key` - The key object. + /// + /// # Returns + /// + /// Returns a JniResult indicating success or failure. + pub extern "java" fn init( + &self, + env: &'borrow JNIEnv<'env>, + opmode: i32, + #[input_type("Ljava/security/Key;")] key: JObject, + ) -> JniResult<()> { + } + + pub fn init2( + &self, + env: &'borrow JNIEnv<'env>, + opmode: i32, + key: Key, + params: JObject, + ) -> JniResult<()> { + env.call_method( + self.raw.as_obj(), + "init", + "(ILjava/security/Key;Ljava/security/AlgorithmParameters;)V", + &[ + JValue::Int(opmode), + JValue::Object(key.raw.as_obj()), + JValue::Object(params), + ], + )?; + Ok(()) + } + + pub fn getIV(&self, env: &JNIEnv) -> JniResult> { + let output = env.call_method(self.raw.as_obj(), "getIV", "()[B", &[])?; + + let output_array = output.l()?.into_inner() as jbyteArray; + let output_vec = env.convert_byte_array(output_array).unwrap(); + + Ok(output_vec) + } + + /// Performs the final operation of the Cipher, processing any remaining data. + /// + /// # Arguments + /// + /// * `env` - The JNIEnv object. + /// * `input` - The input data. + /// + /// # Returns + /// + /// Returns a JniResult containing the output data. + pub fn doFinal(&self, env: &JNIEnv, input: Vec) -> JniResult> { + let input_array = env.byte_array_from_slice(&input)?; + + let output = env.call_method( + self.raw.as_obj(), + "doFinal", + "([B)[B", + &[JValue::from(input_array)], + )?; + + let output_array = output.l()?.into_inner() as jbyteArray; + let output_vec = env.convert_byte_array(output_array).unwrap(); + + Ok(output_vec) + } + } +} diff --git a/src/tpm/android/wrapper/key_store/key_store.rs b/src/tpm/android/wrapper/key_store/key_store.rs new file mode 100644 index 00000000..3291df36 --- /dev/null +++ b/src/tpm/android/wrapper/key_store/key_store.rs @@ -0,0 +1,131 @@ +use robusta_jni::bridge; + +#[bridge] +/// This module contains the JNI bindings for the KeyStore functionality in Android. +pub mod jni { + use crate::tpm::android::wrapper::key_generation::key::jni::{Key, PublicKey}; + use robusta_jni::{ + convert::{IntoJavaValue, Signature, TryFromJavaValue, TryIntoJavaValue}, + jni::{ + errors::Result as JniResult, + objects::{AutoLocal, JObject}, + JNIEnv, + }, + }; + + /// Represents a KeyStore object in Java. + #[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(java.security)] + pub struct KeyStore<'env: 'borrow, 'borrow> { + #[instance] + pub raw: AutoLocal<'env, 'borrow>, + } + + impl<'env: 'borrow, 'borrow> KeyStore<'env, 'borrow> { + /// Retrieves an instance of the KeyStore class. + /// + /// # Arguments + /// + /// * `env` - The JNI environment. + /// * `type1` - The type of the KeyStore. In java the paramenter is just 'type', but we have to use 'type1' because 'type' is a reserved keyword in Rust. + /// + /// # Returns + /// + /// Returns a keystore object of the specified type. + pub extern "java" fn getInstance( + env: &'borrow JNIEnv<'env>, + type1: String, + ) -> JniResult { + } + + /// Retrieves a certificate from the KeyStore. + /// + /// Returns the certificate associated with the given alias. + /// If the given alias name identifies an entry created by a call to setCertificateEntry, + /// or created by a call to setEntry with a TrustedCertificateEntry, then the trusted certificate + /// contained in that entry is returned. + /// + /// # Arguments + /// + /// * `env` - The JNI environment. + /// * `alias` - The alias name. + /// + /// # Returns + /// + /// Returns a `JniResult` containing the Certificate instance. + pub extern "java" fn getCertificate( + &self, + env: &'borrow JNIEnv<'env>, + alias: String, + ) -> JniResult { + } + + /// Retrieves a key from the KeyStore. + /// + /// # Arguments + /// + /// * `env` - The JNI environment. + /// * `alias` - The alias of the key. + /// * `password` - The password for the key. + /// + /// # Returns + /// + /// Returns a `JniResult` containing the Key instance. + pub extern "java" fn getKey( + &self, + env: &'borrow JNIEnv<'env>, + alias: String, + #[input_type("[C")] password: JObject, + ) -> JniResult { + } + + /// Loads the KeyStore. + /// + /// # Arguments + /// + /// * `env` - The JNI environment. + /// * `param` - An optional parameter for loading the KeyStore. + /// + /// # Returns + /// + /// Returns a `JniResult` indicating the success or failure of the operation. + pub fn load(&self, env: &JNIEnv, param: Option) -> JniResult<()> { + let param_obj = param.unwrap_or(JObject::null()); + env.call_method( + self.raw.as_obj(), + "load", + "(Ljava/security/KeyStore$LoadStoreParameter;)V", + &[Into::into(param_obj)], + )?; + Ok(()) + } + } + + /// Represents a Certificate object in Java. + #[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(java.security.cert)] + pub struct Certificate<'env: 'borrow, 'borrow> { + #[instance] + pub raw: AutoLocal<'env, 'borrow>, + } + + impl<'env: 'borrow, 'borrow> Certificate<'env, 'borrow> { + /// Retrieves the public key from the Certificate. + /// + /// # Arguments + /// + /// * `env` - The JNI environment. + /// + /// # Returns + /// + /// Returns a `JniResult` containing the PublicKey instance. + pub extern "java" fn getPublicKey( + &self, + env: &'borrow JNIEnv<'env>, + ) -> JniResult> { + } + + /// toString Java method of the Certificate class. + pub extern "java" fn toString(&self, _env: &JNIEnv) -> JniResult {} + } +} diff --git a/src/tpm/android/wrapper/key_store/mod.rs b/src/tpm/android/wrapper/key_store/mod.rs new file mode 100644 index 00000000..75a40b47 --- /dev/null +++ b/src/tpm/android/wrapper/key_store/mod.rs @@ -0,0 +1,5 @@ +#![allow(clippy::needless_borrow)] + +pub mod cipher; +pub mod key_store; +pub mod signature; diff --git a/src/tpm/android/wrapper/key_store/signature.rs b/src/tpm/android/wrapper/key_store/signature.rs new file mode 100644 index 00000000..fc49b3ea --- /dev/null +++ b/src/tpm/android/wrapper/key_store/signature.rs @@ -0,0 +1,133 @@ +use robusta_jni::bridge; + +#[bridge] +/// This module contains the JNI bindings for the Signature class in the Java security package. +pub mod jni { + use crate::tpm::android::wrapper::key_store::key_store::jni::Certificate; + use robusta_jni::{ + convert::{IntoJavaValue, Signature as JavaSignature, TryFromJavaValue, TryIntoJavaValue}, + jni::{ + errors::Result as JniResult, + objects::{AutoLocal, JObject, JValue}, + JNIEnv, + }, + }; + + /// Represents a Signature object in Java. + #[derive(JavaSignature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)] + #[package(java.security)] + pub struct Signature<'env: 'borrow, 'borrow> { + #[instance] + pub raw: AutoLocal<'env, 'borrow>, + } + + impl<'env: 'borrow, 'borrow> Signature<'env, 'borrow> { + /// Creates a new instance of the Signature class with the specified algorithm. + /// + /// # Arguments + /// + /// * `env` - The JNI environment. + /// * `algorithm` - The algorithm to use for the Signature instance. + /// + /// # Returns + /// + /// Returns a Result containing the Signature instance if successful, or an error if it fails. + pub extern "java" fn getInstance( + env: &'borrow JNIEnv<'env>, + algorithm: String, + ) -> JniResult { + } + + /// Signs the data using the Signature instance. + /// + /// Could not be implemented using `robusta_jni` because the Java method returns a byte array, + /// and byte arrays are not supported as a return value by `robusta_jni`. + /// + /// # Arguments + /// + /// * `env` - The JNI environment. + /// + /// # Returns + /// + /// Returns a Result containing the signed data as a Vec if successful, or an error if it fails. + pub fn sign(&self, env: &JNIEnv) -> JniResult> { + let result = env.call_method(self.raw.as_obj(), "sign", "()[B", &[])?; + + let byte_array = result.l()?.into_inner(); + let output = env.convert_byte_array(byte_array)?; + + Ok(output) + } + + /// Initializes the Signature instance for signing with the specified private key. + /// + /// # Arguments + /// + /// * `env` - The JNI environment. + /// * `privateKey` - The private key to use for signing. + /// + /// # Returns + /// + /// Returns a Result indicating success or failure. + pub extern "java" fn initSign( + &self, + env: &JNIEnv, + #[input_type("Ljava/security/PrivateKey;")] privateKey: JObject, + ) -> JniResult<()> { + } + + /// Initializes the Signature instance for verification with the specified certificate. + /// + /// Could not be implemented using `robusta_jni` because for some reason it doesn't + /// recognize the `Certificate` signature correctly. + /// + /// # Arguments + /// + /// * `env` - The JNI environment. + /// * `certificate` - The certificate to use for verification. + /// + /// # Returns + /// + /// Returns a Result indicating success or failure. + pub fn initVerify(&self, env: &JNIEnv, certificate: Certificate) -> JniResult<()> { + let certificate_obj = certificate.raw.as_obj(); + + env.call_method( + self.raw.as_obj(), + "initVerify", + "(Ljava/security/cert/Certificate;)V", + &[JValue::from(certificate_obj)], + )?; + + Ok(()) + } + + /// Verifies the signature against the specified data. + /// + /// # Arguments + /// + /// * `_env` - The JNI environment. + /// * `signature` - The signature to verify. + /// + /// # Returns + /// + /// Returns a Result indicating whether the signature is valid or not. + pub extern "java" fn verify(&self, _env: &JNIEnv, signature: Box<[u8]>) -> JniResult { + } + + /// Updates the Signature instance with additional data to be signed or verified. + /// + /// # Arguments + /// + /// * `_env` - The JNI environment. + /// * `data` - The data to update the Signature instance with. + /// + /// # Returns + /// + /// Returns a Result indicating success or failure. + pub extern "java" fn update(&self, _env: &JNIEnv, data: Box<[u8]>) -> JniResult<()> {} + + /// toString Java method of the Signature class. + pub extern "java" fn toString(&self, _env: &JNIEnv) -> JniResult {} + } +} diff --git a/src/tpm/android/wrapper/mod.rs b/src/tpm/android/wrapper/mod.rs new file mode 100644 index 00000000..9f90f251 --- /dev/null +++ b/src/tpm/android/wrapper/mod.rs @@ -0,0 +1,61 @@ +use robusta_jni::jni::{ + self, + sys::{jint, jsize}, + JavaVM, +}; + +use crate::tpm::core::error::TpmError; + +pub(crate) mod key_generation; +pub(crate) mod key_store; + +/// This function gets the current Java VM running for the Android app. +/// Every Android app can have only 1 JVM running, so we can't just create a new one. +/// Normally it would be possible to just call the "JNI_GetCreatedJavaVMs" C function, but we can't link against it for some reason +/// so we have to load the symbol manually using the libloading crate. +pub(super) fn get_java_vm() -> Result { + // using jni_sys::JNI_GetCreatedJavaVMs crashes, bc the symbol is not loaded into the process for some reason + // instead we use libloading to load the symbol ourselves + pub type JniGetCreatedJavaVms = unsafe extern "system" fn( + vmBuf: *mut *mut jni::sys::JavaVM, + bufLen: jsize, + nVMs: *mut jsize, + ) -> jint; + pub const JNI_GET_JAVA_VMS_NAME: &[u8] = b"JNI_GetCreatedJavaVMs"; + + let lib = libloading::os::unix::Library::this(); + // let lib = unsafe { libloading::os::unix::Library::new("libart.so") } + // .map_err(|e| TpmError::InitializationError(format!("could not find libart.so: {e}")))?; + + let get_created_java_vms: JniGetCreatedJavaVms = unsafe { + *lib.get(JNI_GET_JAVA_VMS_NAME).map_err(|e| { + TpmError::InitializationError(format!("function JNI_GET_JAVA_VMS_NAME not loaded: {e}")) + })? + }; + + // now that we have the function, we can call it + let mut buffer = [std::ptr::null_mut::(); 1]; + let buffer_ptr = buffer.as_mut_ptr(); + let mut found_vms = 0; + let found_vm_ptr = &mut found_vms as *mut i32; + let res = unsafe { get_created_java_vms(buffer_ptr, 1, found_vm_ptr) }; + + if res != jni::sys::JNI_OK { + return Err(TpmError::InitializationError( + "Unable to get existing JVMs".to_owned(), + )); + } + + if found_vms == 0 { + return Err(TpmError::InitializationError( + "No running JVMs found".to_owned(), + )); + } + + let jvm = unsafe { + JavaVM::from_raw(buffer[0]).map_err(|e| TpmError::InitializationError(e.to_string()))? + }; + jvm.attach_current_thread() + .map_err(|e| TpmError::InitializationError(e.to_string()))?; + Ok(jvm) +} diff --git a/src/tpm/core/error.rs b/src/tpm/core/error.rs index ee6bdffb..a706ad4f 100644 --- a/src/tpm/core/error.rs +++ b/src/tpm/core/error.rs @@ -19,6 +19,8 @@ pub enum TpmError { InitializationError(String), /// Error indicating that an attempted operation is unsupported, containing a description. UnsupportedOperation(String), + /// Error indicating that an internal error occured, possibly caused by ffi bindings + InternalError(Box), } impl fmt::Display for TpmError { @@ -39,10 +41,18 @@ impl TpmError { TpmError::Win(err) => format!("Windows error: {}", err), TpmError::InitializationError(msg) => format!("Initialization error: {}", msg), TpmError::UnsupportedOperation(msg) => format!("Unsupported operation: {}", msg), + TpmError::InternalError(e) => format!("Internal error: {}", e), } } } +/// A trait to allow ergonomic conversions to TpmError +pub trait ToTpmError { + /// Wrap any error in TpmError::InternalError + /// the wrapped error can be accessed througth the error trait + fn err_internal(self) -> Result; +} + /// Enables `TpmError` to be treated as a trait object for any error (`dyn std::error::Error`). /// /// This implementation allows for compatibility with Rust's standard error handling mechanisms, diff --git a/src/tpm/core/instance.rs b/src/tpm/core/instance.rs index 631bc857..fef0d6b6 100644 --- a/src/tpm/core/instance.rs +++ b/src/tpm/core/instance.rs @@ -1,4 +1,4 @@ -use crate::common::traits::module_provider::Provider; +use crate::{common::traits::module_provider::Provider, tpm::macos::SecureEnclaveProvider}; #[cfg(feature = "linux")] use crate::tpm::linux::TpmProvider; #[cfg(feature = "win")] @@ -37,6 +37,8 @@ pub enum TpmType { #[derive(Eq, Hash, PartialEq, Clone, Debug)] #[cfg(feature = "android")] pub enum AndroidTpmType { + /// Android Provider using the Android Keystore API + Keystore, /// Represents the Samsung Knox security platform with TPM functionalities. Knox, } @@ -116,14 +118,22 @@ impl TpmInstance { Arc::new(Mutex::new(instance)) } #[cfg(feature = "macos")] - TpmType::MacOs => todo!(), + TpmType::MacOs => { + let instance = SecureEnclaveProvider::new(key_id); + Arc::new(Mutex::new(instance)) + }, #[cfg(feature = "linux")] TpmType::Linux => { let instance = TpmProvider::new(key_id); Arc::new(Mutex::new(instance)) } #[cfg(feature = "android")] - TpmType::Android(_tpm_type) => todo!(), + TpmType::Android(tpm_type) => match tpm_type { + AndroidTpmType::Keystore => Arc::new(Mutex::new( + crate::tpm::android::AndroidProvider::new(key_id), + )), + AndroidTpmType::Knox => todo!(), + }, TpmType::None => todo!(), } } diff --git a/src/tpm/linux/provider.rs b/src/tpm/linux/provider.rs index 5ecd422e..bcc7c8f5 100644 --- a/src/tpm/linux/provider.rs +++ b/src/tpm/linux/provider.rs @@ -3,10 +3,11 @@ use crate::{ common::{ crypto::{algorithms::encryption::AsymmetricEncryption, KeyUsage}, error::SecurityModuleError, - traits::{module_provider::Provider, module_provider_config::ProviderConfig}, + traits::module_provider::Provider, }, tpm::TpmConfig, }; +use std::any::Any; use std::sync::{Arc, Mutex}; use tracing::instrument; use tss_esapi::{ @@ -50,9 +51,9 @@ impl Provider for TpmProvider { fn create_key( &mut self, key_id: &str, - config: Box, + config: Box, ) -> Result<(), SecurityModuleError> { - let config = config.as_any().downcast_ref::().unwrap(); + let config = config.downcast_ref::().unwrap(); self.key_algorithm = Some(config.key_algorithm); self.sym_algorithm = Some(config.sym_algorithm); @@ -193,12 +194,8 @@ impl Provider for TpmProvider { /// A `Result` that, on success, contains `Ok(())`, indicating that the key was loaded successfully. /// On failure, it returns a `SecurityModuleError`. #[instrument] - fn load_key( - &mut self, - key_id: &str, - config: Box, - ) -> Result<(), SecurityModuleError> { - let config = config.as_any().downcast_ref::().unwrap(); + fn load_key(&mut self, key_id: &str, config: Box) -> Result<(), SecurityModuleError> { + let config = config.downcast_ref::().unwrap(); self.key_algorithm = Some(config.key_algorithm); self.sym_algorithm = Some(config.sym_algorithm); @@ -334,18 +331,7 @@ impl Provider for TpmProvider { /// A `Result` that, on success, contains `Ok(())`, indicating that the module was initialized successfully. /// On failure, it returns a `SecurityModuleError`. #[instrument] - fn initialize_module( - &mut self, - key_algorithm: AsymmetricEncryption, - sym_algorithm: Option, - hash: Option, - key_usages: Vec, - ) -> Result<(), SecurityModuleError> { - self.key_algorithm = Some(key_algorithm); - self.sym_algorithm = sym_algorithm; - self.hash = hash; - self.key_usages = Some(key_usages); - + fn initialize_module(&mut self) -> Result<(), SecurityModuleError> { let tcti = TctiNameConf::from_environment_variable().unwrap(); let context = Context::new(tcti) diff --git a/src/tpm/macos/key_handle.rs b/src/tpm/macos/key_handle.rs new file mode 100755 index 00000000..f9a24d5a --- /dev/null +++ b/src/tpm/macos/key_handle.rs @@ -0,0 +1,139 @@ +extern crate apple_secure_enclave_bindings; +use super::{provider::{convert_algorithms, convert_hash}, SecureEnclaveProvider}; +use crate::common::{error::SecurityModuleError, traits::key_handle::KeyHandle}; +use tracing::instrument; + + +/// Provides cryptographic operations for asymmetric keys on macOS, +/// such as signing, encryption, decryption, and signature verification. +impl KeyHandle for SecureEnclaveProvider { + /// Signs the given data using the cryptographic key managed by the Secure Enclave provider. + /// + /// Uses the rust_crypto_call_sign_data function from the Swift Secure Enclave bindings. + /// + /// # Arguments + /// + /// * `data` - A byte slice representing the data to be signed. + /// + /// # Returns + /// + /// A `Result` containing the signature as a `Vec` on success, or a `SecurityModuleError` on failure. + #[instrument] + fn sign_data(&self, data: &[u8]) -> Result, SecurityModuleError> { + + let data_vec = data.to_vec(); + let key_id = &self.key_id; + let config = self.config.as_ref().ok_or(SecurityModuleError::InitializationError(("Failed to initialize config").to_owned()))?; + let algo = convert_algorithms(config.clone()); + let hash = convert_hash(config.hash.expect("No Hash given")); + + let signed_data = apple_secure_enclave_bindings::keyhandle::rust_crypto_call_sign_data(key_id.clone(), data_vec, algo, hash); + + if signed_data.0 { + Err(SecurityModuleError::EncryptionError(signed_data.1.to_string())) + } else { + Ok(signed_data.1.into_bytes()) + } + } + + + /// Decrypts the given encrypted data using the cryptographic key managed by the Secure Enclave provider. + /// + /// Uses the rust_crypto_call_decrypt_data function from the Swift Secure Enclave bindings. + /// + /// # Arguments + /// + /// * `encrypted_data` - A byte slice representing the data to be decrypted. + /// + /// # Returns + /// + /// A `Result` containing the decrypted data as a `Vec` on success, or a `SecurityModuleError` on failure. + #[instrument] + fn decrypt_data(&self, encrypted_data: &[u8]) -> Result, SecurityModuleError> { + let encrypted_data_vec = encrypted_data.to_vec(); + let config = self.config.as_ref().ok_or(SecurityModuleError::InitializationError(("Failed to initialize config").to_owned()))?; + let algorithm = convert_algorithms(config.clone()); + let hash = convert_hash(config.hash.expect("No Hash given")); + + let decrypted_data = + apple_secure_enclave_bindings::keyhandle::rust_crypto_call_decrypt_data(self.key_id.to_string(), encrypted_data_vec, algorithm, hash); + if decrypted_data.0 { + Err(SecurityModuleError::EncryptionError(decrypted_data.1.to_string())) + } else { + Ok(decrypted_data.1.into_bytes()) + } + } + + + /// Encrypts data with the cryptographic key. + /// + /// Uses the rust_crypto_call_encrypt_data function from the Swift Secure Enclave bindings. + /// + /// # Arguments + /// + /// * `data` - The data to be encrypted. + /// + /// # Returns + /// + /// A `Result` containing the encrypted data as a `Vec` on success, or a `SecurityModuleError` on failure. + #[instrument] + fn encrypt_data(&self, data: &[u8]) -> Result, SecurityModuleError> { + // let string_data = String::from_utf8(data.to_vec()).map_err(|_| { + // SecurityModuleError::EncryptionError("Data conversion error".to_string()) + // })?; + let data_vec = data.to_vec(); + let key_id = &self.key_id; + let config = self.config.as_ref().ok_or(SecurityModuleError::InitializationError(("Failed to initialize config").to_owned()))?; + let algorithm = convert_algorithms(config.clone()); + let hash = convert_hash(config.hash.expect("No Hash given")); + + let encrypted_data = + apple_secure_enclave_bindings::keyhandle::rust_crypto_call_encrypt_data(key_id.to_string(), data_vec, algorithm, hash); + + if encrypted_data.0 { + Err(SecurityModuleError::EncryptionError( + encrypted_data.1.to_string(), + )) + } else { + Ok(encrypted_data.1.into_bytes()) + } + } + + + /// Verifies the signature of the given data using the cryptographic key managed by the Secure Enclave provider. + /// + /// Uses the rust_crypto_call_verify_signature function from the Swift Secure Enclave bindings. + /// + /// # Arguments + /// + /// * `data` - A byte slice representing the data whose signature is to be verified. + /// * `signature` - A byte slice representing the signature to be verified against the data. + /// + /// # Returns + /// + /// A `Result` containing a boolean indicating whether the signature is valid (`true`) or not (`false`), + /// or a `SecurityModuleError` on failure. + #[instrument] + fn verify_signature(&self, data: &[u8], signature: &[u8]) -> Result { + let data_vec = data.to_vec(); + let signature_vec = signature.to_vec(); + let key_id = &self.key_id; + let config = self.config.as_ref().ok_or(SecurityModuleError::InitializationError(("Failed to initialize config").to_owned()))?; + let algo = convert_algorithms(config.clone()); + let hash = convert_hash(config.hash.expect("No Hash given")); + + let verification_result = + apple_secure_enclave_bindings::keyhandle::rust_crypto_call_verify_signature(key_id.clone(), data_vec, signature_vec, algo, hash); + + // The FFI bridge always returns strings by design. + // If not "true" or "false" is found, an error from the function is expected + match verification_result.1.as_str() { + "true" => Ok(true), + "false" => Ok(false), + _ => Err(SecurityModuleError::SignatureVerificationError( + verification_result.1, + )) + } + } +} + diff --git a/src/tpm/macos/logger.rs b/src/tpm/macos/logger.rs new file mode 100755 index 00000000..577f8fb2 --- /dev/null +++ b/src/tpm/macos/logger.rs @@ -0,0 +1,42 @@ +use tracing::Level; +use tracing_appender::rolling; +use tracing_subscriber::FmtSubscriber; +use crate::common::traits::log_config::LogConfig; + + +#[derive(Debug, Clone, Copy)] +pub struct Logger {} + +impl LogConfig for Logger{ + + /// Sets up the logging configuration for the application. + /// + /// This method configures the logging system to write log messages to a file named `output.log` + /// + /// # Arguments + /// + /// * `self` - A reference to the `Logger` instance. + fn setup_logging(&self) { + let file_appender = rolling::daily("./logs", "output.log"); + let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender); + let subscriber = FmtSubscriber::builder() + .with_max_level(Level::TRACE) + .with_writer(non_blocking) + .finish(); + tracing::subscriber::set_global_default(subscriber) + .expect("setting default subscriber failed"); + } +} + +impl Logger { + + /// Creates a new instance of the `Logger` struct. + /// + /// # Returns + /// + /// A new instance of the `Logger` struct. + pub fn new_boxed() -> Box { + Box::new(Self {}) + } +} + diff --git a/src/tpm/macos/mod.rs b/src/tpm/macos/mod.rs old mode 100644 new mode 100755 index 8b137891..85ff3b4f --- a/src/tpm/macos/mod.rs +++ b/src/tpm/macos/mod.rs @@ -1 +1,99 @@ +use crate::{common::{crypto::algorithms::{encryption::AsymmetricEncryption, hashes::Hash}, traits::module_provider_config::ProviderConfig}, SecurityModuleError}; +use anyhow::Result; +use std::fmt::{Debug, Formatter}; +use std::any::Any; +pub mod key_handle; +pub mod provider; +pub mod logger; + +// Provider Setup - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#[derive(Clone, Debug)] +#[repr(C)] +pub struct SecureEnclaveProvider { + pub(super) key_id: String, + config: Option +} + +impl SecureEnclaveProvider { + + /// Constructs a new `SecureEnclaveProvider`. + /// + /// # Arguments + /// + /// * `key_id` - A string identifier for the cryptographic key to be managed by this provider. + /// + /// # Returns + /// + /// A new instance of `SecureEnclaveProvider` with the specified `key_id`. + pub fn new(key_id: String) -> Self { + Self { + key_id, + config: None + } + } + + pub fn set_config (&mut self, config: SecureEnclaveConfig) -> Result <(), SecurityModuleError> { + self.config = Some(config); + Ok(()) + } +} + +// Config Setup - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +#[derive(Clone)] +pub struct SecureEnclaveConfig { + pub asym_algorithm: Option, + pub hash: Option +} + +impl SecureEnclaveConfig{ + + /// Constructs a new `SecureEnclaveConfig`. + /// + /// The sym_algorithm is not supported yet. + /// + /// # Arguments + /// + /// * `asym_algorithm` - The asymmetric algorithm to be used for the key. + /// + /// * `hash` - The hash algorithm to be used for the key. + /// + /// # Returns + /// + /// A new instance of `SecureEnclaveConfig` with the specified `asym_algorithm` and `hash`. + pub fn new(asym_algorithm: Option, hash: Option) -> SecureEnclaveConfig { + Self { + asym_algorithm, + hash, + } + } +} + +impl Debug for SecureEnclaveConfig { + + /// Formats the `SecureEnclaveConfig` struct for debugging purposes. + /// + /// # Arguments + /// + /// * `f` - A mutable reference to a `Formatter` object. + /// + /// # Returns + /// + /// A `Result` containing the formatted `SecureEnclaveConfig` struct. + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TpmProvider") + .field("key_algorithm", &self.asym_algorithm) + .field("asym_algorithm", &self.asym_algorithm) + // .field("sym_algorithm", &self.sym_algorithm) // Not supported by Secure Enclave + .field("hash", &self.hash) + .finish() + } +} + +impl ProviderConfig for SecureEnclaveConfig { + /// Returns the `SecureEnclaveConfig` as a reference. + fn as_any(&self) -> &dyn Any { + self + } +} diff --git a/src/tpm/macos/provider.rs b/src/tpm/macos/provider.rs new file mode 100755 index 00000000..93988e05 --- /dev/null +++ b/src/tpm/macos/provider.rs @@ -0,0 +1,190 @@ +use super::{SecureEnclaveConfig, SecureEnclaveProvider}; +extern crate apple_secure_enclave_bindings; +use crate:: + common::{ + crypto::algorithms::{encryption::{AsymmetricEncryption, EccCurves, EccSchemeAlgorithm}, hashes::Hash, KeyBits}, + error::SecurityModuleError, + traits::module_provider::Provider, + }; +use crate::common::crypto::algorithms::hashes::*; +use std::any::Any; +use crate::common::error::SecurityModuleError::InitializationError; +use tracing::instrument; + + +/// Implements the `Provider` trait, providing cryptographic operations utilizing a Secure Enclave. +impl Provider for SecureEnclaveProvider { + + /// Creates a new cryptographic key identified by `key_id`. + /// + /// This method creates a persisted cryptographic key using the specified algorithm + /// and identifier, making it retrievable for future operations. The key is created + /// with the specified key usages and stored in the Secure Enclave. + /// + /// Uses the rust_crypto_call_create_key function from the Swift Secure Enclave bindings. + /// + /// # Arguments + /// + /// * `key_id` - A string slice that uniquely identifies the key to be created. + /// * `key_algorithm` - The asymmetric encryption algorithm to be used for the key. + /// * `config` - A boxed `SecureEnclaveConfig` object containing the configuration for the key. + /// + /// # Returns + /// + /// A `Result` that, on success, contains `Ok(())`, indicating that the key was created successfully. + /// On failure, it returns a `SecurityModuleError`. + #[instrument] + fn create_key( + &mut self, + _key_id: &str, + _config: Box, + ) -> Result<(), SecurityModuleError> { + let config = *_config.downcast::().map_err(|_| SecurityModuleError::InitializationError(("Failed to initialize config").to_owned()))?; + let key_algorithm_type; + + if config.asym_algorithm.is_some(){ + key_algorithm_type = match config.asym_algorithm.expect("No Asymmetric Algorithm given.") { + AsymmetricEncryption::Rsa(keybits) => { + match keybits { + //Works only in combination with SHA1, SHA224 + KeyBits::Bits512 => "RSA;512".to_string(), + //Works only in combination with SHA256, SHA384 + KeyBits::Bits1024 => "RSA;1024".to_string(), + _ => unimplemented!("With RSA only Keysize of 512 and 1024 are supported"), + } + } + AsymmetricEncryption::Ecc(ecc_scheme_algo) => { + match ecc_scheme_algo { + EccSchemeAlgorithm::EcDsa(ecc_curve) => { + match ecc_curve{ + EccCurves::P256 => "ECDSA;256".to_string(), + EccCurves::P384 => "ECDSA;384".to_string(), + // EccCurves::P521 => "ECDSA;521".to_string(), Not supported by Secure Enclave + _ => {return Err(InitializationError("Ecc-Curve is not supported. Only P256 and P384 are supported.".to_string()))} + } + } + _ => {return Err(InitializationError("ECC-Alogithm is not supported".to_string()))} + } + } + }; + + let keypair = apple_secure_enclave_bindings::provider::rust_crypto_call_create_key(self.key_id.clone(), key_algorithm_type); + + if keypair.0 { + Err(SecurityModuleError::InitializationError(keypair.1.to_string())) + } else { + Ok(()) + } + }else{ + return Err(InitializationError("Algorithm is not supported".to_string())) + } + + } + + /// Loads an existing cryptographic key identified by `key_id`. + /// + /// This method attempts to load a persisted cryptographic key by its identifier from the Secure Enclave. + /// If successful, it sets the key usages and returns a handle to the key for further + /// cryptographic operations. + /// + /// Uses the rust_crypto_call_load_key function from the Swift Secure Enclave bindings. + /// + /// # Arguments + /// + /// * `key_id` - A string slice that uniquely identifies the key to be loaded. + /// * `key_algorithm` - The asymmetric encryption algorithm used for the key. + /// * `config` - A boxed `SecureEnclaveConfig` object containing the configuration for the key. + /// + /// # Returns + /// + /// A `Result` that, on success, contains `Ok(())`, indicating that the key was loaded successfully. + /// On failure, it returns a `SecurityModuleError`. + #[instrument] + fn load_key( + &mut self, + _key_id: &str, + _config: Box, + ) -> Result<(), SecurityModuleError> { + let config = *_config.downcast::().map_err(|_| SecurityModuleError::InitializationError(("Failed to initialize config").to_owned()))?; + let _ = self.set_config(config.clone()); + let algorithm = convert_algorithms(config.clone()); + let hash = convert_hash(config.hash.expect("No Hash given")); + + let load_key = apple_secure_enclave_bindings::provider::rust_crypto_call_load_key(_key_id.to_string(), algorithm, hash); + + if load_key.0 { + return Err(SecurityModuleError::InitializationError(load_key.1.to_string())) + } + return Ok(()) + } + + + /// Initializes the Secure Enclave module and returns a handle for cryptographic operations. + /// + /// This method initializes the Secure Enclave context and prepares it for use. It should be called + /// before performing any other operations with the Secure Enclave. + /// + /// Uses the rust_crypto_call_sign_data function from the Swift Secure Enclave bindings. + /// + /// # Returns + /// + /// A `Result` that, on success, contains `Ok(())`, indicating that the module was initialized successfully. + /// On failure, it returns a `SecurityModuleError`. + #[instrument] + fn initialize_module(&mut self) -> Result<(), SecurityModuleError> { + let initialization_result = + apple_secure_enclave_bindings::provider::rust_crypto_call_initialize_module(); + + match initialization_result { + true => Ok(()), + false => Err(SecurityModuleError::InitializationError( + "Failed to initialize module".to_string(), + )), + } + } +} + +/// Converts the algorithm type to a String. +/// +/// # Arguments +/// +/// * `config` - A `SecureEnclaveConfig` object containing the configuration for the key. +/// +/// # Returns +/// +/// A `String` containing the AsymmetricEncryption algorithm. +pub fn convert_algorithms(config: SecureEnclaveConfig) -> String { + let asym_algorithm_type = match config.asym_algorithm.expect("Invalid config") { + // Is only Asymmetric-Algorithm which is working at that time + AsymmetricEncryption::Rsa(_) => "RSA".to_string(), + AsymmetricEncryption::Ecc(EccSchemeAlgorithm::EcDsa(_)) => "ECDSA".to_string(), + _ => unimplemented!("Only RSA and ECDSA supported") , + }; + + asym_algorithm_type +} + + +/// Converts the Hash algorithm to a String. +/// +/// # Arguments +/// +/// * `hash` - A `Hash` object containing the hash algorithm. +/// +/// # Returns +/// +/// A `String` containing the Hash algorithm. +pub fn convert_hash(hash: Hash) -> String { + match hash { + Hash::Sha2(sha2_bits) =>{ + match sha2_bits { + Sha2Bits::Sha224 => "SHA224".to_string(), + Sha2Bits::Sha256 => "SHA256".to_string(), + Sha2Bits::Sha384 => "SHA384".to_string(), + Sha2Bits::Sha512 => "SHA512".to_string(), + _ => unimplemented!("Only SHA224, SHA256, SHA384, SHA512 supported."), + } + }, + _ => unimplemented!("Only SHA1 and Sha2Bits supported."), + } +} diff --git a/src/tpm/macos/swift_rust_wrapper/.DS_Store b/src/tpm/macos/swift_rust_wrapper/.DS_Store new file mode 100755 index 00000000..8046a318 Binary files /dev/null and b/src/tpm/macos/swift_rust_wrapper/.DS_Store differ diff --git a/src/tpm/macos/swift_rust_wrapper/Cargo.lock b/src/tpm/macos/swift_rust_wrapper/Cargo.lock new file mode 100755 index 00000000..40e80c75 --- /dev/null +++ b/src/tpm/macos/swift_rust_wrapper/Cargo.lock @@ -0,0 +1,229 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "apple-secure-enclave-bindings" +version = "0.1.0" +dependencies = [ + "swift-bridge", + "swift-bridge-build", +] + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "libc" +version = "0.2.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "proc-macro2" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "swift-bridge" +version = "0.1.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6180c668892926e0bc19d75a81b0ee2fdce3ab15ff062a61b3ce9b4d562eac1b" +dependencies = [ + "swift-bridge-build", + "swift-bridge-macro", +] + +[[package]] +name = "swift-bridge-build" +version = "0.1.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b8256d2d8c35795afeab117528f5e42b2706ca29b20f768929d458c7f245fdd" +dependencies = [ + "proc-macro2", + "swift-bridge-ir", + "syn", + "tempfile", +] + +[[package]] +name = "swift-bridge-ir" +version = "0.1.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28407ee88b57fac3e8c9314a0eefb1f63a3743cb0beef4b8d93189d5d8ce0f1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "swift-bridge-macro" +version = "0.1.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e69ec9898b591cfcf473a584e98b54517400dcc67b0d3f8fdf2a099ce7971e3a" +dependencies = [ + "proc-macro2", + "quote", + "swift-bridge-ir", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[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.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[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.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[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.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/src/tpm/macos/swift_rust_wrapper/Cargo.toml b/src/tpm/macos/swift_rust_wrapper/Cargo.toml new file mode 100755 index 00000000..92b51f79 --- /dev/null +++ b/src/tpm/macos/swift_rust_wrapper/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "apple-secure-enclave-bindings" +version = "0.1.0" +edition = "2021" +publish = [] + +build = "build.rs" + +[build-dependencies] +swift-bridge-build = "0.1.55" + +[dependencies] +swift-bridge = "0.1.55" + +[lib] +crate-type=["staticlib", "rlib"] + diff --git a/src/tpm/macos/swift_rust_wrapper/README.md b/src/tpm/macos/swift_rust_wrapper/README.md new file mode 100755 index 00000000..ffe3eb3b --- /dev/null +++ b/src/tpm/macos/swift_rust_wrapper/README.md @@ -0,0 +1,12 @@ +# Rust Binary calls Swift Package + +In this example we create a Rust binary that statically links to a Swift Package. + +This means that we: + +1. Use `swift-bridge-build` to generate our Swift FFI layer. + +2. Compile the Swift Package into a static library. We include our generated `swift-bridge` FFI glue from step 1. + +3. Compile our Rust executable. Along the way we link to our Swift static library. + diff --git a/src/tpm/macos/swift_rust_wrapper/binaryknights.entitlements b/src/tpm/macos/swift_rust_wrapper/binaryknights.entitlements new file mode 100755 index 00000000..94c42fa4 --- /dev/null +++ b/src/tpm/macos/swift_rust_wrapper/binaryknights.entitlements @@ -0,0 +1,20 @@ + + + + + com.apple.application-identifier + R7Y6NESEQW.de.jssoft.BinaryKnights + com.apple.developer.team-identifier + R7Y6NESEQW + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + com.apple.security.get-task-allow + + keychain-access-groups + + R7Y6NESEQW.de.jssoft.BinaryKnights + + + \ No newline at end of file diff --git a/src/tpm/macos/swift_rust_wrapper/build.rs b/src/tpm/macos/swift_rust_wrapper/build.rs new file mode 100755 index 00000000..5b28248b --- /dev/null +++ b/src/tpm/macos/swift_rust_wrapper/build.rs @@ -0,0 +1,114 @@ +use std::{path::PathBuf, process::Command, env}; +fn main() { + + let mut ios = false; + let mut sdk_name = "macosx"; + let target = String::from(env::var("TARGET").unwrap()); + + if target.contains("ios") { + ios = true; + sdk_name = "iphoneos"; + } + + // 1. Use `swift-bridge-build` to generate Swift/C FFI glue. + // You can also use the `swift-bridge` CLI. + let bridge_files = vec!["src/lib.rs"]; + swift_bridge_build::parse_bridges(bridge_files) + .write_all_concatenated(swift_bridge_out_dir(), "rust-calls-swift"); + + // 2. Compile Swift library and set name for linking library + compile_swift(ios); + + println!( + "cargo:rustc-link-search={}", + swift_library_static_lib_dir(ios).to_str().unwrap() + ); + + // Without this we will get warnings about not being able to find dynamic libraries, and then + // we won't be able to compile since the Swift static libraries depend on them: + // For example: + // ld: warning: Could not find or use auto-linked library 'swiftCompatibility51' + // ld: warning: Could not find or use auto-linked library 'swiftCompatibility50' + // ld: warning: Could not find or use auto-linked library 'swiftCompatibilityDynamicReplacements' + // ld: warning: Could not find or use auto-linked library 'swiftCompatibilityConcurrency' + let xcode_path = if let Ok(output) = std::process::Command::new("xcode-select") + .arg("--print-path") + .output() + { + String::from_utf8(output.stdout.as_slice().into()) + .unwrap() + .trim() + .to_string() + } else { + "/Applications/Xcode.app/Contents/Developer".to_string() + }; + + println!( + "cargo:rustc-link-search={}/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/{}/", + &xcode_path, &sdk_name + ); + + println!("cargo:rustc-link-search={}", "/usr/lib/swift"); +} + +fn compile_swift(ios: bool) { + let swift_package_dir = manifest_dir().join("swift-library"); + let mut bash_cmd = Command::new("bash"); + if ios{ + bash_cmd.current_dir(swift_package_dir).args(&["./compile.sh", "ios"]); + println!("cargo:rustc-link-lib=static=swift-library_ios"); + + }else{ + bash_cmd.current_dir(swift_package_dir).args(&["./compile.sh", "macos"]); + println!("cargo:rustc-link-lib=static=swift-library"); + } + + let exit_status = bash_cmd.spawn().unwrap().wait_with_output().unwrap(); + + if !exit_status.status.success() { + panic!( + r#" +Stderr: {} +Stdout: {} +"#, + String::from_utf8(exit_status.stderr).unwrap(), + String::from_utf8(exit_status.stdout).unwrap(), + ) + } +} + +fn swift_bridge_out_dir() -> PathBuf { + generated_code_dir() +} + +fn manifest_dir() -> PathBuf { + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + PathBuf::from(manifest_dir) +} + +fn is_release_build() -> bool { + std::env::var("PROFILE").unwrap() == "release" +} + +fn swift_source_dir() -> PathBuf { + manifest_dir().join("swift-library/Sources/swift-library") +} + +fn generated_code_dir() -> PathBuf { + swift_source_dir().join("generated") +} + +fn swift_library_static_lib_dir(ios: bool) -> PathBuf { + let debug_or_release = if is_release_build() { + "release" + } else { + "debug" + }; + + if ios{ + manifest_dir().join(format!("swift-library/.build/")) + }else{ + manifest_dir().join(format!("swift-library/.build/{}", debug_or_release)) + + } +} diff --git a/src/tpm/macos/swift_rust_wrapper/src/lib.rs b/src/tpm/macos/swift_rust_wrapper/src/lib.rs new file mode 100755 index 00000000..95afe577 --- /dev/null +++ b/src/tpm/macos/swift_rust_wrapper/src/lib.rs @@ -0,0 +1,56 @@ +#[swift_bridge::bridge] +pub mod ffi { + // Swift-Methods can be used in Rust + extern "Swift" { + //Provider operations + fn initialize_module() -> bool; + fn rustcall_create_key(key_id: String, key_type: String) -> (bool, String); + fn rustcall_load_key(key_id: String, key_type: String, hash: String) -> (bool, String); + + //Keyhandle operations + fn rustcall_encrypt_data(key_id: String, data: Vec, algorithm: String, hash: String) -> (bool, String); + fn rustcall_decrypt_data(key_id: String, data: Vec, algorithm: String, hash: String) -> (bool, String); + fn rustcall_sign_data(key_id: String, data: Vec, algorithm: String, hash: String) -> (bool, String); + fn rustcall_verify_signature(key_id: String, data: Vec, signature: Vec, algorithm: String, hash: String) -> (bool, String); + } +} + +/** + * + * + * + */ +pub mod provider { + use crate::ffi; + + pub fn rust_crypto_call_create_key(key_id: String, key_type: String) -> (bool, String) { + ffi::rustcall_create_key(key_id, key_type) + } + + pub fn rust_crypto_call_load_key(key_id: String, key_type: String, hash: String) -> (bool, String) { + ffi::rustcall_load_key(key_id, key_type, hash) + } + + pub fn rust_crypto_call_initialize_module() -> bool { + ffi::initialize_module() + } +} + +pub mod keyhandle { + use crate::ffi; + pub fn rust_crypto_call_encrypt_data(key_id: String, data: Vec, algorithm: String, hash: String) -> (bool, String) { + ffi::rustcall_encrypt_data(key_id, data, algorithm, hash) + } + + pub fn rust_crypto_call_decrypt_data(key_id: String, data: Vec, algorithm: String, hash: String) -> (bool, String) { + ffi::rustcall_decrypt_data(key_id, data, algorithm, hash) + } + + pub fn rust_crypto_call_sign_data(key_id: String, data: Vec, algorithm: String, hash: String) -> (bool, String) { + ffi::rustcall_sign_data(key_id, data, algorithm, hash) + } + + pub fn rust_crypto_call_verify_signature(key_id: String, string_data: Vec, string_signature: Vec, algorithm: String, hash: String) -> (bool, String) { + ffi::rustcall_verify_signature(key_id, string_data, string_signature, algorithm, hash) + } +} diff --git a/src/tpm/macos/swift_rust_wrapper/swift-library/Package.swift b/src/tpm/macos/swift_rust_wrapper/swift-library/Package.swift new file mode 100755 index 00000000..292452d1 --- /dev/null +++ b/src/tpm/macos/swift_rust_wrapper/swift-library/Package.swift @@ -0,0 +1,19 @@ +// swift-tools-version: 5.5 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "swift-library", + products: [ + .library(name: "swift-library", type: .static, targets: ["swift-library"]), + ], + dependencies: [ + ], + targets: [ + .target( + name: "swift-library", + dependencies: [] + ) + ] +) diff --git a/src/tpm/macos/swift_rust_wrapper/swift-library/Sources/swift-library/SecureEnclaveManager.swift b/src/tpm/macos/swift_rust_wrapper/swift-library/Sources/swift-library/SecureEnclaveManager.swift new file mode 100755 index 00000000..afd76d8d --- /dev/null +++ b/src/tpm/macos/swift_rust_wrapper/swift-library/Sources/swift-library/SecureEnclaveManager.swift @@ -0,0 +1,539 @@ +import Foundation +import LocalAuthentication +import Security +import CryptoKit + + /** + Creates a new cryptographic key pair in the Secure Enclave. + + - Parameter keyID: A String used to identify the private key. + - Parameter algorithm: A 'CFString' data type representing the algorithm used to create the key pair. + - Parameter keySize: A String representing the size of the key. + - Throws: 'SecureEnclaveError.CreateKeyError' if a new public-private key pair could not be generated. + - Returns: A 'SEKeyPair' containing the public and private key on success, or a 'SecureEnclaveError' on failure. + */ + func create_key(key_id: String, algorithm: CFString, key_size: String ) throws -> SEKeyPair? { + let accessControl = create_access_control_object() + let params: [String: Any]; + if algorithm == kSecAttrKeyTypeRSA{ // Asymmetric Encryption + params = + [kSecAttrKeyType as String: algorithm, + kSecAttrKeySizeInBits as String: key_size, + kSecPrivateKeyAttrs as String: [ + kSecAttrIsPermanent as String: false, + kSecAttrApplicationTag as String: key_id, + kSecAttrAccessControl as String: accessControl, + ] + ] + }else{ + let privateKeyParams: [String: Any] = [ + kSecAttrLabel as String: key_id, + kSecAttrIsPermanent as String: true, + kSecAttrAccessControl as String: accessControl, + ] + params = [ + kSecAttrKeyType as String: algorithm, + kSecAttrKeySizeInBits as String: key_size, + kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave, + kSecPrivateKeyAttrs as String: privateKeyParams + ] + } + + var error: Unmanaged? + guard let privateKeyReference = SecKeyCreateRandomKey(params as CFDictionary, &error) else { + throw SecureEnclaveError.CreateKeyError("A new public-private key pair could not be generated. \(String(describing: error))") + } + + guard let publicKey = get_public_key_from_private_key(private_key: privateKeyReference) else { + throw SecureEnclaveError.CreateKeyError("Public key could not be received from the private key. \(String(describing: error))") + } + + let keyPair = SEKeyPair(publicKey: publicKey, privateKey: privateKeyReference) + + do{ + try storeKey_Keychain(key_id, privateKeyReference) + }catch{ + throw SecureEnclaveError.CreateKeyError("The key could not be stored successfully into the keychain. \(String(describing: error))") + } + return keyPair + } + + + /** + Optimized method of @create_key() to communicate with the rust-side abstraction-layer. + + - Parameter key_id: A 'RustString' data type used to identify the private key. + - Parameter key_type - A 'RustString' data type used to represent the algorithm that is used to create the key pair. + - Returns: A boolean representing if a error occured and a String representing the private and public key, or an error as a String on failure. + */ + func rustcall_create_key(key_id: RustString, key_type: RustString) -> (Bool, String) { + // For Secure Enclave is only ECC supported + let algorithm = String(key_type.toString().split(separator: ";")[0]) + let keySize = String(key_type.toString().split(separator:";")[1]) + do{ + let algorithm = try get_key_type(key_type: algorithm); + let keyPair = try create_key(key_id: key_id.toString(), algorithm: algorithm, key_size: keySize) + return (false,("Private Key: "+String((keyPair?.privateKey.hashValue)!) + "\nPublic Key: " + String((keyPair?.publicKey.hashValue)!))) + }catch{ + return (true,"Error: \(String(describing: error))") + } + } + + + /** + Creates an access control object for a cryptographic operation. + + - Returns: A 'SecAccessControl' configured for private key usage. + */ + func create_access_control_object() -> SecAccessControl { + let access = SecAccessControlCreateWithFlags( + kCFAllocatorDefault, + kSecAttrAccessibleWhenUnlockedThisDeviceOnly, + .privateKeyUsage, + nil)! + + return access + } + + + /** + Encrypts data using a public key. + + - Parameter data: CFData that has to be encrypted. + - Parameter public_key: A 'SecKey' data type representing a cryptographic public key. + - Parameter algorithm: A 'SecKeyAlgorithm' data type representing the algorithm used to encrypt the data. + - Throws: 'SecureEnclaveError.EncryptionError' if the data could not be encrypted. + - Returns: CFData that has been encrypted. + */ + func encrypt_data(data: CFData, public_key: SecKey, algorithm: SecKeyAlgorithm) throws -> CFData? { + let algorithm = algorithm + var error: Unmanaged? + let result = SecKeyCreateEncryptedData(public_key, algorithm, data, &error) + + if result == nil { + throw SecureEnclaveError.EncryptionError("Data could not be encrypted. \(String(describing: error))") + } + + return result + } + + + /** + Optimized method of @encrypt_data() to communicate with the rust-side abstraction-layer. + + - Parameter key_id: A 'RustString' data type used to identify the private key. + - Parameter data: A 'RustVec' data type used to represent the data that has to be encrypted as a Rust-Vector. + - Parameter algorithm: A 'RustString' data type used to represent the algorithm that is used to encrypt the data. + - Parameter hash: A 'RustString' data type used to represent the hash that is used. + - Returns: A boolean representing if a error occured and a String representing the encrypted data, or an error as a String on failure. + */ + func rustcall_encrypt_data(key_id: RustString, data: RustVec, algorithm: RustString, hash: RustString) -> (Bool, String) { + do{ + let key_type = try get_key_type(key_type: algorithm.toString()) + let privateKey: SecKey = try load_key(key_id: key_id.toString(), algorithm: key_type)! + let publicKey = get_public_key_from_private_key(private_key: privateKey) + let algorithm = try get_encrypt_algorithm(algorithm: algorithm.toString(), hash: hash.toString()) + try check_algorithm_support(key: get_public_key_from_private_key(private_key: publicKey!)!, operation: SecKeyOperationType.encrypt, algorithm: algorithm) + + let encryptedData: Data = try encrypt_data(data: Data(data) as CFData, public_key: publicKey!, algorithm: algorithm)! as Data + + let encryptedData_string = encryptedData.base64EncodedString(options: []) + return (false, encryptedData_string) + }catch{ + return (true, "Error: \(String(describing: error))") + } + } + + /** + Decrypts data using a private key. + + - Parameter data: Encrypted (CF)data that has to be decrypted. + - Parameter privateKey: A 'SecKey' data type representing a cryptographic private key. + - Parameter algorithm: A 'SecKeyAlgorithm' data type representing the algorithm used to decrypt the data. + - Throws: 'SecureEnclaveError.DecryptionError' if the data could not be decrypted. + - Returns: Data that has been decrypted. + */ + func decrypt_data(data: CFData, private_key: SecKey, algorithm: SecKeyAlgorithm) throws -> CFData? { + var error: Unmanaged? + let result = SecKeyCreateDecryptedData(private_key, algorithm, data, &error) + if result == nil { + throw SecureEnclaveError.DecryptionError("Data could not be decrypted. \(String(describing: error))") + } + return result + } + + /** + Optimized method of @decrypt_data() to communicate with the rust-side abstraction-layer. + + - Parameter key_id: A 'RustString' data type used to identify the private key. + - Parameter data: A 'RustVec' data type used to represent the data that has to be decrypted as a Rust-Vector. + - Parameter algorithm: A 'RustString' data type used to represent the algorithm that is used to decrypt the data. + - Parameter hash: A 'RustString' data type used to represent the hash that is used. + - Returns: A boolean representing if a error occured and a String representing the decrypted data, or an error as a String on failure. + */ + func rustcall_decrypt_data(key_id: RustString, data: RustVec, algorithm: RustString, hash: RustString) -> (Bool, String) { + do{ + let seckey_algorithm_enum = try get_encrypt_algorithm(algorithm: algorithm.toString(), hash: hash.toString()) + let key_type = try get_key_type(key_type: algorithm.toString()) + let data_cfdata = Data(base64Encoded: Data(data), options: [])! as CFData + let private_key = try load_key(key_id: key_id.toString(), algorithm: key_type)! + try check_algorithm_support(key: private_key, operation: SecKeyOperationType.decrypt, algorithm: seckey_algorithm_enum) + + let decrypted_data = try (decrypt_data(data: data_cfdata, private_key: private_key, algorithm: seckey_algorithm_enum))! as Data + + return (false, String(data: decrypted_data, encoding: String.Encoding.ascii)!) + } catch { + return (true, "Error: \(String(describing: error))") + } + } + + + /** + Retrieves the public key associated with a given private key. + + - Parameter privateKey: A 'SecKey' data type representing a cryptographic private key. + - Returns: Optionally a public key representing a cryptographic public key on success, or 'nil' on failure. + */ + func get_public_key_from_private_key(private_key: SecKey) -> SecKey? { + return SecKeyCopyPublicKey(private_key) + } + + + /** + Signs data using a private key. + + - Parameter data: CFData that has to be signed. + - Parameter privateKeyReference: A 'SecKey' data type representing a cryptographic private key. + - Parameter algorithm: A 'SecKeyAlgorithm' data type representing the algorithm used to sign the data. + - Throws: 'SecureEnclaveError.SigningError' if the data could not be signed. + - Returns: Optionally data that has been signed as a CFData data type on success, or 'nil' on failure. + */ + func sign_data(data: CFData, privateKey: SecKey, algorithm: SecKeyAlgorithm) throws -> CFData? { + let sign_algorithm = algorithm; + var error: Unmanaged? + guard let signed_data = SecKeyCreateSignature(privateKey, sign_algorithm, data, &error) + else{ + throw SecureEnclaveError.SigningError("Data could not be signed: \(String(describing: error))") + } + return signed_data + } + + + /** + Optimized method of @sign_data() to communicate with the rust-side abstraction-layer. + + - Parameter key_id: A 'RustString' data type used to identify the private key. + - Parameter data: A 'RustVec' data type used to represent the data that has to be signed as a Rust-Vector. + - Parameter algorithm: A 'RustString' data type used to represent the algorithm that is used to sign the data. + - Parameter hash: A 'RustString' data type used to represent the hash that is used. + - Returns: A boolean representing if a error occured and a String representing the signed data, or an error as a String on failure. + */ + func rustcall_sign_data(key_id: RustString, data: RustVec, algorithm: RustString, hash: RustString) -> (Bool, String){ + let privateKeyName_string = key_id.toString() + // let data_cfdata = data.toString().data(using: String.Encoding.utf8)! as CFData + let data_cfdata = Data(data) as CFData; + + do { + let seckey_algorithm_enum = try get_sign_algorithm(algorithm: algorithm.toString(), hash: hash.toString()) + let key_type = try get_key_type(key_type: algorithm.toString()) as CFString + let privateKeyReference = try load_key(key_id: privateKeyName_string, algorithm: key_type)! + try check_algorithm_support(key: privateKeyReference, operation: SecKeyOperationType.sign, algorithm: seckey_algorithm_enum) + let signed_data = try ((sign_data(data: data_cfdata, privateKey: privateKeyReference, algorithm: seckey_algorithm_enum))! as Data) + return (false, signed_data.base64EncodedString(options: [])) + }catch{ + return (true, "Error: \(String(describing: error))") + } + } + + + /** + Verifies a signature using a public key. + + - Parameter publicKey: A 'SecKey' data type representing a cryptographic public key. + - Parameter data: A CFData-Type of the data that has to be verified. + - Parameter signature: A CFData-Type of the signature that has to be verified. + - Parameter sign_algorithm: A 'SecKeyAlgorithm' data type representing the algorithm used to verify the signature. + - Throws: 'SecureEnclaveError.SignatureVerificationError' if the signature could not be verified. + - Returns: A boolean if the signature is valid ('true') or not ('false'). + */ + func verify_signature(public_key: SecKey, data: CFData, signature: CFData, sign_algorithm: SecKeyAlgorithm) throws -> Bool { + let sign_algorithm = sign_algorithm + + var error: Unmanaged? + if SecKeyVerifySignature(public_key, sign_algorithm, data, signature, &error){ + return true + } else{ + return false + } + } + + + /** + Optimized method of @verify_data() to communicate with the rust-side abstraction-layer. + + - Parameter key_id: A 'RustString' data type used to identify the public key. + - Parameter data: A 'RustVec' data type used to represent the data that has to be verified with the signature as a Rust-Vector. + - Parameter signature: A 'RustVec' data type used to represent the signature of the signed data as a Rust-Vector. + - Parameter algorithm: A 'RustString' data type used to represent the algorithm that is used to verify the signature. + - Parameter hash: A 'RustString' data type used to represent the hash that is used. + - Returns: A boolean representing if a error occured and a String representing the verify status, or an error as a String on failure. + */ + func rustcall_verify_signature(key_id: RustString, data: RustVec, signature: RustVec, algorithm: RustString, hash: RustString) -> (Bool, String) { + do{ + let publicKeyName_string = key_id.toString() + let data_cfdata = Data(data) as CFData; + let signature_cfdata = Data(base64Encoded: Data(signature), options: [])! as CFData + + guard Data(base64Encoded: Data(signature)) != nil else{ + throw SecureEnclaveError.SignatureVerificationError("Invalid message to verify.)") + } + + //Get Algorithm enums + let seckey_algorithm_enum = try get_sign_algorithm(algorithm: algorithm.toString(), hash: hash.toString()) + let key_type = try get_key_type(key_type: algorithm.toString()) + + guard let publicKey = get_public_key_from_private_key(private_key: try load_key(key_id: publicKeyName_string, algorithm: key_type)!)else{ + throw SecureEnclaveError.SignatureVerificationError("Public key could not be received from the private key.)") + } + + try check_algorithm_support(key: publicKey, operation: SecKeyOperationType.verify, algorithm: seckey_algorithm_enum) + let status = try verify_signature(public_key: publicKey, data: data_cfdata, signature: signature_cfdata, sign_algorithm: seckey_algorithm_enum) + + if status == true{ + return (false,"true") + }else{ + return (false,"false") + } + }catch{ + return (true,"Error: \(String(describing: error))") + } + } + + + /// Represents errors that can occur within 'SecureEnclaveManager'. + enum SecureEnclaveError: Error { + case runtimeError(String) + case SigningError(String) + case DecryptionError(String) + case EncryptionError(String) + case SignatureVerificationError(String) + case InitializationError(String) + case CreateKeyError(String) + case LoadKeyError(String) + } + + /// Represents a pair of cryptographic keys, both the public key and the private key are objects of the data type 'SecKey'. + struct SEKeyPair { + let publicKey: SecKey + let privateKey: SecKey + } + + + /** + Loads a cryptographic private key from the keychain. + + - Parameter key_id: A String used as the identifier for the key. + - Parameter algo: A 'CFString' data type representing the algorithm used to create the key pair. + - Throws: 'SecureEnclaveError.LoadKeyError' if the key could not be found. + - Returns: Optionally the key as a SecKey data type on success, or a nil on failure. + */ + func load_key(key_id: String, algorithm: CFString) throws -> SecKey? { + let tag = key_id + let query: [String: Any] = [ + kSecClass as String : kSecClassKey, + kSecAttrApplicationTag as String : tag, + kSecAttrKeyType as String : algorithm, + kSecReturnRef as String : true + ] + + var item: CFTypeRef? + let status = SecItemCopyMatching(query as CFDictionary, &item) + guard status == errSecSuccess else { + throw SecureEnclaveError.LoadKeyError("Key could not be found.)") + } + return (item as! SecKey) + } + + + /** + Optimized method of @load_key() to communicate with the rust-side abstraction-layer. + + - Parameter key_id: A 'RustString' data type used to identify the private key. + - Parameter key_type - A 'RustString' data type used to represent the algorithm that is used to create the key pair. + - Parameter hash - A 'RustString' data type used to represent the hash that is used. + - Returns: A boolean representing if a error occured and a String representing the private key, or an error as a String on failure. + */ + func rustcall_load_key(key_id: RustString, key_type: RustString, hash: RustString) -> (Bool, String) { + do { + let key_algorithm = try get_key_type(key_type: key_type.toString()) + + guard let key = try load_key(key_id: key_id.toString(), algorithm: key_algorithm) else { + return (true,"Key with KeyID \(key_id) could not be found.") + } + + return (false,"\(key.hashValue)") + } catch { + return (true,"Error: \(key_type.toString()) + \(String(describing: error))") + } + } + + + /** + Stores a cryptographic key in the keychain. + + - Parameter name: A String used to identify the key in the keychain. + - Parameter privateKey: A 'SecKey' data type representing a cryptographic private key. + - Throws: 'SecureEnclaveError.CreateKeyError' if the key could not be stored. + */ + func storeKey_Keychain(_ name: String, _ private_key: SecKey) throws { + let key = private_key + let tag = name.data(using: .utf8)! + let addquery: [String: Any] = [kSecClass as String: kSecClassKey, + kSecAttrApplicationTag as String: tag, + kSecValueRef as String: key] + + let status = SecItemAdd(addquery as CFDictionary, nil) + guard status == errSecSuccess + else { + throw SecureEnclaveError.CreateKeyError("Failed to store Key in the Keychain.") + } + } + + /** + Initializes a module by creating a private key and the associated private key. + Optimized to communicate with the rust-side abstraction-layer. + + - Returns: A boolean if the module has been inizializes correctly on success ('true') or not ('false'), or a 'SecureEnclaveError' on failure. + */ + func initialize_module() -> Bool { + do { + if #available(macOS 10.15, iOS 14.0, *) { + guard SecureEnclave.isAvailable else { + throw SecureEnclaveError.runtimeError("Secure Enclave is unavailable on this device. Please make sure you are using a device with Secure Enclave and macOS higher 10.15 or iOS higher 14.0") + } + return true + } else { + return false + } + }catch{ + return false + } + } + + /** + Checks if the algorithm is supported. + + - Parameter key: A 'SecKey' data type representing a cryptographic key. + */ + func check_algorithm_support(key: SecKey, operation: SecKeyOperationType, algorithm: SecKeyAlgorithm) throws { + var operation_string: String; + switch operation{ + case SecKeyOperationType.encrypt: + operation_string = "encrypt" + case SecKeyOperationType.decrypt: + operation_string = "decrypt" + case SecKeyOperationType.sign: + operation_string = "sign" + case SecKeyOperationType.verify: + operation_string = "verify" + default: + operation_string = "Noting" + } + //Key usage is going to be implemented. + if !SecKeyIsAlgorithmSupported(key, operation, algorithm){ + throw SecureEnclaveError.EncryptionError("Given Keytype and algorithm do not support the \(operation_string) operation. Please choose other keytype or algorithm.") + } + } + + + /** + Retrieves the type of the key, representing which algorithm is used. + + - Parameter key_type: A String representing the algorithm used to create the key pair. + - Throws: 'SecureEnclaveError.CreateKeyError' if the key algorithm is not supported. + - Returns: A 'CFString' representing the algorithm used to create the key pair. + */ + func get_key_type(key_type: String) throws -> CFString { + switch key_type{ + case "RSA": + return kSecAttrKeyTypeRSA + /* According documentation of Apple, kSecAttrKeyTypeECDSA is deprecated. + Suggesting to use kSecAttrKeyTypeECSECPrimeRandom instead.*/ + case "ECDSA": + return kSecAttrKeyTypeECSECPrimeRandom + default: + throw SecureEnclaveError.CreateKeyError("Key Algorithm is not supported.)") + } + } + + + /** + Retrieves the algorithm used for signing and verifying. + + - Parameter algorithm: A String representing the algorithm. + - Parameter hash: A String representing the hash that is used. + - Throws: 'SecureEnclaveError.SigningError' if the hash for signing is not supported. + - Returns: A 'SecKeyAlgorithm' representing the algorithm used for signing and verifying. + */ + func get_sign_algorithm(algorithm: String, hash: String) throws -> SecKeyAlgorithm{ + let apple_algorithm_enum: SecKeyAlgorithm; + if algorithm == "RSA"{ + switch hash { + case "SHA224": + apple_algorithm_enum = SecKeyAlgorithm.rsaSignatureMessagePSSSHA224 + case "SHA256": + apple_algorithm_enum = SecKeyAlgorithm.rsaSignatureMessagePSSSHA256 + case "SHA384": + apple_algorithm_enum = SecKeyAlgorithm.rsaSignatureMessagePSSSHA384 + default: + throw SecureEnclaveError.SigningError("Hash for asymmetric signing with RSA is not supported.)") + } + return apple_algorithm_enum + }else if algorithm == "ECDSA"{ + switch hash { + case "SHA224": + apple_algorithm_enum = SecKeyAlgorithm.ecdsaSignatureMessageX962SHA224 + case "SHA256": + apple_algorithm_enum = SecKeyAlgorithm.ecdsaSignatureMessageX962SHA256 + case "SHA384": + apple_algorithm_enum = SecKeyAlgorithm.ecdsaSignatureMessageX962SHA384 + default: + throw SecureEnclaveError.SigningError("Hash for asymmetric signing with ECDSA is not supported.)") + } + return apple_algorithm_enum + } + else{ + throw SecureEnclaveError.SigningError("Algorithm for Encryption/Decryption not supported. Only RSA or ECDSA)") + } + } + + + /** + Retrieves the algorithm used for encryption and decryption. + + - Parameter algorithm: A String representing the algorithm. + - Parameter hash: A String representing the hash that is used. + - Throws: 'SecureEnclaveError.EncryptionError' if the hash for encryption is not supported. + - Returns: A 'SecKeyAlgorithm' representing the algorithm used for encryption and decryption. + */ + func get_encrypt_algorithm(algorithm: String, hash: String) throws -> SecKeyAlgorithm{ + let apple_algorithm_enum: SecKeyAlgorithm; + + if algorithm == "RSA"{ + switch hash { + case "SHA1": + apple_algorithm_enum = SecKeyAlgorithm.rsaEncryptionOAEPSHA1 + case "SHA224": + apple_algorithm_enum = SecKeyAlgorithm.rsaEncryptionOAEPSHA224 + case "SHA256": + apple_algorithm_enum = SecKeyAlgorithm.rsaEncryptionOAEPSHA256 + case "SHA384": + apple_algorithm_enum = SecKeyAlgorithm.rsaEncryptionOAEPSHA384 + default: + throw SecureEnclaveError.EncryptionError("Hash for Encryption/Decryption is not supported.)") + } + return apple_algorithm_enum + }else{ + throw SecureEnclaveError.EncryptionError("Algorithm for Encryption/Decryption not supported.))") + } + } diff --git a/src/tpm/macos/swift_rust_wrapper/swift-library/Sources/swift-library/bridging-header.h b/src/tpm/macos/swift_rust_wrapper/swift-library/Sources/swift-library/bridging-header.h new file mode 100755 index 00000000..8a141dde --- /dev/null +++ b/src/tpm/macos/swift_rust_wrapper/swift-library/Sources/swift-library/bridging-header.h @@ -0,0 +1,7 @@ +#ifndef BRIDGING_HEADER_H +#define BRIDGING_HEADER_H + +#import "./generated/SwiftBridgeCore.h" +#import "./generated/rust-calls-swift/rust-calls-swift.h" + +#endif BRIDGING_HEADER_H diff --git a/src/tpm/macos/swift_rust_wrapper/swift-library/compile.sh b/src/tpm/macos/swift_rust_wrapper/swift-library/compile.sh new file mode 100755 index 00000000..09bb0cc8 --- /dev/null +++ b/src/tpm/macos/swift_rust_wrapper/swift-library/compile.sh @@ -0,0 +1,64 @@ + +compile_files_path='.build/libswift-library_ios.a Sources/swift-library/SecureEnclaveManager.swift Sources/swift-library/generated/SwiftBridgeCore.swift Sources/swift-library/generated/rust-calls-swift/rust-calls-swift.swift' +compile_header_path='Sources/swift-library/bridging-header.h' + +regex_file_path='\.build/libswift-library_ios\.a (Sources/[a-zA-Z_/-]+\.swift )+' +regex_header_path='^Sources\/[a-zA-Z0-9_-]+\/bridging-header\.h$' + +TARGET=$1 + +file_path_valid=true +is_valid_file_path() { + if echo "$compile_files_path" | grep -qE "$regex_file_path"; then + echo "valid files path" + file_path_valid=true # valid file path + else + echo "unvalid header path" + file_path_valid=false # unvalid file path + fi +} + +headder_path_valid=true +is_valid_header_path() { + if echo "$compile_header_path" | grep -qE "$regex_header_path"; then + echo "valid header path" + headder_path_valid=true # valid header path + else + echo "unvalid header path" + headder_path_valid=false # unvalid header path + fi +} + +is_valid_file_path +is_valid_header_path + +if $file_path_valid && $headder_path_valid; then + if [ $# -eq 0 ]; then + echo "No target as argument given. Please provide 'ios' or 'macos' as target." + exit 1 + fi + + if [ "$TARGET" == "ios" ]; then + swiftc -target arm64-apple-ios14.0 \ + -sdk $(xcrun --sdk iphoneos --show-sdk-path) \ + -emit-library -static -F /swift-library \ + -o $compile_files_path \ + -import-objc-header $compile_header_path \ + + echo "Compiled for: $TARGET" + + elif [ "$TARGET" == "macos" ]; then + swift build \ + -Xswiftc -static \ + -Xswiftc -import-objc-header \ + -Xswiftc $compile_header_path \ + + echo "Compiled for: $TARGET" + + else + echo "No valid target as argument. Please choose 'ios' or 'macos' as targets." + fi +else + echo "Error. Minimum one parameter is unvalid." + exit 1 +fi diff --git a/src/tpm/mod.rs b/src/tpm/mod.rs index 96746325..4fc6591f 100644 --- a/src/tpm/mod.rs +++ b/src/tpm/mod.rs @@ -41,7 +41,7 @@ impl TpmConfig { sym_algorithm: BlockCiphers, hash: Hash, key_usages: Vec, - ) -> Box { + ) -> Box { Box::new(Self { key_algorithm, sym_algorithm, diff --git a/src/tpm/win/provider.rs b/src/tpm/win/provider.rs index 1eac8ccc..da67aa26 100644 --- a/src/tpm/win/provider.rs +++ b/src/tpm/win/provider.rs @@ -6,10 +6,11 @@ use crate::{ KeyUsage, }, error::SecurityModuleError, - traits::{module_provider::Provider, module_provider_config::ProviderConfig}, + traits::module_provider::Provider, }, tpm::{core::error::TpmError, TpmConfig}, }; +use std::any::Any; use tracing::instrument; use windows::{ core::PCWSTR, @@ -51,9 +52,9 @@ impl Provider for TpmProvider { fn create_key( &mut self, key_id: &str, - config: Box, + config: Box, ) -> Result<(), SecurityModuleError> { - let config = config.as_any().downcast_ref::().unwrap(); + let config = config.downcast_ref::().unwrap(); self.key_algo = Some(config.key_algorithm); self.sym_algo = Some(config.sym_algorithm); @@ -198,12 +199,8 @@ impl Provider for TpmProvider { /// A `Result` that, on success, contains `Ok(())`, indicating that the key was loaded successfully. /// On failure, it returns a `SecurityModuleError`. #[instrument] - fn load_key( - &mut self, - key_id: &str, - config: Box, - ) -> Result<(), SecurityModuleError> { - let config = config.as_any().downcast_ref::().unwrap(); + fn load_key(&mut self, key_id: &str, config: Box) -> Result<(), SecurityModuleError> { + let config = config.downcast_ref::().unwrap(); self.key_algo = Some(config.key_algorithm); self.sym_algo = Some(config.sym_algorithm); @@ -304,13 +301,7 @@ impl Provider for TpmProvider { /// A `Result` that, on success, contains `Ok(())`, indicating that the module was initialized successfully. /// On failure, it returns a `SecurityModuleError`. #[instrument] - fn initialize_module( - &mut self, - key_algorithm: AsymmetricEncryption, - sym_algorithm: Option, - hash: Option, - key_usages: Vec, - ) -> Result<(), SecurityModuleError> { + fn initialize_module(&mut self) -> Result<(), SecurityModuleError> { let mut handle = NCRYPT_PROV_HANDLE::default(); if unsafe { NCryptOpenStorageProvider(&mut handle, MS_PLATFORM_CRYPTO_PROVIDER, 0) } @@ -319,12 +310,6 @@ impl Provider for TpmProvider { return Err(TpmError::Win(windows::core::Error::from_win32()).into()); } - self.handle = Some(handle); - self.key_algo = Some(key_algorithm); - self.sym_algo = sym_algorithm; - self.hash = hash; - self.key_usages = Some(key_usages); - Ok(()) } }