mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-07-25 11:42:50 +02:00
IT TALKS! (HELLO, OK)
This commit is contained in:
parent
37ccc44117
commit
7fa60b10a3
4 changed files with 83 additions and 61 deletions
|
@ -118,6 +118,9 @@ impl<const ROUNDS: usize> Salsa<ROUNDS> {
|
|||
x14 = x14.wrapping_add(j14);
|
||||
x15 = x15.wrapping_add(j15);
|
||||
|
||||
j8 = j8.wrapping_add(1);
|
||||
j9 = j9.wrapping_add((j8 == 0) as u32);
|
||||
|
||||
if plaintext.len() >= 64 {
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))]
|
||||
{
|
||||
|
@ -162,9 +165,6 @@ impl<const ROUNDS: usize> Salsa<ROUNDS> {
|
|||
ciphertext[60..64].copy_from_slice(&(u32::from_ne_bytes(unsafe { *plaintext.as_ptr().add(60).cast::<[u8; 4]>() }) ^ x15.to_le()).to_ne_bytes());
|
||||
}
|
||||
|
||||
j8 = j8.wrapping_add(1);
|
||||
j9 = j9.wrapping_add((j8 == 0) as u32);
|
||||
|
||||
plaintext = &plaintext[64..];
|
||||
ciphertext = &mut ciphertext[64..];
|
||||
} else {
|
||||
|
|
|
@ -80,61 +80,68 @@ fn salsa_poly_create(secret: &SymmetricSecret, header: &PacketHeader, packet_siz
|
|||
}
|
||||
|
||||
/// Attempt AEAD packet encryption and MAC validation. Returns message ID on success.
|
||||
fn try_aead_decrypt(secret: &SymmetricSecret, packet_frag0_payload_bytes: &[u8], header: &PacketHeader, fragments: &[Option<PooledPacketBuffer>], payload: &mut PacketBuffer) -> Option<MessageId> {
|
||||
packet_frag0_payload_bytes.get(0).map_or(None, |verb| {
|
||||
let cipher = header.cipher();
|
||||
match cipher {
|
||||
security_constants::CIPHER_NOCRYPT_POLY1305 | security_constants::CIPHER_SALSA2012_POLY1305 => {
|
||||
if (verb & packet_constants::VERB_MASK) == verbs::VL1_HELLO {
|
||||
let mut total_packet_len = packet_frag0_payload_bytes.len() + packet_constants::HEADER_SIZE;
|
||||
for f in fragments.iter() {
|
||||
total_packet_len += f.as_ref().map_or(0, |f| f.len());
|
||||
}
|
||||
let _ = payload.append_bytes(packet_frag0_payload_bytes);
|
||||
for f in fragments.iter() {
|
||||
let _ = f.as_ref().map(|f| f.as_bytes_starting_at(packet_constants::HEADER_SIZE).map(|f| payload.append_bytes(f)));
|
||||
}
|
||||
let (mut salsa, poly1305_key) = salsa_poly_create(secret, header, total_packet_len);
|
||||
let mac = zerotier_core_crypto::poly1305::compute(&poly1305_key, &payload.as_bytes());
|
||||
if mac[0..8].eq(&header.mac) {
|
||||
if cipher == security_constants::CIPHER_SALSA2012_POLY1305 {
|
||||
salsa.crypt_in_place(payload.as_bytes_mut());
|
||||
}
|
||||
Some(u64::from_ne_bytes(header.id))
|
||||
} else {
|
||||
None
|
||||
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 => {
|
||||
let _ = payload.append_bytes(packet_frag0_payload_bytes);
|
||||
for f in fragments.iter() {
|
||||
if let Some(f) = f.as_ref() {
|
||||
if let Ok(f) = f.as_bytes_starting_at(packet_constants::FRAGMENT_HEADER_SIZE) {
|
||||
let _ = payload.append_bytes(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (mut salsa, poly1305_key) = salsa_poly_create(secret, packet_header, payload.len() + packet_constants::HEADER_SIZE);
|
||||
let mac = zerotier_core_crypto::poly1305::compute(&poly1305_key, &payload.as_bytes());
|
||||
if mac[0..8].eq(&packet_header.mac) {
|
||||
let message_id = u64::from_ne_bytes(packet_header.id);
|
||||
if cipher == security_constants::CIPHER_SALSA2012_POLY1305 {
|
||||
salsa.crypt_in_place(payload.as_bytes_mut());
|
||||
Some(message_id)
|
||||
} else if (payload.u8_at(0).unwrap_or(0) & packet_constants::VERB_MASK) == verbs::VL1_HELLO {
|
||||
Some(message_id)
|
||||
} else {
|
||||
// Only HELLO is permitted without payload encryption. Drop other packet types if sent this way.
|
||||
// SECURITY: fail if there is no encryption and the message is not HELLO. No other types are allowed
|
||||
// to be sent without full packet encryption.
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
security_constants::CIPHER_AES_GMAC_SIV => {
|
||||
let mut aes = secret.aes_gmac_siv.get();
|
||||
aes.decrypt_init(&header.aes_gmac_siv_tag());
|
||||
aes.decrypt_set_aad(&header.aad_bytes());
|
||||
// NOTE: if there are somehow missing fragments this part will silently fail,
|
||||
// but the packet will fail MAC check in decrypt_finish() so meh.
|
||||
let _ = payload.append_bytes_get_mut(packet_frag0_payload_bytes.len()).map(|b| aes.decrypt(packet_frag0_payload_bytes, b));
|
||||
for f in fragments.iter() {
|
||||
f.as_ref().map(|f| {
|
||||
f.as_bytes_starting_at(packet_constants::FRAGMENT_HEADER_SIZE).map(|f| {
|
||||
let _ = payload.append_bytes_get_mut(f.len()).map(|b| aes.decrypt(f, b));
|
||||
})
|
||||
});
|
||||
}
|
||||
aes.decrypt_finish().map_or(None, |tag| {
|
||||
// AES-GMAC-SIV encrypts the packet ID too as part of its computation of a single
|
||||
// opaque 128-bit tag, so to get the original packet ID we have to grab it from the
|
||||
// decrypted tag.
|
||||
Some(u64::from_ne_bytes(*byte_array_range::<16, 0, 8>(tag)))
|
||||
})
|
||||
}
|
||||
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
|
||||
security_constants::CIPHER_AES_GMAC_SIV => {
|
||||
let mut aes = secret.aes_gmac_siv.get();
|
||||
aes.decrypt_init(&packet_header.aes_gmac_siv_tag());
|
||||
aes.decrypt_set_aad(&packet_header.aad_bytes());
|
||||
|
||||
if let Ok(b) = payload.append_bytes_get_mut(packet_frag0_payload_bytes.len()) {
|
||||
aes.decrypt(packet_frag0_payload_bytes, b);
|
||||
}
|
||||
for f in fragments.iter() {
|
||||
if let Some(f) = f.as_ref() {
|
||||
if let Ok(f) = f.as_bytes_starting_at(packet_constants::FRAGMENT_HEADER_SIZE) {
|
||||
if let Ok(b) = payload.append_bytes_get_mut(f.len()) {
|
||||
aes.decrypt(f, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(tag) = aes.decrypt_finish() {
|
||||
// AES-GMAC-SIV encrypts the packet ID too as part of its computation of a single
|
||||
// opaque 128-bit tag, so to get the original packet ID we have to grab it from the
|
||||
// decrypted tag.
|
||||
Some(u64::from_ne_bytes(*byte_array_range::<16, 0, 8>(tag)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
impl<SI: SystemInterface> Peer<SI> {
|
||||
|
@ -287,7 +294,7 @@ impl<SI: SystemInterface> Peer<SI> {
|
|||
// If we made it here it decrypted and passed authentication.
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
debug_event!(si, "[vl1] #{:0>16x} decrypted and authenticated, verb: {:0>2x}", u64::from_be_bytes(packet_header.id), (verb & packet_constants::VERB_MASK) as u32);
|
||||
debug_event!(si, "[vl1] #{:0>16x} decrypted and authenticated, verb: {} ({:0>2x})", u64::from_be_bytes(packet_header.id), verbs::name(verb & packet_constants::VERB_MASK), (verb & packet_constants::VERB_MASK) as u32);
|
||||
|
||||
if (verb & packet_constants::VERB_FLAG_COMPRESSED) != 0 {
|
||||
let mut decompressed_payload: [u8; packet_constants::SIZE_MAX] = unsafe { MaybeUninit::uninit().assume_init() };
|
||||
|
|
|
@ -74,6 +74,21 @@ pub mod verbs {
|
|||
pub const VL1_ECHO: u8 = 0x08;
|
||||
pub const VL1_PUSH_DIRECT_PATHS: u8 = 0x10;
|
||||
pub const VL1_USER_MESSAGE: u8 = 0x14;
|
||||
|
||||
pub fn name(verb: u8) -> &'static str {
|
||||
match verb {
|
||||
VL1_NOP => "VL1_NOP",
|
||||
VL1_HELLO => "VL1_HELLO",
|
||||
VL1_ERROR => "VL1_ERROR",
|
||||
VL1_OK => "VL1_OK",
|
||||
VL1_WHOIS => "VL1_WHOIS",
|
||||
VL1_RENDEZVOUS => "VL1_RENDEZVOUS",
|
||||
VL1_ECHO => "VL1_ECHO",
|
||||
VL1_PUSH_DIRECT_PATHS => "VL1_PUSH_DIRECT_PATHS",
|
||||
VL1_USER_MESSAGE => "VL1_USER_MESSAGE",
|
||||
_ => "???",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Default maximum payload size for UDP transport.
|
||||
|
@ -122,7 +137,7 @@ pub mod packet_constants {
|
|||
pub const MAC_FIELD_INDEX: usize = 19;
|
||||
|
||||
/// Mask to select cipher from header flags field.
|
||||
pub const FLAGS_FIELD_MASK_CIPHER: u8 = 0x30;
|
||||
pub const FLAGS_FIELD_MASK_CIPHER: u8 = 0x38;
|
||||
|
||||
/// Mask to select packet hops from header flags field.
|
||||
pub const FLAGS_FIELD_MASK_HOPS: u8 = 0x07;
|
||||
|
@ -178,13 +193,13 @@ pub mod security_constants {
|
|||
|
||||
/// Packet is encrypted and authenticated with Salsa20/12 and Poly1305.
|
||||
/// Construction is the same as that which is used in the NaCl secret box functions.
|
||||
pub const CIPHER_SALSA2012_POLY1305: u8 = 0x10;
|
||||
pub const CIPHER_SALSA2012_POLY1305: u8 = 0x08;
|
||||
|
||||
/// Formerly 'NONE' which is deprecated; reserved for future use.
|
||||
pub const CIPHER_RESERVED: u8 = 0x20;
|
||||
pub const CIPHER_RESERVED: u8 = 0x10;
|
||||
|
||||
/// Packet is encrypted and authenticated with AES-GMAC-SIV (AES-256).
|
||||
pub const CIPHER_AES_GMAC_SIV: u8 = 0x30;
|
||||
pub const CIPHER_AES_GMAC_SIV: u8 = 0x18;
|
||||
|
||||
/// KBKDF usage label indicating a key used to HMAC packets for extended authentication.
|
||||
pub const KBKDF_KEY_USAGE_LABEL_PACKET_HMAC: u8 = b'M';
|
||||
|
|
|
@ -183,10 +183,10 @@ pub async fn parse_cli_identity(input: &str, validate: bool) -> Result<Identity,
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn c_strerror() -> String {
|
||||
unsafe { std::ffi::CStr::from_ptr(libc::strerror(*libc::__error()).cast()).to_string_lossy().to_string() }
|
||||
}
|
||||
//#[cfg(unix)]
|
||||
//pub fn c_strerror() -> String {
|
||||
// unsafe { std::ffi::CStr::from_ptr(libc::strerror(*libc::__error()).cast()).to_string_lossy().to_string() }
|
||||
//}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
Loading…
Add table
Reference in a new issue