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