Skip to content

Commit 81bf5fb

Browse files
committed
feature: Tighten the constraints for act message sizes
Proper handshake peers won't send more bytes than required for act1 and act2 and it is impossible to generate future acts without first receiving an interleaved response. In those cases, the peer is misbehaving and we can fail early. This unlocks a Vec-less design in the handshake code now that there is an upper limit on read buffer sizes.
1 parent e436255 commit 81bf5fb

File tree

1 file changed

+29
-37
lines changed

1 file changed

+29
-37
lines changed

lightning/src/ln/peers/handshake/states.rs

Lines changed: 29 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,12 @@ impl IHandshakeState for ResponderAwaitingActOneState {
181181
let mut read_buffer = self.read_buffer;
182182
read_buffer.extend_from_slice(input);
183183

184+
// Any payload larger than ACT_ONE_TWO_LENGTH indicates a bad peer since initiator data
185+
// is required to generate act3 (so it can't come before we transition)
186+
if read_buffer.len() > ACT_ONE_TWO_LENGTH {
187+
return Err("Act One too large".to_string());
188+
}
189+
184190
// In the event of a partial fill, stay in the same state and wait for more data
185191
if read_buffer.len() < ACT_ONE_TWO_LENGTH {
186192
return Ok((
@@ -238,6 +244,12 @@ impl IHandshakeState for InitiatorAwaitingActTwoState {
238244
let mut read_buffer = self.read_buffer;
239245
read_buffer.extend_from_slice(input);
240246

247+
// Any payload larger than ACT_ONE_TWO_LENGTH indicates a bad peer since responder data
248+
// is required to generate post-authentication messages (so it can't come before we transition)
249+
if read_buffer.len() > ACT_ONE_TWO_LENGTH {
250+
return Err("Act Two too large".to_string());
251+
}
252+
241253
// In the event of a partial fill, stay in the same state and wait for more data
242254
if read_buffer.len() < ACT_ONE_TWO_LENGTH {
243255
return Ok((
@@ -289,7 +301,7 @@ impl IHandshakeState for InitiatorAwaitingActTwoState {
289301

290302
// 7. rn = 0, sn = 0
291303
// - done by Conduit
292-
let mut conduit = Conduit::new(sending_key, receiving_key, chaining_key);
304+
let conduit = Conduit::new(sending_key, receiving_key, chaining_key);
293305

294306
// Send m = 0 || c || t over the network buffer
295307
let mut act_three = Vec::with_capacity(ACT_THREE_LENGTH);
@@ -298,14 +310,6 @@ impl IHandshakeState for InitiatorAwaitingActTwoState {
298310
act_three.extend(&authentication_tag);
299311
assert_eq!(act_three.len(), ACT_THREE_LENGTH);
300312

301-
// Any remaining data in the read buffer would be encrypted, so transfer ownership
302-
// to the Conduit for future use. In this case, it is unlikely that any valid data
303-
// exists, since the responder doesn't have Act3
304-
if read_buffer.len() > 0 {
305-
conduit.read(&read_buffer[..]);
306-
read_buffer.drain(..);
307-
}
308-
309313
Ok((
310314
Some(act_three),
311315
HandshakeState::Complete(Some((conduit, responder_static_public_key)))
@@ -600,18 +604,16 @@ mod test {
600604
assert_matches!(awaiting_act_three_state, ResponderAwaitingActThree(_));
601605
}
602606

603-
// Responder::AwaitingActOne -> AwaitingActThree
604-
// TODO: Should this fail since we don't expect data > ACT_ONE_TWO_LENGTH and likely indicates
605-
// a bad peer?
607+
// Responder::AwaitingActOne -> AwaitingActThree (bad peer)
608+
// Act2 requires data from the initiator. If we receive a payload for act1 that is larger than
609+
// expected it indicates a bad peer
606610
#[test]
607611
fn awaiting_act_one_to_awaiting_act_three_input_extra_bytes() {
608612
let test_ctx = TestCtx::new();
609613
let mut act1 = test_ctx.valid_act1;
610614
act1.extend_from_slice(&[1]);
611-
let (act2, awaiting_act_three_state) = test_ctx.responder.next(&act1).unwrap();
612615

613-
assert_eq!(act2.unwrap(), test_ctx.valid_act2);
614-
assert_matches!(awaiting_act_three_state, ResponderAwaitingActThree(_));
616+
assert_eq!(test_ctx.responder.next(&act1).err(), Some(String::from("Act One too large")));
615617
}
616618

617619
// Responder::AwaitingActOne -> AwaitingActThree (segmented calls)
@@ -658,36 +660,26 @@ mod test {
658660
assert_eq!(test_ctx.responder.next(&act1).err(), Some(String::from("invalid hmac")));
659661
}
660662

661-
// Initiator::AwaitingActTwo -> Complete
662-
// RFC test vector: transport-initiator successful handshake
663+
// Initiator::AwaitingActTwo -> Complete (bad peer)
664+
// Initiator data is required to generate post-authentication messages. This means any extra
665+
// data indicates a bad peer.
663666
#[test]
664-
fn awaiting_act_two_to_complete() {
667+
fn awaiting_act_two_to_complete_extra_bytes() {
665668
let test_ctx = TestCtx::new();
666669
let (_act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]);
667-
let (act3, complete_state) = do_next_or_panic!(awaiting_act_two_state, &test_ctx.valid_act2);
668-
669-
let (conduit, remote_pubkey) = if let Complete(Some((conduit, remote_pubkey))) = complete_state {
670-
(conduit, remote_pubkey)
671-
} else {
672-
panic!();
673-
};
670+
let mut act2 = test_ctx.valid_act2;
671+
act2.extend_from_slice(&[1]);
674672

675-
assert_eq!(act3, test_ctx.valid_act3);
676-
assert_eq!(remote_pubkey, test_ctx.responder_static_public_key);
677-
assert_eq!(0, conduit.decryptor.read_buffer_length());
673+
assert_eq!(awaiting_act_two_state.next(&act2).err(), Some(String::from("Act Two too large")));
678674
}
679675

680-
// Initiator::AwaitingActTwo -> Complete (with extra data)
681-
// Ensures that any remaining data in the read buffer is transferred to the conduit once
682-
// the handshake is complete
683-
// TODO: Is this valid? Don't we expect peers to need ActThree before sending additional data?
676+
// Initiator::AwaitingActTwo -> Complete
677+
// RFC test vector: transport-initiator successful handshake
684678
#[test]
685-
fn awaiting_act_two_to_complete_excess_bytes_are_in_conduit() {
679+
fn awaiting_act_two_to_complete() {
686680
let test_ctx = TestCtx::new();
687681
let (_act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]);
688-
let mut act2 = test_ctx.valid_act2;
689-
act2.extend_from_slice(&[1; 100]);
690-
let (act3, complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2);
682+
let (act3, complete_state) = do_next_or_panic!(awaiting_act_two_state, &test_ctx.valid_act2);
691683

692684
let (conduit, remote_pubkey) = if let Complete(Some((conduit, remote_pubkey))) = complete_state {
693685
(conduit, remote_pubkey)
@@ -697,7 +689,7 @@ mod test {
697689

698690
assert_eq!(act3, test_ctx.valid_act3);
699691
assert_eq!(remote_pubkey, test_ctx.responder_static_public_key);
700-
assert_eq!(100, conduit.decryptor.read_buffer_length());
692+
assert_eq!(0, conduit.decryptor.read_buffer_length());
701693
}
702694

703695
// Initiator::AwaitingActTwo -> Complete (segmented calls)

0 commit comments

Comments
 (0)