use crate::rr::*;
use crate::ser::*;
+use crate::MAX_PROOF_STEPS;
// In testing use a rather small buffer to ensure we hit the allocation paths sometimes. In
// production, we should generally never actually need to go to heap as DNS messages are rarely
let _ = builder.finish_proof();
}
-const MAX_REQUESTS: usize = 10;
/// A simple state machine which will generate a series of queries and process the responses until
/// it has built a DNSSEC proof.
///
(ProofBuilder {
proof: Vec::new(),
min_ttl: u32::MAX,
- dnskeys_requested: Vec::with_capacity(MAX_REQUESTS),
+ dnskeys_requested: Vec::with_capacity(MAX_PROOF_STEPS),
pending_queries: 1,
queries_made: 1,
}, initial_query)
/// [`Self::process_response`]. Once this returns false, [`Self::finish_proof`] should be used
/// to (possibly) get the final proof.
pub fn awaiting_responses(&self) -> bool {
- self.pending_queries > 0 && self.queries_made <= MAX_REQUESTS
+ self.pending_queries > 0 && self.queries_made <= MAX_PROOF_STEPS
}
/// Processes a query response from the recursive resolver, returning a list of new queries to
}
}
}
- if self.queries_made <= MAX_REQUESTS {
+ if self.queries_made <= MAX_PROOF_STEPS {
Ok(new_queries)
} else {
Ok(Vec::new())
/// used to cache the proof (i.e. the lowest TTL of all records which were used to build the
/// proof).
pub fn finish_proof(self) -> Result<(Vec<u8>, u32), ()> {
- if self.pending_queries > 0 || self.queries_made > MAX_REQUESTS {
+ if self.pending_queries > 0 || self.queries_made > MAX_PROOF_STEPS {
Err(())
} else {
Ok((self.proof, self.min_ttl))
use crate::crypto;
use crate::rr::*;
use crate::ser::write_name;
+use crate::MAX_PROOF_STEPS;
/// Gets the trusted root anchors
///
UnsupportedAlgorithm,
/// The provided data was invalid or signatures did not validate.
Invalid,
+ /// We would need to validate more than [`MAX_PROOF_STEPS`] sets of [`RRSig`]s to validate the
+ /// proof we were given.
+ ValidationCountLimited,
}
fn verify_rrsig<'a, RR: WriteableRecord, Keys>(sig: &RRSig, dnskeys: Keys, mut records: Vec<&RR>)
// no more, return UnsupportedAlgorithm
found_unsupported_alg = true;
},
+ Err(ValidationError::ValidationCountLimited) => {
+ debug_assert!(false, "verify_rrsig doesn't internally limit");
+ return Err(ValidationError::ValidationCountLimited);
+ },
Err(ValidationError::Invalid) => {
// If a signature is invalid, just immediately fail, avoiding KeyTrap issues.
return Err(ValidationError::Invalid);
let mut latest_inception = 0;
let mut earliest_expiry = u64::MAX;
let mut min_ttl = u32::MAX;
+ let mut rrsig_sets_validated = 0;
'next_zone: while zone == "." || !pending_ds_sets.is_empty() {
let next_ds_set;
if let Some((next_zone, ds_set)) = pending_ds_sets.pop() {
next_ds_set = None;
}
+ rrsig_sets_validated += 1;
+ if rrsig_sets_validated > MAX_PROOF_STEPS {
+ return Err(ValidationError::ValidationCountLimited);
+ }
+
let dnskey_rrsigs = inp.iter()
.filter_map(|rr| if let RR::RRSig(sig) = rr { Some(sig) } else { None })
.filter(|rrsig| rrsig.name.as_str() == zone && rrsig.ty == DnsKey::TYPE);
latest_inception = cmp::max(latest_inception, resolve_time(verified_dnskey_rrsig.inception));
earliest_expiry = cmp::min(earliest_expiry, resolve_time(verified_dnskey_rrsig.expiration));
min_ttl = cmp::min(min_ttl, verified_dnskey_rrsig.orig_ttl);
+
for rrsig in inp.iter()
.filter_map(|rr| if let RR::RRSig(sig) = rr { Some(sig) } else { None })
.filter(move |rrsig| rrsig.key_name.as_str() == zone && rrsig.ty != DnsKey::TYPE)
{
+ rrsig_sets_validated += 1;
+ if rrsig_sets_validated > MAX_PROOF_STEPS {
+ return Err(ValidationError::ValidationCountLimited);
+ }
+
if !rrsig.name.ends_with(zone) { return Err(ValidationError::Invalid); }
let signed_records = inp.iter()
.filter(|rr| rr.name() == &rrsig.name && rr.ty() == rrsig.ty);
match verify_rrsig(rrsig, dnskeys.clone(), signed_records.clone().collect()) {
Ok(()) => {},
Err(ValidationError::UnsupportedAlgorithm) => continue,
+ Err(ValidationError::ValidationCountLimited) => {
+ debug_assert!(false, "verify_rrsig doesn't internally limit");
+ return Err(ValidationError::ValidationCountLimited);
+ },
Err(ValidationError::Invalid) => {
// If a signature is invalid, just immediately fail, avoiding KeyTrap issues.
return Err(ValidationError::Invalid);