diff --git a/zssp/src/applicationlayer.rs b/zssp/src/applicationlayer.rs index b8d1d7c84..10083f50d 100644 --- a/zssp/src/applicationlayer.rs +++ b/zssp/src/applicationlayer.rs @@ -43,11 +43,11 @@ pub trait ApplicationLayer: Sized { /// Default is ten minutes. const REKEY_AFTER_TIME_MS_MAX_JITTER: u32 = 1000 * 60 * 10; - /// Timeout for Noise_XK session negotiation in milliseconds. + /// Timeout for incoming Noise_XK session negotiation in milliseconds. /// /// Default is two seconds, which should be enough for even extremely slow links or links /// over very long distances. - const SESSION_NEGOTIATION_TIMEOUT_MS: i64 = 2000; + const INCOMING_SESSION_NEGOTIATION_TIMEOUT_MS: i64 = 2000; /// Type for arbitrary opaque object for use by the application that is attached to each session. type Data; diff --git a/zssp/src/zssp.rs b/zssp/src/zssp.rs index 5811975cc..350ac111c 100644 --- a/zssp/src/zssp.rs +++ b/zssp/src/zssp.rs @@ -99,6 +99,7 @@ struct NoiseXKOutgoing { alice_noise_e_secret: P384KeyPair, noise_es: Secret, alice_hk_secret: Secret, + metadata: Option>, } enum EphemeralOffer { @@ -165,7 +166,7 @@ impl Context { } } for (id, p) in sessions.incomplete.iter() { - if (p.timestamp - current_time) > Application::SESSION_NEGOTIATION_TIMEOUT_MS { + if (p.timestamp - current_time) > Application::INCOMING_SESSION_NEGOTIATION_TIMEOUT_MS { dead_pending.push(*id); } } @@ -181,7 +182,7 @@ impl Context { } } - Application::SESSION_NEGOTIATION_TIMEOUT_MS * 2 + Application::INCOMING_SESSION_NEGOTIATION_TIMEOUT_MS * 2 } /// Create a new session and send initial packet(s) to other side. @@ -245,6 +246,7 @@ impl Context { alice_noise_e_secret, noise_es: noise_es.clone(), alice_hk_secret: Secret(alice_hk_secret.secret), + metadata: metadata.map(|md| ArrayVec::try_from(md).unwrap()), })), }), defrag: Mutex::new(RingBufferMap::new(random::xorshift64_random() as u32)), @@ -639,7 +641,7 @@ impl Context { // entry. If we find one that is actually timed out, that one is replaced instead. let mut newest = i64::MIN; let mut replace_id = None; - let cutoff_time = current_time - Application::SESSION_NEGOTIATION_TIMEOUT_MS; + let cutoff_time = current_time - Application::INCOMING_SESSION_NEGOTIATION_TIMEOUT_MS; for (id, s) in sessions.incomplete.iter() { if s.timestamp <= cutoff_time { replace_id = Some(*id); @@ -719,16 +721,19 @@ impl Context { if let Some(session) = session { let state = session.state.read().unwrap(); - if let EphemeralOffer::NoiseXKInit(boxed_offer) = &state.offer { - let (alice_e_secret, metadata, noise_es, alice_hk_secret) = boxed_offer.as_ref(); + if let EphemeralOffer::NoiseXKInit(outgoing_offer) = &state.offer { let pkt: &BobNoiseXKAck = byte_array_as_proto_buffer(pkt_assembled)?; if let Some(bob_session_id) = SessionId::new_from_bytes(&pkt.bob_session_id) { // Derive noise_es_ee from Bob's ephemeral public key. let bob_noise_e = P384PublicKey::from_bytes(&pkt.bob_noise_e).ok_or(Error::FailedAuthentication)?; let noise_es_ee = Secret(hmac_sha512( - noise_es.as_bytes(), - alice_e_secret.agree(&bob_noise_e).ok_or(Error::FailedAuthentication)?.as_bytes(), + outgoing_offer.noise_es.as_bytes(), + outgoing_offer + .alice_noise_e_secret + .agree(&bob_noise_e) + .ok_or(Error::FailedAuthentication)? + .as_bytes(), )); let noise_es_ee_kex_enc_key = kbkdf::(noise_es_ee.as_bytes()); @@ -757,7 +762,7 @@ impl Context { // the Noise pattern is concerned is the result of mixing the externally supplied PSK // with the Kyber1024 shared secret (hk). Kyber is treated as part of the PSK because // it's an external add-on beyond the Noise spec. - let hk = pqc_kyber::decapsulate(&pkt.bob_hk_ciphertext, alice_hk_secret.as_bytes()) + let hk = pqc_kyber::decapsulate(&pkt.bob_hk_ciphertext, outgoing_offer.alice_hk_secret.as_bytes()) .map_err(|_| Error::FailedAuthentication) .map(|k| Secret(k))?; let noise_es_ee_se_hk_psk = Secret(hmac_sha512( @@ -793,7 +798,7 @@ impl Context { assert!(alice_s_public_blob.len() <= (u16::MAX as usize)); reply_buffer_append(&(alice_s_public_blob.len() as u16).to_le_bytes()); reply_buffer_append(alice_s_public_blob); - if let Some(md) = metadata.as_ref() { + if let Some(md) = outgoing_offer.metadata.as_ref() { reply_buffer_append(&(md.len() as u16).to_le_bytes()); reply_buffer_append(md.as_ref()); } else { @@ -886,7 +891,7 @@ impl Context { if let Some(incomplete) = incomplete { // Check timeout, negotiations aren't allowed to take longer than this. - if (current_time - incomplete.timestamp) > Application::SESSION_NEGOTIATION_TIMEOUT_MS { + if (current_time - incomplete.timestamp) > Application::INCOMING_SESSION_NEGOTIATION_TIMEOUT_MS { return Err(Error::UnknownLocalSessionId); }