diff --git a/controller/src/controller.rs b/controller/src/controller.rs index 895fed827..db6ca1481 100644 --- a/controller/src/controller.rs +++ b/controller/src/controller.rs @@ -276,14 +276,16 @@ impl Controller { tags: HashMap::new(), }; - let mut coo = vl2::v1::CertificateOfOwnership::new(network_id, now, source_identity.address); - for ip in nc.static_ips.iter() { - coo.add_ip(ip); + 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); + } + if !coo.sign(&self.local_identity, &source_identity) { + return Ok((AuthorizationResult::RejectedDueToError, None, None)); + } + v1cred.certificates_of_ownership.push(coo); } - if !coo.sign(&self.local_identity, &source_identity) { - 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)) } diff --git a/controller/src/model/network.rs b/controller/src/model/network.rs index 8ade9f470..cc90b9400 100644 --- a/controller/src/model/network.rs +++ b/controller/src/model/network.rs @@ -113,6 +113,7 @@ pub struct Network { pub min_supported_version: Option, /// MTU inside the virtual network, default of 2800 is used if not set. + #[serde(skip_serializing_if = "Option::is_none")] pub mtu: Option, /// If true the network has access control, which is usually what you want. diff --git a/network-hypervisor/src/vl2/networkconfig.rs b/network-hypervisor/src/vl2/networkconfig.rs index 75d1107db..100212451 100644 --- a/network-hypervisor/src/vl2/networkconfig.rs +++ b/network-hypervisor/src/vl2/networkconfig.rs @@ -122,6 +122,8 @@ impl NetworkConfig { pub fn v1_proto_to_dictionary(&self, controller_identity: &Identity) -> Option { 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() { diff --git a/network-hypervisor/src/vl2/v1/certificateofmembership.rs b/network-hypervisor/src/vl2/v1/certificateofmembership.rs index e11a360a5..eebedf740 100644 --- a/network-hypervisor/src/vl2/v1/certificateofmembership.rs +++ b/network-hypervisor/src/vl2/v1/certificateofmembership.rs @@ -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, } @@ -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
) -> [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> { - if self.signature.len() == 96 { - 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(self.signature.as_bytes()); - return Some(v); - } - return None; + pub fn to_bytes(&self, controller_address: Address) -> ArrayVec { + 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(&controller_address.to_bytes()); + let _ = v.write_all(self.signature.as_bytes()); + 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> { - 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)); } diff --git a/utils/src/blob.rs b/utils/src/blob.rs index 058f6e531..e1b17926b 100644 --- a/utils/src/blob.rs +++ b/utils/src/blob.rs @@ -65,6 +65,7 @@ impl ToString for Blob { } impl Serialize for Blob { + #[inline] fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -82,10 +83,12 @@ struct BlobVisitor; impl<'de, const L: usize> serde::de::Visitor<'de> for BlobVisitor { type Value = Blob; + #[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(self, mut seq: A) -> Result where A: serde::de::SeqAccess<'de>, @@ -99,6 +102,7 @@ impl<'de, const L: usize> serde::de::Visitor<'de> for BlobVisitor { } impl<'de, const L: usize> Deserialize<'de> for Blob { + #[inline] fn deserialize(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>,