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}