mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-07 21:13:44 +02:00
V2 network controller now provides a reply that at least parses!
This commit is contained in:
parent
bc31c35ae8
commit
bc7a9e41bf
5 changed files with 39 additions and 33 deletions
|
@ -276,6 +276,7 @@ impl Controller {
|
|||
tags: HashMap::new(),
|
||||
};
|
||||
|
||||
if !nc.static_ips.is_empty() {
|
||||
let mut coo = vl2::v1::CertificateOfOwnership::new(network_id, now, source_identity.address);
|
||||
for ip in nc.static_ips.iter() {
|
||||
coo.add_ip(ip);
|
||||
|
@ -284,6 +285,7 @@ impl Controller {
|
|||
return Ok((AuthorizationResult::RejectedDueToError, None, None));
|
||||
}
|
||||
v1cred.certificates_of_ownership.push(coo);
|
||||
}
|
||||
|
||||
for (id, value) in member.tags.iter() {
|
||||
let tag = vl2::v1::Tag::new(*id, *value, &self.local_identity, network_id, &source_identity, now);
|
||||
|
@ -417,6 +419,7 @@ impl InnerProtocol for Controller {
|
|||
|
||||
let (result, config) = match self2.get_network_config(&peer.identity, network_id, now).await {
|
||||
Result::Ok((result, Some(config), revocations)) => {
|
||||
dump_network_config(&config);
|
||||
self2.send_network_config(peer.as_ref(), &config, Some(message_id));
|
||||
(result, Some(config))
|
||||
}
|
||||
|
|
|
@ -113,6 +113,7 @@ pub struct Network {
|
|||
pub min_supported_version: Option<u32>,
|
||||
|
||||
/// MTU inside the virtual network, default of 2800 is used if not set.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub mtu: Option<u16>,
|
||||
|
||||
/// If true the network has access control, which is usually what you want.
|
||||
|
|
|
@ -122,6 +122,8 @@ impl NetworkConfig {
|
|||
pub fn v1_proto_to_dictionary(&self, controller_identity: &Identity) -> Option<Dictionary> {
|
||||
let mut d = Dictionary::new();
|
||||
|
||||
d.set_u64(proto_v1_field_name::network_config::VERSION, 6);
|
||||
|
||||
d.set_str(
|
||||
proto_v1_field_name::network_config::NETWORK_ID,
|
||||
self.network_id.to_string().as_str(),
|
||||
|
@ -191,7 +193,11 @@ impl NetworkConfig {
|
|||
if let Some(v1cred) = self.v1_credentials.as_ref() {
|
||||
d.set_bytes(
|
||||
proto_v1_field_name::network_config::CERTIFICATE_OF_MEMBERSHIP,
|
||||
v1cred.certificate_of_membership.to_bytes()?.as_bytes().to_vec(),
|
||||
v1cred
|
||||
.certificate_of_membership
|
||||
.to_bytes(self.network_id.network_controller())
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
);
|
||||
|
||||
if !v1cred.certificates_of_ownership.is_empty() {
|
||||
|
|
|
@ -19,7 +19,7 @@ pub struct CertificateOfMembership {
|
|||
pub timestamp: i64,
|
||||
pub max_delta: i64,
|
||||
pub issued_to: Address,
|
||||
pub issued_to_fingerprint: Blob<{ Identity::FINGERPRINT_SIZE }>,
|
||||
pub issued_to_fingerprint: Blob<32>,
|
||||
pub signature: ArrayVec<u8, { Identity::MAX_SIGNATURE_SIZE }>,
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ impl CertificateOfMembership {
|
|||
signature: ArrayVec::new(),
|
||||
};
|
||||
|
||||
com.issued_to_fingerprint = Blob::from(Self::v1_proto_issued_to_fingerprint(issued_to, Some(issuer.address)));
|
||||
com.issued_to_fingerprint = Blob::from(Self::v1_proto_issued_to_fingerprint(issued_to));
|
||||
if let Some(signature) = issuer.sign(&com.v1_proto_get_qualifier_bytes(), true) {
|
||||
com.signature = signature;
|
||||
Some(com)
|
||||
|
@ -77,32 +77,25 @@ impl CertificateOfMembership {
|
|||
*memory::as_byte_array(&q)
|
||||
}
|
||||
|
||||
fn v1_proto_issued_to_fingerprint(issued_to: &Identity, signed_by: Option<Address>) -> [u8; 48] {
|
||||
/// Get the identity fingerprint used in V1, which only covers the curve25519 keys.
|
||||
fn v1_proto_issued_to_fingerprint(issued_to: &Identity) -> [u8; 32] {
|
||||
let mut v1_signee_hasher = SHA384::new();
|
||||
v1_signee_hasher.update(&issued_to.address.to_bytes());
|
||||
v1_signee_hasher.update(&issued_to.x25519);
|
||||
v1_signee_hasher.update(&issued_to.ed25519);
|
||||
let mut fp = v1_signee_hasher.finish();
|
||||
fp[32..].fill(0);
|
||||
if let Some(signed_by) = signed_by {
|
||||
fp[32..37].copy_from_slice(&signed_by.to_bytes());
|
||||
}
|
||||
fp
|
||||
(&v1_signee_hasher.finish()[..32]).try_into().unwrap()
|
||||
}
|
||||
|
||||
/// Get this certificate of membership in byte encoded format.
|
||||
pub fn to_bytes(&self) -> Option<ArrayVec<u8, 384>> {
|
||||
if self.signature.len() == 96 {
|
||||
pub fn to_bytes(&self, controller_address: Address) -> ArrayVec<u8, 384> {
|
||||
let mut v = ArrayVec::new();
|
||||
v.push(1); // version byte from v1 protocol
|
||||
v.push(0);
|
||||
v.push(7); // 7 qualifiers, big-endian 16-bit
|
||||
let _ = v.write_all(&self.v1_proto_get_qualifier_bytes());
|
||||
let _ = v.write_all(&self.issued_to_fingerprint.as_bytes()[32..38]); // issuer address
|
||||
let _ = v.write_all(&controller_address.to_bytes());
|
||||
let _ = v.write_all(self.signature.as_bytes());
|
||||
return Some(v);
|
||||
}
|
||||
return None;
|
||||
v
|
||||
}
|
||||
|
||||
/// Decode a V1 legacy format certificate of membership in byte format.
|
||||
|
@ -117,7 +110,7 @@ impl CertificateOfMembership {
|
|||
return Err(InvalidParameterError("incomplete"));
|
||||
}
|
||||
|
||||
let (mut network_id, mut issued_to, mut timestamp, mut max_delta, mut v1_fingerprint) = (0, 0, 0, 0, [0u8; 48]);
|
||||
let (mut network_id, mut issued_to, mut timestamp, mut max_delta, mut v1_fingerprint) = (0, 0, 0, 0, [0u8; 32]);
|
||||
for _ in 0..qualifier_count {
|
||||
let qt = u64::from_be_bytes(b[..8].try_into().unwrap());
|
||||
let q: [u8; 8] = b[8..16].try_into().unwrap();
|
||||
|
@ -150,8 +143,7 @@ impl CertificateOfMembership {
|
|||
b = &b[24..];
|
||||
}
|
||||
|
||||
v1_fingerprint[32..38].copy_from_slice(&b[..5]); // issuer address
|
||||
b = &b[5..];
|
||||
b = &b[5..]; // skip issuer address which is always the controller
|
||||
|
||||
Ok(Self {
|
||||
network_id: NetworkId::from_u64(network_id).ok_or(InvalidParameterError("invalid network ID"))?,
|
||||
|
@ -169,7 +161,7 @@ impl CertificateOfMembership {
|
|||
|
||||
/// Verify this certificate of membership.
|
||||
pub fn verify(self, issuer: &Identity, expect_issued_to: &Identity) -> Option<Verified<Self>> {
|
||||
if Self::v1_proto_issued_to_fingerprint(expect_issued_to, None).eq(&self.issued_to_fingerprint.as_bytes()[..32]) {
|
||||
if Self::v1_proto_issued_to_fingerprint(expect_issued_to).eq(&self.issued_to_fingerprint.as_bytes()[..32]) {
|
||||
if issuer.verify(&self.v1_proto_get_qualifier_bytes(), self.signature.as_bytes()) {
|
||||
return Some(Verified(self));
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ impl<const L: usize> ToString for Blob<L> {
|
|||
}
|
||||
|
||||
impl<const L: usize> Serialize for Blob<L> {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
|
@ -82,10 +83,12 @@ struct BlobVisitor<const L: usize>;
|
|||
impl<'de, const L: usize> serde::de::Visitor<'de> for BlobVisitor<L> {
|
||||
type Value = Blob<L>;
|
||||
|
||||
#[inline]
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str(format!("array of {} bytes", L).as_str())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::SeqAccess<'de>,
|
||||
|
@ -99,6 +102,7 @@ impl<'de, const L: usize> serde::de::Visitor<'de> for BlobVisitor<L> {
|
|||
}
|
||||
|
||||
impl<'de, const L: usize> Deserialize<'de> for Blob<L> {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<Blob<L>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
|
|
Loading…
Add table
Reference in a new issue