From: Matt Corallo Date: Tue, 9 Jul 2024 20:54:26 +0000 (+0000) Subject: Keep encoding information in `Txt` `RR`s X-Git-Tag: v0.6.0~2 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=dbe506dceca233de16d32ea30548454a8f65aefe;p=dnssec-prover Keep encoding information in `Txt` `RR`s Sadly `TXT` records can be encoded in many ways (as they're chunked, and chunks can be any size), and are signed in the way in which we receive them on the wire. Thus, we must keep the encoding information we receive on the wire around in `Txt`s to ensure we can validate their signatures. Here we do so, creating a pile of new machinery to store `Txt` data as a series of up-to-255-byte chunks. --- diff --git a/src/query.rs b/src/query.rs index fd99827..e24e52f 100644 --- a/src/query.rs +++ b/src/query.rs @@ -522,7 +522,7 @@ mod tests { assert_eq!(resolved_rrs.len(), 1); if let RR::Txt(txt) = &resolved_rrs[0] { assert_eq!(txt.name.as_str(), "txt_test.dnssec_proof_tests.bitcoin.ninja."); - assert_eq!(txt.data, b"dnssec_prover_test"); + assert_eq!(txt.data.as_vec(), b"dnssec_prover_test"); } else { panic!(); } } } @@ -568,7 +568,7 @@ mod tests { assert_eq!(resolved_rrs.len(), 1); if let RR::Txt(txt) = &resolved_rrs[0] { assert_eq!(txt.name.as_str(), "matt.user._bitcoin-payment.mattcorallo.com."); - assert!(txt.data.starts_with(b"bitcoin:")); + assert!(txt.data.as_vec().starts_with(b"bitcoin:")); } else { panic!(); } } } @@ -594,7 +594,7 @@ mod tests { assert_eq!(resolved_rrs.len(), 1); if let RR::Txt(txt) = &resolved_rrs[0] { assert_eq!(txt.name.as_str(), "cname.wildcard_test.dnssec_proof_tests.bitcoin.ninja."); - assert_eq!(txt.data, b"wildcard_test"); + assert_eq!(txt.data.as_vec(), b"wildcard_test"); } else { panic!(); } } } diff --git a/src/rr.rs b/src/rr.rs index a3839d2..5aa7a57 100644 --- a/src/rr.rs +++ b/src/rr.rs @@ -8,9 +8,10 @@ use alloc::string::String; use alloc::borrow::ToOwned; use alloc::format; -use core::cmp::{self, Ordering}; +use core::cmp::Ordering; use core::fmt; use core::fmt::Write; +use core::num::NonZeroU8; use crate::ser::*; @@ -259,6 +260,126 @@ impl Record for RR { } } +#[derive(Debug, Clone, PartialEq, Eq)] +struct TxtBytePart { + /// The bytes themselves. + /// + /// Bytes at or beyond [`Self::len`] may be filled with garbage and should be ignored. + bytes: [u8; 255], + /// The number of bytes which are to be used. + len: NonZeroU8, +} + +/// The bytes of a [`Txt`] record. +/// +/// They are stored as a series of byte buffers so that we can reconstruct the exact encoding which +/// was used for signatures, however they're really just a simple list of bytes, and the underlying +/// encoding should be ignored. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TxtBytes { + /// The series of byte buffers storing the bytes themselves. + chunks: Vec, +} + +impl TxtBytes { + /// Constructs a new [`TxtBytes`] from the given bytes + /// + /// Fails if there are too many bytes to fit in a [`Txt`] record. + pub fn new(bytes: &[u8]) -> Result { + if bytes.len() > 255*255 + 254 { return Err(()); } + let mut chunks = Vec::with_capacity((bytes.len() + 254) / 255); + let mut data_write = &bytes[..]; + while !data_write.is_empty() { + let split_pos = core::cmp::min(255, data_write.len()); + let mut part = TxtBytePart { + bytes: [0; 255], + len: (split_pos as u8).try_into().expect("Cannot be 0 as data_write is not empty"), + }; + part.bytes[..split_pos].copy_from_slice(&data_write[..split_pos]); + chunks.push(part); + data_write = &data_write[split_pos..]; + } + debug_assert_eq!(chunks.len(), (bytes.len() + 254) / 255); + Ok(TxtBytes { chunks }) + } + + /// Gets the total number of bytes represented in this record. + pub fn len(&self) -> usize { + let mut res = 0; + for chunk in self.chunks.iter() { + res += chunk.len.get() as usize; + } + res + } + + /// The length of the bytes when serialized on the wire. + pub fn serialized_len(&self) -> u16 { + let mut len = 0u16; + for chunk in self.chunks.iter() { + len = len.checked_add(1 + chunk.len.get() as u16) + .expect("TxtBytes objects must fit in 2^16 - 1 bytes when serialized"); + } + len + } + + /// Gets the bytes as a flat `Vec` of `u8`s. This should be considered + pub fn as_vec(&self) -> Vec { + let mut res = Vec::with_capacity(self.len()); + for chunk in self.chunks.iter() { + res.extend_from_slice(&chunk.bytes[..chunk.len.get() as usize]); + } + res + } + + /// Gets an iterator over all the bytes in this [`TxtBytes`]. + pub fn iter<'a>(&'a self) -> TxtBytesIter<'a> { + TxtBytesIter { + bytes: self, + next_part: 0, + next_byte: 0, + } + } +} + +impl TryFrom<&str> for TxtBytes { + type Error = (); + fn try_from(s: &str) -> Result { + TxtBytes::new(s.as_bytes()) + } +} + +impl TryFrom<&[u8]> for TxtBytes { + type Error = (); + fn try_from(b: &[u8]) -> Result { + TxtBytes::new(b) + } +} + +/// An iterator over the bytes in a [`TxtBytes`] +pub struct TxtBytesIter<'a> { + bytes: &'a TxtBytes, + next_part: usize, + next_byte: u8, +} + +impl<'a> Iterator for TxtBytesIter<'a> { + type Item = u8; + fn next(&mut self) -> Option { + self.bytes.chunks.get(self.next_part) + .and_then(|part| if self.next_byte >= part.len.get() { + None + } else { + if self.next_byte == part.len.get() - 1 { + self.next_byte = 0; + self.next_part += 1; + } else { + self.next_byte += 1; + } + Some(part.bytes[self.next_byte as usize]) + }) + } +} + #[derive(Debug, Clone, PartialEq, Eq)] /// A text resource record, containing arbitrary text data pub struct Txt { @@ -268,7 +389,7 @@ pub struct Txt { /// /// While this is generally UTF-8-valid, there is no specific requirement that it be, and thus /// is an arbitrary series of bytes here. - pub data: Vec, + pub data: TxtBytes, } /// The wire type for TXT records pub const TXT_TYPE: u16 = 16; @@ -276,16 +397,24 @@ impl Ord for Txt { fn cmp(&self, o: &Txt) -> Ordering { self.name.cmp(&o.name) .then_with(|| { - // Compare in wire encoding form, i.e. compare in 255-byte chunks - for i in 1..(self.data.len() / 255) + 2 { - let start = (i - 1)*255; - let self_len = cmp::min(i * 255, self.data.len()); - let o_len = cmp::min(i * 255, o.data.len()); - let slice_cmp = self_len.cmp(&o_len) - .then_with(|| self.data[start..self_len].cmp(&o.data[start..o_len])); - if !slice_cmp.is_eq() { return slice_cmp; } + // Compare in wire encoding form, i.e. compare checks in order + let mut o_chunks = o.data.chunks.iter(); + for chunk in self.data.chunks.iter() { + if let Some(o_chunk) = o_chunks.next() { + let chunk_cmp = chunk.len.cmp(&o_chunk.len) + .then_with(||chunk.bytes[..chunk.len.get() as usize] + .cmp(&o_chunk.bytes[..o_chunk.len.get() as usize])); + if !chunk_cmp.is_eq() { return chunk_cmp; } + } else { + // self has more chunks than o + return Ordering::Greater; + } + } + if o_chunks.next().is_some() { + Ordering::Less + } else { + Ordering::Equal } - Ordering::Equal }) } } @@ -296,37 +425,54 @@ impl StaticRecord for Txt { const TYPE: u16 = TXT_TYPE; fn name(&self) -> &Name { &self.name } fn json(&self) -> String { - if let Ok(s) = core::str::from_utf8(&self.data) { - if s.chars().all(|c| !c.is_control() && c != '"' && c != '\\') { - return format!("{{\"type\":\"txt\",\"name\":\"{}\",\"contents\":\"{}\"}}", self.name.0, s); + let mut res = format!("{{\"type\":\"txt\",\"name\":\"{}\",\"contents\":", self.name.0); + if self.data.iter().all(|b| b >= 0x20 && b <= 0x7e) { + res += "\""; + for b in self.data.iter() { + res.push(b as char); } + res += "\"}"; + } else { + res += "["; + let mut first_b = true; + for b in self.data.iter() { + if !first_b { res += ","; } + write!(&mut res, "{}", b).expect("Shouldn't fail to write to a String"); + first_b = false; + } + res += "]}"; } - format!("{{\"type\":\"txt\",\"name\":\"{}\",\"contents\":{:?}}}", self.name.0, &self.data[..]) + res } fn read_from_data(name: Name, mut data: &[u8], _wire_packet: &[u8]) -> Result { - let mut parsed_data = Vec::with_capacity(data.len().saturating_sub(1)); + let mut parts = TxtBytes { + chunks: Vec::with_capacity((data.len() + 255) / 256), + }; + let mut serialized_len = 0; while !data.is_empty() { - let len = read_u8(&mut data)? as usize; - if data.len() < len { return Err(()); } - parsed_data.extend_from_slice(&data[..len]); - data = &data[len..]; + let len = read_u8(&mut data)?; + if data.len() < len as usize { return Err(()); } + if len == 0 { return Err(()); } + serialized_len += 1 + len as u32; + if serialized_len > u16::MAX as u32 { + return Err(()); + } + let mut part = TxtBytePart { + bytes: [0; 255], + len: len.try_into().expect("We already checked 0 above"), + }; + part.bytes[..len as usize].copy_from_slice(&data[..len as usize]); + data = &data[len as usize..]; + parts.chunks.push(part); } debug_assert!(data.is_empty()); - Ok(Txt { name, data: parsed_data }) + Ok(Txt { name, data: parts }) } fn write_u16_len_prefixed_data(&self, out: &mut W) { - let len = (self.data.len() + (self.data.len() + 254) / 255) as u16; - out.write(&len.to_be_bytes()); - - let mut data_write = &self.data[..]; - out.write(&[data_write.len().try_into().unwrap_or(255)]); - while !data_write.is_empty() { - let split_pos = core::cmp::min(255, data_write.len()); - out.write(&data_write[..split_pos]); - data_write = &data_write[split_pos..]; - if !data_write.is_empty() { - out.write(&[data_write.len().try_into().unwrap_or(255)]); - } + out.write(&self.data.serialized_len().to_be_bytes()); + for chunk in self.data.chunks.iter() { + out.write(&[chunk.len.get()]); + out.write(&chunk.bytes[..chunk.len.get() as usize]); } } } diff --git a/src/validation.rs b/src/validation.rs index 3509651..cbcfcfa 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -700,7 +700,7 @@ mod tests { fn mattcorallo_txt_record() -> (Txt, RRSig) { let txt_resp = Txt { name: "matt.user._bitcoin-payment.mattcorallo.com.".try_into().unwrap(), - data: "bitcoin:?b12=lno1qsgqmqvgm96frzdg8m0gc6nzeqffvzsqzrxqy32afmr3jn9ggkwg3egfwch2hy0l6jut6vfd8vpsc3h89l6u3dm4q2d6nuamav3w27xvdmv3lpgklhg7l5teypqz9l53hj7zvuaenh34xqsz2sa967yzqkylfu9xtcd5ymcmfp32h083e805y7jfd236w9afhavqqvl8uyma7x77yun4ehe9pnhu2gekjguexmxpqjcr2j822xr7q34p078gzslf9wpwz5y57alxu99s0z2ql0kfqvwhzycqq45ehh58xnfpuek80hw6spvwrvttjrrq9pphh0dpydh06qqspp5uq4gpyt6n9mwexde44qv7lstzzq60nr40ff38u27un6y53aypmx0p4qruk2tf9mjwqlhxak4znvna5y".to_owned().into_bytes(), + data: "bitcoin:?b12=lno1qsgqmqvgm96frzdg8m0gc6nzeqffvzsqzrxqy32afmr3jn9ggkwg3egfwch2hy0l6jut6vfd8vpsc3h89l6u3dm4q2d6nuamav3w27xvdmv3lpgklhg7l5teypqz9l53hj7zvuaenh34xqsz2sa967yzqkylfu9xtcd5ymcmfp32h083e805y7jfd236w9afhavqqvl8uyma7x77yun4ehe9pnhu2gekjguexmxpqjcr2j822xr7q34p078gzslf9wpwz5y57alxu99s0z2ql0kfqvwhzycqq45ehh58xnfpuek80hw6spvwrvttjrrq9pphh0dpydh06qqspp5uq4gpyt6n9mwexde44qv7lstzzq60nr40ff38u27un6y53aypmx0p4qruk2tf9mjwqlhxak4znvna5y".try_into().unwrap(), }; let txt_rrsig = RRSig { name: "matt.user._bitcoin-payment.mattcorallo.com.".try_into().unwrap(), @@ -744,7 +744,7 @@ mod tests { fn bitcoin_ninja_txt_record() -> (Txt, RRSig) { let txt_resp = Txt { name: "txt_test.dnssec_proof_tests.bitcoin.ninja.".try_into().unwrap(), - data: "dnssec_prover_test".to_owned().into_bytes(), + data: "dnssec_prover_test".try_into().unwrap(), }; let txt_rrsig = RRSig { name: "txt_test.dnssec_proof_tests.bitcoin.ninja.".try_into().unwrap(), @@ -772,28 +772,28 @@ mod tests { fn bitcoin_ninja_txt_sort_edge_cases_records() -> (Vec, RRSig) { let txts = vec![Txt { name: "txt_sort_order.dnssec_proof_tests.bitcoin.ninja.".try_into().unwrap(), - data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab".to_owned().into_bytes(), + data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab".try_into().unwrap(), }, Txt { name: "txt_sort_order.dnssec_proof_tests.bitcoin.ninja.".try_into().unwrap(), - data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".to_owned().into_bytes(), + data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".try_into().unwrap(), }, Txt { name: "txt_sort_order.dnssec_proof_tests.bitcoin.ninja.".try_into().unwrap(), - data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaa".to_owned().into_bytes(), + data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaa".try_into().unwrap(), }, Txt { name: "txt_sort_order.dnssec_proof_tests.bitcoin.ninja.".try_into().unwrap(), - data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaba".to_owned().into_bytes(), + data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaba".try_into().unwrap(), }, Txt { name: "txt_sort_order.dnssec_proof_tests.bitcoin.ninja.".try_into().unwrap(), - data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".to_owned().into_bytes(), + data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".try_into().unwrap(), }, Txt { name: "txt_sort_order.dnssec_proof_tests.bitcoin.ninja.".try_into().unwrap(), - data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab".to_owned().into_bytes(), + data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab".try_into().unwrap(), }, Txt { name: "txt_sort_order.dnssec_proof_tests.bitcoin.ninja.".try_into().unwrap(), - data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".to_owned().into_bytes(), + data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".try_into().unwrap(), }, Txt { name: "txt_sort_order.dnssec_proof_tests.bitcoin.ninja.".try_into().unwrap(), - data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaba".to_owned().into_bytes(), + data: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaba".try_into().unwrap(), }]; let rrsig = RRSig { name: "txt_sort_order.dnssec_proof_tests.bitcoin.ninja.".try_into().unwrap(), @@ -809,7 +809,7 @@ mod tests { let name: Name = (pfx.to_owned() + ".wildcard_test.dnssec_proof_tests.bitcoin.ninja.").try_into().unwrap(); let txt_resp = Txt { name: name.clone(), - data: "wildcard_test".to_owned().into_bytes(), + data: "wildcard_test".try_into().unwrap(), }; let txt_rrsig = RRSig { name: name.clone(), @@ -910,7 +910,7 @@ mod tests { fn bitcoin_ninja_nsec_record() -> (Txt, RRSig) { let txt_resp = Txt { name: "a.nsec_tests.dnssec_proof_tests.bitcoin.ninja.".try_into().unwrap(), - data: "txt_a".to_owned().into_bytes(), + data: "txt_a".try_into().unwrap(), }; let txt_rrsig = RRSig { name: "a.nsec_tests.dnssec_proof_tests.bitcoin.ninja.".try_into().unwrap(), @@ -925,7 +925,7 @@ mod tests { let name: Name = (pfx.to_owned() + ".wildcard_test.nsec_tests.dnssec_proof_tests.bitcoin.ninja.").try_into().unwrap(); let txt_resp = Txt { name: name.clone(), - data: "wildcard_test".to_owned().into_bytes(), + data: "wildcard_test".try_into().unwrap(), }; let txt_rrsig = RRSig { name: name.clone(), @@ -951,7 +951,7 @@ mod tests { let name: Name = (pfx.to_owned() + ".wildcard_test.nsec_tests.dnssec_proof_tests.bitcoin.ninja.").try_into().unwrap(); let txt_resp = Txt { name: name.clone(), - data: "wildcard_test".to_owned().into_bytes(), + data: "wildcard_test".try_into().unwrap(), }; let txt_rrsig = RRSig { name: name.clone(), @@ -996,7 +996,7 @@ mod tests { assert_eq!(verified_rrs.verified_rrs.len(), 1); if let RR::Txt(txt) = &verified_rrs.verified_rrs[0] { assert_eq!(txt.name.as_str(), "matt.user._bitcoin-payment.mattcorallo.com."); - assert_eq!(txt.data, b"bitcoin:?b12=lno1qsgqmqvgm96frzdg8m0gc6nzeqffvzsqzrxqy32afmr3jn9ggkwg3egfwch2hy0l6jut6vfd8vpsc3h89l6u3dm4q2d6nuamav3w27xvdmv3lpgklhg7l5teypqz9l53hj7zvuaenh34xqsz2sa967yzqkylfu9xtcd5ymcmfp32h083e805y7jfd236w9afhavqqvl8uyma7x77yun4ehe9pnhu2gekjguexmxpqjcr2j822xr7q34p078gzslf9wpwz5y57alxu99s0z2ql0kfqvwhzycqq45ehh58xnfpuek80hw6spvwrvttjrrq9pphh0dpydh06qqspp5uq4gpyt6n9mwexde44qv7lstzzq60nr40ff38u27un6y53aypmx0p4qruk2tf9mjwqlhxak4znvna5y"); + assert_eq!(txt.data.as_vec(), b"bitcoin:?b12=lno1qsgqmqvgm96frzdg8m0gc6nzeqffvzsqzrxqy32afmr3jn9ggkwg3egfwch2hy0l6jut6vfd8vpsc3h89l6u3dm4q2d6nuamav3w27xvdmv3lpgklhg7l5teypqz9l53hj7zvuaenh34xqsz2sa967yzqkylfu9xtcd5ymcmfp32h083e805y7jfd236w9afhavqqvl8uyma7x77yun4ehe9pnhu2gekjguexmxpqjcr2j822xr7q34p078gzslf9wpwz5y57alxu99s0z2ql0kfqvwhzycqq45ehh58xnfpuek80hw6spvwrvttjrrq9pphh0dpydh06qqspp5uq4gpyt6n9mwexde44qv7lstzzq60nr40ff38u27un6y53aypmx0p4qruk2tf9mjwqlhxak4znvna5y"); } else { panic!(); } assert_eq!(verified_rrs.valid_from, 1709047250); // The mattcorallo.com. DNSKEY RRSig was created last assert_eq!(verified_rrs.expires, 1709359258); // The mattcorallo.com. DS RRSig expires first @@ -1041,11 +1041,11 @@ mod tests { assert_eq!(verified_rrs.verified_rrs.len(), 3); if let RR::Txt(txt) = &verified_rrs.verified_rrs[0] { assert_eq!(txt.name.as_str(), "matt.user._bitcoin-payment.mattcorallo.com."); - assert_eq!(txt.data, b"bitcoin:?b12=lno1qsgqmqvgm96frzdg8m0gc6nzeqffvzsqzrxqy32afmr3jn9ggkwg3egfwch2hy0l6jut6vfd8vpsc3h89l6u3dm4q2d6nuamav3w27xvdmv3lpgklhg7l5teypqz9l53hj7zvuaenh34xqsz2sa967yzqkylfu9xtcd5ymcmfp32h083e805y7jfd236w9afhavqqvl8uyma7x77yun4ehe9pnhu2gekjguexmxpqjcr2j822xr7q34p078gzslf9wpwz5y57alxu99s0z2ql0kfqvwhzycqq45ehh58xnfpuek80hw6spvwrvttjrrq9pphh0dpydh06qqspp5uq4gpyt6n9mwexde44qv7lstzzq60nr40ff38u27un6y53aypmx0p4qruk2tf9mjwqlhxak4znvna5y"); + assert_eq!(txt.data.as_vec(), b"bitcoin:?b12=lno1qsgqmqvgm96frzdg8m0gc6nzeqffvzsqzrxqy32afmr3jn9ggkwg3egfwch2hy0l6jut6vfd8vpsc3h89l6u3dm4q2d6nuamav3w27xvdmv3lpgklhg7l5teypqz9l53hj7zvuaenh34xqsz2sa967yzqkylfu9xtcd5ymcmfp32h083e805y7jfd236w9afhavqqvl8uyma7x77yun4ehe9pnhu2gekjguexmxpqjcr2j822xr7q34p078gzslf9wpwz5y57alxu99s0z2ql0kfqvwhzycqq45ehh58xnfpuek80hw6spvwrvttjrrq9pphh0dpydh06qqspp5uq4gpyt6n9mwexde44qv7lstzzq60nr40ff38u27un6y53aypmx0p4qruk2tf9mjwqlhxak4znvna5y"); } else { panic!(); } if let RR::Txt(txt) = &verified_rrs.verified_rrs[1] { assert_eq!(txt.name.as_str(), "txt_test.dnssec_proof_tests.bitcoin.ninja."); - assert_eq!(txt.data, b"dnssec_prover_test"); + assert_eq!(txt.data.as_vec(), b"dnssec_prover_test"); } else { panic!(); } if let RR::CName(cname) = &verified_rrs.verified_rrs[2] { assert_eq!(cname.name.as_str(), "cname_test.dnssec_proof_tests.bitcoin.ninja."); @@ -1057,7 +1057,7 @@ mod tests { assert_eq!(filtered_rrs.len(), 1); if let RR::Txt(txt) = &filtered_rrs[0] { assert_eq!(txt.name.as_str(), "txt_test.dnssec_proof_tests.bitcoin.ninja."); - assert_eq!(txt.data, b"dnssec_prover_test"); + assert_eq!(txt.data.as_vec(), b"dnssec_prover_test"); } else { panic!(); } } @@ -1096,7 +1096,7 @@ mod tests { assert_eq!(verified_rrs.verified_rrs.len(), 2); if let RR::Txt(txt) = &verified_rrs.verified_rrs[0] { assert_eq!(txt.name.as_str(), "asdf.wildcard_test.dnssec_proof_tests.bitcoin.ninja."); - assert_eq!(txt.data, b"wildcard_test"); + assert_eq!(txt.data.as_vec(), b"wildcard_test"); } else { panic!(); } if let RR::CName(cname) = &verified_rrs.verified_rrs[1] { assert_eq!(cname.name.as_str(), "asdf.cname_wildcard_test.dnssec_proof_tests.bitcoin.ninja."); @@ -1108,7 +1108,7 @@ mod tests { assert_eq!(filtered_rrs.len(), 1); if let RR::Txt(txt) = &filtered_rrs[0] { assert_eq!(txt.name.as_str(), "asdf.wildcard_test.dnssec_proof_tests.bitcoin.ninja."); - assert_eq!(txt.data, b"wildcard_test"); + assert_eq!(txt.data.as_vec(), b"wildcard_test"); } else { panic!(); } } @@ -1130,7 +1130,7 @@ mod tests { assert_eq!(filtered_rrs.len(), 1); if let RR::Txt(txt) = &filtered_rrs[0] { assert_eq!(txt.name.as_str(), "a.nsec_tests.dnssec_proof_tests.bitcoin.ninja."); - assert_eq!(txt.data, b"txt_a"); + assert_eq!(txt.data.as_vec(), b"txt_a"); } else { panic!(); } } @@ -1161,7 +1161,7 @@ mod tests { assert_eq!(filtered_rrs.len(), 1); if let RR::Txt(txt) = &filtered_rrs[0] { assert_eq!(txt.name, name); - assert_eq!(txt.data, b"wildcard_test"); + assert_eq!(txt.data.as_vec(), b"wildcard_test"); } else { panic!(); } Ok(()) };