From a723403fe9ef536fd9a9edb26f31beadf2004b94 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 19 Aug 2022 11:31:09 -0400 Subject: [PATCH] Prep for new controller, also reorg header fields in Noise session and move some functions around. --- core-crypto/src/noise.rs | 654 ++++++++++++------------ network-hypervisor/src/vl1/node.rs | 7 +- network-hypervisor/src/vl1/peer.rs | 111 ++-- network-hypervisor/src/vl2/networkid.rs | 13 +- network-hypervisor/src/vl2/switch.rs | 13 +- 5 files changed, 384 insertions(+), 414 deletions(-) diff --git a/core-crypto/src/noise.rs b/core-crypto/src/noise.rs index 4bce88a96..b3712fc40 100644 --- a/core-crypto/src/noise.rs +++ b/core-crypto/src/noise.rs @@ -57,6 +57,9 @@ ignored when analyzing the "real" security of the protocol. /// Minimum packet size / minimum size for work buffers. pub const MIN_BUFFER_SIZE: usize = 1400; +/// Minimum possible packet size. +pub const MIN_PACKET_SIZE: usize = HEADER_SIZE + 1 + AES_GCM_TAG_SIZE; + /// Start attempting to rekey after a key has been used to send packets this many times. const REKEY_AFTER_USES: u64 = 536870912; @@ -86,9 +89,7 @@ const E1_TYPE_NONE: u8 = 0; /// Secondary (hybrid) ephemeral key is Kyber512 const E1_TYPE_KYBER512: u8 = 1; -/// Header size; header is: [4] counter | [6] destination session ID | [1] type const HEADER_SIZE: usize = 11; - const AES_GCM_TAG_SIZE: usize = 16; const HMAC_SIZE: usize = 48; // HMAC-SHA384 const SESSION_ID_SIZE: usize = 6; @@ -128,6 +129,9 @@ pub enum Error { /// Attempt to send using session without established key. SessionNotEstablished, + + /// Packet ignored by rate limiter. + RateLimited, } impl std::fmt::Display for Error { @@ -140,6 +144,7 @@ impl std::fmt::Display for Error { Self::NewSessionRejected => f.write_str("NewSessionRejected"), Self::MaxKeyLifetimeExceeded => f.write_str("MaxKeyLifetimeExceeded"), Self::SessionNotEstablished => f.write_str("SessionNotEstablished"), + Self::RateLimited => f.write_str("RateLimited"), } } } @@ -242,21 +247,61 @@ pub struct Session { psk: Secret<64>, ss: Secret<48>, outgoing_obfuscator: Obfuscator, - state: RwLock, + state: RwLock, remote_s_public_p384: [u8; P384_PUBLIC_KEY_SIZE], /// Arbitrary object associated with this session pub associated_object: O, } -/// Mutable inner state of Session (except counter, which is atomic to avoid locks on packet sends) -struct State { +struct MutableState { remote_session_id: Option, keys: [Option; 2], // current, next offer: Option, } impl Session { + /// Create a new session and return this plus an outgoing packet to send to the other end. + pub fn new<'a, const MAX_PACKET_SIZE: usize, const STATIC_PUBLIC_SIZE: usize>( + buffer: &'a mut [u8; MAX_PACKET_SIZE], + local_session_id: SessionId, + local_s_public: &[u8; STATIC_PUBLIC_SIZE], + local_s_keypair_p384: &P384KeyPair, + remote_s_public: &[u8; STATIC_PUBLIC_SIZE], + remote_s_public_p384: &P384PublicKey, + psk: &Secret<64>, + associated_object: O, + current_time: i64, + jedi: bool, + ) -> Result<(Self, &'a [u8]), Error> { + debug_assert!(MAX_PACKET_SIZE >= MIN_BUFFER_SIZE); + let counter = Counter::new(); + if let Some(ss) = local_s_keypair_p384.agree(remote_s_public_p384) { + let outgoing_obfuscator = Obfuscator::new(remote_s_public); + if let Some((offer, psize)) = EphemeralOffer::create_alice_offer(buffer, counter.next(), local_session_id, None, local_s_public, remote_s_public_p384, &ss, &outgoing_obfuscator, current_time, jedi) { + return Ok(( + Session:: { + id: local_session_id, + send_counter: counter, + remote_s_public_hash: SHA384::hash(remote_s_public), + psk: psk.clone(), + ss, + outgoing_obfuscator, + state: RwLock::new(MutableState { + remote_session_id: None, + keys: [None, None], + offer: Some(offer), + }), + remote_s_public_p384: remote_s_public_p384.as_bytes().clone(), + associated_object, + }, + &buffer[..psize], + )); + } + } + return Err(Error::InvalidParameter); + } + /// Check whether this session should initiate a re-key, returning a packet to send if true. /// /// This must be checked often enough to ensure that the hard key usage limit is not reached, which in the @@ -304,352 +349,319 @@ impl Session { Err(Error::SessionNotEstablished) } } -} -/// Create a new session and return this plus an outgoing packet to send to the other end. -pub fn new_session<'a, O, const MAX_PACKET_SIZE: usize, const STATIC_PUBLIC_SIZE: usize>( - buffer: &'a mut [u8; MAX_PACKET_SIZE], - local_session_id: SessionId, - local_s_public: &[u8; STATIC_PUBLIC_SIZE], - local_s_keypair_p384: &P384KeyPair, - remote_s_public: &[u8; STATIC_PUBLIC_SIZE], - remote_s_public_p384: &P384PublicKey, - psk: &Secret<64>, - associated_object: O, - current_time: i64, - jedi: bool, -) -> Result<(Session, &'a [u8]), Error> { - debug_assert!(MAX_PACKET_SIZE >= MIN_BUFFER_SIZE); - let counter = Counter::new(); - if let Some(ss) = local_s_keypair_p384.agree(remote_s_public_p384) { - let outgoing_obfuscator = Obfuscator::new(remote_s_public); - if let Some((offer, psize)) = EphemeralOffer::create_alice_offer(buffer, counter.next(), local_session_id, None, local_s_public, remote_s_public_p384, &ss, &outgoing_obfuscator, current_time, jedi) { - return Ok(( - Session:: { - id: local_session_id, - send_counter: counter, - remote_s_public_hash: SHA384::hash(remote_s_public), - psk: psk.clone(), - ss, - outgoing_obfuscator, - state: RwLock::new(State { - remote_session_id: None, - keys: [None, None], - offer: Some(offer), - }), - remote_s_public_p384: remote_s_public_p384.as_bytes().clone(), - associated_object, - }, - &buffer[..psize], - )); + /// Receive a packet from the network and take the appropriate action. + /// + /// Check ReceiveResult to see if it includes data or a reply packet. + pub fn receive< + 'a, + ExtractP384PublicKeyFunction: FnOnce(&[u8; STATIC_PUBLIC_SIZE]) -> Option, + SessionLookupFunction: FnOnce(SessionId) -> Option, + NewSessionAuthenticatorFunction: FnOnce(&[u8; STATIC_PUBLIC_SIZE]) -> Option<(SessionId, Secret<64>, O)>, + S: std::ops::Deref>, + const MAX_PACKET_SIZE: usize, + const STATIC_PUBLIC_SIZE: usize, + >( + incoming_packet: &[u8], + buffer: &'a mut [u8; MAX_PACKET_SIZE], + local_s_keypair_p384: &P384KeyPair, + incoming_obfuscator: &Obfuscator, + extract_p384_static_public: ExtractP384PublicKeyFunction, + session_lookup: SessionLookupFunction, + new_session_auth: NewSessionAuthenticatorFunction, + current_time: i64, + jedi: bool, + ) -> Result, Error> { + debug_assert!(MAX_PACKET_SIZE >= MIN_BUFFER_SIZE); + if incoming_packet.len() > MAX_PACKET_SIZE || incoming_packet.len() <= MIN_PACKET_SIZE { + unlikely_branch(); + return Err(Error::InvalidPacket); } - } - return Err(Error::InvalidParameter); -} -/// Receive a packet from the network and take the appropriate action. -/// -/// Check ReceiveResult to see if it includes data or a reply packet. -pub fn receive< - 'a, - ExtractP384PublicKeyFunction: FnOnce(&[u8; STATIC_PUBLIC_SIZE]) -> Option, - SessionLookupFunction: FnOnce(SessionId) -> Option, - NewSessionAuthenticatorFunction: FnOnce(&[u8; STATIC_PUBLIC_SIZE]) -> Option<(SessionId, Secret<64>, O)>, - S: std::ops::Deref>, - O, - const MAX_PACKET_SIZE: usize, - const STATIC_PUBLIC_SIZE: usize, ->( - incoming_packet: &[u8], - buffer: &'a mut [u8; MAX_PACKET_SIZE], - local_s_keypair_p384: &P384KeyPair, - incoming_obfuscator: &Obfuscator, - extract_p384_static_public: ExtractP384PublicKeyFunction, - session_lookup: SessionLookupFunction, - new_session_auth: NewSessionAuthenticatorFunction, - current_time: i64, - jedi: bool, -) -> Result, Error> { - debug_assert!(MAX_PACKET_SIZE >= MIN_BUFFER_SIZE); - if incoming_packet.len() > MAX_PACKET_SIZE || incoming_packet.len() <= 16 { - unlikely_branch(); - return Err(Error::InvalidPacket); - } + incoming_obfuscator.0.decrypt_block(&incoming_packet[..16], &mut buffer[..16]); + let packet_type = buffer[0]; + let local_session_id = SessionId::new_from_bytes(&buffer[1..7]); - incoming_obfuscator.0.decrypt_block(&incoming_packet[0..16], &mut buffer[0..16]); - let local_session_id = SessionId::new_from_bytes(&buffer[4..10]); - let packet_type = buffer[10]; + debug_assert_eq!(PACKET_TYPE_DATA, 0); + debug_assert_eq!(PACKET_TYPE_NOP, 1); + if packet_type <= PACKET_TYPE_NOP { + if let Some(local_session_id) = local_session_id { + if let Some(session) = session_lookup(local_session_id) { + let state = session.state.read(); + for ki in 0..2 { + if let Some(key) = state.keys[ki].as_ref() { + let nonce = get_aes_gcm_nonce(buffer); + let mut c = key.get_receive_cipher(); + c.init(&nonce); + c.crypt_in_place(&mut buffer[HEADER_SIZE..16]); + let data_len = incoming_packet.len() - AES_GCM_TAG_SIZE; + c.crypt(&incoming_packet[16..data_len], &mut buffer[16..data_len]); + let tag = c.finish(); + key.return_receive_cipher(c); - debug_assert_eq!(PACKET_TYPE_DATA, 0); - debug_assert_eq!(PACKET_TYPE_NOP, 1); - if packet_type <= PACKET_TYPE_NOP { - if let Some(local_session_id) = local_session_id { - if let Some(session) = session_lookup(local_session_id) { - let state = session.state.read(); - for ki in 0..2 { - if let Some(key) = state.keys[ki].as_ref() { - let nonce = get_aes_gcm_nonce(buffer); - let mut c = key.get_receive_cipher(); - c.init(&nonce); - c.crypt_in_place(&mut buffer[HEADER_SIZE..16]); - let data_len = incoming_packet.len() - AES_GCM_TAG_SIZE; - c.crypt(&incoming_packet[16..data_len], &mut buffer[16..data_len]); - let tag = c.finish(); - key.return_receive_cipher(c); + if tag.eq(&incoming_packet[data_len..]) { + if ki == 1 { + // Promote next key to current key on success. + unlikely_branch(); + drop(state); + let mut state = session.state.write(); + state.keys[0] = state.keys[1].take(); + } - if tag.eq(&incoming_packet[data_len..]) { - if ki == 1 { - // Promote next key to current key on success. - unlikely_branch(); - drop(state); - let mut state = session.state.write(); - state.keys[0] = state.keys[1].take(); - } - - if packet_type == PACKET_TYPE_DATA { - return Ok(ReceiveResult::OkData(&buffer[HEADER_SIZE..data_len], u32::from_le_bytes(nonce[..4].try_into().unwrap()))); - } else { - return Ok(ReceiveResult::Ok); + if packet_type == PACKET_TYPE_DATA { + return Ok(ReceiveResult::OkData(&buffer[HEADER_SIZE..data_len], u32::from_le_bytes(nonce[7..11].try_into().unwrap()))); + } else { + return Ok(ReceiveResult::Ok); + } } } } + return Err(Error::FailedAuthentication); + } else { + unlikely_branch(); + return Err(Error::UnknownLocalSessionId(Some(local_session_id))); } - return Err(Error::FailedAuthentication); } else { unlikely_branch(); - return Err(Error::UnknownLocalSessionId(Some(local_session_id))); + return Err(Error::UnknownLocalSessionId(None)); } } else { unlikely_branch(); - return Err(Error::UnknownLocalSessionId(None)); - } - } else { - unlikely_branch(); - let session = if let Some(local_session_id) = local_session_id { - let s = session_lookup(local_session_id); - if s.is_none() { - return Err(Error::UnknownLocalSessionId(Some(local_session_id))); - } - s - } else { - None - }; - - if incoming_packet.len() > (HEADER_SIZE + P384_PUBLIC_KEY_SIZE + AES_GCM_TAG_SIZE + HMAC_SIZE) { - incoming_obfuscator.0.decrypt_block(&incoming_packet[16..32], &mut buffer[16..32]); - incoming_obfuscator.0.decrypt_block(&incoming_packet[32..48], &mut buffer[32..48]); - incoming_obfuscator.0.decrypt_block(&incoming_packet[48..64], &mut buffer[48..64]); - buffer[64..incoming_packet.len()].copy_from_slice(&incoming_packet[64..]); - } else { - return Err(Error::InvalidPacket); - } - let payload_end = incoming_packet.len() - (AES_GCM_TAG_SIZE + HMAC_SIZE); - let aes_gcm_tag_end = incoming_packet.len() - HMAC_SIZE; - - match packet_type { - PACKET_TYPE_KEY_OFFER => { - // alice (remote) -> bob (local) - - let (alice_e0_public, e0s) = P384PublicKey::from_bytes(&buffer[HEADER_SIZE..HEADER_SIZE + P384_PUBLIC_KEY_SIZE]) - .and_then(|pk| local_s_keypair_p384.agree(&pk).map(move |s| (pk, s))) - .ok_or(Error::FailedAuthentication)?; - - let key = Secret(hmac_sha512(&hmac_sha512(&KEY_DERIVATION_CHAIN_STARTING_SALT, alice_e0_public.as_bytes()), e0s.as_bytes())); - - let original_ciphertext = buffer.clone(); - let mut c = AesGcm::new(kbkdf512(key.as_bytes(), KBKDF_KEY_USAGE_LABEL_AES_GCM_ALICE_TO_BOB).first_n::<32>(), false); - c.init(&get_aes_gcm_nonce(buffer)); - c.crypt_in_place(&mut buffer[(HEADER_SIZE + P384_PUBLIC_KEY_SIZE)..payload_end]); - let c = c.finish(); - if !c.eq(&buffer[payload_end..aes_gcm_tag_end]) { - return Err(Error::FailedAuthentication); + let session = if let Some(local_session_id) = local_session_id { + let s = session_lookup(local_session_id); + if s.is_none() { + return Err(Error::UnknownLocalSessionId(Some(local_session_id))); } + s + } else { + None + }; - let (alice_session_id, alice_s_public, alice_e1_public) = parse_KEY_OFFER_after_header(&buffer[(HEADER_SIZE + P384_PUBLIC_KEY_SIZE)..payload_end])?; + if incoming_packet.len() > (HEADER_SIZE + P384_PUBLIC_KEY_SIZE + AES_GCM_TAG_SIZE + HMAC_SIZE) { + incoming_obfuscator.0.decrypt_block(&incoming_packet[16..32], &mut buffer[16..32]); + incoming_obfuscator.0.decrypt_block(&incoming_packet[32..48], &mut buffer[32..48]); + incoming_obfuscator.0.decrypt_block(&incoming_packet[48..64], &mut buffer[48..64]); + buffer[64..incoming_packet.len()].copy_from_slice(&incoming_packet[64..]); + } else { + return Err(Error::InvalidPacket); + } + let payload_end = incoming_packet.len() - (AES_GCM_TAG_SIZE + HMAC_SIZE); + let aes_gcm_tag_end = incoming_packet.len() - HMAC_SIZE; - if let Some(session) = session.as_ref() { - // If we already have a session for this session ID, make sure this is the same node calling. - if !session.remote_s_public_hash.eq(&SHA384::hash(&alice_s_public)) { + match packet_type { + PACKET_TYPE_KEY_OFFER => { + // alice (remote) -> bob (local) + + // Check rate limit if this session is known. + if let Some(session) = session.as_ref() { + if let Some(offer) = session.state.read().offer.as_ref() { + if (current_time - offer.creation_time) < OFFER_RATE_LIMIT_MS { + return Err(Error::RateLimited); + } + } + } + + let (alice_e0_public, e0s) = P384PublicKey::from_bytes(&buffer[HEADER_SIZE..HEADER_SIZE + P384_PUBLIC_KEY_SIZE]) + .and_then(|pk| local_s_keypair_p384.agree(&pk).map(move |s| (pk, s))) + .ok_or(Error::FailedAuthentication)?; + + let key = Secret(hmac_sha512(&hmac_sha512(&KEY_DERIVATION_CHAIN_STARTING_SALT, alice_e0_public.as_bytes()), e0s.as_bytes())); + + let original_ciphertext = buffer.clone(); + let mut c = AesGcm::new(kbkdf512(key.as_bytes(), KBKDF_KEY_USAGE_LABEL_AES_GCM_ALICE_TO_BOB).first_n::<32>(), false); + c.init(&get_aes_gcm_nonce(buffer)); + c.crypt_in_place(&mut buffer[(HEADER_SIZE + P384_PUBLIC_KEY_SIZE)..payload_end]); + let c = c.finish(); + if !c.eq(&buffer[payload_end..aes_gcm_tag_end]) { return Err(Error::FailedAuthentication); } - } - let alice_s_public_p384 = extract_p384_static_public(&alice_s_public).ok_or(Error::InvalidPacket)?; - let ss = local_s_keypair_p384.agree(&alice_s_public_p384).ok_or(Error::FailedAuthentication)?; + let (alice_session_id, alice_s_public, alice_e1_public) = parse_KEY_OFFER_after_header(&buffer[(HEADER_SIZE + P384_PUBLIC_KEY_SIZE)..payload_end])?; - let key = Secret(hmac_sha512(key.as_bytes(), ss.as_bytes())); - - if !hmac_sha384(kbkdf512(key.as_bytes(), KBKDF_KEY_USAGE_LABEL_HMAC).first_n::<48>(), &original_ciphertext[..aes_gcm_tag_end]).eq(&buffer[aes_gcm_tag_end..incoming_packet.len()]) { - return Err(Error::FailedAuthentication); - } - - // Alice's offer has been verified and her current key state reconstructed. - - let bob_e0_keypair = P384KeyPair::generate(); - let e0e0 = bob_e0_keypair.agree(&alice_e0_public).ok_or(Error::FailedAuthentication)?; - let se0 = bob_e0_keypair.agree(&alice_s_public_p384).ok_or(Error::FailedAuthentication)?; - - let new_session = if session.is_some() { - None - } else { - if let Some((local_session_id, psk, associated_object)) = new_session_auth(&alice_s_public) { - Some(Session:: { - id: local_session_id, - send_counter: Counter::new(), - remote_s_public_hash: SHA384::hash(&alice_s_public), - psk, - ss, - outgoing_obfuscator: Obfuscator::new(&alice_s_public), - state: RwLock::new(State { - remote_session_id: Some(alice_session_id), - keys: [None, None], - offer: None, - }), - remote_s_public_p384: alice_s_public_p384.as_bytes().clone(), - associated_object, - }) - } else { - return Err(Error::NewSessionRejected); - } - }; - let session_ref = session; - let session = session_ref.as_ref().map_or_else(|| new_session.as_ref().unwrap(), |s| &*s); - - // FIPS note: the order of HMAC parameters are flipped here from the usual Noise HMAC(key, X). That's because - // NIST/FIPS allows HKDF with HMAC(salt, key) and salt is allowed to be anything. This way if the PSK is not - // FIPS compliant the compliance of the entire key derivation is not invalidated. Both inputs are secrets of - // fixed size so this shouldn't matter cryptographically. - let key = Secret(hmac_sha512( - session.psk.as_bytes(), - &hmac_sha512(&hmac_sha512(&hmac_sha512(key.as_bytes(), bob_e0_keypair.public_key_bytes()), e0e0.as_bytes()), se0.as_bytes()), - )); - - // At this point we've completed Noise_IK key derivation with NIST P-384 ECDH, but see final step below... - - let (bob_e1_public, e1e1) = if jedi && alice_e1_public.is_some() { - if let Ok((bob_e1_public, e1e1)) = pqc_kyber::encapsulate(alice_e1_public.as_ref().unwrap(), &mut random::SecureRandom::default()) { - (Some(bob_e1_public), Secret(e1e1)) - } else { - return Err(Error::FailedAuthentication); - } - } else { - (None, Secret::default()) // use all zero Kyber secret if disabled - }; - - let counter = session.send_counter.next(); - let mut reply_size = assemble_KEY_COUNTER_OFFER(buffer, counter, alice_session_id, bob_e0_keypair.public_key(), session.id, bob_e1_public.as_ref()); - - let mut c = AesGcm::new(kbkdf512(key.as_bytes(), KBKDF_KEY_USAGE_LABEL_AES_GCM_BOB_TO_ALICE).first_n::<32>(), true); - c.init(&get_aes_gcm_nonce(buffer)); - c.crypt_in_place(&mut buffer[(HEADER_SIZE + P384_PUBLIC_KEY_SIZE)..reply_size]); - let c = c.finish(); - buffer[reply_size..(reply_size + AES_GCM_TAG_SIZE)].copy_from_slice(&c); - reply_size += AES_GCM_TAG_SIZE; - - // Normal Noise_IK is done, but we have one more step: mix in the Kyber shared secret (or all zeroes if Kyber is - // disabled). We have to wait until this point because Kyber's keys are encrypted and can't be decrypted until - // the P-384 exchange is done. We also flip the HMAC parameter order here for the same reason we do in the previous - // key derivation step. - let key = Secret(hmac_sha512(e1e1.as_bytes(), key.as_bytes())); - - let hmac = hmac_sha384(kbkdf512(key.as_bytes(), KBKDF_KEY_USAGE_LABEL_HMAC).first_n::<48>(), &buffer[..reply_size]); - buffer[reply_size..reply_size + HMAC_SIZE].copy_from_slice(&hmac); - reply_size += HMAC_SIZE; - - let mut state = session.state.write(); - let _ = state.remote_session_id.replace(alice_session_id); - state.keys[1].replace(SessionKey::new(key, Role::Bob, current_time, counter, jedi)); - drop(state); - - // Bob now has final key state for this exchange. Yay! Now reply to Alice so she can construct it. - - session.outgoing_obfuscator.0.encrypt_block_in_place(&mut buffer[0..16]); - session.outgoing_obfuscator.0.encrypt_block_in_place(&mut buffer[16..32]); - session.outgoing_obfuscator.0.encrypt_block_in_place(&mut buffer[32..48]); - session.outgoing_obfuscator.0.encrypt_block_in_place(&mut buffer[48..64]); - - return new_session.map_or_else(|| Ok(ReceiveResult::OkSendReply(&buffer[..reply_size])), |ns| Ok(ReceiveResult::OkNewSession(ns, &buffer[..reply_size]))); - } - - PACKET_TYPE_KEY_COUNTER_OFFER => { - // bob (remote) -> alice (local) - - if let Some(session) = session { - let state = session.state.upgradable_read(); - if let Some(offer) = state.offer.as_ref() { - let (bob_e0_public, e0e0) = P384PublicKey::from_bytes(&buffer[HEADER_SIZE..(HEADER_SIZE + P384_PUBLIC_KEY_SIZE)]) - .and_then(|pk| offer.alice_e0_keypair.agree(&pk).map(move |s| (pk, s))) - .ok_or(Error::FailedAuthentication)?; - let se0 = local_s_keypair_p384.agree(&bob_e0_public).ok_or(Error::FailedAuthentication)?; - - let key = Secret(hmac_sha512( - session.psk.as_bytes(), - &hmac_sha512(&hmac_sha512(&hmac_sha512(offer.key.as_bytes(), bob_e0_public.as_bytes()), e0e0.as_bytes()), se0.as_bytes()), - )); - - let original_ciphertext = buffer.clone(); - let mut c = AesGcm::new(kbkdf512(key.as_bytes(), KBKDF_KEY_USAGE_LABEL_AES_GCM_BOB_TO_ALICE).first_n::<32>(), false); - c.init(&get_aes_gcm_nonce(buffer)); - c.crypt_in_place(&mut buffer[(HEADER_SIZE + P384_PUBLIC_KEY_SIZE)..payload_end]); - let c = c.finish(); - if !c.eq(&buffer[payload_end..aes_gcm_tag_end]) { + // Important! Check to make sure the caller's public identity matches the one for this session. + if let Some(session) = session.as_ref() { + if !session.remote_s_public_hash.eq(&SHA384::hash(&alice_s_public)) { return Err(Error::FailedAuthentication); } + } - // Alice has now completed Noise_IK for P-384 and verified with GCM auth, now for the hybrid add-on. + let alice_s_public_p384 = extract_p384_static_public(&alice_s_public).ok_or(Error::InvalidPacket)?; + let ss = local_s_keypair_p384.agree(&alice_s_public_p384).ok_or(Error::FailedAuthentication)?; - let (bob_session_id, bob_e1_public) = parse_KEY_COUNTER_OFFER_after_header(&buffer[(HEADER_SIZE + P384_PUBLIC_KEY_SIZE)..payload_end])?; + let key = Secret(hmac_sha512(key.as_bytes(), ss.as_bytes())); - let e1e1 = if jedi && bob_e1_public.is_some() && offer.alice_e1_keypair.is_some() { - if let Ok(e1e1) = pqc_kyber::decapsulate(bob_e1_public.as_ref().unwrap(), &offer.alice_e1_keypair.as_ref().unwrap().secret) { - Secret(e1e1) - } else { + if !hmac_sha384(kbkdf512(key.as_bytes(), KBKDF_KEY_USAGE_LABEL_HMAC).first_n::<48>(), &original_ciphertext[..aes_gcm_tag_end]).eq(&buffer[aes_gcm_tag_end..incoming_packet.len()]) { + return Err(Error::FailedAuthentication); + } + + // Alice's offer has been verified and her current key state reconstructed. + + let bob_e0_keypair = P384KeyPair::generate(); + let e0e0 = bob_e0_keypair.agree(&alice_e0_public).ok_or(Error::FailedAuthentication)?; + let se0 = bob_e0_keypair.agree(&alice_s_public_p384).ok_or(Error::FailedAuthentication)?; + + let new_session = if session.is_some() { + None + } else { + if let Some((local_session_id, psk, associated_object)) = new_session_auth(&alice_s_public) { + Some(Session:: { + id: local_session_id, + send_counter: Counter::new(), + remote_s_public_hash: SHA384::hash(&alice_s_public), + psk, + ss, + outgoing_obfuscator: Obfuscator::new(&alice_s_public), + state: RwLock::new(MutableState { + remote_session_id: Some(alice_session_id), + keys: [None, None], + offer: None, + }), + remote_s_public_p384: alice_s_public_p384.as_bytes().clone(), + associated_object, + }) + } else { + return Err(Error::NewSessionRejected); + } + }; + let session_ref = session; + let session = session_ref.as_ref().map_or_else(|| new_session.as_ref().unwrap(), |s| &*s); + + // FIPS note: the order of HMAC parameters are flipped here from the usual Noise HMAC(key, X). That's because + // NIST/FIPS allows HKDF with HMAC(salt, key) and salt is allowed to be anything. This way if the PSK is not + // FIPS compliant the compliance of the entire key derivation is not invalidated. Both inputs are secrets of + // fixed size so this shouldn't matter cryptographically. + let key = Secret(hmac_sha512( + session.psk.as_bytes(), + &hmac_sha512(&hmac_sha512(&hmac_sha512(key.as_bytes(), bob_e0_keypair.public_key_bytes()), e0e0.as_bytes()), se0.as_bytes()), + )); + + // At this point we've completed Noise_IK key derivation with NIST P-384 ECDH, but see final step below... + + let (bob_e1_public, e1e1) = if jedi && alice_e1_public.is_some() { + if let Ok((bob_e1_public, e1e1)) = pqc_kyber::encapsulate(alice_e1_public.as_ref().unwrap(), &mut random::SecureRandom::default()) { + (Some(bob_e1_public), Secret(e1e1)) + } else { + return Err(Error::FailedAuthentication); + } + } else { + (None, Secret::default()) // use all zero Kyber secret if disabled + }; + + let counter = session.send_counter.next(); + let mut reply_size = assemble_KEY_COUNTER_OFFER(buffer, counter, alice_session_id, bob_e0_keypair.public_key(), session.id, bob_e1_public.as_ref()); + + let mut c = AesGcm::new(kbkdf512(key.as_bytes(), KBKDF_KEY_USAGE_LABEL_AES_GCM_BOB_TO_ALICE).first_n::<32>(), true); + c.init(&get_aes_gcm_nonce(buffer)); + c.crypt_in_place(&mut buffer[(HEADER_SIZE + P384_PUBLIC_KEY_SIZE)..reply_size]); + let c = c.finish(); + buffer[reply_size..(reply_size + AES_GCM_TAG_SIZE)].copy_from_slice(&c); + reply_size += AES_GCM_TAG_SIZE; + + // Normal Noise_IK is done, but we have one more step: mix in the Kyber shared secret (or all zeroes if Kyber is + // disabled). We have to wait until this point because Kyber's keys are encrypted and can't be decrypted until + // the P-384 exchange is done. We also flip the HMAC parameter order here for the same reason we do in the previous + // key derivation step. + let key = Secret(hmac_sha512(e1e1.as_bytes(), key.as_bytes())); + + let hmac = hmac_sha384(kbkdf512(key.as_bytes(), KBKDF_KEY_USAGE_LABEL_HMAC).first_n::<48>(), &buffer[..reply_size]); + buffer[reply_size..reply_size + HMAC_SIZE].copy_from_slice(&hmac); + reply_size += HMAC_SIZE; + + let mut state = session.state.write(); + let _ = state.remote_session_id.replace(alice_session_id); + state.keys[1].replace(SessionKey::new(key, Role::Bob, current_time, counter, jedi)); + drop(state); + + // Bob now has final key state for this exchange. Yay! Now reply to Alice so she can construct it. + + session.outgoing_obfuscator.0.encrypt_block_in_place(&mut buffer[0..16]); + session.outgoing_obfuscator.0.encrypt_block_in_place(&mut buffer[16..32]); + session.outgoing_obfuscator.0.encrypt_block_in_place(&mut buffer[32..48]); + session.outgoing_obfuscator.0.encrypt_block_in_place(&mut buffer[48..64]); + + return new_session.map_or_else(|| Ok(ReceiveResult::OkSendReply(&buffer[..reply_size])), |ns| Ok(ReceiveResult::OkNewSession(ns, &buffer[..reply_size]))); + } + + PACKET_TYPE_KEY_COUNTER_OFFER => { + // bob (remote) -> alice (local) + + if let Some(session) = session { + let state = session.state.upgradable_read(); + if let Some(offer) = state.offer.as_ref() { + let (bob_e0_public, e0e0) = P384PublicKey::from_bytes(&buffer[HEADER_SIZE..(HEADER_SIZE + P384_PUBLIC_KEY_SIZE)]) + .and_then(|pk| offer.alice_e0_keypair.agree(&pk).map(move |s| (pk, s))) + .ok_or(Error::FailedAuthentication)?; + let se0 = local_s_keypair_p384.agree(&bob_e0_public).ok_or(Error::FailedAuthentication)?; + + let key = Secret(hmac_sha512( + session.psk.as_bytes(), + &hmac_sha512(&hmac_sha512(&hmac_sha512(offer.key.as_bytes(), bob_e0_public.as_bytes()), e0e0.as_bytes()), se0.as_bytes()), + )); + + let original_ciphertext = buffer.clone(); + let mut c = AesGcm::new(kbkdf512(key.as_bytes(), KBKDF_KEY_USAGE_LABEL_AES_GCM_BOB_TO_ALICE).first_n::<32>(), false); + c.init(&get_aes_gcm_nonce(buffer)); + c.crypt_in_place(&mut buffer[(HEADER_SIZE + P384_PUBLIC_KEY_SIZE)..payload_end]); + let c = c.finish(); + if !c.eq(&buffer[payload_end..aes_gcm_tag_end]) { return Err(Error::FailedAuthentication); } - } else { - Secret::default() - }; - let key = Secret(hmac_sha512(e1e1.as_bytes(), key.as_bytes())); + // Alice has now completed Noise_IK for P-384 and verified with GCM auth, now for the hybrid add-on. - if !hmac_sha384(kbkdf512(key.as_bytes(), KBKDF_KEY_USAGE_LABEL_HMAC).first_n::<48>(), &original_ciphertext[..aes_gcm_tag_end]).eq(&buffer[aes_gcm_tag_end..incoming_packet.len()]) { - return Err(Error::FailedAuthentication); - } + let (bob_session_id, bob_e1_public) = parse_KEY_COUNTER_OFFER_after_header(&buffer[(HEADER_SIZE + P384_PUBLIC_KEY_SIZE)..payload_end])?; - // Alice has now completed and validated the full hybrid exchange. If this is the first exchange send - // a NOP back to Bob to acknowledge that the session is open and can now be used. Otherwise just queue - // this up as the next key to be promoted to current when Bob uses it. + let e1e1 = if jedi && bob_e1_public.is_some() && offer.alice_e1_keypair.is_some() { + if let Ok(e1e1) = pqc_kyber::decapsulate(bob_e1_public.as_ref().unwrap(), &offer.alice_e1_keypair.as_ref().unwrap().secret) { + Secret(e1e1) + } else { + return Err(Error::FailedAuthentication); + } + } else { + Secret::default() + }; - let mut state = RwLockUpgradableReadGuard::upgrade(state); - let _ = state.offer.take(); - let _ = state.remote_session_id.replace(bob_session_id); - if state.keys[0].is_some() { - let _ = state.keys[1].replace(SessionKey::new(key, Role::Alice, current_time, session.send_counter.current(), jedi)); - return Ok(ReceiveResult::Ok); - } else { - let counter = session.send_counter.next(); - let key = SessionKey::new(key, Role::Alice, current_time, counter, jedi); + let key = Secret(hmac_sha512(e1e1.as_bytes(), key.as_bytes())); - let dummy_data_len = (random::next_u32_secure() % (MAX_PACKET_SIZE - (HEADER_SIZE + AES_GCM_TAG_SIZE)) as u32) as usize; - let mut dummy_data = [0_u8; MAX_PACKET_SIZE]; - random::fill_bytes_secure(&mut dummy_data[..dummy_data_len]); - let nop_len = assemble_and_armor_DATA(buffer, &dummy_data[..dummy_data_len], PACKET_TYPE_NOP, u64::from(bob_session_id), counter, &key, &session.outgoing_obfuscator)?; + if !hmac_sha384(kbkdf512(key.as_bytes(), KBKDF_KEY_USAGE_LABEL_HMAC).first_n::<48>(), &original_ciphertext[..aes_gcm_tag_end]).eq(&buffer[aes_gcm_tag_end..incoming_packet.len()]) { + return Err(Error::FailedAuthentication); + } - let _ = state.keys[0].replace(key); - let _ = state.keys[1].take(); + // Alice has now completed and validated the full hybrid exchange. If this is the first exchange send + // a NOP back to Bob to acknowledge that the session is open and can now be used. Otherwise just queue + // this up as the next key to be promoted to current when Bob uses it. - return Ok(ReceiveResult::OkSendReply(&buffer[..nop_len])); + let mut state = RwLockUpgradableReadGuard::upgrade(state); + let _ = state.offer.take(); + let _ = state.remote_session_id.replace(bob_session_id); + if state.keys[0].is_some() { + let _ = state.keys[1].replace(SessionKey::new(key, Role::Alice, current_time, session.send_counter.current(), jedi)); + return Ok(ReceiveResult::Ok); + } else { + let counter = session.send_counter.next(); + let key = SessionKey::new(key, Role::Alice, current_time, counter, jedi); + + let dummy_data_len = (random::next_u32_secure() % (MAX_PACKET_SIZE - (HEADER_SIZE + AES_GCM_TAG_SIZE)) as u32) as usize; + let mut dummy_data = [0_u8; MAX_PACKET_SIZE]; + random::fill_bytes_secure(&mut dummy_data[..dummy_data_len]); + let nop_len = assemble_and_armor_DATA(buffer, &dummy_data[..dummy_data_len], PACKET_TYPE_NOP, u64::from(bob_session_id), counter, &key, &session.outgoing_obfuscator)?; + + let _ = state.keys[0].replace(key); + let _ = state.keys[1].take(); + + return Ok(ReceiveResult::OkSendReply(&buffer[..nop_len])); + } } } + + // Just ignore counter-offers that are out of place. They probably indicate that this side + // restarted and needs to establish a new session. + return Ok(ReceiveResult::Ignored); } - // Just ignore counter-offers that are out of place. They probably indicate that this side - // restarted and needs to establish a new session. - return Ok(ReceiveResult::Ignored); + _ => return Err(Error::InvalidPacket), } - - _ => return Err(Error::InvalidPacket), } } } @@ -845,10 +857,10 @@ impl SessionKey { #[allow(non_snake_case)] fn assemble_and_armor_DATA(buffer: &mut [u8; MAX_PACKET_SIZE], data: &[u8], packet_type: u8, remote_session_id: u64, counter: CounterValue, key: &SessionKey, outgoing_obfuscator: &Obfuscator) -> Result { - buffer[0..4].copy_from_slice(&counter.to_bytes()); - buffer[4..10].copy_from_slice(&remote_session_id.to_le_bytes()[..SESSION_ID_SIZE]); debug_assert!(packet_type == PACKET_TYPE_DATA || packet_type == PACKET_TYPE_NOP); - buffer[10] = packet_type; + buffer[0] = packet_type; + buffer[1..7].copy_from_slice(&remote_session_id.to_le_bytes()[..SESSION_ID_SIZE]); + buffer[7..11].copy_from_slice(&counter.to_bytes()); let payload_end = HEADER_SIZE + data.len(); let tag_end = payload_end + AES_GCM_TAG_SIZE; @@ -889,9 +901,9 @@ fn assemble_KEY_OFFER, ) -> usize { - buffer[0..4].copy_from_slice(&counter.to_bytes()); - buffer[4..10].copy_from_slice(&bob_session_id.map_or(0_u64, |i| i.into()).to_le_bytes()[..SESSION_ID_SIZE]); - buffer[10] = PACKET_TYPE_KEY_OFFER; + buffer[0] = PACKET_TYPE_KEY_OFFER; + buffer[1..7].copy_from_slice(&bob_session_id.map_or(0_u64, |i| i.into()).to_le_bytes()[..SESSION_ID_SIZE]); + buffer[7..11].copy_from_slice(&counter.to_bytes()); let mut b = &mut buffer[HEADER_SIZE..]; b[..P384_PUBLIC_KEY_SIZE].copy_from_slice(alice_e0_public.as_bytes()); @@ -961,9 +973,9 @@ fn assemble_KEY_COUNTER_OFFER( bob_session_id: SessionId, bob_e1_public: Option<&[u8; pqc_kyber::KYBER_CIPHERTEXTBYTES]>, ) -> usize { - buffer[0..4].copy_from_slice(&counter.to_bytes()); - alice_session_id.copy_to(&mut buffer[4..10]); - buffer[10] = PACKET_TYPE_KEY_COUNTER_OFFER; + buffer[0] = PACKET_TYPE_KEY_COUNTER_OFFER; + alice_session_id.copy_to(&mut buffer[1..7]); + buffer[7..11].copy_from_slice(&counter.to_bytes()); let mut b = &mut buffer[HEADER_SIZE..]; b[..P384_PUBLIC_KEY_SIZE].copy_from_slice(bob_e0_public.as_bytes()); @@ -1053,7 +1065,7 @@ mod tests { let mut from_bob: Vec> = Vec::new(); // Session TO Bob, on Alice's side. - let (alice, packet) = new_session( + let (alice, packet) = Session::new( &mut a_buffer, SessionId::new_random(), alice_static_keypair.public_key_bytes(), @@ -1075,7 +1087,7 @@ mod tests { for _ in 0..256 { while !from_alice.is_empty() || !from_bob.is_empty() { if let Some(packet) = from_alice.pop() { - let r = receive( + let r = Session::receive( packet.as_slice(), &mut b_buffer, &bob_static_keypair, @@ -1138,7 +1150,7 @@ mod tests { } if let Some(packet) = from_bob.pop() { - let r = receive( + let r = Session::receive( packet.as_slice(), &mut b_buffer, &alice_static_keypair, diff --git a/network-hypervisor/src/vl1/node.rs b/network-hypervisor/src/vl1/node.rs index 6baed36bf..0f4f81b38 100644 --- a/network-hypervisor/src/vl1/node.rs +++ b/network-hypervisor/src/vl1/node.rs @@ -102,11 +102,8 @@ pub trait InnerProtocolInterface: Sync + Send + 'static { /// Handle an OK, returing true if the OK was recognized. async fn handle_ok(&self, source: &Peer, source_path: &Path, in_re_verb: u8, in_re_message_id: u64, payload: &PacketBuffer, cursor: &mut usize) -> bool; - /// Check if this remote peer has a trust relationship with this node. - /// - /// This is checked to determine if we should do things like make direct links or respond to - /// various other VL1 messages. - fn has_trust_relationship(&self, id: &Identity) -> bool; + /// Check if this peer should communicate with another at all. + fn should_communicate_with(&self, id: &Identity) -> bool; } /// How often to check the root cluster definitions against the root list and update. diff --git a/network-hypervisor/src/vl1/peer.rs b/network-hypervisor/src/vl1/peer.rs index ce07dab26..a357b3939 100644 --- a/network-hypervisor/src/vl1/peer.rs +++ b/network-hypervisor/src/vl1/peer.rs @@ -75,13 +75,7 @@ pub struct Peer { } /// Attempt AEAD packet encryption and MAC validation. Returns message ID on success. -fn try_aead_decrypt( - secret: &SymmetricSecret, - packet_frag0_payload_bytes: &[u8], - packet_header: &PacketHeader, - fragments: &[Option], - payload: &mut PacketBuffer, -) -> Option { +fn try_aead_decrypt(secret: &SymmetricSecret, packet_frag0_payload_bytes: &[u8], packet_header: &PacketHeader, fragments: &[Option], payload: &mut PacketBuffer) -> Option { let cipher = packet_header.cipher(); match cipher { security_constants::CIPHER_NOCRYPT_POLY1305 | security_constants::CIPHER_SALSA2012_POLY1305 => { @@ -279,13 +273,7 @@ impl Peer { match &p.endpoint { Endpoint::IpUdp(existing_ip) => { if existing_ip.ip_bytes().eq(new_ip.ip_bytes()) { - debug_event!( - si, - "[vl1] {} replacing path {} with {} (same IP, different port)", - self.identity.address.to_string(), - p.endpoint.to_string(), - new_path.endpoint.to_string() - ); + debug_event!(si, "[vl1] {} replacing path {} with {} (same IP, different port)", self.identity.address.to_string(), p.endpoint.to_string(), new_path.endpoint.to_string()); pi.path = Arc::downgrade(new_path); pi.canonical_instance_id = new_path.canonical.canonical_instance_id(); pi.last_receive_time_ticks = time_ticks; @@ -332,15 +320,7 @@ impl Peer { /// /// This does not set the fragmentation field in the packet header, MAC, or encrypt the packet. The sender /// must do that while building the packet. The fragmentation flag must be set if fragmentation will be needed. - async fn internal_send( - &self, - si: &SI, - endpoint: &Endpoint, - local_socket: Option<&SI::LocalSocket>, - local_interface: Option<&SI::LocalInterface>, - max_fragment_size: usize, - packet: &PacketBuffer, - ) -> bool { + async fn internal_send(&self, si: &SI, endpoint: &Endpoint, local_socket: Option<&SI::LocalSocket>, local_interface: Option<&SI::LocalInterface>, max_fragment_size: usize, packet: &PacketBuffer) -> bool { let packet_size = packet.len(); if packet_size > max_fragment_size { let bytes = packet.as_bytes(); @@ -350,8 +330,7 @@ impl Peer { let mut pos = UDP_DEFAULT_MTU; let overrun_size = (packet_size - UDP_DEFAULT_MTU) as u32; - let fragment_count = - (overrun_size / (UDP_DEFAULT_MTU - packet_constants::FRAGMENT_HEADER_SIZE) as u32) + (((overrun_size % (UDP_DEFAULT_MTU - packet_constants::FRAGMENT_HEADER_SIZE) as u32) != 0) as u32); + let fragment_count = (overrun_size / (UDP_DEFAULT_MTU - packet_constants::FRAGMENT_HEADER_SIZE) as u32) + (((overrun_size % (UDP_DEFAULT_MTU - packet_constants::FRAGMENT_HEADER_SIZE) as u32) != 0) as u32); debug_assert!(fragment_count <= packet_constants::FRAGMENT_COUNT_MAX as u32); let mut header = FragmentHeader { @@ -400,9 +379,16 @@ impl Peer { } }; - let max_fragment_size = if path.endpoint.requires_fragmentation() { UDP_DEFAULT_MTU } else { usize::MAX }; - let flags_cipher_hops = - if packet.len() > max_fragment_size { packet_constants::HEADER_FLAG_FRAGMENTED | security_constants::CIPHER_AES_GMAC_SIV } else { security_constants::CIPHER_AES_GMAC_SIV }; + let max_fragment_size = if path.endpoint.requires_fragmentation() { + UDP_DEFAULT_MTU + } else { + usize::MAX + }; + let flags_cipher_hops = if packet.len() > max_fragment_size { + packet_constants::HEADER_FLAG_FRAGMENTED | security_constants::CIPHER_AES_GMAC_SIV + } else { + security_constants::CIPHER_AES_GMAC_SIV + }; let mut aes_gmac_siv = self.identity_symmetric_key.aes_gmac_siv.get(); aes_gmac_siv.encrypt_init(&self.next_message_id().to_ne_bytes()); @@ -481,7 +467,11 @@ impl Peer { } }; - let max_fragment_size = if destination.requires_fragmentation() { UDP_DEFAULT_MTU } else { usize::MAX }; + let max_fragment_size = if destination.requires_fragmentation() { + UDP_DEFAULT_MTU + } else { + usize::MAX + }; let time_ticks = si.time_ticks(); let mut packet = PacketBuffer::new(); @@ -532,17 +522,7 @@ impl Peer { /// those fragments after the main packet header and first chunk. /// /// This returns true if the packet decrypted and passed authentication. - pub(crate) async fn receive( - &self, - node: &Node, - si: &SI, - ph: &PH, - time_ticks: i64, - source_path: &Arc>, - packet_header: &PacketHeader, - frag0: &PacketBuffer, - fragments: &[Option], - ) -> bool { + pub(crate) async fn receive(&self, node: &Node, si: &SI, ph: &PH, time_ticks: i64, source_path: &Arc>, packet_header: &PacketHeader, frag0: &PacketBuffer, fragments: &[Option]) -> bool { if let Ok(packet_frag0_payload_bytes) = frag0.as_bytes_starting_at(packet_constants::VERB_INDEX) { let mut payload = PacketBuffer::new(); @@ -606,18 +586,8 @@ impl Peer { return false; } - async fn handle_incoming_hello( - &self, - si: &SI, - ph: &PH, - node: &Node, - time_ticks: i64, - message_id: MessageId, - source_path: &Arc>, - hops: u8, - payload: &PacketBuffer, - ) -> bool { - if !(ph.has_trust_relationship(&self.identity) || node.this_node_is_root() || node.is_peer_root(self)) { + async fn handle_incoming_hello(&self, si: &SI, ph: &PH, node: &Node, time_ticks: i64, message_id: MessageId, source_path: &Arc>, hops: u8, payload: &PacketBuffer) -> bool { + if !(ph.should_communicate_with(&self.identity) || node.this_node_is_root() || node.is_peer_root(self)) { debug_event!(si, "[vl1] dropping HELLO from {} due to lack of trust relationship", self.identity.address.to_string()); return true; // packet wasn't invalid, just ignored } @@ -629,9 +599,8 @@ impl Peer { { let mut remote_node_info = self.remote_node_info.write(); remote_node_info.remote_protocol_version = hello_fixed_headers.version_proto; - remote_node_info.remote_version = (hello_fixed_headers.version_major as u64).wrapping_shl(48) - | (hello_fixed_headers.version_minor as u64).wrapping_shl(32) - | (u16::from_be_bytes(hello_fixed_headers.version_revision) as u64).wrapping_shl(16); + remote_node_info.remote_version = + (hello_fixed_headers.version_major as u64).wrapping_shl(48) | (hello_fixed_headers.version_minor as u64).wrapping_shl(32) | (u16::from_be_bytes(hello_fixed_headers.version_revision) as u64).wrapping_shl(16); } let mut packet = PacketBuffer::new(); @@ -648,7 +617,14 @@ impl Peer { f.1.version_revision = VERSION_REVISION.to_be_bytes(); } if hello_fixed_headers.version_proto >= 20 { - let session_metadata = self.create_session_metadata(node, if hops == 0 { Some(&source_path.endpoint) } else { None }); + let session_metadata = self.create_session_metadata( + node, + if hops == 0 { + Some(&source_path.endpoint) + } else { + None + }, + ); assert!(session_metadata.len() <= 0xffff); // sanity check, should be impossible assert!(packet.append_u16(session_metadata.len() as u16).is_ok()); assert!(packet.append_bytes(session_metadata.as_slice()).is_ok()); @@ -676,17 +652,7 @@ impl Peer { return false; } - async fn handle_incoming_ok( - &self, - si: &SI, - ph: &PH, - node: &Node, - time_ticks: i64, - source_path: &Arc>, - hops: u8, - path_is_known: bool, - payload: &PacketBuffer, - ) -> bool { + async fn handle_incoming_ok(&self, si: &SI, ph: &PH, node: &Node, time_ticks: i64, source_path: &Arc>, hops: u8, path_is_known: bool, payload: &PacketBuffer) -> bool { let mut cursor = 0; if let Ok(ok_header) = payload.read_struct::(&mut cursor) { let in_re_message_id: MessageId = u64::from_ne_bytes(ok_header.in_re_message_id); @@ -709,12 +675,7 @@ impl Peer { let reported_endpoint2 = reported_endpoint.clone(); if remote_node_info.reported_local_endpoints.insert(reported_endpoint, time_ticks).is_none() { #[cfg(debug_assertions)] - debug_event!( - si, - "[vl1] {} reported new remote perspective, local endpoint: {}", - self.identity.address.to_string(), - reported_endpoint2.to_string() - ); + debug_event!(si, "[vl1] {} reported new remote perspective, local endpoint: {}", self.identity.address.to_string(), reported_endpoint2.to_string()); } } } @@ -797,7 +758,7 @@ impl Peer { } async fn handle_incoming_whois(&self, si: &SI, ph: &PH, node: &Node, time_ticks: i64, message_id: MessageId, payload: &PacketBuffer) -> bool { - if node.this_node_is_root() || ph.has_trust_relationship(&self.identity) { + if node.this_node_is_root() || ph.should_communicate_with(&self.identity) { let mut packet = PacketBuffer::new(); packet.set_size(packet_constants::HEADER_SIZE); { @@ -832,7 +793,7 @@ impl Peer { } async fn handle_incoming_echo(&self, si: &SI, ph: &PH, node: &Node, time_ticks: i64, message_id: MessageId, payload: &PacketBuffer) -> bool { - if ph.has_trust_relationship(&self.identity) || node.is_peer_root(self) { + if ph.should_communicate_with(&self.identity) || node.is_peer_root(self) { let mut packet = PacketBuffer::new(); packet.set_size(packet_constants::HEADER_SIZE); { diff --git a/network-hypervisor/src/vl2/networkid.rs b/network-hypervisor/src/vl2/networkid.rs index 6d80ad8b0..e8060ca30 100644 --- a/network-hypervisor/src/vl2/networkid.rs +++ b/network-hypervisor/src/vl2/networkid.rs @@ -39,10 +39,19 @@ impl NetworkId { pub fn to_bytes(&self) -> [u8; 8] { self.0.get().to_be_bytes() } +} +impl From for u64 { #[inline(always)] - pub fn to_u64(&self) -> u64 { - self.0.get() + fn from(v: NetworkId) -> Self { + v.0.get() + } +} + +impl From<&NetworkId> for u64 { + #[inline(always)] + fn from(v: &NetworkId) -> Self { + v.0.get() } } diff --git a/network-hypervisor/src/vl2/switch.rs b/network-hypervisor/src/vl2/switch.rs index 5b883c258..3f90f8b2e 100644 --- a/network-hypervisor/src/vl2/switch.rs +++ b/network-hypervisor/src/vl2/switch.rs @@ -18,16 +18,7 @@ impl InnerProtocolInterface for Switch { } #[allow(unused)] - async fn handle_error( - &self, - peer: &Peer, - source_path: &Path, - in_re_verb: u8, - in_re_message_id: u64, - error_code: u8, - payload: &PacketBuffer, - cursor: &mut usize, - ) -> bool { + async fn handle_error(&self, peer: &Peer, source_path: &Path, in_re_verb: u8, in_re_message_id: u64, error_code: u8, payload: &PacketBuffer, cursor: &mut usize) -> bool { false } @@ -37,7 +28,7 @@ impl InnerProtocolInterface for Switch { } #[allow(unused)] - fn has_trust_relationship(&self, id: &Identity) -> bool { + fn should_communicate_with(&self, id: &Identity) -> bool { true } }