mirror of
https://github.com/Noratrieb/tls.git
synced 2026-01-14 08:35:03 +01:00
process server hello
This commit is contained in:
parent
800ff88a6d
commit
b3b5e4c4ae
4 changed files with 114 additions and 10 deletions
101
src/lib.rs
101
src/lib.rs
|
|
@ -25,16 +25,25 @@ struct ClientSetupConnection<W> {
|
||||||
_w: W,
|
_w: W,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! unexpected_message {
|
||||||
|
($($tt:tt)*) => {
|
||||||
|
Err(ErrorKind::UnexpectedMessage(format!($($tt)*)).into())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
impl<W: Read + Write> ClientSetupConnection<W> {
|
impl<W: Read + Write> ClientSetupConnection<W> {
|
||||||
fn establish(mut stream: W, host: &str) -> Result<Self> {
|
fn establish(mut stream: W, host: &str) -> Result<Self> {
|
||||||
let secret = x25519_dalek::EphemeralSecret::random_from_rng(rand::thread_rng());
|
let secret = x25519_dalek::EphemeralSecret::random_from_rng(rand::thread_rng());
|
||||||
let public = x25519_dalek::PublicKey::from(&secret);
|
let public = x25519_dalek::PublicKey::from(&secret);
|
||||||
|
|
||||||
|
let legacy_session_id = rand::random::<[u8; 32]>();
|
||||||
|
let cipher_suites = vec![proto::CipherSuite::TLS_AES_128_GCM_SHA256];
|
||||||
|
|
||||||
let handshake = proto::Handshake::ClientHello {
|
let handshake = proto::Handshake::ClientHello {
|
||||||
legacy_version: proto::LEGACY_TLSV12,
|
legacy_version: proto::LEGACY_TLSV12,
|
||||||
random: rand::random(),
|
random: rand::random(),
|
||||||
legacy_session_id: rand::random::<[u8; 32]>().to_vec().into(),
|
legacy_session_id: legacy_session_id.to_vec().into(),
|
||||||
cipher_suites: vec![proto::CipherSuite::TLS_AES_128_GCM_SHA256].into(),
|
cipher_suites: cipher_suites.clone().into(),
|
||||||
legacy_compressions_methods: vec![0].into(),
|
legacy_compressions_methods: vec![0].into(),
|
||||||
extensions: vec![
|
extensions: vec![
|
||||||
proto::ExtensionCH::ServerName {
|
proto::ExtensionCH::ServerName {
|
||||||
|
|
@ -86,13 +95,89 @@ impl<W: Read + Write> ClientSetupConnection<W> {
|
||||||
let out = proto::TLSPlaintext::read(&mut stream)?;
|
let out = proto::TLSPlaintext::read(&mut stream)?;
|
||||||
dbg!(&out);
|
dbg!(&out);
|
||||||
|
|
||||||
if matches!(out, TLSPlaintext::Handshake { handshake } if handshake.is_hello_retry_request())
|
let proto::TLSPlaintext::Handshake {
|
||||||
{
|
handshake:
|
||||||
println!("hello retry request, the server doesnt like us :(");
|
proto::Handshake::ServerHello {
|
||||||
|
legacy_version,
|
||||||
|
random,
|
||||||
|
legacy_session_id_echo,
|
||||||
|
cipher_suite,
|
||||||
|
legacy_compression_method,
|
||||||
|
extensions,
|
||||||
|
},
|
||||||
|
} = out
|
||||||
|
else {
|
||||||
|
return Err(
|
||||||
|
ErrorKind::UnexpectedMessage(format!("expected ServerHello, got {out:?}")).into(),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if random.is_hello_retry_request() {
|
||||||
|
return Err(ErrorKind::HelloRetryRequest.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
// let res: proto::TLSPlaintext = proto::Value::read(&mut stream.get_mut())?;
|
if legacy_version != proto::LEGACY_TLSV12 {
|
||||||
// dbg!(res);
|
return unexpected_message!(
|
||||||
|
"unexpected TLS version in legacy_version field: {legacy_version:x?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if legacy_session_id_echo.as_ref() != legacy_session_id {
|
||||||
|
return unexpected_message!(
|
||||||
|
"server did not echo the legacy_session_id: {legacy_session_id_echo:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cipher_suites.contains(&cipher_suite) {
|
||||||
|
return unexpected_message!(
|
||||||
|
"cipher suite from server not sent in client hello: {cipher_suite:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if legacy_compression_method != 0 {
|
||||||
|
return unexpected_message!(
|
||||||
|
"legacy compression method MUST be zero: {legacy_compression_method}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut supported_versions = false;
|
||||||
|
let mut server_key = None;
|
||||||
|
|
||||||
|
for ext in extensions.as_ref() {
|
||||||
|
match ext {
|
||||||
|
proto::ExtensionSH::PreSharedKey => todo!(),
|
||||||
|
proto::ExtensionSH::SupportedVersions { selected_version } => {
|
||||||
|
if *selected_version != proto::TLSV13 {
|
||||||
|
return unexpected_message!("server returned non-TLS 1.3 version: {selected_version}");
|
||||||
|
}
|
||||||
|
supported_versions = true;
|
||||||
|
},
|
||||||
|
proto::ExtensionSH::Cookie { .. } => todo!(),
|
||||||
|
proto::ExtensionSH::KeyShare { key_share } => {
|
||||||
|
let entry = key_share.unwrap_server_hello();
|
||||||
|
match entry {
|
||||||
|
proto::KeyShareEntry::X25519 { len, key_exchange } => {
|
||||||
|
if *len != 32 {
|
||||||
|
return unexpected_message!("key length for X25519 key share must be 32: {len}");
|
||||||
|
}
|
||||||
|
server_key = Some(key_exchange);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !supported_versions {
|
||||||
|
return unexpected_message!("server did not send supported_versions extension");
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(server_key) = server_key else {
|
||||||
|
return unexpected_message!("server did not send its key");
|
||||||
|
};
|
||||||
|
let server_key = x25519_dalek::PublicKey::from(*server_key);
|
||||||
|
let dh_shared_secret = secret.diffie_hellman(&server_key);
|
||||||
|
|
||||||
|
println!("we have established a shared secret. dont leak it!! anywhere here is it: {:x?}", dh_shared_secret.as_bytes());
|
||||||
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
@ -106,6 +191,8 @@ pub struct Error {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ErrorKind {
|
pub enum ErrorKind {
|
||||||
InvalidFrame(Box<dyn Debug>),
|
InvalidFrame(Box<dyn Debug>),
|
||||||
|
HelloRetryRequest,
|
||||||
|
UnexpectedMessage(String),
|
||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
13
src/proto.rs
13
src/proto.rs
|
|
@ -358,6 +358,15 @@ pub enum ServerHelloKeyshare {
|
||||||
ServerHello(KeyShareEntry),
|
ServerHello(KeyShareEntry),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ServerHelloKeyshare {
|
||||||
|
pub fn unwrap_server_hello(&self) -> &KeyShareEntry {
|
||||||
|
match self {
|
||||||
|
Self::HelloRetryRequest(_) => panic!("unexpected hello retry request, expected server hello"),
|
||||||
|
Self::ServerHello(entry) => entry,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Value for ServerHelloKeyshare {
|
impl Value for ServerHelloKeyshare {
|
||||||
fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -382,9 +391,9 @@ impl Value for ServerHelloKeyshare {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handshake {
|
impl ServerHelloRandom {
|
||||||
pub fn is_hello_retry_request(&self) -> bool {
|
pub fn is_hello_retry_request(&self) -> bool {
|
||||||
matches!(self, Handshake::ServerHello { random, .. } if random.0 == HELLO_RETRY_REQUEST)
|
self.0 == HELLO_RETRY_REQUEST
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -234,6 +234,12 @@ impl<T, Len: Value> From<Vec<T>> for List<T, Len> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T, Len> AsRef<[T]> for List<T, Len> {
|
||||||
|
fn as_ref(&self) -> &[T] {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Debug, Len> Debug for List<T, Len> {
|
impl<T: Debug, Len> Debug for List<T, Len> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_list().entries(self.0.iter()).finish()
|
f.debug_list().entries(self.0.iter()).finish()
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
struct ExpectServer {
|
struct ExpectServer {
|
||||||
|
|
@ -62,5 +64,5 @@ fn connect() {
|
||||||
Expect::Client(vec![0]), // TODO: do this
|
Expect::Client(vec![0]), // TODO: do this
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let conn = tls::ClientConnection::establish(&mut expect, "example.com").unwrap();
|
tls::ClientConnection::establish(&mut expect, "example.com").unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue