diff --git a/Cargo.lock b/Cargo.lock index 7a9da71..f90d7bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,36 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -23,6 +47,16 @@ dependencies = [ "libc", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "curve25519-dalek" version = "4.1.1" @@ -50,12 +84,33 @@ dependencies = [ "syn", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "fiat-crypto" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -67,12 +122,51 @@ dependencies = [ "wasi", ] +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + [[package]] name = "platforms" version = "3.1.2" @@ -133,6 +227,21 @@ dependencies = [ "getrandom", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + [[package]] name = "rustc_version" version = "0.4.0" @@ -168,6 +277,12 @@ dependencies = [ "syn", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "subtle" version = "2.5.0" @@ -190,22 +305,128 @@ name = "tls" version = "0.1.0" dependencies = [ "byteorder", + "hkdf", "rand", + "ring", "x25519-dalek", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "x25519-dalek" version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index 514bb15..d51a008 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,5 +7,7 @@ edition = "2021" [dependencies] byteorder = "1.4.3" +hkdf = "0.12.3" rand = "0.8.5" +ring = "0.16.20" x25519-dalek = "2.0.0" diff --git a/src/crypt.rs b/src/crypt.rs new file mode 100644 index 0000000..2637e63 --- /dev/null +++ b/src/crypt.rs @@ -0,0 +1,47 @@ +//! Module for encrypting `TLSPlaintext` records. + +use crate::proto; + +use ring::aead; + +struct TlsCiphertext { + encrypted_record: Vec, +} + +pub struct AeadKey { + key: aead::LessSafeKey, +} + +impl AeadKey { + fn new(algorithm: proto::CipherSuite, key_bytes: &[u8]) -> Self { + Self { + key: aead::LessSafeKey::new( + aead::UnboundKey::new(proto_algo_to_ring(algorithm), key_bytes).expect("invalid key"), + ), + } + } +} + +fn proto_algo_to_ring(algo: proto::CipherSuite) -> &'static aead::Algorithm { + match algo { + proto::CipherSuite::TLS_AES_128_GCM_SHA256 => &aead::AES_128_GCM, + proto::CipherSuite::TLS_AES_256_GCM_SHA384 => &aead::AES_256_GCM, + proto::CipherSuite::TLS_CHACHA20_POLY1305_SHA256 => &aead::CHACHA20_POLY1305, + proto::CipherSuite::TLS_AES_128_CCM_SHA256 => todo!("TLS_AES_128_CCM_SHA256"), + proto::CipherSuite::TLS_AES_128_CCM_8_SHA256 => todo!("TLS_AES_128_CCM_8_SHA256"), + } +} + +fn encrypt(key: AeadKey, message: &[u8], seq: u8) -> Vec { + let total_len = message.len() + key.key.algorithm().tag_len(); + let mut ciphertext_payload = Vec::with_capacity(total_len); + ciphertext_payload.extend_from_slice(message); + + // FIXME: dont use zero obviously + let nonce = aead::Nonce::assume_unique_for_key([0; aead::NONCE_LEN]); + // FIXME: fill out the AAD properly + let aad = aead::Aad::from([0; 5]); + key.key.seal_in_place_append_tag(nonce, aad, &mut ciphertext_payload).unwrap(); + + ciphertext_payload +} diff --git a/src/lib.rs b/src/lib.rs index 84ea220..4e20971 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +mod crypt; pub mod proto; use std::{ @@ -58,7 +59,6 @@ impl ClientSetupConnection { proto::ExtensionCH::SupportedGroups { groups: vec![proto::NamedGroup::X25519].into(), }, - // passing this doesnt work and shows up as TLSv1.2 in wireshark and gives a handshake error proto::ExtensionCH::KeyShare { entries: vec![proto::KeyShareEntry::X25519 { len: public.as_bytes().len().try_into().unwrap(), @@ -179,6 +179,8 @@ impl ClientSetupConnection { println!("we have established a shared secret. dont leak it!! anywhere here is it: {:x?}", dh_shared_secret.as_bytes()); + dbg!(proto::TLSPlaintext::read(&mut stream))?; + todo!() } } diff --git a/src/proto.rs b/src/proto.rs index c19a559..3d4872c 100644 --- a/src/proto.rs +++ b/src/proto.rs @@ -15,6 +15,8 @@ pub enum TLSPlaintext { legacy_version: ProtocolVersion, fragment: List, }, + /// This only exists for compatibility and must be sent immediately before the second flight. + /// If this is received with the single byte value `0x01`, then it should just be dropped. ChangeCipherSpec, Alert { alert: Alert, @@ -110,7 +112,9 @@ proto_enum! { } = 2, NewSessionTicket {} = 4, EndOfEarlyData {} = 5, - EncryptedExtensions {} = 8, + EncryptedExtensions { + extensions: List, + } = 8, Certificate {} = 11, CertificateRequest {} = 13, CertificateVerify {} = 15, @@ -197,6 +201,26 @@ proto_enum! { } } +proto_enum! { + #[derive(Debug, Clone, PartialEq, Eq)] + pub enum ExtensionEE: u16, (length: u16) { + ServerName { + server_name: ServerNameList, + } = 0, + MaxFragmentLength { todo: Todo, } = 1, + SupportedGroups { + groups: NamedGroupList, + } = 10, + UseSrtp { todo: Todo, } = 14, + Heartbeat { todo: Todo, } = 15, + ApplicationLayerProtocolNegotiation { todo: Todo, } = 16, + ClientCertificateType { todo: Todo, } = 19, + ServerCertificateType { todo: Todo, } = 20, + EarlyData { todo: Todo, } = 42, + } +} + + proto_enum! { #[derive(Debug, Clone, PartialEq, Eq)] pub enum ServerName: u8 {