From 7318a188b2b9195dee5f5abe41cb600934030470 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 3 Nov 2021 09:52:35 -0400 Subject: [PATCH] Build and test fixes. --- zerotier-core-crypto/Cargo.toml | 8 +-- zerotier-core-crypto/src/balloon.rs | 5 +- .../util => zerotier-core-crypto/src}/hex.rs | 2 +- zerotier-core-crypto/src/lib.rs | 1 + zerotier-core-crypto/src/p521.rs | 20 +++---- zerotier-core-crypto/src/random.rs | 8 ++- zerotier-core-crypto/src/secret.rs | 1 - zerotier-network-hypervisor/src/util/mod.rs | 3 +- zerotier-network-hypervisor/src/util/pool.rs | 1 - .../src/util/varint.rs | 54 ++++++++++--------- zerotier-network-hypervisor/src/vl1/buffer.rs | 9 +++- .../src/vl1/dictionary.rs | 2 +- .../src/vl1/identity.rs | 4 +- .../src/vl1/locator.rs | 10 ++-- zerotier-network-hypervisor/src/vl1/peer.rs | 3 +- .../src/vl1/protocol.rs | 4 +- .../src/vl1/rootset.rs | 1 - zerotier-system-service/Cargo.lock | 2 +- 18 files changed, 73 insertions(+), 65 deletions(-) rename {zerotier-network-hypervisor/src/util => zerotier-core-crypto/src}/hex.rs (94%) diff --git a/zerotier-core-crypto/Cargo.toml b/zerotier-core-crypto/Cargo.toml index 8d4f35455..74536d809 100644 --- a/zerotier-core-crypto/Cargo.toml +++ b/zerotier-core-crypto/Cargo.toml @@ -4,8 +4,8 @@ version = "0.1.0" edition = "2018" [dependencies] -rand_core = "^0" +rand_core = "0.5" aes-gmac-siv = { path = "../aes-gmac-siv" } -gcrypt = "^0" -x25519-dalek = { version = "^1", features = ["u64_backend"] } -ed25519-dalek = { version = "^1", features = ["u64_backend"] } +gcrypt = "0.7.0" +x25519-dalek = { version = "1.2.0", features = ["u64_backend"] } +ed25519-dalek = { version = "1.0.1", features = ["u64_backend"] } diff --git a/zerotier-core-crypto/src/balloon.rs b/zerotier-core-crypto/src/balloon.rs index 9faa92117..94b752c3e 100644 --- a/zerotier-core-crypto/src/balloon.rs +++ b/zerotier-core-crypto/src/balloon.rs @@ -6,7 +6,6 @@ * https://www.zerotier.com/ */ -use std::convert::TryInto; use std::mem::MaybeUninit; use crate::hash::{SHA384, SHA512}; @@ -24,7 +23,7 @@ fn hash_int_le(sha: &mut SHA512, i: u64) { /// Compute balloon memory-hard hash using SHA-512 and SHA-384 for the final. /// SPACE_COST must be a multiple of 64. This is checked with an assertion. /// DELTA is usually 3. -pub fn hash(password: &[u8], salt: &[u8]) -> [u8; crate::crypto::hash::SHA384_HASH_SIZE] { +pub fn hash(password: &[u8], salt: &[u8]) -> [u8; crate::hash::SHA384_HASH_SIZE] { debug_assert_ne!(SPACE_COST, 0); debug_assert_ne!(TIME_COST, 0); debug_assert_ne!(DELTA, 0); @@ -129,7 +128,7 @@ mod tests { let start = std::time::SystemTime::now(); let mut tmp = 0_u8; for _ in 0..100 { - let foo = crate::crypto::balloon::hash::<16384, 3, 3>(&[1_u8], &[2_u8]); + let foo = crate::balloon::hash::<16384, 3, 3>(&[1_u8], &[2_u8]); tmp = tmp.wrapping_add(foo[0]); } let duration = std::time::SystemTime::now().duration_since(start).unwrap(); diff --git a/zerotier-network-hypervisor/src/util/hex.rs b/zerotier-core-crypto/src/hex.rs similarity index 94% rename from zerotier-network-hypervisor/src/util/hex.rs rename to zerotier-core-crypto/src/hex.rs index b03524262..7ef8c655c 100644 --- a/zerotier-network-hypervisor/src/util/hex.rs +++ b/zerotier-core-crypto/src/hex.rs @@ -6,7 +6,7 @@ * https://www.zerotier.com/ */ -pub(crate) const HEX_CHARS: [u8; 16] = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd', b'e', b'f']; +pub const HEX_CHARS: [u8; 16] = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd', b'e', b'f']; /// Encode a byte slice to a hexadecimal string. pub fn to_string(b: &[u8]) -> String { diff --git a/zerotier-core-crypto/src/lib.rs b/zerotier-core-crypto/src/lib.rs index ebfb1b0c5..7b476dc87 100644 --- a/zerotier-core-crypto/src/lib.rs +++ b/zerotier-core-crypto/src/lib.rs @@ -15,6 +15,7 @@ pub mod balloon; pub mod kbkdf; pub mod random; pub mod secret; +pub mod hex; pub use aes_gmac_siv; pub use rand_core; diff --git a/zerotier-core-crypto/src/p521.rs b/zerotier-core-crypto/src/p521.rs index 45972357d..5abeb9edf 100644 --- a/zerotier-core-crypto/src/p521.rs +++ b/zerotier-core-crypto/src/p521.rs @@ -27,7 +27,7 @@ fn dump_sexp(exp: &SExpression) { } else { let b = exp.get_bytes(0); if b.is_some() { - print!("#{}#", crate::util::hex::to_string(b.unwrap())); + print!("#{}#", crate::hex::to_string(b.unwrap())); } else { print!("()"); } @@ -51,14 +51,14 @@ fn dump_sexp(exp: &SExpression) { #[inline(always)] fn hash_to_data_sexp(msg: &[u8]) -> [u8; 155] { - let h = crate::crypto::hash::SHA512::hash(msg); + let h = crate::hash::SHA512::hash(msg); let mut d = [0_u8; 155]; d[0..24].copy_from_slice(b"(data(flags raw)(value #"); let mut j = 24; for i in 0..64 { let b = h[i] as usize; - d[j] = crate::util::hex::HEX_CHARS[b >> 4]; - d[j + 1] = crate::util::hex::HEX_CHARS[b & 0xf]; + d[j] = crate::hex::HEX_CHARS[b >> 4]; + d[j + 1] = crate::hex::HEX_CHARS[b & 0xf]; j += 2; } d[152..155].copy_from_slice(b"#))"); @@ -107,8 +107,8 @@ impl P521KeyPair { public_key: pk_exp, public_key_bytes: [0_u8; P521_PUBLIC_KEY_SIZE], }, - secret_key_for_ecdsa: SExpression::from_str(format!("(private-key(ecc(curve nistp521)(q #{}#)(d #{}#)))", crate::util::hex::to_string(pk), crate::util::hex::to_string(sk)).as_str()).unwrap(), - secret_key_for_ecdh: SExpression::from_str(format!("(data(flags raw)(value #{}#))", crate::util::hex::to_string(sk)).as_str()).unwrap(), + secret_key_for_ecdsa: SExpression::from_str(format!("(private-key(ecc(curve nistp521)(q #{}#)(d #{}#)))", crate::hex::to_string(pk), crate::hex::to_string(sk)).as_str()).unwrap(), + secret_key_for_ecdh: SExpression::from_str(format!("(data(flags raw)(value #{}#))", crate::hex::to_string(sk)).as_str()).unwrap(), secret_key_bytes: Secret::default(), }; kp.public_key.public_key_bytes[((P521_PUBLIC_KEY_SIZE + 1) - pk.len())..P521_PUBLIC_KEY_SIZE].copy_from_slice(&pk[1..]); @@ -132,8 +132,8 @@ impl P521KeyPair { } Some(P521KeyPair { public_key: public_key.unwrap(), - secret_key_for_ecdsa: SExpression::from_str(format!("(private-key(ecc(curve nistp521)(q #04{}#)(d #{}#)))", crate::util::hex::to_string(public_bytes), crate::util::hex::to_string(secret_bytes)).as_str()).unwrap(), - secret_key_for_ecdh: SExpression::from_str(format!("(data(flags raw)(value #{}#))", crate::util::hex::to_string(secret_bytes)).as_str()).unwrap(), + secret_key_for_ecdsa: SExpression::from_str(format!("(private-key(ecc(curve nistp521)(q #04{}#)(d #{}#)))", crate::hex::to_string(public_bytes), crate::hex::to_string(secret_bytes)).as_str()).unwrap(), + secret_key_for_ecdh: SExpression::from_str(format!("(data(flags raw)(value #{}#))", crate::hex::to_string(secret_bytes)).as_str()).unwrap(), secret_key_bytes: Secret::from_bytes(secret_bytes), }) } @@ -188,7 +188,7 @@ impl P521PublicKey { pub fn from_bytes(b: &[u8]) -> Option { if b.len() == P521_PUBLIC_KEY_SIZE { Some(P521PublicKey { - public_key: SExpression::from_str(format!("(public-key(ecc(curve nistp521)(q #04{}#)))", crate::util::hex::to_string(b)).as_str()).unwrap(), + public_key: SExpression::from_str(format!("(public-key(ecc(curve nistp521)(q #04{}#)))", crate::hex::to_string(b)).as_str()).unwrap(), public_key_bytes: b.try_into().unwrap(), }) } else { @@ -201,7 +201,7 @@ impl P521PublicKey { pub fn verify(&self, msg: &[u8], signature: &[u8]) -> bool { if signature.len() == P521_ECDSA_SIGNATURE_SIZE { let data = SExpression::from_str(unsafe { std::str::from_utf8_unchecked(&hash_to_data_sexp(msg)) }).unwrap(); - let sig = SExpression::from_str(format!("(sig-val(ecdsa(r #{}#)(s #{}#)))", crate::util::hex::to_string(&signature[0..66]), crate::util::hex::to_string(&signature[66..132])).as_str()).unwrap(); + let sig = SExpression::from_str(format!("(sig-val(ecdsa(r #{}#)(s #{}#)))", crate::hex::to_string(&signature[0..66]), crate::hex::to_string(&signature[66..132])).as_str()).unwrap(); gcrypt::pkey::verify(&self.public_key, &data, &sig).is_ok() } else { false diff --git a/zerotier-core-crypto/src/random.rs b/zerotier-core-crypto/src/random.rs index 26ee76a4a..372fa10f4 100644 --- a/zerotier-core-crypto/src/random.rs +++ b/zerotier-core-crypto/src/random.rs @@ -6,8 +6,6 @@ * https://www.zerotier.com/ */ -use rand_core::{RngCore, Error}; -use rand_core::CryptoRng; use gcrypt::rand::{Level, randomize}; /// Secure random source based on the desired third party library (gcrypt). @@ -18,7 +16,7 @@ impl SecureRandom { pub fn get() -> Self { Self } } -impl RngCore for SecureRandom { +impl rand_core::RngCore for SecureRandom { #[inline(always)] fn next_u32(&mut self) -> u32 { let mut tmp = 0_u32; @@ -37,13 +35,13 @@ impl RngCore for SecureRandom { fn fill_bytes(&mut self, dest: &mut [u8]) { randomize(Level::Strong, dest); } #[inline(always)] - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { randomize(Level::Strong, dest); Ok(()) } } -impl CryptoRng for SecureRandom {} +impl rand_core::CryptoRng for SecureRandom {} #[inline(always)] pub fn next_u32_secure() -> u32 { diff --git a/zerotier-core-crypto/src/secret.rs b/zerotier-core-crypto/src/secret.rs index 35369dcf6..1a947a0bb 100644 --- a/zerotier-core-crypto/src/secret.rs +++ b/zerotier-core-crypto/src/secret.rs @@ -7,7 +7,6 @@ */ use std::convert::TryInto; -use std::mem::size_of; use std::ptr::write_volatile; /// Container for secrets that clears them on drop. diff --git a/zerotier-network-hypervisor/src/util/mod.rs b/zerotier-network-hypervisor/src/util/mod.rs index 3baf5d7db..6ff2cffed 100644 --- a/zerotier-network-hypervisor/src/util/mod.rs +++ b/zerotier-network-hypervisor/src/util/mod.rs @@ -6,11 +6,12 @@ * https://www.zerotier.com/ */ -pub mod hex; pub mod pool; pub mod gate; pub mod varint; +pub use zerotier_core_crypto::hex; + pub(crate) const ZEROES: [u8; 64] = [0_u8; 64]; #[inline(always)] diff --git a/zerotier-network-hypervisor/src/util/pool.rs b/zerotier-network-hypervisor/src/util/pool.rs index e18622eec..b86060a5a 100644 --- a/zerotier-network-hypervisor/src/util/pool.rs +++ b/zerotier-network-hypervisor/src/util/pool.rs @@ -6,7 +6,6 @@ * https://www.zerotier.com/ */ -use std::mem::size_of; use std::ptr::NonNull; use std::sync::{Arc, Weak}; diff --git a/zerotier-network-hypervisor/src/util/varint.rs b/zerotier-network-hypervisor/src/util/varint.rs index 01e8b8b7b..484e81595 100644 --- a/zerotier-network-hypervisor/src/util/varint.rs +++ b/zerotier-network-hypervisor/src/util/varint.rs @@ -7,55 +7,59 @@ */ use std::io::{Read, Write}; +use crate::vl1::buffer::Buffer; +/// Write a variable length integer, which can consume up to 10 bytes. pub fn write(w: &mut W, mut v: u64) -> std::io::Result<()> { let mut b = [0_u8; 10]; - let mut i = 10; + let mut i = 0; loop { if v > 0x7f { - i -= 1; b[i] = (v as u8) & 0x7f; - v >>= 7; + i += 1; + v = v.wrapping_shr(7); } else { - i -= 1; b[i] = (v as u8) | 0x80; + i += 1; break; } } - w.write_all(&b[i..]) + w.write_all(&b[0..i]) } -pub fn read(r: &mut R) -> std::io::Result { +/// Read a variable length integer, returning the value and the number of bytes written. +pub fn read(r: &mut R) -> std::io::Result<(u64, usize)> { let mut v = 0_u64; let mut buf = [0_u8; 1]; + let mut pos = 0; + let mut i = 0_usize; loop { - v <<= 7; let _ = r.read_exact(&mut buf)?; let b = buf[0]; + i += 1; if b <= 0x7f { - v |= b as u64; + v |= (b as u64).wrapping_shl(pos); + pos += 7; } else { - v |= (b & 0x7f) as u64; - return Ok(v); + v |= ((b & 0x7f) as u64).wrapping_shl(pos); + return Ok((v, i)); } } } -pub(crate) fn read_from_bytes(r: &[u8], cursor: &mut usize) -> std::io::Result { - let mut v = 0_u64; - let mut c = *cursor; - while c < r.len() { - v <<= 7; - let b = unsafe { *r.get_unchecked(c) }; - c += 1; - if b <= 0x7f { - v |= b as u64; - } else { - v |= (b & 0x7f) as u64; - *cursor = c; - return Ok(v); +#[cfg(test)] +mod tests { + use crate::util::varint::*; + + #[test] + fn varint() { + let mut t: Vec = Vec::new(); + for i in 0..131072 { + t.clear(); + let ii = (u64::MAX / 131072) * i; + assert!(write(&mut t, ii).is_ok()); + let mut t2 = t.as_slice(); + assert_eq!(read(&mut t2).unwrap().0, ii); } } - *cursor = c; - return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "incomplete varint")); } diff --git a/zerotier-network-hypervisor/src/vl1/buffer.rs b/zerotier-network-hypervisor/src/vl1/buffer.rs index aaf8bfad2..660004d42 100644 --- a/zerotier-network-hypervisor/src/vl1/buffer.rs +++ b/zerotier-network-hypervisor/src/vl1/buffer.rs @@ -106,6 +106,9 @@ impl Buffer { #[inline(always)] pub unsafe fn set_size_unchecked(&mut self, s: usize) { self.0 = s; } + #[inline(always)] + pub unsafe fn get_unchecked(&self, i: usize) -> u8 { *self.1.get_unchecked(i) } + /// Append a packed structure and call a function to initialize it in place. /// Anything not initialized will be zero. #[inline(always)] @@ -327,7 +330,11 @@ impl Buffer { /// Get the next variable length integer and advance the cursor by its length in bytes. #[inline(always)] pub fn read_varint(&self, cursor: &mut usize) -> std::io::Result { - crate::util::varint::read_from_bytes(&(self.1[self.0..]), cursor) + let mut a = &self.1[*cursor..]; + crate::util::varint::read(&mut a).map(|r| { + *cursor += r.1; + r.0 + }) } /// Get the next u8 and advance the cursor. diff --git a/zerotier-network-hypervisor/src/vl1/dictionary.rs b/zerotier-network-hypervisor/src/vl1/dictionary.rs index fff0927eb..ab8592951 100644 --- a/zerotier-network-hypervisor/src/vl1/dictionary.rs +++ b/zerotier-network-hypervisor/src/vl1/dictionary.rs @@ -16,7 +16,7 @@ use crate::util::hex::HEX_CHARS; /// It also supports binary keys and values which will be minimally escaped but render the result not /// entirely human readable. Keys are serialized in natural sort order so the result can be consistently /// checksummed or hashed. -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct Dictionary(BTreeMap>); fn write_escaped(b: &[u8], w: &mut W) -> std::io::Result<()> { diff --git a/zerotier-network-hypervisor/src/vl1/identity.rs b/zerotier-network-hypervisor/src/vl1/identity.rs index 3fef5ae2e..0fac01246 100644 --- a/zerotier-network-hypervisor/src/vl1/identity.rs +++ b/zerotier-network-hypervisor/src/vl1/identity.rs @@ -306,9 +306,9 @@ impl Identity { /// Verify a signature. pub fn verify(&self, msg: &[u8], signature: &[u8]) -> bool { self.v1.as_ref().map_or_else(|| { - crate::crypto::c25519::ed25519_verify(&self.ed25519, signature, msg) + zerotier_core_crypto::c25519::ed25519_verify(&self.ed25519, signature, msg) }, |p521| { - signature.len() == IDENTITY_TYPE_1_SIGNATURE_SIZE && (*p521).1.verify(msg, &signature[0..P521_ECDSA_SIGNATURE_SIZE]) && crate::crypto::c25519::ed25519_verify(&self.ed25519, &signature[P521_ECDSA_SIGNATURE_SIZE..], msg) + signature.len() == IDENTITY_TYPE_1_SIGNATURE_SIZE && (*p521).1.verify(msg, &signature[0..P521_ECDSA_SIGNATURE_SIZE]) && zerotier_core_crypto::c25519::ed25519_verify(&self.ed25519, &signature[P521_ECDSA_SIGNATURE_SIZE..], msg) }) } diff --git a/zerotier-network-hypervisor/src/vl1/locator.rs b/zerotier-network-hypervisor/src/vl1/locator.rs index d63f9dea9..d04a65143 100644 --- a/zerotier-network-hypervisor/src/vl1/locator.rs +++ b/zerotier-network-hypervisor/src/vl1/locator.rs @@ -92,11 +92,13 @@ impl Locator { self.subject.marshal(buf)?; self.signer.marshal(buf)?; buf.append_varint(self.timestamp as u64)?; - self.metadata.map_or_else(|| buf.append_varint(0), |d| { - let db = d.to_bytes(); + if self.metadata.is_none() { + buf.append_varint(0)?; + } else { + let db = self.metadata.as_ref().unwrap().to_bytes(); buf.append_varint(db.len() as u64)?; - buf.append_bytes(db.as_slice()) - })?; + buf.append_bytes(db.as_slice())?; + } buf.append_varint(self.endpoints.len() as u64)?; for e in self.endpoints.iter() { e.marshal(buf)?; diff --git a/zerotier-network-hypervisor/src/vl1/peer.rs b/zerotier-network-hypervisor/src/vl1/peer.rs index a122c74ac..ad58dd216 100644 --- a/zerotier-network-hypervisor/src/vl1/peer.rs +++ b/zerotier-network-hypervisor/src/vl1/peer.rs @@ -7,7 +7,6 @@ */ use std::convert::TryInto; -use std::mem::MaybeUninit; use std::ptr::copy_nonoverlapping; use std::sync::Arc; use std::sync::atomic::{AtomicI64, AtomicU64, AtomicU8, Ordering}; @@ -449,7 +448,7 @@ impl Peer { let aes_ctr_iv_position = packet.len(); debug_assert!(packet.append_and_init_bytes_fixed(|iv: &mut [u8; 18]| { - crate::crypto::random::fill_bytes_secure(&mut iv[0..16]); + zerotier_core_crypto::random::fill_bytes_secure(&mut iv[0..16]); iv[12] &= 0x7f; // mask off MSB of counter in iv to play nice with some AES-CTR implementations // LEGACY: create a 16-bit encrypted field that specifies zero moons. This is ignored by v2 diff --git a/zerotier-network-hypervisor/src/vl1/protocol.rs b/zerotier-network-hypervisor/src/vl1/protocol.rs index 2b0534f3d..35ec7942d 100644 --- a/zerotier-network-hypervisor/src/vl1/protocol.rs +++ b/zerotier-network-hypervisor/src/vl1/protocol.rs @@ -177,7 +177,7 @@ pub fn compress_packet(src: &[u8], dest: &mut Buffer<{ PACKET_SIZE_MAX }>) -> bo let d = dest.as_bytes_mut(); d[0..PACKET_VERB_INDEX].copy_from_slice(&src[0..PACKET_VERB_INDEX]); d[PACKET_VERB_INDEX] = src[PACKET_VERB_INDEX] | VERB_FLAG_COMPRESSED; - lz4_flex::block::compress_into(&src[PACKET_VERB_INDEX + 1..], d, PACKET_VERB_INDEX + 1) + lz4_flex::block::compress_into(&src[PACKET_VERB_INDEX + 1..], &mut d[PACKET_VERB_INDEX + 1..]) }; if cs.is_ok() { let cs = cs.unwrap(); @@ -193,7 +193,7 @@ pub fn compress_packet(src: &[u8], dest: &mut Buffer<{ PACKET_SIZE_MAX }>) -> bo /// Add HMAC-SHA384 to the end of a packet and set verb flag. #[inline(always)] pub fn add_extended_auth(pkt: &mut Buffer<{ PACKET_SIZE_MAX }>, hmac_secret_key: &[u8]) -> std::io::Result<()> { - pkt.append_bytes_fixed(&ztcrypto::hash::SHA384::hmac(hmac_secret_key, pkt.as_bytes_starting_at(PACKET_VERB_INDEX + 1)?))?; + pkt.append_bytes_fixed(&zerotier_core_crypto::hash::SHA384::hmac(hmac_secret_key, pkt.as_bytes_starting_at(PACKET_VERB_INDEX + 1)?))?; pkt.as_bytes_mut()[PACKET_VERB_INDEX] |= VERB_FLAG_EXTENDED_AUTHENTICATION; Ok(()) } diff --git a/zerotier-network-hypervisor/src/vl1/rootset.rs b/zerotier-network-hypervisor/src/vl1/rootset.rs index 7b4bee2c2..f0e59d2b7 100644 --- a/zerotier-network-hypervisor/src/vl1/rootset.rs +++ b/zerotier-network-hypervisor/src/vl1/rootset.rs @@ -16,7 +16,6 @@ use zerotier_core_crypto::hash::SHA384; use zerotier_core_crypto::p521::*; use zerotier_core_crypto::secret::Secret; -use crate::error::InvalidFormatError; use crate::vl1::{Endpoint, Identity}; use crate::vl1::buffer::Buffer; use crate::vl1::protocol::PACKET_SIZE_MAX; diff --git a/zerotier-system-service/Cargo.lock b/zerotier-system-service/Cargo.lock index 2e070e568..38a500418 100644 --- a/zerotier-system-service/Cargo.lock +++ b/zerotier-system-service/Cargo.lock @@ -1298,7 +1298,7 @@ dependencies = [ "aes-gmac-siv", "ed25519-dalek", "gcrypt", - "rand_core 0.6.3", + "rand_core 0.5.1", "x25519-dalek", ]