Skip to content

Commit 6ad2161

Browse files
authored
crypto/noise: Set timeout limits for the noise handshake (#373)
This PR sets timeout limits for the crypto/noise handshake negotiation. By default, the timeout is bounded similar to protocol negotiation to the substream open timeout. To allow this change, the WebSocket internal API has been opened to accept the open timeout. Before this change, we had no granular control and used the connection timeout as a fallback. cc @paritytech/networking --------- Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
1 parent 48d540d commit 6ad2161

File tree

7 files changed

+913
-73
lines changed

7 files changed

+913
-73
lines changed

src/crypto/noise/mod.rs

Lines changed: 59 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -709,62 +709,71 @@ pub async fn handshake<S: AsyncRead + AsyncWrite + Unpin>(
709709
role: Role,
710710
max_read_ahead_factor: usize,
711711
max_write_buffer_size: usize,
712+
timeout: std::time::Duration,
712713
) -> Result<(NoiseSocket<S>, PeerId), NegotiationError> {
713-
tracing::debug!(target: LOG_TARGET, ?role, "start noise handshake");
714-
715-
let mut noise = NoiseContext::new(keypair, role)?;
716-
let payload = match role {
717-
Role::Dialer => {
718-
// write initial message
719-
let first_message = noise.first_message(Role::Dialer)?;
720-
let _ = io.write(&first_message).await?;
721-
io.flush().await?;
722-
723-
// read back response which contains the remote peer id
724-
let message = noise.read_handshake_message(&mut io).await?;
725-
// Decode the remote identity message.
726-
let payload = handshake_schema::NoiseHandshakePayload::decode(message)
714+
let handle_handshake = async move {
715+
tracing::debug!(target: LOG_TARGET, ?role, "start noise handshake");
716+
717+
let mut noise = NoiseContext::new(keypair, role)?;
718+
let payload = match role {
719+
Role::Dialer => {
720+
// write initial message
721+
let first_message = noise.first_message(Role::Dialer)?;
722+
let _ = io.write(&first_message).await?;
723+
io.flush().await?;
724+
725+
// read back response which contains the remote peer id
726+
let message = noise.read_handshake_message(&mut io).await?;
727+
// Decode the remote identity message.
728+
let payload = handshake_schema::NoiseHandshakePayload::decode(message)
727729
.map_err(ParseError::from)
728730
.map_err(|err| {
729731
tracing::error!(target: LOG_TARGET, ?err, "failed to decode remote identity message");
730732
err
731733
})?;
732734

733-
// send the final message which contains local peer id
734-
let second_message = noise.second_message()?;
735-
let _ = io.write(&second_message).await?;
736-
io.flush().await?;
735+
// send the final message which contains local peer id
736+
let second_message = noise.second_message()?;
737+
let _ = io.write(&second_message).await?;
738+
io.flush().await?;
737739

738-
payload
739-
}
740-
Role::Listener => {
741-
// read remote's first message
742-
let _ = noise.read_handshake_message(&mut io).await?;
743-
744-
// send local peer id.
745-
let second_message = noise.second_message()?;
746-
let _ = io.write(&second_message).await?;
747-
io.flush().await?;
748-
749-
// read remote's second message which contains their peer id
750-
let message = noise.read_handshake_message(&mut io).await?;
751-
// Decode the remote identity message.
752-
handshake_schema::NoiseHandshakePayload::decode(message).map_err(ParseError::from)?
753-
}
754-
};
740+
payload
741+
}
742+
Role::Listener => {
743+
// read remote's first message
744+
let _ = noise.read_handshake_message(&mut io).await?;
745+
746+
// send local peer id.
747+
let second_message = noise.second_message()?;
748+
let _ = io.write(&second_message).await?;
749+
io.flush().await?;
750+
751+
// read remote's second message which contains their peer id
752+
let message = noise.read_handshake_message(&mut io).await?;
753+
// Decode the remote identity message.
754+
handshake_schema::NoiseHandshakePayload::decode(message)
755+
.map_err(ParseError::from)?
756+
}
757+
};
755758

756-
let dh_remote_pubkey = noise.get_handshake_dh_remote_pubkey()?;
757-
let peer = parse_and_verify_peer_id(payload, dh_remote_pubkey)?;
759+
let dh_remote_pubkey = noise.get_handshake_dh_remote_pubkey()?;
760+
let peer = parse_and_verify_peer_id(payload, dh_remote_pubkey)?;
758761

759-
Ok((
760-
NoiseSocket::new(
761-
io,
762-
noise.into_transport()?,
763-
max_read_ahead_factor,
764-
max_write_buffer_size,
765-
),
766-
peer,
767-
))
762+
Ok((
763+
NoiseSocket::new(
764+
io,
765+
noise.into_transport()?,
766+
max_read_ahead_factor,
767+
max_write_buffer_size,
768+
),
769+
peer,
770+
))
771+
};
772+
773+
match tokio::time::timeout(timeout, handle_handshake).await {
774+
Err(_) => Err(NegotiationError::Timeout),
775+
Ok(result) => result,
776+
}
768777
}
769778

770779
// TODO: https://github.com/paritytech/litep2p/issues/125 add more tests
@@ -808,14 +817,16 @@ mod tests {
808817
&keypair1,
809818
Role::Dialer,
810819
MAX_READ_AHEAD_FACTOR,
811-
MAX_WRITE_BUFFER_SIZE
820+
MAX_WRITE_BUFFER_SIZE,
821+
std::time::Duration::from_secs(10),
812822
),
813823
handshake(
814824
io2,
815825
&keypair2,
816826
Role::Listener,
817827
MAX_READ_AHEAD_FACTOR,
818-
MAX_WRITE_BUFFER_SIZE
828+
MAX_WRITE_BUFFER_SIZE,
829+
std::time::Duration::from_secs(10),
819830
)
820831
);
821832
let (mut res1, mut res2) = (res1.unwrap(), res2.unwrap());

src/transport/tcp/connection.rs

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ impl TcpConnection {
437437
role,
438438
max_read_ahead_factor,
439439
max_write_buffer_size,
440+
substream_open_timeout,
440441
)
441442
.await?;
442443

@@ -1146,8 +1147,16 @@ mod tests {
11461147
let keypair = Keypair::generate();
11471148

11481149
// do a noise handshake
1149-
let (stream, _peer) =
1150-
noise::handshake(stream.inner(), &keypair, Role::Dialer, 5, 2).await.unwrap();
1150+
let (stream, _peer) = noise::handshake(
1151+
stream.inner(),
1152+
&keypair,
1153+
Role::Dialer,
1154+
5,
1155+
2,
1156+
std::time::Duration::from_secs(10),
1157+
)
1158+
.await
1159+
.unwrap();
11511160
let stream: NoiseSocket<Compat<TcpStream>> = stream;
11521161

11531162
// after the handshake, try to negotiate some random protocol instead of yamux
@@ -1196,8 +1205,16 @@ mod tests {
11961205

11971206
// do a noise handshake
11981207
let keypair = Keypair::generate();
1199-
let (stream, _peer) =
1200-
noise::handshake(stream.inner(), &keypair, Role::Listener, 5, 2).await.unwrap();
1208+
let (stream, _peer) = noise::handshake(
1209+
stream.inner(),
1210+
&keypair,
1211+
Role::Listener,
1212+
5,
1213+
2,
1214+
std::time::Duration::from_secs(10),
1215+
)
1216+
.await
1217+
.unwrap();
12011218
let stream: NoiseSocket<Compat<TcpStream>> = stream;
12021219

12031220
// after the handshake, try to negotiate some random protocol instead of yamux
@@ -1262,8 +1279,16 @@ mod tests {
12621279

12631280
// do a noise handshake
12641281
let keypair = Keypair::generate();
1265-
let (stream, _peer) =
1266-
noise::handshake(stream.inner(), &keypair, Role::Dialer, 5, 2).await.unwrap();
1282+
let (stream, _peer) = noise::handshake(
1283+
stream.inner(),
1284+
&keypair,
1285+
Role::Dialer,
1286+
5,
1287+
2,
1288+
std::time::Duration::from_secs(10),
1289+
)
1290+
.await
1291+
.unwrap();
12671292
let _stream: NoiseSocket<Compat<TcpStream>> = stream;
12681293

12691294
tokio::time::sleep(std::time::Duration::from_secs(60)).await;
@@ -1307,8 +1332,16 @@ mod tests {
13071332

13081333
// do a noise handshake
13091334
let keypair = Keypair::generate();
1310-
let (stream, _peer) =
1311-
noise::handshake(stream.inner(), &keypair, Role::Listener, 5, 2).await.unwrap();
1335+
let (stream, _peer) = noise::handshake(
1336+
stream.inner(),
1337+
&keypair,
1338+
Role::Listener,
1339+
5,
1340+
2,
1341+
std::time::Duration::from_secs(10),
1342+
)
1343+
.await
1344+
.unwrap();
13121345
let _stream: NoiseSocket<Compat<TcpStream>> = stream;
13131346

13141347
tokio::time::sleep(std::time::Duration::from_secs(60)).await;

0 commit comments

Comments
 (0)