Skip to content

Commit 461facb

Browse files
committed
review: Non-controversial renames, nits, small fixups
Clean up small items based on review comments that are expected to be non-controversial so they can all go in one commit.
1 parent 564c820 commit 461facb

File tree

6 files changed

+90
-67
lines changed

6 files changed

+90
-67
lines changed

fuzz/src/peer_crypt.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ struct TestCtx {
8585
}
8686

8787
impl TestCtx {
88+
// At the completion of this call each handshake has the following state:
89+
// initiator_handshake: HandshakeState::InitiatorStarting
90+
// responder_handshake: HandshakeState::ResponderAwaitingActOne
8891
fn make(generator: &mut FuzzGen) -> Result<Self, GeneratorFinishedError> {
8992
let curve = secp256k1::Secp256k1::new();
9093

@@ -98,6 +101,14 @@ impl TestCtx {
98101

99102
let mut initiator_handshake = PeerHandshake::new_outbound(&initiator_static_private_key, &responder_static_public_key, &initiator_ephemeral_private_key);
100103
let act1 = initiator_handshake.set_up_outbound();
104+
105+
// Sanity checks around initialization to catch errors before we get to the fuzzing
106+
107+
// act 1 is the correct size
108+
assert_eq!(act1.len(), 50);
109+
110+
// act 1 has the correct version
111+
assert_eq!(act1[0], 0);
101112
let responder_handshake = PeerHandshake::new_inbound(&responder_static_private_key, &responder_ephemeral_private_key);
102113

103114
Ok(TestCtx {
@@ -146,8 +157,8 @@ fn do_conduit_tests(generator: &mut FuzzGen, initiator_conduit: &mut Conduit, re
146157
}
147158
}
148159

149-
// This test completes a valid handshake based on "random" private keys and then sends variable
150-
// length encrypted messages between two conduits to validate that they can communicate.
160+
// This test completes a valid handshake based on fuzzer-provided private keys and then sends
161+
// variable length encrypted messages between two conduits to validate that they can communicate.
151162
#[inline]
152163
fn do_completed_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorFinishedError> {
153164
let mut test_ctx = TestCtx::make(generator)?;

lightning/src/ln/peers/handler.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,17 +149,17 @@ impl PeerState {
149149
},
150150
// Otherwise, handshake may or may not be complete depending on whether or not
151151
// we receive a (conduit, pubkey)
152-
Ok((response_vec_opt, conduit_and_remote_pubkey_opt)) => {
152+
Ok((response_vec_option, conduit_and_remote_static_public_key_option)) => {
153153

154154
// Any response generated by the handshake sequence is put into the response buffer
155-
if let Some(response_vec) = response_vec_opt {
155+
if let Some(response_vec) = response_vec_option {
156156
mutable_response_buffer.push_back(response_vec);
157157
}
158158

159-
// if process_act() returns the conduit and remote_pubkey the handshake
160-
// is complete
161-
if let Some((conduit, remote_pubkey)) = conduit_and_remote_pubkey_opt {
162-
(Some(PeerState::Connected(conduit)), PeerDataProcessingDecision::CompleteHandshake(remote_pubkey))
159+
// if process_act() returns the conduit and remote static public key (node id)
160+
// the handshake is complete
161+
if let Some((conduit, remote_static_public_key)) = conduit_and_remote_static_public_key_option {
162+
(Some(PeerState::Connected(conduit)), PeerDataProcessingDecision::CompleteHandshake(remote_static_public_key))
163163
} else {
164164
(None, PeerDataProcessingDecision::Continue)
165165
}

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

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
66
use std::{cmp, ops};
77

8-
pub const ACT_ONE_TWO_LENGTH: usize = 50;
8+
pub const ACT_ONE_LENGTH: usize = 50;
9+
pub const ACT_TWO_LENGTH: usize = 50;
910
pub const ACT_THREE_LENGTH: usize = 66;
10-
pub const EMPTY_ACT_ONE: ActOne = [0; ACT_ONE_TWO_LENGTH];
11-
pub const EMPTY_ACT_TWO: ActTwo = EMPTY_ACT_ONE;
11+
pub const EMPTY_ACT_ONE: ActOne = [0; ACT_ONE_LENGTH];
12+
pub const EMPTY_ACT_TWO: ActTwo = [0; ACT_TWO_LENGTH];
1213
pub const EMPTY_ACT_THREE: ActThree = [0; ACT_THREE_LENGTH];
13-
type ActOne = [u8; ACT_ONE_TWO_LENGTH];
14-
type ActTwo = ActOne;
14+
type ActOne = [u8; ACT_ONE_LENGTH];
15+
type ActTwo = [u8; ACT_TWO_LENGTH];
1516
type ActThree = [u8; ACT_THREE_LENGTH];
1617

1718
/// Wrapper for any act message
@@ -64,19 +65,6 @@ impl AsRef<[u8]> for Act {
6465
}
6566
}
6667

67-
// Simple fill implementation for both almost-identical structs to deduplicate code
68-
// $act: Act[One|Two|Three], $input: &[u8]; returns &[u8] of remaining input that was not processed
69-
macro_rules! fill_impl {
70-
($act:expr, $write_pos:expr, $input:expr) => {{
71-
let fill_amount = cmp::min($act.len() - $write_pos, $input.len());
72-
73-
$act[$write_pos..$write_pos + fill_amount].copy_from_slice(&$input[..fill_amount]);
74-
75-
$write_pos += fill_amount;
76-
&$input[fill_amount..]
77-
}}
78-
}
79-
8068
/// Light wrapper around an Act that allows multiple fill() calls before finally
8169
/// converting to an Act via Act::from(act_builder). Handles all of the bookkeeping
8270
/// and edge cases of the array fill
@@ -96,15 +84,28 @@ impl ActBuilder {
9684

9785
/// Fills the Act with bytes from input and returns the unprocessed bytes
9886
pub(super) fn fill<'a>(&mut self, input: &'a [u8]) -> &'a [u8] {
87+
// Simple fill implementation for both almost-identical structs to deduplicate code
88+
// $act: Act[One|Two|Three], $input: &[u8]; returns &[u8] of remaining input that was not processed
89+
macro_rules! fill_act_content {
90+
($act:expr, $write_pos:expr, $input:expr) => {{
91+
let fill_amount = cmp::min($act.len() - $write_pos, $input.len());
92+
93+
$act[$write_pos..$write_pos + fill_amount].copy_from_slice(&$input[..fill_amount]);
94+
95+
$write_pos += fill_amount;
96+
&$input[fill_amount..]
97+
}}
98+
}
99+
99100
match &mut self.partial_act {
100101
&mut Act::One(ref mut act) => {
101-
fill_impl!(act, self.write_pos, input)
102+
fill_act_content!(act, self.write_pos, input)
102103
}
103104
&mut Act::Two(ref mut act) => {
104-
fill_impl!(act, self.write_pos, input)
105+
fill_act_content!(act, self.write_pos, input)
105106
}
106107
&mut Act::Three(ref mut act) => {
107-
fill_impl!(act, self.write_pos, input)
108+
fill_act_content!(act, self.write_pos, input)
108109
}
109110
}
110111
}
@@ -125,7 +126,7 @@ mod tests {
125126
let mut builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE));
126127

127128
let remaining = builder.fill(&[1, 2, 3]);
128-
assert_eq!(builder.partial_act.len(), ACT_ONE_TWO_LENGTH);
129+
assert_eq!(builder.partial_act.len(), ACT_ONE_LENGTH);
129130
assert_eq!(builder.write_pos, 3);
130131
assert!(!builder.is_finished());
131132
assert_eq!(remaining, &[]);
@@ -138,8 +139,8 @@ mod tests {
138139

139140
let input = [0; 50];
140141
let remaining = builder.fill(&input);
141-
assert_eq!(builder.partial_act.len(), ACT_ONE_TWO_LENGTH);
142-
assert_eq!(builder.write_pos, ACT_ONE_TWO_LENGTH);
142+
assert_eq!(builder.partial_act.len(), ACT_ONE_LENGTH);
143+
assert_eq!(builder.write_pos, ACT_ONE_LENGTH);
143144
assert!(builder.is_finished());
144145
assert_eq!(Act::from(builder).as_ref(), &input[..]);
145146
assert_eq!(remaining, &[]);
@@ -153,16 +154,16 @@ mod tests {
153154
let input = [0; 51];
154155
let remaining = builder.fill(&input);
155156

156-
assert_eq!(builder.partial_act.len(), ACT_ONE_TWO_LENGTH);
157-
assert_eq!(builder.write_pos, ACT_ONE_TWO_LENGTH);
157+
assert_eq!(builder.partial_act.len(), ACT_ONE_LENGTH);
158+
assert_eq!(builder.write_pos, ACT_ONE_LENGTH);
158159
assert!(builder.is_finished());
159160
assert_eq!(Act::from(builder).as_ref(), &input[..50]);
160161
assert_eq!(remaining, &[0]);
161162
}
162163

163164
// Converting an unfinished ActBuilder panics
164165
#[test]
165-
#[should_panic(expected="as")]
166+
#[should_panic(expected="assertion failed: act_builder.is_finished()")]
166167
fn convert_not_finished_panics() {
167168
let builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE));
168169
let _should_panic = Act::from(builder);

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

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,40 +14,39 @@ mod states;
1414
/// Currently requires explicit ephemeral private key specification.
1515
pub struct PeerHandshake {
1616
state: Option<HandshakeState>,
17-
ready_for_process: bool
17+
ready_to_process: bool,
1818
}
1919

2020
impl PeerHandshake {
21-
/// Instantiate a new handshake with a node identity secret key and an ephemeral private key
21+
/// Instantiate a handshake given the peer's static public key. The ephemeral private key MUST
22+
/// generate a new session with strong cryptographic randomness.
2223
pub fn new_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self {
2324
let state = HandshakeState::new_initiator(initiator_static_private_key, responder_static_public_key, initiator_ephemeral_private_key);
2425

2526
Self {
2627
state: Some(state),
27-
ready_for_process: false
28+
ready_to_process: false,
2829
}
2930
}
3031

31-
/// Instantiate a new handshake in anticipation of a peer's first handshake act
32+
/// Instantiate a handshake in anticipation of a peer's first handshake act
3233
pub fn new_inbound(responder_static_private_key: &SecretKey, responder_ephemeral_private_key: &SecretKey) -> Self {
3334
Self {
3435
state: Some(HandshakeState::new_responder(responder_static_private_key, responder_ephemeral_private_key)),
35-
ready_for_process: true
36+
ready_to_process: true,
3637
}
3738
}
3839

3940
/// Initializes the outbound handshake and provides the initial bytes to send to the responder
4041
pub fn set_up_outbound(&mut self) -> Vec<u8> {
41-
assert!(!self.ready_for_process);
42-
let cur_state = self.state.take().unwrap();
42+
assert!(!self.ready_to_process);
43+
self.ready_to_process = true;
4344

4445
// This transition does not have a failure path
45-
let (response_vec_opt, next_state) = cur_state.next(&[]).unwrap();
46-
47-
self.state = Some(next_state);
46+
let (response_vec_option, conduit_and_remote_static_public_key_option) = self.process_act(&[]).unwrap();
47+
assert!(conduit_and_remote_static_public_key_option.is_none());
4848

49-
self.ready_for_process = true;
50-
response_vec_opt.unwrap().to_vec()
49+
response_vec_option.unwrap()
5150
}
5251

5352
/// Process act dynamically
@@ -59,21 +58,19 @@ impl PeerHandshake {
5958
/// `.0`: Byte vector containing the next act to send back to the peer per the handshake protocol
6059
/// `.1`: Some(Conduit, PublicKey) if the handshake was just processed to completion and messages can now be encrypted and decrypted
6160
pub fn process_act(&mut self, input: &[u8]) -> Result<(Option<Vec<u8>>, Option<(Conduit, PublicKey)>), String> {
62-
assert!(self.ready_for_process);
61+
assert!(self.ready_to_process);
6362
let cur_state = self.state.take().unwrap();
6463

65-
// Convert the Act to a Vec before passing it back. Next patch removes this in favor
66-
// of passing back a slice.
67-
let (act_opt, mut next_state) = match cur_state.next(input)? {
64+
let (act_option, mut next_state) = match cur_state.next(input)? {
6865
(Some(act), next_state) => (Some(act.to_vec()), next_state),
6966
(None, next_state) => (None, next_state)
7067
};
7168

7269
let result = match next_state {
7370
HandshakeState::Complete(ref mut conduit_and_pubkey) => {
74-
Ok((act_opt, conduit_and_pubkey.take()))
71+
Ok((act_option, conduit_and_pubkey.take()))
7572
},
76-
_ => { Ok((act_opt, None)) }
73+
_ => { Ok((act_option, None)) }
7774
};
7875

7976
self.state = Some(next_state);
@@ -140,7 +137,7 @@ mod test {
140137

141138
// Test that the outbound needs to call set_up_outbound() before process_act()
142139
#[test]
143-
#[should_panic(expected = "assertion failed: self.ready_for_process")]
140+
#[should_panic(expected = "assertion failed: self.ready_to_process")]
144141
fn new_outbound_no_set_up_panics() {
145142
let curve = secp256k1::Secp256k1::new();
146143

@@ -155,7 +152,7 @@ mod test {
155152

156153
// Test that calling set_up_outbound() on the inbound panics
157154
#[test]
158-
#[should_panic(expected = "assertion failed: !self.ready_for_process")]
155+
#[should_panic(expected = "assertion failed: !self.ready_to_process")]
159156
fn new_inbound_calling_set_up_panics() {
160157
let inbound_static_private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap();
161158
let inbound_ephemeral_private_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap();

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

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use bitcoin::secp256k1::{SecretKey, PublicKey};
66

77
use ln::peers::{chacha, hkdf};
88
use ln::peers::conduit::{Conduit, SymmetricKey};
9-
use ln::peers::handshake::acts::{Act, ActBuilder, EMPTY_ACT_ONE, EMPTY_ACT_TWO, EMPTY_ACT_THREE};
9+
use ln::peers::handshake::acts::{Act, ActBuilder, ACT_ONE_LENGTH, ACT_TWO_LENGTH, ACT_THREE_LENGTH, EMPTY_ACT_ONE, EMPTY_ACT_TWO, EMPTY_ACT_THREE};
1010

11+
// Alias type to help differentiate between temporary key and chaining key when passing bytes around
1112
type ChainingKey = [u8; 32];
1213

1314
// Generate a SHA-256 hash from one or more elements concatenated together
@@ -30,7 +31,8 @@ pub(super) enum HandshakeState {
3031
}
3132

3233
// Trait for all individual states to implement that ensure HandshakeState::next() can
33-
// delegate to a common function signature.
34+
// delegate to a common function signature. May transition to the same state in the event there are
35+
// not yet enough bytes to move forward with the handshake.
3436
pub(super) trait IHandshakeState {
3537
fn next(self, input: &[u8]) -> Result<(Option<Act>, HandshakeState), String>;
3638
}
@@ -101,7 +103,7 @@ pub(super) struct ResponderAwaitingActThreeState {
101103
impl InitiatorStartingState {
102104
pub(crate) fn new(initiator_static_private_key: SecretKey, initiator_ephemeral_private_key: SecretKey, responder_static_public_key: PublicKey) -> Self {
103105
let initiator_static_public_key = private_key_to_public_key(&initiator_static_private_key);
104-
let (hash, chaining_key) = handshake_state_initialization(&responder_static_public_key);
106+
let (hash, chaining_key) = initialize_handshake_state(&responder_static_public_key);
105107
let initiator_ephemeral_public_key = private_key_to_public_key(&initiator_ephemeral_private_key);
106108
InitiatorStartingState {
107109
initiator_static_private_key,
@@ -160,7 +162,7 @@ impl IHandshakeState for InitiatorStartingState {
160162
impl ResponderAwaitingActOneState {
161163
pub(crate) fn new(responder_static_private_key: SecretKey, responder_ephemeral_private_key: SecretKey) -> Self {
162164
let responder_static_public_key = private_key_to_public_key(&responder_static_private_key);
163-
let (hash, chaining_key) = handshake_state_initialization(&responder_static_public_key);
165+
let (hash, chaining_key) = initialize_handshake_state(&responder_static_public_key);
164166
let responder_ephemeral_public_key = private_key_to_public_key(&responder_ephemeral_private_key);
165167

166168
ResponderAwaitingActOneState {
@@ -181,7 +183,7 @@ impl IHandshakeState for ResponderAwaitingActOneState {
181183
let mut act_one_builder = self.act_one_builder;
182184
let remaining = act_one_builder.fill(input);
183185

184-
// Any payload larger than ACT_ONE_TWO_LENGTH indicates a bad peer since initiator data
186+
// Any payload larger than ACT_ONE_LENGTH indicates a bad peer since initiator data
185187
// is required to generate act3 (so it can't come before we transition)
186188
if remaining.len() != 0 {
187189
return Err("Act One too large".to_string());
@@ -247,7 +249,7 @@ impl IHandshakeState for InitiatorAwaitingActTwoState {
247249
let mut act_two_builder = self.act_two_builder;
248250
let remaining = act_two_builder.fill(input);
249251

250-
// Any payload larger than ACT_ONE_TWO_LENGTH indicates a bad peer since responder data
252+
// Any payload larger than ACT_TWO_LENGTH indicates a bad peer since responder data
251253
// is required to generate post-authentication messages (so it can't come before we transition)
252254
if remaining.len() != 0 {
253255
return Err("Act Two too large".to_string());
@@ -310,6 +312,7 @@ impl IHandshakeState for InitiatorAwaitingActTwoState {
310312
// - done by Conduit
311313
let conduit = Conduit::new(sending_key, receiving_key, chaining_key);
312314

315+
// 8. Send m = 0 || c || t
313316
Ok((
314317
Some(Act::Three(act_three)),
315318
HandshakeState::Complete(Some((conduit, responder_static_public_key)))
@@ -345,6 +348,7 @@ impl IHandshakeState for ResponderAwaitingActThreeState {
345348

346349
// 1. Read exactly 66 bytes from the network buffer
347350
let act_three_bytes = Act::from(act_three_builder);
351+
assert_eq!(act_three_bytes.len(), ACT_THREE_LENGTH);
348352

349353
// 2. Parse the read message (m) into v, c, and t
350354
let version = act_three_bytes[0];
@@ -396,8 +400,11 @@ impl IHandshakeState for ResponderAwaitingActThreeState {
396400
}
397401
}
398402

403+
// The handshake state always uses the responder's static public key. When running on the initiator,
404+
// the initiator provides the remote's static public key and running on the responder they provide
405+
// their own.
399406
// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#handshake-state-initialization
400-
fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (Sha256, Sha256) {
407+
fn initialize_handshake_state(responder_static_public_key: &PublicKey) -> (Sha256, Sha256) {
401408
let protocol_name = b"Noise_XK_secp256k1_ChaChaPoly_SHA256";
402409
let prologue = b"lightning";
403410

@@ -414,6 +421,7 @@ fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (S
414421
(hash, chaining_key)
415422
}
416423

424+
// Due to the very high similarity of acts 1 and 2, this method is used to process both
417425
// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender)
418426
// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender)
419427
fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: ChainingKey, hash: Sha256, act_out: &mut [u8]) -> (Sha256, SymmetricKey, SymmetricKey) {
@@ -448,6 +456,11 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_e
448456
// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (receiver)
449457
fn process_act_message(act_bytes: &[u8], local_private_key: &SecretKey, chaining_key: ChainingKey, hash: Sha256) -> Result<(PublicKey, Sha256, SymmetricKey, SymmetricKey), String> {
450458
// 1. Read exactly 50 bytes from the network buffer
459+
// Partial act messages are handled by the callers. By the time it gets here, it
460+
// must be the correct size.
461+
assert_eq!(act_bytes.len(), ACT_ONE_LENGTH);
462+
assert_eq!(act_bytes.len(), ACT_TWO_LENGTH);
463+
451464
// 2.Parse the read message (m) into v, re, and c
452465
let version = act_bytes[0];
453466
let ephemeral_public_key_bytes = &act_bytes[1..34];
@@ -476,7 +489,8 @@ fn process_act_message(act_bytes: &[u8], local_private_key: &SecretKey, chaining
476489
// 6. Act2: ck, temp_k2 = HKDF(ck, ee)
477490
let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh);
478491

479-
// 7. p = decryptWithAD(temp_k1, 0, h, c)
492+
// 7. Act1: p = decryptWithAD(temp_k1, 0, h, c)
493+
// 7. Act2: p = decryptWithAD(temp_k2, 0, h, c)
480494
chacha::decrypt(&temporary_key, 0, &hash, &chacha_tag, &mut [0; 0])?;
481495

482496
// 8. h = SHA-256(h || c)

0 commit comments

Comments
 (0)