use arrayvec::ArrayVec;
use crate::constants::{MAX_HS_MESSAGES_PER_ROLE, MAX_TOKENS_PER_HS_MESSAGE};
use crate::error::{PatternError, PatternResult};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HandshakeType {
DH,
KEM,
HYBRID,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Token {
E,
S,
EE,
ES,
SE,
SS,
Ekem,
Skem,
Psk,
}
#[derive(Clone, Debug)]
pub struct HandshakePattern {
name: &'static str,
pre_initiator: ArrayVec<Token, 4>,
pre_responder: ArrayVec<Token, 4>,
message_pattern: MessagePattern,
has_psk: bool,
hs_type: HandshakeType,
}
#[derive(Clone, Debug)]
pub struct MessagePattern {
pub initiator: ArrayVec<ArrayVec<Token, MAX_TOKENS_PER_HS_MESSAGE>, MAX_HS_MESSAGES_PER_ROLE>,
pub responder: ArrayVec<ArrayVec<Token, MAX_TOKENS_PER_HS_MESSAGE>, MAX_HS_MESSAGES_PER_ROLE>,
}
impl MessagePattern {
pub fn has_psk(&self) -> bool {
self.initiator.iter().flatten().any(|t| *t == Token::Psk)
|| self.responder.iter().flatten().any(|t| *t == Token::Psk)
}
pub fn has_kem(&self) -> bool {
self.initiator
.iter()
.flatten()
.any(|t| *t == Token::Ekem || *t == Token::Skem)
|| self
.responder
.iter()
.flatten()
.any(|t| *t == Token::Ekem || *t == Token::Skem)
}
pub fn has_dh(&self) -> bool {
self.initiator
.iter()
.flatten()
.any(|t| matches!(t, Token::EE | Token::ES | Token::SE | Token::SS))
|| self
.responder
.iter()
.flatten()
.any(|t| matches!(t, Token::EE | Token::ES | Token::SE | Token::SS))
}
}
impl HandshakePattern {
pub fn try_new(
name: &'static str,
pre_initiator: &[Token],
pre_responder: &[Token],
initiator: &[&[Token]],
responder: &[&[Token]],
) -> PatternResult<Self> {
let message_pattern = MessagePattern {
initiator: initiator
.iter()
.map(|p| p.iter().copied().collect())
.collect(),
responder: responder
.iter()
.map(|p| p.iter().copied().collect())
.collect(),
};
let has_kem = message_pattern.has_kem();
let has_dh = message_pattern.has_dh();
let hs_type = match (has_kem, has_dh) {
(true, true) => HandshakeType::HYBRID,
(true, false) => HandshakeType::KEM,
(false, true) => HandshakeType::DH,
(false, false) => unreachable!("Invalid handshake pattern"),
};
if message_pattern.has_psk() {
Self::validate_psk_rule(&message_pattern.initiator)?;
Self::validate_psk_rule(&message_pattern.responder)?;
}
if has_kem {
Self::validate_pq_token_order_rule(&message_pattern.initiator)?;
Self::validate_pq_token_order_rule(&message_pattern.responder)?;
}
Ok(Self {
name,
hs_type,
has_psk: message_pattern.has_psk(),
message_pattern,
pre_initiator: pre_initiator.iter().copied().collect(),
pre_responder: pre_responder.iter().copied().collect(),
})
}
pub fn new(
name: &'static str,
pre_initiator: &[Token],
pre_responder: &[Token],
initiator: &[&[Token]],
responder: &[&[Token]],
) -> Self {
Self::try_new(name, pre_initiator, pre_responder, initiator, responder)
.unwrap_or_else(|e| panic!("Handshake pattern error: {}", e))
}
pub fn validate_pq_token_order_rule(
messages: &[ArrayVec<Token, MAX_TOKENS_PER_HS_MESSAGE>],
) -> PatternResult<()> {
for message in messages.iter() {
let mut skem_seen = false;
let mut public_key_seen = false;
for token in message.iter() {
match token {
Token::Ekem => {
if public_key_seen {
return Err(PatternError::PqTokenOrderViolation);
}
if skem_seen {
return Err(PatternError::PqTokenOrderViolation);
}
}
Token::Skem => {
skem_seen = true;
if public_key_seen {
return Err(PatternError::PqTokenOrderViolation);
}
}
Token::E | Token::S => {
public_key_seen = true;
}
_ => {}
}
}
}
Ok(())
}
pub fn validate_psk_rule(
messages: &[ArrayVec<Token, MAX_TOKENS_PER_HS_MESSAGE>],
) -> PatternResult<()> {
let mut psk_sent = false;
for message in messages.iter() {
for token in message.iter() {
match token {
Token::Psk => {
psk_sent = true;
}
Token::E | Token::Ekem => {
return Ok(());
}
Token::Skem => {
if psk_sent {
return Err(PatternError::PskValidityViolation);
} else {
return Ok(());
}
}
Token::S => {
if psk_sent {
return Err(PatternError::PskValidityViolation);
}
}
_ => {}
}
}
}
Ok(())
}
pub fn get_initiator_pattern_len(&self) -> usize {
self.message_pattern.initiator.len()
}
pub fn get_responder_pattern_len(&self) -> usize {
self.message_pattern.responder.len()
}
pub(crate) fn get_initiator_pre_shared(&self) -> &[Token] {
&self.pre_initiator
}
pub(crate) fn get_responder_pre_shared(&self) -> &[Token] {
&self.pre_responder
}
pub fn get_initiator_pattern(&self, index: usize) -> &[Token] {
&self.message_pattern.initiator[index]
}
pub fn get_responder_pattern(&self, index: usize) -> &[Token] {
&self.message_pattern.responder[index]
}
pub fn has_psk(&self) -> bool {
self.has_psk
}
pub fn get_name(&self) -> &'static str {
self.name
}
pub fn is_one_way(&self) -> bool {
self.message_pattern.responder.is_empty()
}
pub fn get_type(&self) -> HandshakeType {
self.hs_type
}
pub fn add_psks(&self, psks: &[usize], name: &'static str) -> Self {
let mut initiator = self.message_pattern.initiator.clone();
let mut responder = self.message_pattern.responder.clone();
for pos in psks {
if *pos == 0 {
initiator[0].insert(0, Token::Psk);
} else if *pos % 2 == 0 {
let responder_psk = (*pos / 2) - 1;
responder[responder_psk].push(Token::Psk);
} else {
let initiator_psk = *pos / 2;
initiator[initiator_psk].push(Token::Psk);
}
}
let initiator_slices: ArrayVec<&[Token], MAX_HS_MESSAGES_PER_ROLE> =
initiator.iter().map(|v| v.as_slice()).collect();
let responder_slices: ArrayVec<&[Token], MAX_HS_MESSAGES_PER_ROLE> =
responder.iter().map(|v| v.as_slice()).collect();
Self::try_new(
name,
self.pre_initiator.as_slice(),
self.pre_responder.as_slice(),
&initiator_slices,
&responder_slices,
)
.unwrap_or_else(|e| panic!("Handshake pattern error in add_psks: {}", e))
}
}
pub fn noise_pqnn() -> HandshakePattern {
HandshakePattern::new("pqNN", &[], &[], &[&[Token::E]], &[&[Token::Ekem]])
}
pub fn noise_pqnk() -> HandshakePattern {
HandshakePattern::new(
"pqNK",
&[],
&[Token::S],
&[&[Token::Skem, Token::E]],
&[&[Token::Ekem]],
)
}
pub fn noise_pqnx() -> HandshakePattern {
HandshakePattern::new(
"pqNX",
&[],
&[],
&[&[Token::E], &[Token::Skem]],
&[&[Token::Ekem, Token::S]],
)
}
pub fn noise_pqkn() -> HandshakePattern {
HandshakePattern::new(
"pqNK",
&[Token::S],
&[],
&[&[Token::E]],
&[&[Token::Ekem, Token::Skem]],
)
}
pub fn noise_pqkk() -> HandshakePattern {
HandshakePattern::new(
"pqKK",
&[Token::S],
&[Token::S],
&[&[Token::Skem, Token::E]],
&[&[Token::Ekem, Token::Skem]],
)
}
pub fn noise_pqkx() -> HandshakePattern {
HandshakePattern::new(
"pqKX",
&[Token::S],
&[],
&[&[Token::E], &[Token::Skem]],
&[&[Token::Ekem, Token::Skem, Token::S]],
)
}
pub fn noise_pqxn() -> HandshakePattern {
HandshakePattern::new(
"pqXN",
&[],
&[],
&[&[Token::E], &[Token::S]],
&[&[Token::Ekem], &[Token::Skem]],
)
}
pub fn noise_pqxk() -> HandshakePattern {
HandshakePattern::new(
"pqXK",
&[],
&[Token::S],
&[&[Token::Skem, Token::E], &[Token::S]],
&[&[Token::Ekem], &[Token::Skem]],
)
}
pub fn noise_pqxx() -> HandshakePattern {
HandshakePattern::new(
"pqXX",
&[],
&[],
&[&[Token::E], &[Token::Skem, Token::S]],
&[&[Token::Ekem, Token::S], &[Token::Skem]],
)
}
pub fn noise_pqin() -> HandshakePattern {
HandshakePattern::new(
"pqIN",
&[],
&[],
&[&[Token::E, Token::S]],
&[&[Token::Ekem, Token::Skem]],
)
}
pub fn noise_pqik() -> HandshakePattern {
HandshakePattern::new(
"pqIK",
&[],
&[Token::S],
&[&[Token::Skem, Token::E, Token::S]],
&[&[Token::Ekem, Token::Skem]],
)
}
pub fn noise_pqix() -> HandshakePattern {
HandshakePattern::new(
"pqIX",
&[],
&[],
&[&[Token::E, Token::S], &[Token::Skem]],
&[&[Token::Ekem, Token::Skem, Token::S]],
)
}
pub fn noise_pqnn_psk2() -> HandshakePattern {
noise_pqnn().add_psks(&[2], "pqNNpsk2")
}
pub fn noise_pqnk_psk2() -> HandshakePattern {
noise_pqnk().add_psks(&[2], "pqNKpsk2")
}
pub fn noise_pqnx_psk2() -> HandshakePattern {
noise_pqnx().add_psks(&[2], "pqNXpsk2")
}
pub fn noise_pqxn_psk3() -> HandshakePattern {
noise_pqxn().add_psks(&[3], "pqXNpsk3")
}
pub fn noise_pqxk_psk3() -> HandshakePattern {
noise_pqxk().add_psks(&[3], "pqXKpsk3")
}
pub fn noise_pqxx_psk3() -> HandshakePattern {
noise_pqxx().add_psks(&[3], "pqXXpsk3")
}
pub fn noise_pqkn_psk2() -> HandshakePattern {
noise_pqkn().add_psks(&[2], "pqKNpsk2")
}
pub fn noise_pqkk_psk2() -> HandshakePattern {
noise_pqkk().add_psks(&[2], "pqKKpsk2")
}
pub fn noise_pqkx_psk2() -> HandshakePattern {
noise_pqkx().add_psks(&[2], "pqKXpsk2")
}
pub fn noise_pqin_psk1() -> HandshakePattern {
noise_pqin().add_psks(&[1], "pqINpsk1")
}
pub fn noise_pqin_psk2() -> HandshakePattern {
noise_pqin().add_psks(&[2], "pqINpsk2")
}
pub fn noise_pqik_psk1() -> HandshakePattern {
noise_pqik().add_psks(&[1], "pqIKpsk1")
}
pub fn noise_pqik_psk2() -> HandshakePattern {
noise_pqik().add_psks(&[2], "pqIKpsk2")
}
pub fn noise_pqix_psk2() -> HandshakePattern {
noise_pqix().add_psks(&[2], "pqIXpsk2")
}
pub fn noise_n() -> HandshakePattern {
HandshakePattern::new("N", &[], &[Token::S], &[&[Token::E, Token::ES]], &[])
}
pub fn noise_k() -> HandshakePattern {
HandshakePattern::new(
"K",
&[Token::S],
&[Token::S],
&[&[Token::E, Token::ES, Token::SS]],
&[],
)
}
pub fn noise_x() -> HandshakePattern {
HandshakePattern::new(
"X",
&[],
&[Token::S],
&[&[Token::E, Token::ES, Token::S, Token::SS]],
&[],
)
}
pub fn noise_nn() -> HandshakePattern {
HandshakePattern::new("NN", &[], &[], &[&[Token::E]], &[&[Token::E, Token::EE]])
}
pub fn noise_nk() -> HandshakePattern {
HandshakePattern::new(
"NK",
&[],
&[Token::S],
&[&[Token::E, Token::ES]],
&[&[Token::E, Token::EE]],
)
}
pub fn noise_nx() -> HandshakePattern {
HandshakePattern::new(
"NX",
&[],
&[],
&[&[Token::E]],
&[&[Token::E, Token::EE, Token::S, Token::ES]],
)
}
pub fn noise_kn() -> HandshakePattern {
HandshakePattern::new(
"KN",
&[Token::S],
&[],
&[&[Token::E]],
&[&[Token::E, Token::EE, Token::SE]],
)
}
pub fn noise_kk() -> HandshakePattern {
HandshakePattern::new(
"KK",
&[Token::S],
&[Token::S],
&[&[Token::E, Token::ES, Token::SS]],
&[&[Token::E, Token::EE, Token::SE]],
)
}
pub fn noise_kx() -> HandshakePattern {
HandshakePattern::new(
"KX",
&[Token::S],
&[],
&[&[Token::E]],
&[&[Token::E, Token::EE, Token::SE, Token::S, Token::ES]],
)
}
pub fn noise_xn() -> HandshakePattern {
HandshakePattern::new(
"XN",
&[],
&[],
&[&[Token::E], &[Token::S, Token::SE]],
&[&[Token::E, Token::EE]],
)
}
pub fn noise_xk() -> HandshakePattern {
HandshakePattern::new(
"XK",
&[],
&[Token::S],
&[&[Token::E, Token::ES], &[Token::S, Token::SE]],
&[&[Token::E, Token::EE]],
)
}
pub fn noise_xx() -> HandshakePattern {
HandshakePattern::new(
"XX",
&[],
&[],
&[&[Token::E], &[Token::S, Token::SE]],
&[&[Token::E, Token::EE, Token::S, Token::ES]],
)
}
pub fn noise_in() -> HandshakePattern {
HandshakePattern::new(
"IN",
&[],
&[],
&[&[Token::E, Token::S]],
&[&[Token::E, Token::EE, Token::SE]],
)
}
pub fn noise_ik() -> HandshakePattern {
HandshakePattern::new(
"IK",
&[],
&[Token::S],
&[&[Token::E, Token::ES, Token::S, Token::SS]],
&[&[Token::E, Token::EE, Token::SE]],
)
}
pub fn noise_ix() -> HandshakePattern {
HandshakePattern::new(
"IX",
&[],
&[],
&[&[Token::E, Token::S]],
&[&[Token::E, Token::EE, Token::SE, Token::S, Token::ES]],
)
}
pub fn noise_n_psk0() -> HandshakePattern {
noise_n().add_psks(&[0], "Npsk0")
}
pub fn noise_k_psk0() -> HandshakePattern {
noise_k().add_psks(&[0], "Kpsk0")
}
pub fn noise_x_psk1() -> HandshakePattern {
noise_x().add_psks(&[1], "Xpsk1")
}
pub fn noise_nn_psk0() -> HandshakePattern {
noise_nn().add_psks(&[0], "NNpsk0")
}
pub fn noise_nn_psk2() -> HandshakePattern {
noise_nn().add_psks(&[2], "NNpsk2")
}
pub fn noise_nk_psk0() -> HandshakePattern {
noise_nk().add_psks(&[0], "NKpsk0")
}
pub fn noise_nk_psk2() -> HandshakePattern {
noise_nk().add_psks(&[2], "NKpsk2")
}
pub fn noise_nx_psk2() -> HandshakePattern {
noise_nx().add_psks(&[2], "NXpsk2")
}
pub fn noise_xn_psk3() -> HandshakePattern {
noise_xn().add_psks(&[3], "XNpsk3")
}
pub fn noise_xk_psk3() -> HandshakePattern {
noise_xk().add_psks(&[3], "XKpsk3")
}
pub fn noise_xx_psk3() -> HandshakePattern {
noise_xx().add_psks(&[3], "XXpsk3")
}
pub fn noise_kn_psk0() -> HandshakePattern {
noise_kn().add_psks(&[0], "KNpsk0")
}
pub fn noise_kn_psk2() -> HandshakePattern {
noise_kn().add_psks(&[2], "KNpsk2")
}
pub fn noise_kk_psk0() -> HandshakePattern {
noise_kk().add_psks(&[0], "KKpsk0")
}
pub fn noise_kk_psk2() -> HandshakePattern {
noise_kk().add_psks(&[2], "KKpsk2")
}
pub fn noise_kx_psk2() -> HandshakePattern {
noise_kx().add_psks(&[2], "KXpsk2")
}
pub fn noise_in_psk1() -> HandshakePattern {
noise_in().add_psks(&[1], "INpsk1")
}
pub fn noise_in_psk2() -> HandshakePattern {
noise_in().add_psks(&[2], "INpsk2")
}
pub fn noise_ik_psk1() -> HandshakePattern {
noise_ik().add_psks(&[1], "IKpsk1")
}
pub fn noise_ik_psk2() -> HandshakePattern {
noise_ik().add_psks(&[2], "IKpsk2")
}
pub fn noise_ix_psk2() -> HandshakePattern {
noise_ix().add_psks(&[2], "IXpsk2")
}
pub fn noise_hybrid_nn() -> HandshakePattern {
HandshakePattern::new(
"hybridNN",
&[],
&[],
&[&[Token::E]],
&[&[Token::Ekem, Token::E, Token::EE]],
)
}
pub fn noise_hybrid_nk() -> HandshakePattern {
HandshakePattern::new(
"hybridNK",
&[],
&[Token::S],
&[&[Token::Skem, Token::E, Token::ES]],
&[&[Token::Ekem, Token::E, Token::EE]],
)
}
pub fn noise_hybrid_nx() -> HandshakePattern {
HandshakePattern::new(
"hybridNX",
&[],
&[],
&[&[Token::E], &[Token::Skem]],
&[&[Token::Ekem, Token::E, Token::EE, Token::S, Token::ES]],
)
}
pub fn noise_hybrid_kn() -> HandshakePattern {
HandshakePattern::new(
"hybridKN",
&[Token::S],
&[],
&[&[Token::E]],
&[&[Token::Ekem, Token::Skem, Token::E, Token::EE, Token::SE]],
)
}
pub fn noise_hybrid_kk() -> HandshakePattern {
HandshakePattern::new(
"hybridKK",
&[Token::S],
&[Token::S],
&[&[Token::Skem, Token::E, Token::ES, Token::SS]],
&[&[Token::Ekem, Token::Skem, Token::E, Token::EE, Token::SE]],
)
}
pub fn noise_hybrid_kx() -> HandshakePattern {
HandshakePattern::new(
"hybridKX",
&[Token::S],
&[],
&[&[Token::E], &[Token::Skem]],
&[&[
Token::Ekem,
Token::Skem,
Token::E,
Token::EE,
Token::SE,
Token::S,
Token::ES,
]],
)
}
pub fn noise_hybrid_xn() -> HandshakePattern {
HandshakePattern::new(
"hybridXN",
&[],
&[],
&[&[Token::E], &[Token::S, Token::SE]],
&[&[Token::Ekem, Token::E, Token::EE], &[Token::Skem]],
)
}
pub fn noise_hybrid_xk() -> HandshakePattern {
HandshakePattern::new(
"hybridXK",
&[],
&[Token::S],
&[&[Token::Skem, Token::E, Token::ES], &[Token::S, Token::SE]],
&[&[Token::Ekem, Token::E, Token::EE], &[Token::Skem]],
)
}
pub fn noise_hybrid_xx() -> HandshakePattern {
HandshakePattern::new(
"hybridXX",
&[],
&[],
&[&[Token::E], &[Token::Skem, Token::S, Token::SE]],
&[
&[Token::Ekem, Token::E, Token::EE, Token::S, Token::ES],
&[Token::Skem],
],
)
}
pub fn noise_hybrid_in() -> HandshakePattern {
HandshakePattern::new(
"hybridIN",
&[],
&[],
&[&[Token::E, Token::S]],
&[&[Token::Ekem, Token::Skem, Token::E, Token::EE, Token::SE]],
)
}
pub fn noise_hybrid_ik() -> HandshakePattern {
HandshakePattern::new(
"hybridIK",
&[],
&[Token::S],
&[&[Token::Skem, Token::E, Token::ES, Token::S, Token::SS]],
&[&[Token::Ekem, Token::Skem, Token::E, Token::EE, Token::SE]],
)
}
pub fn noise_hybrid_ix() -> HandshakePattern {
HandshakePattern::new(
"hybridIX",
&[],
&[],
&[&[Token::E, Token::S], &[Token::Skem]],
&[&[
Token::Ekem,
Token::Skem,
Token::E,
Token::EE,
Token::SE,
Token::S,
Token::ES,
]],
)
}
pub fn noise_hybrid_nn_psk0() -> HandshakePattern {
noise_hybrid_nn().add_psks(&[0], "hybridNNpsk0")
}
pub fn noise_hybrid_nn_psk2() -> HandshakePattern {
noise_hybrid_nn().add_psks(&[2], "hybridNNpsk2")
}
pub fn noise_hybrid_nk_psk2() -> HandshakePattern {
noise_hybrid_nk().add_psks(&[2], "hybridNKpsk2")
}
pub fn noise_hybrid_nx_psk2() -> HandshakePattern {
noise_hybrid_nx().add_psks(&[2], "hybridNXpsk2")
}
pub fn noise_hybrid_xn_psk3() -> HandshakePattern {
noise_hybrid_xn().add_psks(&[3], "hybridXNpsk3")
}
pub fn noise_hybrid_xk_psk3() -> HandshakePattern {
noise_hybrid_xk().add_psks(&[3], "hybridXKpsk3")
}
pub fn noise_hybrid_xx_psk3() -> HandshakePattern {
noise_hybrid_xx().add_psks(&[3], "hybridXXpsk3")
}
pub fn noise_hybrid_kn_psk0() -> HandshakePattern {
noise_hybrid_kn().add_psks(&[0], "hybridKNpsk0")
}
pub fn noise_hybrid_kn_psk2() -> HandshakePattern {
noise_hybrid_kn().add_psks(&[2], "hybridKNpsk2")
}
pub fn noise_hybrid_kk_psk2() -> HandshakePattern {
noise_hybrid_kk().add_psks(&[2], "hybridKKpsk2")
}
pub fn noise_hybrid_kx_psk2() -> HandshakePattern {
noise_hybrid_kx().add_psks(&[2], "hybridKXpsk2")
}
pub fn noise_hybrid_in_psk1() -> HandshakePattern {
noise_hybrid_in().add_psks(&[1], "hybridINpsk1")
}
pub fn noise_hybrid_in_psk2() -> HandshakePattern {
noise_hybrid_in().add_psks(&[2], "hybridINpsk2")
}
pub fn noise_hybrid_ik_psk1() -> HandshakePattern {
noise_hybrid_ik().add_psks(&[1], "hybridIKpsk1")
}
pub fn noise_hybrid_ik_psk2() -> HandshakePattern {
noise_hybrid_ik().add_psks(&[2], "hybridIKpsk2")
}
pub fn noise_hybrid_ix_psk2() -> HandshakePattern {
noise_hybrid_ix().add_psks(&[2], "hybridIXpsk2")
}
#[cfg(test)]
mod tests {
use crate::handshakepattern::{HandshakePattern, HandshakeType, Token};
#[test]
fn resolve_dh() {
let pattern = HandshakePattern::new("dh", &[], &[], &[&[Token::EE]], &[&[Token::SE]]);
assert_eq!(pattern.get_type(), HandshakeType::DH);
}
#[test]
fn resolve_kem() {
let pattern = HandshakePattern::new("dh", &[], &[], &[&[Token::Ekem]], &[&[Token::Skem]]);
assert_eq!(pattern.get_type(), HandshakeType::KEM);
}
#[test]
fn resolve_hybrid() {
let pattern = HandshakePattern::new(
"dh",
&[],
&[],
&[&[Token::Ekem, Token::SE]],
&[&[Token::Skem]],
);
assert_eq!(pattern.get_type(), HandshakeType::HYBRID);
}
#[test]
#[should_panic]
fn invalid_pattern_empty() {
let _ = HandshakePattern::new("dh", &[], &[], &[], &[]);
}
#[test]
#[should_panic]
fn invalid_pattern_no_ops() {
let _ = HandshakePattern::new("dh", &[], &[], &[&[Token::E, Token::S]], &[]);
}
#[test]
#[should_panic]
fn too_many_tokens() {
let _ = HandshakePattern::new(
"dh",
&[],
&[],
&[&[
Token::E,
Token::E,
Token::E,
Token::E,
Token::E,
Token::E,
Token::E,
Token::E,
Token::E,
Token::E,
Token::E,
Token::E,
]],
&[],
);
}
#[test]
fn psk_validity_e_before_psk() {
let result = HandshakePattern::try_new(
"test",
&[],
&[],
&[&[Token::E, Token::Psk]],
&[&[Token::E, Token::EE]],
);
assert!(result.is_ok());
}
#[test]
fn psk_validity_e_after_psk() {
let result = HandshakePattern::try_new(
"test",
&[],
&[],
&[&[Token::Psk, Token::E]],
&[&[Token::E, Token::EE]],
);
assert!(result.is_ok());
}
#[test]
fn psk_validity_ekem_after_psk() {
let result = HandshakePattern::try_new(
"test",
&[],
&[],
&[&[Token::Psk, Token::Ekem]],
&[&[Token::Ekem]],
);
assert!(result.is_ok());
}
#[test]
fn psk_validity_skem_before_psk() {
let result = HandshakePattern::try_new(
"test",
&[],
&[],
&[&[Token::Skem, Token::Psk]],
&[&[Token::Ekem]],
);
assert!(result.is_ok());
}
#[test]
fn psk_validity_violation_s_after_psk() {
let result = HandshakePattern::try_new(
"test",
&[],
&[],
&[&[Token::Psk, Token::S]],
&[&[Token::E, Token::EE]],
);
assert!(matches!(
result,
Err(crate::error::PatternError::PskValidityViolation)
));
}
#[test]
fn psk_validity_violation_skem_after_psk() {
let result = HandshakePattern::try_new(
"test",
&[],
&[],
&[&[Token::Psk, Token::Skem]],
&[&[Token::Ekem]],
);
assert!(matches!(
result,
Err(crate::error::PatternError::PskValidityViolation)
));
}
#[test]
fn pq_token_order_valid() {
let result = HandshakePattern::try_new(
"test",
&[],
&[],
&[&[Token::Ekem, Token::Skem, Token::E]],
&[&[Token::Ekem]],
);
assert!(result.is_ok());
}
#[test]
fn pq_token_order_violation_ekem_after_skem() {
let result = HandshakePattern::try_new(
"test",
&[],
&[],
&[&[Token::Skem, Token::Ekem]],
&[&[Token::Ekem]],
);
assert!(matches!(
result,
Err(crate::error::PatternError::PqTokenOrderViolation)
));
}
#[test]
fn pq_token_order_violation_ekem_after_public_key() {
let result = HandshakePattern::try_new(
"test",
&[],
&[],
&[&[Token::E, Token::Ekem]],
&[&[Token::Ekem]],
);
assert!(matches!(
result,
Err(crate::error::PatternError::PqTokenOrderViolation)
));
}
#[test]
fn pq_token_order_violation_skem_after_public_key() {
let result = HandshakePattern::try_new(
"test",
&[],
&[],
&[&[Token::E, Token::Skem]],
&[&[Token::Ekem]],
);
assert!(matches!(
result,
Err(crate::error::PatternError::PqTokenOrderViolation)
));
}
#[test]
#[should_panic(expected = "PSK validity rule violation")]
fn add_psks_psk_validity_violation_skem_after_psk() {
let pattern = HandshakePattern::new("test", &[], &[], &[&[Token::Skem]], &[&[Token::Ekem]]);
let _ = pattern.add_psks(&[0], "invalid");
}
#[test]
#[should_panic(expected = "PSK validity rule violation")]
fn add_psks_psk_validity_violation_s_after_psk() {
let pattern =
HandshakePattern::new("test", &[], &[], &[&[Token::S]], &[&[Token::E, Token::EE]]);
let _ = pattern.add_psks(&[0], "invalid");
}
#[test]
fn add_psks_psk_validity_ok_with_e_before() {
let pattern =
HandshakePattern::new("test", &[], &[], &[&[Token::E]], &[&[Token::E, Token::EE]]);
let result = pattern.add_psks(&[1], "valid");
assert!(result.has_psk());
}
#[test]
fn add_psks_psk_validity_ok_with_e_after() {
let pattern =
HandshakePattern::new("test", &[], &[], &[&[Token::E]], &[&[Token::E, Token::EE]]);
let result = pattern.add_psks(&[0], "valid");
assert!(result.has_psk());
}
#[test]
fn add_psks_validates_full_pattern() {
let pattern = HandshakePattern::new("test", &[], &[], &[&[Token::Ekem]], &[&[Token::Ekem]]);
let result = pattern.add_psks(&[0], "valid");
assert!(result.has_psk());
assert_eq!(result.get_type(), HandshakeType::KEM);
}
}