From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 286131FF16B for ; Fri, 26 Sep 2025 13:08:13 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 2CDCBDF9C; Fri, 26 Sep 2025 13:08:46 +0200 (CEST) From: Nicolas Frey To: pbs-devel@lists.proxmox.com Date: Fri, 26 Sep 2025 13:08:42 +0200 Message-ID: <20250926110842.216011-1-n.frey@proxmox.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.187 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RDNS_NONE 0.793 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Subject: [pbs-devel] [PATCH pbs-api-types] crypto: improve deserialization for Fingerprint with custom visitor X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Backup Server development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pbs-devel-bounces@lists.proxmox.com Sender: "pbs-devel" Improve Fingerprint deserialization by introducing a custom Visitor, which: - eliminates unsafe code by zero-initializing buffers - removes unnecessary allocations by using a fixed-size buffer - improves efficiency by filtering and decoding directly from input Also added tests to establish baseline behavior and verify correctness. Signed-off-by: Nicolas Frey --- pbs-api-types/src/crypto.rs | 102 ++++++++++++++++++++++++++++++++---- 1 file changed, 92 insertions(+), 10 deletions(-) diff --git a/pbs-api-types/src/crypto.rs b/pbs-api-types/src/crypto.rs index cdc1ba64..a9528022 100644 --- a/pbs-api-types/src/crypto.rs +++ b/pbs-api-types/src/crypto.rs @@ -67,9 +67,9 @@ fn as_fingerprint(bytes: &[u8]) -> String { } pub mod bytes_as_fingerprint { - use std::mem::MaybeUninit; + use std::fmt; - use serde::{Deserialize, Deserializer, Serializer}; + use serde::{de, Deserializer, Serializer}; pub fn serialize(bytes: &[u8; 32], serializer: S) -> Result where @@ -83,13 +83,95 @@ pub mod bytes_as_fingerprint { where D: Deserializer<'de>, { - // TODO: more efficiently implement with a Visitor implementing visit_str using split() and - // hex::decode by-byte - let mut s = String::deserialize(deserializer)?; - s.retain(|c| c != ':'); - let mut out = MaybeUninit::<[u8; 32]>::uninit(); - hex::decode_to_slice(s.as_bytes(), unsafe { &mut (*out.as_mut_ptr())[..] }) - .map_err(serde::de::Error::custom)?; - Ok(unsafe { out.assume_init() }) + struct FingerprintVisitor; + + impl<'de> de::Visitor<'de> for FingerprintVisitor { + type Value = [u8; 32]; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("a 32-byte fingerprint hex string with colons") + } + + fn visit_str(self, val: &str) -> Result + where + E: de::Error, + { + let mut filtered = [0u8; 64]; + let mut idx = 0; + + for &b in val.as_bytes().iter().filter(|&&b| b != b':') { + if idx == 64 { + return Err(E::custom("fingerprint too long")); + } + filtered[idx] = b; + idx += 1; + } + + if idx != 64 { + return Err(E::custom("fingerprint too short")); + } + + let mut out = [0u8; 32]; + hex::decode_to_slice(&filtered, &mut out).map_err(serde::de::Error::custom)?; + Ok(out) + } + } + + deserializer.deserialize_str(FingerprintVisitor) + } +} + +#[cfg(test)] +mod tests { + use super::Fingerprint; + + static SAMPLE_BYTES: [u8; 32] = [ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, + 0xff, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, + 0xf0, 0x01, + ]; + + #[test] + fn serialize_valid() { + let s = Fingerprint::new(SAMPLE_BYTES); + let encoded = serde_plain::to_string(&s).unwrap(); + assert!(encoded.contains("00:11:22:33:44:55:66:77")); + assert!(encoded.contains("f0:01")); + } + + #[test] + fn deserialize_valid() { + let s = "00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:10:20:30:40:50:60:70:80:90:a0:b0:c0:d0:e0:f0:01"; + let parsed = serde_plain::from_str::(s).unwrap(); + assert_eq!(parsed.bytes(), &SAMPLE_BYTES); + } + + #[test] + fn roundtrip() { + let original = Fingerprint::new(SAMPLE_BYTES); + let encoded = serde_plain::to_string(&original).unwrap(); + let decoded: Fingerprint = serde_plain::from_str(&encoded).unwrap(); + assert_eq!(decoded, original); + } + + #[test] + fn deserialize_invalid_char() { + let s = "zz:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:10:20:30:40:50:60:70:80:90:a0:b0:c0:d0:e0:f0:01"; + let parsed = serde_plain::from_str::(s); + assert!(parsed.is_err()); + } + + #[test] + fn deserialize_too_short() { + let s = "00:11:22:33"; + let parsed = serde_plain::from_str::(s); + assert!(parsed.is_err()); + } + + #[test] + fn deserialize_too_long() { + let s = &"00:".repeat(33); + let parsed = serde_plain::from_str::(&s); + assert!(parsed.is_err()); } } -- 2.47.3 _______________________________________________ pbs-devel mailing list pbs-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel