Skip to content

Commit cfab556

Browse files
MartBdjc
authored andcommitted
proto: ignore RRSIGs in DnssecSummary::from_records
Since 56abc2e only the RRSIG used for verification gets the RRset's proof, any other RRSIG stays Indeterminate. The summary treated those as not secure, so the server never set the AD bit for zones signed with more than one algorithm.
1 parent 819a6bc commit cfab556

1 file changed

Lines changed: 122 additions & 2 deletions

File tree

‎crates/proto/src/dnssec/mod.rs‎

Lines changed: 122 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use thiserror::Error;
1717

1818
use crate::dnssec::crypto::Digest;
1919
use crate::error::ProtoError;
20-
use crate::rr::{Name, RData, Record, rdata::tsig::TsigAlgorithm};
20+
use crate::rr::{Name, RData, Record, RecordType, rdata::tsig::TsigAlgorithm};
2121
use crate::serialize::binary::{BinEncodable, BinEncoder, DecodeError, NameEncoding};
2222

2323
mod algorithm;
@@ -384,7 +384,7 @@ impl Clone for DnsSecError {
384384
}
385385

386386
/// DNSSEC status of an answer
387-
#[derive(Clone, Copy, Debug)]
387+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
388388
pub enum DnssecSummary {
389389
/// All records have been DNSSEC validated
390390
Secure,
@@ -396,9 +396,15 @@ pub enum DnssecSummary {
396396

397397
impl DnssecSummary {
398398
/// Whether the records have been DNSSEC validated or not
399+
///
400+
/// RRSIGs are skipped, since only the RRSIG used for verification carries the RRset's proof.
399401
pub fn from_records<'a>(records: impl Iterator<Item = &'a Record>) -> Self {
400402
let mut all_secure = None;
401403
for record in records {
404+
if record.record_type() == RecordType::RRSIG {
405+
continue;
406+
}
407+
402408
match &record.proof {
403409
Proof::Secure => {
404410
all_secure.get_or_insert(true);
@@ -514,3 +520,117 @@ mod test_utils {
514520
);
515521
}
516522
}
523+
524+
#[cfg(test)]
525+
mod tests {
526+
use alloc::vec;
527+
use core::net::Ipv4Addr;
528+
529+
use super::rdata::{DNSSECRData, RRSIG, SigInput};
530+
use super::*;
531+
use crate::rr::SerialNumber;
532+
533+
fn a_record(name: &Name, proof: Proof) -> Record {
534+
let mut record = Record::from_rdata(
535+
name.clone(),
536+
3600,
537+
RData::A(Ipv4Addr::new(192, 0, 2, 1).into()),
538+
);
539+
record.proof = proof;
540+
record
541+
}
542+
543+
fn rrsig_record(name: &Name, algorithm: Algorithm, proof: Proof) -> Record {
544+
let input = SigInput {
545+
type_covered: RecordType::A,
546+
algorithm,
547+
num_labels: 2,
548+
original_ttl: 3600,
549+
sig_expiration: SerialNumber(0),
550+
sig_inception: SerialNumber(0),
551+
key_tag: 0,
552+
signer_name: Name::root(),
553+
};
554+
let mut record = Record::from_rdata(
555+
name.clone(),
556+
3600,
557+
RData::DNSSEC(DNSSECRData::RRSIG(RRSIG::from_sig(input, vec![]))),
558+
);
559+
record.proof = proof;
560+
record
561+
}
562+
563+
/// Only the RRSIG used for verification is marked, the other one stays Indeterminate.
564+
#[test]
565+
fn summary_ignores_unused_rrsig() {
566+
let name = Name::from_ascii("www.example.").unwrap();
567+
let records = [
568+
a_record(&name, Proof::Secure),
569+
rrsig_record(&name, Algorithm::ECDSAP256SHA256, Proof::Secure),
570+
rrsig_record(&name, Algorithm::RSASHA256, Proof::Indeterminate),
571+
];
572+
573+
assert_eq!(
574+
DnssecSummary::from_records(records.iter()),
575+
DnssecSummary::Secure
576+
);
577+
}
578+
579+
#[test]
580+
fn summary_follows_rrset_proof() {
581+
let name = Name::from_ascii("www.example.").unwrap();
582+
for (proof, expected) in [
583+
(Proof::Secure, DnssecSummary::Secure),
584+
(Proof::Insecure, DnssecSummary::Insecure),
585+
(Proof::Indeterminate, DnssecSummary::Insecure),
586+
(Proof::Bogus, DnssecSummary::Bogus),
587+
] {
588+
let records = [
589+
a_record(&name, proof),
590+
rrsig_record(&name, Algorithm::ECDSAP256SHA256, proof),
591+
];
592+
assert_eq!(DnssecSummary::from_records(records.iter()), expected);
593+
}
594+
}
595+
596+
/// The proof of an RRSIG must not override the proof of the records it covers.
597+
#[test]
598+
fn summary_ignores_rrsig_proof() {
599+
let name = Name::from_ascii("www.example.").unwrap();
600+
let records = [
601+
a_record(&name, Proof::Bogus),
602+
rrsig_record(&name, Algorithm::ECDSAP256SHA256, Proof::Secure),
603+
];
604+
assert_eq!(
605+
DnssecSummary::from_records(records.iter()),
606+
DnssecSummary::Bogus
607+
);
608+
609+
let records = [
610+
a_record(&name, Proof::Insecure),
611+
rrsig_record(&name, Algorithm::ECDSAP256SHA256, Proof::Secure),
612+
];
613+
assert_eq!(
614+
DnssecSummary::from_records(records.iter()),
615+
DnssecSummary::Insecure
616+
);
617+
}
618+
619+
#[test]
620+
fn summary_of_rrsigs_only_is_insecure() {
621+
let name = Name::from_ascii("www.example.").unwrap();
622+
let records = [rrsig_record(
623+
&name,
624+
Algorithm::ECDSAP256SHA256,
625+
Proof::Secure,
626+
)];
627+
assert_eq!(
628+
DnssecSummary::from_records(records.iter()),
629+
DnssecSummary::Insecure
630+
);
631+
assert_eq!(
632+
DnssecSummary::from_records([].iter()),
633+
DnssecSummary::Insecure
634+
);
635+
}
636+
}

0 commit comments

Comments
 (0)