implement RecordData for most DNSSEC RData types
This commit is contained in:
parent
3919e66d9f
commit
0f21992811
80
crates/proto/src/rr/dnssec/rdata/cdnskey.rs
Normal file
80
crates/proto/src/rr/dnssec/rdata/cdnskey.rs
Normal 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)
|
||||
}
|
||||
}
|
80
crates/proto/src/rr/dnssec/rdata/cds.rs
Normal file
80
crates/proto/src/rr/dnssec/rdata/cds.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
98
crates/proto/src/rr/dnssec/rdata/rrsig.rs
Normal file
98
crates/proto/src/rr/dnssec/rdata/rrsig.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user