Some docs, assert AES IV is 96 bits since anything else has security issues.

This commit is contained in:
Adam Ierymenko 2022-11-30 09:43:31 -05:00
parent e8cdce34f2
commit 580496cbd7
4 changed files with 29 additions and 31 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -12,6 +12,11 @@ use zerotier_network_hypervisor::vl1::Address;
use zerotier_network_hypervisor::vl2::NetworkId; use zerotier_network_hypervisor::vl2::NetworkId;
/// Network and member cache used by database implementations to implement change detection. /// Network and member cache used by database implementations to implement change detection.
///
/// Note: the database must ensure that calls to on_X_updated() methods are only performed
/// when a potentially newer version is committed. No-op calls when nothing has changed are
/// okay but calls out of order will result in extra updated events being generated for
/// movements forward and backward in time. Calls must be temporally ordered.
pub struct Cache { pub struct Cache {
by_nwid: RwLock<HashMap<NetworkId, (Network, Mutex<HashMap<Address, Member>>)>>, by_nwid: RwLock<HashMap<NetworkId, (Network, Mutex<HashMap<Address, Member>>)>>,
} }

View file

@ -224,17 +224,10 @@ mod fruit_flavored {
#[inline(always)] #[inline(always)]
pub fn init(&mut self, iv: &[u8]) { pub fn init(&mut self, iv: &[u8]) {
assert_eq!(iv.len(), 12);
unsafe { unsafe {
assert_eq!(CCCryptorGCMReset(self.0), 0); assert_eq!(CCCryptorGCMReset(self.0), 0);
if iv.len() == 16 { assert_eq!(CCCryptorGCMSetIV(self.0, iv.as_ptr().cast(), 12), 0);
assert_eq!(CCCryptorGCMSetIV(self.0, iv.as_ptr().cast(), 16), 0);
} else if iv.len() < 16 {
let mut tmp = [0_u8; 16];
tmp[..iv.len()].copy_from_slice(iv);
assert_eq!(CCCryptorGCMSetIV(self.0, tmp.as_ptr().cast(), 16), 0);
} else {
panic!();
}
} }
} }
@ -408,7 +401,9 @@ mod openssl_aes {
/// Initialize AES-CTR for encryption or decryption with the given IV. /// Initialize AES-CTR for encryption or decryption with the given IV.
/// If it's already been used, this also resets the cipher. There is no separate reset. /// If it's already been used, this also resets the cipher. There is no separate reset.
#[inline]
pub fn init(&mut self, iv: &[u8]) { pub fn init(&mut self, iv: &[u8]) {
assert_eq!(iv.len(), 12);
let mut c = Crypter::new( let mut c = Crypter::new(
aes_gcm_by_key_size(self.1), aes_gcm_by_key_size(self.1),
if self.3 { if self.3 {

View file

@ -20,7 +20,7 @@ use zerotier_utils::ringbuffermap::RingBufferMap;
use zerotier_utils::unlikely_branch; use zerotier_utils::unlikely_branch;
use zerotier_utils::varint; use zerotier_utils::varint;
/// Minimum size of a valid physical packet. /// Minimum size of a valid physical ZSSP packet or packet fragment.
pub const MIN_PACKET_SIZE: usize = HEADER_SIZE + AES_GCM_TAG_SIZE; pub const MIN_PACKET_SIZE: usize = HEADER_SIZE + AES_GCM_TAG_SIZE;
/// Minimum physical MTU for ZSSP to function. /// Minimum physical MTU for ZSSP to function.
@ -43,7 +43,7 @@ pub const SERVICE_INTERVAL: u64 = 10000;
const JEDI: bool = true; const JEDI: bool = true;
/// Maximum number of fragments for data packets. /// Maximum number of fragments for data packets.
const MAX_FRAGMENTS: usize = 48; // protocol max: 63 const MAX_FRAGMENTS: usize = 48; // hard protocol max: 63
/// Maximum number of fragments for key exchange packets (can be smaller to save memory, only a few needed) /// Maximum number of fragments for key exchange packets (can be smaller to save memory, only a few needed)
const KEY_EXCHANGE_MAX_FRAGMENTS: usize = 2; // enough room for p384 + ZT identity + kyber1024 + tag/hmac/etc. const KEY_EXCHANGE_MAX_FRAGMENTS: usize = 2; // enough room for p384 + ZT identity + kyber1024 + tag/hmac/etc.
@ -93,9 +93,7 @@ const HMAC_SIZE: usize = 48;
/// This is large since some ZeroTier nodes handle huge numbers of links, like roots and controllers. /// This is large since some ZeroTier nodes handle huge numbers of links, like roots and controllers.
const SESSION_ID_SIZE: usize = 6; const SESSION_ID_SIZE: usize = 6;
/// Number of session keys to hold at a given time. /// Number of session keys to hold at a given time (current, previous, next).
///
/// This provides room for a current, previous, and next key.
const KEY_HISTORY_SIZE: usize = 3; const KEY_HISTORY_SIZE: usize = 3;
// Packet types can range from 0 to 15 (4 bits) -- 0-3 are defined and 4-15 are reserved for future use // Packet types can range from 0 to 15 (4 bits) -- 0-3 are defined and 4-15 are reserved for future use
@ -105,11 +103,11 @@ const PACKET_TYPE_KEY_OFFER: u8 = 2; // "alice"
const PACKET_TYPE_KEY_COUNTER_OFFER: u8 = 3; // "bob" const PACKET_TYPE_KEY_COUNTER_OFFER: u8 = 3; // "bob"
// Key usage labels for sub-key derivation using NIST-style KBKDF (basically just HMAC KDF). // Key usage labels for sub-key derivation using NIST-style KBKDF (basically just HMAC KDF).
const KBKDF_KEY_USAGE_LABEL_HMAC: u8 = b'M'; const KBKDF_KEY_USAGE_LABEL_HMAC: u8 = b'M'; // HMAC-SHA384 authentication for key exchanges
const KBKDF_KEY_USAGE_LABEL_HEADER_CHECK: u8 = b'H'; const KBKDF_KEY_USAGE_LABEL_HEADER_CHECK: u8 = b'H'; // AES-based header check code generation
const KBKDF_KEY_USAGE_LABEL_AES_GCM_ALICE_TO_BOB: u8 = b'A'; const KBKDF_KEY_USAGE_LABEL_AES_GCM_ALICE_TO_BOB: u8 = b'A'; // AES-GCM in A->B direction
const KBKDF_KEY_USAGE_LABEL_AES_GCM_BOB_TO_ALICE: u8 = b'B'; const KBKDF_KEY_USAGE_LABEL_AES_GCM_BOB_TO_ALICE: u8 = b'B'; // AES-GCM in B->A direction
const KBKDF_KEY_USAGE_LABEL_RATCHETING: u8 = b'R'; const KBKDF_KEY_USAGE_LABEL_RATCHETING: u8 = b'R'; // Key input for next ephemeral ratcheting
/// Aribitrary starting value for master key derivation. /// Aribitrary starting value for master key derivation.
/// ///
@ -125,7 +123,7 @@ const INITIAL_KEY: [u8; 64] = [
]; ];
pub enum Error { pub enum Error {
/// The packet was addressed to an unrecognized local session /// The packet was addressed to an unrecognized local session (should usually be ignored)
UnknownLocalSessionId(SessionId), UnknownLocalSessionId(SessionId),
/// Packet was not well formed /// Packet was not well formed
@ -137,36 +135,36 @@ pub enum Error {
/// Packet failed one or more authentication (MAC) checks /// Packet failed one or more authentication (MAC) checks
FailedAuthentication, FailedAuthentication,
/// New session was rejected by caller's supplied authentication check function /// New session was rejected via Host::check_new_session_attempt or Host::accept_new_session.
NewSessionRejected, NewSessionRejected,
/// Rekeying failed and session secret has reached its maximum usage count /// Rekeying failed and session secret has reached its hard usage count limit
MaxKeyLifetimeExceeded, MaxKeyLifetimeExceeded,
/// Attempt to send using session without established key. /// Attempt to send using session without established key
SessionNotEstablished, SessionNotEstablished,
/// Packet ignored by rate limiter. /// Packet ignored by rate limiter.
RateLimited, RateLimited,
/// Other end sent a protocol version we don't support. /// The other peer specified an unrecognized protocol version
UnknownProtocolVersion, UnknownProtocolVersion,
/// Supplied data buffer is too small to receive data. /// Caller supplied data buffer is too small to receive data
DataBufferTooSmall, DataBufferTooSmall,
/// Data object is too large to send, even fragmented. /// Data object is too large to send, even with fragmentation
DataTooLarge, DataTooLarge,
/// An unexpected I/O error such as a buffer overrun occurred. /// An unexpected I/O error such as a buffer overrun occurred (possible bug)
IoError(std::io::Error), UnexpectedIoError(std::io::Error),
} }
impl From<std::io::Error> for Error { impl From<std::io::Error> for Error {
#[cold] #[cold]
#[inline(never)] #[inline(never)]
fn from(e: std::io::Error) -> Self { fn from(e: std::io::Error) -> Self {
Self::IoError(e) Self::UnexpectedIoError(e)
} }
} }
@ -184,7 +182,7 @@ impl std::fmt::Display for Error {
Self::UnknownProtocolVersion => f.write_str("UnknownProtocolVersion"), Self::UnknownProtocolVersion => f.write_str("UnknownProtocolVersion"),
Self::DataBufferTooSmall => f.write_str("DataBufferTooSmall"), Self::DataBufferTooSmall => f.write_str("DataBufferTooSmall"),
Self::DataTooLarge => f.write_str("DataTooLarge"), Self::DataTooLarge => f.write_str("DataTooLarge"),
Self::IoError(e) => f.write_str(format!("OtherError({})", e.to_string()).as_str()), Self::UnexpectedIoError(e) => f.write_str(format!("UnexpectedIoError({})", e.to_string()).as_str()),
} }
} }
} }
@ -239,7 +237,7 @@ impl SessionId {
#[inline] #[inline]
pub fn new_from_reader<R: Read>(r: &mut R) -> std::io::Result<Option<SessionId>> { pub fn new_from_reader<R: Read>(r: &mut R) -> std::io::Result<Option<SessionId>> {
let mut tmp = [0_u8; 8]; let mut tmp = 0_u64.to_ne_bytes();
r.read_exact(&mut tmp[..SESSION_ID_SIZE])?; r.read_exact(&mut tmp[..SESSION_ID_SIZE])?;
Ok(Self::new_from_u64(u64::from_le_bytes(tmp))) Ok(Self::new_from_u64(u64::from_le_bytes(tmp)))
} }