diff --git a/src/tls.rs b/src/tls.rs index af47d38..fbe9a6e 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -86,7 +86,7 @@ impl TlsSocket { pub fn tls_connect( &mut self, - iface: EthernetInterface, + iface: &mut EthernetInterface, sockets: &mut SocketSet, now: Instant ) -> Result @@ -193,7 +193,7 @@ impl TlsSocket { cipher_suites: &cipher_suites, compression_method_length: 1, compression_methods: 0, - extension_length: supported_versions_extension.get_length(), + extension_length: supported_versions_extension.get_length().try_into().unwrap(), extensions: vec![ supported_versions_extension, signature_algorithms_extension, @@ -208,7 +208,7 @@ impl TlsSocket { for ext in client_hello.extensions.iter() { sum += ext.get_length(); } - sum + sum.try_into().unwrap() }; let handshake_repr = HandshakeRepr { @@ -390,7 +390,7 @@ impl<'a> TlsBuffer<'a> { self.enqueue_extensions(client_hello.extensions) } - fn enqueue_extensions(&mut self, extensions: Vec>) -> Result<()> { + fn enqueue_extensions(&mut self, extensions: Vec) -> Result<()> { for extension in extensions { self.write_u16(extension.extension_type.into())?; self.write_u16(extension.length)?; diff --git a/src/tls_packet.rs b/src/tls_packet.rs index 26d62ed..9ccaae7 100644 --- a/src/tls_packet.rs +++ b/src/tls_packet.rs @@ -5,6 +5,8 @@ use num_enum::TryFromPrimitive; use rand_core::RngCore; use rand_core::CryptoRng; +use p256::{EncodedPoint, AffinePoint, ecdh::EphemeralSecret}; + use core::convert::TryFrom; use core::convert::TryInto; @@ -52,10 +54,19 @@ impl<'a> TlsRepr<'a> { } } - pub(crate) fn client_hello(mut self) -> Self { + pub(crate) fn client_hello(mut self, rng: &mut T) -> Self + where + T: RngCore + CryptoRng + { self.content_type = TlsContentType::Handshake; self.version = TlsVersion::Tls10; - // TODO: Fill in handshake field + self.handshake = Some({ + let mut repr = HandshakeRepr::new(); + repr.handshake_data = HandshakeData::ClientHello({ + ClientHello::new(rng) + }); + repr + }); self } } @@ -103,7 +114,7 @@ impl<'a, 'b> HandshakeRepr<'a> { } #[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)] -#[allow(non_camel_case)] +#[allow(non_camel_case_types)] #[repr(u16)] pub(crate) enum CipherSuite { TLS_AES_128_GCM_SHA256 = 0x1301, @@ -124,7 +135,7 @@ pub(crate) struct ClientHello<'a> { pub(crate) compression_method_length: u8, // Legacy: Must be 1, to contain a byte pub(crate) compression_methods: u8, // Legacy: Must be 1 byte of 0 pub(crate) extension_length: u16, - pub(crate) extensions: Vec>, + pub(crate) extensions: Vec, } #[derive(Debug, Clone)] @@ -169,9 +180,162 @@ impl<'a> ClientHello<'a> { rng.fill_bytes(&mut client_hello.random); rng.fill_bytes(&mut client_hello.session_id); + client_hello.add_ch_supported_versions(); + client_hello.add_sig_algs(); + client_hello.add_client_groups_with_key_shares(&mut rng); + client_hello } + pub(crate) fn add_ch_supported_versions(mut self) -> Self { + let length = 2; + let mut versions = Vec::new(); + versions.push(TlsVersion::Tls13); + + let mut content = SupportedVersions::ClientHello { + length, + versions, + }; + + let extension_data = ExtensionData::SupportedVersions(content); + let length = extension_data.get_length(); + let extension = Extension { + extension_type: ExtensionType::SupportedVersions, + length: length.try_into().unwrap(), + extension_data, + }; + + self.extensions.push(extension); + self + } + + pub(crate) fn add_sh_supported_versions(mut self) -> Self { + let selected_version = TlsVersion::Tls13; + + let mut content = SupportedVersions::ServerHello { + selected_version + }; + + let extension_data = ExtensionData::SupportedVersions(content); + let length = extension_data.get_length(); + let extension = Extension { + extension_type: ExtensionType::SupportedVersions, + length: length.try_into().unwrap(), + extension_data, + }; + + self.extensions.push(extension); + self + } + + pub(crate) fn add_sig_algs(mut self) -> Self { + let mut algorithms = Vec::new(); + { + use SignatureScheme::*; + algorithms.push(ecdsa_secp256r1_sha256); + algorithms.push(ed25519); + algorithms.push(rsa_pss_pss_sha256); + algorithms.push(rsa_pkcs1_sha256); + algorithms.push(rsa_pss_rsae_sha256); + algorithms.push(rsa_pss_pss_sha384); + algorithms.push(rsa_pkcs1_sha384); + algorithms.push(rsa_pss_rsae_sha384); + algorithms.push(rsa_pss_pss_sha512); + algorithms.push(rsa_pkcs1_sha512); + algorithms.push(rsa_pss_rsae_sha512); + } + let length = algorithms.len() * 2; + + let list = SignatureSchemeList { + supported_signature_algorithms: algorithms, + length: length.try_into().unwrap(), + }; + + let extension_data = ExtensionData::SignatureAlgorithms(list); + let length = extension_data.get_length(); + let extension = Extension { + extension_type: ExtensionType::SignatureAlgorithms, + length: length.try_into().unwrap(), + extension_data + }; + + self.extensions.push(extension); + self + } + + pub(crate) fn add_client_groups_with_key_shares(mut self, rng: &mut T) -> Self + where + T: RngCore + CryptoRng + { + // List out all supported groups + let mut list = Vec::new(); + list.push(NamedGroup::secp256r1); + + let length = list.len()*2; + + // Use the list to generate all key shares and store in a vec + let client_shares = Vec::new(); + let client_shares_length = 0; + for named_group in list.iter() { + let mut key_exchange = Vec::new(); + let key_share_entry = match named_group { + NamedGroup::secp256r1 => { + let ecdh_secret = EphemeralSecret::random(&mut rng); + let ecdh_public = EncodedPoint::from(&ecdh_secret); + + let x_coor = ecdh_public.x(); + let y_coor = ecdh_public.y().unwrap(); + + key_exchange.push(0x04); // Legacy value + key_exchange.extend_from_slice(&x_coor); + key_exchange.extend_from_slice(&y_coor); + + let key_exchange_length = key_exchange.len(); + + KeyShareEntry { + group: *named_group, + length: key_exchange_length.try_into().unwrap(), + key_exchange + } + }, + // TODO: Implement keygen for other named groups + _ => todo!(), + }; + + client_shares_length += key_share_entry.get_length(); + client_shares.push(key_share_entry); + } + + // Pack up the client shares into key share + let key_share_content = KeyShareEntryContent::KeyShareClientHello { + length: client_shares_length.try_into().unwrap(), + client_shares, + }; + let extension_data = ExtensionData::KeyShareEntry(key_share_content); + let length = extension_data.get_length(); + let key_share_extension = Extension { + extension_type: ExtensionType::KeyShare, + length: length.try_into().unwrap(), + extension_data, + } + + let group_list = NamedGroupList { + length: length.try_into().unwrap(), + named_group_list: list, + }; + let extension_data = ExtensionData::NegotiatedGroups(group_list); + let length = extension_data.get_length(); + let group_list_extension = Extension { + extension_type: ExtensionType::SupportedGroups, + length: length.try_into().unwrap(), + extension_data, + } + + self.extensions.push(group_list_extension); + self.extensions.push(key_share_extension); + self + } + pub(crate) fn get_length(&self) -> u32 { let mut length :u32 = 2; // TlsVersion size length += 32; // Random size @@ -198,7 +362,7 @@ pub(crate) struct ServerHello<'a> { pub(crate) cipher_suite: CipherSuite, pub(crate) compression_method: u8, // Always 0 pub(crate) extension_length: u16, - pub(crate) extensions: Vec>, + pub(crate) extensions: Vec, } #[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)] @@ -234,15 +398,195 @@ impl ExtensionType { } } -#[derive(Debug, Clone, Copy)] -pub(crate) struct Extension<'a> { +#[derive(Debug, Clone)] +pub(crate) struct Extension { pub(crate) extension_type: ExtensionType, pub(crate) length: u16, - pub(crate) extension_data: &'a[u8], + pub(crate) extension_data: ExtensionData, } -impl<'a> Extension<'a> { - pub(crate) fn get_length(&self) -> u16 { - self.extension_type.get_length() + 2 + (self.extension_data.len() as u16) +impl Extension { + pub(crate) fn get_length(&self) -> usize { + 2 + 2 + usize::try_from(self.length).unwrap() } } + +#[derive(Debug, Clone)] +pub(crate) enum ExtensionData { + SupportedVersions(SupportedVersions), + Cookie(Cookie), + SignatureAlgorithms(SignatureSchemeList), + SignatureAlgorithmsCertificate(SignatureSchemeList), + NegotiatedGroups(NamedGroupList), + KeyShareEntry(KeyShareEntryContent), + ServerName(ServerName), +} + +impl ExtensionData { + pub(crate) fn get_length(&self) -> usize { + match self { + Self::SupportedVersions(s) => s.get_length(), + Self::SignatureAlgorithms(list) => list.get_length(), + Self::NegotiatedGroups(list) => list.get_length(), + Self::KeyShareEntry(entry_content) => entry_content.get_length(), + + // Implement get_length for all textension data + _ => todo!() + } + } +} + +#[derive(Debug, Clone)] +pub(crate) enum SupportedVersions { + ClientHello { + length: u16, + versions: Vec, + }, + ServerHello { + selected_version: TlsVersion, + } +} + +impl SupportedVersions { + pub(crate) fn get_length(&self) -> usize { + match self { + Self::ClientHello { length, versions } => { + usize::try_from(*length).unwrap() + 2 + } + Self::ServerHello { selected_version } => 2 + } + } +} + +#[derive(Debug, Clone)] +pub(crate) struct Cookie { + length: u16, + cookie: Vec, +} + +#[derive(Debug, Clone)] +#[repr(u16)] +pub(crate) enum SignatureScheme { + /* RSASSA-PKCS1-v1_5 algorithms */ + rsa_pkcs1_sha256 = 0x0401, + rsa_pkcs1_sha384 = 0x0501, + rsa_pkcs1_sha512 = 0x0601, + + /* ECDSA algorithms */ + ecdsa_secp256r1_sha256 = 0x0403, + ecdsa_secp384r1_sha384 = 0x0503, + ecdsa_secp521r1_sha512 = 0x0603, + + /* RSASSA-PSS algorithms with public key OID rsaEncryption */ + rsa_pss_rsae_sha256 = 0x0804, + rsa_pss_rsae_sha384 = 0x0805, + rsa_pss_rsae_sha512 = 0x0806, + + /* EdDSA algorithms */ + ed25519 = 0x0807, + ed488 = 0x0808, + + /* RSASSA-PSS algorithms with public key OID RSASSA-PSS */ + rsa_pss_pss_sha256 = 0x0809, + rsa_pss_pss_sha384 = 0x080a, + rsa_pss_pss_sha512 = 0x080b, +} + +#[derive(Debug, Clone)] +pub(crate) struct SignatureSchemeList { + length: u16, + supported_signature_algorithms: Vec, +} + +impl SignatureSchemeList { + pub(crate) fn get_length(&self) -> usize { + 2 + usize::try_from(self.length).unwrap() + } +} + +#[derive(Debug, Clone)] +#[repr(u16)] +pub(crate) enum NamedGroup { + /* Elliptic Curve Groups (ECDHE) */ + secp256r1 = 0x0017, + secp384r1 = 0x0018, + secp521r1 = 0x0019, + x25519 = 0x001D, + x448 = 0x001E, + + /* Finite Field Groups (DHE) */ + ffdhe2048 = 0x0100, + ffdhe3072 = 0x0101, + ffdhe4096 = 0x0102, + ffdhe6144 = 0x0103, + ffdhe8192 = 0x0104, +} + +#[derive(Debug, Clone)] +pub(crate) struct NamedGroupList { + length: u16, + named_group_list: Vec, +} + +impl NamedGroupList { + pub(crate) fn get_length(&self) -> usize { + usize::try_from(self.length).unwrap() + 2 + } +} + +#[derive(Debug, Clone)] +pub(crate) struct KeyShareEntry { + group: NamedGroup, + length: u16, + key_exchange: Vec, +} + +impl KeyShareEntry { + pub(crate) fn get_length(&self) -> usize { + 2 + 2 + usize::try_from(self.length).unwrap() + } +} + +#[derive(Debug, Clone)] +pub(crate) enum KeyShareEntryContent { + KeyShareClientHello { + length: u16, + client_shares: Vec, + }, + KeyShareHelloRetryRequest { + selected_group: NamedGroup, + }, + KeyShareServerHello { + server_share: KeyShareEntry, + } +} + +impl KeyShareEntryContent { + pub(crate) fn get_length(&self) -> usize { + match self { + Self::KeyShareClientHello { length, client_shares } => 2 + usize::try_from(*length).unwrap(), + Self::KeyShareHelloRetryRequest { selected_group } => 2, + Self::KeyShareServerHello { server_share } => server_share.get_length(), + } + } +} + +#[derive(Debug, Clone)] +#[repr(u16)] +pub(crate) enum NameType { + host_name = 0 +} + +#[derive(Debug, Clone)] +pub(crate) enum ServerNameContent { + HostName { + length: u16, + host_name: Vec, + } +} + +#[derive(Debug, Clone)] +pub(crate) struct ServerName { + name_type: NameType, + name: ServerNameContent, +}