mirror of
https://github.com/Noratrieb/tls.git
synced 2026-01-14 16:45:02 +01:00
getting ServerHello from google
This commit is contained in:
parent
22893824c8
commit
df9e3ea17d
5 changed files with 156 additions and 25 deletions
10
src/lib.rs
10
src/lib.rs
|
|
@ -49,16 +49,16 @@ impl ClientSetupConnection {
|
|||
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 {
|
||||
proto::ExtensionCH::KeyShare {
|
||||
entries: vec![proto::KeyShareEntry::X25519 {
|
||||
len: public.as_bytes().len().try_into().unwrap(),
|
||||
key_exchange: *public.as_bytes(),
|
||||
}]
|
||||
.into(),
|
||||
},*/
|
||||
/*proto::ExtensionCH::SignatureAlgorithms {
|
||||
},
|
||||
proto::ExtensionCH::SignatureAlgorithms {
|
||||
supported_signature_algorithms: vec![proto::SignatureScheme::ED25519].into(),
|
||||
},*/
|
||||
},
|
||||
proto::ExtensionCH::SupportedVersions {
|
||||
versions: vec![proto::TLSV13].into(),
|
||||
},
|
||||
|
|
@ -97,6 +97,7 @@ pub enum ErrorKind {
|
|||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(value: io::Error) -> Self {
|
||||
panic!("error: {value}");
|
||||
Self {
|
||||
kind: ErrorKind::Io(value),
|
||||
}
|
||||
|
|
@ -105,6 +106,7 @@ impl From<io::Error> for Error {
|
|||
|
||||
impl From<ErrorKind> for Error {
|
||||
fn from(value: ErrorKind) -> Self {
|
||||
panic!("error:{value:?}");
|
||||
Self { kind: value }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// An example program that makes a shitty HTTP/1.1 request.
|
||||
fn main() {
|
||||
tls::ClientConnection::establish("nilstrieb.dev", 443).unwrap();
|
||||
tls::ClientConnection::establish("google.com", 443).unwrap();
|
||||
}
|
||||
|
|
|
|||
60
src/proto.rs
60
src/proto.rs
|
|
@ -7,7 +7,7 @@ use std::{
|
|||
|
||||
use crate::ErrorKind;
|
||||
|
||||
use self::ser_de::{proto_enum, proto_struct, u24, List, Todo, Value};
|
||||
use self::ser_de::{proto_enum, proto_struct, u24, FrameReader, List, Todo, Value};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum TLSPlaintext {
|
||||
|
|
@ -58,6 +58,7 @@ impl TLSPlaintext {
|
|||
}
|
||||
|
||||
pub fn read(r: &mut impl Read) -> crate::Result<Self> {
|
||||
let r = &mut FrameReader::new(r);
|
||||
let discr = u8::read(r)?;
|
||||
let _legacy_version = ProtocolVersion::read(r)?;
|
||||
let _len = u16::read(r)?;
|
||||
|
|
@ -101,7 +102,7 @@ proto_enum! {
|
|||
} = 1,
|
||||
ServerHello {
|
||||
legacy_version: ProtocolVersion,
|
||||
random: Random,
|
||||
random: ServerHelloRandom,
|
||||
legacy_session_id_echo: LegacySessionId,
|
||||
cipher_suite: CipherSuite,
|
||||
legacy_compression_method: u8,
|
||||
|
|
@ -190,7 +191,7 @@ proto_enum! {
|
|||
} = 43,
|
||||
Cookie { todo: Todo, } = 44,
|
||||
KeyShare {
|
||||
group: NamedGroup,
|
||||
key_share: ServerHelloKeyshare,
|
||||
} = 51,
|
||||
}
|
||||
}
|
||||
|
|
@ -329,9 +330,60 @@ proto_enum! {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ServerHelloRandom(Random);
|
||||
|
||||
impl Value for ServerHelloRandom {
|
||||
fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
self.0.write(w)
|
||||
}
|
||||
|
||||
fn read<R: Read>(r: &mut FrameReader<R>) -> crate::Result<Self> {
|
||||
let random = Random::read(r)?;
|
||||
if random == HELLO_RETRY_REQUEST {
|
||||
r.is_hello_retry_request = true;
|
||||
}
|
||||
Ok(Self(random))
|
||||
}
|
||||
|
||||
fn byte_size(&self) -> usize {
|
||||
self.0.byte_size()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ServerHelloKeyshare {
|
||||
HelloRetryRequest(NamedGroup),
|
||||
ServerHello(KeyShareEntry),
|
||||
}
|
||||
|
||||
impl Value for ServerHelloKeyshare {
|
||||
fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
match self {
|
||||
Self::HelloRetryRequest(group) => group.write(w),
|
||||
Self::ServerHello(entry) => entry.write(w),
|
||||
}
|
||||
}
|
||||
|
||||
fn read<R: Read>(r: &mut FrameReader<R>) -> crate::Result<Self> {
|
||||
if r.is_hello_retry_request {
|
||||
NamedGroup::read(r).map(Self::HelloRetryRequest)
|
||||
} else {
|
||||
KeyShareEntry::read(r).map(Self::ServerHello)
|
||||
}
|
||||
}
|
||||
|
||||
fn byte_size(&self) -> usize {
|
||||
match self {
|
||||
Self::HelloRetryRequest(group) => group.byte_size(),
|
||||
Self::ServerHello(entry) => entry.byte_size(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Handshake {
|
||||
pub fn is_hello_retry_request(&self) -> bool {
|
||||
matches!(self, Handshake::ServerHello { random, .. } if random == &HELLO_RETRY_REQUEST)
|
||||
matches!(self, Handshake::ServerHello { random, .. } if random.0 == HELLO_RETRY_REQUEST)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,34 @@ use std::{
|
|||
io::{self, Read, Write},
|
||||
marker::PhantomData,
|
||||
num::TryFromIntError,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
pub struct FrameReader<R> {
|
||||
read: R,
|
||||
pub is_hello_retry_request: bool,
|
||||
}
|
||||
|
||||
impl<R> FrameReader<R> {
|
||||
pub fn new(read: R) -> Self {
|
||||
FrameReader { read, is_hello_retry_request: false }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Deref for FrameReader<R> {
|
||||
type Target = R;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.read
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> DerefMut for FrameReader<R> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.read
|
||||
}
|
||||
}
|
||||
|
||||
/// ```ignore
|
||||
/// proto_struct! {}
|
||||
/// ```
|
||||
|
|
@ -31,7 +57,7 @@ macro_rules! proto_struct {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn read<R: Read>(r: &mut R) -> crate::Result<Self> {
|
||||
fn read<R: Read>(r: &mut $crate::proto::ser_de::FrameReader<R>) -> crate::Result<Self> {
|
||||
let ( $( $field_name ),* ) = ($( { crate::proto::ser_de::discard!($field_name); crate::proto::ser_de::Value::read(r)? } ),*);
|
||||
|
||||
Ok(Self {
|
||||
|
|
@ -120,7 +146,7 @@ macro_rules! proto_enum {
|
|||
}
|
||||
}
|
||||
|
||||
fn read<R: Read>(r: &mut R) -> crate::Result<Self> {
|
||||
fn read<R: Read>(r: &mut $crate::proto::ser_de::FrameReader<R>) -> crate::Result<Self> {
|
||||
mod discr_consts {
|
||||
#[allow(unused_imports)]
|
||||
use super::*;
|
||||
|
|
@ -140,8 +166,9 @@ macro_rules! proto_enum {
|
|||
match kind {
|
||||
$(
|
||||
discr_consts::$KindName => {
|
||||
#[allow(unused_parens)]
|
||||
$(let ( $( $field_name ),* ) = ($( { crate::proto::ser_de::discard!($field_name); crate::proto::ser_de::Value::read(r)? } ),*);)?
|
||||
$($(
|
||||
let $field_name = crate::proto::ser_de::Value::read(r)?;
|
||||
)*)?
|
||||
|
||||
Ok(Self::$KindName $({
|
||||
$(
|
||||
|
|
@ -186,7 +213,7 @@ impl Value for Todo {
|
|||
todo!()
|
||||
}
|
||||
|
||||
fn read<R: Read>(_: &mut R) -> crate::Result<Self> {
|
||||
fn read<R: Read>(_: &mut FrameReader<R>) -> crate::Result<Self> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
|
@ -211,11 +238,13 @@ impl<T: Debug, Len> Debug for List<T, Len> {
|
|||
}
|
||||
|
||||
impl<T: Value, Len: Value + Into<usize> + TryFrom<usize> + Default> Value for List<T, Len> {
|
||||
fn read<R: Read>(r: &mut R) -> crate::Result<Self> {
|
||||
fn read<R: Read>(r: &mut FrameReader<R>) -> crate::Result<Self> {
|
||||
eprintln!("reading a list");
|
||||
let mut remaining_byte_size = Len::read(r)?.into();
|
||||
let mut v = Vec::new();
|
||||
|
||||
eprintln!("list.. remaining bytes {remaining_byte_size}");
|
||||
while remaining_byte_size > 0 {
|
||||
eprintln!("things {remaining_byte_size} {v:?}");
|
||||
let value = T::read(r)?;
|
||||
remaining_byte_size -= value.byte_size();
|
||||
v.push(value);
|
||||
|
|
@ -242,7 +271,7 @@ impl<T: Value, Len: Value + Into<usize> + TryFrom<usize> + Default> Value for Li
|
|||
|
||||
pub trait Value: Sized + std::fmt::Debug {
|
||||
fn write<W: Write>(&self, w: &mut W) -> io::Result<()>;
|
||||
fn read<R: Read>(r: &mut R) -> crate::Result<Self>;
|
||||
fn read<R: Read>(r: &mut FrameReader<R>) -> crate::Result<Self>;
|
||||
fn byte_size(&self) -> usize;
|
||||
}
|
||||
|
||||
|
|
@ -250,7 +279,7 @@ impl<V: Value, const N: usize> Value for [V; N] {
|
|||
fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
self.iter().try_for_each(|v| Value::write(v, w))
|
||||
}
|
||||
fn read<R: Read>(r: &mut R) -> crate::Result<Self> {
|
||||
fn read<R: Read>(r: &mut FrameReader<R>) -> crate::Result<Self> {
|
||||
// ugly :(
|
||||
let mut values = Vec::with_capacity(N);
|
||||
for _ in 0..N {
|
||||
|
|
@ -268,7 +297,7 @@ impl Value for u8 {
|
|||
fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
w.write_u8(*self)
|
||||
}
|
||||
fn read<R: Read>(r: &mut R) -> crate::Result<Self> {
|
||||
fn read<R: Read>(r: &mut FrameReader<R>) -> crate::Result<Self> {
|
||||
r.read_u8().map_err(Into::into)
|
||||
}
|
||||
fn byte_size(&self) -> usize {
|
||||
|
|
@ -280,7 +309,7 @@ impl Value for u16 {
|
|||
fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
w.write_u16::<B>(*self)
|
||||
}
|
||||
fn read<R: Read>(r: &mut R) -> crate::Result<Self> {
|
||||
fn read<R: Read>(r: &mut FrameReader<R>) -> crate::Result<Self> {
|
||||
r.read_u16::<B>().map_err(Into::into)
|
||||
}
|
||||
fn byte_size(&self) -> usize {
|
||||
|
|
@ -293,7 +322,7 @@ impl Value for u32 {
|
|||
w.write_u32::<B>(*self)
|
||||
}
|
||||
|
||||
fn read<R: Read>(r: &mut R) -> crate::Result<Self> {
|
||||
fn read<R: Read>(r: &mut FrameReader<R>) -> crate::Result<Self> {
|
||||
r.read_u32::<B>().map_err(Into::into)
|
||||
}
|
||||
|
||||
|
|
@ -309,7 +338,7 @@ impl<T: Value, U: Value> Value for (T, U) {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn read<R: Read>(r: &mut R) -> crate::Result<Self> {
|
||||
fn read<R: Read>(r: &mut FrameReader<R>) -> crate::Result<Self> {
|
||||
Ok((T::read(r)?, U::read(r)?))
|
||||
}
|
||||
|
||||
|
|
@ -327,7 +356,7 @@ impl Value for u24 {
|
|||
w.write_u24::<B>(self.0)
|
||||
}
|
||||
|
||||
fn read<R: Read>(r: &mut R) -> crate::Result<Self> {
|
||||
fn read<R: Read>(r: &mut FrameReader<R>) -> crate::Result<Self> {
|
||||
r.read_u24::<B>().map_err(Into::into).map(u24)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ fn parse_hello_retry_request() {
|
|||
TLSPlaintext::Handshake {
|
||||
handshake: Handshake::ServerHello {
|
||||
legacy_version: LEGACY_TLSV12,
|
||||
random: HELLO_RETRY_REQUEST,
|
||||
random: ServerHelloRandom(HELLO_RETRY_REQUEST),
|
||||
legacy_session_id_echo:
|
||||
b"\xdd\x0f\x25\x0a\xf0\xa6\xd9\xb0\x1c\x28\x2f\x55\xcb\xab\x07\x94\
|
||||
\x2e\xb3\x98\x96\x32\x81\xad\x8d\x24\x72\x52\x2a\x45\x26\x10\xa2"
|
||||
|
|
@ -31,7 +31,7 @@ fn parse_hello_retry_request() {
|
|||
selected_version: TLSV13
|
||||
},
|
||||
ExtensionSH::KeyShare {
|
||||
group: NamedGroup::X25519
|
||||
key_share: ServerHelloKeyshare::HelloRetryRequest(NamedGroup::X25519)
|
||||
}
|
||||
]
|
||||
.into()
|
||||
|
|
@ -39,3 +39,51 @@ fn parse_hello_retry_request() {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_server_hello() {
|
||||
let mut bytes: &[u8] = b"\x16\x03\x03\x00\x7a\x02\x00\x00\x76\x03\x03\x15\x2a\x7b\x01\xaa\
|
||||
\x65\xde\x1f\xe0\x87\x52\x73\xd6\x7d\xd4\x8c\xc8\xf1\x9d\x55\x09\
|
||||
\x4c\xbd\xa2\xb0\xc9\x77\xa2\x4b\x81\xed\x63\x20\x05\xc1\x7d\x07\
|
||||
\x34\x68\xaf\xd5\xfc\x7f\x1c\x0c\x07\xd7\x14\x9e\x2b\x66\x87\x44\
|
||||
\x02\xbb\xf7\xb7\x1d\x6a\x29\xaf\x93\xaf\xe2\x02\x13\x01\x00\x00\
|
||||
\x2e\x00\x33\x00\x24\x00\x1d\x00\x20\x8e\xbc\x32\x53\xd7\x4d\xf9\
|
||||
\x4a\xb8\x04\x03\xda\xfe\xbf\xf5\xab\x6f\x8f\x65\x2a\x1d\x70\xde\
|
||||
\xe7\xaf\x93\x82\x59\x70\xac\x75\x4d\x00\x2b\x00\x02\x03\x04";
|
||||
|
||||
let handshake = TLSPlaintext::read(&mut bytes).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
handshake,
|
||||
TLSPlaintext::Handshake {
|
||||
handshake: Handshake::ServerHello {
|
||||
legacy_version: LEGACY_TLSV12,
|
||||
random: ServerHelloRandom(
|
||||
*b"\x15\x2a\x7b\x01\xaa\x65\xde\x1f\xe0\x87\x52\x73\xd6\x7d\xd4\x8c\
|
||||
\xc8\xf1\x9d\x55\x09\x4c\xbd\xa2\xb0\xc9\x77\xa2\x4b\x81\xed\x63"
|
||||
),
|
||||
legacy_session_id_echo:
|
||||
b"\x05\xc1\x7d\x07\x34\x68\xaf\xd5\xfc\x7f\x1c\x0c\x07\xd7\x14\x9e\
|
||||
\x2b\x66\x87\x44\x02\xbb\xf7\xb7\x1d\x6a\x29\xaf\x93\xaf\xe2\x02"
|
||||
.to_vec()
|
||||
.into(),
|
||||
cipher_suite: CipherSuite::TlsAes128GcmSha256,
|
||||
legacy_compression_method: 0,
|
||||
extensions: vec![
|
||||
ExtensionSH::KeyShare {
|
||||
key_share: ServerHelloKeyshare::ServerHello(KeyShareEntry::X25519 {
|
||||
len: 32,
|
||||
key_exchange:
|
||||
*b"\x8e\xbc\x32\x53\xd7\x4d\xf9\x4a\xb8\x04\x03\xda\xfe\xbf\xf5\xab\
|
||||
\x6f\x8f\x65\x2a\x1d\x70\xde\xe7\xaf\x93\x82\x59\x70\xac\x75\x4d"
|
||||
})
|
||||
},
|
||||
ExtensionSH::SupportedVersions {
|
||||
selected_version: TLSV13
|
||||
},
|
||||
]
|
||||
.into()
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue