use std::fmt;
use std::io::BufWriter;
use async_trait::async_trait;
use log::*;
use super::flight6::*;
use super::*;
use crate::cipher_suite::*;
use crate::client_certificate_type::*;
use crate::compression_methods::*;
use crate::config::*;
use crate::content::*;
use crate::crypto::*;
use crate::curve::named_curve::*;
use crate::curve::*;
use crate::error::Error;
use crate::extension::extension_supported_elliptic_curves::*;
use crate::extension::extension_supported_point_formats::*;
use crate::extension::extension_use_extended_master_secret::*;
use crate::extension::extension_use_srtp::*;
use crate::extension::renegotiation_info::ExtensionRenegotiationInfo;
use crate::extension::*;
use crate::handshake::handshake_message_certificate::*;
use crate::handshake::handshake_message_certificate_request::*;
use crate::handshake::handshake_message_server_hello::*;
use crate::handshake::handshake_message_server_hello_done::*;
use crate::handshake::handshake_message_server_key_exchange::*;
use crate::handshake::*;
use crate::prf::*;
use crate::record_layer::record_layer_header::*;
use crate::record_layer::*;
use crate::signature_hash_algorithm::*;
#[derive(Debug, PartialEq)]
pub(crate) struct Flight4;
impl fmt::Display for Flight4 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Flight 4")
}
}
#[async_trait]
impl Flight for Flight4 {
async fn parse(
&self,
tx: &mut mpsc::Sender<mpsc::Sender<()>>,
state: &mut State,
cache: &HandshakeCache,
cfg: &HandshakeConfig,
) -> Result<Box<dyn Flight + Send + Sync>, (Option<Alert>, Option<Error>)> {
let (seq, msgs) = match cache
.full_pull_map(
state.handshake_recv_sequence,
&[
HandshakeCachePullRule {
typ: HandshakeType::Certificate,
epoch: cfg.initial_epoch,
is_client: true,
optional: true,
},
HandshakeCachePullRule {
typ: HandshakeType::ClientKeyExchange,
epoch: cfg.initial_epoch,
is_client: true,
optional: false,
},
HandshakeCachePullRule {
typ: HandshakeType::CertificateVerify,
epoch: cfg.initial_epoch,
is_client: true,
optional: true,
},
],
)
.await
{
Ok((seq, msgs)) => (seq, msgs),
Err(_) => return Err((None, None)),
};
let client_key_exchange = if let Some(HandshakeMessage::ClientKeyExchange(h)) =
msgs.get(&HandshakeType::ClientKeyExchange)
{
h
} else {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::InternalError,
}),
None,
));
};
if let Some(message) = msgs.get(&HandshakeType::Certificate) {
let h = match message {
HandshakeMessage::Certificate(h) => h,
_ => {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::InternalError,
}),
None,
))
}
};
state.peer_certificates.clone_from(&h.certificate);
trace!(
"[handshake] PeerCertificates4 {}",
state.peer_certificates.len()
);
}
if let Some(message) = msgs.get(&HandshakeType::CertificateVerify) {
let h = match message {
HandshakeMessage::CertificateVerify(h) => h,
_ => {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::InternalError,
}),
None,
))
}
};
if state.peer_certificates.is_empty() {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::NoCertificate,
}),
Some(Error::ErrCertificateVerifyNoCertificate),
));
}
let plain_text = cache
.pull_and_merge(&[
HandshakeCachePullRule {
typ: HandshakeType::ClientHello,
epoch: cfg.initial_epoch,
is_client: true,
optional: false,
},
HandshakeCachePullRule {
typ: HandshakeType::ServerHello,
epoch: cfg.initial_epoch,
is_client: false,
optional: false,
},
HandshakeCachePullRule {
typ: HandshakeType::Certificate,
epoch: cfg.initial_epoch,
is_client: false,
optional: false,
},
HandshakeCachePullRule {
typ: HandshakeType::ServerKeyExchange,
epoch: cfg.initial_epoch,
is_client: false,
optional: false,
},
HandshakeCachePullRule {
typ: HandshakeType::CertificateRequest,
epoch: cfg.initial_epoch,
is_client: false,
optional: false,
},
HandshakeCachePullRule {
typ: HandshakeType::ServerHelloDone,
epoch: cfg.initial_epoch,
is_client: false,
optional: false,
},
HandshakeCachePullRule {
typ: HandshakeType::Certificate,
epoch: cfg.initial_epoch,
is_client: true,
optional: false,
},
HandshakeCachePullRule {
typ: HandshakeType::ClientKeyExchange,
epoch: cfg.initial_epoch,
is_client: true,
optional: false,
},
])
.await;
let mut valid_signature_scheme = false;
for ss in &cfg.local_signature_schemes {
if ss.hash == h.algorithm.hash && ss.signature == h.algorithm.signature {
valid_signature_scheme = true;
break;
}
}
if !valid_signature_scheme {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::InsufficientSecurity,
}),
Some(Error::ErrNoAvailableSignatureSchemes),
));
}
if let Err(err) = verify_certificate_verify(
&plain_text,
&h.algorithm,
&h.signature,
&state.peer_certificates,
cfg.insecure_verification,
) {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::BadCertificate,
}),
Some(err),
));
}
let mut chains = vec![];
let mut verified = false;
if cfg.client_auth as u8 >= ClientAuthType::VerifyClientCertIfGiven as u8 {
if let Some(client_cert_verifier) = &cfg.client_cert_verifier {
chains =
match verify_client_cert(&state.peer_certificates, client_cert_verifier) {
Ok(chains) => chains,
Err(err) => {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::BadCertificate,
}),
Some(err),
))
}
};
} else {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::BadCertificate,
}),
Some(Error::ErrInvalidCertificate),
));
}
verified = true
}
if let Some(verify_peer_certificate) = &cfg.verify_peer_certificate {
if let Err(err) = verify_peer_certificate(&state.peer_certificates, &chains) {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::BadCertificate,
}),
Some(err),
));
}
}
state.peer_certificates_verified = verified
} else if !state.peer_certificates.is_empty() {
return Err((None, None));
}
{
let mut cipher_suite = state.cipher_suite.lock().await;
if let Some(cipher_suite) = &mut *cipher_suite {
if !cipher_suite.is_initialized() {
let mut server_random = vec![];
{
let mut writer = BufWriter::<&mut Vec<u8>>::new(server_random.as_mut());
let _ = state.local_random.marshal(&mut writer);
}
let mut client_random = vec![];
{
let mut writer = BufWriter::<&mut Vec<u8>>::new(client_random.as_mut());
let _ = state.remote_random.marshal(&mut writer);
}
let mut pre_master_secret = vec![];
if let Some(local_psk_callback) = &cfg.local_psk_callback {
let psk = match local_psk_callback(&client_key_exchange.identity_hint).await
{
Ok(psk) => psk,
Err(err) => {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::InternalError,
}),
Some(err),
))
}
};
state
.identity_hint
.clone_from(&client_key_exchange.identity_hint);
pre_master_secret = prf_psk_pre_master_secret(&psk);
} else if let Some(local_keypair) = &state.local_keypair {
pre_master_secret = match prf_pre_master_secret(
&client_key_exchange.public_key,
&local_keypair.private_key,
local_keypair.curve,
) {
Ok(pre_master_secret) => pre_master_secret,
Err(err) => {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::IllegalParameter,
}),
Some(err),
))
}
};
}
if state.extended_master_secret {
let hf = cipher_suite.hash_func();
let session_hash =
match cache.session_hash(hf, cfg.initial_epoch, &[]).await {
Ok(s) => s,
Err(err) => {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::InternalError,
}),
Some(err),
))
}
};
state.master_secret = match prf_extended_master_secret(
&pre_master_secret,
&session_hash,
cipher_suite.hash_func(),
) {
Ok(ms) => ms,
Err(err) => {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::InternalError,
}),
Some(err),
))
}
};
} else {
state.master_secret = match prf_master_secret(
&pre_master_secret,
&client_random,
&server_random,
cipher_suite.hash_func(),
) {
Ok(ms) => ms,
Err(err) => {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::InternalError,
}),
Some(err),
))
}
};
}
if let Err(err) = cipher_suite.init(
&state.master_secret,
&client_random,
&server_random,
false,
) {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::InternalError,
}),
Some(err),
));
}
}
}
}
let (done_tx, mut done_rx) = mpsc::channel(1);
if let Err(err) = tx.send(done_tx).await {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::InternalError,
}),
Some(Error::Other(err.to_string())),
));
}
done_rx.recv().await;
let (seq, msgs) = match cache
.full_pull_map(
seq,
&[HandshakeCachePullRule {
typ: HandshakeType::Finished,
epoch: cfg.initial_epoch + 1,
is_client: true,
optional: false,
}],
)
.await
{
Ok((seq, msgs)) => (seq, msgs),
Err(_) => return Err((None, None)),
};
state.handshake_recv_sequence = seq;
if let Some(HandshakeMessage::Finished(h)) = msgs.get(&HandshakeType::Finished) {
h
} else {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::InternalError,
}),
None,
));
};
match cfg.client_auth {
ClientAuthType::RequireAnyClientCert => {
trace!(
"{} peer_certificates.len() {}",
srv_cli_str(state.is_client),
state.peer_certificates.len(),
);
if state.peer_certificates.is_empty() {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::NoCertificate,
}),
Some(Error::ErrClientCertificateRequired),
));
}
}
ClientAuthType::VerifyClientCertIfGiven => {
if !state.peer_certificates.is_empty() && !state.peer_certificates_verified {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::BadCertificate,
}),
Some(Error::ErrClientCertificateNotVerified),
));
}
}
ClientAuthType::RequireAndVerifyClientCert => {
if state.peer_certificates.is_empty() {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::NoCertificate,
}),
Some(Error::ErrClientCertificateRequired),
));
}
if !state.peer_certificates_verified {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::BadCertificate,
}),
Some(Error::ErrClientCertificateNotVerified),
));
}
}
ClientAuthType::NoClientCert | ClientAuthType::RequestClientCert => {
return Ok(Box::new(Flight6 {}) as Box<dyn Flight + Send + Sync>);
}
}
Ok(Box::new(Flight6 {}) as Box<dyn Flight + Send + Sync>)
}
async fn generate(
&self,
state: &mut State,
_cache: &HandshakeCache,
cfg: &HandshakeConfig,
) -> Result<Vec<Packet>, (Option<Alert>, Option<Error>)> {
let mut extensions = vec![Extension::RenegotiationInfo(ExtensionRenegotiationInfo {
renegotiated_connection: 0,
})];
if (cfg.extended_master_secret == ExtendedMasterSecretType::Request
|| cfg.extended_master_secret == ExtendedMasterSecretType::Require)
&& state.extended_master_secret
{
extensions.push(Extension::UseExtendedMasterSecret(
ExtensionUseExtendedMasterSecret { supported: true },
));
}
if state.srtp_protection_profile != SrtpProtectionProfile::Unsupported {
extensions.push(Extension::UseSrtp(ExtensionUseSrtp {
protection_profiles: vec![state.srtp_protection_profile],
}));
}
if cfg.local_psk_callback.is_none() {
extensions.extend_from_slice(&[
Extension::SupportedEllipticCurves(ExtensionSupportedEllipticCurves {
elliptic_curves: vec![NamedCurve::P256, NamedCurve::X25519, NamedCurve::P384],
}),
Extension::SupportedPointFormats(ExtensionSupportedPointFormats {
point_formats: vec![ELLIPTIC_CURVE_POINT_FORMAT_UNCOMPRESSED],
}),
]);
}
let mut pkts = vec![Packet {
record: RecordLayer::new(
PROTOCOL_VERSION1_2,
0,
Content::Handshake(Handshake::new(HandshakeMessage::ServerHello(
HandshakeMessageServerHello {
version: PROTOCOL_VERSION1_2,
random: state.local_random.clone(),
cipher_suite: {
let cipher_suite = state.cipher_suite.lock().await;
if let Some(cipher_suite) = &*cipher_suite {
cipher_suite.id()
} else {
CipherSuiteId::Unsupported
}
},
compression_method: default_compression_methods().ids[0],
extensions,
},
))),
),
should_encrypt: false,
reset_local_sequence_number: false,
}];
if cfg.local_psk_callback.is_none() {
let certificate = match cfg.get_certificate(&cfg.server_name) {
Ok(cert) => cert,
Err(err) => {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::HandshakeFailure,
}),
Some(err),
))
}
};
pkts.push(Packet {
record: RecordLayer::new(
PROTOCOL_VERSION1_2,
0,
Content::Handshake(Handshake::new(HandshakeMessage::Certificate(
HandshakeMessageCertificate {
certificate: certificate
.certificate
.iter()
.map(|x| x.as_ref().to_owned())
.collect(),
},
))),
),
should_encrypt: false,
reset_local_sequence_number: false,
});
let mut server_random = vec![];
{
let mut writer = BufWriter::<&mut Vec<u8>>::new(server_random.as_mut());
let _ = state.local_random.marshal(&mut writer);
}
let mut client_random = vec![];
{
let mut writer = BufWriter::<&mut Vec<u8>>::new(client_random.as_mut());
let _ = state.remote_random.marshal(&mut writer);
}
let signature_hash_algo = match select_signature_scheme(
&cfg.local_signature_schemes,
&certificate.private_key,
) {
Ok(s) => s,
Err(err) => {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::InsufficientSecurity,
}),
Some(err),
))
}
};
if let Some(local_keypair) = &state.local_keypair {
let signature = match generate_key_signature(
&client_random,
&server_random,
&local_keypair.public_key,
state.named_curve,
&certificate.private_key,
) {
Ok(s) => s,
Err(err) => {
return Err((
Some(Alert {
alert_level: AlertLevel::Fatal,
alert_description: AlertDescription::InternalError,
}),
Some(err),
))
}
};
state.local_key_signature = signature;
pkts.push(Packet {
record: RecordLayer::new(
PROTOCOL_VERSION1_2,
0,
Content::Handshake(Handshake::new(HandshakeMessage::ServerKeyExchange(
HandshakeMessageServerKeyExchange {
identity_hint: vec![],
elliptic_curve_type: EllipticCurveType::NamedCurve,
named_curve: state.named_curve,
public_key: local_keypair.public_key.clone(),
algorithm: SignatureHashAlgorithm {
hash: signature_hash_algo.hash,
signature: signature_hash_algo.signature,
},
signature: state.local_key_signature.clone(),
},
))),
),
should_encrypt: false,
reset_local_sequence_number: false,
});
}
if cfg.client_auth as u8 > ClientAuthType::NoClientCert as u8 {
pkts.push(Packet {
record: RecordLayer::new(
PROTOCOL_VERSION1_2,
0,
Content::Handshake(Handshake::new(HandshakeMessage::CertificateRequest(
HandshakeMessageCertificateRequest {
certificate_types: vec![
ClientCertificateType::RsaSign,
ClientCertificateType::EcdsaSign,
],
signature_hash_algorithms: cfg.local_signature_schemes.clone(),
},
))),
),
should_encrypt: false,
reset_local_sequence_number: false,
});
}
} else if let Some(local_psk_identity_hint) = &cfg.local_psk_identity_hint {
pkts.push(Packet {
record: RecordLayer::new(
PROTOCOL_VERSION1_2,
0,
Content::Handshake(Handshake::new(HandshakeMessage::ServerKeyExchange(
HandshakeMessageServerKeyExchange {
identity_hint: local_psk_identity_hint.clone(),
elliptic_curve_type: EllipticCurveType::Unsupported,
named_curve: NamedCurve::Unsupported,
public_key: vec![],
algorithm: SignatureHashAlgorithm {
hash: HashAlgorithm::Unsupported,
signature: SignatureAlgorithm::Unsupported,
},
signature: vec![],
},
))),
),
should_encrypt: false,
reset_local_sequence_number: false,
});
}
pkts.push(Packet {
record: RecordLayer::new(
PROTOCOL_VERSION1_2,
0,
Content::Handshake(Handshake::new(HandshakeMessage::ServerHelloDone(
HandshakeMessageServerHelloDone {},
))),
),
should_encrypt: false,
reset_local_sequence_number: false,
});
Ok(pkts)
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use tokio::sync::Mutex;
use super::*;
use crate::error::Result;
struct MockCipherSuite {}
impl CipherSuite for MockCipherSuite {
fn to_string(&self) -> String {
"MockCipherSuite".into()
}
fn id(&self) -> CipherSuiteId {
unimplemented!();
}
fn certificate_type(&self) -> ClientCertificateType {
unimplemented!();
}
fn hash_func(&self) -> CipherSuiteHash {
unimplemented!();
}
fn is_psk(&self) -> bool {
false
}
fn is_initialized(&self) -> bool {
panic!("is_initialized called with Certificate but not CertificateVerify");
}
fn init(
&mut self,
_master_secret: &[u8],
_client_random: &[u8],
_server_random: &[u8],
_is_client: bool,
) -> Result<()> {
unimplemented!();
}
fn encrypt(&self, _pkt_rlh: &RecordLayerHeader, _raw: &[u8]) -> Result<Vec<u8>> {
unimplemented!();
}
fn decrypt(&self, _input: &[u8]) -> Result<Vec<u8>> {
unimplemented!();
}
}
#[tokio::test]
async fn test_flight4_process_certificateverify() {
let mut state = State {
cipher_suite: Arc::new(Mutex::new(Some(Box::new(MockCipherSuite {})))),
..Default::default()
};
let raw_certificate = vec![
0x0b, 0x00, 0x01, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x9b, 0x00, 0x01,
0x98, 0x00, 0x01, 0x95, 0x30, 0x82, 0x01, 0x91, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03,
0x02, 0x01, 0x02, 0x02, 0x11, 0x01, 0x65, 0x03, 0x3f, 0x4d, 0x0b, 0x9a, 0x62, 0x91,
0xdb, 0x4d, 0x28, 0x2c, 0x1f, 0xd6, 0x73, 0x32, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x00, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x32,
0x30, 0x35, 0x31, 0x35, 0x31, 0x38, 0x34, 0x33, 0x35, 0x35, 0x5a, 0x17, 0x0d, 0x32,
0x32, 0x30, 0x36, 0x31, 0x35, 0x31, 0x38, 0x34, 0x33, 0x35, 0x35, 0x5a, 0x30, 0x00,
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06,
0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xc3,
0xb7, 0x13, 0x1a, 0x0a, 0xfc, 0xd0, 0x82, 0xf8, 0x94, 0x5e, 0xc0, 0x77, 0x07, 0x81,
0x28, 0xc9, 0xcb, 0x08, 0x84, 0x50, 0x6b, 0xf0, 0x22, 0xe8, 0x79, 0xb9, 0x15, 0x33,
0xc4, 0x56, 0xa1, 0xd3, 0x1b, 0x24, 0xe3, 0x61, 0xbd, 0x4d, 0x65, 0x80, 0x6b, 0x5d,
0x96, 0x48, 0xa2, 0x44, 0x9e, 0xce, 0xe8, 0x65, 0xd6, 0x3c, 0xe0, 0x9b, 0x6b, 0xa1,
0x36, 0x34, 0xb2, 0x39, 0xe2, 0x03, 0x00, 0xa3, 0x81, 0x92, 0x30, 0x81, 0x8f, 0x30,
0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02,
0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08,
0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
0x05, 0x07, 0x03, 0x01, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
0x04, 0x16, 0x04, 0x14, 0xb1, 0x1a, 0xe3, 0xeb, 0x6f, 0x7c, 0xc3, 0x8f, 0xba, 0x6f,
0x1c, 0xe8, 0xf0, 0x23, 0x08, 0x50, 0x8d, 0x3c, 0xea, 0x31, 0x30, 0x2e, 0x06, 0x03,
0x55, 0x1d, 0x11, 0x01, 0x01, 0xff, 0x04, 0x24, 0x30, 0x22, 0x82, 0x20, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x06, 0x31, 0x43, 0xac, 0x03, 0x45, 0x79,
0x3c, 0xd7, 0x5f, 0x6e, 0x6a, 0xf8, 0x0e, 0xfd, 0x35, 0x49, 0xee, 0x1b, 0xbc, 0x47,
0xce, 0xe3, 0x39, 0xec, 0xe4, 0x62, 0xe1, 0x30, 0x1a, 0xa1, 0x89, 0x02, 0x20, 0x35,
0xcd, 0x7a, 0x15, 0x68, 0x09, 0x50, 0x49, 0x9e, 0x3e, 0x05, 0xd7, 0xc2, 0x69, 0x3f,
0x9c, 0x0c, 0x98, 0x92, 0x65, 0xec, 0xae, 0x44, 0xfe, 0xe5, 0x68, 0xb8, 0x09, 0x78,
0x7f, 0x6b, 0x77,
];
let raw_client_key_exchange = vec![
0x10, 0x00, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x20, 0x96,
0xed, 0x0c, 0xee, 0xf3, 0x11, 0xb1, 0x9d, 0x8b, 0x1c, 0x02, 0x7f, 0x06, 0x7c, 0x57,
0x7a, 0x14, 0xa6, 0x41, 0xde, 0x63, 0x57, 0x9e, 0xcd, 0x34, 0x54, 0xba, 0x37, 0x4d,
0x34, 0x15, 0x18,
];
let mut cache = HandshakeCache::new();
cache
.push(raw_certificate, 0, 0, HandshakeType::Certificate, true)
.await;
cache
.push(
raw_client_key_exchange,
0,
1,
HandshakeType::ClientKeyExchange,
true,
)
.await;
let cfg = HandshakeConfig::default();
let (mut tx, _rx) = mpsc::channel::<mpsc::Sender<()>>(1);
let f = Flight4 {};
let res = f.parse(&mut tx, &mut state, &cache, &cfg).await;
assert!(res.is_err());
}
}