trust_dns_proto/xfer/dnssec_dns_handle.rs
1// Copyright 2015-2023 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! The `DnssecDnsHandle` is used to validate all DNS responses for correct DNSSEC signatures.
9
10use std::{clone::Clone, collections::HashSet, error::Error, pin::Pin, sync::Arc};
11
12use futures_util::{
13 future::{self, Future, FutureExt, TryFutureExt},
14 stream::{self, Stream, TryStreamExt},
15};
16use tracing::{debug, trace};
17
18use crate::{
19 error::{ProtoError, ProtoErrorKind, ProtoResult},
20 op::{Edns, OpCode, Query},
21 rr::{
22 dnssec::{
23 rdata::{DNSSECRData, DNSKEY, RRSIG},
24 Algorithm, SupportedAlgorithms, TrustAnchor,
25 },
26 rdata::opt::EdnsOption,
27 DNSClass, Name, RData, Record, RecordData, RecordType,
28 },
29 xfer::{dns_handle::DnsHandle, DnsRequest, DnsRequestOptions, DnsResponse, FirstAnswer},
30};
31
32#[cfg(feature = "dnssec")]
33use crate::rr::dnssec::Verifier;
34
35#[derive(Debug)]
36struct Rrset {
37 pub(crate) name: Name,
38 pub(crate) record_type: RecordType,
39 pub(crate) record_class: DNSClass,
40 pub(crate) records: Vec<Record>,
41}
42
43/// Performs DNSSEC validation of all DNS responses from the wrapped DnsHandle
44///
45/// This wraps a DnsHandle, changing the implementation `send()` to validate all
46/// message responses for Query operations. Update operation responses are not validated by
47/// this process.
48#[derive(Clone)]
49#[must_use = "queries can only be sent through a DnsHandle"]
50pub struct DnssecDnsHandle<H>
51where
52 H: DnsHandle + Unpin + 'static,
53{
54 handle: H,
55 trust_anchor: Arc<TrustAnchor>,
56 request_depth: usize,
57 minimum_key_len: usize,
58 minimum_algorithm: Algorithm, // used to prevent down grade attacks...
59}
60
61impl<H> DnssecDnsHandle<H>
62where
63 H: DnsHandle + Unpin + 'static,
64{
65 /// Create a new DnssecDnsHandle wrapping the specified handle.
66 ///
67 /// This uses the compiled in TrustAnchor default trusted keys.
68 ///
69 /// # Arguments
70 /// * `handle` - handle to use for all connections to a remote server.
71 pub fn new(handle: H) -> Self {
72 Self::with_trust_anchor(handle, TrustAnchor::default())
73 }
74
75 /// Create a new DnssecDnsHandle wrapping the specified handle.
76 ///
77 /// This allows a custom TrustAnchor to be define.
78 ///
79 /// # Arguments
80 /// * `handle` - handle to use for all connections to a remote server.
81 /// * `trust_anchor` - custom DNSKEYs that will be trusted, can be used to pin trusted keys.
82 pub fn with_trust_anchor(handle: H, trust_anchor: TrustAnchor) -> Self {
83 Self {
84 handle,
85 trust_anchor: Arc::new(trust_anchor),
86 request_depth: 0,
87 minimum_key_len: 0,
88 minimum_algorithm: Algorithm::RSASHA256,
89 }
90 }
91
92 /// An internal function used to clone the handle, but maintain some information back to the
93 /// original handle, such as the request_depth such that infinite recursion does
94 /// not occur.
95 fn clone_with_context(&self) -> Self {
96 Self {
97 handle: self.handle.clone(),
98 trust_anchor: Arc::clone(&self.trust_anchor),
99 request_depth: self.request_depth + 1,
100 minimum_key_len: self.minimum_key_len,
101 minimum_algorithm: self.minimum_algorithm,
102 }
103 }
104}
105
106impl<H> DnsHandle for DnssecDnsHandle<H>
107where
108 H: DnsHandle + Sync + Unpin,
109{
110 type Response = Pin<Box<dyn Stream<Item = Result<DnsResponse, Self::Error>> + Send>>;
111 type Error = <H as DnsHandle>::Error;
112
113 fn is_verifying_dnssec(&self) -> bool {
114 // This handler is always verifying...
115 true
116 }
117
118 fn send<R: Into<DnsRequest>>(&mut self, request: R) -> Self::Response {
119 let mut request = request.into();
120
121 // backstop
122 if self.request_depth > request.options().max_request_depth {
123 return Box::pin(stream::once(future::err(Self::Error::from(
124 ProtoError::from("exceeded max validation depth"),
125 ))));
126 }
127
128 // dnssec only matters on queries.
129 if let OpCode::Query = request.op_code() {
130 // This will panic on no queries, that is a very odd type of request, isn't it?
131 // TODO: with mDNS there can be multiple queries
132 let query = request
133 .queries()
134 .first()
135 .cloned()
136 .expect("no queries in request");
137 let handle: Self = self.clone_with_context();
138
139 // TODO: cache response of the server about understood algorithms
140 #[cfg(feature = "dnssec")]
141 {
142 let edns = request.extensions_mut().get_or_insert_with(Edns::new);
143 edns.set_dnssec_ok(true);
144
145 // send along the algorithms which are supported by this handle
146 let mut algorithms = SupportedAlgorithms::new();
147 #[cfg(feature = "ring")]
148 {
149 algorithms.set(Algorithm::ED25519);
150 }
151 algorithms.set(Algorithm::ECDSAP256SHA256);
152 algorithms.set(Algorithm::ECDSAP384SHA384);
153 algorithms.set(Algorithm::RSASHA256);
154
155 let dau = EdnsOption::DAU(algorithms);
156 let dhu = EdnsOption::DHU(algorithms);
157
158 edns.options_mut().insert(dau);
159 edns.options_mut().insert(dhu);
160 }
161
162 request.set_authentic_data(true);
163 request.set_checking_disabled(false);
164 let dns_class = request
165 .queries()
166 .first()
167 .map_or(DNSClass::IN, Query::query_class);
168 let options = *request.options();
169
170 return Box::pin(
171 self.handle
172 .send(request)
173 .and_then(move |message_response| {
174 // group the record sets by name and type
175 // each rrset type needs to validated independently
176 debug!(
177 "validating message_response: {}, with {} trust_anchors",
178 message_response.id(),
179 handle.trust_anchor.len(),
180 );
181 verify_rrsets(handle.clone(), message_response, dns_class, options)
182 })
183 .and_then(move |verified_message| {
184 // at this point all of the message is verified.
185 // This is where NSEC (and possibly NSEC3) validation occurs
186 // As of now, only NSEC is supported.
187 if verified_message.answers().is_empty() {
188 // get SOA name
189 let soa_name = if let Some(soa_name) = verified_message
190 .name_servers()
191 .iter()
192 // there should only be one
193 .find(|rr| rr.record_type() == RecordType::SOA)
194 .map(Record::name)
195 {
196 soa_name
197 } else {
198 return future::err(Self::Error::from(ProtoError::from(
199 "could not validate negative response missing SOA",
200 )));
201 };
202
203 let nsecs = verified_message
204 .name_servers()
205 .iter()
206 .filter(|rr| is_dnssec(rr, RecordType::NSEC))
207 .collect::<Vec<_>>();
208
209 if !verify_nsec(&query, soa_name, nsecs.as_slice()) {
210 // TODO change this to remove the NSECs, like we do for the others?
211 return future::err(Self::Error::from(ProtoError::from(
212 "could not validate negative response with NSEC",
213 )));
214 }
215 }
216
217 future::ok(verified_message)
218 }),
219 );
220 }
221
222 Box::pin(self.handle.send(request))
223 }
224}
225
226/// this pulls all records returned in a Message response and returns a future which will
227/// validate all of them.
228#[allow(clippy::type_complexity)]
229async fn verify_rrsets<H, E>(
230 handle: DnssecDnsHandle<H>,
231 message_result: DnsResponse,
232 dns_class: DNSClass,
233 options: DnsRequestOptions,
234) -> Result<DnsResponse, E>
235where
236 H: DnsHandle<Error = E> + Sync + Unpin,
237 E: From<ProtoError> + Error + Clone + Send + Unpin + 'static,
238{
239 let mut rrset_types: HashSet<(Name, RecordType)> = HashSet::new();
240 for rrset in message_result
241 .answers()
242 .iter()
243 .chain(message_result.name_servers())
244 .filter(|rr| {
245 !is_dnssec(rr, RecordType::RRSIG) &&
246 // if we are at a depth greater than 1, we are only interested in proving evaluation chains
247 // this means that only DNSKEY and DS are interesting at that point.
248 // this protects against looping over things like NS records and DNSKEYs in responses.
249 // TODO: is there a cleaner way to prevent cycles in the evaluations?
250 (handle.request_depth <= 1 ||
251 is_dnssec(rr, RecordType::DNSKEY) ||
252 is_dnssec(rr, RecordType::DS))
253 })
254 .map(|rr| (rr.name().clone(), rr.record_type()))
255 {
256 rrset_types.insert(rrset);
257 }
258
259 // there was no data returned in that message
260 if rrset_types.is_empty() {
261 let mut message_result = message_result.into_message();
262
263 // there were no returned results, double check by dropping all the results
264 message_result.take_answers();
265 message_result.take_name_servers();
266 message_result.take_additionals();
267
268 return Err(E::from(ProtoError::from(ProtoErrorKind::Message(
269 "no results to verify",
270 ))));
271 }
272
273 // collect all the rrsets to verify
274 // TODO: is there a way to get rid of this clone() safely?
275 let mut rrsets_to_verify = Vec::with_capacity(rrset_types.len());
276 for (name, record_type) in rrset_types {
277 // TODO: should we evaluate the different sections (answers and name_servers) separately?
278 let records: Vec<Record> = message_result
279 .answers()
280 .iter()
281 .chain(message_result.name_servers())
282 .chain(message_result.additionals())
283 .filter(|rr| rr.record_type() == record_type && rr.name() == &name)
284 .cloned()
285 .collect();
286
287 let rrsigs: Vec<Record<RRSIG>> = message_result
288 .answers()
289 .iter()
290 .chain(message_result.name_servers())
291 .chain(message_result.additionals())
292 .filter(|rr| is_dnssec(rr, RecordType::RRSIG))
293 .filter(|rr| {
294 if let Some(RData::DNSSEC(DNSSECRData::RRSIG(ref rrsig))) = rr.data() {
295 rrsig.type_covered() == record_type
296 } else {
297 false
298 }
299 })
300 .cloned()
301 .map(|rr| Record::<RRSIG>::try_from(rr).expect("the record type was checked above"))
302 .collect();
303
304 // if there is already an active validation going on, assume the other validation will
305 // complete properly or error if it is invalid
306 let rrset = Rrset {
307 name,
308 record_type,
309 record_class: dns_class,
310 records,
311 };
312
313 // TODO: support non-IN classes?
314 debug!(
315 "verifying: {}, record_type: {:?}, rrsigs: {}",
316 rrset.name,
317 record_type,
318 rrsigs.len()
319 );
320 rrsets_to_verify
321 .push(verify_rrset(handle.clone_with_context(), rrset, rrsigs, options).boxed());
322 }
323
324 // spawn a select_all over this vec, these are the individual RRSet validators
325 verify_all_rrsets(message_result, rrsets_to_verify).await
326}
327
328// TODO: is this method useful/necessary?
329fn is_dnssec<D: RecordData>(rr: &Record<D>, dnssec_type: RecordType) -> bool {
330 rr.record_type().is_dnssec() && dnssec_type.is_dnssec() && rr.record_type() == dnssec_type
331}
332
333async fn verify_all_rrsets<F, E>(
334 message_result: DnsResponse,
335 rrsets: Vec<F>,
336) -> Result<DnsResponse, E>
337where
338 F: Future<Output = Result<Rrset, E>> + Send + Unpin,
339 E: From<ProtoError> + Error + Clone + Send + Unpin + 'static,
340{
341 let mut verified_rrsets: HashSet<(Name, RecordType)> = HashSet::new();
342 let mut rrsets = future::select_all(rrsets);
343 let mut last_validation_err: Option<E> = None;
344
345 // loop through all the rrset evaluations, filter all the rrsets in the Message
346 // down to just the ones that were able to be validated
347 loop {
348 let (rrset, _, remaining) = rrsets.await;
349 match rrset {
350 Ok(rrset) => {
351 debug!(
352 "an rrset was verified: {}, {:?}",
353 rrset.name, rrset.record_type
354 );
355 verified_rrsets.insert((rrset.name, rrset.record_type));
356 }
357 // TODO: should we return the Message on errors? Allow the consumer to decide what to do
358 // on a validation failure?
359 // any error, is an error for all
360 Err(e) => {
361 if tracing::enabled!(tracing::Level::DEBUG) {
362 let mut query = message_result
363 .queries()
364 .iter()
365 .map(|q| q.to_string())
366 .fold(String::new(), |s, q| format!("{q},{s}"));
367
368 query.truncate(query.len() - 1);
369 debug!("an rrset failed to verify ({}): {:?}", query, e);
370 }
371
372 last_validation_err = Some(e);
373 }
374 };
375
376 if !remaining.is_empty() {
377 // continue the evaluation
378 rrsets = future::select_all(remaining);
379 } else {
380 break;
381 }
382 }
383
384 // check if any are valid, otherwise return whatever error caused it to fail
385 if verified_rrsets.is_empty() && last_validation_err.is_some() {
386 return Err(last_validation_err.expect("can not be none based on above check"));
387 }
388
389 // validated not none above...
390 let (mut message_result, message_buffer) = message_result.into_parts();
391
392 // take all the rrsets from the Message, filter down each set to the validated rrsets
393 // TODO: does the section in the message matter here?
394 // we could probably end up with record_types in any section.
395 // track the section in the rrset evaluation?
396 let answers = message_result
397 .take_answers()
398 .into_iter()
399 .chain(message_result.take_additionals().into_iter())
400 .filter(|record| verified_rrsets.contains(&(record.name().clone(), record.record_type())))
401 .collect::<Vec<Record>>();
402
403 let name_servers = message_result
404 .take_name_servers()
405 .into_iter()
406 .filter(|record| verified_rrsets.contains(&(record.name().clone(), record.record_type())))
407 .collect::<Vec<Record>>();
408
409 let additionals = message_result
410 .take_additionals()
411 .into_iter()
412 .filter(|record| verified_rrsets.contains(&(record.name().clone(), record.record_type())))
413 .collect::<Vec<Record>>();
414
415 // add the filtered records back to the message
416 message_result.insert_answers(answers);
417 message_result.insert_name_servers(name_servers);
418 message_result.insert_additionals(additionals);
419
420 // breaks out of the loop... and returns the filtered Message.
421 Ok(DnsResponse::new(message_result, message_buffer))
422}
423
424/// Generic entrypoint to verify any RRSET against the provided signatures.
425///
426/// Generally, the RRSET will be validated by `verify_default_rrset()`. There are additional
427/// checks that happen after the RRSET is successfully validated. In the case of DNSKEYs this
428/// triggers `verify_dnskey_rrset()`. If it's an NSEC record, then the NSEC record will be
429/// validated to prove it's correctness. There is a special case for DNSKEY, where if the RRSET
430/// is unsigned, `rrsigs` is empty, then an immediate `verify_dnskey_rrset()` is triggered. In
431/// this case, it's possible the DNSKEY is a trust_anchor and is not self-signed.
432async fn verify_rrset<H, E>(
433 handle: DnssecDnsHandle<H>,
434 rrset: Rrset,
435 rrsigs: Vec<Record<RRSIG>>,
436 options: DnsRequestOptions,
437) -> Result<Rrset, E>
438where
439 H: DnsHandle<Error = E> + Sync + Unpin,
440 E: From<ProtoError> + Error + Clone + Send + Unpin + 'static,
441{
442 // Special case for unsigned DNSKEYs, it's valid for a DNSKEY to be bare in the zone if
443 // it's a trust_anchor, though some DNS servers choose to self-sign in this case,
444 // for self-signed KEYS they will drop through to the standard validation logic.
445 if let RecordType::DNSKEY = rrset.record_type {
446 if rrsigs.is_empty() {
447 debug!("unsigned key: {}, {:?}", rrset.name, rrset.record_type);
448 // TODO: validate that this DNSKEY is stronger than the one lower in the chain,
449 // also, set the min algorithm to this algorithm to prevent downgrade attacks.
450 return verify_dnskey_rrset(handle.clone_with_context(), rrset, options).await;
451 }
452 }
453
454 // standard validation path
455 let rrset = verify_default_rrset(&handle.clone_with_context(), rrset, rrsigs, options).await?;
456
457 // validation of DNSKEY records
458 match rrset.record_type {
459 RecordType::DNSKEY => verify_dnskey_rrset(handle, rrset, options).await,
460 _ => Ok(rrset),
461 }
462}
463
464/// Verifies a dnskey rrset
465///
466/// This first checks to see if the key is in the set of trust_anchors. If so then it's returned
467/// as a success. Otherwise, a query is sent to get the DS record, and the DNSKEY is validated
468/// against the DS record.
469async fn verify_dnskey_rrset<H, E>(
470 mut handle: DnssecDnsHandle<H>,
471 rrset: Rrset,
472 options: DnsRequestOptions,
473) -> Result<Rrset, E>
474where
475 H: DnsHandle<Error = E> + Sync + Unpin,
476 E: From<ProtoError> + Error + Clone + Send + Unpin + 'static,
477{
478 trace!(
479 "dnskey validation {}, record_type: {:?}",
480 rrset.name,
481 rrset.record_type
482 );
483
484 // check the DNSKEYS against the trust_anchor, if it's approved allow it.
485 {
486 let anchored_keys = rrset
487 .records
488 .iter()
489 .enumerate()
490 .filter(|&(_, rr)| is_dnssec(rr, RecordType::DNSKEY))
491 .filter_map(|(i, rr)| rr.data().map(|rr| (i, rr)))
492 .filter_map(|(i, rr)| DNSKEY::try_borrow(rr).map(|rr| (i, rr)))
493 .filter_map(|(i, rdata)| {
494 if handle
495 .trust_anchor
496 .contains_dnskey_bytes(rdata.public_key())
497 {
498 debug!(
499 "validated dnskey with trust_anchor: {}, {}",
500 rrset.name, rdata
501 );
502
503 Some(i)
504 } else {
505 None
506 }
507 })
508 .collect::<Vec<usize>>();
509
510 if !anchored_keys.is_empty() {
511 let mut rrset = rrset;
512 preserve(&mut rrset.records, anchored_keys);
513 return Ok(rrset);
514 }
515 }
516
517 // need to get DS records for each DNSKEY
518 let ds_message = handle
519 .lookup(Query::query(rrset.name.clone(), RecordType::DS), options)
520 .first_answer()
521 .await?;
522 let valid_keys = rrset
523 .records
524 .iter()
525 .enumerate()
526 .filter(|&(_, rr)| is_dnssec(rr, RecordType::DNSKEY))
527 .filter_map(|(i, rr)| {
528 if let Some(RData::DNSSEC(DNSSECRData::DNSKEY(ref rdata))) = rr.data() {
529 Some((i, rdata))
530 } else {
531 None
532 }
533 })
534 .filter(|&(_, key_rdata)| {
535 ds_message
536 .answers()
537 .iter()
538 .filter(|ds| is_dnssec(ds, RecordType::DS))
539 .filter_map(|ds| {
540 if let Some(RData::DNSSEC(DNSSECRData::DS(ref ds_rdata))) = ds.data() {
541 Some((ds.name(), ds_rdata))
542 } else {
543 None
544 }
545 })
546 // must be covered by at least one DS record
547 .any(|(ds_name, ds_rdata)| {
548 if ds_rdata.covers(&rrset.name, key_rdata).unwrap_or(false) {
549 debug!(
550 "validated dnskey ({}, {}) with {} {}",
551 rrset.name, key_rdata, ds_name, ds_rdata
552 );
553
554 true
555 } else {
556 false
557 }
558 })
559 })
560 .map(|(i, _)| i)
561 .collect::<Vec<usize>>();
562
563 if !valid_keys.is_empty() {
564 let mut rrset = rrset;
565 preserve(&mut rrset.records, valid_keys);
566
567 trace!("validated dnskey: {}", rrset.name);
568 Ok(rrset)
569 } else {
570 Err(E::from(ProtoError::from(ProtoErrorKind::Message(
571 "Could not validate all DNSKEYs",
572 ))))
573 }
574}
575
576/// Preserves the specified indexes in vec, all others will be removed
577///
578/// # Arguments
579///
580/// * `vec` - vec to mutate
581/// * `indexes` - ordered list of indexes to remove
582fn preserve<T, I>(vec: &mut Vec<T>, indexes: I)
583where
584 I: IntoIterator<Item = usize>,
585 <I as IntoIterator>::IntoIter: DoubleEndedIterator,
586{
587 // this removes all indexes that were not part of the anchored keys
588 let mut indexes_iter = indexes.into_iter().rev();
589 let mut i = indexes_iter.next();
590 for j in (0..vec.len()).rev() {
591 // check the next index to preserve
592 if i.map_or(false, |i| i > j) {
593 i = indexes_iter.next();
594 }
595 // if the key is not in the set of anchored_keys, remove it
596 if i.map_or(true, |i| i != j) {
597 vec.remove(j);
598 }
599 }
600}
601
602#[test]
603fn test_preserve() {
604 let mut vec = vec![1, 2, 3];
605 let indexes = vec![];
606 preserve(&mut vec, indexes);
607 assert_eq!(vec, vec![]);
608
609 let mut vec = vec![1, 2, 3];
610 let indexes = vec![0];
611 preserve(&mut vec, indexes);
612 assert_eq!(vec, vec![1]);
613
614 let mut vec = vec![1, 2, 3];
615 let indexes = vec![1];
616 preserve(&mut vec, indexes);
617 assert_eq!(vec, vec![2]);
618
619 let mut vec = vec![1, 2, 3];
620 let indexes = vec![2];
621 preserve(&mut vec, indexes);
622 assert_eq!(vec, vec![3]);
623
624 let mut vec = vec![1, 2, 3];
625 let indexes = vec![0, 2];
626 preserve(&mut vec, indexes);
627 assert_eq!(vec, vec![1, 3]);
628
629 let mut vec = vec![1, 2, 3];
630 let indexes = vec![0, 1, 2];
631 preserve(&mut vec, indexes);
632 assert_eq!(vec, vec![1, 2, 3]);
633}
634
635/// Verifies that a given RRSET is validly signed by any of the specified RRSIGs.
636///
637/// Invalid RRSIGs will be ignored. RRSIGs will only be validated against DNSKEYs which can
638/// be validated through a chain back to the `trust_anchor`. As long as one RRSIG is valid,
639/// then the RRSET will be valid.
640#[allow(clippy::blocks_in_if_conditions)]
641async fn verify_default_rrset<H, E>(
642 handle: &DnssecDnsHandle<H>,
643 rrset: Rrset,
644 rrsigs: Vec<Record<RRSIG>>,
645 options: DnsRequestOptions,
646) -> Result<Rrset, E>
647where
648 H: DnsHandle<Error = E> + Sync + Unpin,
649 E: From<ProtoError> + Error + Clone + Send + Unpin + 'static,
650{
651 // the record set is going to be shared across a bunch of futures, Arc for that.
652 let rrset = Arc::new(rrset);
653 trace!(
654 "default validation {}, record_type: {:?}",
655 rrset.name,
656 rrset.record_type
657 );
658
659 // Special case for self-signed DNSKEYS, validate with itself...
660 if rrsigs
661 .iter()
662 .filter(|rrsig| is_dnssec(rrsig, RecordType::RRSIG))
663 .filter_map(|rrsig| rrsig.data())
664 .any(|rrsig| RecordType::DNSKEY == rrset.record_type && rrsig.signer_name() == &rrset.name)
665 {
666 // in this case it was looks like a self-signed key, first validate the signature
667 // then return rrset. Like the standard case below, the DNSKEY is validated
668 // after this function. This function is only responsible for validating the signature
669 // the DNSKey validation should come after, see verify_rrset().
670 return future::ready(
671 rrsigs
672 .into_iter()
673 // this filter is technically unnecessary, can probably remove it...
674 .filter(|rrsig| is_dnssec(rrsig, RecordType::RRSIG))
675 .filter_map(|rrsig| rrsig.into_data())
676 .filter_map(|sig| {
677 let rrset = Arc::clone(&rrset);
678
679 if rrset.records.iter().any(|r| {
680 if let Some(RData::DNSSEC(DNSSECRData::DNSKEY(ref dnskey))) = r.data() {
681 let dnskey_name = r.name();
682 verify_rrset_with_dnskey(dnskey_name, dnskey, &sig, &rrset).is_ok()
683 } else {
684 panic!("expected a DNSKEY here: {:?}", r.data());
685 }
686 }) {
687 Some(())
688 } else {
689 None
690 }
691 })
692 .next()
693 .ok_or_else(|| {
694 E::from(ProtoError::from(ProtoErrorKind::Message(
695 "self-signed dnskey is invalid",
696 )))
697 }),
698 )
699 .map_ok(move |_| Arc::try_unwrap(rrset).expect("unable to unwrap Arc"))
700 .await;
701 }
702
703 // we can validate with any of the rrsigs...
704 // i.e. the first that validates is good enough
705 // TODO: could there be a cert downgrade attack here with a MITM stripping stronger RRSIGs?
706 // we could check for the strongest RRSIG and only use that...
707 // though, since the entire package isn't signed any RRSIG could have been injected,
708 // right? meaning if there is an attack on any of the acceptable algorithms, we'd be
709 // susceptible until that algorithm is removed as an option.
710 // dns over TLS will mitigate this.
711 // TODO: strip RRSIGS to accepted algorithms and make algorithms configurable.
712 let verifications = rrsigs.into_iter()
713 // this filter is technically unnecessary, can probably remove it...
714 .filter(|rrsig| is_dnssec(rrsig, RecordType::RRSIG))
715 .filter_map(|rrsig|rrsig.into_data())
716 .map(|sig| {
717 let rrset = Arc::clone(&rrset);
718 let mut handle = handle.clone_with_context();
719
720 handle
721 .lookup(
722 Query::query(sig.signer_name().clone(), RecordType::DNSKEY),
723 options,
724 )
725 .first_answer()
726 .and_then(move |message|
727 // DNSKEYs are validated by the inner query
728 future::ready(message
729 .answers()
730 .iter()
731 .filter(|r| is_dnssec(r, RecordType::DNSKEY))
732 .filter_map(|r| r.data().map(|data| (r.name(), data)))
733 .filter_map(|(dnskey_name, data)|
734 DNSKEY::try_borrow(data).map(|data| (dnskey_name, data)))
735 .find(|(dnskey_name, dnskey)|
736 verify_rrset_with_dnskey(dnskey_name, dnskey, &sig, &rrset).is_ok()
737 )
738 .map(|_| ())
739 .ok_or_else(|| E::from(ProtoError::from(ProtoErrorKind::Message("validation failed")))))
740 )
741 })
742 .collect::<Vec<_>>();
743
744 // if there are no available verifications, then we are in a failed state.
745 if verifications.is_empty() {
746 return Err(E::from(ProtoError::from(
747 ProtoErrorKind::RrsigsNotPresent {
748 name: rrset.name.clone(),
749 record_type: rrset.record_type,
750 },
751 )));
752 }
753
754 // as long as any of the verifications is good, then the RRSET is valid.
755 let select = future::select_ok(verifications)
756 // getting here means at least one of the rrsigs succeeded...
757 .map_ok(move |((), rest)| {
758 drop(rest); // drop all others, should free up Arc
759 Arc::try_unwrap(rrset).expect("unable to unwrap Arc")
760 });
761
762 select.await
763}
764
765/// Verifies the given SIG of the RRSET with the DNSKEY.
766#[cfg(feature = "dnssec")]
767fn verify_rrset_with_dnskey(
768 dnskey_name: &Name,
769 dnskey: &DNSKEY,
770 sig: &RRSIG,
771 rrset: &Rrset,
772) -> ProtoResult<()> {
773 if dnskey.revoke() {
774 debug!("revoked");
775 return Err(ProtoErrorKind::Message("revoked").into());
776 } // TODO: does this need to be validated? RFC 5011
777 if !dnskey.zone_key() {
778 return Err(ProtoErrorKind::Message("is not a zone key").into());
779 }
780 if dnskey.algorithm() != sig.algorithm() {
781 return Err(ProtoErrorKind::Message("mismatched algorithm").into());
782 }
783
784 dnskey
785 .verify_rrsig(&rrset.name, rrset.record_class, sig, &rrset.records)
786 .map(|r| {
787 debug!(
788 "validated ({}, {:?}) with ({}, {})",
789 rrset.name, rrset.record_type, dnskey_name, dnskey
790 );
791 r
792 })
793 .map_err(Into::into)
794 .map_err(|e| {
795 debug!(
796 "failed validation of ({}, {:?}) with ({}, {})",
797 rrset.name, rrset.record_type, dnskey_name, dnskey
798 );
799 e
800 })
801}
802
803/// Will always return an error. To enable record verification compile with the openssl feature.
804#[cfg(not(feature = "dnssec"))]
805fn verify_rrset_with_dnskey(_: &DNSKEY, _: &RRSIG, _: &Rrset) -> ProtoResult<()> {
806 Err(ProtoErrorKind::Message("openssl or ring feature(s) not enabled").into())
807}
808
809/// Verifies NSEC records
810///
811/// ```text
812/// RFC 4035 DNSSEC Protocol Modifications March 2005
813///
814/// 5.4. Authenticated Denial of Existence
815///
816/// A resolver can use authenticated NSEC RRs to prove that an RRset is
817/// not present in a signed zone. Security-aware name servers should
818/// automatically include any necessary NSEC RRs for signed zones in
819/// their responses to security-aware resolvers.
820///
821/// Denial of existence is determined by the following rules:
822///
823/// o If the requested RR name matches the owner name of an
824/// authenticated NSEC RR, then the NSEC RR's type bit map field lists
825/// all RR types present at that owner name, and a resolver can prove
826/// that the requested RR type does not exist by checking for the RR
827/// type in the bit map. If the number of labels in an authenticated
828/// NSEC RR's owner name equals the Labels field of the covering RRSIG
829/// RR, then the existence of the NSEC RR proves that wildcard
830/// expansion could not have been used to match the request.
831///
832/// o If the requested RR name would appear after an authenticated NSEC
833/// RR's owner name and before the name listed in that NSEC RR's Next
834/// Domain Name field according to the canonical DNS name order
835/// defined in [RFC4034], then no RRsets with the requested name exist
836/// in the zone. However, it is possible that a wildcard could be
837/// used to match the requested RR owner name and type, so proving
838/// that the requested RRset does not exist also requires proving that
839/// no possible wildcard RRset exists that could have been used to
840/// generate a positive response.
841///
842/// In addition, security-aware resolvers MUST authenticate the NSEC
843/// RRsets that comprise the non-existence proof as described in Section
844/// 5.3.
845///
846/// To prove the non-existence of an RRset, the resolver must be able to
847/// verify both that the queried RRset does not exist and that no
848/// relevant wildcard RRset exists. Proving this may require more than
849/// one NSEC RRset from the zone. If the complete set of necessary NSEC
850/// RRsets is not present in a response (perhaps due to message
851/// truncation), then a security-aware resolver MUST resend the query in
852/// order to attempt to obtain the full collection of NSEC RRs necessary
853/// to verify the non-existence of the requested RRset. As with all DNS
854/// operations, however, the resolver MUST bound the work it puts into
855/// answering any particular query.
856///
857/// Since a validated NSEC RR proves the existence of both itself and its
858/// corresponding RRSIG RR, a validator MUST ignore the settings of the
859/// NSEC and RRSIG bits in an NSEC RR.
860/// ```
861#[allow(clippy::blocks_in_if_conditions)]
862#[doc(hidden)]
863pub fn verify_nsec(query: &Query, soa_name: &Name, nsecs: &[&Record]) -> bool {
864 // TODO: consider converting this to Result, and giving explicit reason for the failure
865
866 // first look for a record with the same name
867 // if they are, then the query_type should not exist in the NSEC record.
868 // if we got an NSEC record of the same name, but it is listed in the NSEC types,
869 // WTF? is that bad server, bad record
870 if let Some(nsec) = nsecs.iter().find(|nsec| query.name() == nsec.name()) {
871 return nsec
872 .data()
873 .and_then(RData::as_dnssec)
874 .and_then(DNSSECRData::as_nsec)
875 .map_or(false, |rdata| {
876 // this should not be in the covered list
877 !rdata.type_bit_maps().contains(&query.query_type())
878 });
879 }
880
881 let verify_nsec_coverage = |name: &Name| -> bool {
882 nsecs.iter().any(|nsec| {
883 // the query name must be greater than nsec's label (or equal in the case of wildcard)
884 name >= nsec.name() && {
885 nsec.data()
886 .and_then(RData::as_dnssec)
887 .and_then(DNSSECRData::as_nsec)
888 .map_or(false, |rdata| {
889 // the query name is less than the next name
890 // or this record wraps the end, i.e. is the last record
891 name < rdata.next_domain_name() || rdata.next_domain_name() < nsec.name()
892 })
893 }
894 })
895 };
896
897 if !verify_nsec_coverage(query.name()) {
898 // continue to validate there is no wildcard
899 return false;
900 }
901
902 // validate ANY or *.domain record existence
903
904 // we need the wildcard proof, but make sure that it's still part of the zone.
905 let wildcard = query.name().base_name();
906 let wildcard = if soa_name.zone_of(&wildcard) {
907 wildcard
908 } else {
909 soa_name.clone()
910 };
911
912 // don't need to validate the same name again
913 if wildcard == *query.name() {
914 // this was validated by the nsec coverage over the query.name()
915 true
916 } else {
917 // this is the final check, return it's value
918 // if there is wildcard coverage, we're good.
919 verify_nsec_coverage(&wildcard)
920 }
921}