Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fallback modifier #158

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/params/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,4 +309,18 @@ mod tests {
_ => panic!("missing token!"),
}
}

#[test]
fn test_xx_fallback_handshake() {
let p: NoiseParams = "Noise_XXfallback_25519_AESGCM_SHA256".parse().unwrap();

let tokens = HandshakeTokens::try_from(&p.handshake).unwrap();

assert!(tokens.premsg_pattern_i.is_empty());
assert_eq!(tokens.premsg_pattern_r, &[Token::E]);
assert_eq!(tokens.msg_patterns[0].as_slice(), &[Token::E, Token::Dh(DhToken::Ee), Token::S, Token::Dh(DhToken::Se)]);
assert_eq!(tokens.msg_patterns[1].as_slice(), &[Token::S, Token::Dh(DhToken::Es)]);
// Hey, why is this different from XXfallback listed in Noise spec 10.4?
// It's the same, it's just in Bob-initiated form.
}
}
57 changes: 54 additions & 3 deletions src/params/patterns.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::error::{Error, PatternProblem};
use std::{convert::TryFrom, str::FromStr};
use std::{convert::TryFrom, str::FromStr, mem};

/// A small helper macro that behaves similar to the `vec![]` standard macro,
/// except it allocates a bit extra to avoid resizing.
Expand Down Expand Up @@ -97,14 +97,22 @@ pub(crate) enum Token {
Ekem1,
}

#[cfg(feature = "hfs")]
impl Token {
#[cfg(feature = "hfs")]
fn is_dh(&self) -> bool {
match *self {
Dh(_) => true,
_ => false,
}
}

fn invert_direction(&self) -> Token {
match *self {
Dh(DhToken::Es) => Dh(DhToken::Se),
Dh(DhToken::Se) => Dh(DhToken::Es),
x => x,
}
}
}

// See the documentation in the macro above.
Expand Down Expand Up @@ -490,9 +498,9 @@ impl<'a> TryFrom<&'a HandshakeChoice> for HandshakeTokens {
for modifier in handshake.modifiers.list.iter() {
match modifier {
HandshakeModifier::Psk(n) => apply_psk_modifier(&mut patterns, *n),
HandshakeModifier::Fallback => apply_fallback_modifier(&mut patterns),
#[cfg(feature = "hfs")]
HandshakeModifier::Hfs => apply_hfs_modifier(&mut patterns),
_ => return Err(PatternProblem::UnsupportedModifier.into()),
}
}

Expand Down Expand Up @@ -534,6 +542,49 @@ fn apply_psk_modifier(patterns: &mut Patterns, n: u8) {
}
}

fn apply_fallback_modifier(patterns: &mut Patterns) {
// From the noise spec, Section 10.2:
//
// The fallback modifier converts an Alice-initiated pattern to a
// Bob-initiated pattern by converting Alice's initial message to
// a pre-message that Bob must receive through some other means
// (e.g. via an initial IK message from Alice). After this conversion,
// the rest of the handshake pattern is interpreted as a Bob-initiated
// handshake pattern.
//
// Note that fallback can only be applied to handshake patterns in
// Alice-initiated form where Alice's first message is capable of being
// interpreted as a pre-message (i.e. it must be either "e", "s", or "e, s").

assert!(patterns.0.is_empty(), "Cannot convert a pattern with pre-existing pre-messages");

// Replace first pattern with empty one.
let tokens = patterns.2.remove(0);

// Set first pattern as Alice pre-message
patterns.0 = match tokens.as_slice() {
[Token::E] => static_slice![Token: E],
[Token::S] => static_slice![Token: S],
[Token::E, Token::S] | [Token::S, Token::E] =>
static_slice![Token: E, S],
_ => panic!("Cannot apply fallback modifier, the first message cannot be interpreted as a pre-message")
};

// In the standard it does not invert the arrows,
// it just says that the protocol is Bob-initiated and the first
// message begins with <-, but since we encode the patterns with
// the "initiator" as the first pattern, we need to perform an
// inversion (described in 7.2)
mem::swap(&mut patterns.0, &mut patterns.1);

for pattern in patterns.2.iter_mut() {
for token in pattern.iter_mut() {
*token = token.invert_direction();
}
}

}

#[cfg(feature = "hfs")]
fn apply_hfs_modifier(patterns: &mut Patterns) {
// From the HFS spec, Section 5:
Expand Down