another 700 lines of untested protocol code, fun
This commit is contained in:
parent
3b6a8a00d7
commit
15ac941df5
|
@ -21,28 +21,6 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-stream"
|
|
||||||
version = "0.3.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51"
|
|
||||||
dependencies = [
|
|
||||||
"async-stream-impl",
|
|
||||||
"futures-core",
|
|
||||||
"pin-project-lite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-stream-impl"
|
|
||||||
version = "0.3.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.15",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.68"
|
version = "0.1.68"
|
||||||
|
@ -54,6 +32,17 @@ dependencies = [
|
||||||
"syn 2.0.15",
|
"syn 2.0.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atty"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi 0.1.19",
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -145,7 +134,7 @@ dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"time",
|
"time 0.1.45",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
@ -171,6 +160,17 @@ dependencies = [
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
|
||||||
|
dependencies = [
|
||||||
|
"atty",
|
||||||
|
"lazy_static",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const-oid"
|
name = "const-oid"
|
||||||
version = "0.9.2"
|
version = "0.9.2"
|
||||||
|
@ -312,12 +312,95 @@ version = "0.1.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77"
|
checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-io",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-channel"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.28"
|
version = "0.3.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
|
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-executor"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-io"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-macro"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.15",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-sink"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-task"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-util"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"futures-macro",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"memchr",
|
||||||
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
|
"slab",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.7"
|
version = "0.14.7"
|
||||||
|
@ -339,12 +422,36 @@ dependencies = [
|
||||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex"
|
name = "hex"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex-literal"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.56"
|
version = "0.1.56"
|
||||||
|
@ -378,6 +485,12 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.61"
|
version = "0.3.61"
|
||||||
|
@ -387,6 +500,12 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.142"
|
version = "0.2.142"
|
||||||
|
@ -401,15 +520,19 @@ dependencies = [
|
||||||
"chacha20poly1305",
|
"chacha20poly1305",
|
||||||
"chrono",
|
"chrono",
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
|
"futures",
|
||||||
"hex",
|
"hex",
|
||||||
|
"hex-literal",
|
||||||
|
"log",
|
||||||
"pem",
|
"pem",
|
||||||
"rand",
|
"rand",
|
||||||
"rmp-serde",
|
"rmp-serde",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_arrays",
|
"serde_arrays",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
"simple_logger",
|
||||||
|
"tcp-test",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-test",
|
|
||||||
"x25519-dalek",
|
"x25519-dalek",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -437,6 +560,24 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "0.8.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
|
"windows-sys 0.45.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.45"
|
version = "0.1.45"
|
||||||
|
@ -456,6 +597,25 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi 0.2.6",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_threads"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.17.1"
|
version = "1.17.1"
|
||||||
|
@ -500,6 +660,12 @@ version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkcs8"
|
name = "pkcs8"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
|
@ -655,6 +821,38 @@ version = "2.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
|
checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simple_logger"
|
||||||
|
version = "4.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e78beb34673091ccf96a8816fce8bfd30d1292c7621ca2bcb5f2ba0fae4f558d"
|
||||||
|
dependencies = [
|
||||||
|
"atty",
|
||||||
|
"colored",
|
||||||
|
"log",
|
||||||
|
"time 0.3.20",
|
||||||
|
"windows-sys 0.42.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab"
|
||||||
|
version = "0.4.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spki"
|
name = "spki"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -693,6 +891,15 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tcp-test"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2ead44ab42fbfdf2dfa78e1822f537a042a117f5677317007ff46af50d3dd80"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
@ -713,6 +920,35 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.3.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"libc",
|
||||||
|
"num_threads",
|
||||||
|
"serde",
|
||||||
|
"time-core",
|
||||||
|
"time-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-core"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-macros"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36"
|
||||||
|
dependencies = [
|
||||||
|
"time-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.28.0"
|
version = "1.28.0"
|
||||||
|
@ -721,32 +957,24 @@ checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"libc",
|
||||||
|
"mio",
|
||||||
|
"num_cpus",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"windows-sys",
|
"socket2",
|
||||||
|
"tokio-macros",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-stream"
|
name = "tokio-macros"
|
||||||
version = "0.1.14"
|
version = "2.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
|
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"proc-macro2",
|
||||||
"pin-project-lite",
|
"quote",
|
||||||
"tokio",
|
"syn 2.0.15",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-test"
|
|
||||||
version = "0.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "53474327ae5e166530d17f2d956afcb4f8a004de581b3cae10f12006bc8163e3"
|
|
||||||
dependencies = [
|
|
||||||
"async-stream",
|
|
||||||
"bytes",
|
|
||||||
"futures-core",
|
|
||||||
"tokio",
|
|
||||||
"tokio-stream",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -886,7 +1114,31 @@ version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-targets 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.42.2",
|
||||||
|
"windows_aarch64_msvc 0.42.2",
|
||||||
|
"windows_i686_gnu 0.42.2",
|
||||||
|
"windows_i686_msvc 0.42.2",
|
||||||
|
"windows_x86_64_gnu 0.42.2",
|
||||||
|
"windows_x86_64_gnullvm 0.42.2",
|
||||||
|
"windows_x86_64_msvc 0.42.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.45.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.42.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -895,7 +1147,22 @@ version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-targets 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.42.2",
|
||||||
|
"windows_aarch64_msvc 0.42.2",
|
||||||
|
"windows_i686_gnu 0.42.2",
|
||||||
|
"windows_i686_msvc 0.42.2",
|
||||||
|
"windows_x86_64_gnu 0.42.2",
|
||||||
|
"windows_x86_64_gnullvm 0.42.2",
|
||||||
|
"windows_x86_64_msvc 0.42.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -904,51 +1171,93 @@ version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"windows_aarch64_gnullvm 0.48.0",
|
||||||
"windows_aarch64_msvc",
|
"windows_aarch64_msvc 0.48.0",
|
||||||
"windows_i686_gnu",
|
"windows_i686_gnu 0.48.0",
|
||||||
"windows_i686_msvc",
|
"windows_i686_msvc 0.48.0",
|
||||||
"windows_x86_64_gnu",
|
"windows_x86_64_gnu 0.48.0",
|
||||||
"windows_x86_64_gnullvm",
|
"windows_x86_64_gnullvm 0.48.0",
|
||||||
"windows_x86_64_msvc",
|
"windows_x86_64_msvc 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
|
|
|
@ -14,11 +14,16 @@ hex = "0.4"
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
ed25519-dalek = { version = "2.0.0-rc.2", features = ["rand_core"] }
|
ed25519-dalek = { version = "2.0.0-rc.2", features = ["rand_core"] }
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
x25519-dalek = "2.0.0-rc.2"
|
x25519-dalek = { version = "2.0.0-rc.2", features = ["static_secrets"] }
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
tokio = { version = "1.28", features = ["io-util"] }
|
tokio = { version = "1.28", features = ["io-util"] }
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
chacha20poly1305 = "0.10"
|
chacha20poly1305 = "0.10"
|
||||||
|
log = "0.4"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio-test = "0.4"
|
tokio = { version = "1.28", features = ["io-util", "macros", "rt-multi-thread", "net"] }
|
||||||
|
tcp-test = "0.1"
|
||||||
|
futures = "0.3"
|
||||||
|
simple_logger = "4.1"
|
||||||
|
hex-literal = "0.4.1"
|
|
@ -4,6 +4,8 @@ use std::error::Error;
|
||||||
use std::ffi::{OsStr};
|
use std::ffi::{OsStr};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use log::trace;
|
||||||
|
use crate::util::verifying_key;
|
||||||
|
|
||||||
pub struct EpfCaPool {
|
pub struct EpfCaPool {
|
||||||
pub ca_lookup_table: HashMap<EpfPublicKey, EPFCertificate>,
|
pub ca_lookup_table: HashMap<EpfPublicKey, EPFCertificate>,
|
||||||
|
@ -28,7 +30,7 @@ impl EpfCaPoolOps for EpfCaPool {
|
||||||
|
|
||||||
fn insert(&mut self, cert: &EPFCertificate) {
|
fn insert(&mut self, cert: &EPFCertificate) {
|
||||||
self.ca_lookup_table
|
self.ca_lookup_table
|
||||||
.insert(cert.details.public_key, cert.clone());
|
.insert(verifying_key(&cert.details.public_key), cert.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,19 +3,20 @@ use std::io;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use chacha20poly1305::{AeadCore, Key, KeyInit, XChaCha20Poly1305, XNonce};
|
use chacha20poly1305::{AeadCore, Key, KeyInit, XChaCha20Poly1305, XNonce};
|
||||||
use chacha20poly1305::aead::{Aead, Payload};
|
use chacha20poly1305::aead::{Aead, Payload};
|
||||||
use ed25519_dalek::{SigningKey};
|
use ed25519_dalek::{SecretKey, SigningKey};
|
||||||
|
use log::{debug, trace};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use x25519_dalek::x25519;
|
use x25519_dalek::{PublicKey, StaticSecret, x25519};
|
||||||
use crate::ca_pool::{load_ca_pool};
|
use crate::ca_pool::{EpfCaPool, load_ca_pool};
|
||||||
|
use crate::danger_trace;
|
||||||
use crate::error::EpfHandshakeError;
|
use crate::error::EpfHandshakeError;
|
||||||
use crate::pki::{EPFCertificate, EpfPkiCertificateOps, EpfPrivateKey, EpfPublicKey};
|
use crate::pki::{EPFCertificate, EPFPKI_PUBLIC_KEY_LENGTH, EpfPkiCertificateOps, EpfPrivateKey, EpfPublicKey};
|
||||||
use crate::protocol::{encode_packet, EpfApplicationData, EpfClientHello, EpfClientState, EpfFinished, EpfMessage, EpfServerHello, EpfServerState, PACKET_APPLICATION_DATA, PACKET_CLIENT_HELLO, PACKET_FINISHED, PACKET_SERVER_HELLO, PROTOCOL_VERSION, recv_packet};
|
use crate::protocol::{encode_packet, EpfApplicationData, EpfClientHello, EpfClientState, EpfFinished, EpfMessage, EpfServerHello, EpfServerState, PACKET_APPLICATION_DATA, PACKET_CLIENT_HELLO, PACKET_FINISHED, PACKET_SERVER_HELLO, PROTOCOL_VERSION, recv_packet};
|
||||||
|
|
||||||
///// CLIENT /////
|
///// CLIENT /////
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct EpfClientUpgraded<T: AsyncWriteExt + AsyncReadExt> {
|
pub struct EpfClientUpgraded<T: AsyncWriteExt + AsyncReadExt> {
|
||||||
inner: T,
|
inner: T,
|
||||||
state: EpfClientState,
|
state: EpfClientState,
|
||||||
|
@ -26,9 +27,10 @@ pub struct EpfClientUpgraded<T: AsyncWriteExt + AsyncReadExt> {
|
||||||
server_cert: Option<EPFCertificate>,
|
server_cert: Option<EPFCertificate>,
|
||||||
cipher: Option<XChaCha20Poly1305>,
|
cipher: Option<XChaCha20Poly1305>,
|
||||||
private_key: EpfPrivateKey,
|
private_key: EpfPrivateKey,
|
||||||
public_key: EpfPublicKey
|
public_key: PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ClientAuthentication {
|
pub enum ClientAuthentication {
|
||||||
Cert(Box<EPFCertificate>, EpfPrivateKey),
|
Cert(Box<EPFCertificate>, EpfPrivateKey),
|
||||||
Ephemeral
|
Ephemeral
|
||||||
|
@ -42,22 +44,25 @@ pub trait EpfClientUpgradable {
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T> EpfClientUpgradable for T where T: AsyncWriteExt + AsyncReadExt + Send {
|
impl<T> EpfClientUpgradable for T where T: AsyncWriteExt + AsyncReadExt + Send {
|
||||||
async fn upgrade(self, auth: ClientAuthentication) -> EpfClientUpgraded<Self> where Self: Sized + AsyncWriteExt + AsyncReadExt + Send {
|
async fn upgrade(self, auth: ClientAuthentication) -> EpfClientUpgraded<Self> where Self: Sized + AsyncWriteExt + AsyncReadExt + Send {
|
||||||
|
danger_trace!(target: "EpfClientUpgradable", "upgrade(auth: {:?})", auth);
|
||||||
|
|
||||||
let private_key;
|
let private_key;
|
||||||
let public_key: [u8; 32];
|
let public_key;
|
||||||
let cert;
|
let cert;
|
||||||
|
|
||||||
match auth {
|
match auth {
|
||||||
ClientAuthentication::Cert(cert_d, key) => {
|
ClientAuthentication::Cert(cert_d, key) => {
|
||||||
|
trace!("----!!!!! CERT AUTHENTICATION !!!!!----");
|
||||||
cert = Some(cert_d);
|
cert = Some(cert_d);
|
||||||
private_key = key;
|
private_key = key.clone();
|
||||||
public_key = key[32..].try_into().unwrap();
|
public_key = PublicKey::from(&StaticSecret::from(private_key.to_bytes()));
|
||||||
},
|
},
|
||||||
ClientAuthentication::Ephemeral => {
|
ClientAuthentication::Ephemeral => {
|
||||||
cert = None;
|
cert = None;
|
||||||
let private_key_l: [u8; 32] = OsRng.gen();
|
let private_key_l: [u8; 32] = OsRng.gen();
|
||||||
let private_key_real = SigningKey::from(private_key_l);
|
let private_key_real = SigningKey::from(private_key_l);
|
||||||
public_key = *private_key_real.verifying_key().as_bytes();
|
public_key = PublicKey::from(&StaticSecret::from(private_key_real.to_bytes()));
|
||||||
private_key = private_key_real.to_keypair_bytes();
|
private_key = private_key_real;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,33 +83,37 @@ impl<T> EpfClientUpgradable for T where T: AsyncWriteExt + AsyncReadExt + Send {
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait EpfClientHandshaker<S: AsyncWriteExt + AsyncReadExt + Unpin> {
|
pub trait EpfClientHandshaker<S: AsyncWriteExt + AsyncReadExt + Unpin> {
|
||||||
async fn handshake(&mut self) -> Result<(), Box<dyn Error>>;
|
async fn handshake(&mut self, cert_pool: EpfCaPool) -> Result<(), Box<dyn Error>>;
|
||||||
async fn upgrade(self) -> EpfClientStream<Self, S> where Self: Sized;
|
async fn upgrade(self) -> EpfClientStream<S> where Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfClientHandshaker<T> for EpfClientUpgraded<T> {
|
impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin> EpfClientHandshaker<T> for EpfClientUpgraded<T> {
|
||||||
async fn handshake(&mut self) -> Result<(), Box<dyn Error>> {
|
async fn handshake(&mut self, cert_pool: EpfCaPool) -> Result<(), Box<dyn Error>> {
|
||||||
match self.state {
|
match self.state {
|
||||||
EpfClientState::NotStarted => (),
|
EpfClientState::NotStarted => (),
|
||||||
_ => return Err(EpfHandshakeError::AlreadyTunnelled.into())
|
_ => return Err(EpfHandshakeError::AlreadyTunnelled.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 0: Load Trusted Cert Store
|
|
||||||
let cert_pool = load_ca_pool()?;
|
|
||||||
|
|
||||||
// Step 1: Send Client Hello
|
// Step 1: Send Client Hello
|
||||||
self.inner.write_all(&encode_packet(PACKET_CLIENT_HELLO, &EpfClientHello {
|
self.inner.write_all(&encode_packet(PACKET_CLIENT_HELLO, &EpfClientHello {
|
||||||
protocol_version: PROTOCOL_VERSION,
|
protocol_version: PROTOCOL_VERSION,
|
||||||
client_random: self.client_random,
|
client_random: self.client_random,
|
||||||
client_certificate: self.client_cert.clone(),
|
client_certificate: self.client_cert.clone(),
|
||||||
client_public_key: self.public_key,
|
client_x25519_public_key: self.public_key.to_bytes(),
|
||||||
})?).await?;
|
})?).await?;
|
||||||
|
self.inner.flush().await?;
|
||||||
|
|
||||||
|
trace!("---- !!!!! SENT CLIENT HELLO");
|
||||||
|
|
||||||
self.state = EpfClientState::WaitingForServerHello;
|
self.state = EpfClientState::WaitingForServerHello;
|
||||||
|
|
||||||
|
let server_x25519_key;
|
||||||
|
|
||||||
// Step 2: Wait for Server Hello
|
// Step 2: Wait for Server Hello
|
||||||
loop {
|
loop {
|
||||||
|
trace!("waiting for server hello");
|
||||||
|
|
||||||
let packet = recv_packet(&mut self.inner).await?;
|
let packet = recv_packet(&mut self.inner).await?;
|
||||||
|
|
||||||
if packet.packet_id != PACKET_SERVER_HELLO {
|
if packet.packet_id != PACKET_SERVER_HELLO {
|
||||||
|
@ -122,6 +131,8 @@ impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfClientHandshaker
|
||||||
|
|
||||||
self.server_cert = Some(server_hello.server_certificate);
|
self.server_cert = Some(server_hello.server_certificate);
|
||||||
|
|
||||||
|
server_x25519_key = server_hello.server_x25519_public_key;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +147,18 @@ impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfClientHandshaker
|
||||||
// Server Cert OK
|
// Server Cert OK
|
||||||
|
|
||||||
// Step 4: Build the cipher
|
// Step 4: Build the cipher
|
||||||
let shared_key = x25519(self.private_key[..32].try_into().unwrap(), self.server_cert.as_ref().unwrap().details.public_key);
|
|
||||||
|
let private_key = StaticSecret::from(self.private_key.to_bytes());
|
||||||
|
let their_public_key = PublicKey::from(server_x25519_key);
|
||||||
|
|
||||||
|
assert_ne!(their_public_key.to_bytes(), PublicKey::from(&private_key).to_bytes());
|
||||||
|
|
||||||
|
danger_trace!("pr: {}, their pub: {}, my pub: {}", hex::encode(self.private_key.to_bytes()), hex::encode(self.server_cert.as_ref().unwrap().details.public_key), hex::encode(self.private_key.verifying_key().to_bytes()));
|
||||||
|
|
||||||
|
let shared_key = private_key.diffie_hellman(&their_public_key).to_bytes();
|
||||||
|
|
||||||
|
trace!("server public key: {:x?}", self.server_cert.as_ref().unwrap().details.public_key);
|
||||||
|
danger_trace!("shared key: {}", hex::encode(shared_key));
|
||||||
|
|
||||||
let cc20p1305_key = Key::from(shared_key);
|
let cc20p1305_key = Key::from(shared_key);
|
||||||
let cc20p1305 = XChaCha20Poly1305::new(&cc20p1305_key);
|
let cc20p1305 = XChaCha20Poly1305::new(&cc20p1305_key);
|
||||||
|
@ -149,6 +171,10 @@ impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfClientHandshaker
|
||||||
|
|
||||||
let nonce = XNonce::from_slice(&self.client_random);
|
let nonce = XNonce::from_slice(&self.client_random);
|
||||||
|
|
||||||
|
trace!("encrypting 0x42");
|
||||||
|
|
||||||
|
danger_trace!("aad: {:?} nonce: {:?}", payload.aad, nonce);
|
||||||
|
|
||||||
let encrypted_0x42 = match self.cipher.as_ref().unwrap().encrypt(nonce, payload) {
|
let encrypted_0x42 = match self.cipher.as_ref().unwrap().encrypt(nonce, payload) {
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
@ -160,6 +186,7 @@ impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfClientHandshaker
|
||||||
protocol_version: PROTOCOL_VERSION,
|
protocol_version: PROTOCOL_VERSION,
|
||||||
encrypted_0x42
|
encrypted_0x42
|
||||||
})?).await?;
|
})?).await?;
|
||||||
|
self.inner.flush().await?;
|
||||||
|
|
||||||
self.state = EpfClientState::WaitingForFinished;
|
self.state = EpfClientState::WaitingForFinished;
|
||||||
|
|
||||||
|
@ -173,11 +200,15 @@ impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfClientHandshaker
|
||||||
|
|
||||||
let packet_finished: EpfFinished = rmp_serde::from_slice(&packet.packet_data)?;
|
let packet_finished: EpfFinished = rmp_serde::from_slice(&packet.packet_data)?;
|
||||||
|
|
||||||
|
trace!("trying to debug 0x42");
|
||||||
|
|
||||||
let payload = Payload {
|
let payload = Payload {
|
||||||
msg: &packet_finished.encrypted_0x42,
|
msg: &packet_finished.encrypted_0x42,
|
||||||
aad: &self.server_random,
|
aad: &self.server_random,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
danger_trace!("ciphertext: {:?}, aad: {:?}, nonce: {:?}", packet_finished.encrypted_0x42, payload.aad, nonce);
|
||||||
|
|
||||||
let hopefully_0x42 = match self.cipher.as_ref().unwrap().decrypt(nonce, payload) {
|
let hopefully_0x42 = match self.cipher.as_ref().unwrap().decrypt(nonce, payload) {
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
@ -197,23 +228,29 @@ impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfClientHandshaker
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn upgrade(self) -> EpfClientStream<Self, T> where Self: Sized {
|
async fn upgrade(self) -> EpfClientStream<T> where Self: Sized {
|
||||||
|
let aad = self.server_random.clone();
|
||||||
|
let client_cert = self.client_cert.clone();
|
||||||
|
let packet_queue = self.packet_queue.clone();
|
||||||
|
let server_cert = self.server_cert.unwrap().clone();
|
||||||
|
let cipher = self.cipher.unwrap().clone();
|
||||||
|
let private_key = self.private_key.clone();
|
||||||
|
let public_key = self.public_key.clone();
|
||||||
|
let raw_stream = self.inner;
|
||||||
EpfClientStream {
|
EpfClientStream {
|
||||||
inner: self.clone(),
|
raw_stream,
|
||||||
aad: self.server_random,
|
aad,
|
||||||
client_cert: self.client_cert,
|
client_cert,
|
||||||
packet_queue: self.packet_queue,
|
packet_queue,
|
||||||
server_cert: self.server_cert.unwrap(),
|
server_cert,
|
||||||
cipher: self.cipher.unwrap(),
|
cipher,
|
||||||
private_key: self.private_key,
|
private_key,
|
||||||
public_key: self.public_key,
|
public_key,
|
||||||
raw_stream: self.inner
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EpfClientStream<T: EpfClientHandshaker<S>, S: AsyncReadExt + AsyncWriteExt + Unpin> {
|
pub struct EpfClientStream<S: AsyncReadExt + AsyncWriteExt + Unpin> {
|
||||||
inner: T,
|
|
||||||
raw_stream: S,
|
raw_stream: S,
|
||||||
aad: [u8; 16],
|
aad: [u8; 16],
|
||||||
client_cert: Option<EPFCertificate>,
|
client_cert: Option<EPFCertificate>,
|
||||||
|
@ -221,7 +258,7 @@ pub struct EpfClientStream<T: EpfClientHandshaker<S>, S: AsyncReadExt + AsyncWri
|
||||||
server_cert: EPFCertificate,
|
server_cert: EPFCertificate,
|
||||||
cipher: XChaCha20Poly1305,
|
cipher: XChaCha20Poly1305,
|
||||||
private_key: EpfPrivateKey,
|
private_key: EpfPrivateKey,
|
||||||
public_key: EpfPublicKey
|
public_key: PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -231,7 +268,7 @@ pub trait EpfStreamOps {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T: EpfClientHandshaker<S> + Send, S: AsyncReadExt + AsyncWriteExt + Unpin + Send> EpfStreamOps for EpfClientStream<T, S> {
|
impl<S: AsyncReadExt + AsyncWriteExt + Unpin + Send> EpfStreamOps for EpfClientStream<S> {
|
||||||
async fn write(&mut self, data: &[u8]) -> Result<(), Box<dyn Error>> {
|
async fn write(&mut self, data: &[u8]) -> Result<(), Box<dyn Error>> {
|
||||||
let nonce = XChaCha20Poly1305::generate_nonce(OsRng);
|
let nonce = XChaCha20Poly1305::generate_nonce(OsRng);
|
||||||
|
|
||||||
|
@ -255,6 +292,7 @@ impl<T: EpfClientHandshaker<S> + Send, S: AsyncReadExt + AsyncWriteExt + Unpin +
|
||||||
let packet = encode_packet(PACKET_APPLICATION_DATA, &application_data)?;
|
let packet = encode_packet(PACKET_APPLICATION_DATA, &application_data)?;
|
||||||
|
|
||||||
self.raw_stream.write_all(&packet).await?;
|
self.raw_stream.write_all(&packet).await?;
|
||||||
|
self.raw_stream.flush().await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -291,7 +329,6 @@ impl<T: EpfClientHandshaker<S> + Send, S: AsyncReadExt + AsyncWriteExt + Unpin +
|
||||||
|
|
||||||
///// SERVER /////
|
///// SERVER /////
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct EpfServerUpgraded<T: AsyncWriteExt + AsyncReadExt> {
|
pub struct EpfServerUpgraded<T: AsyncWriteExt + AsyncReadExt> {
|
||||||
inner: T,
|
inner: T,
|
||||||
state: EpfServerState,
|
state: EpfServerState,
|
||||||
|
@ -311,7 +348,7 @@ pub trait EpfServerUpgradable {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T> EpfServerUpgradable for T where T: AsyncWriteExt + AsyncReadExt + Send {
|
impl<T: ?Sized> EpfServerUpgradable for T where T: AsyncWriteExt + AsyncReadExt + Send {
|
||||||
async fn upgrade(self, cert: EPFCertificate, private_key: EpfPrivateKey) -> EpfServerUpgraded<Self> where Self: Sized + AsyncWriteExt + AsyncReadExt + Send {
|
async fn upgrade(self, cert: EPFCertificate, private_key: EpfPrivateKey) -> EpfServerUpgraded<Self> where Self: Sized + AsyncWriteExt + AsyncReadExt + Send {
|
||||||
EpfServerUpgraded {
|
EpfServerUpgraded {
|
||||||
inner: self,
|
inner: self,
|
||||||
|
@ -322,29 +359,26 @@ impl<T> EpfServerUpgradable for T where T: AsyncWriteExt + AsyncReadExt + Send {
|
||||||
client_cert: None,
|
client_cert: None,
|
||||||
packet_queue: vec![],
|
packet_queue: vec![],
|
||||||
cipher: None,
|
cipher: None,
|
||||||
private_key,
|
private_key: private_key.clone(),
|
||||||
public_key: SigningKey::from_keypair_bytes(&private_key).unwrap().verifying_key().to_bytes(),
|
public_key: private_key.verifying_key(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait EpfServerHandshaker<S: AsyncWriteExt + AsyncReadExt + Unpin> {
|
pub trait EpfServerHandshaker<S: AsyncWriteExt + AsyncReadExt + Unpin> {
|
||||||
async fn handshake(&mut self) -> Result<(), Box<dyn Error>>;
|
async fn handshake(&mut self, cert_pool: EpfCaPool) -> Result<(), Box<dyn Error>>;
|
||||||
async fn upgrade(self) -> EpfServerStream<Self, S> where Self: Sized;
|
async fn upgrade(self) -> EpfServerStream<S> where Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfServerHandshaker<T> for EpfServerUpgraded<T> {
|
impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin> EpfServerHandshaker<T> for EpfServerUpgraded<T> {
|
||||||
async fn handshake(&mut self) -> Result<(), Box<dyn Error>> {
|
async fn handshake(&mut self, cert_pool: EpfCaPool) -> Result<(), Box<dyn Error>> {
|
||||||
match self.state {
|
match self.state {
|
||||||
EpfServerState::WaitingForClientHello => (),
|
EpfServerState::WaitingForClientHello => (),
|
||||||
_ => return Err(EpfHandshakeError::AlreadyTunnelled.into())
|
_ => return Err(EpfHandshakeError::AlreadyTunnelled.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 0: Load Trusted Cert Store
|
|
||||||
let cert_pool = load_ca_pool()?;
|
|
||||||
|
|
||||||
let client_public_key;
|
let client_public_key;
|
||||||
|
|
||||||
// Step 1: Wait for Client Hello
|
// Step 1: Wait for Client Hello
|
||||||
|
@ -356,6 +390,8 @@ impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfServerHandshaker
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trace!("got client hello");
|
||||||
|
|
||||||
let client_hello: EpfClientHello = rmp_serde::from_slice(&packet.packet_data)?;
|
let client_hello: EpfClientHello = rmp_serde::from_slice(&packet.packet_data)?;
|
||||||
|
|
||||||
self.client_random = client_hello.client_random;
|
self.client_random = client_hello.client_random;
|
||||||
|
@ -366,7 +402,9 @@ impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfServerHandshaker
|
||||||
|
|
||||||
self.client_cert = client_hello.client_certificate;
|
self.client_cert = client_hello.client_certificate;
|
||||||
|
|
||||||
client_public_key = client_hello.client_public_key;
|
client_public_key = client_hello.client_x25519_public_key;
|
||||||
|
|
||||||
|
trace!("exiting loop");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -383,17 +421,33 @@ impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfServerHandshaker
|
||||||
}
|
}
|
||||||
// Client Cert OK (if present)
|
// Client Cert OK (if present)
|
||||||
|
|
||||||
|
trace!("client cert okay");
|
||||||
|
|
||||||
// Step 3: Send Server Hello
|
// Step 3: Send Server Hello
|
||||||
self.inner.write_all(&encode_packet(PACKET_SERVER_HELLO, &EpfServerHello {
|
self.inner.write_all(&encode_packet(PACKET_SERVER_HELLO, &EpfServerHello {
|
||||||
protocol_version: PROTOCOL_VERSION,
|
protocol_version: PROTOCOL_VERSION,
|
||||||
server_certificate: self.cert.clone(),
|
server_certificate: self.cert.clone(),
|
||||||
server_random: self.server_random,
|
server_random: self.server_random,
|
||||||
|
server_x25519_public_key: PublicKey::from(&StaticSecret::from(self.private_key.to_bytes())).to_bytes()
|
||||||
})?).await?;
|
})?).await?;
|
||||||
|
self.inner.flush().await?;
|
||||||
|
|
||||||
|
trace!("sent server hello");
|
||||||
|
|
||||||
self.state = EpfServerState::WaitingForFinished;
|
self.state = EpfServerState::WaitingForFinished;
|
||||||
|
|
||||||
// Step 4: Build the cipher
|
// Step 4: Build the cipher
|
||||||
let shared_key = x25519(self.private_key[..32].try_into().unwrap(), client_public_key);
|
let private_key = StaticSecret::from(self.private_key.to_bytes());
|
||||||
|
let their_public_key = PublicKey::from(client_public_key);
|
||||||
|
|
||||||
|
assert_ne!(their_public_key.to_bytes(), PublicKey::from(&private_key).to_bytes());
|
||||||
|
|
||||||
|
danger_trace!("pr: {}, their pub: {}, my pub: {}", hex::encode(self.private_key.to_bytes()), hex::encode(client_public_key), hex::encode(self.private_key.verifying_key().to_bytes()));
|
||||||
|
|
||||||
|
let shared_key = private_key.diffie_hellman(&their_public_key).to_bytes();
|
||||||
|
|
||||||
|
trace!("client public key: {:x?}", client_public_key);
|
||||||
|
danger_trace!("shared key: {}", hex::encode(shared_key));
|
||||||
|
|
||||||
let cc20p1305_key = Key::from(shared_key);
|
let cc20p1305_key = Key::from(shared_key);
|
||||||
let cc20p1305 = XChaCha20Poly1305::new(&cc20p1305_key);
|
let cc20p1305 = XChaCha20Poly1305::new(&cc20p1305_key);
|
||||||
|
@ -421,6 +475,9 @@ impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfServerHandshaker
|
||||||
aad: &self.server_random,
|
aad: &self.server_random,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
trace!("trying to decrypt 0x42");
|
||||||
|
danger_trace!("ciphertext: {:?}, nonce: {:?}, aad: {:?}", payload.msg, nonce, payload.aad);
|
||||||
|
|
||||||
let hopefully_0x42 = match self.cipher.as_ref().unwrap().decrypt(nonce, payload) {
|
let hopefully_0x42 = match self.cipher.as_ref().unwrap().decrypt(nonce, payload) {
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
@ -446,6 +503,7 @@ impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfServerHandshaker
|
||||||
protocol_version: PROTOCOL_VERSION,
|
protocol_version: PROTOCOL_VERSION,
|
||||||
encrypted_0x42
|
encrypted_0x42
|
||||||
})?).await?;
|
})?).await?;
|
||||||
|
self.inner.flush().await?;
|
||||||
|
|
||||||
self.state = EpfServerState::WaitingForFinished;
|
self.state = EpfServerState::WaitingForFinished;
|
||||||
|
|
||||||
|
@ -454,9 +512,8 @@ impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfServerHandshaker
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn upgrade(self) -> EpfServerStream<Self, T> where Self: Sized {
|
async fn upgrade(self) -> EpfServerStream<T> where Self: Sized {
|
||||||
EpfServerStream {
|
EpfServerStream {
|
||||||
inner: self.clone(),
|
|
||||||
aad: self.server_random,
|
aad: self.server_random,
|
||||||
server_cert: self.cert,
|
server_cert: self.cert,
|
||||||
packet_queue: self.packet_queue,
|
packet_queue: self.packet_queue,
|
||||||
|
@ -469,8 +526,7 @@ impl<T: AsyncWriteExt + AsyncReadExt + Send + Unpin + Clone> EpfServerHandshaker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EpfServerStream<T: EpfServerHandshaker<S>, S: AsyncReadExt + AsyncWriteExt + Unpin> {
|
pub struct EpfServerStream<S: AsyncReadExt + AsyncWriteExt + Unpin> {
|
||||||
inner: T,
|
|
||||||
raw_stream: S,
|
raw_stream: S,
|
||||||
aad: [u8; 16],
|
aad: [u8; 16],
|
||||||
client_cert: Option<EPFCertificate>,
|
client_cert: Option<EPFCertificate>,
|
||||||
|
@ -482,7 +538,7 @@ pub struct EpfServerStream<T: EpfServerHandshaker<S>, S: AsyncReadExt + AsyncWri
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T: EpfServerHandshaker<S> + Send, S: AsyncReadExt + AsyncWriteExt + Unpin + Send> EpfStreamOps for EpfServerStream<T, S> {
|
impl<S: AsyncReadExt + AsyncWriteExt + Unpin + Send> EpfStreamOps for EpfServerStream<S> {
|
||||||
async fn write(&mut self, data: &[u8]) -> Result<(), Box<dyn Error>> {
|
async fn write(&mut self, data: &[u8]) -> Result<(), Box<dyn Error>> {
|
||||||
let nonce = XChaCha20Poly1305::generate_nonce(OsRng);
|
let nonce = XChaCha20Poly1305::generate_nonce(OsRng);
|
||||||
|
|
||||||
|
@ -506,6 +562,7 @@ impl<T: EpfServerHandshaker<S> + Send, S: AsyncReadExt + AsyncWriteExt + Unpin +
|
||||||
let packet = encode_packet(PACKET_APPLICATION_DATA, &application_data)?;
|
let packet = encode_packet(PACKET_APPLICATION_DATA, &application_data)?;
|
||||||
|
|
||||||
self.raw_stream.write_all(&packet).await?;
|
self.raw_stream.write_all(&packet).await?;
|
||||||
|
self.raw_stream.flush().await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -542,10 +599,109 @@ impl<T: EpfServerHandshaker<S> + Send, S: AsyncReadExt + AsyncWriteExt + Unpin +
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::io::Cursor;
|
use std::net::SocketAddr;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
use ed25519_dalek::{SecretKey, SigningKey};
|
||||||
|
use log::{debug, trace};
|
||||||
|
use rand::rngs::OsRng;
|
||||||
|
use tcp_test::channel;
|
||||||
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
use tokio::join;
|
||||||
|
use tokio::net::{TcpListener, TcpSocket, TcpStream};
|
||||||
|
use x25519_dalek::{PublicKey, StaticSecret};
|
||||||
|
use crate::ca_pool::{EpfCaPool, EpfCaPoolOps};
|
||||||
|
use crate::handshake_stream::{ClientAuthentication, EpfClientHandshaker, EpfClientUpgradable, EpfClientUpgraded, EpfServerHandshaker, EpfServerUpgradable, EpfServerUpgraded, EpfStreamOps};
|
||||||
|
use crate::pki::{EPFCertificate, EPFCertificateDetails, EpfPkiCertificateOps};
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
pub async fn stream_test() {
|
||||||
|
simple_logger::init().unwrap();
|
||||||
|
|
||||||
|
let tcp_listener = TcpListener::bind("0.0.0.0:36116").await.unwrap();
|
||||||
|
|
||||||
|
let tcp_client_future = TcpSocket::new_v4().unwrap().connect(SocketAddr::from_str("127.0.0.1:36116").unwrap());
|
||||||
|
|
||||||
|
let (a, b) = join![tcp_listener.accept(), tcp_client_future];
|
||||||
|
|
||||||
|
let (s, _) = a.unwrap();
|
||||||
|
let c = b.unwrap();
|
||||||
|
|
||||||
|
let server_private_key = SigningKey::from([1u8; 32]);
|
||||||
|
let client_private_key = SigningKey::from([2u8; 32]);
|
||||||
|
|
||||||
|
let mut server_cert = EPFCertificate {
|
||||||
|
details: EPFCertificateDetails {
|
||||||
|
name: "Testing Server Certificate".to_string(),
|
||||||
|
not_before: 0,
|
||||||
|
not_after: SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() + 30,
|
||||||
|
public_key: server_private_key.verifying_key().to_bytes(),
|
||||||
|
issuer_public_key: [0u8; 32],
|
||||||
|
claims: Default::default(),
|
||||||
|
},
|
||||||
|
fingerprint: "".to_string(),
|
||||||
|
signature: [0u8; 64],
|
||||||
|
};
|
||||||
|
server_cert.sign(&server_private_key).unwrap();
|
||||||
|
|
||||||
|
debug!("{}", hex::encode(server_private_key.verifying_key().to_bytes()));
|
||||||
|
|
||||||
|
let mut client_cert = EPFCertificate {
|
||||||
|
details: EPFCertificateDetails {
|
||||||
|
name: "Testing Client Certificate".to_string(),
|
||||||
|
not_before: 0,
|
||||||
|
not_after: SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() + 30,
|
||||||
|
public_key: client_private_key.verifying_key().to_bytes(),
|
||||||
|
issuer_public_key: [0u8; 32],
|
||||||
|
claims: Default::default(),
|
||||||
|
},
|
||||||
|
fingerprint: "".to_string(),
|
||||||
|
signature: [0u8; 64],
|
||||||
|
};
|
||||||
|
client_cert.sign(&client_private_key).unwrap();
|
||||||
|
|
||||||
|
let mut cert_pool = EpfCaPool::new();
|
||||||
|
let mut cert_pool_2 = EpfCaPool::new();
|
||||||
|
cert_pool.insert(&server_cert);
|
||||||
|
cert_pool.insert(&client_cert);
|
||||||
|
cert_pool_2.insert(&client_cert);
|
||||||
|
cert_pool_2.insert(&server_cert);
|
||||||
|
|
||||||
|
let mut c: EpfClientUpgraded<TcpStream> = EpfClientUpgradable::upgrade(c, ClientAuthentication::Cert(Box::new(client_cert), client_private_key)).await;
|
||||||
|
let mut s: EpfServerUpgraded<TcpStream> = EpfServerUpgradable::upgrade(s, server_cert, server_private_key).await;
|
||||||
|
|
||||||
|
let server_handshake_accept_task = tokio::spawn(async move {
|
||||||
|
trace!("starting server handshake listener");
|
||||||
|
s.handshake(cert_pool_2).await.unwrap();
|
||||||
|
let mut upgraded = s.upgrade().await;
|
||||||
|
assert_eq!(upgraded.read().await.unwrap(), vec![0x42, 0x42])
|
||||||
|
});
|
||||||
|
|
||||||
|
let client_handshake_send_task = tokio::spawn(async move {
|
||||||
|
trace!("starting client handshake sender");
|
||||||
|
c.handshake(cert_pool).await.unwrap();
|
||||||
|
let mut upgraded = EpfClientHandshaker::upgrade(c).await;
|
||||||
|
upgraded.write(&[0x42, 0x42]).await.unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
let (a, b) = join![server_handshake_accept_task, client_handshake_send_task];
|
||||||
|
a.unwrap();
|
||||||
|
b.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn stream_test() {
|
pub fn x25519_sanity_check() {
|
||||||
|
let bob_key = StaticSecret::from([1u8; 32]);
|
||||||
|
let bob_pub = PublicKey::from(&bob_key);
|
||||||
|
|
||||||
|
let alice_key = StaticSecret::from([2u8; 32]);
|
||||||
|
let alice_pub = PublicKey::from(&alice_key);
|
||||||
|
|
||||||
|
let ss_1 = bob_key.diffie_hellman(&alice_pub);
|
||||||
|
let ss_2 = alice_key.diffie_hellman(&bob_pub);
|
||||||
|
|
||||||
|
assert_eq!(ss_1.to_bytes(), ss_2.to_bytes());
|
||||||
|
|
||||||
|
println!("SS: {}, B_p: {}, A_p: {}", hex::encode(ss_1.to_bytes()), hex::encode(bob_pub.to_bytes()), hex::encode(alice_pub.to_bytes()));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,4 +3,6 @@ pub mod pki;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
pub mod protocol;
|
pub mod protocol;
|
||||||
pub mod handshake_stream;
|
pub mod handshake_stream;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
#[macro_use]
|
||||||
|
pub mod log;
|
|
@ -0,0 +1,17 @@
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! danger_trace {
|
||||||
|
// trace!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
|
||||||
|
// trace!(target: "my_target", "a {} event", "log")
|
||||||
|
(target: $target:expr, $($arg:tt)+) => {
|
||||||
|
if std::env::var("E3PF_SUPER_DANGEROUS_VERY_VERBOSE_DEBUGGING_LOGGING") == Ok("enabled".to_string()) && cfg!(debug_assertions) {
|
||||||
|
log::trace!(target: $target, $($arg)+)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// trace!("a {} event", "log")
|
||||||
|
($($arg:tt)+) => {
|
||||||
|
if std::env::var("E3PF_SUPER_DANGEROUS_VERY_VERBOSE_DEBUGGING_LOGGING") == Ok("enabled".to_string()) && cfg!(debug_assertions) {
|
||||||
|
log::trace!($($arg)+)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::ca_pool::{EpfCaPool, EpfCaPoolOps};
|
use crate::ca_pool::{EpfCaPool, EpfCaPoolOps};
|
||||||
use crate::util::{pretty_print_date, u64_to_st};
|
use crate::util::{pretty_print_date, u64_to_st, verifying_key};
|
||||||
use ed25519_dalek::{Signature, SignatureError, Signer, SigningKey, Verifier, VerifyingKey};
|
use ed25519_dalek::{Signature, SignatureError, Signer, SigningKey, Verifier, VerifyingKey};
|
||||||
use pem::Pem;
|
use pem::Pem;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -15,8 +15,8 @@ pub const EPFPKI_SIGNATURE_LENGTH: usize = 64;
|
||||||
pub const EPFPKI_SELF_SIGNED_CERTIFICATE: &str =
|
pub const EPFPKI_SELF_SIGNED_CERTIFICATE: &str =
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000";
|
"0000000000000000000000000000000000000000000000000000000000000000";
|
||||||
|
|
||||||
pub type EpfPublicKey = [u8; 32];
|
pub type EpfPublicKey = VerifyingKey;
|
||||||
pub type EpfPrivateKey = [u8; 64];
|
pub type EpfPrivateKey = SigningKey;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Eq, Clone)]
|
#[derive(Serialize, Deserialize, PartialEq, Debug, Eq, Clone)]
|
||||||
pub struct EPFCertificate {
|
pub struct EPFCertificate {
|
||||||
|
@ -43,8 +43,8 @@ pub struct EPFCertificateDetails {
|
||||||
pub trait EpfPkiSerializable {
|
pub trait EpfPkiSerializable {
|
||||||
const PEM_BANNER: &'static str;
|
const PEM_BANNER: &'static str;
|
||||||
|
|
||||||
fn as_bytes(&self) -> Result<Vec<u8>, rmp_serde::encode::Error>;
|
fn as_bytes_pki(&self) -> Result<Vec<u8>, rmp_serde::encode::Error>;
|
||||||
fn from_bytes(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error>
|
fn from_bytes_pki(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
|
@ -62,10 +62,6 @@ pub fn fingerprint(cert: &EPFCertificateDetails) -> Result<String, rmp_serde::en
|
||||||
Ok(hex::encode(hash))
|
Ok(hex::encode(hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_signing_key(b: &[u8; 64]) -> Result<SigningKey, SignatureError> {
|
|
||||||
SigningKey::from_keypair_bytes(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum EpfPkiCertificateValidationError {
|
pub enum EpfPkiCertificateValidationError {
|
||||||
NoLongerValid { expired_at: SystemTime },
|
NoLongerValid { expired_at: SystemTime },
|
||||||
|
@ -132,12 +128,11 @@ impl EpfPkiCertificateOps for EPFCertificate {
|
||||||
fn sign(&mut self, private_key: &EpfPrivateKey) -> Result<(), Box<dyn Error>> {
|
fn sign(&mut self, private_key: &EpfPrivateKey) -> Result<(), Box<dyn Error>> {
|
||||||
self.recalculate_fingerprint()?;
|
self.recalculate_fingerprint()?;
|
||||||
|
|
||||||
let signing_key = load_signing_key(private_key)?;
|
self.details.issuer_public_key = *private_key.verifying_key().as_bytes();
|
||||||
self.details.issuer_public_key = *signing_key.verifying_key().as_bytes();
|
|
||||||
|
|
||||||
let cert_data_bytes = rmp_serde::to_vec(&self.details)?;
|
let cert_data_bytes = rmp_serde::to_vec(&self.details)?;
|
||||||
|
|
||||||
let signature = signing_key.sign(&cert_data_bytes).to_vec();
|
let signature = private_key.sign(&cert_data_bytes).to_vec();
|
||||||
|
|
||||||
self.signature = signature.try_into().unwrap();
|
self.signature = signature.try_into().unwrap();
|
||||||
|
|
||||||
|
@ -182,26 +177,19 @@ impl EpfPkiCertificateOps for EPFCertificate {
|
||||||
|
|
||||||
let is_self_signed;
|
let is_self_signed;
|
||||||
|
|
||||||
println!(
|
let public_key = if self.details.issuer_public_key == self.details.public_key {
|
||||||
"{}: {:?} {:?}",
|
|
||||||
self.details.name, self.details.issuer_public_key, self.details.public_key
|
|
||||||
);
|
|
||||||
|
|
||||||
let verifying_key = if self.details.issuer_public_key == self.details.public_key {
|
|
||||||
// self-signed certificate
|
// self-signed certificate
|
||||||
is_self_signed = true;
|
is_self_signed = true;
|
||||||
VerifyingKey::from_bytes(&self.details.public_key)
|
verifying_key(&self.details.public_key)
|
||||||
.map_err(|e| EpfPkiCertificateValidationError::InvalidSignature { e })?
|
|
||||||
} else {
|
} else {
|
||||||
is_self_signed = false;
|
is_self_signed = false;
|
||||||
VerifyingKey::from_bytes(&self.details.issuer_public_key)
|
verifying_key(&self.details.issuer_public_key)
|
||||||
.map_err(|e| EpfPkiCertificateValidationError::InvalidSignature { e })?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let cert_data_bytes = rmp_serde::to_vec(&self.details)
|
let cert_data_bytes = rmp_serde::to_vec(&self.details)
|
||||||
.map_err(|e| EpfPkiCertificateValidationError::InvalidCertificateData { e })?;
|
.map_err(|e| EpfPkiCertificateValidationError::InvalidCertificateData { e })?;
|
||||||
|
|
||||||
verifying_key
|
public_key
|
||||||
.verify(&cert_data_bytes, &signature)
|
.verify(&cert_data_bytes, &signature)
|
||||||
.map_err(|e| EpfPkiCertificateValidationError::InvalidSignature { e })?;
|
.map_err(|e| EpfPkiCertificateValidationError::InvalidSignature { e })?;
|
||||||
|
|
||||||
|
@ -209,12 +197,12 @@ impl EpfPkiCertificateOps for EPFCertificate {
|
||||||
|
|
||||||
// Is the signer trusted?
|
// Is the signer trusted?
|
||||||
let ca_cert = if is_self_signed {
|
let ca_cert = if is_self_signed {
|
||||||
if let Some(cert) = ca_pool.get_ca(&self.details.public_key) {
|
if let Some(cert) = ca_pool.get_ca(&verifying_key(&self.details.public_key)) {
|
||||||
cert
|
cert
|
||||||
} else {
|
} else {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
} else if let Some(cert) = ca_pool.get_ca(&self.details.issuer_public_key) {
|
} else if let Some(cert) = ca_pool.get_ca(&verifying_key(&self.details.issuer_public_key) ){
|
||||||
cert
|
cert
|
||||||
} else {
|
} else {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
|
@ -275,16 +263,16 @@ impl Display for EPFCertificate {
|
||||||
impl EpfPkiSerializable for EPFCertificate {
|
impl EpfPkiSerializable for EPFCertificate {
|
||||||
const PEM_BANNER: &'static str = "EPF CERTIFICATE";
|
const PEM_BANNER: &'static str = "EPF CERTIFICATE";
|
||||||
|
|
||||||
fn as_bytes(&self) -> Result<Vec<u8>, rmp_serde::encode::Error> {
|
fn as_bytes_pki(&self) -> Result<Vec<u8>, rmp_serde::encode::Error> {
|
||||||
rmp_serde::to_vec(self)
|
rmp_serde::to_vec(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_bytes(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
|
fn from_bytes_pki(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
|
||||||
rmp_serde::from_slice(bytes)
|
rmp_serde::from_slice(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_pem(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
fn as_pem(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
Ok(pem::encode(&Pem::new(Self::PEM_BANNER, self.as_bytes()?))
|
Ok(pem::encode(&Pem::new(Self::PEM_BANNER, self.as_bytes_pki()?))
|
||||||
.as_bytes()
|
.as_bytes()
|
||||||
.to_vec())
|
.to_vec())
|
||||||
}
|
}
|
||||||
|
@ -297,25 +285,25 @@ impl EpfPkiSerializable for EPFCertificate {
|
||||||
if pem.tag() != Self::PEM_BANNER {
|
if pem.tag() != Self::PEM_BANNER {
|
||||||
return Err("Not a certificate".into());
|
return Err("Not a certificate".into());
|
||||||
}
|
}
|
||||||
Ok(Self::from_bytes(pem.contents())?)
|
Ok(Self::from_bytes_pki(pem.contents())?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EpfPkiSerializable for EpfPublicKey {
|
impl EpfPkiSerializable for EpfPublicKey {
|
||||||
const PEM_BANNER: &'static str = "EPF PUBLIC KEY";
|
const PEM_BANNER: &'static str = "EPF PUBLIC KEY";
|
||||||
|
|
||||||
fn as_bytes(&self) -> Result<Vec<u8>, rmp_serde::encode::Error> {
|
fn as_bytes_pki(&self) -> Result<Vec<u8>, rmp_serde::encode::Error> {
|
||||||
Ok(self.to_vec())
|
Ok(self.as_bytes().to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_bytes(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
|
fn from_bytes_pki(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
|
||||||
bytes
|
bytes
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|_| rmp_serde::decode::Error::LengthMismatch(bytes.len() as u32))
|
.map_err(|_| rmp_serde::decode::Error::LengthMismatch(bytes.len() as u32))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_pem(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
fn as_pem(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
Ok(pem::encode(&Pem::new(Self::PEM_BANNER, self.as_bytes()?))
|
Ok(pem::encode(&Pem::new(Self::PEM_BANNER, self.as_bytes().to_vec()))
|
||||||
.as_bytes()
|
.as_bytes()
|
||||||
.to_vec())
|
.to_vec())
|
||||||
}
|
}
|
||||||
|
@ -328,25 +316,25 @@ impl EpfPkiSerializable for EpfPublicKey {
|
||||||
if pem.tag() != Self::PEM_BANNER {
|
if pem.tag() != Self::PEM_BANNER {
|
||||||
return Err("Not a public key".into());
|
return Err("Not a public key".into());
|
||||||
}
|
}
|
||||||
Ok(Self::from_bytes(pem.contents())?)
|
Ok(Self::from_bytes(pem.contents().try_into().map_err(|_| -> Box<dyn Error> { "Wrong size".into() })?)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EpfPkiSerializable for EpfPrivateKey {
|
impl EpfPkiSerializable for EpfPrivateKey {
|
||||||
const PEM_BANNER: &'static str = "EPF PRIVATE KEY";
|
const PEM_BANNER: &'static str = "EPF PRIVATE KEY";
|
||||||
|
|
||||||
fn as_bytes(&self) -> Result<Vec<u8>, rmp_serde::encode::Error> {
|
fn as_bytes_pki(&self) -> Result<Vec<u8>, rmp_serde::encode::Error> {
|
||||||
Ok(self.to_vec())
|
Ok(self.to_keypair_bytes().to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_bytes(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
|
fn from_bytes_pki(bytes: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
|
||||||
bytes
|
bytes
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|_| rmp_serde::decode::Error::LengthMismatch(bytes.len() as u32))
|
.map_err(|_| rmp_serde::decode::Error::LengthMismatch(bytes.len() as u32))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_pem(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
fn as_pem(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
Ok(pem::encode(&Pem::new(Self::PEM_BANNER, self.as_bytes()?))
|
Ok(pem::encode(&Pem::new(Self::PEM_BANNER, self.as_bytes_pki()?))
|
||||||
.as_bytes()
|
.as_bytes()
|
||||||
.to_vec())
|
.to_vec())
|
||||||
}
|
}
|
||||||
|
@ -359,7 +347,7 @@ impl EpfPkiSerializable for EpfPrivateKey {
|
||||||
if pem.tag() != Self::PEM_BANNER {
|
if pem.tag() != Self::PEM_BANNER {
|
||||||
return Err("Incorrect PEM tag".into());
|
return Err("Incorrect PEM tag".into());
|
||||||
}
|
}
|
||||||
Ok(Self::from_bytes(pem.contents())?)
|
Ok(Self::from_keypair_bytes(pem.contents().try_into().map_err(|_| -> Box<dyn Error> { "Wrong size".into() })?)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,15 +363,17 @@ mod tests {
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
use hex_literal::hex;
|
||||||
|
use crate::util::{signing_key, verifying_key};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn certificate_serialization() {
|
pub fn certificate_serialization() {
|
||||||
assert_eq!(cert().as_bytes().unwrap(), cert_bytes())
|
assert_eq!(cert().as_bytes_pki().unwrap(), cert_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn certificate_deserialization() {
|
pub fn certificate_deserialization() {
|
||||||
assert_eq!(EPFCertificate::from_bytes(&cert_bytes()).unwrap(), cert())
|
assert_eq!(EPFCertificate::from_bytes_pki(&cert_bytes()).unwrap(), cert())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -404,24 +394,24 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn pubkey_serialization() {
|
pub fn pubkey_serialization() {
|
||||||
assert_eq!(([0u8; 32]).as_bytes().unwrap(), [0u8; 32].to_vec())
|
assert_eq!((verifying_key(&[0u8; 32])).as_bytes_pki().unwrap(), [0u8; 32].to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn pubkey_deserialization() {
|
pub fn pubkey_deserialization() {
|
||||||
assert_eq!(EpfPublicKey::from_bytes(&[0u8; 32]).unwrap(), [0u8; 32])
|
assert_eq!(EpfPublicKey::from_bytes(&[0u8; 32]).unwrap(), verifying_key(&[0u8; 32]))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn pubkey_serialization_pem() {
|
pub fn pubkey_serialization_pem() {
|
||||||
assert_eq!(([0u8; 32]).as_pem().unwrap(), null_public_key_pem())
|
assert_eq!((verifying_key(&[0u8; 32])).as_pem().unwrap(), null_public_key_pem())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn pubkey_deserialization_pem() {
|
pub fn pubkey_deserialization_pem() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
EpfPublicKey::from_pem(&null_public_key_pem()).unwrap(),
|
EpfPublicKey::from_pem(&null_public_key_pem()).unwrap(),
|
||||||
[0u8; 32]
|
verifying_key(&[0u8; 32])
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,24 +423,31 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn privkey_serialization() {
|
pub fn privkey_serialization() {
|
||||||
assert_eq!(([0u8; 64]).as_bytes().unwrap(), [0u8; 64].to_vec())
|
let priv_key_data = hex!("00000000000000000000000000000000000000000000000000000000000000003B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29");
|
||||||
|
assert_eq!((signing_key(&priv_key_data)).as_bytes_pki().unwrap(), priv_key_data.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn privkey_deserialization() {
|
pub fn privkey_deserialization() {
|
||||||
assert_eq!(EpfPrivateKey::from_bytes(&[0u8; 64]).unwrap(), [0u8; 64])
|
let priv_key = EpfPrivateKey::generate(&mut OsRng);
|
||||||
|
|
||||||
|
assert_eq!(priv_key.to_keypair_bytes(), signing_key(&priv_key.to_keypair_bytes()).to_keypair_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn privkey_serialization_pem() {
|
pub fn privkey_serialization_pem() {
|
||||||
assert_eq!(([0u8; 64]).as_pem().unwrap(), null_private_key_pem())
|
let priv_key_data = hex!("00000000000000000000000000000000000000000000000000000000000000003B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29");
|
||||||
|
|
||||||
|
assert_eq!((signing_key(&priv_key_data)).as_pem().unwrap(), null_private_key_pem())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn privkey_deserialization_pem() {
|
pub fn privkey_deserialization_pem() {
|
||||||
|
let priv_key_data = hex!("00000000000000000000000000000000000000000000000000000000000000003B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
EpfPrivateKey::from_pem(&null_private_key_pem()).unwrap(),
|
EpfPrivateKey::from_pem(&null_private_key_pem()).unwrap().to_keypair_bytes(),
|
||||||
[0u8; 64]
|
signing_key(&priv_key_data).to_keypair_bytes()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,8 +455,8 @@ mod tests {
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
pub fn privkey_deserialization_pem_wrong_tag() {
|
pub fn privkey_deserialization_pem_wrong_tag() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
EpfPrivateKey::from_pem(&null_public_key_pem()).unwrap(),
|
EpfPrivateKey::from_pem(&null_public_key_pem()).unwrap().to_keypair_bytes(),
|
||||||
[0u8; 64]
|
signing_key(&[0u8; 64]).to_keypair_bytes()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,7 +510,7 @@ mod tests {
|
||||||
|
|
||||||
assert!(ca_cert.verify(&ca_pool).is_err());
|
assert!(ca_cert.verify(&ca_pool).is_err());
|
||||||
|
|
||||||
ca_cert.sign(&private_key.to_keypair_bytes()).unwrap();
|
ca_cert.sign(&private_key).unwrap();
|
||||||
|
|
||||||
assert!(!ca_cert.verify(&ca_pool).unwrap());
|
assert!(!ca_cert.verify(&ca_pool).unwrap());
|
||||||
|
|
||||||
|
@ -545,7 +542,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(not_ca_cert.verify(&ca_pool).is_err());
|
assert!(not_ca_cert.verify(&ca_pool).is_err());
|
||||||
not_ca_cert.sign(&private_key.to_keypair_bytes()).unwrap();
|
not_ca_cert.sign(&private_key).unwrap();
|
||||||
assert!(not_ca_cert.verify(&ca_pool).unwrap());
|
assert!(not_ca_cert.verify(&ca_pool).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,7 +633,7 @@ mod tests {
|
||||||
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
|
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
|
||||||
};
|
};
|
||||||
not_trusted_cert
|
not_trusted_cert
|
||||||
.sign(&private_key.to_keypair_bytes())
|
.sign(&private_key)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let ca_pool = EpfCaPool::new();
|
let ca_pool = EpfCaPool::new();
|
||||||
|
@ -675,7 +672,7 @@ mod tests {
|
||||||
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
|
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
|
||||||
};
|
};
|
||||||
|
|
||||||
ca_cert.sign(&private_key.to_keypair_bytes()).unwrap();
|
ca_cert.sign(&private_key).unwrap();
|
||||||
ca_pool.insert(&ca_cert);
|
ca_pool.insert(&ca_cert);
|
||||||
|
|
||||||
let mut not_ca_cert = EPFCertificate {
|
let mut not_ca_cert = EPFCertificate {
|
||||||
|
@ -700,7 +697,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(not_ca_cert.verify(&ca_pool).is_err());
|
assert!(not_ca_cert.verify(&ca_pool).is_err());
|
||||||
not_ca_cert.sign(&private_key.to_keypair_bytes()).unwrap();
|
not_ca_cert.sign(&private_key).unwrap();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
not_ca_cert.verify(&ca_pool).unwrap_err(),
|
not_ca_cert.verify(&ca_pool).unwrap_err(),
|
||||||
EpfPkiCertificateValidationError::ExpiresAfterSigner
|
EpfPkiCertificateValidationError::ExpiresAfterSigner
|
||||||
|
@ -738,7 +735,7 @@ mod tests {
|
||||||
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
|
signature: [0u8; EPFPKI_SIGNATURE_LENGTH],
|
||||||
};
|
};
|
||||||
|
|
||||||
ca_cert.sign(&private_key.to_keypair_bytes()).unwrap();
|
ca_cert.sign(&private_key).unwrap();
|
||||||
ca_pool.insert(&ca_cert);
|
ca_pool.insert(&ca_cert);
|
||||||
|
|
||||||
let mut not_ca_cert = EPFCertificate {
|
let mut not_ca_cert = EPFCertificate {
|
||||||
|
@ -763,7 +760,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(not_ca_cert.verify(&ca_pool).is_err());
|
assert!(not_ca_cert.verify(&ca_pool).is_err());
|
||||||
not_ca_cert.sign(&private_key.to_keypair_bytes()).unwrap();
|
not_ca_cert.sign(&private_key).unwrap();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
not_ca_cert.verify(&ca_pool).unwrap_err(),
|
not_ca_cert.verify(&ca_pool).unwrap_err(),
|
||||||
EpfPkiCertificateValidationError::ValidAfterSigner
|
EpfPkiCertificateValidationError::ValidAfterSigner
|
||||||
|
@ -869,15 +866,6 @@ mod tests {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
fn null_private_key_pem() -> Vec<u8> {
|
fn null_private_key_pem() -> Vec<u8> {
|
||||||
vec![
|
vec![45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 69, 80, 70, 32, 80, 82, 73, 86, 65, 84, 69, 32, 75, 69, 89, 45, 45, 45, 45, 45, 13, 10, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 55, 97, 105, 101, 56, 122, 114, 97, 107, 76, 87, 75, 106, 113, 78, 65, 113, 98, 119, 49, 122, 13, 10, 90, 84, 73, 86, 100, 120, 51, 105, 81, 54, 89, 54, 119, 69, 105, 104, 105, 49, 110, 97, 75, 81, 61, 61, 13, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 69, 80, 70, 32, 80, 82, 73, 86, 65, 84, 69, 32, 75, 69, 89, 45, 45, 45, 45, 45, 13, 10]
|
||||||
45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 69, 80, 70, 32, 80, 82, 73, 86, 65, 84, 69,
|
|
||||||
32, 75, 69, 89, 45, 45, 45, 45, 45, 13, 10, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
|
|
||||||
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
|
|
||||||
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
|
|
||||||
65, 65, 65, 65, 65, 65, 65, 65, 65, 13, 10, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
|
|
||||||
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 61, 61, 13, 10, 45, 45, 45, 45, 45, 69, 78,
|
|
||||||
68, 32, 69, 80, 70, 32, 80, 82, 73, 86, 65, 84, 69, 32, 75, 69, 89, 45, 45, 45, 45, 45,
|
|
||||||
13, 10,
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::io::{AsyncReadExt};
|
use tokio::io::{AsyncReadExt};
|
||||||
use crate::pki::{EPFCertificate, EPFPKI_PUBLIC_KEY_LENGTH};
|
use crate::pki::{EPFCertificate, EPFPKI_PUBLIC_KEY_LENGTH};
|
||||||
|
@ -18,7 +19,7 @@ pub struct EpfClientHello {
|
||||||
pub protocol_version: u32,
|
pub protocol_version: u32,
|
||||||
pub client_random: [u8; 24],
|
pub client_random: [u8; 24],
|
||||||
pub client_certificate: Option<EPFCertificate>,
|
pub client_certificate: Option<EPFCertificate>,
|
||||||
pub client_public_key: [u8; EPFPKI_PUBLIC_KEY_LENGTH]
|
pub client_x25519_public_key: [u8; EPFPKI_PUBLIC_KEY_LENGTH]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const PACKET_SERVER_HELLO: u32 = 2;
|
pub const PACKET_SERVER_HELLO: u32 = 2;
|
||||||
|
@ -27,7 +28,8 @@ pub const PACKET_SERVER_HELLO: u32 = 2;
|
||||||
pub struct EpfServerHello {
|
pub struct EpfServerHello {
|
||||||
pub protocol_version: u32,
|
pub protocol_version: u32,
|
||||||
pub server_certificate: EPFCertificate,
|
pub server_certificate: EPFCertificate,
|
||||||
pub server_random: [u8; 16]
|
pub server_random: [u8; 16],
|
||||||
|
pub server_x25519_public_key: [u8; EPFPKI_PUBLIC_KEY_LENGTH]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const PACKET_FINISHED: u32 = 3;
|
pub const PACKET_FINISHED: u32 = 3;
|
||||||
|
@ -71,6 +73,7 @@ pub fn encode_packet<T: Serialize>(id: u32, packet: &T) -> Result<Vec<u8>, rmp_s
|
||||||
packet_data: message_data,
|
packet_data: message_data,
|
||||||
};
|
};
|
||||||
let mut packet_data = rmp_serde::to_vec(&message_wrapper)?;
|
let mut packet_data = rmp_serde::to_vec(&message_wrapper)?;
|
||||||
|
|
||||||
let mut packet = (packet_data.len() as u64).to_le_bytes().to_vec();
|
let mut packet = (packet_data.len() as u64).to_le_bytes().to_vec();
|
||||||
// Packet: 8-byte little-endian length prefix, packet data
|
// Packet: 8-byte little-endian length prefix, packet data
|
||||||
packet.append(&mut packet_data);
|
packet.append(&mut packet_data);
|
||||||
|
@ -79,6 +82,7 @@ pub fn encode_packet<T: Serialize>(id: u32, packet: &T) -> Result<Vec<u8>, rmp_s
|
||||||
|
|
||||||
pub async fn recv_packet<C: AsyncReadExt + Unpin>(stream: &mut C) -> Result<EpfMessage, Box<dyn Error>> {
|
pub async fn recv_packet<C: AsyncReadExt + Unpin>(stream: &mut C) -> Result<EpfMessage, Box<dyn Error>> {
|
||||||
let packet_length = stream.read_u64_le().await?;
|
let packet_length = stream.read_u64_le().await?;
|
||||||
|
|
||||||
let mut packet_data_buf = vec![0u8; packet_length as usize];
|
let mut packet_data_buf = vec![0u8; packet_length as usize];
|
||||||
stream.read_exact(&mut packet_data_buf).await?;
|
stream.read_exact(&mut packet_data_buf).await?;
|
||||||
let message: EpfMessage = rmp_serde::from_slice(&packet_data_buf)?;
|
let message: EpfMessage = rmp_serde::from_slice(&packet_data_buf)?;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
use ed25519_dalek::{SigningKey, VerifyingKey};
|
||||||
|
|
||||||
pub fn pretty_print_date(date: &SystemTime) -> String {
|
pub fn pretty_print_date(date: &SystemTime) -> String {
|
||||||
let datetime: DateTime<Utc> = (*date).into();
|
let datetime: DateTime<Utc> = (*date).into();
|
||||||
|
@ -10,3 +11,10 @@ pub fn pretty_print_date(date: &SystemTime) -> String {
|
||||||
pub fn u64_to_st(unix: u64) -> SystemTime {
|
pub fn u64_to_st(unix: u64) -> SystemTime {
|
||||||
SystemTime::UNIX_EPOCH.add(Duration::from_secs(unix))
|
SystemTime::UNIX_EPOCH.add(Duration::from_secs(unix))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn verifying_key(key: &[u8; 32]) -> VerifyingKey {
|
||||||
|
VerifyingKey::from_bytes(key).unwrap()
|
||||||
|
}
|
||||||
|
pub fn signing_key(key: &[u8; 64]) -> SigningKey {
|
||||||
|
SigningKey::from_keypair_bytes(key).unwrap()
|
||||||
|
}
|
Loading…
Reference in New Issue