From 505a6909e8bdb59cbb31cfc5cad4a8ba3051fd90 Mon Sep 17 00:00:00 2001 From: Louis Hampton Date: Sun, 28 Jun 2026 10:37:35 +0100 Subject: [PATCH] Add support for X448/Ed448 and P521 --- Cargo.lock | 414 ++++++++++++++------------------------------ Cargo.toml | 3 + src/kx.rs | 42 ++++- src/sign.rs | 12 +- src/sign/ecdsa.rs | 1 + src/sign/eddsa.rs | 45 +++++ src/verify.rs | 8 +- src/verify/ecdsa.rs | 1 + src/verify/eddsa.rs | 30 ++++ 9 files changed, 261 insertions(+), 295 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c709b2..8bec600 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aead" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef60ac202874e574ce7a7158cc8bca7313dd344322482e4fadee288bf4a306b8" +checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99" dependencies = [ "crypto-common", "inout", @@ -37,12 +37,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "anyhow" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" - [[package]] name = "autocfg" version = "1.5.1" @@ -61,12 +55,6 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" -[[package]] -name = "bitflags" -version = "2.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" - [[package]] name = "block-buffer" version = "0.12.1" @@ -78,9 +66,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.63" +version = "1.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" +checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" dependencies = [ "find-msvc-tools", "shlex", @@ -94,9 +82,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chacha20" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" dependencies = [ "cfg-if", "cipher", @@ -155,9 +143,9 @@ dependencies = [ [[package]] name = "crypto-bigint" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a0d26b245348befa0c121944541476763dcc46ede886c88f9d12e1697d27c3" +checksum = "1a52aa3fcda4e6302a9f48734f234d35d4721b96f8fe07d073f07ce9df4f0271" dependencies = [ "cpubits", "ctutils", @@ -210,9 +198,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "5.0.0-rc.0" +version = "5.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f359e08ca85e7bd759e1fd933ff2bccd81864c60a8fba0e259c7f822b0924bf" +checksum = "c906a87e53a36ff795d72e06e8162a83c5436e3ea89e942a9cb9fc083f0a384f" dependencies = [ "cfg-if", "cpufeatures", @@ -260,9 +248,9 @@ dependencies = [ [[package]] name = "ecdsa" -version = "0.17.0-rc.19" +version = "0.17.0-rc.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcddae1289a08e614a83d155a070f54c1803196e92089b8299e2738eb74d3e4" +checksum = "b7c72d1455753a703ad4b90ed2a759f2bc4562024a303176439cf6e593b5ade4" dependencies = [ "der", "digest", @@ -285,9 +273,9 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "3.0.0-rc.0" +version = "3.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b011170fe4f04665565b4110afef66774fe9ffff278f3eb5b81cc73d26e27d60" +checksum = "1685663e23882cd8517dcbcb1c23a6ebff4433c22dfb681d760219b62cd1b849" dependencies = [ "curve25519-dalek", "ed25519", @@ -298,11 +286,36 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ed448" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae112a25f86ae3598d4e8533ed1e65149cec6eb21918e7a6f4c06dddec370263" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed448-goldilocks" +version = "0.14.0-pre.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b805154de2e68f59874ec217ca36790dcffe500cd872c60fe509d28d0814a74d" +dependencies = [ + "ed448", + "elliptic-curve", + "hash2curve", + "rand_core", + "shake", + "signature", + "subtle", +] + [[package]] name = "elliptic-curve" -version = "0.14.0-rc.34" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a44d097c9f3e494ddc19f77af5aab89f0b3b2652cde370ec8c6064faca5bd2" +checksum = "3273f1195b6f6253ebda493d6742c8baa9b26a291674cd96d92a0f09e90e9b46" dependencies = [ "base16ct", "crypto-bigint", @@ -320,12 +333,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - [[package]] name = "ff" version = "0.14.0" @@ -348,12 +355,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "getrandom" version = "0.2.17" @@ -367,16 +368,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", "r-efi", "rand_core", - "wasip2", - "wasip3", ] [[package]] @@ -400,26 +399,15 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.15.5" +name = "hash2curve" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "1eaf40612d7d854743e7189228a6d528f0f6e8502cf6a0cb831d28a218b7f3f6" dependencies = [ - "foldhash", + "digest", + "elliptic-curve", ] -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - [[package]] name = "hkdf" version = "0.13.0" @@ -440,33 +428,15 @@ dependencies = [ [[package]] name = "hybrid-array" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" dependencies = [ "subtle", "typenum", "zeroize", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[package]] -name = "indexmap" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" -dependencies = [ - "equivalent", - "hashbrown 0.17.1", - "serde", - "serde_core", -] - [[package]] name = "inout" version = "0.2.2" @@ -477,16 +447,14 @@ dependencies = [ ] [[package]] -name = "itoa" -version = "1.0.18" +name = "keccak" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa" +dependencies = [ + "cfg-if", + "cpufeatures", +] [[package]] name = "libc" @@ -496,15 +464,9 @@ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "log" -version = "0.4.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" - -[[package]] -name = "memchr" -version = "2.8.1" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "num-traits" @@ -523,9 +485,9 @@ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "p256" -version = "0.14.0-rc.11" +version = "0.14.0-rc.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cfbd444125de5ec2af6c4bc081d932e2ca90497cbd0300f7c862133ea6e27b" +checksum = "c855a8d2ffd346aa03122626f22e96e3aa75e3bfe64e6bf6cb82f71821ed6ae7" dependencies = [ "ecdsa", "elliptic-curve", @@ -536,9 +498,9 @@ dependencies = [ [[package]] name = "p384" -version = "0.14.0-rc.11" +version = "0.14.0-rc.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f97421b5d7307a188830f1fc45688ee3ae7daae97c479019ccc795e78b4ac3b2" +checksum = "62941b68907ddf996ac20f0debf700c236ccc3d874637731a93c631129ca042f" dependencies = [ "ecdsa", "elliptic-curve", @@ -548,6 +510,20 @@ dependencies = [ "sha2", ] +[[package]] +name = "p521" +version = "0.14.0-rc.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd6f2fe6e76c8d5e8828e92aafa463777d1e72e70b78acc724214757e92479a" +dependencies = [ + "base16ct", + "ecdsa", + "elliptic-curve", + "primefield", + "primeorder", + "sha2", +] + [[package]] name = "paste" version = "1.0.15" @@ -604,21 +580,11 @@ dependencies = [ "universal-hash", ] -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn", -] - [[package]] name = "primefield" -version = "0.14.0-rc.11" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d7e42f46a29abc16fb621a3466ee453358ebaae48a9e515f287e0af052ed8f" +checksum = "c555a6e4eb7d4e158fcb028c835c3b8642206ddc279b5c6b202ef9a8bdb592f4" dependencies = [ "crypto-bigint", "crypto-common", @@ -630,11 +596,12 @@ dependencies = [ [[package]] name = "primeorder" -version = "0.14.0-rc.11" +version = "0.14.0-rc.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1576f33b3071d61b06389caf381238dd95ccd2519cd04d788cd52450462eab4" +checksum = "4e56e6d67fdf5744e9e245ae571450fe584b91f5af261d0e40163b618e53a1f6" dependencies = [ "elliptic-curve", + "primefield", ] [[package]] @@ -648,9 +615,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.45" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" dependencies = [ "proc-macro2", ] @@ -721,9 +688,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.40" +version = "0.23.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ "log", "once_cell", @@ -754,10 +721,12 @@ dependencies = [ "digest", "ecdsa", "ed25519-dalek", - "getrandom 0.4.2", + "ed448-goldilocks", + "getrandom 0.4.3", "hmac", "p256", "p384", + "p521", "paste", "pkcs8", "rsa", @@ -767,6 +736,7 @@ dependencies = [ "sha2", "signature", "x25519-dalek", + "x448", ] [[package]] @@ -829,19 +799,6 @@ dependencies = [ "syn", ] -[[package]] -name = "serde_json" -version = "1.0.150" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - [[package]] name = "serdect" version = "0.4.3" @@ -863,6 +820,17 @@ dependencies = [ "digest", ] +[[package]] +name = "shake" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09057cb2149ad4cbd2da1e26b351f9a4c354219421229c69c3063e6f61947c4a" +dependencies = [ + "digest", + "keccak", + "sponge-cursor", +] + [[package]] name = "shlex" version = "2.0.1" @@ -889,6 +857,12 @@ dependencies = [ "der", ] +[[package]] +name = "sponge-cursor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a0219bd7d979d58245a4f41f695e1ac9f8befdffadd7f61f1bae9e39abc6620" + [[package]] name = "subtle" version = "2.6.1" @@ -897,9 +871,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.117" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -918,12 +892,6 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "universal-hash" version = "0.6.1" @@ -946,58 +914,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasip2" -version = "1.0.3+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" -dependencies = [ - "wit-bindgen 0.57.1", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -dependencies = [ - "wit-bindgen 0.51.0", -] - -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap", - "semver", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -1072,118 +988,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "wit-bindgen" -version = "0.51.0" +name = "x25519-dalek" +version = "3.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +checksum = "eee64e8620caa64914d669b1f68f858aaff54e2d0f9ad3b30a613b58a1baa83e" dependencies = [ - "wit-bindgen-rust-macro", + "curve25519-dalek", + "rand_core", + "zeroize", ] [[package]] -name = "wit-bindgen" -version = "0.57.1" +name = "x448" +version = "0.14.0-pre.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +checksum = "1c166d06b9fa4328c890d46bda797269fb6aeca96393aeaad0e74b4b11550e06" dependencies = [ - "anyhow", - "heck", - "wit-parser", + "ed448-goldilocks", + "zeroize", ] [[package]] -name = "wit-bindgen-rust" -version = "0.51.0" +name = "zeroize" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", + "zeroize_derive", ] [[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" +name = "zeroize_derive" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" dependencies = [ - "anyhow", - "prettyplease", "proc-macro2", "quote", "syn", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - -[[package]] -name = "x25519-dalek" -version = "3.0.0-rc.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17b575e04fcdb37e5509a85a14ff08116678a1c9724befb8b571db742dbdbb0" -dependencies = [ - "curve25519-dalek", - "rand_core", - "zeroize", ] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 5ab2c24..c8a066d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ getrandom = { version = "0.4", default-features = false, features = ["sys_rng"] hmac = { version = "0.13", default-features = false } p256 = { version = "0.14.0-rc.9", default-features = false, features = ["pem", "ecdsa", "ecdh"] } p384 = { version = "0.14.0-rc.9", default-features = false, features = ["pem", "ecdsa", "ecdh"] } +p521 = { version = "0.14.0-rc.9", default-features = false, features = ["pem", "ecdsa", "ecdh"] } paste = { version = "1", default-features = false } pkcs8 = { version = "0.11", default-features = false } pki-types = { package = "rustls-pki-types", version = "1", default-features = false } @@ -39,6 +40,8 @@ sec1 = { version = "0.8", default-features = false } sha2 = { version = "0.11", default-features = false } signature = { version = "3", default-features = false } x25519-dalek = { version = "3.0.0-rc.0", default-features = false } +ed448-goldilocks = { version = "0.14.0-pre.15", default-features = false, features = ["signing", "pkcs8"] } +x448 = { version = "0.14.0-pre.12", default-features = false } [features] default = ["std", "tls12", "zeroize"] diff --git a/src/kx.rs b/src/kx.rs index 3f8a4dd..5352731 100644 --- a/src/kx.rs +++ b/src/kx.rs @@ -49,6 +49,44 @@ impl crypto::ActiveKeyExchange for X25519KeyExchange { } } +#[derive(Debug)] +pub struct X448; + +impl crypto::SupportedKxGroup for X448 { + fn name(&self) -> rustls::NamedGroup { + rustls::NamedGroup::X448 + } + + fn start(&self) -> Result, rustls::Error> { + let mut rng = UnwrapErr(getrandom::SysRng); + let priv_key = x448::EphemeralSecret::try_generate_from_rng(&mut rng) + .map_err(|_| rustls::Error::from(rustls::PeerMisbehaved::InvalidKeyShare))?; + let pub_key = (&priv_key).into(); + Ok(Box::new(X448KeyExchange { priv_key, pub_key })) + } +} + +pub struct X448KeyExchange { + priv_key: x448::EphemeralSecret, + pub_key: x448::PublicKey, +} + +impl crypto::ActiveKeyExchange for X448KeyExchange { + fn complete(self: Box, peer: &[u8]) -> Result { + let peer = x448::PublicKey::from_bytes(peer) + .ok_or_else(|| rustls::Error::from(rustls::PeerMisbehaved::InvalidKeyShare))?; + Ok(self.priv_key.diffie_hellman(&peer).as_bytes()[..].into()) + } + + fn pub_key(&self) -> &[u8] { + self.pub_key.as_bytes() + } + + fn group(&self) -> rustls::NamedGroup { + X448.name() + } +} + macro_rules! impl_kx { ($name:ident, $kx_name:ty, $secret:ty, $public_key:ty) => { paste! { @@ -108,5 +146,7 @@ macro_rules! impl_kx { impl_kx! {SecP256R1, rustls::NamedGroup::secp256r1, p256::ecdh::EphemeralSecret, p256::PublicKey} impl_kx! {SecP384R1, rustls::NamedGroup::secp384r1, p384::ecdh::EphemeralSecret, p384::PublicKey} +impl_kx! {SecP521R1, rustls::NamedGroup::secp521r1, p521::ecdh::EphemeralSecret, p521::PublicKey} -pub const ALL_KX_GROUPS: &[&dyn SupportedKxGroup] = &[&X25519, &SecP256R1, &SecP384R1]; +pub const ALL_KX_GROUPS: &[&dyn SupportedKxGroup] = + &[&X25519, &X448, &SecP256R1, &SecP384R1, &SecP521R1]; diff --git a/src/sign.rs b/src/sign.rs index cf30cc5..39cf145 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -2,8 +2,8 @@ use alloc::{sync::Arc, vec::Vec}; use core::marker::PhantomData; -use self::ecdsa::{EcdsaSigningKeyP256, EcdsaSigningKeyP384}; -use self::eddsa::Ed25519SigningKey; +use self::ecdsa::{EcdsaSigningKeyP256, EcdsaSigningKeyP384, EcdsaSigningKeyP521}; +use self::eddsa::{Ed25519SigningKey, Ed448SigningKey}; use self::rsa::RsaSigningKey; use getrandom::rand_core::UnwrapErr; @@ -89,7 +89,8 @@ pub fn any_supported_type(der: &PrivateKeyDer<'_>) -> Result pub fn any_ecdsa_type(der: &PrivateKeyDer<'_>) -> Result, rustls::Error> { let p256 = |_| EcdsaSigningKeyP256::try_from(der).map(|x| Arc::new(x) as _); let p384 = |_| EcdsaSigningKeyP384::try_from(der).map(|x| Arc::new(x) as _); - p256(()).or_else(p384) + let p521 = |_| EcdsaSigningKeyP521::try_from(der).map(|x| Arc::new(x) as _); + p256(()).or_else(p384).or_else(p521) } /// Extract any supported EDDSA key from the given DER input. @@ -98,8 +99,9 @@ pub fn any_ecdsa_type(der: &PrivateKeyDer<'_>) -> Result, ru /// /// Returns an error if the key couldn't be decoded. pub fn any_eddsa_type(der: &PrivateKeyDer<'_>) -> Result, rustls::Error> { - // TODO: Add support for Ed448 - Ed25519SigningKey::try_from(der).map(|x| Arc::new(x) as _) + let ed25519 = |_| Ed25519SigningKey::try_from(der).map(|x| Arc::new(x) as _); + let ed448 = |_| Ed448SigningKey::try_from(der).map(|x| Arc::new(x) as _); + ed25519(()).or_else(ed448) } pub mod ecdsa; diff --git a/src/sign/ecdsa.rs b/src/sign/ecdsa.rs index 347bc25..6e9dfc2 100644 --- a/src/sign/ecdsa.rs +++ b/src/sign/ecdsa.rs @@ -69,3 +69,4 @@ macro_rules! impl_ecdsa { impl_ecdsa! {P256, SignatureScheme::ECDSA_NISTP256_SHA256, p256::ecdsa::SigningKey, p256::ecdsa::DerSignature} impl_ecdsa! {P384, SignatureScheme::ECDSA_NISTP384_SHA384, p384::ecdsa::SigningKey, p384::ecdsa::DerSignature} +impl_ecdsa! {P521, SignatureScheme::ECDSA_NISTP521_SHA512, p521::ecdsa::SigningKey, p521::ecdsa::DerSignature} diff --git a/src/sign/eddsa.rs b/src/sign/eddsa.rs index 15f4fe8..e8cb34f 100644 --- a/src/sign/eddsa.rs +++ b/src/sign/eddsa.rs @@ -51,3 +51,48 @@ impl SigningKey for Ed25519SigningKey { SignatureAlgorithm::ED25519 } } + +#[derive(Debug)] +pub struct Ed448SigningKey { + key: Arc, + scheme: SignatureScheme, +} + +impl TryFrom<&PrivateKeyDer<'_>> for Ed448SigningKey { + type Error = rustls::Error; + + fn try_from(value: &PrivateKeyDer<'_>) -> Result { + let pkey = match value { + PrivateKeyDer::Pkcs8(der) => { + ed448_goldilocks::SigningKey::from_pkcs8_der(der.secret_pkcs8_der()) + .map_err(|e| format!("failed to decrypt private key: {e}")) + } + PrivateKeyDer::Pkcs1(_) => Err("ED448 does not support PKCS#1 key".to_string()), + PrivateKeyDer::Sec1(_) => Err("ED448 does not support SEC1 key".to_string()), + _ => Err("not supported".into()), + }; + pkey.map(|kp| Self { + key: Arc::new(kp), + scheme: SignatureScheme::ED448, + }) + .map_err(rustls::Error::General) + } +} + +impl SigningKey for Ed448SigningKey { + fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option> { + if offered.contains(&self.scheme) { + Some(Box::new(super::GenericSigner { + _marker: PhantomData, + key: self.key.clone(), + scheme: self.scheme, + })) + } else { + None + } + } + + fn algorithm(&self) -> SignatureAlgorithm { + SignatureAlgorithm::ED448 + } +} diff --git a/src/verify.rs b/src/verify.rs index 2043b64..2990829 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -1,8 +1,10 @@ use rustls::crypto::WebPkiSupportedAlgorithms; use rustls::SignatureScheme; -use self::ecdsa::{ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P384_SHA256, ECDSA_P384_SHA384}; -use self::eddsa::ED25519; +use self::ecdsa::{ + ECDSA_P256_SHA256, ECDSA_P256_SHA384, ECDSA_P384_SHA256, ECDSA_P384_SHA384, ECDSA_P521_SHA512, +}; +use self::eddsa::{ED25519, ED448}; use self::rsa::{ RSA_PKCS1_SHA256, RSA_PKCS1_SHA384, RSA_PKCS1_SHA512, RSA_PSS_SHA256, RSA_PSS_SHA384, RSA_PSS_SHA512, @@ -31,7 +33,9 @@ pub static ALGORITHMS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms { SignatureScheme::ECDSA_NISTP256_SHA256, &[ECDSA_P256_SHA256, ECDSA_P384_SHA256], ), + (SignatureScheme::ECDSA_NISTP521_SHA512, &[ECDSA_P521_SHA512]), (SignatureScheme::ED25519, &[ED25519]), + (SignatureScheme::ED448, &[ED448]), (SignatureScheme::RSA_PKCS1_SHA256, &[RSA_PKCS1_SHA256]), (SignatureScheme::RSA_PKCS1_SHA384, &[RSA_PKCS1_SHA384]), (SignatureScheme::RSA_PKCS1_SHA512, &[RSA_PKCS1_SHA512]), diff --git a/src/verify/ecdsa.rs b/src/verify/ecdsa.rs index 743a6c5..11de758 100644 --- a/src/verify/ecdsa.rs +++ b/src/verify/ecdsa.rs @@ -51,3 +51,4 @@ impl_generic_ecdsa_verifer! {ECDSA_P256_SHA256, alg_id::ECDSA_P256, alg_id::ECDS impl_generic_ecdsa_verifer! {ECDSA_P256_SHA384, alg_id::ECDSA_P256, alg_id::ECDSA_SHA384, p256::ecdsa::VerifyingKey, p256::ecdsa::DerSignature, sha2::Sha384} impl_generic_ecdsa_verifer! {ECDSA_P384_SHA256, alg_id::ECDSA_P384, alg_id::ECDSA_SHA256, p384::ecdsa::VerifyingKey, p384::ecdsa::DerSignature, sha2::Sha256} impl_generic_ecdsa_verifer! {ECDSA_P384_SHA384, alg_id::ECDSA_P384, alg_id::ECDSA_SHA384, p384::ecdsa::VerifyingKey, p384::ecdsa::DerSignature, sha2::Sha384} +impl_generic_ecdsa_verifer! {ECDSA_P521_SHA512, alg_id::ECDSA_P521, alg_id::ECDSA_SHA512, p521::ecdsa::VerifyingKey, p521::ecdsa::DerSignature, sha2::Sha512} diff --git a/src/verify/eddsa.rs b/src/verify/eddsa.rs index 61009e1..3ac4c12 100644 --- a/src/verify/eddsa.rs +++ b/src/verify/eddsa.rs @@ -30,3 +30,33 @@ impl SignatureVerificationAlgorithm for Ed25519Verify { } pub const ED25519: &dyn SignatureVerificationAlgorithm = &Ed25519Verify; + +#[derive(Debug)] +struct Ed448Verify; + +impl SignatureVerificationAlgorithm for Ed448Verify { + fn public_key_alg_id(&self) -> AlgorithmIdentifier { + alg_id::ED448 + } + + fn signature_alg_id(&self) -> AlgorithmIdentifier { + alg_id::ED448 + } + + fn verify_signature( + &self, + public_key: &[u8], + message: &[u8], + signature: &[u8], + ) -> Result<(), InvalidSignature> { + let public_key = public_key.try_into().map_err(|_| InvalidSignature)?; + let signature = + ed448_goldilocks::Signature::from_slice(signature).map_err(|_| InvalidSignature)?; + ed448_goldilocks::VerifyingKey::from_bytes(public_key) + .map_err(|_| InvalidSignature)? + .verify(message, &signature) + .map_err(|_| InvalidSignature) + } +} + +pub const ED448: &dyn SignatureVerificationAlgorithm = &Ed448Verify;