fix RRSIG and SIG usage with new RecordData types
This commit is contained in:
parent
f705256c55
commit
9e56c123c2
@ -17,7 +17,7 @@ use tokio::runtime::Runtime;
|
||||
use tracing::{info, warn};
|
||||
use trust_dns_client::client::*;
|
||||
use trust_dns_client::proto::xfer::DnsResponse;
|
||||
use trust_dns_client::rr::*;
|
||||
use trust_dns_proto::rr::*;
|
||||
#[cfg(feature = "dnssec")]
|
||||
use trust_dns_proto::rr::{dnssec::rdata::DNSSECRData, dnssec::*};
|
||||
|
||||
@ -266,6 +266,8 @@ pub fn query_all_dnssec(
|
||||
algorithm: Algorithm,
|
||||
with_rfc6975: bool,
|
||||
) {
|
||||
use trust_dns_client::rr::rdata::{DNSKEY, RRSIG};
|
||||
|
||||
let name = Name::from_str("example.com.").unwrap();
|
||||
let mut client = MutMessageHandle::new(client);
|
||||
client.lookup_options.set_is_dnssec(true);
|
||||
@ -280,14 +282,8 @@ pub fn query_all_dnssec(
|
||||
let dnskey = response
|
||||
.answers()
|
||||
.iter()
|
||||
.filter(|r| r.record_type() == RecordType::DNSKEY)
|
||||
.map(|r| {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::DNSKEY(ref dnskey))) = r.data() {
|
||||
dnskey.clone()
|
||||
} else {
|
||||
panic!("wrong RDATA")
|
||||
}
|
||||
})
|
||||
.filter_map(|r| r.data())
|
||||
.filter_map(|r| DNSKEY::try_borrow(r).ok())
|
||||
.find(|d| d.algorithm() == algorithm);
|
||||
assert!(dnskey.is_some(), "DNSKEY not found");
|
||||
|
||||
@ -296,14 +292,8 @@ pub fn query_all_dnssec(
|
||||
let rrsig = response
|
||||
.answers()
|
||||
.iter()
|
||||
.filter(|r| r.record_type() == RecordType::RRSIG)
|
||||
.map(|r| {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::SIG(ref rrsig))) = r.data() {
|
||||
rrsig.clone()
|
||||
} else {
|
||||
panic!("wrong RDATA")
|
||||
}
|
||||
})
|
||||
.filter_map(|r| r.data())
|
||||
.filter_map(|r| RRSIG::try_borrow(r).ok())
|
||||
.filter(|rrsig| rrsig.algorithm() == algorithm)
|
||||
.find(|rrsig| rrsig.type_covered() == RecordType::DNSKEY);
|
||||
assert!(rrsig.is_some(), "Associated RRSIG not found");
|
||||
|
@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
error::ProtoResult,
|
||||
rr::{RData, RecordData, RecordDataDecodable, RecordType},
|
||||
rr::{dnssec::Algorithm, Name, RData, RecordData, RecordDataDecodable, RecordType},
|
||||
serialize::binary::{BinDecoder, BinEncodable, BinEncoder, Restrict},
|
||||
};
|
||||
|
||||
@ -25,6 +25,52 @@ use super::{DNSSECRData, SIG};
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
||||
pub struct RRSIG(SIG);
|
||||
|
||||
impl RRSIG {
|
||||
/// Creates a new SIG record data, used for both RRSIG and SIG(0) records.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `type_covered` - The `RecordType` which this signature covers, should be NULL for SIG(0).
|
||||
/// * `algorithm` - The `Algorithm` used to generate the `signature`.
|
||||
/// * `num_labels` - The number of labels in the name, should be less 1 for *.name labels,
|
||||
/// see `Name::num_labels()`.
|
||||
/// * `original_ttl` - The TTL for the RRSet stored in the zone, should be 0 for SIG(0).
|
||||
/// * `sig_expiration` - Timestamp at which this signature is no longer valid, very important to
|
||||
/// keep this low, < +5 minutes to limit replay attacks.
|
||||
/// * `sig_inception` - Timestamp when this signature was generated.
|
||||
/// * `key_tag` - See the key_tag generation in `rr::dnssec::Signer::key_tag()`.
|
||||
/// * `signer_name` - Domain name of the server which was used to generate the signature.
|
||||
/// * `sig` - signature stored in this record.
|
||||
///
|
||||
/// # Return value
|
||||
///
|
||||
/// The new SIG record data.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
type_covered: RecordType,
|
||||
algorithm: Algorithm,
|
||||
num_labels: u8,
|
||||
original_ttl: u32,
|
||||
sig_expiration: u32,
|
||||
sig_inception: u32,
|
||||
key_tag: u16,
|
||||
signer_name: Name,
|
||||
sig: Vec<u8>,
|
||||
) -> Self {
|
||||
Self(SIG::new(
|
||||
type_covered,
|
||||
algorithm,
|
||||
num_labels,
|
||||
original_ttl,
|
||||
sig_expiration,
|
||||
sig_inception,
|
||||
key_tag,
|
||||
signer_name,
|
||||
sig,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for RRSIG {
|
||||
type Target = SIG;
|
||||
|
||||
|
@ -595,7 +595,7 @@ mod tests {
|
||||
|
||||
use crate::op::{Message, Query};
|
||||
use crate::rr::dnssec::rdata::key::KeyUsage;
|
||||
use crate::rr::dnssec::rdata::{DNSSECRData, SIG};
|
||||
use crate::rr::dnssec::rdata::{DNSSECRData, RRSIG, SIG};
|
||||
use crate::rr::dnssec::*;
|
||||
use crate::rr::rdata::NS;
|
||||
use crate::rr::{DNSClass, Name, Record, RecordType};
|
||||
@ -677,9 +677,9 @@ mod tests {
|
||||
let rrsig = Record::new()
|
||||
.set_name(origin.clone())
|
||||
.set_ttl(86400)
|
||||
.set_rr_type(RecordType::NS)
|
||||
.set_rr_type(RecordType::RRSIG)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_data(Some(RData::DNSSEC(DNSSECRData::SIG(SIG::new(
|
||||
.set_data(Some(RRSIG::new(
|
||||
RecordType::NS,
|
||||
Algorithm::RSASHA256,
|
||||
origin.num_labels(),
|
||||
@ -689,7 +689,7 @@ mod tests {
|
||||
signer.calculate_key_tag().unwrap(),
|
||||
origin.clone(),
|
||||
vec![],
|
||||
)))))
|
||||
)))
|
||||
.clone();
|
||||
let rrset = vec![
|
||||
Record::new()
|
||||
@ -799,7 +799,7 @@ MC0CAQACBQC+L6pNAgMBAAECBQCYj0ZNAgMA9CsCAwDHZwICeEUCAnE/AgMA3u0=
|
||||
mod tests {
|
||||
use openssl::rsa::Rsa;
|
||||
|
||||
use crate::rr::dnssec::rdata::{DNSSECRData, SIG};
|
||||
use crate::rr::dnssec::rdata::RRSIG;
|
||||
use crate::rr::dnssec::tbs::*;
|
||||
use crate::rr::dnssec::*;
|
||||
use crate::rr::rdata::{CNAME, NS};
|
||||
@ -816,9 +816,9 @@ MC0CAQACBQC+L6pNAgMBAAECBQCYj0ZNAgMA9CsCAwDHZwICeEUCAnE/AgMA3u0=
|
||||
let rrsig = Record::new()
|
||||
.set_name(origin.clone())
|
||||
.set_ttl(86400)
|
||||
.set_rr_type(RecordType::NS)
|
||||
.set_rr_type(RecordType::RRSIG)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_data(Some(RData::DNSSEC(DNSSECRData::SIG(SIG::new(
|
||||
.set_data(Some(RRSIG::new(
|
||||
RecordType::NS,
|
||||
Algorithm::RSASHA256,
|
||||
origin.num_labels(),
|
||||
@ -828,7 +828,7 @@ MC0CAQACBQC+L6pNAgMBAAECBQCYj0ZNAgMA9CsCAwDHZwICeEUCAnE/AgMA3u0=
|
||||
signer.calculate_key_tag().unwrap(),
|
||||
origin.clone(),
|
||||
vec![],
|
||||
)))))
|
||||
)))
|
||||
.clone();
|
||||
let rrset = vec![
|
||||
Record::new()
|
||||
|
@ -1,9 +1,9 @@
|
||||
//! hash functions for DNSSEC operations
|
||||
|
||||
use super::rdata::{sig, DNSSECRData, SIG};
|
||||
use super::rdata::{sig, RRSIG, SIG};
|
||||
use crate::error::*;
|
||||
use crate::rr::dnssec::Algorithm;
|
||||
use crate::rr::{DNSClass, Name, RData, Record, RecordType};
|
||||
use crate::rr::{DNSClass, Name, Record, RecordType};
|
||||
use crate::serialize::binary::{BinEncodable, BinEncoder, EncodeMode};
|
||||
|
||||
/// Data To Be Signed.
|
||||
@ -183,8 +183,8 @@ pub fn rrset_tbs(
|
||||
/// # Return
|
||||
///
|
||||
/// binary hash of the RRSet with the information from the RRSIG record
|
||||
pub fn rrset_tbs_with_rrsig(rrsig: &Record, records: &[Record]) -> ProtoResult<TBS> {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::SIG(ref sig))) = rrsig.data() {
|
||||
pub fn rrset_tbs_with_rrsig(rrsig: &Record<RRSIG>, records: &[Record]) -> ProtoResult<TBS> {
|
||||
if let Some(sig) = rrsig.data() {
|
||||
rrset_tbs_with_sig(rrsig.name(), rrsig.dns_class(), sig, records)
|
||||
} else {
|
||||
Err(format!("could not determine name from {}", rrsig.name()).into())
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Verifier is a structure for performing many of the signing processes of the DNSSEC specification
|
||||
|
||||
use crate::error::*;
|
||||
use crate::rr::dnssec::rdata::{DNSKEY, KEY, SIG};
|
||||
use crate::rr::dnssec::rdata::{DNSKEY, KEY, RRSIG, SIG};
|
||||
use crate::rr::dnssec::Algorithm;
|
||||
use crate::rr::dnssec::{tbs, PublicKey, PublicKeyEnum};
|
||||
use crate::rr::{DNSClass, Name, Record};
|
||||
@ -62,7 +62,7 @@ pub trait Verifier {
|
||||
&self,
|
||||
name: &Name,
|
||||
dns_class: DNSClass,
|
||||
sig: &SIG,
|
||||
sig: &RRSIG,
|
||||
records: &[Record],
|
||||
) -> ProtoResult<()> {
|
||||
let rrset_tbs = tbs::rrset_tbs_with_sig(name, dns_class, sig, records)?;
|
||||
|
@ -55,6 +55,7 @@ pub trait RecordData: Clone + Sized + PartialEq + Eq + fmt::Display + BinEncodab
|
||||
fn try_from_rdata(data: RData) -> Result<Self, RData>;
|
||||
|
||||
/// Attempts to borrow this RecordData from the RData type, if it is not the correct type the original is returned
|
||||
/// FIXME: make this return Option instead of Result
|
||||
fn try_borrow(data: &RData) -> Result<&Self, &RData>;
|
||||
|
||||
/// Get the associated RecordType for the RData
|
||||
|
@ -19,8 +19,8 @@ use enum_as_inner::EnumAsInner;
|
||||
use tracing::{trace, warn};
|
||||
|
||||
use super::rdata::{
|
||||
ANAME, CAA, CNAME, CSYNC, HINFO, MX, NAPTR, NS, NULL, OPENPGPKEY, OPT, PTR, SOA, SRV, SSHFP,
|
||||
SVCB, TLSA, TXT,
|
||||
ANAME, CAA, CNAME, CSYNC, HINFO, HTTPS, MX, NAPTR, NS, NULL, OPENPGPKEY, OPT, PTR, SOA, SRV,
|
||||
SSHFP, SVCB, TLSA, TXT,
|
||||
};
|
||||
use super::record_type::RecordType;
|
||||
use super::{RecordData, RecordDataDecodable};
|
||||
@ -232,7 +232,7 @@ pub enum RData {
|
||||
///
|
||||
/// Name TTL IN HTTPS SvcPriority TargetName SvcParams
|
||||
/// ```
|
||||
HTTPS(SVCB),
|
||||
HTTPS(HTTPS),
|
||||
|
||||
/// ```text
|
||||
/// 3.3.9. MX RDATA format
|
||||
@ -827,7 +827,7 @@ impl BinEncodable for RData {
|
||||
Self::PTR(ref ptr) => ptr.emit(encoder),
|
||||
Self::CSYNC(ref csync) => csync.emit(encoder),
|
||||
Self::HINFO(ref hinfo) => hinfo.emit(encoder),
|
||||
Self::HTTPS(ref svcb) => svcb.emit(encoder),
|
||||
Self::HTTPS(ref https) => https.emit(encoder),
|
||||
Self::ZERO => Ok(()),
|
||||
Self::MX(ref mx) => mx.emit(encoder),
|
||||
Self::NAPTR(ref naptr) => encoder.with_canonical_names(|encoder| naptr.emit(encoder)),
|
||||
@ -891,7 +891,7 @@ impl<'r> RecordDataDecodable<'r> for RData {
|
||||
}
|
||||
RecordType::HTTPS => {
|
||||
trace!("reading HTTPS");
|
||||
SVCB::read_data(decoder, record_type, length).map(Self::HTTPS)
|
||||
HTTPS::read_data(decoder, record_type, length).map(Self::HTTPS)
|
||||
}
|
||||
RecordType::ZERO => {
|
||||
trace!("reading EMPTY");
|
||||
@ -1014,7 +1014,7 @@ impl fmt::Display for RData {
|
||||
Self::PTR(ref ptr) => w(f, ptr),
|
||||
Self::CSYNC(ref csync) => w(f, csync),
|
||||
Self::HINFO(ref hinfo) => w(f, hinfo),
|
||||
Self::HTTPS(ref svcb) => w(f, svcb),
|
||||
Self::HTTPS(ref https) => w(f, https),
|
||||
Self::ZERO => Ok(()),
|
||||
// to_lowercase for rfc4034 and rfc6840
|
||||
Self::MX(ref mx) => w(f, mx),
|
||||
|
@ -280,7 +280,19 @@ impl<R: RecordData> Record<R> {
|
||||
/// For example, the if the TYPE is A and the CLASS is IN,
|
||||
/// the RDATA field is a 4 octet ARPA Internet address.
|
||||
/// ```
|
||||
#[track_caller]
|
||||
pub fn set_data(&mut self, rdata: Option<R>) -> &mut Self {
|
||||
debug_assert!(
|
||||
if let Some(rdata) = &rdata {
|
||||
rdata.record_type() == self.record_type() || rdata.record_type() == RecordType::NULL
|
||||
} else {
|
||||
true
|
||||
},
|
||||
"record types do not match, {} <> {:?}",
|
||||
self.record_type(),
|
||||
rdata.map(|r| r.record_type())
|
||||
);
|
||||
|
||||
self.rdata = rdata;
|
||||
self
|
||||
}
|
||||
@ -538,6 +550,17 @@ impl<'r, R: RecordData + RecordDataDecodable<'r>> BinDecodable<'r> for Record<R>
|
||||
)?)
|
||||
};
|
||||
|
||||
debug_assert!(
|
||||
if let Some(rdata) = &rdata {
|
||||
rdata.record_type() == record_type
|
||||
} else {
|
||||
true
|
||||
},
|
||||
"record types do not match, {} <> {:?}",
|
||||
record_type,
|
||||
rdata.map(|r| r.record_type())
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
name_labels,
|
||||
rr_type: record_type,
|
||||
|
@ -562,14 +562,14 @@ impl<'r> Iterator for RrsigsByAlgorithms<'r> {
|
||||
self.rrsigs
|
||||
.by_ref()
|
||||
.filter(|record| {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::SIG(ref rrsig))) = record.data() {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::RRSIG(ref rrsig))) = record.data() {
|
||||
supported_algorithms.has(rrsig.algorithm())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.max_by_key(|record| {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::SIG(ref rrsig))) = record.data() {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::RRSIG(ref rrsig))) = record.data() {
|
||||
rrsig.algorithm()
|
||||
} else {
|
||||
#[allow(deprecated)]
|
||||
@ -870,11 +870,11 @@ mod test {
|
||||
#[allow(clippy::blocks_in_if_conditions)]
|
||||
fn test_get_filter() {
|
||||
use crate::rr::dnssec::rdata::DNSSECRData;
|
||||
use crate::rr::dnssec::rdata::SIG;
|
||||
use crate::rr::dnssec::rdata::RRSIG;
|
||||
use crate::rr::dnssec::{Algorithm, SupportedAlgorithms};
|
||||
|
||||
let name = Name::root();
|
||||
let rsasha256 = SIG::new(
|
||||
let rsasha256 = RRSIG::new(
|
||||
RecordType::A,
|
||||
Algorithm::RSASHA256,
|
||||
0,
|
||||
@ -885,7 +885,7 @@ mod test {
|
||||
Name::root(),
|
||||
vec![],
|
||||
);
|
||||
let ecp256 = SIG::new(
|
||||
let ecp256 = RRSIG::new(
|
||||
RecordType::A,
|
||||
Algorithm::ECDSAP256SHA256,
|
||||
0,
|
||||
@ -896,7 +896,7 @@ mod test {
|
||||
Name::root(),
|
||||
vec![],
|
||||
);
|
||||
let ecp384 = SIG::new(
|
||||
let ecp384 = RRSIG::new(
|
||||
RecordType::A,
|
||||
Algorithm::ECDSAP384SHA384,
|
||||
0,
|
||||
@ -907,7 +907,7 @@ mod test {
|
||||
Name::root(),
|
||||
vec![],
|
||||
);
|
||||
let ed25519 = SIG::new(
|
||||
let ed25519 = RRSIG::new(
|
||||
RecordType::A,
|
||||
Algorithm::ED25519,
|
||||
0,
|
||||
@ -924,28 +924,28 @@ mod test {
|
||||
.set_ttl(3600)
|
||||
.set_rr_type(RecordType::RRSIG)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_data(Some(RData::DNSSEC(DNSSECRData::SIG(rsasha256))))
|
||||
.set_data(Some(RData::DNSSEC(DNSSECRData::RRSIG(rsasha256))))
|
||||
.clone();
|
||||
let rrsig_ecp256 = Record::new()
|
||||
.set_name(name.clone())
|
||||
.set_ttl(3600)
|
||||
.set_rr_type(RecordType::RRSIG)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_data(Some(RData::DNSSEC(DNSSECRData::SIG(ecp256))))
|
||||
.set_data(Some(RData::DNSSEC(DNSSECRData::RRSIG(ecp256))))
|
||||
.clone();
|
||||
let rrsig_ecp384 = Record::new()
|
||||
.set_name(name.clone())
|
||||
.set_ttl(3600)
|
||||
.set_rr_type(RecordType::RRSIG)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_data(Some(RData::DNSSEC(DNSSECRData::SIG(ecp384))))
|
||||
.set_data(Some(RData::DNSSEC(DNSSECRData::RRSIG(ecp384))))
|
||||
.clone();
|
||||
let rrsig_ed25519 = Record::new()
|
||||
.set_name(name.clone())
|
||||
.set_ttl(3600)
|
||||
.set_rr_type(RecordType::RRSIG)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_data(Some(RData::DNSSEC(DNSSECRData::SIG(ed25519))))
|
||||
.set_data(Some(RData::DNSSEC(DNSSECRData::RRSIG(ed25519))))
|
||||
.clone();
|
||||
|
||||
let a = Record::new()
|
||||
@ -965,7 +965,7 @@ mod test {
|
||||
assert!(rrset
|
||||
.records_with_rrsigs(SupportedAlgorithms::all(),)
|
||||
.any(
|
||||
|r| if let Some(RData::DNSSEC(DNSSECRData::SIG(ref sig))) = r.data() {
|
||||
|r| if let Some(RData::DNSSEC(DNSSECRData::RRSIG(ref sig))) = r.data() {
|
||||
sig.algorithm() == Algorithm::ED25519
|
||||
} else {
|
||||
false
|
||||
@ -975,7 +975,7 @@ mod test {
|
||||
let mut supported_algorithms = SupportedAlgorithms::new();
|
||||
supported_algorithms.set(Algorithm::ECDSAP384SHA384);
|
||||
assert!(rrset.records_with_rrsigs(supported_algorithms).any(|r| {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::SIG(ref sig))) = r.data() {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::RRSIG(ref sig))) = r.data() {
|
||||
sig.algorithm() == Algorithm::ECDSAP384SHA384
|
||||
} else {
|
||||
false
|
||||
@ -985,7 +985,7 @@ mod test {
|
||||
let mut supported_algorithms = SupportedAlgorithms::new();
|
||||
supported_algorithms.set(Algorithm::ED25519);
|
||||
assert!(rrset.records_with_rrsigs(supported_algorithms).any(|r| {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::SIG(ref sig))) = r.data() {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::RRSIG(ref sig))) = r.data() {
|
||||
sig.algorithm() == Algorithm::ED25519
|
||||
} else {
|
||||
false
|
||||
|
@ -20,7 +20,7 @@
|
||||
use crate::rr::dnssec::rdata::DNSSECRData;
|
||||
use crate::{
|
||||
rr::{
|
||||
rdata::{ANAME, CNAME, NS, PTR},
|
||||
rdata::{ANAME, CNAME, HTTPS, NS, PTR},
|
||||
Name, RData, RecordType,
|
||||
},
|
||||
serialize::txt::{
|
||||
@ -81,7 +81,7 @@ impl RDataParser for RData {
|
||||
RecordType::CNAME => Self::CNAME(CNAME(name::parse(tokens, origin)?)),
|
||||
RecordType::CSYNC => csync::parse(tokens).map(Self::CSYNC)?,
|
||||
RecordType::HINFO => Self::HINFO(hinfo::parse(tokens)?),
|
||||
RecordType::HTTPS => svcb::parse(tokens).map(Self::SVCB)?,
|
||||
RecordType::HTTPS => svcb::parse(tokens).map(HTTPS).map(Self::HTTPS)?,
|
||||
RecordType::IXFR => return Err(ParseError::from("parsing IXFR doesn't make sense")),
|
||||
RecordType::MX => Self::MX(mx::parse(tokens, origin)?),
|
||||
RecordType::NAPTR => Self::NAPTR(naptr::parse(tokens, origin)?),
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2016 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
|
||||
@ -20,12 +20,12 @@ use futures_util::stream::{Stream, TryStreamExt};
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use crate::op::{OpCode, Query};
|
||||
use crate::rr::dnssec::rdata::{DNSSECRData, DNSKEY, SIG};
|
||||
use crate::rr::dnssec::rdata::{DNSSECRData, DNSKEY, RRSIG};
|
||||
#[cfg(feature = "dnssec")]
|
||||
use crate::rr::dnssec::Verifier;
|
||||
use crate::rr::dnssec::{Algorithm, SupportedAlgorithms, TrustAnchor};
|
||||
use crate::rr::rdata::opt::EdnsOption;
|
||||
use crate::rr::{DNSClass, Name, RData, Record, RecordType};
|
||||
use crate::rr::{DNSClass, Name, RData, Record, RecordData, RecordType};
|
||||
use crate::xfer::dns_handle::DnsHandle;
|
||||
use crate::xfer::{DnsRequest, DnsRequestOptions, DnsResponse, FirstAnswer};
|
||||
use crate::{error::*, op::Edns};
|
||||
@ -282,20 +282,21 @@ where
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let rrsigs: Vec<Record> = message_result
|
||||
let rrsigs: Vec<Record<RRSIG>> = message_result
|
||||
.answers()
|
||||
.iter()
|
||||
.chain(message_result.name_servers())
|
||||
.chain(message_result.additionals())
|
||||
.filter(|rr| is_dnssec(rr, RecordType::RRSIG))
|
||||
.filter(|rr| {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::SIG(ref rrsig))) = rr.data() {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::RRSIG(ref rrsig))) = rr.data() {
|
||||
rrsig.type_covered() == record_type
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.cloned()
|
||||
.map(|rr| Record::<RRSIG>::try_from(rr).expect("the record type was checked above"))
|
||||
.collect();
|
||||
|
||||
// if there is already an active validation going on, assume the other validation will
|
||||
@ -322,7 +323,8 @@ where
|
||||
verify_all_rrsets(message_result, rrsets_to_verify).await
|
||||
}
|
||||
|
||||
fn is_dnssec(rr: &Record, dnssec_type: RecordType) -> bool {
|
||||
// TODO: is this method useful/necessary?
|
||||
fn is_dnssec<D: RecordData>(rr: &Record<D>, dnssec_type: RecordType) -> bool {
|
||||
rr.record_type().is_dnssec() && dnssec_type.is_dnssec() && rr.record_type() == dnssec_type
|
||||
}
|
||||
|
||||
@ -428,7 +430,7 @@ where
|
||||
async fn verify_rrset<H, E>(
|
||||
handle: DnssecDnsHandle<H>,
|
||||
rrset: Rrset,
|
||||
rrsigs: Vec<Record>,
|
||||
rrsigs: Vec<Record<RRSIG>>,
|
||||
options: DnsRequestOptions,
|
||||
) -> Result<Rrset, E>
|
||||
where
|
||||
@ -484,13 +486,8 @@ where
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, rr)| is_dnssec(rr, RecordType::DNSKEY))
|
||||
.filter_map(|(i, rr)| {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::DNSKEY(ref rdata))) = rr.data() {
|
||||
Some((i, rdata))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter_map(|(i, rr)| rr.data().map(|rr| (i, rr)))
|
||||
.filter_map(|(i, rr)| DNSKEY::try_borrow(rr).map(|rr| (i, rr)).ok())
|
||||
.filter_map(|(i, rdata)| {
|
||||
if handle
|
||||
.trust_anchor
|
||||
@ -642,7 +639,7 @@ fn test_preserve() {
|
||||
async fn verify_default_rrset<H, E>(
|
||||
handle: &DnssecDnsHandle<H>,
|
||||
rrset: Rrset,
|
||||
rrsigs: Vec<Record>,
|
||||
rrsigs: Vec<Record<RRSIG>>,
|
||||
options: DnsRequestOptions,
|
||||
) -> Result<Rrset, E>
|
||||
where
|
||||
@ -661,13 +658,8 @@ where
|
||||
if rrsigs
|
||||
.iter()
|
||||
.filter(|rrsig| is_dnssec(rrsig, RecordType::RRSIG))
|
||||
.any(|rrsig| {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::SIG(ref sig))) = rrsig.data() {
|
||||
RecordType::DNSKEY == rrset.record_type && sig.signer_name() == &rrset.name
|
||||
} else {
|
||||
panic!("expected a SIG here");
|
||||
}
|
||||
})
|
||||
.filter_map(|rrsig| rrsig.data())
|
||||
.any(|rrsig| RecordType::DNSKEY == rrset.record_type && rrsig.signer_name() == &rrset.name)
|
||||
{
|
||||
// in this case it was looks like a self-signed key, first validate the signature
|
||||
// then return rrset. Like the standard case below, the DNSKEY is validated
|
||||
@ -678,14 +670,7 @@ where
|
||||
.into_iter()
|
||||
// this filter is technically unnecessary, can probably remove it...
|
||||
.filter(|rrsig| is_dnssec(rrsig, RecordType::RRSIG))
|
||||
.map(|rrsig| {
|
||||
if let Some(RData::DNSSEC(DNSSECRData::SIG(sig))) = rrsig.into_data() {
|
||||
// setting up the context explicitly.
|
||||
sig
|
||||
} else {
|
||||
panic!("expected a SIG here");
|
||||
}
|
||||
})
|
||||
.filter_map(|rrsig| rrsig.into_data())
|
||||
.filter_map(|sig| {
|
||||
let rrset = Arc::clone(&rrset);
|
||||
|
||||
@ -725,14 +710,7 @@ where
|
||||
let verifications = rrsigs.into_iter()
|
||||
// this filter is technically unnecessary, can probably remove it...
|
||||
.filter(|rrsig| is_dnssec(rrsig, RecordType::RRSIG))
|
||||
.map(|rrsig|
|
||||
if let Some(RData::DNSSEC(DNSSECRData::SIG(sig))) = rrsig.into_data() {
|
||||
// setting up the context explicitly.
|
||||
sig
|
||||
} else {
|
||||
panic!("expected a SIG here");
|
||||
}
|
||||
)
|
||||
.filter_map(|rrsig|rrsig.into_data())
|
||||
.map(|sig| {
|
||||
let rrset = Arc::clone(&rrset);
|
||||
let mut handle = handle.clone_with_context();
|
||||
@ -749,13 +727,11 @@ where
|
||||
.answers()
|
||||
.iter()
|
||||
.filter(|r| is_dnssec(r, RecordType::DNSKEY))
|
||||
.find(|r|
|
||||
if let Some(RData::DNSSEC(DNSSECRData::DNSKEY(ref dnskey))) = r.data() {
|
||||
let dnskey_name = r.name();
|
||||
.filter_map(|r| r.data().map(|data| (r.name(), data)))
|
||||
.filter_map(|(dnskey_name, data)|
|
||||
DNSKEY::try_borrow(data).ok().map(|data| (dnskey_name, data)))
|
||||
.find(|(dnskey_name, dnskey)|
|
||||
verify_rrset_with_dnskey(dnskey_name, dnskey, &sig, &rrset).is_ok()
|
||||
} else {
|
||||
panic!("expected a DNSKEY here: {:?}", r.data());
|
||||
}
|
||||
)
|
||||
.map(|_| ())
|
||||
.ok_or_else(|| E::from(ProtoError::from(ProtoErrorKind::Message("validation failed")))))
|
||||
@ -789,7 +765,7 @@ where
|
||||
fn verify_rrset_with_dnskey(
|
||||
dnskey_name: &Name,
|
||||
dnskey: &DNSKEY,
|
||||
sig: &SIG,
|
||||
sig: &RRSIG,
|
||||
rrset: &Rrset,
|
||||
) -> ProtoResult<()> {
|
||||
if dnskey.revoke() {
|
||||
@ -824,7 +800,7 @@ fn verify_rrset_with_dnskey(
|
||||
|
||||
/// Will always return an error. To enable record verification compile with the openssl feature.
|
||||
#[cfg(not(feature = "dnssec"))]
|
||||
fn verify_rrset_with_dnskey(_: &DNSKEY, _: &SIG, _: &Rrset) -> ProtoResult<()> {
|
||||
fn verify_rrset_with_dnskey(_: &DNSKEY, _: &RRSIG, _: &Rrset) -> ProtoResult<()> {
|
||||
Err(ProtoErrorKind::Message("openssl or ring feature(s) not enabled").into())
|
||||
}
|
||||
|
||||
|
@ -251,6 +251,8 @@ mod tests {
|
||||
use std::net::Ipv4Addr;
|
||||
use std::str::FromStr;
|
||||
|
||||
use trust_dns_client::rr::RecordType;
|
||||
|
||||
use crate::proto::op::{Header, Message};
|
||||
use crate::proto::rr::{DNSClass, Name, RData, Record};
|
||||
use crate::proto::serialize::binary::BinEncoder;
|
||||
@ -265,6 +267,7 @@ mod tests {
|
||||
encoder.set_max_size(512);
|
||||
|
||||
let answer = Record::new()
|
||||
.set_record_type(RecordType::A)
|
||||
.set_name(Name::from_str("www.example.com.").unwrap())
|
||||
.set_data(Some(RData::A(Ipv4Addr::new(93, 184, 216, 34))))
|
||||
.set_dns_class(DNSClass::NONE)
|
||||
@ -301,6 +304,7 @@ mod tests {
|
||||
encoder.set_max_size(512);
|
||||
|
||||
let answer = Record::new()
|
||||
.set_record_type(RecordType::A)
|
||||
.set_name(Name::from_str("www.example.com.").unwrap())
|
||||
.set_data(Some(RData::A(Ipv4Addr::new(93, 184, 216, 34))))
|
||||
.set_dns_class(DNSClass::NONE)
|
||||
|
@ -744,6 +744,10 @@ impl InnerInMemory {
|
||||
zone_ttl: u32,
|
||||
zone_class: DNSClass,
|
||||
) -> DnsSecResult<()> {
|
||||
use crate::client::rr::dnssec::tbs;
|
||||
use time::OffsetDateTime;
|
||||
use trust_dns_client::rr::rdata::RRSIG;
|
||||
|
||||
let inception = OffsetDateTime::now_utc();
|
||||
|
||||
rr_set.clear_rrsigs();
|
||||
@ -798,7 +802,7 @@ impl InnerInMemory {
|
||||
};
|
||||
|
||||
let mut rrsig = rrsig_temp.clone();
|
||||
rrsig.set_data(Some(RData::DNSSEC(DNSSECRData::SIG(SIG::new(
|
||||
rrsig.set_data(Some(RData::DNSSEC(DNSSECRData::RRSIG(RRSIG::new(
|
||||
// type_covered: RecordType,
|
||||
rr_set.record_type(),
|
||||
// algorithm: Algorithm,
|
||||
|
@ -5,13 +5,19 @@ use std::str::FromStr;
|
||||
|
||||
use futures_executor::block_on;
|
||||
|
||||
use trust_dns_proto::op::{Header, Query};
|
||||
use trust_dns_proto::rr::dnssec::rdata::DNSKEY;
|
||||
use trust_dns_proto::rr::dnssec::{Algorithm, SupportedAlgorithms, Verifier};
|
||||
use trust_dns_proto::rr::{DNSClass, Name, RData, Record, RecordType};
|
||||
use trust_dns_proto::xfer;
|
||||
use trust_dns_server::authority::{AuthLookup, Authority, DnssecAuthority, LookupOptions};
|
||||
use trust_dns_server::server::{Protocol, RequestInfo};
|
||||
use trust_dns_proto::{
|
||||
op::{Header, Query},
|
||||
rr::{
|
||||
dnssec::{rdata::DNSKEY, Algorithm, SupportedAlgorithms, Verifier},
|
||||
rdata::RRSIG,
|
||||
DNSClass, Name, RData, Record, RecordType,
|
||||
},
|
||||
xfer,
|
||||
};
|
||||
use trust_dns_server::{
|
||||
authority::{AuthLookup, Authority, DnssecAuthority, LookupOptions},
|
||||
server::{Protocol, RequestInfo},
|
||||
};
|
||||
|
||||
const TEST_HEADER: &Header = &Header::new();
|
||||
|
||||
@ -35,9 +41,10 @@ pub fn test_a_lookup<A: Authority<Lookup = AuthLookup>>(authority: A, keys: &[DN
|
||||
.cloned()
|
||||
.partition(|r| r.record_type() == RecordType::A);
|
||||
|
||||
let (rrsig_records, _other_records): (Vec<_>, Vec<_>) = other_records
|
||||
let rrsig_records: Vec<_> = other_records
|
||||
.into_iter()
|
||||
.partition(|r| r.record_type() == RecordType::RRSIG);
|
||||
.filter_map(|r| Record::<RRSIG>::try_from(r).ok())
|
||||
.collect();
|
||||
|
||||
assert!(!rrsig_records.is_empty());
|
||||
verify(&a_records, &rrsig_records, keys);
|
||||
@ -71,9 +78,10 @@ pub fn test_soa<A: Authority<Lookup = AuthLookup>>(authority: A, keys: &[DNSKEY]
|
||||
assert_eq!(604800, soa.expire());
|
||||
assert_eq!(86400, soa.minimum());
|
||||
|
||||
let (rrsig_records, _other_records): (Vec<_>, Vec<_>) = other_records
|
||||
let rrsig_records: Vec<_> = other_records
|
||||
.into_iter()
|
||||
.partition(|r| r.record_type() == RecordType::RRSIG);
|
||||
.filter_map(|r| Record::<RRSIG>::try_from(r).ok())
|
||||
.collect();
|
||||
|
||||
assert!(!rrsig_records.is_empty());
|
||||
verify(&soa_records, &rrsig_records, keys);
|
||||
@ -100,9 +108,10 @@ pub fn test_ns<A: Authority<Lookup = AuthLookup>>(authority: A, keys: &[DNSKEY])
|
||||
Name::from_str("bbb.example.com.").unwrap()
|
||||
);
|
||||
|
||||
let (rrsig_records, _other_records): (Vec<_>, Vec<_>) = other_records
|
||||
let rrsig_records: Vec<_> = other_records
|
||||
.into_iter()
|
||||
.partition(|r| r.record_type() == RecordType::RRSIG);
|
||||
.filter_map(|r| Record::<RRSIG>::try_from(r).ok())
|
||||
.collect();
|
||||
|
||||
assert!(!rrsig_records.is_empty());
|
||||
verify(&ns_records, &rrsig_records, keys);
|
||||
@ -132,9 +141,10 @@ pub fn test_aname_lookup<A: Authority<Lookup = AuthLookup>>(authority: A, keys:
|
||||
.cloned()
|
||||
.partition(|r| r.record_type() == RecordType::A);
|
||||
|
||||
let (rrsig_records, _other_records): (Vec<_>, Vec<_>) = other_records
|
||||
let rrsig_records: Vec<_> = other_records
|
||||
.into_iter()
|
||||
.partition(|r| r.record_type() == RecordType::RRSIG);
|
||||
.filter_map(|r| Record::<RRSIG>::try_from(r).ok())
|
||||
.collect();
|
||||
|
||||
assert!(!rrsig_records.is_empty());
|
||||
verify(&a_records, &rrsig_records, keys);
|
||||
@ -169,9 +179,10 @@ pub fn test_wildcard<A: Authority<Lookup = AuthLookup>>(authority: A, keys: &[DN
|
||||
.iter()
|
||||
.all(|r| *r.name() == Name::from_str("www.wildcard.example.com.").unwrap()));
|
||||
|
||||
let (rrsig_records, _other_records): (Vec<_>, Vec<_>) = other_records
|
||||
let rrsig_records: Vec<_> = other_records
|
||||
.into_iter()
|
||||
.partition(|r| r.record_type() == RecordType::RRSIG);
|
||||
.filter_map(|r| Record::<RRSIG>::try_from(r).ok())
|
||||
.collect();
|
||||
|
||||
assert!(!rrsig_records.is_empty());
|
||||
verify(&cname_records, &rrsig_records, keys);
|
||||
@ -331,16 +342,17 @@ pub fn test_rfc_6975_supported_algorithms<A: Authority<Lookup = AuthLookup>>(
|
||||
.cloned()
|
||||
.partition(|r| r.record_type() == RecordType::A);
|
||||
|
||||
let (rrsig_records, _other_records): (Vec<_>, Vec<_>) = other_records
|
||||
let rrsig_records: Vec<_> = other_records
|
||||
.into_iter()
|
||||
.partition(|r| r.record_type() == RecordType::RRSIG);
|
||||
.filter_map(|r| Record::<RRSIG>::try_from(r).ok())
|
||||
.collect();
|
||||
|
||||
assert!(!rrsig_records.is_empty());
|
||||
verify(&a_records, &rrsig_records, &[key.clone()]);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify(records: &[Record], rrsig_records: &[Record], keys: &[DNSKEY]) {
|
||||
pub fn verify(records: &[Record], rrsig_records: &[Record<RRSIG>], keys: &[DNSKEY]) {
|
||||
let record_name = records.first().unwrap().name();
|
||||
let record_type = records.first().unwrap().record_type();
|
||||
println!("record_name: {record_name}, type: {record_type}");
|
||||
@ -348,19 +360,8 @@ pub fn verify(records: &[Record], rrsig_records: &[Record], keys: &[DNSKEY]) {
|
||||
// should be signed with all the keys
|
||||
assert!(keys.iter().all(|key| rrsig_records
|
||||
.iter()
|
||||
.filter_map(|rrsig| {
|
||||
let rrsig = rrsig
|
||||
.data()
|
||||
.and_then(RData::as_dnssec)
|
||||
.expect("not DNSSEC")
|
||||
.as_sig()
|
||||
.expect("not RRSIG");
|
||||
if rrsig.algorithm() == key.algorithm() {
|
||||
Some(rrsig)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter_map(|rrsig| rrsig.data())
|
||||
.filter(|rrsig| rrsig.algorithm() == key.algorithm())
|
||||
.filter(|rrsig| rrsig.key_tag() == key.calculate_key_tag().unwrap())
|
||||
.filter(|rrsig| rrsig.type_covered() == record_type)
|
||||
.any(|rrsig| key
|
||||
|
@ -961,13 +961,11 @@ async fn test_zone_signing() {
|
||||
assert!(
|
||||
inner_results
|
||||
.iter()
|
||||
.any(|r| r.record_type() == RecordType::RRSIG
|
||||
&& r.name() == record.name()
|
||||
&& if let RData::DNSSEC(DNSSECRData::SIG(ref rrsig)) = *r.data().unwrap() {
|
||||
rrsig.type_covered() == record.record_type()
|
||||
} else {
|
||||
false
|
||||
}),
|
||||
.filter(|r| r.record_type() == RecordType::RRSIG)
|
||||
.filter(|r| r.name() == record.name())
|
||||
.filter_map(|r| r.data())
|
||||
.filter_map(|r| RRSIG::try_borrow(r).ok())
|
||||
.any(|rrsig| rrsig.type_covered() == record.record_type()),
|
||||
"record type not covered: {:?}",
|
||||
record
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user