use nom::{be_u8,be_u16,be_u24,be_u32,rest,IResult,Err,ErrorKind};
use tls_alert::*;
use tls_ciphers::*;
use tls_ec::ECPoint;
use std::ops::Deref;
use std::convert::AsRef;
use std::fmt;
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct TlsHandshakeType(pub u8);
newtype_enum!{
impl debug TlsHandshakeType {
HelloRequest = 0x00,
ClientHello = 0x01,
ServerHello = 0x02,
NewSessionTicket = 0x04,
EndOfEarlyData = 0x05,
HelloRetryRequest = 0x06,
EncryptedExtensions = 0x08,
Certificate = 0x0b,
ServerKeyExchange = 0x0c,
CertificateRequest = 0x0d,
ServerDone = 0x0e,
CertificateVerify = 0x0f,
ClientKeyExchange = 0x10,
Finished = 0x14,
CertificateURL = 0x15,
CertificateStatus = 0x16,
KeyUpdate = 0x18,
NextProtocol = 0x43,
}
}
impl From<TlsHandshakeType> for u8 {
fn from(v: TlsHandshakeType) -> u8 { v.0 }
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct TlsVersion(pub u16);
newtype_enum!{
impl debug TlsVersion {
Ssl30 = 0x0300,
Tls10 = 0x0301,
Tls11 = 0x0302,
Tls12 = 0x0303,
Tls13 = 0x0304,
Tls13Draft18 = 0x7f12,
Tls13Draft19 = 0x7f13,
Tls13Draft20 = 0x7f14,
Tls13Draft21 = 0x7f15,
Tls13Draft22 = 0x7f16,
Tls13Draft23 = 0x7f17,
}
}
impl From<TlsVersion> for u16 {
fn from(v: TlsVersion) -> u16 { v.0 }
}
impl fmt::LowerHex for TlsVersion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:x}", self.0)
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct TlsHeartbeatMessageType(pub u8);
newtype_enum!{
impl debug TlsHeartbeatMessageType {
HeartBeatRequest = 0x1,
HeartBeatResponse = 0x2,
}
}
impl From<TlsHeartbeatMessageType> for u8 {
fn from(v: TlsHeartbeatMessageType) -> u8 { v.0 }
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct TlsRecordType(pub u8);
newtype_enum!{
impl debug TlsRecordType {
ChangeCipherSpec = 0x14,
Alert = 0x15,
Handshake = 0x16,
ApplicationData = 0x17,
Heartbeat = 0x18,
}
}
impl From<TlsRecordType> for u8 {
fn from(v: TlsRecordType) -> u8 { v.0 }
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct TlsCompressionID(pub u8);
newtype_enum!{
impl debug TlsCompressionID {
Null = 0x00,
}
}
impl From<TlsCompressionID> for u8 {
fn from(c: TlsCompressionID) -> u8 { c.0 }
}
impl Deref for TlsCompressionID {
type Target = u8;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl AsRef<u8> for TlsCompressionID {
fn as_ref(&self) -> &u8 { &self.0 }
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct TlsCipherSuiteID(pub u16);
impl TlsCipherSuiteID {
pub fn get_ciphersuite(&self) -> Option<&'static TlsCipherSuite> {
TlsCipherSuite::from_id(self.0)
}
}
impl From<TlsCipherSuiteID> for u16 {
fn from(c: TlsCipherSuiteID) -> u16 { c.0 }
}
impl Deref for TlsCipherSuiteID {
type Target = u16;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl AsRef<u16> for TlsCipherSuiteID {
fn as_ref(&self) -> &u16 { &self.0 }
}
impl fmt::Display for TlsCipherSuiteID {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Debug for TlsCipherSuiteID {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match TlsCipherSuite::from_id(self.0) {
Some(ref c) => write!(f,"0x{:04x}({})",self.0,c.name),
None => write!(f,"0x{:04x}(Unknown cipher)",self.0),
}
}
}
impl fmt::LowerHex for TlsCipherSuiteID {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:x}", self.0)
}
}
#[derive(Clone,PartialEq)]
pub struct TlsClientHelloContents<'a> {
pub version: TlsVersion,
pub rand_time: u32,
pub rand_data: &'a[u8],
pub session_id: Option<&'a[u8]>,
pub ciphers: Vec<TlsCipherSuiteID>,
pub comp: Vec<TlsCompressionID>,
pub ext: Option<&'a[u8]>,
}
impl<'a> TlsClientHelloContents<'a> {
pub fn new(v:u16,rt:u32,rd:&'a[u8],sid:Option<&'a[u8]>,c:Vec<TlsCipherSuiteID>,co:Vec<TlsCompressionID>,e:Option<&'a[u8]>) -> Self {
TlsClientHelloContents {
version: TlsVersion(v),
rand_time: rt,
rand_data: rd,
session_id: sid,
ciphers: c,
comp: co,
ext: e,
}
}
pub fn get_version(&self) -> TlsVersion {
self.version
}
pub fn get_ciphers(&self) -> Vec<Option<&'static TlsCipherSuite>> {
self.ciphers.iter().map(|&x|
x.get_ciphersuite()
).collect()
}
}
#[derive(Clone,PartialEq)]
pub struct TlsServerHelloContents<'a> {
pub version: TlsVersion,
pub rand_time: u32,
pub rand_data: &'a[u8],
pub session_id: Option<&'a[u8]>,
pub cipher: TlsCipherSuiteID,
pub compression: TlsCompressionID,
pub ext: Option<&'a[u8]>,
}
#[derive(Clone,PartialEq)]
pub struct TlsServerHelloV13Draft18Contents<'a> {
pub version: TlsVersion,
pub random: &'a[u8],
pub cipher: TlsCipherSuiteID,
pub ext: Option<&'a[u8]>,
}
#[derive(Clone,PartialEq)]
pub struct TlsHelloRetryRequestContents<'a> {
pub version: TlsVersion,
pub cipher: TlsCipherSuiteID,
pub ext: Option<&'a[u8]>,
}
impl<'a> TlsServerHelloContents<'a> {
pub fn new(v:u16,rt:u32,rd:&'a[u8],sid:Option<&'a[u8]>,c:u16,co:u8,e:Option<&'a[u8]>) -> Self {
TlsServerHelloContents {
version: TlsVersion(v),
rand_time: rt,
rand_data: rd,
session_id: sid,
cipher: TlsCipherSuiteID(c),
compression: TlsCompressionID(co),
ext: e,
}
}
pub fn get_version(&self) -> TlsVersion {
self.version
}
pub fn get_cipher(&self) -> Option<&'static TlsCipherSuite> {
self.cipher.get_ciphersuite()
}
}
#[derive(Clone,Debug,PartialEq)]
pub struct TlsNewSessionTicketContent<'a> {
pub ticket_lifetime_hint: u32,
pub ticket: &'a[u8],
}
#[derive(Clone,PartialEq)]
pub struct RawCertificate<'a> {
pub data: &'a[u8],
}
#[derive(Clone,Debug,PartialEq)]
pub struct TlsCertificateContents<'a> {
pub cert_chain: Vec<RawCertificate<'a> >,
}
#[derive(Clone,Debug,PartialEq)]
pub struct TlsCertificateRequestContents<'a> {
pub cert_types: Vec<u8>,
pub sig_hash_algs: Option<Vec<u16>>,
pub unparsed_ca: Vec<&'a[u8]>,
}
#[derive(Clone,PartialEq)]
pub struct TlsServerKeyExchangeContents<'a> {
pub parameters: &'a[u8],
}
#[derive(Clone,PartialEq)]
pub enum TlsClientKeyExchangeContents<'a> {
Dh(&'a[u8]),
Ecdh(ECPoint<'a>),
Unknown(&'a[u8]),
}
#[derive(Clone,Debug,PartialEq)]
pub struct TlsCertificateStatusContents<'a> {
pub status_type: u8,
pub blob: &'a[u8],
}
#[derive(Clone,Debug,PartialEq)]
pub struct TlsNextProtocolContent<'a> {
pub selected_protocol: &'a[u8],
pub padding: &'a[u8],
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct KeyUpdateRequest(pub u8);
newtype_enum!{
impl KeyUpdateRequest {
NotRequested = 0x0,
Requested = 0x1,
}
}
#[derive(Clone,Debug,PartialEq)]
pub enum TlsMessageHandshake<'a> {
HelloRequest,
ClientHello(TlsClientHelloContents<'a>),
ServerHello(TlsServerHelloContents<'a>),
ServerHelloV13Draft18(TlsServerHelloV13Draft18Contents<'a>),
NewSessionTicket(TlsNewSessionTicketContent<'a>),
EndOfEarlyData,
HelloRetryRequest(TlsHelloRetryRequestContents<'a>),
Certificate(TlsCertificateContents<'a>),
ServerKeyExchange(TlsServerKeyExchangeContents<'a>),
CertificateRequest(TlsCertificateRequestContents<'a>),
ServerDone(&'a[u8]),
CertificateVerify(&'a[u8]),
ClientKeyExchange(TlsClientKeyExchangeContents<'a>),
Finished(&'a[u8]),
CertificateStatus(TlsCertificateStatusContents<'a>),
NextProtocol(TlsNextProtocolContent<'a>),
KeyUpdate(u8),
}
#[derive(Clone,Debug,PartialEq)]
pub struct TlsMessageApplicationData<'a>{
pub blob: &'a[u8],
}
#[derive(Clone,Debug,PartialEq)]
pub struct TlsMessageHeartbeat<'a>{
pub heartbeat_type: TlsHeartbeatMessageType,
pub payload_len: u16,
pub payload: &'a[u8],
}
#[derive(Clone,PartialEq)]
pub struct TlsRecordHeader {
pub record_type: TlsRecordType,
pub version: TlsVersion,
pub len: u16,
}
#[derive(Clone,Debug,PartialEq)]
pub enum TlsMessage<'a> {
Handshake(TlsMessageHandshake<'a>),
ChangeCipherSpec,
Alert(TlsMessageAlert),
ApplicationData(TlsMessageApplicationData<'a>),
Heartbeat(TlsMessageHeartbeat<'a>),
}
#[derive(Clone,Debug,PartialEq)]
pub struct TlsPlaintext<'a> {
pub hdr: TlsRecordHeader,
pub msg: Vec<TlsMessage<'a>>,
}
#[derive(Clone,Debug,PartialEq)]
pub struct TlsEncryptedContent<'a> {
pub blob: &'a[u8],
}
#[derive(Clone,Debug,PartialEq)]
pub struct TlsEncrypted<'a> {
pub hdr: TlsRecordHeader,
pub msg: TlsEncryptedContent<'a>,
}
#[derive(Clone,Debug,PartialEq)]
pub struct TlsRawRecord<'a> {
pub hdr: TlsRecordHeader,
pub data: &'a[u8],
}
fn parse_cipher_suites(i:&[u8], len:usize) -> IResult<&[u8],Vec<TlsCipherSuiteID>> {
if len == 0 { return Ok((i,Vec::new())) }
if len%2 == 1 || len > i.len() { return Err(Err::Error(error_position!(i, ErrorKind::LengthValue))); }
let v = (&i[..len]).chunks(2).map(|chunk| {
TlsCipherSuiteID((chunk[0] as u16) << 8 | chunk[1] as u16) }).collect();
Ok((&i[len..],v))
}
fn parse_compressions_algs(i:&[u8], len:usize) -> IResult<&[u8],Vec<TlsCompressionID>> {
if len == 0 { return Ok((i,Vec::new())) }
if len > i.len() { return Err(Err::Error(error_position!(i, ErrorKind::LengthValue))); }
let v = (&i[..len]).iter().map(|&it| { TlsCompressionID(it) }).collect();
Ok((&i[len..],v))
}
pub(crate) fn parse_tls_versions(i:&[u8]) -> IResult<&[u8],Vec<TlsVersion>> {
let len = i.len();
if len == 0 { return Ok((i,Vec::new())) }
if len%2 == 1 || len > i.len() { return Err(Err::Error(error_position!(i, ErrorKind::LengthValue))); }
let v = (&i[..len]).chunks(2).map(|chunk| {
TlsVersion((chunk[0] as u16) << 8 | chunk[1] as u16) }).collect();
Ok((&i[len..],v))
}
named!(parse_certs<Vec<RawCertificate> >,
many0!(
complete!(
map!(
length_bytes!(be_u24),
|s| RawCertificate{ data: s }
)
)
)
);
named!(parse_tls_record_header<TlsRecordHeader>,
do_parse!(
t: be_u8 >>
v: be_u16 >>
l: be_u16 >>
(
TlsRecordHeader {
record_type: TlsRecordType(t),
version: TlsVersion(v),
len: l,
}
)
)
);
named!(parse_tls_handshake_msg_hello_request<TlsMessageHandshake>,
value!(TlsMessageHandshake::HelloRequest)
);
named!(parse_tls_handshake_msg_client_hello<TlsMessageHandshake>,
do_parse!(
v: be_u16 >>
rand_time: be_u32 >>
rand_data: take!(28) >>
sidlen: be_u8 >>
error_if!(sidlen > 32, ErrorKind::Custom(128)) >>
sid: cond!(sidlen > 0, take!(sidlen as usize)) >>
ciphers_len: be_u16 >>
ciphers: call!(parse_cipher_suites, ciphers_len as usize) >>
comp_len: be_u8 >>
comp: call!(parse_compressions_algs, comp_len as usize) >>
ext: opt!(complete!(length_bytes!(be_u16))) >>
(
TlsMessageHandshake::ClientHello(
TlsClientHelloContents::new(v,rand_time,rand_data,sid,ciphers,comp.to_vec(),ext)
)
)
)
);
named!(parse_tls_handshake_msg_server_hello_tlsv12<TlsMessageHandshake>,
do_parse!(
v: be_u16 >>
rand_time: be_u32 >>
rand_data: take!(28) >>
sidlen: be_u8 >>
error_if!(sidlen > 32, ErrorKind::Custom(128)) >>
sid: cond!(sidlen > 0, take!(sidlen as usize)) >>
cipher: be_u16 >>
comp: be_u8 >>
ext: opt!(complete!(length_bytes!(be_u16))) >>
(
TlsMessageHandshake::ServerHello(
TlsServerHelloContents::new(v,rand_time,rand_data,sid,cipher,comp,ext)
)
)
)
);
named!(parse_tls_handshake_msg_server_hello_tlsv13draft18<TlsMessageHandshake>,
do_parse!(
hv: be_u16 >>
random: take!(32) >>
cipher: be_u16 >>
ext: opt!(complete!(length_bytes!(be_u16))) >>
(
TlsMessageHandshake::ServerHelloV13Draft18(
TlsServerHelloV13Draft18Contents {
version: TlsVersion(hv),
random: random,
cipher: TlsCipherSuiteID(cipher),
ext: ext,
}
)
)
)
);
named!(parse_tls_handshake_msg_server_hello<TlsMessageHandshake>,
switch!(peek!(be_u16),
0x7f12 => call!(parse_tls_handshake_msg_server_hello_tlsv13draft18) |
0x0303 => call!(parse_tls_handshake_msg_server_hello_tlsv12) |
0x0302 => call!(parse_tls_handshake_msg_server_hello_tlsv12) |
0x0301 => call!(parse_tls_handshake_msg_server_hello_tlsv12)
)
);
fn parse_tls_handshake_msg_newsessionticket( i:&[u8], len: usize ) -> IResult<&[u8], TlsMessageHandshake> {
do_parse!(i,
hint: be_u32 >>
raw: take!(len - 4) >>
(
TlsMessageHandshake::NewSessionTicket(
TlsNewSessionTicketContent {
ticket_lifetime_hint: hint,
ticket: raw,
}
)
)
)
}
named!(parse_tls_handshake_msg_hello_retry_request<TlsMessageHandshake>,
do_parse!(
hv: be_u16 >>
c: be_u16 >>
ext: opt!(complete!(length_bytes!(be_u16))) >>
(
TlsMessageHandshake::HelloRetryRequest(
TlsHelloRetryRequestContents {
version: TlsVersion(hv),
cipher: TlsCipherSuiteID(c),
ext: ext,
}
)
)
)
);
named!(parse_tls_handshake_msg_certificate<TlsMessageHandshake>,
do_parse!(
cert_len: be_u24 >>
certs: flat_map!(take!(cert_len),parse_certs) >>
(
TlsMessageHandshake::Certificate(
TlsCertificateContents {
cert_chain: certs,
}
)
)
)
);
fn parse_tls_handshake_msg_serverkeyexchange( i:&[u8], len: usize ) -> IResult<&[u8], TlsMessageHandshake> {
map!(i,
take!(len),
|ext| {
TlsMessageHandshake::ServerKeyExchange(
TlsServerKeyExchangeContents {
parameters: ext,
}
)
}
)
}
fn parse_tls_handshake_msg_serverdone( i:&[u8], len: usize ) -> IResult<&[u8], TlsMessageHandshake> {
map!(i,
take!(len),
|ext| { TlsMessageHandshake::ServerDone(ext) }
)
}
fn parse_tls_handshake_msg_certificateverify( i:&[u8], len: usize ) -> IResult<&[u8], TlsMessageHandshake> {
map!(i,
take!(len),
|blob| { TlsMessageHandshake::CertificateVerify(blob) }
)
}
fn parse_tls_handshake_msg_clientkeyexchange( i:&[u8], len: usize ) -> IResult<&[u8], TlsMessageHandshake> {
map!(i,
take!(len),
|ext| {
TlsMessageHandshake::ClientKeyExchange(
TlsClientKeyExchangeContents::Unknown(ext)
)
}
)
}
fn parse_certrequest_nosigalg( i:&[u8] ) -> IResult<&[u8], TlsMessageHandshake> {
do_parse!(i,
cert_types: length_count!(be_u8,be_u8) >>
ca_len: be_u16 >>
ca: flat_map!(take!(ca_len),many0!(complete!(length_bytes!(be_u16)))) >>
(
TlsMessageHandshake::CertificateRequest(
TlsCertificateRequestContents {
cert_types: cert_types,
sig_hash_algs: None,
unparsed_ca: ca,
}
)
)
)
}
fn parse_certrequest_full( i:&[u8] ) -> IResult<&[u8], TlsMessageHandshake> {
do_parse!(i,
cert_types: length_count!(be_u8,be_u8) >>
sig_hash_algs_len: be_u16 >>
sig_hash_algs: flat_map!(take!(sig_hash_algs_len),many0!(complete!(be_u16))) >>
ca_len: be_u16 >>
ca: flat_map!(take!(ca_len),many0!(complete!(length_bytes!(be_u16)))) >>
(
TlsMessageHandshake::CertificateRequest(
TlsCertificateRequestContents {
cert_types: cert_types,
sig_hash_algs: Some(sig_hash_algs),
unparsed_ca: ca,
}
)
)
)
}
#[inline]
fn parse_tls_handshake_msg_certificaterequest( i:&[u8] ) -> IResult<&[u8], TlsMessageHandshake> {
alt_complete!(i, parse_certrequest_full | parse_certrequest_nosigalg)
}
fn parse_tls_handshake_msg_finished( i:&[u8], len: usize ) -> IResult<&[u8], TlsMessageHandshake> {
map!(i,
take!(len),
|blob| { TlsMessageHandshake::Finished(blob) }
)
}
named!(parse_tls_handshake_msg_certificatestatus<TlsMessageHandshake>,
do_parse!(
status_type: be_u8 >>
blob: length_bytes!(be_u24) >>
( TlsMessageHandshake::CertificateStatus(
TlsCertificateStatusContents{
status_type:status_type,
blob:blob,
}
) )
)
);
fn parse_tls_handshake_msg_next_protocol( i:&[u8] ) -> IResult<&[u8], TlsMessageHandshake> {
do_parse!(i,
selected_protocol: length_bytes!(be_u8) >>
padding: length_bytes!(be_u8) >>
(
TlsMessageHandshake::NextProtocol(
TlsNextProtocolContent {
selected_protocol: selected_protocol,
padding: padding,
}
)
)
)
}
fn parse_tls_handshake_msg_key_update( i:&[u8] ) -> IResult<&[u8], TlsMessageHandshake> {
map!(i,
be_u8,
|update_request| { TlsMessageHandshake::KeyUpdate(update_request) }
)
}
named!(parse_tls_message_handshake<TlsMessage>,
do_parse!(
ht: be_u8 >>
hl: be_u24 >>
m: flat_map!(take!(hl),
switch!(value!(ht),
0x00 => call!(parse_tls_handshake_msg_hello_request) |
0x01 => call!(parse_tls_handshake_msg_client_hello) |
0x02 => call!(parse_tls_handshake_msg_server_hello) |
0x04 => call!(parse_tls_handshake_msg_newsessionticket,hl as usize) |
0x05 => value!(TlsMessageHandshake::EndOfEarlyData) |
0x06 => call!(parse_tls_handshake_msg_hello_retry_request) |
0x0b => call!(parse_tls_handshake_msg_certificate) |
0x0c => call!(parse_tls_handshake_msg_serverkeyexchange,hl as usize) |
0x0d => call!(parse_tls_handshake_msg_certificaterequest) |
0x0e => call!(parse_tls_handshake_msg_serverdone,hl as usize) |
0x0f => call!(parse_tls_handshake_msg_certificateverify,hl as usize) |
0x10 => call!(parse_tls_handshake_msg_clientkeyexchange,hl as usize) |
0x14 => call!(parse_tls_handshake_msg_finished,hl as usize) |
0x16 => call!(parse_tls_handshake_msg_certificatestatus) |
0x18 => call!(parse_tls_handshake_msg_key_update) |
0x43 => call!(parse_tls_handshake_msg_next_protocol)
)
) >>
( TlsMessage::Handshake(m) )
)
);
named!(parse_tls_message_changecipherspec<TlsMessage>,
map!( tag!([0x01]),
|_| { TlsMessage::ChangeCipherSpec }
)
);
named!(parse_tls_message_alert<TlsMessage>,
do_parse!(
s: be_u8 >>
c: be_u8 >>
( TlsMessage::Alert(
TlsMessageAlert {
severity: TlsAlertSeverity(s),
code: TlsAlertDescription(c),
}
) )
)
);
fn parse_tls_message_applicationdata( i:&[u8] ) -> IResult<&[u8], TlsMessage> {
map!(i,
rest,
|b| {
TlsMessage::ApplicationData(
TlsMessageApplicationData {
blob: b,
})
})
}
fn parse_tls_message_heartbeat( i:&[u8] ) -> IResult<&[u8], TlsMessage> {
do_parse!(i,
hb_type: be_u8 >>
hb_len: be_u16 >>
b: take!(i.len()-3) >>
(
TlsMessage::Heartbeat(
TlsMessageHeartbeat {
heartbeat_type: TlsHeartbeatMessageType(hb_type),
payload_len: hb_len,
payload: b,
}
)
)
)
}
pub fn parse_tls_record_with_header( i:&[u8], hdr:TlsRecordHeader ) -> IResult<&[u8], Vec<TlsMessage>> {
match hdr.record_type {
TlsRecordType::ChangeCipherSpec => many1!(i, complete!(parse_tls_message_changecipherspec)),
TlsRecordType::Alert => many1!(i, complete!(parse_tls_message_alert)),
TlsRecordType::Handshake => many1!(i, complete!(parse_tls_message_handshake)),
TlsRecordType::ApplicationData => many1!(i, complete!(parse_tls_message_applicationdata)),
TlsRecordType::Heartbeat => many1!(i, complete!(parse_tls_message_heartbeat)),
_ => Err(Err::Error(error_position!(i, ErrorKind::Switch)))
}
}
pub fn parse_tls_plaintext(i:&[u8]) -> IResult<&[u8],TlsPlaintext> {
do_parse!(i,
hdr: parse_tls_record_header >>
msg: flat_map!(take!(hdr.len),
apply!(parse_tls_record_with_header,hdr.clone())
) >>
( TlsPlaintext {hdr:hdr, msg:msg} )
)
}
pub fn parse_tls_encrypted(i:&[u8]) -> IResult<&[u8],TlsEncrypted> {
do_parse!(i,
hdr: parse_tls_record_header >>
blob: take!(hdr.len) >>
( TlsEncrypted {hdr:hdr, msg:TlsEncryptedContent{ blob: blob}} )
)
}
pub fn parse_tls_raw_record(i:&[u8]) -> IResult<&[u8],TlsRawRecord> {
do_parse!(i,
hdr: parse_tls_record_header >>
data: take!(hdr.len) >>
( TlsRawRecord {hdr:hdr, data: data} )
)
}
pub fn tls_parser(i:&[u8]) -> IResult<&[u8],TlsPlaintext> {
parse_tls_plaintext(i)
}
pub fn tls_parser_many(i:&[u8]) -> IResult<&[u8],Vec<TlsPlaintext>> {
many1!(i,complete!(parse_tls_plaintext))
}