diff --git a/Cargo.lock b/Cargo.lock index dcf00ee..0bcecd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,7 +25,7 @@ checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" dependencies = [ "cfg-if", "cipher", - "cpufeatures", + "cpufeatures 0.2.12", "zeroize", ] @@ -259,6 +259,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base16ct" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" + [[package]] name = "base64" version = "0.21.7" @@ -330,6 +336,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array 0.4.11", +] + [[package]] name = "blowfish" version = "0.9.1" @@ -378,7 +393,7 @@ dependencies = [ "rand", "rand_chacha", "rp-pac", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -395,7 +410,7 @@ checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", "cipher", - "cpufeatures", + "cpufeatures 0.2.12", ] [[package]] @@ -404,11 +419,17 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", + "crypto-common 0.1.6", "inout", "zeroize", ] +[[package]] +name = "cmov" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -440,6 +461,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "cortex-m" version = "0.7.7" @@ -473,6 +500,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "cpubits" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef0c543070d296ea414df2dd7625d1b24866ce206709d8a4a424f28377f5861" + [[package]] name = "cpufeatures" version = "0.2.12" @@ -482,6 +515,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc-any" version = "2.4.4" @@ -516,7 +558,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a0d26b245348befa0c121944541476763dcc46ede886c88f9d12e1697d27c3" +dependencies = [ + "cpubits", + "ctutils", + "hybrid-array 0.4.11", + "num-traits", + "rand_core 0.10.1", "subtle", "zeroize", ] @@ -531,6 +588,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +dependencies = [ + "hybrid-array 0.4.11", + "rand_core 0.10.1", +] + [[package]] name = "ctr" version = "0.9.2" @@ -540,6 +607,16 @@ dependencies = [ "cipher", ] +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", + "subtle", +] + [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -547,9 +624,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.12", "curve25519-dalek-derive", - "digest", + "digest 0.10.7", "fiat-crypto", "rustc_version 0.4.0", "subtle", @@ -644,7 +721,17 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" dependencies = [ - "const-oid", + "const-oid 0.9.6", + "zeroize", +] + +[[package]] +name = "der" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +dependencies = [ + "const-oid 0.10.2", "zeroize", ] @@ -674,12 +761,24 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.6", "subtle", ] +[[package]] +name = "digest" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" +dependencies = [ + "block-buffer 0.12.0", + "const-oid 0.10.2", + "crypto-common 0.2.1", + "ctutils", +] + [[package]] name = "document-features" version = "0.2.11" @@ -695,21 +794,35 @@ version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", + "der 0.7.8", + "digest 0.10.7", + "elliptic-curve 0.13.8", + "rfc6979 0.4.0", + "signature 2.2.0", "spki", ] +[[package]] +name = "ecdsa" +version = "0.17.0-rc.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4bf51f0534ed6e59a0f2f26272b64ba55c470133f8424c2adfd1c4d59d9988" +dependencies = [ + "der 0.8.0", + "digest 0.11.2", + "elliptic-curve 0.14.0-rc.32", + "rfc6979 0.5.0-rc.5", + "signature 3.0.0-rc.10", + "zeroize", +] + [[package]] name = "ed25519" version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "signature", + "signature 2.2.0", ] [[package]] @@ -720,8 +833,8 @@ checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", - "rand_core", - "sha2", + "rand_core 0.6.4", + "sha2 0.10.9", "subtle", "zeroize", ] @@ -738,15 +851,34 @@ version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ - "base16ct", - "crypto-bigint", - "digest", + "base16ct 0.2.0", + "crypto-bigint 0.5.5", + "digest 0.10.7", "ff", "generic-array", "group", "pkcs8", - "rand_core", - "sec1", + "rand_core 0.6.4", + "sec1 0.7.3", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.14.0-rc.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda94f31325c4275e9706adecbb6f0650dee2f904c915a98e3d81adaaaa757aa" +dependencies = [ + "base16ct 1.0.0", + "crypto-bigint 0.7.3", + "crypto-common 0.2.1", + "digest 0.11.2", + "hybrid-array 0.4.11", + "rand_core 0.10.1", + "rustcrypto-ff", + "rustcrypto-group", + "sec1 0.8.1", "subtle", "zeroize", ] @@ -901,7 +1033,7 @@ dependencies = [ "fixed", "nb 1.1.0", "pio", - "rand_core", + "rand_core 0.6.4", "rp-pac", "rp2040-boot2", "sha2-const-stable", @@ -1175,7 +1307,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1348,7 +1480,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1414,7 +1546,16 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.2", ] [[package]] @@ -1454,6 +1595,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "hybrid-array" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d46837a0ed51fe95bd3b05de33cd64a1ee88fc797477ca48446872504507c5" +dependencies = [ + "subtle", + "typenum", + "zeroize", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1536,7 +1688,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.12", ] [[package]] @@ -1545,7 +1697,7 @@ version = "0.3.0-pre.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b8645470337db67b01a7f966decf7d0bafedbae74147d33e641c67a91df239f" dependencies = [ - "rand_core", + "rand_core 0.6.4", "zeroize", ] @@ -1686,9 +1838,9 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97befee0c869cb56f3118f49d0f9bb68c9e3f380dec23c1100aedc4ec3ba239a" dependencies = [ - "hybrid-array", + "hybrid-array 0.2.3", "kem", - "rand_core", + "rand_core 0.6.4", "sha3", "zeroize", ] @@ -1772,9 +1924,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -1860,10 +2012,23 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder 0.13.6", + "sha2 0.10.9", +] + +[[package]] +name = "p256" +version = "0.14.0-rc.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b97e3bf0465157ae90975ff52dbeb1362ba618924878c9f74c25baa27a65f9a" +dependencies = [ + "ecdsa 0.17.0-rc.17", + "elliptic-curve 0.14.0-rc.32", + "primefield", + "primeorder 0.14.0-rc.9", + "sha2 0.11.0", ] [[package]] @@ -1872,10 +2037,10 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder 0.13.6", + "sha2 0.10.9", ] [[package]] @@ -1884,12 +2049,12 @@ version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" dependencies = [ - "base16ct", - "ecdsa", - "elliptic-curve", - "primeorder", - "rand_core", - "sha2", + "base16ct 0.2.0", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder 0.13.6", + "rand_core 0.6.4", + "sha2 0.10.9", ] [[package]] @@ -2027,7 +2192,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "der", + "der 0.7.8", "pkcs8", "spki", ] @@ -2038,7 +2203,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der", + "der 0.7.8", "spki", ] @@ -2064,7 +2229,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.12", "opaque-debug", "universal-hash", ] @@ -2096,13 +2261,36 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "primefield" +version = "0.14.0-rc.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b52e6ee42db392378a95622b463c9740631171d1efce43fa445a569c1600cb6" +dependencies = [ + "crypto-bigint 0.7.3", + "crypto-common 0.2.1", + "rand_core 0.10.1", + "rustcrypto-ff", + "subtle", + "zeroize", +] + [[package]] name = "primeorder" version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" dependencies = [ - "elliptic-curve", + "elliptic-curve 0.13.8", +] + +[[package]] +name = "primeorder" +version = "0.14.0-rc.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0556580e42c19833f5d232aca11a7687a503ee41f937b54f5ae1d50fc2a6a36a" +dependencies = [ + "elliptic-curve 0.14.0-rc.32", ] [[package]] @@ -2152,7 +2340,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "rand_chacha", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2162,7 +2350,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2174,6 +2362,12 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "redox_syscall" version = "0.4.1" @@ -2227,7 +2421,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "hmac", + "hmac 0.12.1", + "subtle", +] + +[[package]] +name = "rfc6979" +version = "0.5.0-rc.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23a3127ee32baec36af75b4107082d9bd823501ec14a4e016be4b6b37faa74ae" +dependencies = [ + "hmac 0.13.0", "subtle", ] @@ -2276,16 +2480,16 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" dependencies = [ - "const-oid", - "digest", + "const-oid 0.9.6", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", "pkcs1", "pkcs8", - "rand_core", - "sha2", - "signature", + "rand_core 0.6.4", + "sha2 0.10.9", + "signature 2.2.0", "spki", "subtle", "zeroize", @@ -2344,6 +2548,27 @@ dependencies = [ "semver 1.0.21", ] +[[package]] +name = "rustcrypto-ff" +version = "0.14.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd2a8adb347447693cd2ba0d218c4b66c62da9b0a5672b17b981e4291ec65ff6" +dependencies = [ + "rand_core 0.10.1", + "subtle", +] + +[[package]] +name = "rustcrypto-group" +version = "0.14.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "369f9b61aa45933c062c9f6b5c3c50ab710687eca83dd3802653b140b43f85ed" +dependencies = [ + "rand_core 0.10.1", + "rustcrypto-ff", + "subtle", +] + [[package]] name = "rustix" version = "0.37.27" @@ -2385,14 +2610,28 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ - "base16ct", - "der", + "base16ct 0.2.0", + "der 0.7.8", "generic-array", "pkcs8", "subtle", "zeroize", ] +[[package]] +name = "sec1" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56d437c2f19203ce5f7122e507831de96f3d2d4d3be5af44a0b0a09d8a80e4d" +dependencies = [ + "base16ct 1.0.0", + "ctutils", + "der 0.8.0", + "hybrid-array 0.4.11", + "subtle", + "zeroize", +] + [[package]] name = "semver" version = "0.9.0" @@ -2451,8 +2690,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.12", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.2", ] [[package]] @@ -2467,7 +2717,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest", + "digest 0.10.7", "keccak", ] @@ -2486,8 +2736,18 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", - "rand_core", + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "signature" +version = "3.0.0-rc.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f1880df446116126965eeec169136b2e0251dba37c6223bcc819569550edea3" +dependencies = [ + "digest 0.11.2", + "rand_core 0.10.1", ] [[package]] @@ -2608,7 +2868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der", + "der 0.7.8", ] [[package]] @@ -2629,7 +2889,7 @@ checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" dependencies = [ "base64ct", "pem-rfc7468", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -2639,14 +2899,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01f8f4ea73476c0aa5d5e6a75ce1e8634e2c3f82005ef3bbed21547ac57f2bf7" dependencies = [ "num-bigint-dig", - "p256", + "p256 0.13.2", "p384", "p521", - "rand_core", + "rand_core 0.6.4", "rsa", - "sec1", - "sha2", - "signature", + "sec1 0.7.3", + "sha2 0.10.9", + "signature 2.2.0", "ssh-cipher", "ssh-encoding", "subtle", @@ -2699,9 +2959,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sunset" @@ -2715,19 +2975,20 @@ dependencies = [ "cipher", "ctr", "curve25519-dalek", - "digest", + "digest 0.10.7", + "ecdsa 0.17.0-rc.17", "ed25519-dalek", "embedded-io", "getrandom", "heapless", - "hmac", + "hmac 0.12.1", "log", "ml-kem", + "p256 0.14.0-rc.9", "poly1305", - "rand_core", + "rand_core 0.6.4", "rsa", - "sha2", - "signature", + "sha2 0.10.9", "simplelog", "snafu", "ssh-key", @@ -2763,9 +3024,9 @@ dependencies = [ "embassy-time", "embedded-io-async", "heapless", - "hmac", + "hmac 0.12.1", "log", - "sha2", + "sha2 0.10.9", "subtle", "sunset", "sunset-async", @@ -2803,7 +3064,7 @@ dependencies = [ "portable-atomic", "rand", "rtt-target", - "sha2", + "sha2 0.10.9", "snafu", "static_cell", "sunset", @@ -2830,7 +3091,7 @@ dependencies = [ "libc", "log", "rand", - "sha2", + "sha2 0.10.9", "sunset", "sunset-async", "sunset-demo-common", @@ -2989,9 +3250,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" [[package]] name = "ufmt-write" @@ -3023,7 +3284,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "crypto-common", + "crypto-common 0.1.6", "subtle", ] @@ -3494,7 +3755,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ "curve25519-dalek", - "rand_core", + "rand_core 0.6.4", "zeroize", ] diff --git a/Cargo.toml b/Cargo.toml index 61e4667..238c0cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,6 @@ sha2 = { version = "0.10", default-features = false } hmac = "0.12" poly1305 = "0.8" digest = "0.10" -signature = { version = "2.0", default-features = false } zeroize = { version = "1", default-features = false, features = ["derive"] } cipher = { version = "0.4", features = ["zeroize"] } subtle = { version = "2.4", default-features = false } @@ -57,19 +56,27 @@ ed25519-dalek = { version = "2.1", default-features = false, features = ["zeroiz x25519-dalek = { version = "2.0", default-features = false, features = ["zeroize"] } curve25519-dalek = { version = "4.1", default-features = false, features = ["zeroize"] } ml-kem = { version = "0.2.1", default-features = false, features = ["zeroize"], optional = true } -# p521 = { version = "0.13.2", default-features = false, features = ["ecdh", "ecdsa"] } rsa = { version = "0.9", default-features = false, optional = true, features = ["sha2"] } # TODO: getrandom feature is a workaround for missing ssh-key dependency with rsa. fixed in pending 0.6 ssh-key = { version = "0.6", default-features = false, optional = true, features = ["getrandom"] } embedded-io = { version = "0.6", optional = true } +# TODO rc versions +p256 = { version = "0.14.0-rc.9", optional = true, default-features = false, features = ["ecdsa"] } +ecdsa = { version = "0.17.0-rc.17", default-features = false, optional = true , features = ["hazmat", "algorithm"]} + [features] default = [] std = ["snafu/std", "ssh-key/alloc", "larger", "mlkem"] backtrace = ["snafu/backtrace"] rsa = ["dep:rsa", "ssh-key/rsa"] mlkem = ["dep:ml-kem"] + +_ecdsa = ["dep:ecdsa", "ssh-key/ecdsa"] +# ecdsa-sha2-nistp256 +ecdsa256 = ["_ecdsa", "dep:p256", "ssh-key/p256"] + # allows conversion to/from OpenSSH key formats openssh-key = ["ssh-key"] # implements embedded_io::Error for sunset::Error diff --git a/demo/common/src/server.rs b/demo/common/src/server.rs index 3bf9521..833d039 100644 --- a/demo/common/src/server.rs +++ b/demo/common/src/server.rs @@ -138,14 +138,8 @@ impl DemoCommon { } fn handle_password(&mut self, a: ServPasswordAuth) -> Result<()> { - let username = match a.username() { - Ok(u) => u, - Err(_) => return Ok(()), - }; - let password = match a.password() { - Ok(u) => u, - Err(_) => return Ok(()), - }; + let username = a.username()?; + let password = a.password()?; let p = if self.is_admin(username) { &self.config.admin_pw diff --git a/src/error.rs b/src/error.rs index 87ddbf3..599e174 100644 --- a/src/error.rs +++ b/src/error.rs @@ -47,6 +47,9 @@ pub enum Error { /// Signature is incorrect BadSig, + /// Received a badly formatted number + BadNumber, + /// Error in received SSH protocol. Will disconnect. SSHProto { #[cfg(feature = "backtrace")] @@ -61,9 +64,6 @@ pub enum Error { // TODO: 'static disconnect message to return? SSHProtoUnsupported, - /// Received a key with invalid structure, or too large. - BadKeyFormat, - /// Remote peer isn't SSH 2.0 NotSSH, diff --git a/src/kex.rs b/src/kex.rs index b731ad2..108dd4e 100644 --- a/src/kex.rs +++ b/src/kex.rs @@ -60,6 +60,8 @@ const fixed_options_hostsig: &[&str] = &[ SSH_NAME_ED25519, #[cfg(feature = "rsa")] SSH_NAME_RSA_SHA256, + #[cfg(feature = "ecdsa256")] + SSH_NAME_ECDSA256, ]; const fixed_options_cipher: &[&str] = &[SSH_NAME_CHAPOLY, SSH_NAME_AES256_CTR]; diff --git a/src/lib.rs b/src/lib.rs index 88cdfa5..c16f54d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,6 @@ mod traffic; use conn::DispatchEvent; -// Application API pub use sshwire::TextString; pub use auth::AuthSigMsg; diff --git a/src/packets.rs b/src/packets.rs index a3f0365..29b374b 100644 --- a/src/packets.rs +++ b/src/packets.rs @@ -16,6 +16,9 @@ use core::fmt::{Debug, Display}; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; +#[cfg(feature = "ecdsa256")] +use p256::NistP256; + use sunset_sshwire_derive::*; use crate::*; @@ -331,6 +334,10 @@ pub enum PubKey<'a> { #[sshwire(variant = SSH_NAME_RSA)] RSA(RSAPubKey), + #[cfg(feature = "ecdsa256")] + #[sshwire(variant = SSH_NAME_ECDSA256)] + ECDSA256(ECDSAPubKey), + #[sshwire(unknown)] Unknown(Unknown<'a>), } @@ -342,6 +349,8 @@ impl PubKey<'_> { PubKey::Ed25519(_) => Ok(SSH_NAME_ED25519), #[cfg(feature = "rsa")] PubKey::RSA(_) => Ok(SSH_NAME_RSA), + #[cfg(feature = "ecdsa256")] + PubKey::ECDSA256(_) => Ok(SSH_NAME_ECDSA256), PubKey::Unknown(u) => Err(u), } } @@ -390,6 +399,19 @@ impl TryFrom<&PubKey<'_>> for ssh_key::PublicKey { Ok(k.into()) } + #[cfg(feature = "ecdsa256")] + PubKey::ECDSA256(k) => { + // TODO can simplify once ecdsa crate isn't rc + let k = ssh_key::public::EcdsaPublicKey::NistP256( + k.key + .to_sec1_point(false) + .as_bytes() + .try_into() + .map_err(|_| Error::BadKex)?, + ); + Ok(k.into()) + } + PubKey::Unknown(u) => { trace!("unsupported {u}"); Err(Error::msg("Unsupported OpenSSH key")) @@ -431,7 +453,7 @@ impl<'de> SSHDecode<'de> for RSAPubKey { let n = SSHDecode::dec(s)?; let key = rsa::RsaPublicKey::new(n, e).map_err(|e| { debug!("Invalid RSA public key: {e}"); - WireError::BadKeyFormat + WireError::BadKey })?; Ok(Self { key }) } @@ -457,6 +479,64 @@ impl Arbitrary<'_> for RSAPubKey { } } +#[cfg(feature = "_ecdsa")] +#[derive(Clone, PartialEq)] +pub struct ECDSAPubKey +{ + pub key: ecdsa::VerifyingKey, +} + +#[cfg(feature = "_ecdsa")] +const ECDSA_ID_NISTP256: &str = "nistp256"; + +#[cfg(feature = "ecdsa256")] +impl SSHEncode for ECDSAPubKey { + fn enc(&self, s: &mut dyn SSHSink) -> WireResult<()> { + ECDSA_ID_NISTP256.enc(s)?; + let pt = self.key.to_sec1_point(false); + BinString(pt.as_bytes()).enc(s) + } +} + +#[cfg(feature = "ecdsa256")] +impl<'de> SSHDecode<'de> for ECDSAPubKey { + fn dec(s: &mut S) -> WireResult + where + S: SSHSource<'de>, + { + let name: &str = SSHDecode::dec(s)?; + if name != ECDSA_ID_NISTP256 { + trace!("Wrong ecdsa name {name}"); + return Err(WireError::BadKey); + } + + let key = BinString::dec(s)?; + let key = ecdsa::VerifyingKey::from_sec1_bytes(key.0).map_err(|_| { + trace!("Bad ecdsa key"); + WireError::BadKey + })?; + Ok(Self { key }) + } +} + +#[cfg(feature = "ecdsa256")] +impl Debug for ECDSAPubKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ECDSAPubKey").finish_non_exhaustive() + } +} + +#[cfg(all(feature = "arbitrary", feature = "ecdsa256"))] +impl Arbitrary<'_> for ECDSAPubKey { + fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result { + let key = ecdsa::VerifyingKey::from_sec1_bytes( + arbitrary::Arbitrary::arbitrary(u)?, + ) + .map_err(|_| arbitrary::Error::IncorrectFormat)?; + Ok(Self { key }) + } +} + #[derive(Debug, SSHEncode, SSHDecode, Clone)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[sshwire(variant_prefix)] @@ -468,6 +548,10 @@ pub enum Signature<'a> { #[sshwire(variant = SSH_NAME_RSA_SHA256)] RSA(RSASig<'a>), + #[cfg(feature = "ecdsa256")] + #[sshwire(variant = SSH_NAME_ECDSA256)] + ECDSA256(Blob>), + #[sshwire(unknown)] Unknown(Unknown<'a>), } @@ -479,6 +563,8 @@ impl<'a> Signature<'a> { Signature::Ed25519(_) => Ok(SSH_NAME_ED25519), #[cfg(feature = "rsa")] Signature::RSA(_) => Ok(SSH_NAME_RSA_SHA256), + #[cfg(feature = "ecdsa256")] + Signature::ECDSA256(_) => Ok(SSH_NAME_ECDSA256), Signature::Unknown(u) => Err(u), } } @@ -494,6 +580,8 @@ impl<'a> Signature<'a> { PubKey::Ed25519(_) => Ok(SSH_NAME_ED25519), #[cfg(feature = "rsa")] PubKey::RSA(_) => Ok(SSH_NAME_RSA_SHA256), + #[cfg(feature = "ecdsa256")] + PubKey::ECDSA256(_) => Ok(SSH_NAME_ECDSA256), PubKey::Unknown(u) => { warn!("Unknown key type \"{}\"", u); Err(Error::UnknownMethod { kind: "key" }) @@ -506,6 +594,8 @@ impl<'a> Signature<'a> { Signature::Ed25519(_) => Ok(SigType::Ed25519), #[cfg(feature = "rsa")] Signature::RSA(_) => Ok(SigType::RSA), + #[cfg(feature = "ecdsa256")] + Signature::ECDSA256(_) => Ok(SigType::ECDSA256), Signature::Unknown(u) => { warn!("Unknown signature type \"{}\"", u); Err(Error::UnknownMethod { kind: "signature" }) @@ -524,6 +614,11 @@ impl<'a> From<&'a OwnedSig> for Signature<'a> { OwnedSig::RSA(s) => { Signature::RSA(RSASig { sig: BinString(s.as_ref()) }) } + #[cfg(feature = "ecdsa256")] + OwnedSig::ECDSA256 { r, s } => Signature::ECDSA256(Blob(ECDSASig { + r: sshwire::Mpint::new(r), + s: sshwire::Mpint::new(s), + })), } } } @@ -540,6 +635,13 @@ pub struct Ed25519Sig<'a> { pub struct RSASig<'a> { pub sig: BinString<'a>, } +#[cfg(feature = "_ecdsa")] +#[derive(Debug, SSHEncode, SSHDecode, Clone)] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub struct ECDSASig<'a> { + pub r: sshwire::Mpint<'a>, + pub s: sshwire::Mpint<'a>, +} #[derive(Debug, SSHEncode, SSHDecode)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] diff --git a/src/sign.rs b/src/sign.rs index 460ac7b..2b86840 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -19,6 +19,21 @@ use sshwire::{Blob, SSHEncode}; use core::mem::discriminant; +// RSA requires alloc. +#[cfg(feature = "rsa")] +use packets::RSAPubKey; +#[cfg(feature = "rsa")] +use rsa::signature::{DigestSigner as _, DigestVerifier as _}; + +#[cfg(feature = "_ecdsa")] +use crate::packets::ECDSAPubKey; +#[cfg(feature = "_ecdsa")] +use ecdsa::signature::hazmat::{PrehashSigner as _, PrehashVerifier as _}; +#[cfg(feature = "_ecdsa")] +use ecdsa::VerifyingKey; +#[cfg(feature = "ecdsa256")] +use p256::NistP256; + // only required for some configurations #[allow(unused_imports)] use digest::Digest; @@ -26,7 +41,7 @@ use digest::Digest; // TODO remove once we use byupdate. // signatures are for hostkey (32 byte sessiid) or pubkey (auth packet || sessid). // we assume a max 40 character username here. -const MAX_SIG_MSG: usize = 1 +const MAX_ED25519_SIG_MSG: usize = 1 + 4 + 40 + 4 @@ -40,18 +55,20 @@ const MAX_SIG_MSG: usize = 1 + 32 + 32; -// RSA requires alloc. -#[cfg(feature = "rsa")] -use packets::RSAPubKey; -#[cfg(feature = "rsa")] -use rsa::signature::{DigestSigner, DigestVerifier}; - #[derive(Debug, Clone, Copy)] pub enum SigType { Ed25519, #[cfg(feature = "rsa")] RSA, - // Ecdsa + #[cfg(feature = "ecdsa256")] + ECDSA256, +} + +#[allow(dead_code)] +fn copy_right_aligned(src: &[u8], dest: &mut [u8]) -> Result<(), ()> { + let Some(offset) = dest.len().checked_sub(src.len()) else { return Err(()) }; + dest[offset..].copy_from_slice(src); + Ok(()) } impl SigType { @@ -61,6 +78,8 @@ impl SigType { SSH_NAME_ED25519 => Ok(SigType::Ed25519), #[cfg(feature = "rsa")] SSH_NAME_RSA_SHA256 => Ok(SigType::RSA), + #[cfg(feature = "ecdsa256")] + SSH_NAME_ECDSA256 => Ok(SigType::ECDSA256), _ => Err(Error::bug()), } } @@ -71,6 +90,8 @@ impl SigType { SigType::Ed25519 => SSH_NAME_ED25519, #[cfg(feature = "rsa")] SigType::RSA => SSH_NAME_RSA_SHA256, + #[cfg(feature = "ecdsa256")] + SigType::ECDSA256 => SSH_NAME_ECDSA256, } } @@ -122,6 +143,13 @@ impl SigType { Self::verify_rsa(k, msg, s) } + #[cfg(feature = "ecdsa256")] + ( + SigType::ECDSA256, + PubKey::ECDSA256(ECDSAPubKey { key }), + Signature::ECDSA256(s), + ) => Self::verify_ecdsa(key, msg, &s.0), + _ => { warn!( "Signature \"{:?}\" doesn't match key type \"{:?}\"", @@ -158,7 +186,7 @@ impl SigType { // &s, // ) // .map_err(|_| Error::BadSig) - let mut buf = [0; MAX_SIG_MSG]; + let mut buf = [0; MAX_ED25519_SIG_MSG]; let l = sshwire::write_ssh(&mut buf, msg)?; let buf = &buf[..l]; k.verify(buf, &s).map_err(|_| Error::BadSig) @@ -184,6 +212,54 @@ impl SigType { Error::BadSig }) } + + #[cfg(feature = "_ecdsa")] + fn verify_ecdsa( + k: &VerifyingKey, + msg: &dyn SSHEncode, + sig: &packets::ECDSASig, + ) -> Result<()> + where + ecdsa::SignatureSize: ecdsa::elliptic_curve::array::ArraySize, + { + // RFC5656 defined r and s as mpint, so SSH will trim leading zeros. + // ecdsa crate requires exact sized inputs, so copy them in + // zero padded (big endian). + let mut pad_r = ecdsa::elliptic_curve::FieldBytes::::default(); + let mut pad_s = ecdsa::elliptic_curve::FieldBytes::::default(); + copy_right_aligned(sig.r.as_ref(), &mut pad_r).map_err(|_| { + debug!("Bad signature r"); + error::BadSig.build() + })?; + copy_right_aligned(sig.s.as_ref(), &mut pad_s).map_err(|_| { + debug!("Bad signature s"); + error::BadSig.build() + })?; + + let sig = + ecdsa::Signature::::from_scalars(pad_r, pad_s).map_err(|_| { + trace!("ECDSA bad signature"); + error::BadSig.build() + })?; + + // TODO: once ecdsa is non-rc and all the crates like digest are aligned, + // can use verify_digest() instead of hazmat::verify_prehashed. + // k.verify_digest(|&mut d| { + // sshwire::hash_ser(d, msg).map_err(|_| ecdsa::Error::new()) + // }, &signature).map_err(|_| { + // trace!("ECDSA verify failed"); + // Error::BadSig + // }) + + let mut h = sha2::Sha256::new(); + sshwire::hash_ser(&mut h, msg)?; + let h = h.finalize(); + + k.verify_prehash(&h, &sig).map_err(|_| { + trace!("ECDSA verify failed"); + Error::BadSig + }) + } } pub enum OwnedSig { @@ -191,6 +267,11 @@ pub enum OwnedSig { Ed25519([u8; 64]), #[cfg(feature = "rsa")] RSA(Box<[u8]>), + #[cfg(feature = "ecdsa256")] + ECDSA256 { + r: [u8; 32], + s: [u8; 32], + }, } #[cfg(feature = "rsa")] @@ -213,6 +294,21 @@ impl TryFrom> for OwnedSig { let s = s.sig.0.try_into().map_err(|_| Error::BadSig)?; Ok(OwnedSig::RSA(s)) } + #[cfg(feature = "ecdsa256")] + Signature::ECDSA256(sig) => { + let sig = sig.0; + let mut r = [0; 32]; + let mut s = [0; 32]; + copy_right_aligned(sig.r.as_ref(), &mut r).map_err(|_| { + debug!("Bad signature r"); + error::BadSig.build() + })?; + copy_right_aligned(sig.s.as_ref(), &mut s).map_err(|_| { + debug!("Bad signature s"); + error::BadSig.build() + })?; + Ok(OwnedSig::ECDSA256 { r, s }) + } Signature::Unknown(u) => { debug!("Unknown {u} signature"); Err(Error::UnknownMethod { kind: "signature" }) @@ -250,6 +346,14 @@ pub enum SignKey { #[cfg(feature = "rsa")] #[zeroize(skip)] AgentRSA(rsa::RsaPublicKey), + + #[cfg(feature = "ecdsa256")] + #[zeroize(skip)] + ECDSA256(ecdsa::SigningKey), + + #[cfg(feature = "ecdsa256")] + #[zeroize(skip)] + AgentECDSA256(ecdsa::VerifyingKey), } impl SignKey { @@ -300,6 +404,14 @@ impl SignKey { #[cfg(feature = "rsa")] SignKey::AgentRSA(pk) => PubKey::RSA(RSAPubKey { key: pk.clone() }), + + #[cfg(feature = "ecdsa256")] + SignKey::ECDSA256(k) => PubKey::ECDSA256(ECDSAPubKey { key: k.into() }), + + #[cfg(feature = "ecdsa256")] + SignKey::AgentECDSA256(pk) => { + PubKey::ECDSA256(ECDSAPubKey { key: pk.clone() }) + } } } @@ -321,6 +433,8 @@ impl SignKey { #[cfg(feature = "rsa")] PubKey::RSA(k) => Ok(Self::AgentRSA(k.key.clone())), + #[cfg(feature = "ecdsa256")] + PubKey::ECDSA256(k) => Ok(Self::AgentECDSA256(k.key.clone())), PubKey::Unknown(_) => Err(Error::msg("Unsupported agent key")), } @@ -337,6 +451,10 @@ impl SignKey { SignKey::RSA(_) | SignKey::AgentRSA(_) => { matches!(sig_type, SigType::RSA) } + #[cfg(feature = "ecdsa256")] + SignKey::ECDSA256(_) | SignKey::AgentECDSA256(_) => { + matches!(sig_type, SigType::ECDSA256) + } } } @@ -354,7 +472,7 @@ impl SignKey { // &k.verifying_key(), // ) // .trap()?; - let mut buf = [0; MAX_SIG_MSG]; + let mut buf = [0; MAX_ED25519_SIG_MSG]; let l = sshwire::write_ssh(&mut buf, msg)?; let buf = &buf[..l]; let sig = k.sign(buf); @@ -375,10 +493,26 @@ impl SignKey { OwnedSig::RSA(sig.into()) } + #[cfg(feature = "ecdsa256")] + SignKey::ECDSA256(k) => { + let mut h = sha2::Sha256::new(); + sshwire::hash_ser(&mut h, msg)?; + let h = h.finalize(); + let sig: ecdsa::Signature = + k.sign_prehash(&h).map_err(|_| { + trace!("ECDSA signing failed"); + Error::bug() + })?; + let (r, s) = sig.split_bytes(); + OwnedSig::ECDSA256 { r: r.into(), s: s.into() } + } + // callers should check for agent keys first - SignKey::AgentEd25519(_) => return Error::bug_msg("agent sign"), + SignKey::AgentEd25519(_) => unreachable!(), #[cfg(feature = "rsa")] - SignKey::AgentRSA(_) => return Error::bug_msg("agent sign"), + SignKey::AgentRSA(_) => unreachable!(), + #[cfg(feature = "ecdsa256")] + SignKey::AgentECDSA256(_) => unreachable!(), }; // { @@ -398,10 +532,14 @@ impl SignKey { SignKey::Ed25519(_) => false, #[cfg(feature = "rsa")] SignKey::RSA(_) => false, + #[cfg(feature = "ecdsa256")] + SignKey::ECDSA256(_) => false, SignKey::AgentEd25519(_) => true, #[cfg(feature = "rsa")] SignKey::AgentRSA(_) => true, + #[cfg(feature = "ecdsa256")] + SignKey::AgentECDSA256(_) => true, } } } @@ -415,6 +553,10 @@ impl core::fmt::Debug for SignKey { Self::RSA(_) => "RSA", #[cfg(feature = "rsa")] Self::AgentRSA(_) => "AgentRSA", + #[cfg(feature = "ecdsa256")] + Self::ECDSA256(_) => "ECDSA256", + #[cfg(feature = "ecdsa256")] + Self::AgentECDSA256(_) => "AgentECDSA256", }; write!(f, "SignKey::{s}") } diff --git a/src/sshnames.rs b/src/sshnames.rs index 5826f6b..253e24d 100644 --- a/src/sshnames.rs +++ b/src/sshnames.rs @@ -32,6 +32,8 @@ pub const SSH_NAME_ED25519: &str = "ssh-ed25519"; pub const SSH_NAME_RSA_SHA256: &str = "rsa-sha2-256"; /// [RFC4253](https://tools.ietf.org/html/rfc4253). Deprecated for signatures but is a valid key type. pub const SSH_NAME_RSA: &str = "ssh-rsa"; +/// [RFC5656](https://tools.ietf.org/html/rfc5656). +pub const SSH_NAME_ECDSA256: &str = "ecdsa-sha2-nistp256"; /// [RFC4344](https://tools.ietf.org/html/rfc4344) pub const SSH_NAME_AES256_CTR: &str = "aes256-ctr"; diff --git a/src/sshwire.rs b/src/sshwire.rs index c0d2f71..bd8435e 100644 --- a/src/sshwire.rs +++ b/src/sshwire.rs @@ -92,7 +92,9 @@ pub enum WireError { SSHProto, - BadKeyFormat, + BadKey, + + BadNumber, UnknownPacket { number: u8 }, } @@ -106,7 +108,8 @@ impl From for Error { WireError::BadName => Error::BadName, WireError::SSHProto => error::SSHProto.build(), WireError::PacketWrong => error::PacketWrong.build(), - WireError::BadKeyFormat => Error::BadKeyFormat, + WireError::BadKey => Error::BadKey, + WireError::BadNumber => Error::BadNumber, WireError::UnknownVariant => Error::bug_err_msg("Can't encode Unknown"), WireError::UnknownPacket { number } => Error::UnknownPacket { number }, } @@ -250,23 +253,18 @@ impl<'de> SSHSource<'de> for DecodeBytes<'de> { } } -// Hashes a slice to be treated as a mpint. Has u32 length prefix -// and an extra 0x00 byte if the MSB is set. -pub fn hash_mpint(hash_ctx: &mut dyn SSHWireDigestUpdate, m: &[u8]) { - let pad = !m.is_empty() && (m[0] & 0x80) != 0; - let l = m.len() as u32 + pad as u32; - hash_ctx.digest_update(&l.to_be_bytes()); - if pad { - hash_ctx.digest_update(&[0x00]); - } - hash_ctx.digest_update(m); +/// Hashes a slice to be treated as a rfc4253 mpint. +/// +/// Has u32 length prefix and an extra 0x00 byte if the MSB is set. +pub fn hash_mpint(hash_ctx: &mut impl SSHWireDigestUpdate, m: &[u8]) { + // OK unwrap, hash_ser can't fail since Mpint::enc can't fail + hash_ser(hash_ctx, &Mpint(m)).unwrap(); } /////////////////////////////////////////////// /// A SSH style binary string. Serialized as `u32` length followed by the bytes /// of the slice. -/// Application API #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pub struct BinString<'a>(pub &'a [u8]); @@ -317,8 +315,6 @@ impl SSHEncode for heapless::String { /// Note that SSH protocol identifiers in [`Packet`] /// are `&str` rather than `TextString`, and always defined as ASCII. For /// example `"publickey"`, `"ssh-ed25519"`. -/// -/// Application API #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pub struct TextString<'a>(pub &'a [u8]); @@ -463,6 +459,78 @@ impl<'de, B: SSHDecode<'de>> SSHDecode<'de> for Blob { } } +fn top_bit_set(b: &[u8]) -> bool { + b.first().unwrap_or(&0) & 0x80 != 0 +} + +/// SSH `mpint` value +/// +/// Represents a zero or positive rfc4251 mpint. +/// The inner slice must not have leading padding 0x00s, use new() to strip them. +/// Its wire encoding has a padding byte if the slice's top bit is set. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] +pub struct Mpint<'a>(&'a [u8]); + +impl<'a> Mpint<'a> { + /// Construct a Mpint, removing leading 0x00 bytes. + pub fn new(mut b: &'a [u8]) -> Self { + while b.get(0) == Some(&0x00) { + b = &b[1..]; + } + Mpint(b) + } +} + +impl<'a> AsRef<[u8]> for Mpint<'a> { + fn as_ref(&self) -> &[u8] { + self.0 + } +} + +impl Debug for Mpint<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "mpint(")?; + for b in self.0 { + write!(f, "{b:02x}")?; + } + write!(f, ")") + } +} + +impl SSHEncode for Mpint<'_> { + fn enc(&self, s: &mut dyn SSHSink) -> WireResult<()> { + // rfc4251 + // "Unnecessary leading bytes with the value 0 or 255 MUST NOT be included" + debug_assert!( + self.0.is_empty() || self.0[0] != 0x00, + "Shouldn't have leading padding" + ); + + let pad = top_bit_set(self.0); + (self.0.len() as u32 + pad as u32).enc(s)?; + if pad { + 0u8.enc(s)?; + } + self.0.enc(s) + } +} + +impl<'de> SSHDecode<'de> for Mpint<'de> { + fn dec(s: &mut S) -> WireResult + where + S: sshwire::SSHSource<'de>, + { + let b = BinString::dec(s)?.0; + if top_bit_set(b) { + trace!("received negative mpint"); + return Err(WireError::BadNumber); + } + // Strip padding bytes + Ok(Mpint::new(b)) + } +} + /////////////////////////////////////////////// impl SSHEncode for u8 { @@ -675,27 +743,12 @@ impl From for SSHWireDigestTrace { } } -#[cfg(feature = "rsa")] -fn top_bit_set(b: &[u8]) -> bool { - b.first().unwrap_or(&0) & 0x80 != 0 -} - #[cfg(feature = "rsa")] impl SSHEncode for rsa::BigUint { fn enc(&self, s: &mut dyn SSHSink) -> WireResult<()> { let b = self.to_bytes_be(); let b = b.as_slice(); - - // rfc4251 mpint, need a leading zero byte if top bit is set - let pad = top_bit_set(b); - let len = b.len() as u32 + pad as u32; - len.enc(s)?; - - if pad { - 0u8.enc(s)?; - } - - b.enc(s) + Mpint(b).enc(s) } } @@ -705,11 +758,7 @@ impl<'de> SSHDecode<'de> for rsa::BigUint { where S: SSHSource<'de>, { - let b = BinString::dec(s)?; - if top_bit_set(b.0) { - trace!("received negative mpint"); - return Err(WireError::BadKeyFormat); - } + let b = Mpint::dec(s)?; Ok(rsa::BigUint::from_bytes_be(b.0)) } } diff --git a/testing/ci.sh b/testing/ci.sh index e04e41e..47295a3 100755 --- a/testing/ci.sh +++ b/testing/ci.sh @@ -33,6 +33,7 @@ cargo fmt --check # stable # only test lib since some examples are broken cargo test --lib +cargo test --lib --all-features # build non-testing, will be no_std cargo build cargo doc