-//! Serialization/Deserialization logic lives here
+//! Logic to read and write resource record (streams)
use alloc::vec::Vec;
use alloc::string::String;
-use ring::signature;
-
use crate::rr::*;
+use crate::query::QueryBuf;
pub(crate) fn read_u8(inp: &mut &[u8]) -> Result<u8, ()> {
let res = *inp.get(0).ok_or(())?;
Ok(u32::from_be_bytes(bytes))
}
-pub(crate) fn read_name(inp: &mut &[u8]) -> Result<Name, ()> {
- let mut name = String::with_capacity(1024);
+fn do_read_wire_packet_labels(inp: &mut &[u8], wire_packet: &[u8], name: &mut String, recursion_limit: usize) -> Result<(), ()> {
loop {
let len = read_u8(inp)? as usize;
if len == 0 {
- if name.is_empty() { name += "."; }
+ if name.is_empty() { *name += "."; }
+ break;
+ } else if len >= 0xc0 && recursion_limit > 0 {
+ let offs = ((len & !0xc0) << 8) | read_u8(inp)? as usize;
+ if offs >= wire_packet.len() { return Err(()); }
+ do_read_wire_packet_labels(&mut &wire_packet[offs..], wire_packet, name, recursion_limit - 1)?;
break;
}
if inp.len() <= len { return Err(()); }
- name += core::str::from_utf8(&inp[..len]).map_err(|_| ())?;
- name += ".";
+ *name += core::str::from_utf8(&inp[..len]).map_err(|_| ())?;
+ *name += ".";
*inp = &inp[len..];
- if name.len() > 1024 { return Err(()); }
+ if name.len() > 255 { return Err(()); }
}
+ Ok(())
+}
+
+fn read_wire_packet_labels(inp: &mut &[u8], wire_packet: &[u8], name: &mut String) -> Result<(), ()> {
+ do_read_wire_packet_labels(inp, wire_packet, name, 255)
+}
+
+pub(crate) fn read_wire_packet_name(inp: &mut &[u8], wire_packet: &[u8]) -> Result<Name, ()> {
+ let mut name = String::with_capacity(1024);
+ read_wire_packet_labels(inp, wire_packet, &mut name)?;
Ok(name.try_into()?)
}
pub(crate) trait Writer { fn write(&mut self, buf: &[u8]); }
impl Writer for Vec<u8> { fn write(&mut self, buf: &[u8]) { self.extend_from_slice(buf); } }
+impl Writer for QueryBuf { fn write(&mut self, buf: &[u8]) { self.extend_from_slice(buf); } }
+#[cfg(feature = "validation")]
impl Writer for ring::digest::Context { fn write(&mut self, buf: &[u8]) { self.update(buf); } }
pub(crate) fn write_name<W: Writer>(out: &mut W, name: &str) {
let canonical_name = name.to_ascii_lowercase();
}
}
-pub(crate) fn parse_rr(inp: &mut &[u8]) -> Result<RR, ()> {
- let name = read_name(inp)?;
+pub(crate) fn parse_wire_packet_rr(inp: &mut &[u8], wire_packet: &[u8]) -> Result<(RR, u32), ()> {
+ let name = read_wire_packet_name(inp, wire_packet)?;
let ty = read_u16(inp)?;
let class = read_u16(inp)?;
if class != 1 { return Err(()); } // We only support the INternet
- let _ttl = read_u32(inp)?;
+ let ttl = read_u32(inp)?;
let data_len = read_u16(inp)? as usize;
if inp.len() < data_len { return Err(()); }
let data = &inp[..data_len];
*inp = &inp[data_len..];
- match ty {
- A::TYPE => Ok(RR::A(A::read_from_data(name, data)?)),
- AAAA::TYPE => Ok(RR::AAAA(AAAA::read_from_data(name, data)?)),
- NS::TYPE => Ok(RR::NS(NS::read_from_data(name, data)?)),
- Txt::TYPE => {
- Ok(RR::Txt(Txt::read_from_data(name, data)?))
- }
- CName::TYPE => {
- Ok(RR::CName(CName::read_from_data(name, data)?))
- }
- TLSA::TYPE => {
- Ok(RR::TLSA(TLSA::read_from_data(name, data)?))
- },
- DnsKey::TYPE => {
- Ok(RR::DnsKey(DnsKey::read_from_data(name, data)?))
- },
- DS::TYPE => {
- Ok(RR::DS(DS::read_from_data(name, data)?))
- },
- RRSig::TYPE => {
- Ok(RR::RRSig(RRSig::read_from_data(name, data)?))
- },
- _ => Err(()),
- }
+ let rr = match ty {
+ A::TYPE => RR::A(A::read_from_data(name, data, wire_packet)?),
+ AAAA::TYPE => RR::AAAA(AAAA::read_from_data(name, data, wire_packet)?),
+ NS::TYPE => RR::NS(NS::read_from_data(name, data, wire_packet)?),
+ Txt::TYPE => RR::Txt(Txt::read_from_data(name, data, wire_packet)?),
+ CName::TYPE => RR::CName(CName::read_from_data(name, data, wire_packet)?),
+ DName::TYPE => RR::DName(DName::read_from_data(name, data, wire_packet)?),
+ TLSA::TYPE => RR::TLSA(TLSA::read_from_data(name, data, wire_packet)?),
+ DnsKey::TYPE => RR::DnsKey(DnsKey::read_from_data(name, data, wire_packet)?),
+ DS::TYPE => RR::DS(DS::read_from_data(name, data, wire_packet)?),
+ RRSig::TYPE => RR::RRSig(RRSig::read_from_data(name, data, wire_packet)?),
+ _ => return Err(()),
+ };
+ Ok((rr, ttl))
}
-pub(crate) fn bytes_to_rsa_pk<'a>(pubkey: &'a [u8])
--> Result<signature::RsaPublicKeyComponents<&'a [u8]>, ()> {
- if pubkey.len() <= 3 { return Err(()); }
+pub(crate) fn parse_rr(inp: &mut &[u8]) -> Result<RR, ()> {
+ parse_wire_packet_rr(inp, &[]).map(|(rr, _)| rr)
+}
- let mut pos = 0;
- let exponent_length;
- if pubkey[0] == 0 {
- exponent_length = ((pubkey[1] as usize) << 8) | (pubkey[2] as usize);
- pos += 3;
- } else {
- exponent_length = pubkey[0] as usize;
- pos += 1;
+/// Parse a stream of [`RR`]s from the format described in [RFC 9102](https://www.rfc-editor.org/rfc/rfc9102.html).
+///
+/// Note that this is only the series of `AuthenticationChain` records, and does not read the
+/// `ExtSupportLifetime` field at the start of a `DnssecChainExtension`.
+pub fn parse_rr_stream(mut inp: &[u8]) -> Result<Vec<RR>, ()> {
+ let mut res = Vec::with_capacity(32);
+ while !inp.is_empty() {
+ res.push(parse_rr(&mut inp)?);
}
+ Ok(res)
+}
- if pubkey.len() <= pos + exponent_length { return Err(()); }
- Ok(signature::RsaPublicKeyComponents {
- n: &pubkey[pos + exponent_length..],
- e: &pubkey[pos..pos + exponent_length]
- })
+/// Writes the given resource record in its wire encoding to the given `Vec`.
+///
+/// An [RFC 9102](https://www.rfc-editor.org/rfc/rfc9102.html) `AuthenticationChain` is simply a
+/// series of such records with no additional bytes in between.
+pub fn write_rr<RR: Record>(rr: &RR, ttl: u32, out: &mut Vec<u8>) {
+ write_name(out, rr.name());
+ out.extend_from_slice(&rr.ty().to_be_bytes());
+ out.extend_from_slice(&1u16.to_be_bytes()); // The INternet class
+ out.extend_from_slice(&ttl.to_be_bytes());
+ rr.write_u16_len_prefixed_data(out);
}