Skip to content
This repository has been archived by the owner on Jun 7, 2024. It is now read-only.

Commit

Permalink
test a bogus DNSSEC scenario
Browse files Browse the repository at this point in the history
  • Loading branch information
japaric committed Feb 20, 2024
1 parent 6aaa994 commit 8c879cd
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/conformance-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ publish = false
version = "0.1.0"

[dependencies]
base64 = "0.21.7"
dns-test.path = "../dns-test"

[lib]
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
mod bogus;
mod secure;
92 changes: 92 additions & 0 deletions packages/conformance-tests/src/resolver/dnssec/scenarios/bogus.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use std::net::Ipv4Addr;

use base64::prelude::*;
use dns_test::client::{Client, DigSettings};
use dns_test::name_server::NameServer;
use dns_test::record::{Record, RecordType};
use dns_test::zone_file::Root;
use dns_test::{Network, Resolver, Result, TrustAnchor, FQDN};

#[ignore]
#[test]
fn bad_signature_in_leaf_nameserver() -> Result<()> {
let expected_ipv4_addr = Ipv4Addr::new(1, 2, 3, 4);
let needle_fqdn = FQDN("example.nameservers.com.")?;

let network = Network::new()?;
let mut root_ns = NameServer::new(FQDN::ROOT, &network)?;
let mut com_ns = NameServer::new(FQDN::COM, &network)?;

let mut nameservers_ns = NameServer::new(FQDN("nameservers.com.")?, &network)?;
nameservers_ns
.add(Record::a(root_ns.fqdn().clone(), root_ns.ipv4_addr()))
.add(Record::a(com_ns.fqdn().clone(), com_ns.ipv4_addr()))
.add(Record::a(needle_fqdn.clone(), expected_ipv4_addr));
let mut nameservers_ns = nameservers_ns.sign()?;

// fault injection: change the signature field of the RRSIG that covers the A record we'll query
let mut modified = 0;
for record in &mut nameservers_ns.signed_zone_file_mut().records {
if let Record::RRSIG(rrsig) = record {
if rrsig.fqdn == needle_fqdn {
let mut signature = BASE64_STANDARD.decode(&rrsig.signature)?;
let last = signature.last_mut().expect("empty signature");
*last = !*last;

rrsig.signature = BASE64_STANDARD.encode(&signature);
modified += 1;
}
}
}
assert_eq!(modified, 1, "sanity check");

let nameservers_ds = nameservers_ns.ds().clone();
let nameservers_ns = nameservers_ns.start()?;

com_ns
.referral(
nameservers_ns.zone().clone(),
nameservers_ns.fqdn().clone(),
nameservers_ns.ipv4_addr(),
)
.add(nameservers_ds);
let com_ns = com_ns.sign()?;
let com_ds = com_ns.ds().clone();
let com_ns = com_ns.start()?;

root_ns
.referral(FQDN::COM, com_ns.fqdn().clone(), com_ns.ipv4_addr())
.add(com_ds);
let root_ns = root_ns.sign()?;
let root_ksk = root_ns.key_signing_key().clone();
let root_zsk = root_ns.zone_signing_key().clone();

let root_ns = root_ns.start()?;

let roots = &[Root::new(root_ns.fqdn().clone(), root_ns.ipv4_addr())];

let trust_anchor = TrustAnchor::from_iter([root_ksk.clone(), root_zsk.clone()]);
let resolver = Resolver::start(dns_test::subject(), roots, &trust_anchor, &network)?;
let resolver_addr = resolver.ipv4_addr();

let client = Client::new(&network)?;

let mut settings = *DigSettings::default().recurse().authentic_data();
let output = client.dig(settings, resolver_addr, RecordType::A, &needle_fqdn)?;

// the resolver will try to validate the chain of trust; the validation fails so it responds
// with SERVFAIL
assert!(output.status.is_servfail());

// avoids a SERVFAIL response
settings.checking_disabled();

let output = client.dig(settings, resolver_addr, RecordType::A, &needle_fqdn)?;

// when the CD (Checking Disabled) bit is set the server won't respond with SERVFAIL on
// validation errors. the outcome of the validation process is reported in the AD bit
assert!(output.status.is_noerror());
assert!(!output.flags.authenticated_data);

Ok(())
}

0 comments on commit 8c879cd

Please sign in to comment.