use bitcoin_hashes::sha256::Hash as Sha256;
use bitcoin_hashes::{Hash, HashEngine};
use secp256k1::{PublicKey, SecretKey};
use super::ceremony::{
Act, ActBuilder, ACT_ONE_LENGTH, ACT_THREE_LENGTH, ACT_TWO_LENGTH,
EMPTY_ACT_ONE, EMPTY_ACT_THREE, EMPTY_ACT_TWO,
};
use super::transcoder::{NoiseTranscoder, SymmetricKey};
use super::{chacha, hkdf};
use crate::noise::EncryptionError;
type ChainingKey = [u8; 32];
macro_rules! concat_then_sha256 {
( $( $x:expr ),+ ) => {{
let mut sha = Sha256::engine();
$(
sha.input($x.as_ref());
)+
Sha256::from_engine(sha)
}}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Display, Error, From)]
#[display(inner)]
pub enum HandshakeError {
#[from]
Other(String),
#[from]
#[from(chacha20poly1305::aead::Error)]
Encryption(EncryptionError),
#[from]
InvalidSecretKey(secp256k1::scalar::OutOfRangeError),
}
#[derive(Debug)]
pub enum HandshakeState<const LEN_SIZE: usize> {
InitiatorStarting(InitiatorStartingState),
ResponderAwaitingActOne(ResponderAwaitingActOneState),
InitiatorAwaitingActTwo(InitiatorAwaitingActTwoState),
ResponderAwaitingActThree(ResponderAwaitingActThreeState),
Complete(NoiseTranscoder<LEN_SIZE>),
}
impl<const LEN_SIZE: usize> HandshakeState<LEN_SIZE> {
pub fn new_initiator(
initiator_static_private_key: &SecretKey,
responder_static_public_key: &PublicKey,
initiator_ephemeral_private_key: &SecretKey,
) -> Self {
HandshakeState::InitiatorStarting(InitiatorStartingState::new(
*initiator_static_private_key,
*initiator_ephemeral_private_key,
*responder_static_public_key,
))
}
pub fn new_responder(
responder_static_private_key: &SecretKey,
responder_ephemeral_private_key: &SecretKey,
) -> Self {
HandshakeState::ResponderAwaitingActOne(
ResponderAwaitingActOneState::new(
*responder_static_private_key,
*responder_ephemeral_private_key,
),
)
}
pub fn next(
self,
input: &[u8],
) -> Result<(Option<Act>, HandshakeState<LEN_SIZE>), HandshakeError> {
match self {
HandshakeState::InitiatorStarting(state) => {
state.next::<LEN_SIZE>()
}
HandshakeState::ResponderAwaitingActOne(state) => {
state.next::<LEN_SIZE>(input)
}
HandshakeState::InitiatorAwaitingActTwo(state) => {
state.next::<LEN_SIZE>(input)
}
HandshakeState::ResponderAwaitingActThree(state) => {
state.next::<LEN_SIZE>(input)
}
HandshakeState::Complete(_conduit) => {
Err(HandshakeError::Other(String::from(
"Handshake State is Complete, nothing to process ",
)))
}
}
}
pub fn data_len(&self) -> usize {
match self {
HandshakeState::InitiatorStarting(_) => 50,
HandshakeState::ResponderAwaitingActOne(_) => 50,
HandshakeState::InitiatorAwaitingActTwo(_) => 50,
HandshakeState::ResponderAwaitingActThree(_) => 66,
HandshakeState::Complete(_) => 66,
}
}
}
#[derive(Debug)]
pub struct InitiatorStartingState {
initiator_static_private_key: SecretKey,
initiator_static_public_key: PublicKey,
initiator_ephemeral_private_key: SecretKey,
initiator_ephemeral_public_key: PublicKey,
responder_static_public_key: PublicKey,
chaining_key: Sha256,
hash: Sha256,
}
#[derive(Debug)]
pub struct ResponderAwaitingActOneState {
responder_static_private_key: SecretKey,
responder_ephemeral_private_key: SecretKey,
responder_ephemeral_public_key: PublicKey,
chaining_key: Sha256,
hash: Sha256,
act_one_builder: ActBuilder,
}
#[derive(Debug)]
pub struct InitiatorAwaitingActTwoState {
initiator_static_private_key: SecretKey,
initiator_static_public_key: PublicKey,
initiator_ephemeral_private_key: SecretKey,
responder_static_public_key: PublicKey,
chaining_key: ChainingKey,
hash: Sha256,
act_two_builder: ActBuilder,
}
#[derive(Debug)]
pub struct ResponderAwaitingActThreeState {
hash: Sha256,
responder_ephemeral_private_key: SecretKey,
chaining_key: ChainingKey,
temporary_key: [u8; 32],
act_three_builder: ActBuilder,
}
impl InitiatorStartingState {
pub fn new(
initiator_static_private_key: SecretKey,
initiator_ephemeral_private_key: SecretKey,
responder_static_public_key: PublicKey,
) -> Self {
let initiator_static_public_key =
private_key_to_public_key(&initiator_static_private_key);
let (hash, chaining_key) =
initialize_handshake_state(&responder_static_public_key);
let initiator_ephemeral_public_key =
private_key_to_public_key(&initiator_ephemeral_private_key);
InitiatorStartingState {
initiator_static_private_key,
initiator_static_public_key,
initiator_ephemeral_private_key,
initiator_ephemeral_public_key,
responder_static_public_key,
chaining_key,
hash,
}
}
pub fn next<const LEN_SIZE: usize>(
self,
) -> Result<(Option<Act>, HandshakeState<LEN_SIZE>), HandshakeError> {
let initiator_static_private_key = self.initiator_static_private_key;
let initiator_static_public_key = self.initiator_static_public_key;
let initiator_ephemeral_private_key =
self.initiator_ephemeral_private_key;
let initiator_ephemeral_public_key =
self.initiator_ephemeral_public_key;
let responder_static_public_key = self.responder_static_public_key;
let chaining_key = self.chaining_key;
let hash = self.hash;
let mut act_one = EMPTY_ACT_ONE;
let (hash, chaining_key, _) = calculate_act_message(
&initiator_ephemeral_private_key,
&initiator_ephemeral_public_key,
&responder_static_public_key,
chaining_key.into_inner(),
hash,
&mut act_one,
)?;
Ok((
Some(Act::One(act_one)),
HandshakeState::InitiatorAwaitingActTwo(
InitiatorAwaitingActTwoState {
initiator_static_private_key,
initiator_static_public_key,
initiator_ephemeral_private_key,
responder_static_public_key,
chaining_key,
hash,
act_two_builder: ActBuilder::new(Act::Two(EMPTY_ACT_TWO)),
},
),
))
}
}
impl ResponderAwaitingActOneState {
pub fn new(
responder_static_private_key: SecretKey,
responder_ephemeral_private_key: SecretKey,
) -> Self {
let responder_static_public_key =
private_key_to_public_key(&responder_static_private_key);
let (hash, chaining_key) =
initialize_handshake_state(&responder_static_public_key);
let responder_ephemeral_public_key =
private_key_to_public_key(&responder_ephemeral_private_key);
ResponderAwaitingActOneState {
responder_static_private_key,
responder_ephemeral_private_key,
responder_ephemeral_public_key,
chaining_key,
hash,
act_one_builder: ActBuilder::new(Act::One(EMPTY_ACT_ONE)),
}
}
pub fn next<const LEN_SIZE: usize>(
self,
input: &[u8],
) -> Result<(Option<Act>, HandshakeState<LEN_SIZE>), HandshakeError> {
let mut act_one_builder = self.act_one_builder;
let bytes_read = act_one_builder.fill(input);
if bytes_read < input.len() {
return Err(HandshakeError::Other("Act One too large".to_string()));
}
if !act_one_builder.is_finished() {
assert_eq!(bytes_read, input.len());
return Ok((
None,
HandshakeState::ResponderAwaitingActOne(Self {
responder_static_private_key: self
.responder_static_private_key,
responder_ephemeral_private_key: self
.responder_ephemeral_private_key,
responder_ephemeral_public_key: self
.responder_ephemeral_public_key,
chaining_key: self.chaining_key,
hash: self.hash,
act_one_builder,
}),
));
}
let hash = self.hash;
let responder_static_private_key = self.responder_static_private_key;
let chaining_key = self.chaining_key;
let responder_ephemeral_private_key =
self.responder_ephemeral_private_key;
let responder_ephemeral_public_key =
self.responder_ephemeral_public_key;
let act_one = Act::from(act_one_builder);
let (initiator_ephemeral_public_key, hash, chaining_key, _) =
process_act_message(
&act_one,
&responder_static_private_key,
chaining_key.into_inner(),
hash,
)?;
let mut act_two = EMPTY_ACT_TWO;
let (hash, chaining_key, temporary_key) = calculate_act_message(
&responder_ephemeral_private_key,
&responder_ephemeral_public_key,
&initiator_ephemeral_public_key,
chaining_key,
hash,
&mut act_two,
)?;
Ok((
Some(Act::Two(act_two)),
HandshakeState::ResponderAwaitingActThree(
ResponderAwaitingActThreeState {
hash,
responder_ephemeral_private_key,
chaining_key,
temporary_key,
act_three_builder: ActBuilder::new(Act::Three(
EMPTY_ACT_THREE,
)),
},
),
))
}
}
impl InitiatorAwaitingActTwoState {
pub fn next<const LEN_SIZE: usize>(
self,
input: &[u8],
) -> Result<(Option<Act>, HandshakeState<LEN_SIZE>), HandshakeError> {
let mut act_two_builder = self.act_two_builder;
let bytes_read = act_two_builder.fill(input);
if bytes_read < input.len() {
return Err(HandshakeError::Other("Act Two too large".to_string()));
}
if !act_two_builder.is_finished() {
assert_eq!(bytes_read, input.len());
return Ok((
None,
HandshakeState::InitiatorAwaitingActTwo(Self {
initiator_static_private_key: self
.initiator_static_private_key,
initiator_static_public_key: self
.initiator_static_public_key,
initiator_ephemeral_private_key: self
.initiator_ephemeral_private_key,
responder_static_public_key: self
.responder_static_public_key,
chaining_key: self.chaining_key,
hash: self.hash,
act_two_builder,
}),
));
}
let initiator_static_private_key = self.initiator_static_private_key;
let initiator_static_public_key = self.initiator_static_public_key;
let initiator_ephemeral_private_key =
self.initiator_ephemeral_private_key;
let responder_static_public_key = self.responder_static_public_key;
let hash = self.hash;
let chaining_key = self.chaining_key;
let act_two = Act::from(act_two_builder);
let (responder_ephemeral_public_key, hash, chaining_key, temporary_key) =
process_act_message(
&act_two,
&initiator_ephemeral_private_key,
chaining_key,
hash,
)?;
let mut act_three = EMPTY_ACT_THREE;
chacha::encrypt(
&temporary_key,
1,
&hash,
&initiator_static_public_key.serialize(),
&mut act_three[1..50],
)?;
let hash = concat_then_sha256!(hash, act_three[1..50]);
let ecdh = ecdh(
&initiator_static_private_key,
&responder_ephemeral_public_key,
)?;
let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh);
chacha::encrypt(
&temporary_key,
0,
&hash,
&[0; 0],
&mut act_three[50..],
)?;
let (sending_key, receiving_key) = hkdf::derive(&chaining_key, &[0; 0]);
let conduit = NoiseTranscoder::with(
sending_key,
receiving_key,
chaining_key,
responder_static_public_key,
);
act_three[0] = 0;
Ok((
Some(Act::Three(act_three)),
HandshakeState::Complete(conduit),
))
}
}
impl ResponderAwaitingActThreeState {
fn next<const LEN_SIZE: usize>(
self,
input: &[u8],
) -> Result<(Option<Act>, HandshakeState<LEN_SIZE>), HandshakeError> {
let mut act_three_builder = self.act_three_builder;
let bytes_read = act_three_builder.fill(input);
if !act_three_builder.is_finished() {
assert_eq!(bytes_read, input.len());
return Ok((
None,
HandshakeState::ResponderAwaitingActThree(Self {
hash: self.hash,
responder_ephemeral_private_key: self
.responder_ephemeral_private_key,
chaining_key: self.chaining_key,
temporary_key: self.temporary_key,
act_three_builder,
}),
));
}
let hash = self.hash;
let temporary_key = self.temporary_key;
let responder_ephemeral_private_key =
self.responder_ephemeral_private_key;
let chaining_key = self.chaining_key;
let act_three_bytes = Act::from(act_three_builder);
assert_eq!(act_three_bytes.len(), ACT_THREE_LENGTH);
let version = act_three_bytes[0];
let tagged_encrypted_pubkey = &act_three_bytes[1..50];
let chacha_tag = &act_three_bytes[50..];
if version != 0 {
return Err(HandshakeError::Other(
"unexpected version".to_string(),
));
}
let mut remote_pubkey = [0; 33];
chacha::decrypt(
&temporary_key,
1,
&hash,
tagged_encrypted_pubkey,
&mut remote_pubkey,
)?;
let initiator_pubkey =
if let Ok(public_key) = PublicKey::from_slice(&remote_pubkey) {
public_key
} else {
return Err(HandshakeError::Other(
"invalid remote public key".to_string(),
));
};
let hash = concat_then_sha256!(hash, tagged_encrypted_pubkey);
let ecdh = ecdh(&responder_ephemeral_private_key, &initiator_pubkey)?;
let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh);
chacha::decrypt(&temporary_key, 0, &hash, chacha_tag, &mut [0; 0])?;
let (receiving_key, sending_key) = hkdf::derive(&chaining_key, &[0; 0]);
let mut conduit = NoiseTranscoder::with(
sending_key,
receiving_key,
chaining_key,
initiator_pubkey,
);
conduit.read_buf(&input[bytes_read..]);
Ok((None, HandshakeState::Complete(conduit)))
}
}
fn initialize_handshake_state(
responder_static_public_key: &PublicKey,
) -> (Sha256, Sha256) {
let protocol_name = b"Noise_XK_secp256k1_ChaChaPoly_SHA256";
let prologue = b"lightning";
let chaining_key = concat_then_sha256!(protocol_name);
let hash = concat_then_sha256!(chaining_key, prologue);
let hash =
concat_then_sha256!(hash, responder_static_public_key.serialize());
(hash, chaining_key)
}
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],
) -> Result<(Sha256, SymmetricKey, SymmetricKey), HandshakeError> {
let serialized_local_public_key = local_public_ephemeral_key.serialize();
let hash = concat_then_sha256!(hash, serialized_local_public_key);
let ecdh = ecdh(local_private_ephemeral_key, remote_public_key)?;
let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh);
chacha::encrypt(&temporary_key, 0, &hash, &[0; 0], &mut act_out[34..])?;
let hash = concat_then_sha256!(hash, &act_out[34..]);
act_out[0] = 0;
act_out[1..34].copy_from_slice(&serialized_local_public_key);
Ok((hash, chaining_key, temporary_key))
}
fn process_act_message(
act_bytes: &[u8],
local_private_key: &SecretKey,
chaining_key: ChainingKey,
hash: Sha256,
) -> Result<(PublicKey, Sha256, SymmetricKey, SymmetricKey), HandshakeError> {
assert_eq!(act_bytes.len(), ACT_ONE_LENGTH);
assert_eq!(act_bytes.len(), ACT_TWO_LENGTH);
let version = act_bytes[0];
let ephemeral_public_key_bytes = &act_bytes[1..34];
let chacha_tag = &act_bytes[34..];
let ephemeral_public_key = if let Ok(public_key) =
PublicKey::from_slice(ephemeral_public_key_bytes)
{
public_key
} else {
return Err(HandshakeError::Other(
"invalid remote ephemeral public key".to_string(),
));
};
if version != 0 {
return Err(HandshakeError::Other("unexpected version".to_string()));
}
let hash = concat_then_sha256!(hash, ephemeral_public_key_bytes);
let ecdh = ecdh(local_private_key, &ephemeral_public_key)?;
let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh);
chacha::decrypt(&temporary_key, 0, &hash, chacha_tag, &mut [0; 0])?;
let hash = concat_then_sha256!(hash, chacha_tag);
Ok((ephemeral_public_key, hash, chaining_key, temporary_key))
}
fn private_key_to_public_key(private_key: &SecretKey) -> PublicKey {
let curve = secp256k1::Secp256k1::new();
PublicKey::from_secret_key(&curve, private_key)
}
fn ecdh(
private_key: &SecretKey,
public_key: &PublicKey,
) -> Result<SymmetricKey, secp256k1::scalar::OutOfRangeError> {
let curve = secp256k1::Secp256k1::new();
let scalar = secp256k1::Scalar::from_be_bytes(private_key.secret_bytes())?;
let preimage = public_key
.mul_tweak(&curve, &scalar)
.expect("invalid multiplication")
.serialize();
Ok(concat_then_sha256!(preimage).into_inner())
}
#[cfg(test)]
mod test {
use bitcoin_hashes::hex::{FromHex, ToHex};
use secp256k1::{PublicKey, SecretKey};
use super::HandshakeState::*;
use super::*;
struct TestCtx {
initiator: HandshakeState<2>,
initiator_public_key: PublicKey,
responder: HandshakeState<2>,
responder_static_public_key: PublicKey,
valid_act1: Vec<u8>,
valid_act2: Vec<u8>,
valid_act3: Vec<u8>,
}
impl TestCtx {
fn new() -> Self {
let curve = secp256k1::Secp256k1::new();
let initiator_static_private_key =
SecretKey::from_slice(&[0x_11_u8; 32]).unwrap();
let initiator_public_key = PublicKey::from_secret_key(
&curve,
&initiator_static_private_key,
);
let initiator_ephemeral_private_key =
SecretKey::from_slice(&[0x_12_u8; 32]).unwrap();
let responder_static_private_key =
SecretKey::from_slice(&[0x_21_u8; 32]).unwrap();
let responder_static_public_key = PublicKey::from_secret_key(
&curve,
&responder_static_private_key,
);
let responder_ephemeral_private_key =
SecretKey::from_slice(&[0x_22_u8; 32]).unwrap();
let initiator = InitiatorStartingState::new(
initiator_static_private_key,
initiator_ephemeral_private_key,
responder_static_public_key,
);
let responder = ResponderAwaitingActOneState::new(
responder_static_private_key,
responder_ephemeral_private_key,
);
TestCtx {
initiator: InitiatorStarting(initiator),
initiator_public_key,
responder: ResponderAwaitingActOne(responder),
responder_static_public_key,
valid_act1: Vec::<u8>::from_hex("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap(),
valid_act2: Vec::<u8>::from_hex("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap(),
valid_act3: Vec::<u8>::from_hex("00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba").unwrap()
}
}
}
macro_rules! do_next_or_panic {
($state:expr, $input:expr) => {
if let (Some(output_act), next_state) = $state.next($input).unwrap()
{
(output_act, next_state)
} else {
panic!();
}
};
}
macro_rules! assert_matches {
($e:expr, $state_match:pat) => {
match $e {
$state_match => (),
_ => panic!(),
}
};
}
#[test]
fn starting_to_awaiting_act_two() {
let test_ctx = TestCtx::new();
let (act1, awaiting_act_two_state) =
do_next_or_panic!(test_ctx.initiator, &[]);
assert_eq!(act1.as_ref(), test_ctx.valid_act1.as_slice());
assert_matches!(awaiting_act_two_state, InitiatorAwaitingActTwo(_));
}
#[test]
fn awaiting_act_one_to_awaiting_act_three() {
let test_ctx = TestCtx::new();
let (act2, awaiting_act_three_state) =
test_ctx.responder.next(&test_ctx.valid_act1).unwrap();
assert_eq!(act2.unwrap().as_ref(), test_ctx.valid_act2.as_slice());
assert_matches!(awaiting_act_three_state, ResponderAwaitingActThree(_));
}
#[test]
fn awaiting_act_one_to_awaiting_act_three_input_extra_bytes() {
let test_ctx = TestCtx::new();
let mut act1 = test_ctx.valid_act1;
act1.extend_from_slice(&[1]);
assert_eq!(
test_ctx.responder.next(&act1).err().unwrap(),
HandshakeError::Other(String::from("Act One too large"))
);
}
#[test]
fn awaiting_act_one_to_awaiting_act_three_segmented() {
let test_ctx = TestCtx::new();
let act1_partial1 = &test_ctx.valid_act1[..25];
let act1_partial2 = &test_ctx.valid_act1[25..];
let next_state = test_ctx.responder.next(act1_partial1).unwrap();
assert_matches!(next_state, (None, ResponderAwaitingActOne(_)));
assert_matches!(
next_state.1.next(act1_partial2).unwrap(),
(Some(_), ResponderAwaitingActThree(_))
);
}
#[test]
fn awaiting_act_one_to_awaiting_act_three_input_bad_version() {
let test_ctx = TestCtx::new();
let act1 = Vec::<u8>::from_hex("01036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap();
assert_eq!(
test_ctx.responder.next(&act1).err().unwrap(),
HandshakeError::Other(String::from("unexpected version"))
);
}
#[test]
fn awaiting_act_one_to_awaiting_act_three_invalid_remote_ephemeral_key() {
let test_ctx = TestCtx::new();
let act1 = Vec::<u8>::from_hex("00046360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap();
assert_eq!(
test_ctx.responder.next(&act1).err().unwrap(),
HandshakeError::Other(String::from(
"invalid remote ephemeral public key"
))
);
}
#[test]
fn awaiting_act_one_to_awaiting_act_three_invalid_hmac() {
let test_ctx = TestCtx::new();
let act1 = Vec::<u8>::from_hex("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6b").unwrap();
assert_eq!(
test_ctx.responder.next(&act1).err().unwrap(),
HandshakeError::Encryption(chacha20poly1305::aead::Error.into())
);
}
#[test]
fn awaiting_act_two_to_complete_extra_bytes() {
let test_ctx = TestCtx::new();
let (_act1, awaiting_act_two_state) =
do_next_or_panic!(test_ctx.initiator, &[]);
let mut act2 = test_ctx.valid_act2;
act2.extend_from_slice(&[1]);
assert_eq!(
awaiting_act_two_state.next(&act2).err().unwrap(),
HandshakeError::Other(String::from("Act Two too large"))
);
}
#[test]
fn awaiting_act_two_to_complete() {
let test_ctx = TestCtx::new();
let (_act1, awaiting_act_two_state) =
do_next_or_panic!(test_ctx.initiator, &[]);
let (act3, complete_state) =
do_next_or_panic!(awaiting_act_two_state, &test_ctx.valid_act2);
let transcoder = if let Complete(transcoder) = complete_state {
transcoder
} else {
panic!();
};
assert_eq!(act3.as_ref(), test_ctx.valid_act3.as_slice());
assert_eq!(
transcoder.remote_pubkey(),
test_ctx.responder_static_public_key
);
assert_eq!(0, transcoder.decryptor.read_buffer_length());
}
#[test]
fn awaiting_act_two_to_complete_segmented() {
let test_ctx = TestCtx::new();
let (_act1, awaiting_act_two_state) =
do_next_or_panic!(test_ctx.initiator, &[]);
let act2_partial1 = &test_ctx.valid_act2[..25];
let act2_partial2 = &test_ctx.valid_act2[25..];
let next_state = awaiting_act_two_state.next(act2_partial1).unwrap();
assert_matches!(next_state, (None, InitiatorAwaitingActTwo(_)));
assert_matches!(
next_state.1.next(act2_partial2).unwrap(),
(Some(_), Complete(_))
);
}
#[test]
fn awaiting_act_two_bad_version_byte() {
let test_ctx = TestCtx::new();
let (_act1, awaiting_act_two_state) =
do_next_or_panic!(test_ctx.initiator, &[]);
let act2 = Vec::<u8>::from_hex("0102466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap();
assert_eq!(
awaiting_act_two_state.next(&act2).err().unwrap(),
HandshakeError::Other(String::from("unexpected version"))
);
}
#[test]
fn awaiting_act_two_invalid_ephemeral_public_key() {
let test_ctx = TestCtx::new();
let (_act1, awaiting_act_two_state) =
do_next_or_panic!(test_ctx.initiator, &[]);
let act2 = Vec::<u8>::from_hex("0004466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap();
assert_eq!(
awaiting_act_two_state.next(&act2).err().unwrap(),
HandshakeError::Other(String::from(
"invalid remote ephemeral public key"
))
);
}
#[test]
fn awaiting_act_two_invalid_hmac() {
let test_ctx = TestCtx::new();
let (_act1, awaiting_act_two_state) =
do_next_or_panic!(test_ctx.initiator, &[]);
let act2 = Vec::<u8>::from_hex("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730af").unwrap();
assert_eq!(
awaiting_act_two_state.next(&act2).err().unwrap(),
HandshakeError::Encryption(chacha20poly1305::aead::Error.into())
);
}
#[test]
fn awaiting_act_three_to_complete() {
let test_ctx = TestCtx::new();
let (_act2, awaiting_act_three_state) =
do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1);
let transcoder = if let (None, Complete(transcoder)) =
awaiting_act_three_state.next(&test_ctx.valid_act3).unwrap()
{
transcoder
} else {
panic!();
};
assert_eq!(transcoder.remote_pubkey(), test_ctx.initiator_public_key);
assert_eq!(0, transcoder.decryptor.read_buffer_length());
}
#[test]
fn awaiting_act_three_excess_bytes_after_complete_are_in_conduit() {
let test_ctx = TestCtx::new();
let (_act2, awaiting_act_three_state) =
do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1);
let mut act3 = test_ctx.valid_act3;
act3.extend_from_slice(&[2; 100]);
let conduit = if let (None, Complete(conduit)) =
awaiting_act_three_state.next(&act3).unwrap()
{
conduit
} else {
panic!();
};
assert_eq!(conduit.remote_pubkey(), test_ctx.initiator_public_key);
assert_eq!(100, conduit.decryptor.read_buffer_length());
}
#[test]
fn awaiting_act_three_bad_version_bytes() {
let test_ctx = TestCtx::new();
let (_act2, awaiting_act_three_state) =
do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1);
let act3 = Vec::<u8>::from_hex("01b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba").unwrap();
assert_eq!(
awaiting_act_three_state.next(&act3).err().unwrap(),
HandshakeError::Other(String::from("unexpected version"))
);
}
#[test]
fn awaiting_act_three_to_complete_segmented() {
let test_ctx = TestCtx::new();
let (_act2, awaiting_act_three_state) =
do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1);
let act3_partial1 = &test_ctx.valid_act3[..35];
let act3_partial2 = &test_ctx.valid_act3[35..];
let next_state = awaiting_act_three_state.next(act3_partial1).unwrap();
assert_matches!(next_state, (None, ResponderAwaitingActThree(_)));
assert_matches!(
next_state.1.next(act3_partial2),
Ok((None, Complete(_)))
);
}
#[test]
fn awaiting_act_three_invalid_hmac() {
let test_ctx = TestCtx::new();
let (_act2, awaiting_act_three_state) =
do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1);
let act3 = Vec::<u8>::from_hex("00c9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba").unwrap();
assert_eq!(
awaiting_act_three_state.next(&act3).err().unwrap(),
HandshakeError::Encryption(chacha20poly1305::aead::Error.into())
);
}
#[test]
fn awaiting_act_three_invalid_rs() {
let test_ctx = TestCtx::new();
let (_act2, awaiting_act_three_state) =
do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1);
let act3 = Vec::<u8>::from_hex("00bfe3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa2235536ad09a8ee351870c2bb7f78b754a26c6cef79a98d25139c856d7efd252c2ae73c").unwrap();
assert_eq!(
awaiting_act_three_state.next(&act3).err().unwrap(),
HandshakeError::Other(String::from("invalid remote public key"))
);
}
#[test]
fn awaiting_act_three_invalid_tag_hmac() {
let test_ctx = TestCtx::new();
let (_act2, awaiting_act_three_state) =
do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1);
let act3 = Vec::<u8>::from_hex("00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139bb").unwrap();
assert_eq!(
awaiting_act_three_state.next(&act3).err().unwrap(),
HandshakeError::Encryption(chacha20poly1305::aead::Error.into())
);
}
#[test]
#[should_panic(expected = "nothing to process")]
fn initiator_complete_next_fail() {
let test_ctx = TestCtx::new();
let (act1, awaiting_act_two_state) =
do_next_or_panic!(test_ctx.initiator, &[]);
let (act2, _awaiting_act_three_state) =
do_next_or_panic!(test_ctx.responder, &act1);
let (_act3, complete_state) =
do_next_or_panic!(awaiting_act_two_state, &act2);
complete_state.next(&[]).unwrap();
}
#[test]
#[should_panic(expected = "nothing to process")]
fn responder_complete_next_fail() {
let test_ctx = TestCtx::new();
let (act1, awaiting_act_two_state) =
do_next_or_panic!(test_ctx.initiator, &[]);
let (act2, awaiting_act_three_state) =
do_next_or_panic!(test_ctx.responder, &act1);
let (act3, _complete_state) =
do_next_or_panic!(awaiting_act_two_state, &act2);
let complete_state = if let (None, complete_state) =
awaiting_act_three_state.next(&act3).unwrap()
{
complete_state
} else {
panic!();
};
complete_state.next(&[]).unwrap();
}
#[test]
fn test_acts_against_reference_bytes() {
let test_ctx = TestCtx::new();
let (act1, awaiting_act_two_state) =
do_next_or_panic!(test_ctx.initiator, &[]);
let (act2, _awaiting_act_three_state) =
do_next_or_panic!(test_ctx.responder, &act1);
let (act3, _complete_state) =
do_next_or_panic!(awaiting_act_two_state, &act2);
assert_eq!(act1.as_ref().to_hex(),
"00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a");
assert_eq!(act2.as_ref().to_hex(),
"0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae");
assert_eq!(act3.as_ref().to_hex(),
"00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba");
}
}