diff --git a/Cargo.lock b/Cargo.lock index 96eb5ff..c3393d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,28 +21,6 @@ dependencies = [ "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]] name = "async-trait" version = "0.1.68" @@ -54,6 +32,17 @@ dependencies = [ "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]] name = "autocfg" version = "1.1.0" @@ -145,7 +134,7 @@ dependencies = [ "js-sys", "num-integer", "num-traits", - "time", + "time 0.1.45", "wasm-bindgen", "winapi", ] @@ -171,6 +160,17 @@ dependencies = [ "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]] name = "const-oid" version = "0.9.2" @@ -312,12 +312,95 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "futures-core" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "generic-array" version = "0.14.7" @@ -339,12 +422,36 @@ dependencies = [ "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]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + [[package]] name = "iana-time-zone" version = "0.1.56" @@ -378,6 +485,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + [[package]] name = "js-sys" version = "0.3.61" @@ -387,6 +500,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.142" @@ -401,15 +520,19 @@ dependencies = [ "chacha20poly1305", "chrono", "ed25519-dalek", + "futures", "hex", + "hex-literal", + "log", "pem", "rand", "rmp-serde", "serde", "serde_arrays", "sha2", + "simple_logger", + "tcp-test", "tokio", - "tokio-test", "x25519-dalek", ] @@ -437,6 +560,24 @@ dependencies = [ "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]] name = "num-integer" version = "0.1.45" @@ -456,6 +597,25 @@ dependencies = [ "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]] name = "once_cell" version = "1.17.1" @@ -500,6 +660,12 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "pkcs8" version = "0.10.2" @@ -655,6 +821,38 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "spki" version = "0.7.1" @@ -693,6 +891,15 @@ dependencies = [ "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]] name = "termcolor" version = "1.2.0" @@ -713,6 +920,35 @@ dependencies = [ "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]] name = "tokio" version = "1.28.0" @@ -721,32 +957,24 @@ checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f" dependencies = [ "autocfg", "bytes", + "libc", + "mio", + "num_cpus", "pin-project-lite", - "windows-sys", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", ] [[package]] -name = "tokio-stream" -version = "0.1.14" +name = "tokio-macros" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[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", + "proc-macro2", + "quote", + "syn 2.0.15", ] [[package]] @@ -886,7 +1114,31 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" 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]] @@ -895,7 +1147,22 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 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]] @@ -904,51 +1171,93 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "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]] name = "windows_aarch64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "windows_x86_64_msvc" version = "0.48.0" diff --git a/libepf/Cargo.toml b/libepf/Cargo.toml index 4828feb..d2b49e8 100644 --- a/libepf/Cargo.toml +++ b/libepf/Cargo.toml @@ -14,11 +14,16 @@ hex = "0.4" sha2 = "0.10" ed25519-dalek = { version = "2.0.0-rc.2", features = ["rand_core"] } rand = "0.8" -x25519-dalek = "2.0.0-rc.2" +x25519-dalek = { version = "2.0.0-rc.2", features = ["static_secrets"] } chrono = "0.4" tokio = { version = "1.28", features = ["io-util"] } async-trait = "0.1" chacha20poly1305 = "0.10" +log = "0.4" [dev-dependencies] -tokio-test = "0.4" \ No newline at end of file +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" \ No newline at end of file diff --git a/libepf/src/ca_pool.rs b/libepf/src/ca_pool.rs index bd81034..b81ddb5 100644 --- a/libepf/src/ca_pool.rs +++ b/libepf/src/ca_pool.rs @@ -4,6 +4,8 @@ use std::error::Error; use std::ffi::{OsStr}; use std::fmt::{Display, Formatter}; use std::fs; +use log::trace; +use crate::util::verifying_key; pub struct EpfCaPool { pub ca_lookup_table: HashMap, @@ -28,7 +30,7 @@ impl EpfCaPoolOps for EpfCaPool { fn insert(&mut self, cert: &EPFCertificate) { self.ca_lookup_table - .insert(cert.details.public_key, cert.clone()); + .insert(verifying_key(&cert.details.public_key), cert.clone()); } } diff --git a/libepf/src/handshake_stream.rs b/libepf/src/handshake_stream.rs index d22bca5..99e132b 100644 --- a/libepf/src/handshake_stream.rs +++ b/libepf/src/handshake_stream.rs @@ -3,19 +3,20 @@ use std::io; use async_trait::async_trait; use chacha20poly1305::{AeadCore, Key, KeyInit, XChaCha20Poly1305, XNonce}; use chacha20poly1305::aead::{Aead, Payload}; -use ed25519_dalek::{SigningKey}; +use ed25519_dalek::{SecretKey, SigningKey}; +use log::{debug, trace}; use rand::Rng; use rand::rngs::OsRng; use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use x25519_dalek::x25519; -use crate::ca_pool::{load_ca_pool}; +use x25519_dalek::{PublicKey, StaticSecret, x25519}; +use crate::ca_pool::{EpfCaPool, load_ca_pool}; +use crate::danger_trace; 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}; ///// CLIENT ///// -#[derive(Clone)] pub struct EpfClientUpgraded { inner: T, state: EpfClientState, @@ -26,9 +27,10 @@ pub struct EpfClientUpgraded { server_cert: Option, cipher: Option, private_key: EpfPrivateKey, - public_key: EpfPublicKey + public_key: PublicKey } +#[derive(Debug)] pub enum ClientAuthentication { Cert(Box, EpfPrivateKey), Ephemeral @@ -42,22 +44,25 @@ pub trait EpfClientUpgradable { #[async_trait] impl EpfClientUpgradable for T where T: AsyncWriteExt + AsyncReadExt + Send { async fn upgrade(self, auth: ClientAuthentication) -> EpfClientUpgraded where Self: Sized + AsyncWriteExt + AsyncReadExt + Send { + danger_trace!(target: "EpfClientUpgradable", "upgrade(auth: {:?})", auth); + let private_key; - let public_key: [u8; 32]; + let public_key; let cert; match auth { ClientAuthentication::Cert(cert_d, key) => { + trace!("----!!!!! CERT AUTHENTICATION !!!!!----"); cert = Some(cert_d); - private_key = key; - public_key = key[32..].try_into().unwrap(); + private_key = key.clone(); + public_key = PublicKey::from(&StaticSecret::from(private_key.to_bytes())); }, ClientAuthentication::Ephemeral => { cert = None; let private_key_l: [u8; 32] = OsRng.gen(); let private_key_real = SigningKey::from(private_key_l); - public_key = *private_key_real.verifying_key().as_bytes(); - private_key = private_key_real.to_keypair_bytes(); + public_key = PublicKey::from(&StaticSecret::from(private_key_real.to_bytes())); + private_key = private_key_real; } } @@ -78,33 +83,37 @@ impl EpfClientUpgradable for T where T: AsyncWriteExt + AsyncReadExt + Send { #[async_trait] pub trait EpfClientHandshaker { - async fn handshake(&mut self) -> Result<(), Box>; - async fn upgrade(self) -> EpfClientStream where Self: Sized; + async fn handshake(&mut self, cert_pool: EpfCaPool) -> Result<(), Box>; + async fn upgrade(self) -> EpfClientStream where Self: Sized; } #[async_trait] -impl EpfClientHandshaker for EpfClientUpgraded { - async fn handshake(&mut self) -> Result<(), Box> { +impl EpfClientHandshaker for EpfClientUpgraded { + async fn handshake(&mut self, cert_pool: EpfCaPool) -> Result<(), Box> { match self.state { EpfClientState::NotStarted => (), _ => return Err(EpfHandshakeError::AlreadyTunnelled.into()) } - // Step 0: Load Trusted Cert Store - let cert_pool = load_ca_pool()?; - // Step 1: Send Client Hello self.inner.write_all(&encode_packet(PACKET_CLIENT_HELLO, &EpfClientHello { protocol_version: PROTOCOL_VERSION, client_random: self.client_random, client_certificate: self.client_cert.clone(), - client_public_key: self.public_key, + client_x25519_public_key: self.public_key.to_bytes(), })?).await?; + self.inner.flush().await?; + + trace!("---- !!!!! SENT CLIENT HELLO"); self.state = EpfClientState::WaitingForServerHello; + let server_x25519_key; + // Step 2: Wait for Server Hello loop { + trace!("waiting for server hello"); + let packet = recv_packet(&mut self.inner).await?; if packet.packet_id != PACKET_SERVER_HELLO { @@ -122,6 +131,8 @@ impl EpfClientHandshaker self.server_cert = Some(server_hello.server_certificate); + server_x25519_key = server_hello.server_x25519_public_key; + break; } @@ -136,7 +147,18 @@ impl EpfClientHandshaker // Server Cert OK // 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 = XChaCha20Poly1305::new(&cc20p1305_key); @@ -149,6 +171,10 @@ impl EpfClientHandshaker 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) { Ok(d) => d, Err(_) => { @@ -160,6 +186,7 @@ impl EpfClientHandshaker protocol_version: PROTOCOL_VERSION, encrypted_0x42 })?).await?; + self.inner.flush().await?; self.state = EpfClientState::WaitingForFinished; @@ -173,11 +200,15 @@ impl EpfClientHandshaker let packet_finished: EpfFinished = rmp_serde::from_slice(&packet.packet_data)?; + trace!("trying to debug 0x42"); + let payload = Payload { msg: &packet_finished.encrypted_0x42, 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) { Ok(d) => d, Err(_) => { @@ -197,23 +228,29 @@ impl EpfClientHandshaker Ok(()) } - async fn upgrade(self) -> EpfClientStream where Self: Sized { + async fn upgrade(self) -> EpfClientStream 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 { - inner: self.clone(), - aad: self.server_random, - client_cert: self.client_cert, - packet_queue: self.packet_queue, - server_cert: self.server_cert.unwrap(), - cipher: self.cipher.unwrap(), - private_key: self.private_key, - public_key: self.public_key, - raw_stream: self.inner + raw_stream, + aad, + client_cert, + packet_queue, + server_cert, + cipher, + private_key, + public_key, } } } -pub struct EpfClientStream, S: AsyncReadExt + AsyncWriteExt + Unpin> { - inner: T, +pub struct EpfClientStream { raw_stream: S, aad: [u8; 16], client_cert: Option, @@ -221,7 +258,7 @@ pub struct EpfClientStream, S: AsyncReadExt + AsyncWri server_cert: EPFCertificate, cipher: XChaCha20Poly1305, private_key: EpfPrivateKey, - public_key: EpfPublicKey + public_key: PublicKey } #[async_trait] @@ -231,7 +268,7 @@ pub trait EpfStreamOps { } #[async_trait] -impl + Send, S: AsyncReadExt + AsyncWriteExt + Unpin + Send> EpfStreamOps for EpfClientStream { +impl EpfStreamOps for EpfClientStream { async fn write(&mut self, data: &[u8]) -> Result<(), Box> { let nonce = XChaCha20Poly1305::generate_nonce(OsRng); @@ -255,6 +292,7 @@ impl + Send, S: AsyncReadExt + AsyncWriteExt + Unpin + let packet = encode_packet(PACKET_APPLICATION_DATA, &application_data)?; self.raw_stream.write_all(&packet).await?; + self.raw_stream.flush().await?; Ok(()) } @@ -291,7 +329,6 @@ impl + Send, S: AsyncReadExt + AsyncWriteExt + Unpin + ///// SERVER ///// -#[derive(Clone)] pub struct EpfServerUpgraded { inner: T, state: EpfServerState, @@ -311,7 +348,7 @@ pub trait EpfServerUpgradable { } #[async_trait] -impl EpfServerUpgradable for T where T: AsyncWriteExt + AsyncReadExt + Send { +impl EpfServerUpgradable for T where T: AsyncWriteExt + AsyncReadExt + Send { async fn upgrade(self, cert: EPFCertificate, private_key: EpfPrivateKey) -> EpfServerUpgraded where Self: Sized + AsyncWriteExt + AsyncReadExt + Send { EpfServerUpgraded { inner: self, @@ -322,29 +359,26 @@ impl EpfServerUpgradable for T where T: AsyncWriteExt + AsyncReadExt + Send { client_cert: None, packet_queue: vec![], cipher: None, - private_key, - public_key: SigningKey::from_keypair_bytes(&private_key).unwrap().verifying_key().to_bytes(), + private_key: private_key.clone(), + public_key: private_key.verifying_key(), } } } #[async_trait] pub trait EpfServerHandshaker { - async fn handshake(&mut self) -> Result<(), Box>; - async fn upgrade(self) -> EpfServerStream where Self: Sized; + async fn handshake(&mut self, cert_pool: EpfCaPool) -> Result<(), Box>; + async fn upgrade(self) -> EpfServerStream where Self: Sized; } #[async_trait] -impl EpfServerHandshaker for EpfServerUpgraded { - async fn handshake(&mut self) -> Result<(), Box> { +impl EpfServerHandshaker for EpfServerUpgraded { + async fn handshake(&mut self, cert_pool: EpfCaPool) -> Result<(), Box> { match self.state { EpfServerState::WaitingForClientHello => (), _ => return Err(EpfHandshakeError::AlreadyTunnelled.into()) } - // Step 0: Load Trusted Cert Store - let cert_pool = load_ca_pool()?; - let client_public_key; // Step 1: Wait for Client Hello @@ -356,6 +390,8 @@ impl EpfServerHandshaker continue; } + trace!("got client hello"); + let client_hello: EpfClientHello = rmp_serde::from_slice(&packet.packet_data)?; self.client_random = client_hello.client_random; @@ -366,7 +402,9 @@ impl EpfServerHandshaker 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; } @@ -383,17 +421,33 @@ impl EpfServerHandshaker } // Client Cert OK (if present) + trace!("client cert okay"); + // Step 3: Send Server Hello self.inner.write_all(&encode_packet(PACKET_SERVER_HELLO, &EpfServerHello { protocol_version: PROTOCOL_VERSION, server_certificate: self.cert.clone(), server_random: self.server_random, + server_x25519_public_key: PublicKey::from(&StaticSecret::from(self.private_key.to_bytes())).to_bytes() })?).await?; + self.inner.flush().await?; + + trace!("sent server hello"); self.state = EpfServerState::WaitingForFinished; // 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 = XChaCha20Poly1305::new(&cc20p1305_key); @@ -421,6 +475,9 @@ impl EpfServerHandshaker 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) { Ok(d) => d, Err(_) => { @@ -446,6 +503,7 @@ impl EpfServerHandshaker protocol_version: PROTOCOL_VERSION, encrypted_0x42 })?).await?; + self.inner.flush().await?; self.state = EpfServerState::WaitingForFinished; @@ -454,9 +512,8 @@ impl EpfServerHandshaker Ok(()) } - async fn upgrade(self) -> EpfServerStream where Self: Sized { + async fn upgrade(self) -> EpfServerStream where Self: Sized { EpfServerStream { - inner: self.clone(), aad: self.server_random, server_cert: self.cert, packet_queue: self.packet_queue, @@ -469,8 +526,7 @@ impl EpfServerHandshaker } } -pub struct EpfServerStream, S: AsyncReadExt + AsyncWriteExt + Unpin> { - inner: T, +pub struct EpfServerStream { raw_stream: S, aad: [u8; 16], client_cert: Option, @@ -482,7 +538,7 @@ pub struct EpfServerStream, S: AsyncReadExt + AsyncWri } #[async_trait] -impl + Send, S: AsyncReadExt + AsyncWriteExt + Unpin + Send> EpfStreamOps for EpfServerStream { +impl EpfStreamOps for EpfServerStream { async fn write(&mut self, data: &[u8]) -> Result<(), Box> { let nonce = XChaCha20Poly1305::generate_nonce(OsRng); @@ -506,6 +562,7 @@ impl + Send, S: AsyncReadExt + AsyncWriteExt + Unpin + let packet = encode_packet(PACKET_APPLICATION_DATA, &application_data)?; self.raw_stream.write_all(&packet).await?; + self.raw_stream.flush().await?; Ok(()) } @@ -542,10 +599,109 @@ impl + Send, S: AsyncReadExt + AsyncWriteExt + Unpin + #[cfg(test)] 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 = EpfClientUpgradable::upgrade(c, ClientAuthentication::Cert(Box::new(client_cert), client_private_key)).await; + let mut s: EpfServerUpgraded = 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] - 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())); } } \ No newline at end of file diff --git a/libepf/src/lib.rs b/libepf/src/lib.rs index 0cdc4c5..63f46d8 100644 --- a/libepf/src/lib.rs +++ b/libepf/src/lib.rs @@ -3,4 +3,6 @@ pub mod pki; pub mod util; pub mod protocol; pub mod handshake_stream; -pub mod error; \ No newline at end of file +pub mod error; +#[macro_use] +pub mod log; \ No newline at end of file diff --git a/libepf/src/log.rs b/libepf/src/log.rs new file mode 100644 index 0000000..7d804cf --- /dev/null +++ b/libepf/src/log.rs @@ -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)+) + } + } +} \ No newline at end of file diff --git a/libepf/src/pki.rs b/libepf/src/pki.rs index 8ae03e2..f09e59b 100644 --- a/libepf/src/pki.rs +++ b/libepf/src/pki.rs @@ -1,5 +1,5 @@ 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 pem::Pem; use serde::{Deserialize, Serialize}; @@ -15,8 +15,8 @@ pub const EPFPKI_SIGNATURE_LENGTH: usize = 64; pub const EPFPKI_SELF_SIGNED_CERTIFICATE: &str = "0000000000000000000000000000000000000000000000000000000000000000"; -pub type EpfPublicKey = [u8; 32]; -pub type EpfPrivateKey = [u8; 64]; +pub type EpfPublicKey = VerifyingKey; +pub type EpfPrivateKey = SigningKey; #[derive(Serialize, Deserialize, PartialEq, Debug, Eq, Clone)] pub struct EPFCertificate { @@ -43,8 +43,8 @@ pub struct EPFCertificateDetails { pub trait EpfPkiSerializable { const PEM_BANNER: &'static str; - fn as_bytes(&self) -> Result, rmp_serde::encode::Error>; - fn from_bytes(bytes: &[u8]) -> Result + fn as_bytes_pki(&self) -> Result, rmp_serde::encode::Error>; + fn from_bytes_pki(bytes: &[u8]) -> Result where Self: Sized; @@ -62,10 +62,6 @@ pub fn fingerprint(cert: &EPFCertificateDetails) -> Result Result { - SigningKey::from_keypair_bytes(b) -} - #[derive(Debug)] pub enum EpfPkiCertificateValidationError { NoLongerValid { expired_at: SystemTime }, @@ -132,12 +128,11 @@ impl EpfPkiCertificateOps for EPFCertificate { fn sign(&mut self, private_key: &EpfPrivateKey) -> Result<(), Box> { self.recalculate_fingerprint()?; - let signing_key = load_signing_key(private_key)?; - self.details.issuer_public_key = *signing_key.verifying_key().as_bytes(); + self.details.issuer_public_key = *private_key.verifying_key().as_bytes(); 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(); @@ -182,26 +177,19 @@ impl EpfPkiCertificateOps for EPFCertificate { let is_self_signed; - println!( - "{}: {:?} {:?}", - 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 { + let public_key = if self.details.issuer_public_key == self.details.public_key { // self-signed certificate is_self_signed = true; - VerifyingKey::from_bytes(&self.details.public_key) - .map_err(|e| EpfPkiCertificateValidationError::InvalidSignature { e })? + verifying_key(&self.details.public_key) } else { is_self_signed = false; - VerifyingKey::from_bytes(&self.details.issuer_public_key) - .map_err(|e| EpfPkiCertificateValidationError::InvalidSignature { e })? + verifying_key(&self.details.issuer_public_key) }; let cert_data_bytes = rmp_serde::to_vec(&self.details) .map_err(|e| EpfPkiCertificateValidationError::InvalidCertificateData { e })?; - verifying_key + public_key .verify(&cert_data_bytes, &signature) .map_err(|e| EpfPkiCertificateValidationError::InvalidSignature { e })?; @@ -209,12 +197,12 @@ impl EpfPkiCertificateOps for EPFCertificate { // Is the signer trusted? 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 } else { 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 } else { return Ok(false); @@ -275,16 +263,16 @@ impl Display for EPFCertificate { impl EpfPkiSerializable for EPFCertificate { const PEM_BANNER: &'static str = "EPF CERTIFICATE"; - fn as_bytes(&self) -> Result, rmp_serde::encode::Error> { + fn as_bytes_pki(&self) -> Result, rmp_serde::encode::Error> { rmp_serde::to_vec(self) } - fn from_bytes(bytes: &[u8]) -> Result { + fn from_bytes_pki(bytes: &[u8]) -> Result { rmp_serde::from_slice(bytes) } fn as_pem(&self) -> Result, Box> { - 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() .to_vec()) } @@ -297,25 +285,25 @@ impl EpfPkiSerializable for EPFCertificate { if pem.tag() != Self::PEM_BANNER { return Err("Not a certificate".into()); } - Ok(Self::from_bytes(pem.contents())?) + Ok(Self::from_bytes_pki(pem.contents())?) } } impl EpfPkiSerializable for EpfPublicKey { const PEM_BANNER: &'static str = "EPF PUBLIC KEY"; - fn as_bytes(&self) -> Result, rmp_serde::encode::Error> { - Ok(self.to_vec()) + fn as_bytes_pki(&self) -> Result, rmp_serde::encode::Error> { + Ok(self.as_bytes().to_vec()) } - fn from_bytes(bytes: &[u8]) -> Result { + fn from_bytes_pki(bytes: &[u8]) -> Result { bytes .try_into() .map_err(|_| rmp_serde::decode::Error::LengthMismatch(bytes.len() as u32)) } fn as_pem(&self) -> Result, Box> { - 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() .to_vec()) } @@ -328,25 +316,25 @@ impl EpfPkiSerializable for EpfPublicKey { if pem.tag() != Self::PEM_BANNER { return Err("Not a public key".into()); } - Ok(Self::from_bytes(pem.contents())?) + Ok(Self::from_bytes(pem.contents().try_into().map_err(|_| -> Box { "Wrong size".into() })?)?) } } impl EpfPkiSerializable for EpfPrivateKey { const PEM_BANNER: &'static str = "EPF PRIVATE KEY"; - fn as_bytes(&self) -> Result, rmp_serde::encode::Error> { - Ok(self.to_vec()) + fn as_bytes_pki(&self) -> Result, rmp_serde::encode::Error> { + Ok(self.to_keypair_bytes().to_vec()) } - fn from_bytes(bytes: &[u8]) -> Result { + fn from_bytes_pki(bytes: &[u8]) -> Result { bytes .try_into() .map_err(|_| rmp_serde::decode::Error::LengthMismatch(bytes.len() as u32)) } fn as_pem(&self) -> Result, Box> { - 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() .to_vec()) } @@ -359,7 +347,7 @@ impl EpfPkiSerializable for EpfPrivateKey { if pem.tag() != Self::PEM_BANNER { return Err("Incorrect PEM tag".into()); } - Ok(Self::from_bytes(pem.contents())?) + Ok(Self::from_keypair_bytes(pem.contents().try_into().map_err(|_| -> Box { "Wrong size".into() })?)?) } } @@ -375,15 +363,17 @@ mod tests { use rand::rngs::OsRng; use std::collections::HashMap; use std::time::{SystemTime, UNIX_EPOCH}; + use hex_literal::hex; + use crate::util::{signing_key, verifying_key}; #[test] pub fn certificate_serialization() { - assert_eq!(cert().as_bytes().unwrap(), cert_bytes()) + assert_eq!(cert().as_bytes_pki().unwrap(), cert_bytes()) } #[test] pub fn certificate_deserialization() { - assert_eq!(EPFCertificate::from_bytes(&cert_bytes()).unwrap(), cert()) + assert_eq!(EPFCertificate::from_bytes_pki(&cert_bytes()).unwrap(), cert()) } #[test] @@ -404,24 +394,24 @@ mod tests { #[test] 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] 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] 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] pub fn pubkey_deserialization_pem() { assert_eq!( EpfPublicKey::from_pem(&null_public_key_pem()).unwrap(), - [0u8; 32] + verifying_key(&[0u8; 32]) ) } @@ -433,24 +423,31 @@ mod tests { #[test] 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] 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] 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] pub fn privkey_deserialization_pem() { + let priv_key_data = hex!("00000000000000000000000000000000000000000000000000000000000000003B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29"); + assert_eq!( - EpfPrivateKey::from_pem(&null_private_key_pem()).unwrap(), - [0u8; 64] + EpfPrivateKey::from_pem(&null_private_key_pem()).unwrap().to_keypair_bytes(), + signing_key(&priv_key_data).to_keypair_bytes() ) } @@ -458,8 +455,8 @@ mod tests { #[should_panic] pub fn privkey_deserialization_pem_wrong_tag() { assert_eq!( - EpfPrivateKey::from_pem(&null_public_key_pem()).unwrap(), - [0u8; 64] + EpfPrivateKey::from_pem(&null_public_key_pem()).unwrap().to_keypair_bytes(), + signing_key(&[0u8; 64]).to_keypair_bytes() ) } @@ -513,7 +510,7 @@ mod tests { 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()); @@ -545,7 +542,7 @@ mod tests { }; 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()); } @@ -636,7 +633,7 @@ mod tests { signature: [0u8; EPFPKI_SIGNATURE_LENGTH], }; not_trusted_cert - .sign(&private_key.to_keypair_bytes()) + .sign(&private_key) .unwrap(); let ca_pool = EpfCaPool::new(); @@ -675,7 +672,7 @@ mod tests { 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); let mut not_ca_cert = EPFCertificate { @@ -700,7 +697,7 @@ mod tests { }; 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!( not_ca_cert.verify(&ca_pool).unwrap_err(), EpfPkiCertificateValidationError::ExpiresAfterSigner @@ -738,7 +735,7 @@ mod tests { 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); let mut not_ca_cert = EPFCertificate { @@ -763,7 +760,7 @@ mod tests { }; 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!( not_ca_cert.verify(&ca_pool).unwrap_err(), EpfPkiCertificateValidationError::ValidAfterSigner @@ -869,15 +866,6 @@ mod tests { ] } fn null_private_key_pem() -> 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, 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, - ] + 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] } } diff --git a/libepf/src/protocol.rs b/libepf/src/protocol.rs index a8a4a87..2b66570 100644 --- a/libepf/src/protocol.rs +++ b/libepf/src/protocol.rs @@ -1,4 +1,5 @@ use std::error::Error; +use log::debug; use serde::{Deserialize, Serialize}; use tokio::io::{AsyncReadExt}; use crate::pki::{EPFCertificate, EPFPKI_PUBLIC_KEY_LENGTH}; @@ -18,7 +19,7 @@ pub struct EpfClientHello { pub protocol_version: u32, pub client_random: [u8; 24], pub client_certificate: Option, - 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; @@ -27,7 +28,8 @@ pub const PACKET_SERVER_HELLO: u32 = 2; pub struct EpfServerHello { pub protocol_version: u32, 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; @@ -71,6 +73,7 @@ pub fn encode_packet(id: u32, packet: &T) -> Result, rmp_s packet_data: message_data, }; let mut packet_data = rmp_serde::to_vec(&message_wrapper)?; + let mut packet = (packet_data.len() as u64).to_le_bytes().to_vec(); // Packet: 8-byte little-endian length prefix, packet data packet.append(&mut packet_data); @@ -79,6 +82,7 @@ pub fn encode_packet(id: u32, packet: &T) -> Result, rmp_s pub async fn recv_packet(stream: &mut C) -> Result> { let packet_length = stream.read_u64_le().await?; + let mut packet_data_buf = vec![0u8; packet_length as usize]; stream.read_exact(&mut packet_data_buf).await?; let message: EpfMessage = rmp_serde::from_slice(&packet_data_buf)?; diff --git a/libepf/src/util.rs b/libepf/src/util.rs index 074e695..8870b66 100644 --- a/libepf/src/util.rs +++ b/libepf/src/util.rs @@ -1,6 +1,7 @@ use chrono::{DateTime, Utc}; use std::ops::Add; use std::time::{Duration, SystemTime}; +use ed25519_dalek::{SigningKey, VerifyingKey}; pub fn pretty_print_date(date: &SystemTime) -> String { let datetime: DateTime = (*date).into(); @@ -10,3 +11,10 @@ pub fn pretty_print_date(date: &SystemTime) -> String { pub fn u64_to_st(unix: u64) -> SystemTime { 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() +} \ No newline at end of file