use crate::tls_ec::{parse_named_groups, NamedGroup};
use crate::tls_handshake::{parse_tls_versions, TlsCipherSuiteID, TlsVersion};
use alloc::{vec, vec::Vec};
use nom::bytes::streaming::{tag, take};
use nom::combinator::{complete, cond, map, map_parser, opt, verify};
use nom::error::{make_error, ErrorKind};
use nom::multi::{length_data, many0};
use nom::number::streaming::{be_u16, be_u32, be_u8};
use nom::{Err, IResult};
use nom_derive::{NomBE, Parse};
use rusticata_macros::newtype_enum;
#[derive(Clone, Copy, Debug, PartialEq, Eq, NomBE)]
pub struct TlsExtensionType(pub u16);
newtype_enum! {
impl display TlsExtensionType {
    ServerName                          = 0, MaxFragmentLength                   = 1,
    ClientCertificate                   = 2,
    TrustedCaKeys                       = 3,
    TruncatedHMac                       = 4,
    StatusRequest                       = 5, UserMapping                         = 6,
    ClientAuthz                         = 7,
    ServerAuthz                         = 8,
    CertType                            = 9,
    SupportedGroups                     = 10, EcPointFormats                      = 11, Srp                                 = 12, SignatureAlgorithms                 = 13, UseSrtp                             = 14,
    Heartbeat                           = 15, ApplicationLayerProtocolNegotiation = 16, StatusRequestv2                     = 17,
    SignedCertificateTimestamp          = 18,
    ClientCertificateType               = 19,
    ServerCertificateType               = 20,
    Padding                             = 21, EncryptThenMac                      = 22, ExtendedMasterSecret                = 23, TokenBinding                        = 24,
    CachedInfo                          = 25,
    RecordSizeLimit                     = 28, SessionTicketTLS                    = 35,
    KeyShareOld                         = 40, PreSharedKey                        = 41, EarlyData                           = 42, SupportedVersions                   = 43, Cookie                              = 44, PskExchangeModes                    = 45, TicketEarlyDataInfo                 = 46, CertificateAuthorities              = 47,
    OidFilters                          = 48, PostHandshakeAuth                   = 49, SigAlgorithmsCert                   = 50, KeyShare                            = 51, NextProtocolNegotiation             = 13172,
    Grease                              = 0xfafa,
    RenegotiationInfo                   = 0xff01, EncryptedServerName                 = 0xffce, }
}
impl TlsExtensionType {
    pub fn from_u16(t: u16) -> TlsExtensionType {
        TlsExtensionType(t)
    }
}
impl From<TlsExtensionType> for u16 {
    fn from(ext: TlsExtensionType) -> u16 {
        ext.0
    }
}
#[derive(Clone, PartialEq)]
pub enum TlsExtension<'a> {
    SNI(Vec<(SNIType, &'a [u8])>),
    MaxFragmentLength(u8),
    StatusRequest(Option<(CertificateStatusType, &'a [u8])>),
    EllipticCurves(Vec<NamedGroup>),
    EcPointFormats(&'a [u8]),
    SignatureAlgorithms(Vec<u16>),
    RecordSizeLimit(u16),
    SessionTicket(&'a [u8]),
    KeyShareOld(&'a [u8]),
    KeyShare(&'a [u8]),
    PreSharedKey(&'a [u8]),
    EarlyData(Option<u32>),
    SupportedVersions(Vec<TlsVersion>),
    Cookie(&'a [u8]),
    PskExchangeModes(Vec<u8>),
    Heartbeat(u8),
    ALPN(Vec<&'a [u8]>),
    SignedCertificateTimestamp(Option<&'a [u8]>),
    Padding(&'a [u8]),
    EncryptThenMac,
    ExtendedMasterSecret,
    OidFilters(Vec<OidFilter<'a>>),
    PostHandshakeAuth,
    NextProtocolNegotiation,
    RenegotiationInfo(&'a [u8]),
    EncryptedServerName {
        ciphersuite: TlsCipherSuiteID,
        group: NamedGroup,
        key_share: &'a [u8],
        record_digest: &'a [u8],
        encrypted_sni: &'a [u8],
    },
    Grease(u16, &'a [u8]),
    Unknown(TlsExtensionType, &'a [u8]),
}
impl<'a> From<&'a TlsExtension<'a>> for TlsExtensionType {
    #[rustfmt::skip]
    fn from(ext: &TlsExtension) -> TlsExtensionType {
        match *ext {
            TlsExtension::SNI(_)                        => TlsExtensionType::ServerName,
            TlsExtension::MaxFragmentLength(_)          => TlsExtensionType::MaxFragmentLength,
            TlsExtension::StatusRequest(_)              => TlsExtensionType::StatusRequest,
            TlsExtension::EllipticCurves(_)             => TlsExtensionType::SupportedGroups,
            TlsExtension::EcPointFormats(_)             => TlsExtensionType::EcPointFormats,
            TlsExtension::SignatureAlgorithms(_)        => TlsExtensionType::SignatureAlgorithms,
            TlsExtension::SessionTicket(_)              => TlsExtensionType::SessionTicketTLS,
            TlsExtension::RecordSizeLimit(_)            => TlsExtensionType::RecordSizeLimit,
            TlsExtension::KeyShareOld(_)                => TlsExtensionType::KeyShareOld,
            TlsExtension::KeyShare(_)                   => TlsExtensionType::KeyShare,
            TlsExtension::PreSharedKey(_)               => TlsExtensionType::PreSharedKey,
            TlsExtension::EarlyData(_)                  => TlsExtensionType::EarlyData,
            TlsExtension::SupportedVersions(_)          => TlsExtensionType::SupportedVersions,
            TlsExtension::Cookie(_)                     => TlsExtensionType::Cookie,
            TlsExtension::PskExchangeModes(_)           => TlsExtensionType::PskExchangeModes,
            TlsExtension::Heartbeat(_)                  => TlsExtensionType::Heartbeat,
            TlsExtension::ALPN(_)                       => TlsExtensionType::ApplicationLayerProtocolNegotiation,
            TlsExtension::SignedCertificateTimestamp(_) => TlsExtensionType::SignedCertificateTimestamp,
            TlsExtension::Padding(_)                    => TlsExtensionType::Padding,
            TlsExtension::EncryptThenMac                => TlsExtensionType::EncryptThenMac,
            TlsExtension::ExtendedMasterSecret          => TlsExtensionType::ExtendedMasterSecret,
            TlsExtension::OidFilters(_)                 => TlsExtensionType::OidFilters,
            TlsExtension::PostHandshakeAuth             => TlsExtensionType::PostHandshakeAuth,
            TlsExtension::NextProtocolNegotiation       => TlsExtensionType::NextProtocolNegotiation,
            TlsExtension::RenegotiationInfo(_)          => TlsExtensionType::RenegotiationInfo,
            TlsExtension::EncryptedServerName{..}       => TlsExtensionType::EncryptedServerName,
            TlsExtension::Grease(_,_)                   => TlsExtensionType::Grease,
            TlsExtension::Unknown(x,_)                  => x
        }
    }
}
#[derive(Clone, Debug, PartialEq)]
pub struct KeyShareEntry<'a> {
    pub group: NamedGroup, pub kx: &'a [u8],      }
#[derive(Clone, Copy, Debug, PartialEq, Eq, NomBE)]
pub struct PskKeyExchangeMode(pub u8);
newtype_enum! {
impl PskKeyExchangeMode {
    Psk    = 0,
    PskDhe = 1,
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, NomBE)]
pub struct SNIType(pub u8);
newtype_enum! {
impl display SNIType {
    HostName = 0,
}
}
#[derive(Clone, Copy, PartialEq, Eq, NomBE)]
pub struct CertificateStatusType(pub u8);
newtype_enum! {
impl debug CertificateStatusType {
    OCSP = 1,
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct OidFilter<'a> {
    pub cert_ext_oid: &'a [u8],
    pub cert_ext_val: &'a [u8],
}
pub fn parse_tls_extension_sni_hostname(i: &[u8]) -> IResult<&[u8], (SNIType, &[u8])> {
    let (i, t) = SNIType::parse(i)?;
    let (i, v) = length_data(be_u16)(i)?;
    Ok((i, (t, v)))
}
pub fn parse_tls_extension_sni_content(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    if i.is_empty() {
        return Ok((i, TlsExtension::SNI(Vec::new())));
    }
    let (i, list_len) = be_u16(i)?;
    let (i, v) = map_parser(
        take(list_len),
        many0(complete(parse_tls_extension_sni_hostname)),
    )(i)?;
    Ok((i, TlsExtension::SNI(v)))
}
pub fn parse_tls_extension_sni(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x00])(i)?;
    map_parser(length_data(be_u16), parse_tls_extension_sni_content)(i)
}
pub fn parse_tls_extension_max_fragment_length_content(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    map(be_u8, TlsExtension::MaxFragmentLength)(i)
}
pub fn parse_tls_extension_max_fragment_length(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x01])(i)?;
    map_parser(
        length_data(be_u16),
        parse_tls_extension_max_fragment_length_content,
    )(i)
}
fn parse_tls_extension_status_request_content(
    i: &[u8],
    ext_len: u16,
) -> IResult<&[u8], TlsExtension> {
    match ext_len {
        0 => Ok((i, TlsExtension::StatusRequest(None))),
        _ => {
            let (i, status_type) = be_u8(i)?;
            let (i, request) = take(ext_len - 1)(i)?;
            Ok((
                i,
                TlsExtension::StatusRequest(Some((CertificateStatusType(status_type), request))),
            ))
        }
    }
}
pub fn parse_tls_extension_status_request(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x05])(i)?;
    let (i, ext_len) = be_u16(i)?;
    map_parser(take(ext_len), move |d| {
        parse_tls_extension_status_request_content(d, ext_len)
    })(i)
}
pub fn parse_tls_extension_elliptic_curves_content(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    map_parser(
        length_data(be_u16),
        map(parse_named_groups, TlsExtension::EllipticCurves),
    )(i)
}
pub fn parse_tls_extension_elliptic_curves(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x0a])(i)?;
    map_parser(
        length_data(be_u16),
        parse_tls_extension_elliptic_curves_content,
    )(i)
}
pub fn parse_tls_extension_ec_point_formats_content(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    map(length_data(be_u8), TlsExtension::EcPointFormats)(i)
}
pub fn parse_tls_extension_ec_point_formats(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x0a])(i)?;
    map_parser(
        length_data(be_u16),
        parse_tls_extension_ec_point_formats_content,
    )(i)
}
pub fn parse_tls_extension_signature_algorithms_content(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, l) = map_parser(length_data(be_u16), many0(complete(be_u16)))(i)?;
    Ok((i, TlsExtension::SignatureAlgorithms(l))) }
pub fn parse_tls_extension_signature_algorithms(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 13])(i)?;
    map_parser(
        length_data(be_u16),
        parse_tls_extension_signature_algorithms_content,
    )(i)
}
pub fn parse_tls_extension_heartbeat_content(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    map(be_u8, TlsExtension::Heartbeat)(i)
}
pub fn parse_tls_extension_heartbeat(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x0d])(i)?;
    let (i, ext_len) = verify(be_u16, |&n| n == 1)(i)?;
    map_parser(take(ext_len), parse_tls_extension_heartbeat_content)(i)
}
fn parse_protocol_name(i: &[u8]) -> IResult<&[u8], &[u8]> {
    length_data(be_u8)(i)
}
pub fn parse_tls_extension_alpn_content(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, v) = map_parser(length_data(be_u16), many0(complete(parse_protocol_name)))(i)?;
    Ok((i, TlsExtension::ALPN(v)))
}
fn parse_tls_extension_padding_content(i: &[u8], ext_len: u16) -> IResult<&[u8], TlsExtension> {
    map(take(ext_len), TlsExtension::Padding)(i)
}
pub fn parse_tls_extension_signed_certificate_timestamp_content(
    i: &[u8],
) -> IResult<&[u8], TlsExtension> {
    map(
        opt(complete(length_data(be_u16))),
        TlsExtension::SignedCertificateTimestamp,
    )(i)
}
fn parse_tls_extension_encrypt_then_mac_content(
    i: &[u8],
    ext_len: u16,
) -> IResult<&[u8], TlsExtension> {
    if ext_len != 0 {
        return Err(Err::Error(make_error(i, ErrorKind::Verify)));
    }
    Ok((i, TlsExtension::EncryptThenMac))
}
pub fn parse_tls_extension_encrypt_then_mac(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x16])(i)?;
    let (i, ext_len) = be_u16(i)?;
    map_parser(take(ext_len), move |d| {
        parse_tls_extension_encrypt_then_mac_content(d, ext_len)
    })(i)
}
fn parse_tls_extension_extended_master_secret_content(
    i: &[u8],
    ext_len: u16,
) -> IResult<&[u8], TlsExtension> {
    if ext_len != 0 {
        return Err(Err::Error(make_error(i, ErrorKind::Verify)));
    }
    Ok((i, TlsExtension::ExtendedMasterSecret))
}
pub fn parse_tls_extension_extended_master_secret(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x17])(i)?;
    let (i, ext_len) = be_u16(i)?;
    map_parser(take(ext_len), move |d| {
        parse_tls_extension_extended_master_secret_content(d, ext_len)
    })(i)
}
fn parse_tls_extension_record_size_limit(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    map(be_u16, TlsExtension::RecordSizeLimit)(i)
}
fn parse_tls_extension_session_ticket_content(
    i: &[u8],
    ext_len: u16,
) -> IResult<&[u8], TlsExtension> {
    map(take(ext_len), TlsExtension::SessionTicket)(i)
}
pub fn parse_tls_extension_session_ticket(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x23])(i)?;
    let (i, ext_len) = be_u16(i)?;
    map_parser(take(ext_len), move |d| {
        parse_tls_extension_session_ticket_content(d, ext_len)
    })(i)
}
fn parse_tls_extension_key_share_old_content(
    i: &[u8],
    ext_len: u16,
) -> IResult<&[u8], TlsExtension> {
    map(take(ext_len), TlsExtension::KeyShareOld)(i)
}
fn parse_tls_extension_key_share_content(i: &[u8], ext_len: u16) -> IResult<&[u8], TlsExtension> {
    map(take(ext_len), TlsExtension::KeyShare)(i)
}
pub fn parse_tls_extension_key_share(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x33])(i)?;
    let (i, ext_len) = be_u16(i)?;
    map_parser(take(ext_len), move |d| {
        parse_tls_extension_key_share_content(d, ext_len)
    })(i)
}
fn parse_tls_extension_pre_shared_key_content(
    i: &[u8],
    ext_len: u16,
) -> IResult<&[u8], TlsExtension> {
    map(take(ext_len), TlsExtension::PreSharedKey)(i)
}
pub fn parse_tls_extension_pre_shared_key(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x28])(i)?;
    let (i, ext_len) = be_u16(i)?;
    map_parser(take(ext_len), move |d| {
        parse_tls_extension_pre_shared_key_content(d, ext_len)
    })(i)
}
fn parse_tls_extension_early_data_content(i: &[u8], ext_len: u16) -> IResult<&[u8], TlsExtension> {
    map(cond(ext_len > 0, be_u32), TlsExtension::EarlyData)(i)
}
pub fn parse_tls_extension_early_data(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x2a])(i)?;
    let (i, ext_len) = be_u16(i)?;
    map_parser(take(ext_len), move |d| {
        parse_tls_extension_early_data_content(d, ext_len)
    })(i)
}
fn parse_tls_extension_supported_versions_content(
    i: &[u8],
    ext_len: u16,
) -> IResult<&[u8], TlsExtension> {
    if ext_len == 2 {
        map(be_u16, |x| {
            TlsExtension::SupportedVersions(vec![TlsVersion(x)])
        })(i)
    } else {
        let (i, _) = be_u8(i)?;
        if ext_len == 0 {
            return Err(Err::Error(make_error(i, ErrorKind::Verify)));
        }
        let (i, l) = map_parser(take(ext_len - 1), parse_tls_versions)(i)?;
        Ok((i, TlsExtension::SupportedVersions(l)))
    }
}
pub fn parse_tls_extension_supported_versions(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x2b])(i)?;
    let (i, ext_len) = be_u16(i)?;
    map_parser(take(ext_len), move |d| {
        parse_tls_extension_supported_versions_content(d, ext_len)
    })(i)
}
fn parse_tls_extension_cookie_content(i: &[u8], ext_len: u16) -> IResult<&[u8], TlsExtension> {
    map(take(ext_len), TlsExtension::Cookie)(i)
}
pub fn parse_tls_extension_cookie(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x2c])(i)?;
    let (i, ext_len) = be_u16(i)?;
    map_parser(take(ext_len), move |d| {
        parse_tls_extension_cookie_content(d, ext_len)
    })(i)
}
pub fn parse_tls_extension_psk_key_exchange_modes_content(
    i: &[u8],
) -> IResult<&[u8], TlsExtension> {
    let (i, v) = length_data(be_u8)(i)?;
    Ok((i, TlsExtension::PskExchangeModes(v.to_vec())))
}
pub fn parse_tls_extension_psk_key_exchange_modes(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, _) = tag([0x00, 0x2d])(i)?;
    let (i, ext_len) = be_u16(i)?;
    map_parser(
        take(ext_len),
        parse_tls_extension_psk_key_exchange_modes_content,
    )(i)
}
fn parse_tls_extension_npn_content(i: &[u8], ext_len: u16) -> IResult<&[u8], TlsExtension> {
    if ext_len != 0 {
        return Err(Err::Error(make_error(i, ErrorKind::Verify)));
    }
    Ok((i, TlsExtension::NextProtocolNegotiation))
}
pub fn parse_tls_extension_renegotiation_info_content(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    map(length_data(be_u8), TlsExtension::RenegotiationInfo)(i)
}
pub fn parse_tls_extension_encrypted_server_name(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, ciphersuite) = map(be_u16, TlsCipherSuiteID)(i)?;
    let (i, group) = NamedGroup::parse(i)?;
    let (i, key_share) = length_data(be_u16)(i)?;
    let (i, record_digest) = length_data(be_u16)(i)?;
    let (i, encrypted_sni) = length_data(be_u16)(i)?;
    let esn = TlsExtension::EncryptedServerName {
        ciphersuite,
        group,
        key_share,
        record_digest,
        encrypted_sni,
    };
    Ok((i, esn))
}
fn parse_tls_oid_filter(i: &[u8]) -> IResult<&[u8], OidFilter> {
    let (i, cert_ext_oid) = length_data(be_u8)(i)?;
    let (i, cert_ext_val) = length_data(be_u16)(i)?;
    let filter = OidFilter {
        cert_ext_oid,
        cert_ext_val,
    };
    Ok((i, filter))
}
fn parse_tls_extension_oid_filters(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, v) = map_parser(length_data(be_u16), many0(complete(parse_tls_oid_filter)))(i)?;
    Ok((i, TlsExtension::OidFilters(v)))
}
fn parse_tls_extension_post_handshake_auth_content(
    i: &[u8],
    ext_len: u16,
) -> IResult<&[u8], TlsExtension> {
    if ext_len != 0 {
        return Err(Err::Error(make_error(i, ErrorKind::Verify)));
    }
    Ok((i, TlsExtension::PostHandshakeAuth))
}
pub fn parse_tls_extension_unknown(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, ext_type) = be_u16(i)?;
    let (i, ext_data) = length_data(be_u16)(i)?;
    Ok((
        i,
        TlsExtension::Unknown(TlsExtensionType(ext_type), ext_data),
    ))
}
pub fn parse_tls_client_hello_extension(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, ext_type) = be_u16(i)?;
    let (i, ext_data) = length_data(be_u16)(i)?;
    if ext_type & 0x0f0f == 0x0a0a {
        return Ok((i, TlsExtension::Grease(ext_type, ext_data)));
    }
    let ext_len = ext_data.len() as u16;
    let (_, ext) = match ext_type {
        0 => parse_tls_extension_sni_content(ext_data),
        1 => parse_tls_extension_max_fragment_length_content(ext_data),
        5 => parse_tls_extension_status_request_content(ext_data, ext_len),
        10 => parse_tls_extension_elliptic_curves_content(ext_data),
        11 => parse_tls_extension_ec_point_formats_content(ext_data),
        13 => parse_tls_extension_signature_algorithms_content(ext_data),
        15 => parse_tls_extension_heartbeat_content(ext_data),
        16 => parse_tls_extension_alpn_content(ext_data),
        18 => parse_tls_extension_signed_certificate_timestamp_content(ext_data), 21 => parse_tls_extension_padding_content(ext_data, ext_len),
        22 => parse_tls_extension_encrypt_then_mac_content(ext_data, ext_len),
        23 => parse_tls_extension_extended_master_secret_content(ext_data, ext_len),
        28 => parse_tls_extension_record_size_limit(ext_data),
        35 => parse_tls_extension_session_ticket_content(ext_data, ext_len),
        41 => parse_tls_extension_pre_shared_key_content(ext_data, ext_len),
        42 => parse_tls_extension_early_data_content(ext_data, ext_len),
        43 => parse_tls_extension_supported_versions_content(ext_data, ext_len),
        44 => parse_tls_extension_cookie_content(ext_data, ext_len),
        45 => parse_tls_extension_psk_key_exchange_modes_content(ext_data),
        48 => parse_tls_extension_oid_filters(ext_data),
        49 => parse_tls_extension_post_handshake_auth_content(ext_data, ext_len),
        51 => parse_tls_extension_key_share_content(ext_data, ext_len), 13172 => parse_tls_extension_npn_content(ext_data, ext_len),    0xff01 => parse_tls_extension_renegotiation_info_content(ext_data),
        0xffce => parse_tls_extension_encrypted_server_name(ext_data),
        _ => Ok((
            i,
            TlsExtension::Unknown(TlsExtensionType(ext_type), ext_data),
        )),
    }?;
    Ok((i, ext))
}
pub fn parse_tls_server_hello_extension(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, ext_type) = be_u16(i)?;
    let (i, ext_data) = length_data(be_u16)(i)?;
    if ext_type & 0x0f0f == 0x0a0a {
        return Ok((i, TlsExtension::Grease(ext_type, ext_data)));
    }
    let ext_len = ext_data.len() as u16;
    let (_, ext) = match ext_type {
        0 => parse_tls_extension_sni_content(ext_data), 1 => parse_tls_extension_max_fragment_length_content(ext_data),
        5 => parse_tls_extension_status_request_content(ext_data, ext_len), 11 => parse_tls_extension_ec_point_formats_content(ext_data),       13 => parse_tls_extension_signature_algorithms_content(ext_data),   15 => parse_tls_extension_heartbeat_content(ext_data),
        16 => parse_tls_extension_alpn_content(ext_data), 18 => parse_tls_extension_signed_certificate_timestamp_content(ext_data),
        21 => parse_tls_extension_encrypt_then_mac_content(ext_data, ext_len),
        23 => parse_tls_extension_extended_master_secret_content(ext_data, ext_len),
        28 => parse_tls_extension_record_size_limit(ext_data),
        35 => parse_tls_extension_session_ticket_content(ext_data, ext_len),
        41 => parse_tls_extension_pre_shared_key_content(ext_data, ext_len),
        42 => parse_tls_extension_early_data_content(ext_data, ext_len),
        43 => parse_tls_extension_supported_versions_content(ext_data, ext_len), 44 => parse_tls_extension_cookie_content(ext_data, ext_len),
        51 => parse_tls_extension_key_share_content(ext_data, ext_len), 13172 => parse_tls_extension_npn_content(ext_data, ext_len),
        0xff01 => parse_tls_extension_renegotiation_info_content(ext_data),
        _ => Ok((
            i,
            TlsExtension::Unknown(TlsExtensionType(ext_type), ext_data),
        )),
    }?;
    Ok((i, ext))
}
pub fn parse_tls_extension(i: &[u8]) -> IResult<&[u8], TlsExtension> {
    let (i, ext_type) = be_u16(i)?;
    let (i, ext_data) = length_data(be_u16)(i)?;
    if ext_type & 0x0f0f == 0x0a0a {
        return Ok((i, TlsExtension::Grease(ext_type, ext_data)));
    }
    let ext_len = ext_data.len() as u16;
    let (_, ext) = match ext_type {
        0 => parse_tls_extension_sni_content(ext_data),
        1 => parse_tls_extension_max_fragment_length_content(ext_data),
        5 => parse_tls_extension_status_request_content(ext_data, ext_len),
        10 => parse_tls_extension_elliptic_curves_content(ext_data),
        11 => parse_tls_extension_ec_point_formats_content(ext_data),
        13 => parse_tls_extension_signature_algorithms_content(ext_data),
        15 => parse_tls_extension_heartbeat_content(ext_data),
        16 => parse_tls_extension_alpn_content(ext_data),
        18 => parse_tls_extension_signed_certificate_timestamp_content(ext_data),
        21 => parse_tls_extension_padding_content(ext_data, ext_len),
        22 => parse_tls_extension_encrypt_then_mac_content(ext_data, ext_len),
        23 => parse_tls_extension_extended_master_secret_content(ext_data, ext_len),
        28 => parse_tls_extension_record_size_limit(ext_data),
        35 => parse_tls_extension_session_ticket_content(ext_data, ext_len),
        40 => parse_tls_extension_key_share_old_content(ext_data, ext_len),
        41 => parse_tls_extension_pre_shared_key_content(ext_data, ext_len),
        42 => parse_tls_extension_early_data_content(ext_data, ext_len),
        43 => parse_tls_extension_supported_versions_content(ext_data, ext_len),
        44 => parse_tls_extension_cookie_content(ext_data, ext_len),
        45 => parse_tls_extension_psk_key_exchange_modes_content(ext_data),
        48 => parse_tls_extension_oid_filters(ext_data),
        49 => parse_tls_extension_post_handshake_auth_content(ext_data, ext_len),
        51 => parse_tls_extension_key_share_content(ext_data, ext_len),
        13172 => parse_tls_extension_npn_content(ext_data, ext_len),
        0xff01 => parse_tls_extension_renegotiation_info_content(ext_data),
        0xffce => parse_tls_extension_encrypted_server_name(ext_data),
        _ => Ok((
            i,
            TlsExtension::Unknown(TlsExtensionType(ext_type), ext_data),
        )),
    }?;
    Ok((i, ext))
}
pub fn parse_tls_client_hello_extensions(i: &[u8]) -> IResult<&[u8], Vec<TlsExtension>> {
    many0(complete(parse_tls_client_hello_extension))(i)
}
pub fn parse_tls_server_hello_extensions(i: &[u8]) -> IResult<&[u8], Vec<TlsExtension>> {
    many0(complete(parse_tls_server_hello_extension))(i)
}
pub fn parse_tls_extensions(i: &[u8]) -> IResult<&[u8], Vec<TlsExtension>> {
    many0(complete(parse_tls_extension))(i)
}