use crate::registration::handshake::messages::{Finalization, GatewayMaterialExchange};
use crate::registration::handshake::state::State;
use crate::registration::handshake::HandshakeResult;
use crate::registration::handshake::{error::HandshakeError, WsItem};
use crate::GatewayProtocolVersionExt;
use futures::{Sink, Stream};
use rand::{CryptoRng, RngCore};
use tracing::info;
use tungstenite::Message as WsMessage;
impl<S, R> State<'_, S, R> {
async fn client_handshake_inner(&mut self) -> Result<(), HandshakeError>
where
S: Stream<Item = WsItem> + Sink<WsMessage> + Unpin,
R: CryptoRng + RngCore,
{
let hkdf_salt = self.generate_initiator_salt();
let init_message = self.init_message(hkdf_salt.clone());
self.send_handshake_data(init_message).await?;
let (mid_res, gateway_protocol) = self
.receive_handshake_message::<GatewayMaterialExchange>()
.await?;
if gateway_protocol.is_future_version() {
return Err(HandshakeError::UnsupportedProtocol {
version: gateway_protocol,
});
}
if gateway_protocol != self.proposed_protocol_version() {
info!("the gateway insists on protocol version different from the one we suggested. it wants {gateway_protocol} whilst we wanted {:?}, however, we can support it", self.proposed_protocol_version());
self.set_protocol_version(gateway_protocol);
}
self.derive_shared_key(&mid_res.ephemeral_dh, &hkdf_salt);
self.verify_remote_key_material(&mid_res.materials, &mid_res.ephemeral_dh)?;
let materials = self.prepare_key_material_sig(&mid_res.ephemeral_dh)?;
self.send_handshake_data(materials).await?;
let (finalization, _) = self.receive_handshake_message::<Finalization>().await?;
finalization.ensure_success()?;
Ok(())
}
pub(crate) async fn perform_client_handshake(
mut self,
) -> Result<HandshakeResult, HandshakeError>
where
S: Stream<Item = WsItem> + Sink<WsMessage> + Unpin,
R: CryptoRng + RngCore,
{
let handshake_res = self.client_handshake_inner().await;
self.check_for_handshake_processing_error(handshake_res)
.await?;
Ok(self.finalize_handshake())
}
}