X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fser.rs;h=779bcec194ffa915a04906623d0ee48818b97ed7;hb=8b836e295ec81c50907fe1f60ca43c82df792025;hp=e88c9ba63a5b5700ed06ae6c2a0cac1bcb341c23;hpb=821d8fdb9880a306ff870c45a9268c0dfff1056e;p=dnssec-prover diff --git a/src/ser.rs b/src/ser.rs index e88c9ba..779bcec 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -1,11 +1,10 @@ -//! 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 { let res = *inp.get(0).ok_or(())?; @@ -27,16 +26,16 @@ pub(crate) fn read_u32(inp: &mut &[u8]) -> Result { Ok(u32::from_be_bytes(bytes)) } -fn read_wire_packet_labels(inp: &mut &[u8], wire_packet: &[u8], name: &mut String) -> Result<(), ()> { +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 += "."; } break; - } else if len >= 0xc0 { + } else if len >= 0xc0 && recursion_limit > 0 { let offs = ((len & !0xc0) << 8) | read_u8(inp)? as usize; if offs >= wire_packet.len() { return Err(()); } - read_wire_packet_labels(&mut &wire_packet[offs..], wire_packet, name)?; + do_read_wire_packet_labels(&mut &wire_packet[offs..], wire_packet, name, recursion_limit - 1)?; break; } if inp.len() <= len { return Err(()); } @@ -48,6 +47,10 @@ fn read_wire_packet_labels(inp: &mut &[u8], wire_packet: &[u8], name: &mut Strin 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 { let mut name = String::with_capacity(1024); read_wire_packet_labels(inp, wire_packet, &mut name)?; @@ -56,6 +59,8 @@ pub(crate) fn read_wire_packet_name(inp: &mut &[u8], wire_packet: &[u8]) -> Resu pub(crate) trait Writer { fn write(&mut self, buf: &[u8]); } impl Writer for Vec { 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(out: &mut W, name: &str) { let canonical_name = name.to_ascii_lowercase(); @@ -80,52 +85,57 @@ pub(crate) fn name_len(name: &Name) -> u16 { } } -pub(crate) fn parse_wire_packet_rr(inp: &mut &[u8], wire_packet: &[u8]) -> Result { +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, wire_packet)?)), - AAAA::TYPE => Ok(RR::AAAA(AAAA::read_from_data(name, data, wire_packet)?)), - NS::TYPE => Ok(RR::NS(NS::read_from_data(name, data, wire_packet)?)), - Txt::TYPE => Ok(RR::Txt(Txt::read_from_data(name, data, wire_packet)?)), - CName::TYPE => Ok(RR::CName(CName::read_from_data(name, data, wire_packet)?)), - TLSA::TYPE => Ok(RR::TLSA(TLSA::read_from_data(name, data, wire_packet)?)), - DnsKey::TYPE => Ok(RR::DnsKey(DnsKey::read_from_data(name, data, wire_packet)?)), - DS::TYPE => Ok(RR::DS(DS::read_from_data(name, data, wire_packet)?)), - RRSig::TYPE => Ok(RR::RRSig(RRSig::read_from_data(name, data, wire_packet)?)), - _ => 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 parse_rr(inp: &mut &[u8]) -> Result { - parse_wire_packet_rr(inp, &[]) + parse_wire_packet_rr(inp, &[]).map(|(rr, _)| rr) } -pub(crate) fn bytes_to_rsa_pk<'a>(pubkey: &'a [u8]) --> Result, ()> { - if pubkey.len() <= 3 { return Err(()); } - - 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, ()> { + 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: &RR, ttl: u32, out: &mut Vec) { + 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); }