Prep for new controller, also reorg header fields in Noise session and move some functions around.

This commit is contained in:
Adam Ierymenko 2022-08-19 11:31:09 -04:00
parent f153d43797
commit a723403fe9
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
5 changed files with 384 additions and 414 deletions

View file

@ -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<O> {
psk: Secret<64>,
ss: Secret<48>,
outgoing_obfuscator: Obfuscator,
state: RwLock<State>,
state: RwLock<MutableState>,
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<SessionId>,
keys: [Option<SessionKey>; 2], // current, next
offer: Option<EphemeralOffer>,
}
impl<O> Session<O> {
/// 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::<O> {
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<O> Session<O> {
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<O>, &'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::<O> {
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<P384PublicKey>,
SessionLookupFunction: FnOnce(SessionId) -> Option<S>,
NewSessionAuthenticatorFunction: FnOnce(&[u8; STATIC_PUBLIC_SIZE]) -> Option<(SessionId, Secret<64>, O)>,
S: std::ops::Deref<Target = Session<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<ReceiveResult<'a, O>, 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<P384PublicKey>,
SessionLookupFunction: FnOnce(SessionId) -> Option<S>,
NewSessionAuthenticatorFunction: FnOnce(&[u8; STATIC_PUBLIC_SIZE]) -> Option<(SessionId, Secret<64>, O)>,
S: std::ops::Deref<Target = Session<O>>,
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<ReceiveResult<'a, O>, 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::<O> {
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::<O> {
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<const MAX_PACKET_SIZE: usize>(buffer: &mut [u8; MAX_PACKET_SIZE], data: &[u8], packet_type: u8, remote_session_id: u64, counter: CounterValue, key: &SessionKey, outgoing_obfuscator: &Obfuscator) -> Result<usize, Error> {
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<const MAX_PACKET_SIZE: usize, const STATIC_PUBLIC_SIZE: us
alice_s_public: &[u8; STATIC_PUBLIC_SIZE],
alice_e1_public: Option<&[u8; pqc_kyber::KYBER_PUBLICKEYBYTES]>,
) -> 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<const MAX_PACKET_SIZE: usize>(
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<u8>> = 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,

View file

@ -102,11 +102,8 @@ pub trait InnerProtocolInterface: Sync + Send + 'static {
/// Handle an OK, returing true if the OK was recognized.
async fn handle_ok<SI: SystemInterface>(&self, source: &Peer<SI>, source_path: &Path<SI>, 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.

View file

@ -75,13 +75,7 @@ pub struct Peer<SI: SystemInterface> {
}
/// 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<PooledPacketBuffer>],
payload: &mut PacketBuffer,
) -> Option<MessageId> {
fn try_aead_decrypt(secret: &SymmetricSecret, packet_frag0_payload_bytes: &[u8], packet_header: &PacketHeader, fragments: &[Option<PooledPacketBuffer>], payload: &mut PacketBuffer) -> Option<MessageId> {
let cipher = packet_header.cipher();
match cipher {
security_constants::CIPHER_NOCRYPT_POLY1305 | security_constants::CIPHER_SALSA2012_POLY1305 => {
@ -279,13 +273,7 @@ impl<SI: SystemInterface> Peer<SI> {
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<SI: SystemInterface> Peer<SI> {
///
/// 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<SI: SystemInterface> Peer<SI> {
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<SI: SystemInterface> Peer<SI> {
}
};
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<SI: SystemInterface> Peer<SI> {
}
};
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<SI: SystemInterface> Peer<SI> {
/// 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<PH: InnerProtocolInterface>(
&self,
node: &Node<SI>,
si: &SI,
ph: &PH,
time_ticks: i64,
source_path: &Arc<Path<SI>>,
packet_header: &PacketHeader,
frag0: &PacketBuffer,
fragments: &[Option<PooledPacketBuffer>],
) -> bool {
pub(crate) async fn receive<PH: InnerProtocolInterface>(&self, node: &Node<SI>, si: &SI, ph: &PH, time_ticks: i64, source_path: &Arc<Path<SI>>, packet_header: &PacketHeader, frag0: &PacketBuffer, fragments: &[Option<PooledPacketBuffer>]) -> 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<SI: SystemInterface> Peer<SI> {
return false;
}
async fn handle_incoming_hello<PH: InnerProtocolInterface>(
&self,
si: &SI,
ph: &PH,
node: &Node<SI>,
time_ticks: i64,
message_id: MessageId,
source_path: &Arc<Path<SI>>,
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<PH: InnerProtocolInterface>(&self, si: &SI, ph: &PH, node: &Node<SI>, time_ticks: i64, message_id: MessageId, source_path: &Arc<Path<SI>>, 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<SI: SystemInterface> Peer<SI> {
{
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<SI: SystemInterface> Peer<SI> {
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<SI: SystemInterface> Peer<SI> {
return false;
}
async fn handle_incoming_ok<PH: InnerProtocolInterface>(
&self,
si: &SI,
ph: &PH,
node: &Node<SI>,
time_ticks: i64,
source_path: &Arc<Path<SI>>,
hops: u8,
path_is_known: bool,
payload: &PacketBuffer,
) -> bool {
async fn handle_incoming_ok<PH: InnerProtocolInterface>(&self, si: &SI, ph: &PH, node: &Node<SI>, time_ticks: i64, source_path: &Arc<Path<SI>>, hops: u8, path_is_known: bool, payload: &PacketBuffer) -> bool {
let mut cursor = 0;
if let Ok(ok_header) = payload.read_struct::<message_component_structs::OkHeader>(&mut cursor) {
let in_re_message_id: MessageId = u64::from_ne_bytes(ok_header.in_re_message_id);
@ -709,12 +675,7 @@ impl<SI: SystemInterface> Peer<SI> {
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<SI: SystemInterface> Peer<SI> {
}
async fn handle_incoming_whois<PH: InnerProtocolInterface>(&self, si: &SI, ph: &PH, node: &Node<SI>, 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<SI: SystemInterface> Peer<SI> {
}
async fn handle_incoming_echo<PH: InnerProtocolInterface>(&self, si: &SI, ph: &PH, node: &Node<SI>, 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);
{

View file

@ -39,10 +39,19 @@ impl NetworkId {
pub fn to_bytes(&self) -> [u8; 8] {
self.0.get().to_be_bytes()
}
}
impl From<NetworkId> 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()
}
}

View file

@ -18,16 +18,7 @@ impl InnerProtocolInterface for Switch {
}
#[allow(unused)]
async fn handle_error<SI: SystemInterface>(
&self,
peer: &Peer<SI>,
source_path: &Path<SI>,
in_re_verb: u8,
in_re_message_id: u64,
error_code: u8,
payload: &PacketBuffer,
cursor: &mut usize,
) -> bool {
async fn handle_error<SI: SystemInterface>(&self, peer: &Peer<SI>, source_path: &Path<SI>, 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
}
}