implement RecordData for most DNSSEC RData types

This commit is contained in:
Benjamin Fry 2022-12-28 15:14:06 -08:00
parent 3919e66d9f
commit 0f21992811
14 changed files with 1068 additions and 566 deletions

View File

@ -0,0 +1,80 @@
// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! CDNSKEY type and related implementations
use std::{fmt, ops::Deref};
#[cfg(feature = "serde-config")]
use serde::{Deserialize, Serialize};
use crate::{
error::ProtoResult,
rr::{RData, RecordData, RecordDataDecodable, RecordType},
serialize::binary::{BinDecoder, BinEncodable, BinEncoder, Restrict},
};
use super::{DNSSECRData, DNSKEY};
/// RRSIG is really a derivation of the original SIG record data. See SIG for more documentation
#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct CDNSKEY(DNSKEY);
impl Deref for CDNSKEY {
type Target = DNSKEY;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl BinEncodable for CDNSKEY {
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
self.0.emit(encoder)
}
}
impl<'r> RecordDataDecodable<'r> for CDNSKEY {
fn read_data(
decoder: &mut BinDecoder<'r>,
record_type: RecordType,
length: Restrict<u16>,
) -> ProtoResult<Self> {
DNSKEY::read_data(decoder, record_type, length).map(Self)
}
}
impl RecordData for CDNSKEY {
fn try_from_rdata(data: RData) -> Result<Self, RData> {
match data {
RData::DNSSEC(DNSSECRData::CDNSKEY(cdnskey)) => Ok(cdnskey),
_ => Err(data),
}
}
fn try_borrow(data: &RData) -> Result<&Self, &RData> {
match data {
RData::DNSSEC(DNSSECRData::CDNSKEY(cdnskey)) => Ok(cdnskey),
_ => Err(data),
}
}
fn record_type(&self) -> RecordType {
RecordType::CDNSKEY
}
fn into_rdata(self) -> RData {
RData::DNSSEC(DNSSECRData::CDNSKEY(self))
}
}
impl fmt::Display for CDNSKEY {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}", self.0)
}
}

View File

@ -0,0 +1,80 @@
// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! CDS type and related implementations
use std::{fmt, ops::Deref};
#[cfg(feature = "serde-config")]
use serde::{Deserialize, Serialize};
use crate::{
error::ProtoResult,
rr::{RData, RecordData, RecordDataDecodable, RecordType},
serialize::binary::{BinDecoder, BinEncodable, BinEncoder, Restrict},
};
use super::{DNSSECRData, DS};
/// RRSIG is really a derivation of the original SIG record data. See SIG for more documentation
#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct CDS(DS);
impl Deref for CDS {
type Target = DS;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl BinEncodable for CDS {
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
self.0.emit(encoder)
}
}
impl<'r> RecordDataDecodable<'r> for CDS {
fn read_data(
decoder: &mut BinDecoder<'r>,
record_type: RecordType,
length: Restrict<u16>,
) -> ProtoResult<Self> {
DS::read_data(decoder, record_type, length).map(Self)
}
}
impl RecordData for CDS {
fn try_from_rdata(data: RData) -> Result<Self, RData> {
match data {
RData::DNSSEC(DNSSECRData::CDS(cds)) => Ok(cds),
_ => Err(data),
}
}
fn try_borrow(data: &RData) -> Result<&Self, &RData> {
match data {
RData::DNSSEC(DNSSECRData::CDS(cds)) => Ok(cds),
_ => Err(data),
}
}
fn record_type(&self) -> RecordType {
RecordType::CDS
}
fn into_rdata(self) -> RData {
RData::DNSSEC(DNSSECRData::CDS(self))
}
}
impl fmt::Display for CDS {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}", self.0)
}
}

View File

@ -1,18 +1,9 @@
/*
* Copyright (C) 2016 Benjamin Fry <benjaminfry@me.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! public key record data for signing zone records
@ -24,11 +15,13 @@ use serde::{Deserialize, Serialize};
use crate::error::*;
use crate::rr::dnssec::{Algorithm, Digest, DigestType};
use crate::rr::record_data::RData;
use crate::rr::Name;
use crate::rr::{Name, RecordData, RecordDataDecodable, RecordType};
use crate::serialize::binary::{
BinDecodable, BinDecoder, BinEncodable, BinEncoder, Restrict, RestrictedMath,
};
use super::DNSSECRData;
/// [RFC 4034](https://tools.ietf.org/html/rfc4034#section-2), DNSSEC Resource Records, March 2005
///
/// ```text
@ -247,7 +240,7 @@ impl DNSKEY {
encoder.set_canonical_names(true);
if let Err(e) = name
.emit(&mut encoder)
.and_then(|_| emit(&mut encoder, self))
.and_then(|_| self.emit(&mut encoder))
{
tracing::warn!("error serializing dnskey: {e}");
return Err(format!("error serializing dnskey: {e}").into());
@ -322,7 +315,7 @@ impl DNSKEY {
let mut bytes: Vec<u8> = Vec::with_capacity(512);
{
let mut e = BinEncoder::new(&mut bytes);
self::emit(&mut e, self)?;
self.emit(&mut e)?;
}
Ok(Self::calculate_key_tag_internal(&bytes))
}
@ -346,62 +339,93 @@ impl From<DNSKEY> for RData {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder<'_>, rdata_length: Restrict<u16>) -> ProtoResult<DNSKEY> {
let flags: u16 = decoder.read_u16()?.unverified(/*used as a bitfield, this is safe*/);
impl BinEncodable for DNSKEY {
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
encoder.emit_u16(self.flags())?;
encoder.emit(3)?; // always 3 for now
self.algorithm().emit(encoder)?;
encoder.emit_vec(self.public_key())?;
// Bits 0-6 and 8-14 are reserved: these bits MUST have value 0 upon
// creation of the DNSKEY RR and MUST be ignored upon receipt.
let zone_key: bool = flags & 0b0000_0001_0000_0000 == 0b0000_0001_0000_0000;
let secure_entry_point: bool = flags & 0b0000_0000_0000_0001 == 0b0000_0000_0000_0001;
let revoke: bool = flags & 0b0000_0000_1000_0000 == 0b0000_0000_1000_0000;
let _protocol: u8 = decoder
.read_u8()?
.verify_unwrap(|protocol| {
// RFC 4034 DNSSEC Resource Records March 2005
//
// 2.1.2. The Protocol Field
//
// The Protocol Field MUST have value 3, and the DNSKEY RR MUST be
// treated as invalid during signature verification if it is found to be
// some value other than 3.
//
// protocol is defined to only be '3' right now
Ok(())
}
}
*protocol == 3
})
.map_err(|protocol| ProtoError::from(ProtoErrorKind::DnsKeyProtocolNot3(protocol)))?;
impl<'r> RecordDataDecodable<'r> for DNSKEY {
fn read_data(
decoder: &mut BinDecoder<'r>,
record_type: RecordType,
length: Restrict<u16>,
) -> ProtoResult<Self> {
assert_eq!(record_type, RecordType::DNSKEY);
let flags: u16 = decoder.read_u16()?.unverified(/*used as a bitfield, this is safe*/);
let algorithm: Algorithm = Algorithm::read(decoder)?;
// Bits 0-6 and 8-14 are reserved: these bits MUST have value 0 upon
// creation of the DNSKEY RR and MUST be ignored upon receipt.
let zone_key: bool = flags & 0b0000_0001_0000_0000 == 0b0000_0001_0000_0000;
let secure_entry_point: bool = flags & 0b0000_0000_0000_0001 == 0b0000_0000_0000_0001;
let revoke: bool = flags & 0b0000_0000_1000_0000 == 0b0000_0000_1000_0000;
let _protocol: u8 = decoder
.read_u8()?
.verify_unwrap(|protocol| {
// RFC 4034 DNSSEC Resource Records March 2005
//
// 2.1.2. The Protocol Field
//
// The Protocol Field MUST have value 3, and the DNSKEY RR MUST be
// treated as invalid during signature verification if it is found to be
// some value other than 3.
//
// protocol is defined to only be '3' right now
// the public key is the left-over bytes minus 4 for the first fields
// this sub is safe, as the first 4 fields must have been in the rdata, otherwise there would have been
// an earlier return.
let key_len = rdata_length
*protocol == 3
})
.map_err(|protocol| ProtoError::from(ProtoErrorKind::DnsKeyProtocolNot3(protocol)))?;
let algorithm: Algorithm = Algorithm::read(decoder)?;
// the public key is the left-over bytes minus 4 for the first fields
// this sub is safe, as the first 4 fields must have been in the rdata, otherwise there would have been
// an earlier return.
let key_len = length
.map(|u| u as usize)
.checked_sub(4)
.map_err(|_| ProtoError::from("invalid rdata length in DNSKEY"))?
.unverified(/*used only as length safely*/);
let public_key: Vec<u8> =
decoder.read_vec(key_len)?.unverified(/*the byte array will fail in usage if invalid*/);
let public_key: Vec<u8> =
decoder.read_vec(key_len)?.unverified(/*the byte array will fail in usage if invalid*/);
Ok(DNSKEY::new(
zone_key,
secure_entry_point,
revoke,
algorithm,
public_key,
))
Ok(Self::new(
zone_key,
secure_entry_point,
revoke,
algorithm,
public_key,
))
}
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder<'_>, rdata: &DNSKEY) -> ProtoResult<()> {
encoder.emit_u16(rdata.flags())?;
encoder.emit(3)?; // always 3 for now
rdata.algorithm().emit(encoder)?;
encoder.emit_vec(rdata.public_key())?;
impl RecordData for DNSKEY {
fn try_from_rdata(data: RData) -> Result<Self, RData> {
match data {
RData::DNSSEC(DNSSECRData::DNSKEY(csync)) => Ok(csync),
_ => Err(data),
}
}
Ok(())
fn try_borrow(data: &RData) -> Result<&Self, &RData> {
match data {
RData::DNSSEC(DNSSECRData::DNSKEY(csync)) => Ok(csync),
_ => Err(data),
}
}
fn record_type(&self) -> RecordType {
RecordType::DNSKEY
}
fn into_rdata(self) -> RData {
RData::DNSSEC(DNSSECRData::DNSKEY(self))
}
}
/// [RFC 4034, DNSSEC Resource Records, March 2005](https://tools.ietf.org/html/rfc4034#section-2.2)
@ -476,13 +500,17 @@ mod tests {
let mut bytes = Vec::new();
let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
assert!(emit(&mut encoder, &rdata).is_ok());
assert!(rdata.emit(&mut encoder).is_ok());
let bytes = encoder.into_bytes();
println!("bytes: {bytes:?}");
let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
let read_rdata = read(&mut decoder, Restrict::new(bytes.len() as u16));
let read_rdata = DNSKEY::read_data(
&mut decoder,
RecordType::DNSKEY,
Restrict::new(bytes.len() as u16),
);
let read_rdata = read_rdata.expect("error decoding");
assert_eq!(rdata, read_rdata);

View File

@ -1,18 +1,9 @@
/*
* Copyright (C) 2016 Benjamin Fry <benjaminfry@me.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! pointer record from parent zone to child zone for dnskey proof
@ -26,7 +17,9 @@ use crate::rr::dnssec::{Algorithm, DigestType};
use crate::serialize::binary::*;
use crate::rr::dnssec::rdata::DNSKEY;
use crate::rr::Name;
use crate::rr::{Name, RData, RecordData, RecordDataDecodable, RecordType};
use super::DNSSECRData;
/// [RFC 4034, DNSSEC Resource Records, March 2005](https://tools.ietf.org/html/rfc4034#section-5)
///
@ -197,35 +190,65 @@ impl DS {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder<'_>, rdata_length: Restrict<u16>) -> ProtoResult<DS> {
let start_idx = decoder.index();
impl BinEncodable for DS {
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
encoder.emit_u16(self.key_tag())?;
self.algorithm().emit(encoder)?; // always 3 for now
encoder.emit(self.digest_type().into())?;
encoder.emit_vec(self.digest())?;
let key_tag: u16 = decoder.read_u16()?.unverified(/*key_tag is valid as any u16*/);
let algorithm: Algorithm = Algorithm::read(decoder)?;
let digest_type: DigestType =
DigestType::from_u8(decoder.read_u8()?.unverified(/*DigestType is verified as safe*/))?;
Ok(())
}
}
let bytes_read = decoder.index() - start_idx;
let left: usize = rdata_length
impl<'r> RecordDataDecodable<'r> for DS {
fn read_data(
decoder: &mut BinDecoder<'r>,
_record_type: RecordType,
length: Restrict<u16>,
) -> ProtoResult<Self> {
let start_idx = decoder.index();
let key_tag: u16 = decoder.read_u16()?.unverified(/*key_tag is valid as any u16*/);
let algorithm: Algorithm = Algorithm::read(decoder)?;
let digest_type: DigestType =
DigestType::from_u8(decoder.read_u8()?.unverified(/*DigestType is verified as safe*/))?;
let bytes_read = decoder.index() - start_idx;
let left: usize = length
.map(|u| u as usize)
.checked_sub(bytes_read)
.map_err(|_| ProtoError::from("invalid rdata length in DS"))?
.unverified(/*used only as length safely*/);
let digest =
decoder.read_vec(left)?.unverified(/*the byte array will fail in usage if invalid*/);
let digest =
decoder.read_vec(left)?.unverified(/*the byte array will fail in usage if invalid*/);
Ok(DS::new(key_tag, algorithm, digest_type, digest))
Ok(Self::new(key_tag, algorithm, digest_type, digest))
}
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder<'_>, rdata: &DS) -> ProtoResult<()> {
encoder.emit_u16(rdata.key_tag())?;
rdata.algorithm().emit(encoder)?; // always 3 for now
encoder.emit(rdata.digest_type().into())?;
encoder.emit_vec(rdata.digest())?;
impl RecordData for DS {
fn try_from_rdata(data: RData) -> Result<Self, RData> {
match data {
RData::DNSSEC(DNSSECRData::DS(csync)) => Ok(csync),
_ => Err(data),
}
}
Ok(())
fn try_borrow(data: &RData) -> Result<&Self, &RData> {
match data {
RData::DNSSEC(DNSSECRData::DS(csync)) => Ok(csync),
_ => Err(data),
}
}
fn record_type(&self) -> RecordType {
RecordType::DS
}
fn into_rdata(self) -> RData {
RData::DNSSEC(DNSSECRData::DS(self))
}
}
/// [RFC 4034, DNSSEC Resource Records, March 2005](https://tools.ietf.org/html/rfc4034#section-5.3)
@ -301,14 +324,15 @@ mod tests {
let mut bytes = Vec::new();
let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
assert!(emit(&mut encoder, &rdata).is_ok());
assert!(rdata.emit(&mut encoder).is_ok());
let bytes = encoder.into_bytes();
println!("bytes: {bytes:?}");
let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
let restrict = Restrict::new(bytes.len() as u16);
let read_rdata = read(&mut decoder, restrict).expect("Decoding error");
let read_rdata =
DS::read_data(&mut decoder, RecordType::DS, restrict).expect("Decoding error");
assert_eq!(rdata, read_rdata);
}

View File

@ -1,18 +1,9 @@
/*
* Copyright (C) 2016 Benjamin Fry <benjaminfry@me.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! public key record data for signing zone records
#![allow(clippy::use_self)]
@ -25,8 +16,11 @@ use serde::{Deserialize, Serialize};
use crate::error::*;
use crate::rr::dnssec::Algorithm;
use crate::rr::record_data::RData;
use crate::rr::{RecordData, RecordDataDecodable, RecordType};
use crate::serialize::binary::*;
use super::DNSSECRData;
/// [RFC 2535](https://tools.ietf.org/html/rfc2535#section-3), Domain Name System Security Extensions, March 1999
///
/// ```text
@ -767,60 +761,91 @@ impl From<KEY> for RData {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder<'_>, rdata_length: Restrict<u16>) -> ProtoResult<KEY> {
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// | A/C | Z | XT| Z | Z | NAMTYP| Z | Z | Z | Z | SIG |
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
let flags: u16 = decoder
.read_u16()?
.verify_unwrap(|flags| {
// Bits 2 is reserved and must be zero.
// Bits 4-5 are reserved and must be zero.
// Bits 8-11 are reserved and must be zero.
flags & 0b0010_1100_1111_0000 == 0
})
.map_err(|_| ProtoError::from("flag 2, 4-5, and 8-11 are reserved, must be zero"))?;
impl BinEncodable for KEY {
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
encoder.emit_u16(self.flags())?;
encoder.emit(u8::from(self.protocol))?;
self.algorithm().emit(encoder)?;
encoder.emit_vec(self.public_key())?;
let key_trust = KeyTrust::from(flags);
let extended_flags: bool = flags & 0b0001_0000_0000_0000 != 0;
let key_usage = KeyUsage::from(flags);
let signatory = UpdateScope::from(flags);
if extended_flags {
// TODO: add an optional field to return the raw u16?
return Err("extended flags currently not supported".into());
Ok(())
}
}
// TODO: protocol my be infallible
let protocol = Protocol::from(decoder.read_u8()?.unverified(/*Protocol is verified as safe*/));
impl<'r> RecordDataDecodable<'r> for KEY {
fn read_data(
decoder: &mut BinDecoder<'r>,
_record_type: RecordType,
length: Restrict<u16>,
) -> ProtoResult<KEY> {
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// | A/C | Z | XT| Z | Z | NAMTYP| Z | Z | Z | Z | SIG |
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
let flags: u16 = decoder
.read_u16()?
.verify_unwrap(|flags| {
// Bits 2 is reserved and must be zero.
// Bits 4-5 are reserved and must be zero.
// Bits 8-11 are reserved and must be zero.
flags & 0b0010_1100_1111_0000 == 0
})
.map_err(|_| ProtoError::from("flag 2, 4-5, and 8-11 are reserved, must be zero"))?;
let algorithm: Algorithm = Algorithm::read(decoder)?;
let key_trust = KeyTrust::from(flags);
let extended_flags: bool = flags & 0b0001_0000_0000_0000 != 0;
let key_usage = KeyUsage::from(flags);
let signatory = UpdateScope::from(flags);
// the public key is the left-over bytes minus 4 for the first fields
// TODO: decode the key here?
let key_len = rdata_length
if extended_flags {
// TODO: add an optional field to return the raw u16?
return Err("extended flags currently not supported".into());
}
// TODO: protocol my be infallible
let protocol =
Protocol::from(decoder.read_u8()?.unverified(/*Protocol is verified as safe*/));
let algorithm: Algorithm = Algorithm::read(decoder)?;
// the public key is the left-over bytes minus 4 for the first fields
// TODO: decode the key here?
let key_len = length
.map(|u| u as usize)
.checked_sub(4)
.map_err(|_| ProtoError::from("invalid rdata length in KEY"))?
.unverified(/*used only as length safely*/);
let public_key: Vec<u8> =
decoder.read_vec(key_len)?.unverified(/*the byte array will fail in usage if invalid*/);
let public_key: Vec<u8> =
decoder.read_vec(key_len)?.unverified(/*the byte array will fail in usage if invalid*/);
Ok(KEY::new(
key_trust, key_usage, signatory, protocol, algorithm, public_key,
))
Ok(Self::new(
key_trust, key_usage, signatory, protocol, algorithm, public_key,
))
}
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder<'_>, rdata: &KEY) -> ProtoResult<()> {
encoder.emit_u16(rdata.flags())?;
encoder.emit(u8::from(rdata.protocol))?;
rdata.algorithm().emit(encoder)?;
encoder.emit_vec(rdata.public_key())?;
impl RecordData for KEY {
fn try_from_rdata(data: RData) -> Result<Self, RData> {
match data {
RData::DNSSEC(DNSSECRData::KEY(csync)) => Ok(csync),
_ => Err(data),
}
}
Ok(())
fn try_borrow(data: &RData) -> Result<&Self, &RData> {
match data {
RData::DNSSEC(DNSSECRData::KEY(csync)) => Ok(csync),
_ => Err(data),
}
}
fn record_type(&self) -> RecordType {
RecordType::KEY
}
fn into_rdata(self) -> RData {
RData::DNSSEC(DNSSECRData::KEY(self))
}
}
/// Note that KEY is a deprecated type in DNS
@ -919,14 +944,15 @@ mod tests {
let mut bytes = Vec::new();
let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
assert!(emit(&mut encoder, &rdata).is_ok());
assert!(rdata.emit(&mut encoder).is_ok());
let bytes = encoder.into_bytes();
println!("bytes: {bytes:?}");
let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
let restrict = Restrict::new(bytes.len() as u16);
let read_rdata = read(&mut decoder, restrict).expect("Decoding error");
let read_rdata =
KEY::read_data(&mut decoder, RecordType::KEY, restrict).expect("Decoding error");
assert_eq!(rdata, read_rdata);
// #[cfg(any(feature = "openssl", feature = "ring"))]
// assert!(rdata

View File

@ -1,18 +1,9 @@
/*
* Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! All record data structures and related serialization methods
@ -24,6 +15,8 @@ use serde::{Deserialize, Serialize};
// TODO: these should each be it's own struct, it would make parsing and decoding a little cleaner
// and also a little more ergonomic when accessing.
// each of these module's has the parser for that rdata embedded, to keep the file sizes down...
pub mod cdnskey;
pub mod cds;
pub mod dnskey;
pub mod ds;
#[allow(deprecated)]
@ -31,6 +24,7 @@ pub mod key;
pub mod nsec;
pub mod nsec3;
pub mod nsec3param;
pub mod rrsig;
pub mod sig;
pub mod tsig;
@ -39,15 +33,18 @@ use tracing::trace;
use crate::error::*;
use crate::rr::rdata::NULL;
use crate::rr::{RData, RecordType};
use crate::serialize::binary::{BinDecoder, BinEncodable, BinEncoder, Restrict};
use crate::rr::{RData, RecordDataDecodable, RecordType};
use crate::serialize::binary::{BinDecodable, BinDecoder, BinEncodable, BinEncoder, Restrict};
pub use self::cdnskey::CDNSKEY;
pub use self::cds::CDS;
pub use self::dnskey::DNSKEY;
pub use self::ds::DS;
pub use self::key::KEY;
pub use self::nsec::NSEC;
pub use self::nsec3::NSEC3;
pub use self::nsec3param::NSEC3PARAM;
pub use self::rrsig::RRSIG;
pub use self::sig::SIG;
pub use self::tsig::TSIG;
@ -75,7 +72,7 @@ pub enum DNSSECRData {
/// resolvers, when serving or resolving. For all practical purposes,
/// CDNSKEY is a regular RR type.
/// ```
CDNSKEY(DNSKEY),
CDNSKEY(CDNSKEY),
/// ```text
/// RFC 7344 Delegation Trust Maintenance September 2014
@ -91,7 +88,7 @@ pub enum DNSSECRData {
/// resolvers, when serving or resolving. For all practical purposes,
/// CDS is a regular RR type.
/// ```
CDS(DS),
CDS(CDS),
/// ```text
/// RFC 4034 DNSSEC Resource Records March 2005
@ -384,6 +381,40 @@ pub enum DNSSECRData {
/// ```
NSEC3PARAM(NSEC3PARAM),
/// ```text
/// RFC 2535 & 2931 DNS Security Extensions March 1999
/// RFC 4034 DNSSEC Resource Records March 2005
///
/// 3.1. RRSIG RDATA Wire Format
///
/// The RDATA for an RRSIG RR consists of a 2 octet Type Covered field, a
/// 1 octet Algorithm field, a 1 octet Labels field, a 4 octet Original
/// TTL field, a 4 octet Signature Expiration field, a 4 octet Signature
/// Inception field, a 2 octet Key tag, the Signer's Name field, and the
/// Signature field.
///
/// 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Type Covered | Algorithm | Labels |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Original TTL |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Signature Expiration |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Signature Inception |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Key Tag | /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Signer's Name /
/// / /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// / /
/// / Signature /
/// / /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ```
RRSIG(RRSIG),
/// ```text
/// RFC 2535 & 2931 DNS Security Extensions March 1999
/// RFC 4034 DNSSEC Resource Records March 2005
@ -550,47 +581,47 @@ impl DNSSECRData {
match record_type {
RecordType::CDNSKEY => {
trace!("reading CDNSKEY");
dnskey::read(decoder, rdata_length).map(Self::CDNSKEY)
CDNSKEY::read_data(decoder, record_type, rdata_length).map(Self::CDNSKEY)
}
RecordType::CDS => {
trace!("reading CDS");
ds::read(decoder, rdata_length).map(Self::CDS)
CDS::read_data(decoder, record_type, rdata_length).map(Self::CDS)
}
RecordType::DNSKEY => {
trace!("reading DNSKEY");
dnskey::read(decoder, rdata_length).map(Self::DNSKEY)
DNSKEY::read_data(decoder, record_type, rdata_length).map(Self::DNSKEY)
}
RecordType::DS => {
trace!("reading DS");
ds::read(decoder, rdata_length).map(Self::DS)
DS::read_data(decoder, record_type, rdata_length).map(Self::DS)
}
RecordType::KEY => {
trace!("reading KEY");
key::read(decoder, rdata_length).map(Self::KEY)
KEY::read_data(decoder, record_type, rdata_length).map(Self::KEY)
}
RecordType::NSEC => {
trace!("reading NSEC");
nsec::read(decoder, rdata_length).map(Self::NSEC)
NSEC::read_data(decoder, record_type, rdata_length).map(Self::NSEC)
}
RecordType::NSEC3 => {
trace!("reading NSEC3");
nsec3::read(decoder, rdata_length).map(Self::NSEC3)
NSEC3::read_data(decoder, record_type, rdata_length).map(Self::NSEC3)
}
RecordType::NSEC3PARAM => {
trace!("reading NSEC3PARAM");
nsec3param::read(decoder).map(Self::NSEC3PARAM)
NSEC3PARAM::read(decoder).map(Self::NSEC3PARAM)
}
RecordType::RRSIG => {
trace!("reading RRSIG");
sig::read(decoder, rdata_length).map(Self::SIG)
RRSIG::read_data(decoder, record_type, rdata_length).map(Self::RRSIG)
}
RecordType::SIG => {
trace!("reading SIG");
sig::read(decoder, rdata_length).map(Self::SIG)
SIG::read_data(decoder, record_type, rdata_length).map(Self::SIG)
}
RecordType::TSIG => {
trace!("reading TSIG");
tsig::read(decoder, rdata_length).map(Self::TSIG)
TSIG::read_data(decoder, record_type, rdata_length).map(Self::TSIG)
}
r => {
panic!("not a dnssec RecordType: {}", r);
@ -601,25 +632,22 @@ impl DNSSECRData {
pub(crate) fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
match *self {
Self::CDNSKEY(ref cdnskey) => {
encoder.with_canonical_names(|encoder| dnskey::emit(encoder, cdnskey))
encoder.with_canonical_names(|encoder| cdnskey.emit(encoder))
}
Self::CDS(ref cds) => encoder.with_canonical_names(|encoder| ds::emit(encoder, cds)),
Self::DS(ref ds) => encoder.with_canonical_names(|encoder| ds::emit(encoder, ds)),
Self::KEY(ref key) => encoder.with_canonical_names(|encoder| key::emit(encoder, key)),
Self::CDS(ref cds) => encoder.with_canonical_names(|encoder| cds.emit(encoder)),
Self::DS(ref ds) => encoder.with_canonical_names(|encoder| ds.emit(encoder)),
Self::KEY(ref key) => encoder.with_canonical_names(|encoder| key.emit(encoder)),
Self::DNSKEY(ref dnskey) => {
encoder.with_canonical_names(|encoder| dnskey::emit(encoder, dnskey))
}
Self::NSEC(ref nsec) => {
encoder.with_canonical_names(|encoder| nsec::emit(encoder, nsec))
}
Self::NSEC3(ref nsec3) => {
encoder.with_canonical_names(|encoder| nsec3::emit(encoder, nsec3))
encoder.with_canonical_names(|encoder| dnskey.emit(encoder))
}
Self::NSEC(ref nsec) => encoder.with_canonical_names(|encoder| nsec.emit(encoder)),
Self::NSEC3(ref nsec3) => encoder.with_canonical_names(|encoder| nsec3.emit(encoder)),
Self::NSEC3PARAM(ref nsec3param) => {
encoder.with_canonical_names(|encoder| nsec3param::emit(encoder, nsec3param))
encoder.with_canonical_names(|encoder| nsec3param.emit(encoder))
}
Self::SIG(ref sig) => encoder.with_canonical_names(|encoder| sig::emit(encoder, sig)),
Self::TSIG(ref tsig) => tsig::emit(encoder, tsig),
Self::RRSIG(ref rrsig) => encoder.with_canonical_names(|encoder| rrsig.emit(encoder)),
Self::SIG(ref sig) => encoder.with_canonical_names(|encoder| sig.emit(encoder)),
Self::TSIG(ref tsig) => tsig.emit(encoder),
Self::Unknown { ref rdata, .. } => {
encoder.with_canonical_names(|encoder| rdata.emit(encoder))
}
@ -637,6 +665,7 @@ impl DNSSECRData {
Self::NSEC3(..) => RecordType::NSEC3,
Self::NSEC3PARAM(..) => RecordType::NSEC3PARAM,
Self::SIG(..) => RecordType::SIG,
Self::RRSIG(..) => RecordType::RRSIG,
Self::TSIG(..) => RecordType::TSIG,
Self::Unknown { code, .. } => RecordType::Unknown(code),
}
@ -659,6 +688,7 @@ impl fmt::Display for DNSSECRData {
Self::NSEC3(nsec3) => w(f, nsec3),
Self::NSEC3PARAM(nsec3param) => w(f, nsec3param),
Self::SIG(sig) => w(f, sig),
Self::RRSIG(rrsig) => w(f, rrsig),
Self::TSIG(ref tsig) => w(f, tsig),
Self::Unknown { rdata, .. } => w(f, rdata),
}

View File

@ -1,18 +1,9 @@
/*
* Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! NSEC record types
use std::fmt;
@ -22,9 +13,11 @@ use serde::{Deserialize, Serialize};
use crate::error::*;
use crate::rr::type_bit_map::{decode_type_bit_maps, encode_type_bit_maps};
use crate::rr::{Name, RecordType};
use crate::rr::{Name, RData, RecordData, RecordDataDecodable, RecordType};
use crate::serialize::binary::*;
use super::DNSSECRData;
/// [RFC 4034](https://tools.ietf.org/html/rfc4034#section-4), DNSSEC Resource Records, March 2005
///
/// ```text
@ -133,36 +126,69 @@ impl NSEC {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder<'_>, rdata_length: Restrict<u16>) -> ProtoResult<NSEC> {
let start_idx = decoder.index();
let next_domain_name = Name::read(decoder)?;
let bit_map_len = rdata_length
.map(|u| u as usize)
.checked_sub(decoder.index() - start_idx)
.map_err(|_| ProtoError::from("invalid rdata length in NSEC"))?;
let record_types = decode_type_bit_maps(decoder, bit_map_len)?;
Ok(NSEC::new(next_domain_name, record_types))
impl BinEncodable for NSEC {
/// [RFC 6840](https://tools.ietf.org/html/rfc6840#section-6)
///
/// ```text
/// 5.1. Errors in Canonical Form Type Code List
///
/// When canonicalizing DNS names (for both ordering and signing), DNS
/// names in the RDATA section of NSEC resource records are not converted
/// to lowercase. DNS names in the RDATA section of RRSIG resource
/// records are converted to lowercase.
/// ```
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
encoder.with_canonical_names(|encoder| {
self.next_domain_name().emit(encoder)?;
encode_type_bit_maps(encoder, self.type_bit_maps())
})
}
}
/// [RFC 6840](https://tools.ietf.org/html/rfc6840#section-6)
///
/// ```text
/// 5.1. Errors in Canonical Form Type Code List
///
/// When canonicalizing DNS names (for both ordering and signing), DNS
/// names in the RDATA section of NSEC resource records are not converted
/// to lowercase. DNS names in the RDATA section of RRSIG resource
/// records are converted to lowercase.
/// ```
pub fn emit(encoder: &mut BinEncoder<'_>, rdata: &NSEC) -> ProtoResult<()> {
encoder.with_canonical_names(|encoder| {
rdata.next_domain_name().emit(encoder)?;
encode_type_bit_maps(encoder, rdata.type_bit_maps())
})
impl<'r> RecordDataDecodable<'r> for NSEC {
fn read_data(
decoder: &mut BinDecoder<'r>,
record_type: RecordType,
length: Restrict<u16>,
) -> ProtoResult<Self> {
assert_eq!(record_type, RecordType::NSEC);
let start_idx = decoder.index();
let next_domain_name = Name::read(decoder)?;
let bit_map_len = length
.map(|u| u as usize)
.checked_sub(decoder.index() - start_idx)
.map_err(|_| ProtoError::from("invalid rdata length in NSEC"))?;
let record_types = decode_type_bit_maps(decoder, bit_map_len)?;
Ok(Self::new(next_domain_name, record_types))
}
}
impl RecordData for NSEC {
fn try_from_rdata(data: RData) -> Result<Self, RData> {
match data {
RData::DNSSEC(DNSSECRData::NSEC(csync)) => Ok(csync),
_ => Err(data),
}
}
fn try_borrow(data: &RData) -> Result<&Self, &RData> {
match data {
RData::DNSSEC(DNSSECRData::NSEC(csync)) => Ok(csync),
_ => Err(data),
}
}
fn record_type(&self) -> RecordType {
RecordType::NSEC
}
fn into_rdata(self) -> RData {
RData::DNSSEC(DNSSECRData::NSEC(self))
}
}
/// [RFC 4034](https://tools.ietf.org/html/rfc4034#section-4.2), DNSSEC Resource Records, March 2005
@ -233,14 +259,15 @@ mod tests {
let mut bytes = Vec::new();
let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
assert!(emit(&mut encoder, &rdata).is_ok());
assert!(rdata.emit(&mut encoder).is_ok());
let bytes = encoder.into_bytes();
println!("bytes: {bytes:?}");
let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
let restrict = Restrict::new(bytes.len() as u16);
let read_rdata = read(&mut decoder, restrict).expect("Decoding error");
let read_rdata =
NSEC::read_data(&mut decoder, RecordType::NSEC, restrict).expect("Decoding error");
assert_eq!(rdata, read_rdata);
}
}

View File

@ -1,18 +1,9 @@
/*
* Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! NSEC record types
@ -24,9 +15,14 @@ use serde::{Deserialize, Serialize};
use crate::error::*;
use crate::rr::dnssec::Nsec3HashAlgorithm;
use crate::rr::type_bit_map::*;
use crate::rr::RData;
use crate::rr::RecordData;
use crate::rr::RecordDataDecodable;
use crate::rr::RecordType;
use crate::serialize::binary::*;
use super::DNSSECRData;
/// [RFC 5155](https://tools.ietf.org/html/rfc5155#section-3), NSEC3, March 2008
///
/// ```text
@ -253,77 +249,110 @@ impl NSEC3 {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder<'_>, rdata_length: Restrict<u16>) -> ProtoResult<NSEC3> {
let start_idx = decoder.index();
impl BinEncodable for NSEC3 {
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
encoder.emit(self.hash_algorithm().into())?;
encoder.emit(self.flags())?;
encoder.emit_u16(self.iterations())?;
encoder.emit(self.salt().len() as u8)?;
encoder.emit_vec(self.salt())?;
encoder.emit(self.next_hashed_owner_name().len() as u8)?;
encoder.emit_vec(self.next_hashed_owner_name())?;
encode_type_bit_maps(encoder, self.type_bit_maps())?;
let hash_algorithm =
Nsec3HashAlgorithm::from_u8(decoder.read_u8()?.unverified(/*Algorithm verified as safe*/))?;
let flags: u8 = decoder
.read_u8()?
.verify_unwrap(|flags| flags & 0b1111_1110 == 0)
.map_err(|flags| ProtoError::from(ProtoErrorKind::UnrecognizedNsec3Flags(flags)))?;
let opt_out: bool = flags & 0b0000_0001 == 0b0000_0001;
let iterations: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
// read the salt
let salt_len = decoder.read_u8()?.map(|u| u as usize);
let salt_len_max = rdata_length
.map(|u| u as usize)
.checked_sub(decoder.index() - start_idx)
.map_err(|_| "invalid rdata for salt_len_max")?;
let salt_len = salt_len
.verify_unwrap(|salt_len| {
*salt_len <= salt_len_max.unverified(/*safe in comparison usage*/)
})
.map_err(|_| ProtoError::from("salt_len exceeds buffer length"))?;
let salt: Vec<u8> =
decoder.read_vec(salt_len)?.unverified(/*salt is any valid array of bytes*/);
// read the hashed_owner_name
let hash_len = decoder.read_u8()?.map(|u| u as usize);
let hash_len_max = rdata_length
.map(|u| u as usize)
.checked_sub(decoder.index() - start_idx)
.map_err(|_| "invalid rdata for hash_len_max")?;
let hash_len = hash_len
.verify_unwrap(|hash_len| {
*hash_len <= hash_len_max.unverified(/*safe in comparison usage*/)
})
.map_err(|_| ProtoError::from("hash_len exceeds buffer length"))?;
let next_hashed_owner_name: Vec<u8> =
decoder.read_vec(hash_len)?.unverified(/*will fail in usage if invalid*/);
// read the bitmap
let bit_map_len = rdata_length
.map(|u| u as usize)
.checked_sub(decoder.index() - start_idx)
.map_err(|_| "invalid rdata length in NSEC3")?;
let record_types = decode_type_bit_maps(decoder, bit_map_len)?;
Ok(NSEC3::new(
hash_algorithm,
opt_out,
iterations,
salt,
next_hashed_owner_name,
record_types,
))
Ok(())
}
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder<'_>, rdata: &NSEC3) -> ProtoResult<()> {
encoder.emit(rdata.hash_algorithm().into())?;
encoder.emit(rdata.flags())?;
encoder.emit_u16(rdata.iterations())?;
encoder.emit(rdata.salt().len() as u8)?;
encoder.emit_vec(rdata.salt())?;
encoder.emit(rdata.next_hashed_owner_name().len() as u8)?;
encoder.emit_vec(rdata.next_hashed_owner_name())?;
encode_type_bit_maps(encoder, rdata.type_bit_maps())?;
impl<'r> RecordDataDecodable<'r> for NSEC3 {
fn read_data(
decoder: &mut BinDecoder<'r>,
record_type: RecordType,
length: Restrict<u16>,
) -> ProtoResult<Self> {
assert_eq!(record_type, RecordType::NSEC3);
Ok(())
let start_idx = decoder.index();
let hash_algorithm = Nsec3HashAlgorithm::from_u8(
decoder.read_u8()?.unverified(/*Algorithm verified as safe*/),
)?;
let flags: u8 = decoder
.read_u8()?
.verify_unwrap(|flags| flags & 0b1111_1110 == 0)
.map_err(|flags| ProtoError::from(ProtoErrorKind::UnrecognizedNsec3Flags(flags)))?;
let opt_out: bool = flags & 0b0000_0001 == 0b0000_0001;
let iterations: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
// read the salt
let salt_len = decoder.read_u8()?.map(|u| u as usize);
let salt_len_max = length
.map(|u| u as usize)
.checked_sub(decoder.index() - start_idx)
.map_err(|_| "invalid rdata for salt_len_max")?;
let salt_len = salt_len
.verify_unwrap(|salt_len| {
*salt_len <= salt_len_max.unverified(/*safe in comparison usage*/)
})
.map_err(|_| ProtoError::from("salt_len exceeds buffer length"))?;
let salt: Vec<u8> =
decoder.read_vec(salt_len)?.unverified(/*salt is any valid array of bytes*/);
// read the hashed_owner_name
let hash_len = decoder.read_u8()?.map(|u| u as usize);
let hash_len_max = length
.map(|u| u as usize)
.checked_sub(decoder.index() - start_idx)
.map_err(|_| "invalid rdata for hash_len_max")?;
let hash_len = hash_len
.verify_unwrap(|hash_len| {
*hash_len <= hash_len_max.unverified(/*safe in comparison usage*/)
})
.map_err(|_| ProtoError::from("hash_len exceeds buffer length"))?;
let next_hashed_owner_name: Vec<u8> =
decoder.read_vec(hash_len)?.unverified(/*will fail in usage if invalid*/);
// read the bitmap
let bit_map_len = length
.map(|u| u as usize)
.checked_sub(decoder.index() - start_idx)
.map_err(|_| "invalid rdata length in NSEC3")?;
let record_types = decode_type_bit_maps(decoder, bit_map_len)?;
Ok(Self::new(
hash_algorithm,
opt_out,
iterations,
salt,
next_hashed_owner_name,
record_types,
))
}
}
impl RecordData for NSEC3 {
fn try_from_rdata(data: RData) -> Result<Self, RData> {
match data {
RData::DNSSEC(DNSSECRData::NSEC3(csync)) => Ok(csync),
_ => Err(data),
}
}
fn try_borrow(data: &RData) -> Result<&Self, &RData> {
match data {
RData::DNSSEC(DNSSECRData::NSEC3(csync)) => Ok(csync),
_ => Err(data),
}
}
fn record_type(&self) -> RecordType {
RecordType::NSEC3
}
fn into_rdata(self) -> RData {
RData::DNSSEC(DNSSECRData::NSEC3(self))
}
}
/// [RFC 5155](https://tools.ietf.org/html/rfc5155#section-3.3), NSEC3, March 2008
@ -411,14 +440,15 @@ mod tests {
let mut bytes = Vec::new();
let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
assert!(emit(&mut encoder, &rdata).is_ok());
assert!(rdata.emit(&mut encoder).is_ok());
let bytes = encoder.into_bytes();
println!("bytes: {bytes:?}");
let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
let restrict = Restrict::new(bytes.len() as u16);
let read_rdata = read(&mut decoder, restrict).expect("Decoding error");
let read_rdata =
NSEC3::read_data(&mut decoder, RecordType::NSEC3, restrict).expect("Decoding error");
assert_eq!(rdata, read_rdata);
}
@ -457,14 +487,15 @@ mod tests {
let mut bytes = Vec::new();
let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
assert!(emit(&mut encoder, &rdata_with_dups).is_ok());
assert!(rdata_with_dups.emit(&mut encoder).is_ok());
let bytes = encoder.into_bytes();
println!("bytes: {bytes:?}");
let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
let restrict = Restrict::new(bytes.len() as u16);
let read_rdata = read(&mut decoder, restrict).expect("Decoding error");
let read_rdata =
NSEC3::read_data(&mut decoder, RecordType::NSEC3, restrict).expect("Decoding error");
assert_eq!(rdata_wo, read_rdata);
}
}

View File

@ -1,18 +1,9 @@
/*
* Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! parameters used for the nsec3 hash method
@ -23,8 +14,11 @@ use serde::{Deserialize, Serialize};
use crate::error::*;
use crate::rr::dnssec::Nsec3HashAlgorithm;
use crate::rr::{RData, RecordData, RecordType};
use crate::serialize::binary::*;
use super::DNSSECRData;
/// [RFC 5155](https://tools.ietf.org/html/rfc5155#section-4), NSEC3, March 2008
///
/// ```text
@ -173,36 +167,63 @@ impl NSEC3PARAM {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder<'_>) -> ProtoResult<NSEC3PARAM> {
let hash_algorithm =
Nsec3HashAlgorithm::from_u8(decoder.read_u8()?.unverified(/*Algorithm verified as safe*/))?;
let flags: u8 = decoder
.read_u8()?
.verify_unwrap(|flags| flags & 0b1111_1110 == 0)
.map_err(|flags| ProtoError::from(ProtoErrorKind::UnrecognizedNsec3Flags(flags)))?;
impl BinEncodable for NSEC3PARAM {
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
encoder.emit(self.hash_algorithm().into())?;
encoder.emit(self.flags())?;
encoder.emit_u16(self.iterations())?;
encoder.emit(self.salt().len() as u8)?;
encoder.emit_vec(self.salt())?;
let opt_out: bool = flags & 0b0000_0001 == 0b0000_0001;
let iterations: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
let salt_len: usize = decoder
.read_u8()?
.map(|u| u as usize)
.verify_unwrap(|salt_len| *salt_len <= decoder.len())
.map_err(|_| ProtoError::from("salt_len exceeds buffer length"))?;
let salt: Vec<u8> = decoder.read_vec(salt_len)?.unverified(/*valid as any array of u8*/);
Ok(NSEC3PARAM::new(hash_algorithm, opt_out, iterations, salt))
Ok(())
}
}
/// Write the RData from the given Decoder
pub fn emit(encoder: &mut BinEncoder<'_>, rdata: &NSEC3PARAM) -> ProtoResult<()> {
encoder.emit(rdata.hash_algorithm().into())?;
encoder.emit(rdata.flags())?;
encoder.emit_u16(rdata.iterations())?;
encoder.emit(rdata.salt().len() as u8)?;
encoder.emit_vec(rdata.salt())?;
impl<'r> BinDecodable<'r> for NSEC3PARAM {
fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
let hash_algorithm = Nsec3HashAlgorithm::from_u8(
decoder.read_u8()?.unverified(/*Algorithm verified as safe*/),
)?;
let flags: u8 = decoder
.read_u8()?
.verify_unwrap(|flags| flags & 0b1111_1110 == 0)
.map_err(|flags| ProtoError::from(ProtoErrorKind::UnrecognizedNsec3Flags(flags)))?;
Ok(())
let opt_out: bool = flags & 0b0000_0001 == 0b0000_0001;
let iterations: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
let salt_len: usize = decoder
.read_u8()?
.map(|u| u as usize)
.verify_unwrap(|salt_len| *salt_len <= decoder.len())
.map_err(|_| ProtoError::from("salt_len exceeds buffer length"))?;
let salt: Vec<u8> = decoder.read_vec(salt_len)?.unverified(/*valid as any array of u8*/);
Ok(Self::new(hash_algorithm, opt_out, iterations, salt))
}
}
impl RecordData for NSEC3PARAM {
fn try_from_rdata(data: RData) -> Result<Self, RData> {
match data {
RData::DNSSEC(DNSSECRData::NSEC3PARAM(csync)) => Ok(csync),
_ => Err(data),
}
}
fn try_borrow(data: &RData) -> Result<&Self, &RData> {
match data {
RData::DNSSEC(DNSSECRData::NSEC3PARAM(csync)) => Ok(csync),
_ => Err(data),
}
}
fn record_type(&self) -> RecordType {
RecordType::NSEC3PARAM
}
fn into_rdata(self) -> RData {
RData::DNSSEC(DNSSECRData::NSEC3PARAM(self))
}
}
/// [RFC 5155](https://tools.ietf.org/html/rfc5155#section-4), NSEC3, March 2008
@ -259,13 +280,13 @@ mod tests {
let mut bytes = Vec::new();
let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
assert!(emit(&mut encoder, &rdata).is_ok());
assert!(rdata.emit(&mut encoder).is_ok());
let bytes = encoder.into_bytes();
println!("bytes: {bytes:?}");
let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
let read_rdata = read(&mut decoder).expect("Decoding error");
let read_rdata = NSEC3PARAM::read(&mut decoder).expect("Decoding error");
assert_eq!(rdata, read_rdata);
}
}

View File

@ -0,0 +1,98 @@
// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! RRSIG type and related implementations
use std::{fmt, ops::Deref};
#[cfg(feature = "serde-config")]
use serde::{Deserialize, Serialize};
use crate::{
error::ProtoResult,
rr::{RData, RecordData, RecordDataDecodable, RecordType},
serialize::binary::{BinDecoder, BinEncodable, BinEncoder, Restrict},
};
use super::{DNSSECRData, SIG};
/// RRSIG is really a derivation of the original SIG record data. See SIG for more documentation
#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct RRSIG(SIG);
impl Deref for RRSIG {
type Target = SIG;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl BinEncodable for RRSIG {
/// [RFC 4034](https://tools.ietf.org/html/rfc4034#section-6), DNSSEC Resource Records, March 2005
///
/// This is accurate for all currently known name records.
///
/// ```text
/// 6.2. Canonical RR Form
///
/// For the purposes of DNS security, the canonical form of an RR is the
/// wire format of the RR where:
///
/// ...
///
/// 3. if the type of the RR is NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
/// HINFO, MINFO, MX, HINFO, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
/// SRV, DNAME, A6, RRSIG, or (rfc6840 removes NSEC), all uppercase
/// US-ASCII letters in the DNS names contained within the RDATA are replaced
/// by the corresponding lowercase US-ASCII letters;
/// ```
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
self.0.emit(encoder)
}
}
impl<'r> RecordDataDecodable<'r> for RRSIG {
fn read_data(
decoder: &mut BinDecoder<'r>,
record_type: RecordType,
length: Restrict<u16>,
) -> ProtoResult<Self> {
SIG::read_data(decoder, record_type, length).map(Self)
}
}
impl RecordData for RRSIG {
fn try_from_rdata(data: RData) -> Result<Self, RData> {
match data {
RData::DNSSEC(DNSSECRData::RRSIG(csync)) => Ok(csync),
_ => Err(data),
}
}
fn try_borrow(data: &RData) -> Result<&Self, &RData> {
match data {
RData::DNSSEC(DNSSECRData::RRSIG(csync)) => Ok(csync),
_ => Err(data),
}
}
fn record_type(&self) -> RecordType {
RecordType::RRSIG
}
fn into_rdata(self) -> RData {
RData::DNSSEC(DNSSECRData::RRSIG(self))
}
}
impl fmt::Display for RRSIG {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}", self.0)
}
}

View File

@ -1,18 +1,9 @@
/*
* Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! signature record for signing queries, updates, and responses
use std::fmt;
@ -22,9 +13,11 @@ use serde::{Deserialize, Serialize};
use crate::error::*;
use crate::rr::dnssec::Algorithm;
use crate::rr::{Name, RecordType};
use crate::rr::{Name, RData, RecordData, RecordDataDecodable, RecordType};
use crate::serialize::binary::*;
use super::DNSSECRData;
/// [RFC 2535](https://tools.ietf.org/html/rfc2535#section-4), Domain Name System Security Extensions, March 1999
///
/// NOTE: RFC 2535 was obsoleted with 4034+, with the exception of the
@ -454,76 +447,108 @@ impl SIG {
}
}
/// Read the RData from the given Decoder
pub fn read(decoder: &mut BinDecoder<'_>, rdata_length: Restrict<u16>) -> ProtoResult<SIG> {
let start_idx = decoder.index();
impl BinEncodable for SIG {
/// [RFC 4034](https://tools.ietf.org/html/rfc4034#section-6), DNSSEC Resource Records, March 2005
///
/// This is accurate for all currently known name records.
///
/// ```text
/// 6.2. Canonical RR Form
///
/// For the purposes of DNS security, the canonical form of an RR is the
/// wire format of the RR where:
///
/// ...
///
/// 3. if the type of the RR is NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
/// HINFO, MINFO, MX, HINFO, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
/// SRV, DNAME, A6, RRSIG, or (rfc6840 removes NSEC), all uppercase
/// US-ASCII letters in the DNS names contained within the RDATA are replaced
/// by the corresponding lowercase US-ASCII letters;
/// ```
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
let is_canonical_names = encoder.is_canonical_names();
// TODO should we verify here? or elsewhere...
let type_covered = RecordType::read(decoder)?;
let algorithm = Algorithm::read(decoder)?;
let num_labels = decoder.read_u8()?.unverified(/*technically valid as any u8*/);
let original_ttl = decoder.read_u32()?.unverified(/*valid as any u32*/);
let sig_expiration =
decoder.read_u32()?.unverified(/*valid as any u32, in practice should be in the future*/);
let sig_inception = decoder.read_u32()?.unverified(/*valid as any u32, in practice should be before expiration*/);
let key_tag = decoder.read_u16()?.unverified(/*valid as any u16*/);
let signer_name = Name::read(decoder)?;
self.type_covered().emit(encoder)?;
self.algorithm().emit(encoder)?;
encoder.emit(self.num_labels())?;
encoder.emit_u32(self.original_ttl())?;
encoder.emit_u32(self.sig_expiration())?;
encoder.emit_u32(self.sig_inception())?;
encoder.emit_u16(self.key_tag())?;
self.signer_name()
.emit_with_lowercase(encoder, is_canonical_names)?;
encoder.emit_vec(self.sig())?;
Ok(())
}
}
// read the signature, this will vary buy key size
let sig_len = rdata_length
impl<'r> RecordDataDecodable<'r> for SIG {
fn read_data(
decoder: &mut BinDecoder<'r>,
record_type: RecordType,
length: Restrict<u16>,
) -> ProtoResult<Self> {
assert!(record_type == RecordType::SIG || record_type == RecordType::RRSIG);
let start_idx = decoder.index();
// TODO should we verify here? or elsewhere...
let type_covered = RecordType::read(decoder)?;
let algorithm = Algorithm::read(decoder)?;
let num_labels = decoder.read_u8()?.unverified(/*technically valid as any u8*/);
let original_ttl = decoder.read_u32()?.unverified(/*valid as any u32*/);
let sig_expiration = decoder.read_u32()?.unverified(/*valid as any u32, in practice should be in the future*/);
let sig_inception = decoder.read_u32()?.unverified(/*valid as any u32, in practice should be before expiration*/);
let key_tag = decoder.read_u16()?.unverified(/*valid as any u16*/);
let signer_name = Name::read(decoder)?;
// read the signature, this will vary buy key size
let sig_len = length
.map(|u| u as usize)
.checked_sub(decoder.index() - start_idx)
.map_err(|_| ProtoError::from("invalid rdata length in SIG"))?
.unverified(/*used only as length safely*/);
let sig = decoder
let sig = decoder
.read_vec(sig_len)?
.unverified(/*will fail in usage if invalid*/);
Ok(SIG::new(
type_covered,
algorithm,
num_labels,
original_ttl,
sig_expiration,
sig_inception,
key_tag,
signer_name,
sig,
))
Ok(Self::new(
type_covered,
algorithm,
num_labels,
original_ttl,
sig_expiration,
sig_inception,
key_tag,
signer_name,
sig,
))
}
}
/// [RFC 4034](https://tools.ietf.org/html/rfc4034#section-6), DNSSEC Resource Records, March 2005
///
/// This is accurate for all currently known name records.
///
/// ```text
/// 6.2. Canonical RR Form
///
/// For the purposes of DNS security, the canonical form of an RR is the
/// wire format of the RR where:
///
/// ...
///
/// 3. if the type of the RR is NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
/// HINFO, MINFO, MX, HINFO, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
/// SRV, DNAME, A6, RRSIG, or (rfc6840 removes NSEC), all uppercase
/// US-ASCII letters in the DNS names contained within the RDATA are replaced
/// by the corresponding lowercase US-ASCII letters;
/// ```
pub fn emit(encoder: &mut BinEncoder<'_>, sig: &SIG) -> ProtoResult<()> {
let is_canonical_names = encoder.is_canonical_names();
impl RecordData for SIG {
fn try_from_rdata(data: RData) -> Result<Self, RData> {
match data {
RData::DNSSEC(DNSSECRData::SIG(csync)) => Ok(csync),
_ => Err(data),
}
}
sig.type_covered().emit(encoder)?;
sig.algorithm().emit(encoder)?;
encoder.emit(sig.num_labels())?;
encoder.emit_u32(sig.original_ttl())?;
encoder.emit_u32(sig.sig_expiration())?;
encoder.emit_u32(sig.sig_inception())?;
encoder.emit_u16(sig.key_tag())?;
sig.signer_name()
.emit_with_lowercase(encoder, is_canonical_names)?;
encoder.emit_vec(sig.sig())?;
Ok(())
fn try_borrow(data: &RData) -> Result<&Self, &RData> {
match data {
RData::DNSSEC(DNSSECRData::SIG(csync)) => Ok(csync),
_ => Err(data),
}
}
fn record_type(&self) -> RecordType {
RecordType::SIG
}
fn into_rdata(self) -> RData {
RData::DNSSEC(DNSSECRData::SIG(self))
}
}
/// specifically for outputting the RData for an RRSIG, with signer_name in canonical form
@ -637,14 +662,15 @@ mod tests {
let mut bytes = Vec::new();
let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
assert!(emit(&mut encoder, &rdata).is_ok());
assert!(rdata.emit(&mut encoder).is_ok());
let bytes = encoder.into_bytes();
println!("bytes: {bytes:?}");
let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
let restrict = Restrict::new(bytes.len() as u16);
let read_rdata = read(&mut decoder, restrict).expect("Decoding error");
let read_rdata =
SIG::read_data(&mut decoder, RecordType::SIG, restrict).expect("Decoding error");
assert_eq!(rdata, read_rdata);
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
@ -13,15 +13,14 @@ use std::fmt;
#[cfg(feature = "serde-config")]
use serde::{Deserialize, Serialize};
use crate::rr::rdata::sshfp;
use crate::error::*;
use crate::op::{Header, Message, Query};
use crate::rr::dns_class::DNSClass;
use crate::rr::dnssec::rdata::DNSSECRData;
use crate::rr::rdata::sshfp;
use crate::rr::record_data::RData;
use crate::rr::record_type::RecordType;
use crate::rr::{Name, Record};
use crate::rr::{Name, Record, RecordData, RecordDataDecodable};
use crate::serialize::binary::*;
/// [RFC 8945, Secret Key Transaction Authentication for DNS](https://tools.ietf.org/html/rfc8945#section-4.2)
@ -321,115 +320,143 @@ impl TSIG {
}
}
/// Read the RData from the given Decoder
///
/// ```text
/// 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// / Algorithm Name /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | |
/// | Time Signed +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | | Fudge |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | MAC Size | /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ MAC /
/// / /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Original ID | Error |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Other Len | /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Other Data /
/// / /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ```
pub fn read(decoder: &mut BinDecoder<'_>, rdata_length: Restrict<u16>) -> ProtoResult<TSIG> {
let end_idx = rdata_length.map(|rdl| rdl as usize)
impl BinEncodable for TSIG {
/// Write the RData from the given Encoder
///
/// ```text
/// 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// / Algorithm Name /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | |
/// | Time Signed +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | | Fudge |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | MAC Size | /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ MAC /
/// / /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Original ID | Error |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Other Len | /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Other Data /
/// / /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ```
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
self.algorithm.emit(encoder)?;
encoder.emit_u16(
(self.time >> 32)
.try_into()
.map_err(|_| ProtoError::from("invalid time, overflow 48 bit counter in TSIG"))?,
)?;
encoder.emit_u32(self.time as u32)?; // this cast is supposed to truncate
encoder.emit_u16(self.fudge)?;
encoder.emit_u16(
self.mac
.len()
.try_into()
.map_err(|_| ProtoError::from("invalid mac, longer than 65535 B in TSIG"))?,
)?;
encoder.emit_vec(&self.mac)?;
encoder.emit_u16(self.oid)?;
encoder.emit_u16(self.error)?;
encoder.emit_u16(self.other.len().try_into().map_err(|_| {
ProtoError::from("invalid other_buffer, longer than 65535 B in TSIG")
})?)?;
encoder.emit_vec(&self.other)?;
Ok(())
}
}
impl<'r> RecordDataDecodable<'r> for TSIG {
/// Read the RData from the given Decoder
///
/// ```text
/// 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// / Algorithm Name /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | |
/// | Time Signed +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | | Fudge |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | MAC Size | /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ MAC /
/// / /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Original ID | Error |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Other Len | /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Other Data /
/// / /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ```
fn read_data(
decoder: &mut BinDecoder<'r>,
_record_type: RecordType,
length: Restrict<u16>,
) -> ProtoResult<Self> {
let end_idx = length.map(|rdl| rdl as usize)
.checked_add(decoder.index())
.map_err(|_| ProtoError::from("rdata end position overflow"))? // no legal message is long enough to trigger that
.unverified(/*used only as length safely*/);
let algorithm = TsigAlgorithm::read(decoder)?;
let time_high = decoder.read_u16()?.unverified(/*valid as any u16*/) as u64;
let time_low = decoder.read_u32()?.unverified(/*valid as any u32*/) as u64;
let time = (time_high << 32) | time_low;
let fudge = decoder.read_u16()?.unverified(/*valid as any u16*/);
let mac_size = decoder
.read_u16()?
.verify_unwrap(|&size| decoder.index() + size as usize + 6 /* 3 u16 */ <= end_idx)
.map_err(|_| ProtoError::from("invalid mac length in TSIG"))?;
let mac =
decoder.read_vec(mac_size as usize)?.unverified(/*valid as any vec of the right size*/);
let oid = decoder.read_u16()?.unverified(/*valid as any u16*/);
let error = decoder.read_u16()?.unverified(/*valid as any u16*/);
let other_len = decoder
.read_u16()?
.verify_unwrap(|&size| decoder.index() + size as usize == end_idx)
.map_err(|_| ProtoError::from("invalid other length in TSIG"))?;
let other =
decoder.read_vec(other_len as usize)?.unverified(/*valid as any vec of the right size*/);
let algorithm = TsigAlgorithm::read(decoder)?;
let time_high = decoder.read_u16()?.unverified(/*valid as any u16*/) as u64;
let time_low = decoder.read_u32()?.unverified(/*valid as any u32*/) as u64;
let time = (time_high << 32) | time_low;
let fudge = decoder.read_u16()?.unverified(/*valid as any u16*/);
let mac_size = decoder
.read_u16()?
.verify_unwrap(|&size| decoder.index() + size as usize + 6 /* 3 u16 */ <= end_idx)
.map_err(|_| ProtoError::from("invalid mac length in TSIG"))?;
let mac =
decoder.read_vec(mac_size as usize)?.unverified(/*valid as any vec of the right size*/);
let oid = decoder.read_u16()?.unverified(/*valid as any u16*/);
let error = decoder.read_u16()?.unverified(/*valid as any u16*/);
let other_len = decoder
.read_u16()?
.verify_unwrap(|&size| decoder.index() + size as usize == end_idx)
.map_err(|_| ProtoError::from("invalid other length in TSIG"))?;
let other = decoder.read_vec(other_len as usize)?.unverified(/*valid as any vec of the right size*/);
Ok(TSIG {
algorithm,
time,
fudge,
mac,
oid,
error,
other,
})
Ok(Self {
algorithm,
time,
fudge,
mac,
oid,
error,
other,
})
}
}
/// Write the RData from the given Encoder
///
/// ```text
/// 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// / Algorithm Name /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | |
/// | Time Signed +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | | Fudge |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | MAC Size | /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ MAC /
/// / /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Original ID | Error |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Other Len | /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Other Data /
/// / /
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ```
pub fn emit(encoder: &mut BinEncoder<'_>, tsig: &TSIG) -> ProtoResult<()> {
tsig.algorithm.emit(encoder)?;
encoder.emit_u16(
(tsig.time >> 32)
.try_into()
.map_err(|_| ProtoError::from("invalid time, overflow 48 bit counter in TSIG"))?,
)?;
encoder.emit_u32(tsig.time as u32)?; // this cast is supposed to truncate
encoder.emit_u16(tsig.fudge)?;
encoder.emit_u16(
tsig.mac
.len()
.try_into()
.map_err(|_| ProtoError::from("invalid mac, longer than 65535 B in TSIG"))?,
)?;
encoder.emit_vec(&tsig.mac)?;
encoder.emit_u16(tsig.oid)?;
encoder.emit_u16(tsig.error)?;
encoder.emit_u16(
tsig.other
.len()
.try_into()
.map_err(|_| ProtoError::from("invalid other_buffer, longer than 65535 B in TSIG"))?,
)?;
encoder.emit_vec(&tsig.other)?;
Ok(())
impl RecordData for TSIG {
fn try_from_rdata(data: RData) -> Result<Self, RData> {
match data {
RData::DNSSEC(DNSSECRData::TSIG(csync)) => Ok(csync),
_ => Err(data),
}
}
fn try_borrow(data: &RData) -> Result<&Self, &RData> {
match data {
RData::DNSSEC(DNSSECRData::TSIG(csync)) => Ok(csync),
_ => Err(data),
}
}
fn record_type(&self) -> RecordType {
RecordType::TSIG
}
fn into_rdata(self) -> RData {
RData::DNSSEC(DNSSECRData::TSIG(self))
}
}
// Does not appear to have a normalized text representation
@ -796,14 +823,18 @@ mod tests {
fn test_encode_decode(rdata: TSIG) {
let mut bytes = Vec::new();
let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
emit(&mut encoder, &rdata).expect("failed to emit tsig");
rdata.emit(&mut encoder).expect("failed to emit tsig");
let bytes = encoder.into_bytes();
println!("bytes: {bytes:?}");
let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
let read_rdata =
read(&mut decoder, Restrict::new(bytes.len() as u16)).expect("failed to read back");
let read_rdata = TSIG::read_data(
&mut decoder,
RecordType::TSIG,
Restrict::new(bytes.len() as u16),
)
.expect("failed to read back");
assert_eq!(rdata, read_rdata);
}

View File

@ -592,12 +592,12 @@ mod tests {
use openssl::bn::BigNum;
use openssl::pkey::Private;
use openssl::rsa::Rsa;
use trust_dns_proto::rr::rdata::NS;
use crate::op::{Message, Query};
use crate::rr::dnssec::rdata::key::KeyUsage;
use crate::rr::dnssec::rdata::{DNSSECRData, SIG};
use crate::rr::dnssec::*;
use crate::rr::rdata::NS;
use crate::rr::{DNSClass, Name, Record, RecordType};
use super::*;
@ -798,11 +798,11 @@ MC0CAQACBQC+L6pNAgMBAAECBQCYj0ZNAgMA9CsCAwDHZwICeEUCAnE/AgMA3u0=
#[cfg(test)]
mod tests {
use openssl::rsa::Rsa;
use trust_dns_proto::rr::rdata::{CNAME, NS};
use crate::rr::dnssec::rdata::{DNSSECRData, SIG};
use crate::rr::dnssec::tbs::*;
use crate::rr::dnssec::*;
use crate::rr::rdata::{CNAME, NS};
use crate::rr::*;
#[test]

View File

@ -16,7 +16,7 @@ use futures::stream::{once, Stream};
use futures::{future, AsyncRead, AsyncWrite, Future};
use trust_dns_client::op::{Message, Query};
use trust_dns_client::rr::rdata::CNAME;
use trust_dns_client::rr::rdata::{CNAME, SOA};
use trust_dns_client::rr::{Name, RData, Record};
use trust_dns_proto::error::ProtoError;
use trust_dns_proto::tcp::DnsTcpStream;