#[cfg(feature = "serialize")]
pub mod serialize {
use tls::*;
use tls_ec::{ECPoint,NamedGroup};
use tls_extensions::{SNIType,TlsExtension,TlsExtensionType};
use cookie_factory::*;
#[macro_export]
macro_rules! gen_tagged_extension(
(($i:expr, $idx:expr), $tag:expr, $submac:ident!( $($args:tt)* )) => (
do_gen!(($i,$idx),
gen_be_u16!($tag) >>
ofs: gen_skip!(2) >>
start: $submac!( $($args)* ) >>
end: gen_at_offset!(ofs,gen_be_u16!(end-start))
)
);
(($i:expr, $idx:expr), $tag:expr, $f:ident( $($args:tt)* )) => (
gen_tagged_extension!(($i,$idx), $tag, $gen_call!($f( $($args)* )))
);
($x:expr, $tag:expr, $submac:ident!( $($args:tt)* )) => (
gen_tagged_extension!(($x.0, $x.1), $tag, $submac!( $($args)* )) );
($x:expr, $tag:expr, $f:ident( $($args:tt)* )) => (
gen_tagged_extension!(($x.0, $x.1), $tag, $f( $($args)* )) );
);
#[macro_export]
macro_rules! gen_length_bytes_be_u16(
(($i:expr, $idx:expr), $submac:ident!( $($args:tt)* )) => (
do_gen!(($i,$idx),
ofs: gen_skip!(2) >>
start: $submac!( $($args)* ) >>
end: gen_at_offset!(ofs,gen_be_u16!(end-start))
)
);
(($i:expr, $idx:expr), $f:ident( $($args:tt)* )) => (
gen_length_bytes_be_u16!(($i,$idx), $gen_call!($f( $($args)* )))
);
($x:ident, $submac:ident!( $($args:tt)* )) => ( gen_length_bytes_be_u16!(($x.0,$x.1), $submac!( $($args)* )));
($x:ident, $f:ident( $($args:tt)* )) => ( gen_length_bytes_be_u16!(($x.0,$x.1), $f( $($args)* )));
);
#[macro_export]
macro_rules! gen_many_deref(
(($i:expr, $idx:expr), $l:expr, $f:expr) => (
$l.into_iter().fold(
Ok(($i,$idx)),
|r,&v| {
match r {
Err(e) => Err(e),
Ok(x) => { $f(x, (*v)) },
}
}
)
);
);
#[inline]
pub fn gen_tls_named_group<'a>(x:(&'a mut [u8],usize),g:NamedGroup) -> Result<(&'a mut [u8],usize),GenError> {
set_be_u16(x, g.0)
}
#[inline]
pub fn gen_tls_ec_point<'a>(x:(&'a mut [u8],usize),p:ECPoint) -> Result<(&'a mut [u8],usize),GenError> {
do_gen!(
x,
gen_be_u8!(p.point.len() as u8) >>
gen_slice!(p.point)
)
}
pub fn gen_tls_ext_sni_hostname<'a,'b>(x:(&'a mut [u8],usize),h:&(SNIType,&'b[u8])) -> Result<(&'a mut [u8],usize),GenError> {
do_gen!(
x,
gen_be_u8!((h.0).0 as u8) >>
gen_be_u16!(h.1.len() as u16) >>
gen_slice!(h.1)
)
}
#[inline]
pub fn gen_tls_ext_sni<'a,'b>(x:(&'a mut [u8],usize),m:&'b Vec<(SNIType,&'b[u8])>) -> Result<(&'a mut [u8],usize),GenError> {
gen_tagged_extension!(x, 0x0000, gen_many_ref!(m,gen_tls_ext_sni_hostname))
}
#[inline]
pub fn gen_tls_ext_max_fragment_length<'a,'b>(x:(&'a mut [u8],usize),l:u8) -> Result<(&'a mut [u8],usize),GenError> {
gen_tagged_extension!(x, 0x0001, gen_be_u8!(l))
}
#[inline]
pub fn gen_tls_ext_elliptic_curves<'a,'b>(x:(&'a mut [u8],usize),v:&'b Vec<NamedGroup>) -> Result<(&'a mut [u8],usize),GenError> {
gen_tagged_extension!(
x,
u16::from(TlsExtensionType::SupportedGroups),
gen_length_bytes_be_u16!(gen_many_byref!(v,gen_tls_named_group))
)
}
pub fn gen_tls_extension<'a,'b>(x:(&'a mut [u8],usize),m:&'b TlsExtension) -> Result<(&'a mut [u8],usize),GenError> {
match m {
&TlsExtension::SNI(ref v) => gen_tls_ext_sni(x,v),
&TlsExtension::MaxFragmentLength(l) => gen_tls_ext_max_fragment_length(x,l),
&TlsExtension::EllipticCurves(ref v) => gen_tls_ext_elliptic_curves(x,v),
_ => Err(GenError::NotYetImplemented),
}
}
pub fn gen_tls_extensions<'a,'b>(x:(&'a mut [u8],usize),m:&'b Vec<TlsExtension>) -> Result<(&'a mut [u8],usize),GenError> {
gen_length_bytes_be_u16!(x, gen_many_ref!(m,gen_tls_extension))
}
#[inline]
pub fn gen_tls_sessionid<'a,'b>(x:(&'a mut [u8],usize),m:&Option<&'b [u8]>) -> Result<(&'a mut [u8],usize),GenError> {
match m {
&None => gen_be_u8!(x,0),
&Some(o) => {
do_gen!(
x,
gen_be_u8!(o.len() as u8) >>
gen_slice!(o)
)
}
}
}
pub fn gen_tls_hellorequest<'a>(x:(&'a mut [u8],usize)) -> Result<(&'a mut [u8],usize),GenError> {
do_gen!(
x,
gen_be_u8!(u8::from(TlsHandshakeType::HelloRequest)) >>
gen_be_u24!(0)
)
}
pub fn gen_tls_clienthello<'a,'b>(x:(&'a mut [u8],usize),m:&'b TlsClientHelloContents) -> Result<(&'a mut [u8],usize),GenError> {
do_gen!(
x,
gen_be_u8!(u8::from(TlsHandshakeType::ClientHello)) >>
ofs_len: gen_skip!(3) >>
start: gen_be_u16!(u16::from(m.version)) >>
gen_be_u32!(m.rand_time) >>
gen_copy!(m.rand_data,28) >>
gen_tls_sessionid(&m.session_id) >>
gen_be_u16!((m.ciphers.len()*2) as u16) >>
gen_many_deref!(&m.ciphers,set_be_u16) >>
gen_be_u8!(m.comp.len() as u8) >>
gen_many_deref!(&m.comp,set_be_u8) >>
gen_cond!(m.ext.is_some(),gen_slice!(m.ext.unwrap())) >>
end: gen_at_offset!(ofs_len,gen_be_u24!(end-start))
)
}
pub fn gen_tls_serverhello<'a,'b>(x:(&'a mut [u8],usize),m:&'b TlsServerHelloContents) -> Result<(&'a mut [u8],usize),GenError> {
do_gen!(
x,
gen_be_u8!(u8::from(TlsHandshakeType::ServerHello)) >>
ofs_len: gen_skip!(3) >>
start: gen_be_u16!(u16::from(m.version)) >>
gen_be_u32!(m.rand_time) >>
gen_copy!(m.rand_data,28) >>
gen_tls_sessionid(&m.session_id) >>
gen_be_u16!(*m.cipher) >>
gen_be_u8!(*m.compression) >>
gen_cond!(m.ext.is_some(),gen_slice!(m.ext.unwrap())) >>
end: gen_at_offset!(ofs_len,gen_be_u24!(end-start))
)
}
pub fn gen_tls_serverhellov13draft18<'a,'b>(x:(&'a mut [u8],usize),m:&'b TlsServerHelloV13Draft18Contents) -> Result<(&'a mut [u8],usize),GenError> {
do_gen!(
x,
gen_be_u8!(u8::from(TlsHandshakeType::ServerHello)) >>
ofs_len: gen_skip!(3) >>
start: gen_copy!(m.random,32) >>
gen_be_u16!(*m.cipher) >>
gen_cond!(m.ext.is_some(),gen_slice!(m.ext.unwrap())) >>
end: gen_at_offset!(ofs_len,gen_be_u24!(end-start))
)
}
pub fn gen_tls_finished<'a,'b>(x:(&'a mut [u8],usize),m:&'b [u8]) -> Result<(&'a mut [u8],usize),GenError> {
do_gen!(
x,
gen_be_u8!(u8::from(TlsHandshakeType::ServerHello)) >>
ofs_len: gen_skip!(3) >>
start: gen_slice!(m) >>
end: gen_at_offset!(ofs_len,gen_be_u24!(end-start))
)
}
pub fn gen_tls_clientkeyexchange_unknown<'a,'b>(x:(&'a mut [u8],usize),m:&'b [u8]) -> Result<(&'a mut [u8],usize),GenError> {
do_gen!(
x,
gen_be_u8!(u8::from(TlsHandshakeType::ClientKeyExchange)) >>
gen_be_u24!(m.len()) >>
gen_slice!(m)
)
}
pub fn gen_tls_clientkeyexchange_dh<'a,'b>(x:(&'a mut [u8],usize),m:&'b [u8]) -> Result<(&'a mut [u8],usize),GenError> {
do_gen!(
x,
gen_be_u8!(u8::from(TlsHandshakeType::ClientKeyExchange)) >>
ofs_len: gen_skip!(3) >>
start: gen_be_u16!(m.len()) >>
gen_slice!(m) >>
end: gen_at_offset!(ofs_len,gen_be_u24!(end-start))
)
}
pub fn gen_tls_clientkeyexchange_ecdh<'a,'b>(x:(&'a mut [u8],usize),m:&'b ECPoint) -> Result<(&'a mut [u8],usize),GenError> {
do_gen!(
x,
gen_be_u8!(u8::from(TlsHandshakeType::ClientKeyExchange)) >>
ofs_len: gen_skip!(3) >>
start: gen_skip!(1) >>
s2: gen_slice!(m.point) >>
end: gen_at_offset!(start,gen_be_u8!((end-s2) as u8)) >>
gen_at_offset!(ofs_len,gen_be_u24!(end-start))
)
}
pub fn gen_tls_clientkeyexchange<'a,'b>(x:(&'a mut [u8],usize),m:&'b TlsClientKeyExchangeContents) -> Result<(&'a mut [u8],usize),GenError> {
match m {
&TlsClientKeyExchangeContents::Unknown(ref b) => gen_tls_clientkeyexchange_unknown(x,b),
&TlsClientKeyExchangeContents::Dh(ref b) => gen_tls_clientkeyexchange_dh(x,b),
&TlsClientKeyExchangeContents::Ecdh(ref b) => gen_tls_clientkeyexchange_ecdh(x,b),
}
}
pub fn gen_tls_messagehandshake<'a,'b>(x:(&'a mut [u8],usize),m:&'b TlsMessageHandshake) -> Result<(&'a mut [u8],usize),GenError> {
match m {
&TlsMessageHandshake::HelloRequest => gen_tls_hellorequest(x),
&TlsMessageHandshake::ClientHello(ref m) => gen_tls_clienthello(x,m),
&TlsMessageHandshake::ServerHello(ref m) => gen_tls_serverhello(x,m),
&TlsMessageHandshake::ServerHelloV13Draft18(ref m) => gen_tls_serverhellov13draft18(x,m),
&TlsMessageHandshake::ClientKeyExchange(ref m) => gen_tls_clientkeyexchange(x,m),
&TlsMessageHandshake::Finished(ref m) => gen_tls_finished(x,m),
_ => Err(GenError::NotYetImplemented),
}
}
#[inline]
pub fn gen_tls_changecipherspec<'a>(x:(&'a mut [u8],usize)) -> Result<(&'a mut [u8],usize),GenError> {
gen_be_u8!(x,1)
}
pub fn gen_tls_message<'a,'b>(x:(&'a mut [u8],usize),m:&'b TlsMessage) -> Result<(&'a mut [u8],usize),GenError> {
match m {
&TlsMessage::Handshake(ref m) => gen_tls_messagehandshake(x,m),
&TlsMessage::ChangeCipherSpec => gen_tls_changecipherspec(x),
_ => Err(GenError::NotYetImplemented),
}
}
pub fn gen_tls_plaintext<'a,'b>(x:(&'a mut [u8],usize),p:&'b TlsPlaintext) -> Result<(&'a mut [u8],usize),GenError> {
do_gen!(
x,
gen_be_u8!(u8::from(p.hdr.record_type)) >>
gen_be_u16!(p.hdr.version) >>
ofs_len: gen_be_u16!(p.hdr.len) >>
start: gen_many_ref!(&p.msg,gen_tls_message) >>
end: gen_cond!(p.hdr.len == 0,
gen_at_offset!(ofs_len,gen_be_u16!(end-start)))
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serialize_plaintext() {
let rand_data = [0xff, 0x21, 0xeb, 0x04, 0xc8, 0xa5, 0x38, 0x39, 0x9a,
0xcf, 0xb7, 0xa3, 0x82, 0x1f, 0x82, 0x6c, 0x49, 0xbc, 0x8b, 0xb8, 0xa9,
0x03, 0x0a, 0x2d, 0xce, 0x38, 0x0b, 0xf4];
let ciphers = vec![
0xc030,
0xc02c, 0xc028, 0xc024, 0xc014, 0xc00a, 0x00a5,
0x00a3, 0x00a1, 0x009f, 0x006b, 0x006a, 0x0069,
0x0068, 0x0039, 0x0038, 0x0037, 0x0036, 0x0088,
0x0087, 0x0086, 0x0085, 0xc032, 0xc02e, 0xc02a,
0xc026, 0xc00f, 0xc005, 0x009d, 0x003d, 0x0035,
0x0084, 0xc02f, 0xc02b, 0xc027, 0xc023, 0xc013,
0xc009, 0x00a4, 0x00a2, 0x00a0, 0x009e, 0x0067,
0x0040, 0x003f, 0x003e, 0x0033, 0x0032, 0x0031,
0x0030, 0x009a, 0x0099, 0x0098, 0x0097, 0x0045,
0x0044, 0x0043, 0x0042, 0xc031, 0xc02d, 0xc029,
0xc025, 0xc00e, 0xc004, 0x009c, 0x003c, 0x002f,
0x0096, 0x0041, 0xc011, 0xc007, 0xc00c, 0xc002,
0x0005, 0x0004, 0xc012, 0xc008, 0x0016, 0x0013,
0x0010, 0x000d, 0xc00d, 0xc003, 0x000a, 0x00ff
];
let comp = vec![TlsCompressionID(0x00)];
let expected = TlsPlaintext {
hdr: TlsRecordHeader {
record_type: TlsRecordType::Handshake,
version: 0x0301,
len: 213,
},
msg: vec![TlsMessage::Handshake(
TlsMessageHandshake::ClientHello(
TlsClientHelloContents {
version: TlsVersion::Tls12,
rand_time: 0xb29dd787,
rand_data: &rand_data,
session_id: None,
ciphers: ciphers.iter().map(|&x| TlsCipherSuiteID(x)).collect(),
comp: comp,
ext: None,
})
)]
};
{
let mut mem : [u8; 218] = [0; 218];
let s = &mut mem[..];
let res = gen_tls_plaintext((s,0), &expected);
match res {
Ok((b,_)) => {
let res_reparse = parse_tls_plaintext(b);
assert_eq!(res_reparse,Ok((&b""[..],expected)));
},
Err(e) => println!("Error: {:?}",e),
};
}
}
#[test]
fn serialize_hellorequest() {
let mut mem : [u8; 256] = [0; 256];
let s = &mut mem[..];
let m = TlsMessageHandshake::HelloRequest;
let res = gen_tls_messagehandshake((s,0), &m);
match res {
Ok((b,_)) => {
let v = [0, 0, 0, 0];
assert_eq!(&b[..v.len()],v);
},
Err(e) => println!("Error: {:?}",e),
};
}
#[test]
fn serialize_tls_ext() {
let mut mem : [u8; 256] = [0; 256];
let s = &mut mem[..];
let ext = vec![
TlsExtension::SNI(vec![(SNIType::HostName,b"www.google.com")]),
];
let res = gen_many_ref!((s,0),ext,gen_tls_extension);
match res {
Ok((b,idx)) => {
let v = [
0x00, 0x00,
0x00, 0x11,
0x00,
0x00, 0x0e,
0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
];
assert_eq!(idx,v.len());
assert_eq!(&b[..v.len()],&v[..]);
},
Err(e) => println!("Error: {:?}",e),
};
}
#[test]
fn serialize_clienthello() {
let rand_data = [0xff, 0x21, 0xeb, 0x04, 0xc8, 0xa5, 0x38, 0x39, 0x9a,
0xcf, 0xb7, 0xa3, 0x82, 0x1f, 0x82, 0x6c, 0x49, 0xbc, 0x8b, 0xb8, 0xa9,
0x03, 0x0a, 0x2d, 0xce, 0x38, 0x0b, 0xf4];
let ciphers = vec![ 0xc030, 0xc02c ];
let comp = vec![TlsCompressionID(0x00)];
let m = TlsMessageHandshake::ClientHello(
TlsClientHelloContents {
version: TlsVersion::Tls12,
rand_time: 0xb29dd787,
rand_data: &rand_data,
session_id: None,
ciphers: ciphers.iter().map(|&x| TlsCipherSuiteID(x)).collect(),
comp: comp,
ext: None,
});
let mut mem : [u8; 256] = [0; 256];
let s = &mut mem[..];
let res = gen_tls_messagehandshake((s,0), &m);
match res {
Ok((b,idx)) => {
let v = [
0x01, 0x00, 0x00, 0x2b, 0x03, 0x03,
0xb2, 0x9d, 0xd7, 0x87,
0xff, 0x21, 0xeb, 0x04, 0xc8, 0xa5, 0x38, 0x39,
0x9a, 0xcf, 0xb7, 0xa3, 0x82, 0x1f, 0x82, 0x6c,
0x49, 0xbc, 0x8b, 0xb8, 0xa9, 0x03, 0x0a, 0x2d,
0xce, 0x38, 0x0b, 0xf4,
0x00,
0x00, 0x04, 0xc0, 0x30, 0xc0, 0x2c,
0x01, 0x00,
];
assert_eq!(idx,v.len());
assert_eq!(&b[..v.len()],&v[..]);
},
Err(e) => println!("Error: {:?}",e),
};
}
#[test]
fn serialize_serverhello() {
let rand_data = [0xff, 0x21, 0xeb, 0x04, 0xc8, 0xa5, 0x38, 0x39, 0x9a,
0xcf, 0xb7, 0xa3, 0x82, 0x1f, 0x82, 0x6c, 0x49, 0xbc, 0x8b, 0xb8, 0xa9,
0x03, 0x0a, 0x2d, 0xce, 0x38, 0x0b, 0xf4];
let m = TlsMessageHandshake::ServerHello(
TlsServerHelloContents {
version: TlsVersion::Tls12,
rand_time: 0xb29dd787,
rand_data: &rand_data,
session_id: None,
cipher: TlsCipherSuiteID(0xc030),
compression: TlsCompressionID(0),
ext: None,
});
let mut mem : [u8; 256] = [0; 256];
let s = &mut mem[..];
let res = gen_tls_messagehandshake((s,0), &m);
match res {
Ok((b,idx)) => {
let v = [
0x02, 0x00, 0x00, 0x26, 0x03, 0x03,
0xb2, 0x9d, 0xd7, 0x87,
0xff, 0x21, 0xeb, 0x04, 0xc8, 0xa5, 0x38, 0x39,
0x9a, 0xcf, 0xb7, 0xa3, 0x82, 0x1f, 0x82, 0x6c,
0x49, 0xbc, 0x8b, 0xb8, 0xa9, 0x03, 0x0a, 0x2d,
0xce, 0x38, 0x0b, 0xf4,
0x00,
0xc0, 0x30,
0x00,
];
assert_eq!(idx,v.len());
assert_eq!(&b[..v.len()],&v[..]);
},
Err(e) => println!("Error: {:?}",e),
};
}
}
}