domain/rdata/
dnssec.rs

1//! Record data from [RFC 4034]: DS, DNSKEY, RRSIG, and NSEC records.
2//!
3//! This RFC defines the record types for DNSSEC.
4//!
5//! [RFC 4034]: https://tools.ietf.org/html/rfc4034
6
7use crate::base::cmp::CanonicalOrd;
8use crate::base::iana::{DigestAlgorithm, Rtype, SecurityAlgorithm};
9use crate::base::name::{FlattenInto, ParsedName, ToName};
10use crate::base::rdata::{
11    ComposeRecordData, LongRecordData, ParseRecordData, RecordData,
12};
13use crate::base::scan::{Scan, Scanner, ScannerError};
14use crate::base::serial::Serial;
15use crate::base::wire::{Compose, Composer, FormError, Parse, ParseError};
16use crate::base::zonefile_fmt::{self, Formatter, ZonefileFmt};
17use crate::base::Ttl;
18use crate::utils::{base16, base64};
19use core::cmp::Ordering;
20use core::convert::TryInto;
21use core::{cmp, fmt, hash, str};
22use octseq::builder::{
23    EmptyBuilder, FreezeBuilder, FromBuilder, OctetsBuilder, Truncate,
24};
25use octseq::octets::{Octets, OctetsFrom, OctetsInto};
26use octseq::parse::Parser;
27#[cfg(feature = "serde")]
28use octseq::serde::{DeserializeOctets, SerializeOctets};
29#[cfg(feature = "std")]
30use std::vec::Vec;
31use time::{Date, Month, PrimitiveDateTime, Time};
32
33//------------ Dnskey --------------------------------------------------------
34
35#[derive(Clone)]
36#[cfg_attr(
37    feature = "serde",
38    derive(serde::Serialize, serde::Deserialize),
39    serde(bound(
40        serialize = "
41            Octs: octseq::serde::SerializeOctets + AsRef<[u8]>
42        ",
43        deserialize = "
44            Octs: FromBuilder + octseq::serde::DeserializeOctets<'de>,
45            <Octs as FromBuilder>::Builder:
46                OctetsBuilder + EmptyBuilder,
47        ",
48    ))
49)]
50pub struct Dnskey<Octs> {
51    flags: u16,
52    protocol: u8,
53    algorithm: SecurityAlgorithm,
54    #[cfg_attr(
55        feature = "serde",
56        serde(with = "crate::utils::base64::serde")
57    )]
58    public_key: Octs,
59}
60
61impl Dnskey<()> {
62    /// The rtype of this record data type.
63    pub(crate) const RTYPE: Rtype = Rtype::DNSKEY;
64}
65
66impl<Octs> Dnskey<Octs> {
67    pub fn new(
68        flags: u16,
69        protocol: u8,
70        algorithm: SecurityAlgorithm,
71        public_key: Octs,
72    ) -> Result<Self, LongRecordData>
73    where
74        Octs: AsRef<[u8]>,
75    {
76        LongRecordData::check_len(
77            usize::from(
78                u16::COMPOSE_LEN + u8::COMPOSE_LEN + SecurityAlgorithm::COMPOSE_LEN,
79            )
80            .checked_add(public_key.as_ref().len())
81            .expect("long key"),
82        )?;
83        Ok(Dnskey {
84            flags,
85            protocol,
86            algorithm,
87            public_key,
88        })
89    }
90
91    /// Creates new DNSKEY record data without checking.
92    ///
93    /// # Safety
94    ///
95    /// The caller needs to ensure that wire format representation of the
96    /// record data is at most 65,535 octets long.
97    pub unsafe fn new_unchecked(
98        flags: u16,
99        protocol: u8,
100        algorithm: SecurityAlgorithm,
101        public_key: Octs,
102    ) -> Self {
103        Dnskey {
104            flags,
105            protocol,
106            algorithm,
107            public_key,
108        }
109    }
110
111    pub fn flags(&self) -> u16 {
112        self.flags
113    }
114
115    pub fn protocol(&self) -> u8 {
116        self.protocol
117    }
118
119    pub fn algorithm(&self) -> SecurityAlgorithm {
120        self.algorithm
121    }
122
123    pub fn public_key(&self) -> &Octs {
124        &self.public_key
125    }
126
127    pub fn into_public_key(self) -> Octs {
128        self.public_key
129    }
130
131    pub fn convert<Other: From<Octs>>(self) -> Dnskey<Other> {
132        Dnskey {
133            flags: self.flags,
134            protocol: self.protocol,
135            algorithm: self.algorithm,
136            public_key: self.public_key.into(),
137        }
138    }
139
140    /// Returns whether the Revoke flag is set.
141    ///
142    /// See [RFC 5011, Section 3].
143    ///
144    /// [RFC 5011, Section 3]: https://tools.ietf.org/html/rfc5011#section-3
145    pub fn is_revoked(&self) -> bool {
146        self.flags() & 0b0000_0000_1000_0000 != 0
147    }
148
149    /// Returns whether the the Secure Entry Point (SEP) flag is set.
150    ///
151    /// See [RFC 4034, Section 2.1.1]:
152    ///
153    /// > This flag is only intended to be a hint to zone signing or
154    /// > debugging software as to the intended use of this DNSKEY record;
155    /// > validators MUST NOT alter their behavior during the signature
156    /// > validation process in any way based on the setting of this bit.
157    ///
158    /// [RFC 4034, Section 2.1.1]: https://tools.ietf.org/html/rfc4034#section-2.1.1
159    pub fn is_secure_entry_point(&self) -> bool {
160        self.flags() & 0b0000_0000_0000_0001 != 0
161    }
162
163    /// Returns whether the Zone Key flag is set.
164    ///
165    /// If the flag is not set, the key MUST NOT be used to verify RRSIGs that
166    /// cover RRSETs. See [RFC 4034, Section 2.1.1].
167    ///
168    /// [RFC 4034, Section 2.1.1]: https://tools.ietf.org/html/rfc4034#section-2.1.1
169    pub fn is_zone_key(&self) -> bool {
170        self.flags() & 0b0000_0001_0000_0000 != 0
171    }
172
173    /// Returns the key tag for this DNSKEY data.
174    pub fn key_tag(&self) -> u16
175    where
176        Octs: AsRef<[u8]>,
177    {
178        if self.algorithm == SecurityAlgorithm::RSAMD5 {
179            // The key tag is third-to-last and second-to-last octets of the
180            // key as a big-endian u16. If we don’t have enough octets in the
181            // key, we return 0.
182            let len = self.public_key.as_ref().len();
183            if len > 2 {
184                u16::from_be_bytes(
185                    self.public_key.as_ref()[len - 3..len - 1]
186                        .try_into()
187                        .unwrap(),
188                )
189            } else {
190                0
191            }
192        } else {
193            // Treat record data as a octet sequence. Add octets at odd
194            // indexes as they are, add octets at even indexes shifted left
195            // by 8 bits.
196            let mut res = u32::from(self.flags);
197            res += u32::from(self.protocol) << 8;
198            res += u32::from(self.algorithm.to_int());
199            let mut iter = self.public_key().as_ref().iter();
200
201            // I find this clearer with a loop.
202            #[allow(clippy::while_let_loop)]
203            loop {
204                match iter.next() {
205                    Some(&x) => res += u32::from(x) << 8,
206                    None => break,
207                }
208                match iter.next() {
209                    Some(&x) => res += u32::from(x),
210                    None => break,
211                }
212            }
213
214            res += (res >> 16) & 0xFFFF;
215            (res & 0xFFFF) as u16
216        }
217    }
218
219    pub(super) fn convert_octets<Target: OctetsFrom<Octs>>(
220        self,
221    ) -> Result<Dnskey<Target>, Target::Error> {
222        Ok(unsafe {
223            Dnskey::new_unchecked(
224                self.flags,
225                self.protocol,
226                self.algorithm,
227                self.public_key.try_octets_into()?,
228            )
229        })
230    }
231
232    pub(super) fn flatten<Target: OctetsFrom<Octs>>(
233        self,
234    ) -> Result<Dnskey<Target>, Target::Error> {
235        self.convert_octets()
236    }
237
238    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
239        parser: &mut Parser<'a, Src>,
240    ) -> Result<Self, ParseError> {
241        let len = match parser.remaining().checked_sub(4) {
242            Some(len) => len,
243            None => return Err(ParseError::ShortInput),
244        };
245        Ok(unsafe {
246            Self::new_unchecked(
247                u16::parse(parser)?,
248                u8::parse(parser)?,
249                SecurityAlgorithm::parse(parser)?,
250                parser.parse_octets(len)?,
251            )
252        })
253    }
254
255    pub fn scan<S: Scanner<Octets = Octs>>(
256        scanner: &mut S,
257    ) -> Result<Self, S::Error>
258    where
259        Octs: AsRef<[u8]>,
260    {
261        Self::new(
262            u16::scan(scanner)?,
263            u8::scan(scanner)?,
264            SecurityAlgorithm::scan(scanner)?,
265            scanner.convert_entry(base64::SymbolConverter::new())?,
266        )
267        .map_err(|err| S::Error::custom(err.as_str()))
268    }
269}
270
271//--- OctetsFrom
272
273impl<Octs, SrcOcts> OctetsFrom<Dnskey<SrcOcts>> for Dnskey<Octs>
274where
275    Octs: OctetsFrom<SrcOcts>,
276{
277    type Error = Octs::Error;
278
279    fn try_octets_from(source: Dnskey<SrcOcts>) -> Result<Self, Self::Error> {
280        Ok(unsafe {
281            Dnskey::new_unchecked(
282                source.flags,
283                source.protocol,
284                source.algorithm,
285                Octs::try_octets_from(source.public_key)?,
286            )
287        })
288    }
289}
290
291//--- PartialEq and Eq
292
293impl<Octs, Other> PartialEq<Dnskey<Other>> for Dnskey<Octs>
294where
295    Octs: AsRef<[u8]>,
296    Other: AsRef<[u8]>,
297{
298    fn eq(&self, other: &Dnskey<Other>) -> bool {
299        self.flags == other.flags
300            && self.protocol == other.protocol
301            && self.algorithm == other.algorithm
302            && self.public_key.as_ref() == other.public_key.as_ref()
303    }
304}
305
306impl<Octs: AsRef<[u8]>> Eq for Dnskey<Octs> {}
307
308//--- PartialOrd, CanonicalOrd, and Ord
309
310impl<Octs, Other> PartialOrd<Dnskey<Other>> for Dnskey<Octs>
311where
312    Octs: AsRef<[u8]>,
313    Other: AsRef<[u8]>,
314{
315    fn partial_cmp(&self, other: &Dnskey<Other>) -> Option<Ordering> {
316        Some(self.canonical_cmp(other))
317    }
318}
319
320impl<Octs, Other> CanonicalOrd<Dnskey<Other>> for Dnskey<Octs>
321where
322    Octs: AsRef<[u8]>,
323    Other: AsRef<[u8]>,
324{
325    fn canonical_cmp(&self, other: &Dnskey<Other>) -> Ordering {
326        match self.flags.cmp(&other.flags) {
327            Ordering::Equal => {}
328            other => return other,
329        }
330        match self.protocol.cmp(&other.protocol) {
331            Ordering::Equal => {}
332            other => return other,
333        }
334        match self.algorithm.cmp(&other.algorithm) {
335            Ordering::Equal => {}
336            other => return other,
337        }
338        self.public_key.as_ref().cmp(other.public_key.as_ref())
339    }
340}
341
342impl<Octs: AsRef<[u8]>> Ord for Dnskey<Octs> {
343    fn cmp(&self, other: &Self) -> Ordering {
344        self.canonical_cmp(other)
345    }
346}
347
348//--- Hash
349
350impl<Octs: AsRef<[u8]>> hash::Hash for Dnskey<Octs> {
351    fn hash<H: hash::Hasher>(&self, state: &mut H) {
352        self.flags.hash(state);
353        self.protocol.hash(state);
354        self.algorithm.hash(state);
355        self.public_key.as_ref().hash(state);
356    }
357}
358
359//--- RecordData, ParseRecordData, ComposeRecordData
360
361impl<Octs> RecordData for Dnskey<Octs> {
362    fn rtype(&self) -> Rtype {
363        Dnskey::RTYPE
364    }
365}
366
367impl<'a, Octs> ParseRecordData<'a, Octs> for Dnskey<Octs::Range<'a>>
368where
369    Octs: Octets + ?Sized,
370{
371    fn parse_rdata(
372        rtype: Rtype,
373        parser: &mut Parser<'a, Octs>,
374    ) -> Result<Option<Self>, ParseError> {
375        if rtype == Dnskey::RTYPE {
376            Self::parse(parser).map(Some)
377        } else {
378            Ok(None)
379        }
380    }
381}
382
383impl<Octs: AsRef<[u8]>> ComposeRecordData for Dnskey<Octs> {
384    fn rdlen(&self, _compress: bool) -> Option<u16> {
385        Some(
386            u16::try_from(self.public_key.as_ref().len())
387                .expect("long key")
388                .checked_add(
389                    u16::COMPOSE_LEN + u8::COMPOSE_LEN + SecurityAlgorithm::COMPOSE_LEN,
390                )
391                .expect("long key"),
392        )
393    }
394
395    fn compose_rdata<Target: Composer + ?Sized>(
396        &self,
397        target: &mut Target,
398    ) -> Result<(), Target::AppendError> {
399        self.flags.compose(target)?;
400        self.protocol.compose(target)?;
401        self.algorithm.compose(target)?;
402        target.append_slice(self.public_key.as_ref())
403    }
404
405    fn compose_canonical_rdata<Target: Composer + ?Sized>(
406        &self,
407        target: &mut Target,
408    ) -> Result<(), Target::AppendError> {
409        self.compose_rdata(target)
410    }
411}
412
413//--- Display
414
415impl<Octs: AsRef<[u8]>> fmt::Display for Dnskey<Octs> {
416    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
417        write!(f, "{} {} {} ", self.flags, self.protocol, self.algorithm)?;
418        base64::display(&self.public_key, f)
419    }
420}
421
422//--- Debug
423
424impl<Octs: AsRef<[u8]>> fmt::Debug for Dnskey<Octs> {
425    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
426        f.debug_struct("Dnskey")
427            .field("flags", &self.flags)
428            .field("protocol", &self.protocol)
429            .field("algorithm", &self.algorithm)
430            .field("public_key", &self.public_key.as_ref())
431            .finish()
432    }
433}
434
435//--- ZonefileFmt
436
437impl<Octs: AsRef<[u8]>> ZonefileFmt for Dnskey<Octs> {
438    fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
439        let revoked = self.is_revoked();
440        let sep = self.is_secure_entry_point();
441        let zone_key = self.is_zone_key();
442
443        p.block(|p| {
444            p.write_token(self.flags)?;
445            p.write_comment(format_args!(
446                "flags:{}{}{}{}",
447                if revoked { " revoked" } else { "" },
448                if sep { " sep" } else { "" },
449                if zone_key { " zone_key" } else { "" },
450                if self.flags == 0 { " <none>" } else { "" },
451            ))?;
452            p.write_token(self.protocol)?;
453            p.write_comment("protocol")?;
454            p.write_show(self.algorithm)?;
455            p.write_token(base64::encode_display(&self.public_key))?;
456            p.write_comment(format_args!("key tag: {}", self.key_tag()))
457        })
458    }
459}
460
461//------------ ProtoRrsig ----------------------------------------------------
462
463/// The RRSIG RDATA to be included when creating the signature.
464#[derive(Clone)]
465pub struct ProtoRrsig<Name> {
466    type_covered: Rtype,
467    algorithm: SecurityAlgorithm,
468    labels: u8,
469    original_ttl: Ttl,
470    expiration: Timestamp,
471    inception: Timestamp,
472    key_tag: u16,
473    signer_name: Name,
474}
475
476impl<Name> ProtoRrsig<Name> {
477    #[allow(clippy::too_many_arguments)] // XXX Consider changing.
478    pub fn new(
479        type_covered: Rtype,
480        algorithm: SecurityAlgorithm,
481        labels: u8,
482        original_ttl: Ttl,
483        expiration: Timestamp,
484        inception: Timestamp,
485        key_tag: u16,
486        signer_name: Name,
487    ) -> Self {
488        ProtoRrsig {
489            type_covered,
490            algorithm,
491            labels,
492            original_ttl,
493            expiration,
494            inception,
495            key_tag,
496            signer_name,
497        }
498    }
499
500    pub fn into_rrsig<Octs: AsRef<[u8]>>(
501        self,
502        signature: Octs,
503    ) -> Result<Rrsig<Octs, Name>, LongRecordData>
504    where
505        Name: ToName,
506    {
507        Rrsig::new(
508            self.type_covered,
509            self.algorithm,
510            self.labels,
511            self.original_ttl,
512            self.expiration,
513            self.inception,
514            self.key_tag,
515            self.signer_name,
516            signature,
517        )
518    }
519}
520
521impl<Name: ToName> ProtoRrsig<Name> {
522    pub fn compose<Target: Composer + ?Sized>(
523        &self,
524        target: &mut Target,
525    ) -> Result<(), Target::AppendError> {
526        self.compose_head(target)?;
527        self.signer_name.compose(target)
528    }
529
530    pub fn compose_canonical<Target: Composer + ?Sized>(
531        &self,
532        target: &mut Target,
533    ) -> Result<(), Target::AppendError> {
534        self.compose_head(target)?;
535        self.signer_name.compose_canonical(target)
536    }
537
538    fn compose_head<Target: Composer + ?Sized>(
539        &self,
540        target: &mut Target,
541    ) -> Result<(), Target::AppendError> {
542        self.type_covered.compose(target)?;
543        self.algorithm.compose(target)?;
544        self.labels.compose(target)?;
545        self.original_ttl.compose(target)?;
546        self.expiration.compose(target)?;
547        self.inception.compose(target)?;
548        self.key_tag.compose(target)
549    }
550}
551
552//--- OctetsFrom and FlattenInto
553
554impl<Name, SrcName> OctetsFrom<ProtoRrsig<SrcName>> for ProtoRrsig<Name>
555where
556    Name: OctetsFrom<SrcName>,
557{
558    type Error = Name::Error;
559
560    fn try_octets_from(
561        source: ProtoRrsig<SrcName>,
562    ) -> Result<Self, Self::Error> {
563        Ok(ProtoRrsig::new(
564            source.type_covered,
565            source.algorithm,
566            source.labels,
567            source.original_ttl,
568            source.expiration,
569            source.inception,
570            source.key_tag,
571            Name::try_octets_from(source.signer_name)?,
572        ))
573    }
574}
575
576impl<Name, TName> FlattenInto<ProtoRrsig<TName>> for ProtoRrsig<Name>
577where
578    Name: FlattenInto<TName>,
579{
580    type AppendError = Name::AppendError;
581
582    fn try_flatten_into(
583        self,
584    ) -> Result<ProtoRrsig<TName>, Name::AppendError> {
585        Ok(ProtoRrsig::new(
586            self.type_covered,
587            self.algorithm,
588            self.labels,
589            self.original_ttl,
590            self.expiration,
591            self.inception,
592            self.key_tag,
593            self.signer_name.try_flatten_into()?,
594        ))
595    }
596}
597
598//------------ Timestamp ------------------------------------------------------
599
600/// A Timestamp for RRSIG Records.
601///
602/// DNS uses 32 bit timestamps that are conceptionally
603/// viewed as the 32 bit modulus of a larger number space. Because of that,
604/// special rules apply when processing these values.
605///
606/// [RFC 4034] defines Timestamps as the number of seconds elepased since
607/// since 1 January 1970 00:00:00 UTC, ignoring leap seconds. Timestamps
608/// are compared using so-called "Serial number arithmetic", as defined in
609/// [RFC 1982].
610///
611/// The RFC defines the semantics for doing arithmetics in the
612/// face of these wrap-arounds. This type implements these semantics atop a
613/// native `u32`. The RFC defines two operations: addition and comparison.
614///
615/// For addition, the amount added can only be a positive number of up to
616/// `2^31 - 1`. Because of this, we decided to not implement the
617/// `Add` trait but rather have a dedicated method `add` so as to not cause
618/// surprise panics.
619///
620/// Timestamps only implement a partial ordering. That is, there are
621/// pairs of values that are not equal but there still isn’t one value larger
622/// than the other. Since this is neatly implemented by the `PartialOrd`
623/// trait, the type implements that.
624///
625/// [RFC 1982]: https://tools.ietf.org/html/rfc1982
626/// [RFC 4034]: https://tools.ietf.org/html/rfc4034
627
628#[derive(Clone, Copy, Debug, PartialEq)]
629#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
630pub struct Timestamp(Serial);
631
632impl Timestamp {
633    /// Returns a serial number for the current Unix time.
634    #[cfg(feature = "std")]
635    #[must_use]
636    pub fn now() -> Self {
637        Self(Serial::now())
638    }
639
640    /// Scan a serial represention signature time value.
641    ///
642    /// In [RRSIG] records, the expiration and inception times are given as
643    /// serial values. Their representation format can either be the
644    /// value or a specific date in `YYYYMMDDHHmmSS` format.
645    ///
646    /// [RRSIG]: Rrsig
647    pub fn scan<S: Scanner>(scanner: &mut S) -> Result<Self, S::Error> {
648        let mut pos = 0;
649        let mut buf = [0u8; 14];
650        scanner.scan_symbols(|symbol| {
651            if pos >= 14 {
652                return Err(S::Error::custom("illegal signature time"));
653            }
654            buf[pos] = symbol
655                .into_digit(10)
656                .map_err(|_| S::Error::custom("illegal signature time"))?
657                as u8;
658            pos += 1;
659            Ok(())
660        })?;
661        if pos <= 10 {
662            // We have an integer. We generate it into a u64 to deal
663            // with possible overflows.
664            let mut res = 0u64;
665            for ch in &buf[..pos] {
666                res = res * 10 + (u64::from(*ch));
667            }
668            if res > u64::from(u32::MAX) {
669                Err(S::Error::custom("illegal signature time"))
670            } else {
671                Ok(Self(Serial(res as u32)))
672            }
673        } else if pos == 14 {
674            let year = u32_from_buf(&buf[0..4]) as i32;
675            let month = Month::try_from(u8_from_buf(&buf[4..6]))
676                .map_err(|_| S::Error::custom("illegal signature time"))?;
677            let day = u8_from_buf(&buf[6..8]);
678            let hour = u8_from_buf(&buf[8..10]);
679            let minute = u8_from_buf(&buf[10..12]);
680            let second = u8_from_buf(&buf[12..14]);
681            Ok(Self(Serial(
682                PrimitiveDateTime::new(
683                    Date::from_calendar_date(year, month, day).map_err(
684                        |_| S::Error::custom("illegal signature time"),
685                    )?,
686                    Time::from_hms(hour, minute, second).map_err(|_| {
687                        S::Error::custom("illegal signature time")
688                    })?,
689                )
690                .assume_utc()
691                .unix_timestamp() as u32,
692            )))
693        } else {
694            Err(S::Error::custom("illegal signature time"))
695        }
696    }
697
698    /// Returns the timestamp as a raw integer.
699    #[must_use]
700    pub fn into_int(self) -> u32 {
701        self.0.into_int()
702    }
703}
704
705/// # Parsing and Composing
706///
707impl Timestamp {
708    pub const COMPOSE_LEN: u16 = Serial::COMPOSE_LEN;
709
710    pub fn parse<Octs: AsRef<[u8]> + ?Sized>(
711        parser: &mut Parser<Octs>,
712    ) -> Result<Self, ParseError> {
713        Serial::parse(parser).map(Self)
714    }
715
716    pub fn compose<Target: Composer + ?Sized>(
717        &self,
718        target: &mut Target,
719    ) -> Result<(), Target::AppendError> {
720        self.0.compose(target)
721    }
722}
723
724//--- From and FromStr
725
726impl From<u32> for Timestamp {
727    fn from(item: u32) -> Self {
728        Self(Serial::from(item))
729    }
730}
731
732impl str::FromStr for Timestamp {
733    type Err = IllegalSignatureTime;
734
735    /// Parses a timestamp value from a string.
736    ///
737    /// The presentation format can either be their integer value or a
738    /// specific date in `YYYYMMDDHHmmSS` format.
739    fn from_str(src: &str) -> Result<Self, Self::Err> {
740        if !src.is_ascii() {
741            return Err(IllegalSignatureTime(()));
742        }
743        if src.len() == 14 {
744            let year = u32::from_str(&src[0..4])
745                .map_err(|_| IllegalSignatureTime(()))?
746                as i32;
747            let month = Month::try_from(
748                u8::from_str(&src[4..6])
749                    .map_err(|_| IllegalSignatureTime(()))?,
750            )
751            .map_err(|_| IllegalSignatureTime(()))?;
752            let day = u8::from_str(&src[6..8])
753                .map_err(|_| IllegalSignatureTime(()))?;
754            let hour = u8::from_str(&src[8..10])
755                .map_err(|_| IllegalSignatureTime(()))?;
756            let minute = u8::from_str(&src[10..12])
757                .map_err(|_| IllegalSignatureTime(()))?;
758            let second = u8::from_str(&src[12..14])
759                .map_err(|_| IllegalSignatureTime(()))?;
760            Ok(Timestamp(Serial(
761                PrimitiveDateTime::new(
762                    Date::from_calendar_date(year, month, day)
763                        .map_err(|_| IllegalSignatureTime(()))?,
764                    Time::from_hms(hour, minute, second)
765                        .map_err(|_| IllegalSignatureTime(()))?,
766                )
767                .assume_utc()
768                .unix_timestamp() as u32,
769            )))
770        } else {
771            Serial::from_str(src)
772                .map(Timestamp)
773                .map_err(|_| IllegalSignatureTime(()))
774        }
775    }
776}
777
778//--- Display
779
780impl fmt::Display for Timestamp {
781    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
782        write!(f, "{}", self.0)
783    }
784}
785
786//--- ZonefileFmt
787
788impl ZonefileFmt for Timestamp {
789    fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
790        p.write_token(self.0)
791    }
792}
793
794//--- PartialOrd and CanonicalOrd
795
796impl cmp::PartialOrd for Timestamp {
797    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
798        self.0.partial_cmp(&other.0)
799    }
800}
801
802impl CanonicalOrd for Timestamp {
803    fn canonical_cmp(&self, other: &Self) -> cmp::Ordering {
804        self.0.canonical_cmp(&other.0)
805    }
806}
807
808//------------ Helper Functions ----------------------------------------------
809
810fn u8_from_buf(buf: &[u8]) -> u8 {
811    let mut res = 0;
812    for ch in buf {
813        res = res * 10 + *ch;
814    }
815    res
816}
817
818fn u32_from_buf(buf: &[u8]) -> u32 {
819    let mut res = 0;
820    for ch in buf {
821        res = res * 10 + (u32::from(*ch));
822    }
823    res
824}
825
826//------------ Rrsig ---------------------------------------------------------
827
828#[derive(Clone)]
829#[cfg_attr(
830    feature = "serde",
831    derive(serde::Serialize, serde::Deserialize),
832    serde(bound(
833        serialize = "
834            Octs: octseq::serde::SerializeOctets + AsRef<[u8]>,
835            Name: serde::Serialize,
836        ",
837        deserialize = "
838            Octs: FromBuilder + octseq::serde::DeserializeOctets<'de>,
839            <Octs as FromBuilder>::Builder:
840                OctetsBuilder + EmptyBuilder,
841            Name: serde::Deserialize<'de>,
842        ",
843    ))
844)]
845pub struct Rrsig<Octs, Name> {
846    type_covered: Rtype,
847    algorithm: SecurityAlgorithm,
848    labels: u8,
849    original_ttl: Ttl,
850    expiration: Timestamp,
851    inception: Timestamp,
852    key_tag: u16,
853    signer_name: Name,
854    #[cfg_attr(
855        feature = "serde",
856        serde(with = "crate::utils::base64::serde")
857    )]
858    signature: Octs,
859}
860
861impl Rrsig<(), ()> {
862    /// The rtype of this record data type.
863    pub(crate) const RTYPE: Rtype = Rtype::RRSIG;
864}
865
866impl<Octs, Name> Rrsig<Octs, Name> {
867    #[allow(clippy::too_many_arguments)] // XXX Consider changing.
868    pub fn new(
869        type_covered: Rtype,
870        algorithm: SecurityAlgorithm,
871        labels: u8,
872        original_ttl: Ttl,
873        expiration: Timestamp,
874        inception: Timestamp,
875        key_tag: u16,
876        signer_name: Name,
877        signature: Octs,
878    ) -> Result<Self, LongRecordData>
879    where
880        Octs: AsRef<[u8]>,
881        Name: ToName,
882    {
883        LongRecordData::check_len(
884            usize::from(
885                Rtype::COMPOSE_LEN
886                    + SecurityAlgorithm::COMPOSE_LEN
887                    + u8::COMPOSE_LEN
888                    + u32::COMPOSE_LEN
889                    + Timestamp::COMPOSE_LEN
890                    + Timestamp::COMPOSE_LEN
891                    + u16::COMPOSE_LEN
892                    + signer_name.compose_len(),
893            )
894            .checked_add(signature.as_ref().len())
895            .expect("long signature"),
896        )?;
897        Ok(unsafe {
898            Rrsig::new_unchecked(
899                type_covered,
900                algorithm,
901                labels,
902                original_ttl,
903                expiration,
904                inception,
905                key_tag,
906                signer_name,
907                signature,
908            )
909        })
910    }
911
912    /// Creates new RRSIG record data without checking.
913    ///
914    /// # Safety
915    ///
916    /// The caller needs to ensure that wire format representation of the
917    /// record data is at most 65,535 octets long.
918    #[allow(clippy::too_many_arguments)] // XXX Consider changing.
919    pub unsafe fn new_unchecked(
920        type_covered: Rtype,
921        algorithm: SecurityAlgorithm,
922        labels: u8,
923        original_ttl: Ttl,
924        expiration: Timestamp,
925        inception: Timestamp,
926        key_tag: u16,
927        signer_name: Name,
928        signature: Octs,
929    ) -> Self {
930        Rrsig {
931            type_covered,
932            algorithm,
933            labels,
934            original_ttl,
935            expiration,
936            inception,
937            key_tag,
938            signer_name,
939            signature,
940        }
941    }
942
943    pub fn type_covered(&self) -> Rtype {
944        self.type_covered
945    }
946
947    pub fn algorithm(&self) -> SecurityAlgorithm {
948        self.algorithm
949    }
950
951    pub fn labels(&self) -> u8 {
952        self.labels
953    }
954
955    pub fn original_ttl(&self) -> Ttl {
956        self.original_ttl
957    }
958
959    pub fn expiration(&self) -> Timestamp {
960        self.expiration
961    }
962
963    pub fn inception(&self) -> Timestamp {
964        self.inception
965    }
966
967    pub fn key_tag(&self) -> u16 {
968        self.key_tag
969    }
970
971    pub fn signer_name(&self) -> &Name {
972        &self.signer_name
973    }
974
975    pub fn signature(&self) -> &Octs {
976        &self.signature
977    }
978
979    pub fn set_signature(&mut self, signature: Octs) {
980        self.signature = signature
981    }
982
983    pub(super) fn convert_octets<TOcts, TName>(
984        self,
985    ) -> Result<Rrsig<TOcts, TName>, TOcts::Error>
986    where
987        TOcts: OctetsFrom<Octs>,
988        TName: OctetsFrom<Name, Error = TOcts::Error>,
989    {
990        Ok(unsafe {
991            Rrsig::new_unchecked(
992                self.type_covered,
993                self.algorithm,
994                self.labels,
995                self.original_ttl,
996                self.expiration,
997                self.inception,
998                self.key_tag,
999                TName::try_octets_from(self.signer_name)?,
1000                TOcts::try_octets_from(self.signature)?,
1001            )
1002        })
1003    }
1004
1005    pub(super) fn flatten<TOcts, TName>(
1006        self,
1007    ) -> Result<Rrsig<TOcts, TName>, TOcts::Error>
1008    where
1009        TOcts: OctetsFrom<Octs>,
1010        Name: FlattenInto<TName, AppendError = TOcts::Error>,
1011    {
1012        Ok(unsafe {
1013            Rrsig::new_unchecked(
1014                self.type_covered,
1015                self.algorithm,
1016                self.labels,
1017                self.original_ttl,
1018                self.expiration,
1019                self.inception,
1020                self.key_tag,
1021                self.signer_name.try_flatten_into()?,
1022                TOcts::try_octets_from(self.signature)?,
1023            )
1024        })
1025    }
1026
1027    pub fn scan<S: Scanner<Octets = Octs, Name = Name>>(
1028        scanner: &mut S,
1029    ) -> Result<Self, S::Error>
1030    where
1031        Octs: AsRef<[u8]>,
1032        Name: ToName,
1033    {
1034        Self::new(
1035            Rtype::scan(scanner)?,
1036            SecurityAlgorithm::scan(scanner)?,
1037            u8::scan(scanner)?,
1038            Ttl::scan(scanner)?,
1039            Timestamp::scan(scanner)?,
1040            Timestamp::scan(scanner)?,
1041            u16::scan(scanner)?,
1042            scanner.scan_name()?,
1043            scanner.convert_entry(base64::SymbolConverter::new())?,
1044        )
1045        .map_err(|err| S::Error::custom(err.as_str()))
1046    }
1047}
1048
1049impl<Octs> Rrsig<Octs, ParsedName<Octs>> {
1050    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized + 'a>(
1051        parser: &mut Parser<'a, Src>,
1052    ) -> Result<Self, ParseError> {
1053        let type_covered = Rtype::parse(parser)?;
1054        let algorithm = SecurityAlgorithm::parse(parser)?;
1055        let labels = u8::parse(parser)?;
1056        let original_ttl = Ttl::parse(parser)?;
1057        let expiration = Timestamp::parse(parser)?;
1058        let inception = Timestamp::parse(parser)?;
1059        let key_tag = u16::parse(parser)?;
1060        let signer_name = ParsedName::parse(parser)?;
1061        let len = parser.remaining();
1062        let signature = parser.parse_octets(len)?;
1063        Ok(unsafe {
1064            Self::new_unchecked(
1065                type_covered,
1066                algorithm,
1067                labels,
1068                original_ttl,
1069                expiration,
1070                inception,
1071                key_tag,
1072                signer_name,
1073                signature,
1074            )
1075        })
1076    }
1077}
1078
1079//--- OctetsFrom and FlattenInto
1080
1081impl<Octs, SrcOcts, Name, SrcName> OctetsFrom<Rrsig<SrcOcts, SrcName>>
1082    for Rrsig<Octs, Name>
1083where
1084    Octs: OctetsFrom<SrcOcts>,
1085    Name: OctetsFrom<SrcName>,
1086    Octs::Error: From<Name::Error>,
1087{
1088    type Error = Octs::Error;
1089
1090    fn try_octets_from(
1091        source: Rrsig<SrcOcts, SrcName>,
1092    ) -> Result<Self, Self::Error> {
1093        Ok(unsafe {
1094            Rrsig::new_unchecked(
1095                source.type_covered,
1096                source.algorithm,
1097                source.labels,
1098                source.original_ttl,
1099                source.expiration,
1100                source.inception,
1101                source.key_tag,
1102                Name::try_octets_from(source.signer_name)?,
1103                Octs::try_octets_from(source.signature)?,
1104            )
1105        })
1106    }
1107}
1108
1109impl<Octs, TOcts, Name, TName> FlattenInto<Rrsig<TOcts, TName>>
1110    for Rrsig<Octs, Name>
1111where
1112    TOcts: OctetsFrom<Octs>,
1113    Name: FlattenInto<TName, AppendError = TOcts::Error>,
1114{
1115    type AppendError = TOcts::Error;
1116
1117    fn try_flatten_into(self) -> Result<Rrsig<TOcts, TName>, TOcts::Error> {
1118        self.flatten()
1119    }
1120}
1121
1122//--- PartialEq and Eq
1123
1124impl<N, NN, O, OO> PartialEq<Rrsig<OO, NN>> for Rrsig<O, N>
1125where
1126    N: ToName,
1127    NN: ToName,
1128    O: AsRef<[u8]>,
1129    OO: AsRef<[u8]>,
1130{
1131    fn eq(&self, other: &Rrsig<OO, NN>) -> bool {
1132        self.type_covered == other.type_covered
1133            && self.algorithm == other.algorithm
1134            && self.labels == other.labels
1135            && self.original_ttl == other.original_ttl
1136            && self.expiration.into_int() == other.expiration.into_int()
1137            && self.inception.into_int() == other.inception.into_int()
1138            && self.key_tag == other.key_tag
1139            && self.signer_name.name_eq(&other.signer_name)
1140            && self.signature.as_ref() == other.signature.as_ref()
1141    }
1142}
1143
1144impl<Octs, Name> Eq for Rrsig<Octs, Name>
1145where
1146    Octs: AsRef<[u8]>,
1147    Name: ToName,
1148{
1149}
1150
1151//--- PartialOrd, CanonicalOrd, and Ord
1152
1153impl<N, NN, O, OO> PartialOrd<Rrsig<OO, NN>> for Rrsig<O, N>
1154where
1155    N: ToName,
1156    NN: ToName,
1157    O: AsRef<[u8]>,
1158    OO: AsRef<[u8]>,
1159{
1160    fn partial_cmp(&self, other: &Rrsig<OO, NN>) -> Option<Ordering> {
1161        match self.type_covered.partial_cmp(&other.type_covered) {
1162            Some(Ordering::Equal) => {}
1163            other => return other,
1164        }
1165        match self.algorithm.partial_cmp(&other.algorithm) {
1166            Some(Ordering::Equal) => {}
1167            other => return other,
1168        }
1169        match self.labels.partial_cmp(&other.labels) {
1170            Some(Ordering::Equal) => {}
1171            other => return other,
1172        }
1173        match self.original_ttl.partial_cmp(&other.original_ttl) {
1174            Some(Ordering::Equal) => {}
1175            other => return other,
1176        }
1177        match self.expiration.partial_cmp(&other.expiration) {
1178            Some(Ordering::Equal) => {}
1179            other => return other,
1180        }
1181        match self.inception.partial_cmp(&other.inception) {
1182            Some(Ordering::Equal) => {}
1183            other => return other,
1184        }
1185        match self.key_tag.partial_cmp(&other.key_tag) {
1186            Some(Ordering::Equal) => {}
1187            other => return other,
1188        }
1189        match self.signer_name.name_cmp(&other.signer_name) {
1190            Ordering::Equal => {}
1191            other => return Some(other),
1192        }
1193        self.signature
1194            .as_ref()
1195            .partial_cmp(other.signature.as_ref())
1196    }
1197}
1198
1199impl<N, NN, O, OO> CanonicalOrd<Rrsig<OO, NN>> for Rrsig<O, N>
1200where
1201    N: ToName,
1202    NN: ToName,
1203    O: AsRef<[u8]>,
1204    OO: AsRef<[u8]>,
1205{
1206    fn canonical_cmp(&self, other: &Rrsig<OO, NN>) -> Ordering {
1207        match self.type_covered.cmp(&other.type_covered) {
1208            Ordering::Equal => {}
1209            other => return other,
1210        }
1211        match self.algorithm.cmp(&other.algorithm) {
1212            Ordering::Equal => {}
1213            other => return other,
1214        }
1215        match self.labels.cmp(&other.labels) {
1216            Ordering::Equal => {}
1217            other => return other,
1218        }
1219        match self.original_ttl.cmp(&other.original_ttl) {
1220            Ordering::Equal => {}
1221            other => return other,
1222        }
1223        match self.expiration.canonical_cmp(&other.expiration) {
1224            Ordering::Equal => {}
1225            other => return other,
1226        }
1227        match self.inception.canonical_cmp(&other.inception) {
1228            Ordering::Equal => {}
1229            other => return other,
1230        }
1231        match self.key_tag.cmp(&other.key_tag) {
1232            Ordering::Equal => {}
1233            other => return other,
1234        }
1235        match self.signer_name.lowercase_composed_cmp(&other.signer_name) {
1236            Ordering::Equal => {}
1237            other => return other,
1238        }
1239        self.signature.as_ref().cmp(other.signature.as_ref())
1240    }
1241}
1242
1243impl<O: AsRef<[u8]>, N: ToName> Ord for Rrsig<O, N> {
1244    fn cmp(&self, other: &Self) -> Ordering {
1245        self.canonical_cmp(other)
1246    }
1247}
1248
1249//--- Hash
1250
1251impl<O: AsRef<[u8]>, N: hash::Hash> hash::Hash for Rrsig<O, N> {
1252    fn hash<H: hash::Hasher>(&self, state: &mut H) {
1253        self.type_covered.hash(state);
1254        self.algorithm.hash(state);
1255        self.labels.hash(state);
1256        self.original_ttl.hash(state);
1257        self.expiration.into_int().hash(state);
1258        self.inception.into_int().hash(state);
1259        self.key_tag.hash(state);
1260        self.signer_name.hash(state);
1261        self.signature.as_ref().hash(state);
1262    }
1263}
1264
1265//--- RecordData, ParseRecordData, ComposeRecordData
1266
1267impl<Octs, Name> RecordData for Rrsig<Octs, Name> {
1268    fn rtype(&self) -> Rtype {
1269        Rrsig::RTYPE
1270    }
1271}
1272
1273impl<'a, Octs: Octets + ?Sized> ParseRecordData<'a, Octs>
1274    for Rrsig<Octs::Range<'a>, ParsedName<Octs::Range<'a>>>
1275{
1276    fn parse_rdata(
1277        rtype: Rtype,
1278        parser: &mut Parser<'a, Octs>,
1279    ) -> Result<Option<Self>, ParseError> {
1280        if rtype == Rrsig::RTYPE {
1281            Self::parse(parser).map(Some)
1282        } else {
1283            Ok(None)
1284        }
1285    }
1286}
1287
1288impl<Octs, Name> ComposeRecordData for Rrsig<Octs, Name>
1289where
1290    Octs: AsRef<[u8]>,
1291    Name: ToName,
1292{
1293    fn rdlen(&self, _compress: bool) -> Option<u16> {
1294        Some(
1295            (Rtype::COMPOSE_LEN
1296                + SecurityAlgorithm::COMPOSE_LEN
1297                + u8::COMPOSE_LEN
1298                + u32::COMPOSE_LEN
1299                + Timestamp::COMPOSE_LEN
1300                + Timestamp::COMPOSE_LEN
1301                + u16::COMPOSE_LEN
1302                + self.signer_name.compose_len())
1303            .checked_add(
1304                u16::try_from(self.signature.as_ref().len())
1305                    .expect("long signature"),
1306            )
1307            .expect("long signature"),
1308        )
1309    }
1310
1311    fn compose_rdata<Target: Composer + ?Sized>(
1312        &self,
1313        target: &mut Target,
1314    ) -> Result<(), Target::AppendError> {
1315        self.compose_head(target)?;
1316        self.signer_name.compose(target)?;
1317        target.append_slice(self.signature.as_ref())
1318    }
1319
1320    fn compose_canonical_rdata<Target: Composer + ?Sized>(
1321        &self,
1322        target: &mut Target,
1323    ) -> Result<(), Target::AppendError> {
1324        self.compose_head(target)?;
1325        self.signer_name.compose_canonical(target)?;
1326        target.append_slice(self.signature.as_ref())
1327    }
1328}
1329
1330impl<Octs: AsRef<[u8]>, Name: ToName> Rrsig<Octs, Name> {
1331    fn compose_head<Target: Composer + ?Sized>(
1332        &self,
1333        target: &mut Target,
1334    ) -> Result<(), Target::AppendError> {
1335        self.type_covered.compose(target)?;
1336        self.algorithm.compose(target)?;
1337        self.labels.compose(target)?;
1338        self.original_ttl.compose(target)?;
1339        self.expiration.compose(target)?;
1340        self.inception.compose(target)?;
1341        self.key_tag.compose(target)
1342    }
1343}
1344
1345//--- Display
1346
1347impl<Octs, Name> fmt::Display for Rrsig<Octs, Name>
1348where
1349    Octs: AsRef<[u8]>,
1350    Name: fmt::Display,
1351{
1352    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1353        write!(
1354            f,
1355            "{} {} {} {} {} {} {} {}. ",
1356            self.type_covered,
1357            self.algorithm,
1358            self.labels,
1359            self.original_ttl.as_secs(),
1360            self.expiration,
1361            self.inception,
1362            self.key_tag,
1363            self.signer_name
1364        )?;
1365        base64::display(&self.signature, f)
1366    }
1367}
1368
1369//--- Debug
1370
1371impl<Octs, Name> fmt::Debug for Rrsig<Octs, Name>
1372where
1373    Octs: AsRef<[u8]>,
1374    Name: fmt::Debug,
1375{
1376    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1377        f.debug_struct("Rrsig")
1378            .field("type_covered", &self.type_covered)
1379            .field("algorithm", &self.algorithm)
1380            .field("labels", &self.labels)
1381            .field("original_ttl", &self.original_ttl)
1382            .field("expiration", &self.expiration)
1383            .field("inception", &self.inception)
1384            .field("key_tag", &self.key_tag)
1385            .field("signer_name", &self.signer_name)
1386            .field("signature", &self.signature.as_ref())
1387            .finish()
1388    }
1389}
1390
1391//--- ZonefileFmt
1392
1393impl<Octs, Name> ZonefileFmt for Rrsig<Octs, Name>
1394where
1395    Octs: AsRef<[u8]>,
1396    Name: ToName,
1397{
1398    fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
1399        p.block(|p| {
1400            p.write_show(self.type_covered)?;
1401            p.write_show(self.algorithm)?;
1402            p.write_token(self.labels)?;
1403            p.write_comment("labels")?;
1404            p.write_show(self.original_ttl)?;
1405            p.write_comment("original ttl")?;
1406            p.write_show(self.expiration)?;
1407            p.write_comment("expiration")?;
1408            p.write_show(self.inception)?;
1409            p.write_comment("inception")?;
1410            p.write_token(self.key_tag)?;
1411            p.write_comment("key tag")?;
1412            p.write_token(self.signer_name.fmt_with_dot())?;
1413            p.write_comment("signer name")?;
1414            p.write_token(base64::encode_display(&self.signature))
1415        })
1416    }
1417}
1418
1419//------------ Nsec ----------------------------------------------------------
1420
1421#[derive(Clone)]
1422#[cfg_attr(
1423    feature = "serde",
1424    derive(serde::Serialize, serde::Deserialize),
1425    serde(bound(
1426        serialize = "
1427            Octs: octseq::serde::SerializeOctets + AsRef<[u8]>,
1428            Name: serde::Serialize,
1429        ",
1430        deserialize = "
1431            Octs: FromBuilder + octseq::serde::DeserializeOctets<'de>,
1432            <Octs as FromBuilder>::Builder:
1433                OctetsBuilder + EmptyBuilder + Truncate 
1434                + AsRef<[u8]> + AsMut<[u8]>,
1435            Name: serde::Deserialize<'de>,
1436        ",
1437    ))
1438)]
1439pub struct Nsec<Octs, Name> {
1440    next_name: Name,
1441    types: RtypeBitmap<Octs>,
1442}
1443
1444impl Nsec<(), ()> {
1445    /// The rtype of this record data type.
1446    pub(crate) const RTYPE: Rtype = Rtype::NSEC;
1447}
1448
1449impl<Octs, Name> Nsec<Octs, Name> {
1450    pub fn new(next_name: Name, types: RtypeBitmap<Octs>) -> Self {
1451        Nsec { next_name, types }
1452    }
1453
1454    pub fn next_name(&self) -> &Name {
1455        &self.next_name
1456    }
1457
1458    pub fn set_next_name(&mut self, next_name: Name) {
1459        self.next_name = next_name
1460    }
1461
1462    pub fn types(&self) -> &RtypeBitmap<Octs> {
1463        &self.types
1464    }
1465
1466    pub(super) fn convert_octets<TOcts, TName>(
1467        self,
1468    ) -> Result<Nsec<TOcts, TName>, TOcts::Error>
1469    where
1470        TOcts: OctetsFrom<Octs>,
1471        TName: OctetsFrom<Name, Error = TOcts::Error>,
1472    {
1473        Ok(Nsec::new(
1474            self.next_name.try_octets_into()?,
1475            self.types.convert_octets()?,
1476        ))
1477    }
1478
1479    pub(super) fn flatten<TOcts, TName>(
1480        self,
1481    ) -> Result<Nsec<TOcts, TName>, TOcts::Error>
1482    where
1483        TOcts: OctetsFrom<Octs>,
1484        Name: FlattenInto<TName, AppendError = TOcts::Error>,
1485    {
1486        Ok(Nsec::new(
1487            self.next_name.try_flatten_into()?,
1488            self.types.convert_octets()?,
1489        ))
1490    }
1491
1492    pub fn scan<S: Scanner<Octets = Octs, Name = Name>>(
1493        scanner: &mut S,
1494    ) -> Result<Self, S::Error> {
1495        Ok(Self::new(scanner.scan_name()?, RtypeBitmap::scan(scanner)?))
1496    }
1497}
1498
1499impl<Octs: AsRef<[u8]>> Nsec<Octs, ParsedName<Octs>> {
1500    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized + 'a>(
1501        parser: &mut Parser<'a, Src>,
1502    ) -> Result<Self, ParseError> {
1503        Ok(Nsec::new(
1504            ParsedName::parse(parser)?,
1505            RtypeBitmap::parse(parser)?,
1506        ))
1507    }
1508}
1509
1510//--- OctetsFrom and FlattenInto
1511
1512impl<Octs, SrcOcts, Name, SrcName> OctetsFrom<Nsec<SrcOcts, SrcName>>
1513    for Nsec<Octs, Name>
1514where
1515    Octs: OctetsFrom<SrcOcts>,
1516    Name: OctetsFrom<SrcName, Error = Octs::Error>,
1517{
1518    type Error = Octs::Error;
1519
1520    fn try_octets_from(
1521        source: Nsec<SrcOcts, SrcName>,
1522    ) -> Result<Self, Self::Error> {
1523        Ok(Nsec::new(
1524            Name::try_octets_from(source.next_name)?,
1525            RtypeBitmap::try_octets_from(source.types)?,
1526        ))
1527    }
1528}
1529
1530impl<Octs, TOcts, Name, TName> FlattenInto<Nsec<TOcts, TName>>
1531    for Nsec<Octs, Name>
1532where
1533    TOcts: OctetsFrom<Octs>,
1534    Name: FlattenInto<TName, AppendError = TOcts::Error>,
1535{
1536    type AppendError = TOcts::Error;
1537
1538    fn try_flatten_into(self) -> Result<Nsec<TOcts, TName>, TOcts::Error> {
1539        self.flatten()
1540    }
1541}
1542
1543//--- PartialEq and Eq
1544
1545impl<O, OO, N, NN> PartialEq<Nsec<OO, NN>> for Nsec<O, N>
1546where
1547    O: AsRef<[u8]>,
1548    OO: AsRef<[u8]>,
1549    N: ToName,
1550    NN: ToName,
1551{
1552    fn eq(&self, other: &Nsec<OO, NN>) -> bool {
1553        self.next_name.name_eq(&other.next_name) && self.types == other.types
1554    }
1555}
1556
1557impl<O: AsRef<[u8]>, N: ToName> Eq for Nsec<O, N> {}
1558
1559//--- PartialOrd, Ord, and CanonicalOrd
1560
1561impl<O, OO, N, NN> PartialOrd<Nsec<OO, NN>> for Nsec<O, N>
1562where
1563    O: AsRef<[u8]>,
1564    OO: AsRef<[u8]>,
1565    N: ToName,
1566    NN: ToName,
1567{
1568    fn partial_cmp(&self, other: &Nsec<OO, NN>) -> Option<Ordering> {
1569        match self.next_name.name_cmp(&other.next_name) {
1570            Ordering::Equal => {}
1571            other => return Some(other),
1572        }
1573        self.types.partial_cmp(&self.types)
1574    }
1575}
1576
1577impl<O, OO, N, NN> CanonicalOrd<Nsec<OO, NN>> for Nsec<O, N>
1578where
1579    O: AsRef<[u8]>,
1580    OO: AsRef<[u8]>,
1581    N: ToName,
1582    NN: ToName,
1583{
1584    fn canonical_cmp(&self, other: &Nsec<OO, NN>) -> Ordering {
1585        // RFC 6840 says that Nsec::next_name is not converted to lower case.
1586        match self.next_name.composed_cmp(&other.next_name) {
1587            Ordering::Equal => {}
1588            other => return other,
1589        }
1590        self.types.cmp(&self.types)
1591    }
1592}
1593
1594impl<O, N> Ord for Nsec<O, N>
1595where
1596    O: AsRef<[u8]>,
1597    N: ToName,
1598{
1599    fn cmp(&self, other: &Self) -> Ordering {
1600        match self.next_name.name_cmp(&other.next_name) {
1601            Ordering::Equal => {}
1602            other => return other,
1603        }
1604        self.types.cmp(&self.types)
1605    }
1606}
1607
1608//--- Hash
1609
1610impl<Octs: AsRef<[u8]>, Name: hash::Hash> hash::Hash for Nsec<Octs, Name> {
1611    fn hash<H: hash::Hasher>(&self, state: &mut H) {
1612        self.next_name.hash(state);
1613        self.types.hash(state);
1614    }
1615}
1616
1617//--- RecordData, ParseRecordData, ComposeRecordData
1618
1619impl<Octs, Name> RecordData for Nsec<Octs, Name> {
1620    fn rtype(&self) -> Rtype {
1621        Nsec::RTYPE
1622    }
1623}
1624
1625impl<'a, Octs: Octets + ?Sized> ParseRecordData<'a, Octs>
1626    for Nsec<Octs::Range<'a>, ParsedName<Octs::Range<'a>>>
1627{
1628    fn parse_rdata(
1629        rtype: Rtype,
1630        parser: &mut Parser<'a, Octs>,
1631    ) -> Result<Option<Self>, ParseError> {
1632        if rtype == Nsec::RTYPE {
1633            Self::parse(parser).map(Some)
1634        } else {
1635            Ok(None)
1636        }
1637    }
1638}
1639
1640impl<Octs, Name> ComposeRecordData for Nsec<Octs, Name>
1641where
1642    Octs: AsRef<[u8]>,
1643    Name: ToName,
1644{
1645    fn rdlen(&self, _compress: bool) -> Option<u16> {
1646        Some(
1647            self.next_name
1648                .compose_len()
1649                .checked_add(self.types.compose_len())
1650                .expect("long type bitmap"),
1651        )
1652    }
1653
1654    fn compose_rdata<Target: Composer + ?Sized>(
1655        &self,
1656        target: &mut Target,
1657    ) -> Result<(), Target::AppendError> {
1658        self.next_name.compose(target)?;
1659        self.types.compose(target)
1660    }
1661
1662    fn compose_canonical_rdata<Target: Composer + ?Sized>(
1663        &self,
1664        target: &mut Target,
1665    ) -> Result<(), Target::AppendError> {
1666        // Deferring to compose_rdata is correct as we keep the case of the
1667        // next name.
1668        self.compose_rdata(target)
1669    }
1670}
1671
1672//--- Display
1673
1674impl<Octs, Name> fmt::Display for Nsec<Octs, Name>
1675where
1676    Octs: AsRef<[u8]>,
1677    Name: fmt::Display,
1678{
1679    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1680        write!(f, "{}. {}", self.next_name, self.types)
1681    }
1682}
1683
1684//--- Debug
1685
1686impl<Octs, Name> fmt::Debug for Nsec<Octs, Name>
1687where
1688    Octs: AsRef<[u8]>,
1689    Name: fmt::Debug,
1690{
1691    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1692        f.debug_struct("Nsec")
1693            .field("next_name", &self.next_name)
1694            .field("types", &self.types)
1695            .finish()
1696    }
1697}
1698
1699//--- ZonefileFmt
1700
1701impl<Octs, Name> ZonefileFmt for Nsec<Octs, Name>
1702where
1703    Octs: AsRef<[u8]>,
1704    Name: ToName,
1705{
1706    fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
1707        p.block(|p| {
1708            p.write_token(self.next_name.fmt_with_dot())?;
1709            p.write_show(&self.types)
1710        })
1711    }
1712}
1713
1714//------------ Ds -----------------------------------------------------------
1715
1716#[derive(Clone)]
1717#[cfg_attr(
1718    feature = "serde",
1719    derive(serde::Serialize, serde::Deserialize),
1720    serde(bound(
1721        serialize = "
1722            Octs: octseq::serde::SerializeOctets + AsRef<[u8]>
1723        ",
1724        deserialize = "
1725            Octs: FromBuilder + octseq::serde::DeserializeOctets<'de>,
1726            <Octs as FromBuilder>::Builder:
1727                OctetsBuilder + EmptyBuilder,
1728        ",
1729    ))
1730)]
1731pub struct Ds<Octs> {
1732    key_tag: u16,
1733    algorithm: SecurityAlgorithm,
1734    digest_type: DigestAlgorithm,
1735    #[cfg_attr(
1736        feature = "serde",
1737        serde(with = "crate::utils::base16::serde")
1738    )]
1739    digest: Octs,
1740}
1741
1742impl Ds<()> {
1743    /// The rtype of this record data type.
1744    pub(crate) const RTYPE: Rtype = Rtype::DS;
1745}
1746
1747impl<Octs> Ds<Octs> {
1748    pub fn new(
1749        key_tag: u16,
1750        algorithm: SecurityAlgorithm,
1751        digest_type: DigestAlgorithm,
1752        digest: Octs,
1753    ) -> Result<Self, LongRecordData>
1754    where
1755        Octs: AsRef<[u8]>,
1756    {
1757        LongRecordData::check_len(
1758            usize::from(
1759                u16::COMPOSE_LEN
1760                    + SecurityAlgorithm::COMPOSE_LEN
1761                    + DigestAlgorithm::COMPOSE_LEN,
1762            )
1763            .checked_add(digest.as_ref().len())
1764            .expect("long digest"),
1765        )?;
1766        Ok(unsafe {
1767            Ds::new_unchecked(key_tag, algorithm, digest_type, digest)
1768        })
1769    }
1770
1771    /// Creates new DS record data without checking.
1772    ///
1773    /// # Safety
1774    ///
1775    /// The caller needs to ensure that wire format representation of the
1776    /// record data is at most 65,535 octets long.
1777    pub unsafe fn new_unchecked(
1778        key_tag: u16,
1779        algorithm: SecurityAlgorithm,
1780        digest_type: DigestAlgorithm,
1781        digest: Octs,
1782    ) -> Self {
1783        Ds {
1784            key_tag,
1785            algorithm,
1786            digest_type,
1787            digest,
1788        }
1789    }
1790
1791    pub fn key_tag(&self) -> u16 {
1792        self.key_tag
1793    }
1794
1795    pub fn algorithm(&self) -> SecurityAlgorithm {
1796        self.algorithm
1797    }
1798
1799    pub fn digest_type(&self) -> DigestAlgorithm {
1800        self.digest_type
1801    }
1802
1803    pub fn digest(&self) -> &Octs {
1804        &self.digest
1805    }
1806
1807    pub fn into_digest(self) -> Octs {
1808        self.digest
1809    }
1810
1811    pub(super) fn convert_octets<Target: OctetsFrom<Octs>>(
1812        self,
1813    ) -> Result<Ds<Target>, Target::Error> {
1814        Ok(unsafe {
1815            Ds::new_unchecked(
1816                self.key_tag,
1817                self.algorithm,
1818                self.digest_type,
1819                self.digest.try_octets_into()?,
1820            )
1821        })
1822    }
1823
1824    pub(super) fn flatten<Target: OctetsFrom<Octs>>(
1825        self,
1826    ) -> Result<Ds<Target>, Target::Error> {
1827        self.convert_octets()
1828    }
1829
1830    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
1831        parser: &mut Parser<'a, Src>,
1832    ) -> Result<Self, ParseError> {
1833        let len = match parser.remaining().checked_sub(4) {
1834            Some(len) => len,
1835            None => return Err(ParseError::ShortInput),
1836        };
1837        Ok(unsafe {
1838            Self::new_unchecked(
1839                u16::parse(parser)?,
1840                SecurityAlgorithm::parse(parser)?,
1841                DigestAlgorithm::parse(parser)?,
1842                parser.parse_octets(len)?,
1843            )
1844        })
1845    }
1846
1847    pub fn scan<S: Scanner<Octets = Octs>>(
1848        scanner: &mut S,
1849    ) -> Result<Self, S::Error>
1850    where
1851        Octs: AsRef<[u8]>,
1852    {
1853        Self::new(
1854            u16::scan(scanner)?,
1855            SecurityAlgorithm::scan(scanner)?,
1856            DigestAlgorithm::scan(scanner)?,
1857            scanner.convert_entry(base16::SymbolConverter::new())?,
1858        )
1859        .map_err(|err| S::Error::custom(err.as_str()))
1860    }
1861}
1862
1863//--- OctetsFrom
1864
1865impl<Octs, SrcOcts> OctetsFrom<Ds<SrcOcts>> for Ds<Octs>
1866where
1867    Octs: OctetsFrom<SrcOcts>,
1868{
1869    type Error = Octs::Error;
1870
1871    fn try_octets_from(source: Ds<SrcOcts>) -> Result<Self, Self::Error> {
1872        Ok(unsafe {
1873            Ds::new_unchecked(
1874                source.key_tag,
1875                source.algorithm,
1876                source.digest_type,
1877                Octs::try_octets_from(source.digest)?,
1878            )
1879        })
1880    }
1881}
1882
1883//--- PartialEq and Eq
1884
1885impl<Octs, Other> PartialEq<Ds<Other>> for Ds<Octs>
1886where
1887    Octs: AsRef<[u8]>,
1888    Other: AsRef<[u8]>,
1889{
1890    fn eq(&self, other: &Ds<Other>) -> bool {
1891        self.key_tag == other.key_tag
1892            && self.algorithm == other.algorithm
1893            && self.digest_type == other.digest_type
1894            && self.digest.as_ref().eq(other.digest.as_ref())
1895    }
1896}
1897
1898impl<Octs: AsRef<[u8]>> Eq for Ds<Octs> {}
1899
1900//--- PartialOrd, CanonicalOrd, and Ord
1901
1902impl<Octs, Other> PartialOrd<Ds<Other>> for Ds<Octs>
1903where
1904    Octs: AsRef<[u8]>,
1905    Other: AsRef<[u8]>,
1906{
1907    fn partial_cmp(&self, other: &Ds<Other>) -> Option<Ordering> {
1908        match self.key_tag.partial_cmp(&other.key_tag) {
1909            Some(Ordering::Equal) => {}
1910            other => return other,
1911        }
1912        match self.algorithm.partial_cmp(&other.algorithm) {
1913            Some(Ordering::Equal) => {}
1914            other => return other,
1915        }
1916        match self.digest_type.partial_cmp(&other.digest_type) {
1917            Some(Ordering::Equal) => {}
1918            other => return other,
1919        }
1920        self.digest.as_ref().partial_cmp(other.digest.as_ref())
1921    }
1922}
1923
1924impl<Octs, Other> CanonicalOrd<Ds<Other>> for Ds<Octs>
1925where
1926    Octs: AsRef<[u8]>,
1927    Other: AsRef<[u8]>,
1928{
1929    fn canonical_cmp(&self, other: &Ds<Other>) -> Ordering {
1930        match self.key_tag.cmp(&other.key_tag) {
1931            Ordering::Equal => {}
1932            other => return other,
1933        }
1934        match self.algorithm.cmp(&other.algorithm) {
1935            Ordering::Equal => {}
1936            other => return other,
1937        }
1938        match self.digest_type.cmp(&other.digest_type) {
1939            Ordering::Equal => {}
1940            other => return other,
1941        }
1942        self.digest.as_ref().cmp(other.digest.as_ref())
1943    }
1944}
1945
1946impl<Octs: AsRef<[u8]>> Ord for Ds<Octs> {
1947    fn cmp(&self, other: &Self) -> Ordering {
1948        self.canonical_cmp(other)
1949    }
1950}
1951
1952//--- Hash
1953
1954impl<Octs: AsRef<[u8]>> hash::Hash for Ds<Octs> {
1955    fn hash<H: hash::Hasher>(&self, state: &mut H) {
1956        self.key_tag.hash(state);
1957        self.algorithm.hash(state);
1958        self.digest_type.hash(state);
1959        self.digest.as_ref().hash(state);
1960    }
1961}
1962
1963//--- RecordData, ParseRecordData, ComposeRecordData
1964
1965impl<Octs> RecordData for Ds<Octs> {
1966    fn rtype(&self) -> Rtype {
1967        Ds::RTYPE
1968    }
1969}
1970
1971impl<'a, Octs> ParseRecordData<'a, Octs> for Ds<Octs::Range<'a>>
1972where
1973    Octs: Octets + ?Sized,
1974{
1975    fn parse_rdata(
1976        rtype: Rtype,
1977        parser: &mut Parser<'a, Octs>,
1978    ) -> Result<Option<Self>, ParseError> {
1979        if rtype == Ds::RTYPE {
1980            Self::parse(parser).map(Some)
1981        } else {
1982            Ok(None)
1983        }
1984    }
1985}
1986
1987impl<Octs: AsRef<[u8]>> ComposeRecordData for Ds<Octs> {
1988    fn rdlen(&self, _compress: bool) -> Option<u16> {
1989        Some(
1990            u16::checked_add(
1991                u16::COMPOSE_LEN
1992                    + SecurityAlgorithm::COMPOSE_LEN
1993                    + DigestAlgorithm::COMPOSE_LEN,
1994                self.digest.as_ref().len().try_into().expect("long digest"),
1995            )
1996            .expect("long digest"),
1997        )
1998    }
1999
2000    fn compose_rdata<Target: Composer + ?Sized>(
2001        &self,
2002        target: &mut Target,
2003    ) -> Result<(), Target::AppendError> {
2004        self.key_tag.compose(target)?;
2005        self.algorithm.compose(target)?;
2006        self.digest_type.compose(target)?;
2007        target.append_slice(self.digest.as_ref())
2008    }
2009
2010    fn compose_canonical_rdata<Target: Composer + ?Sized>(
2011        &self,
2012        target: &mut Target,
2013    ) -> Result<(), Target::AppendError> {
2014        self.compose_rdata(target)
2015    }
2016}
2017
2018//--- Display
2019
2020impl<Octs: AsRef<[u8]>> fmt::Display for Ds<Octs> {
2021    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2022        write!(
2023            f,
2024            "{} {} {} ",
2025            self.key_tag, self.algorithm, self.digest_type
2026        )?;
2027        for ch in self.digest.as_ref() {
2028            write!(f, "{:02x}", ch)?
2029        }
2030        Ok(())
2031    }
2032}
2033
2034//--- Debug
2035
2036impl<Octs: AsRef<[u8]>> fmt::Debug for Ds<Octs> {
2037    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2038        f.debug_struct("Ds")
2039            .field("key_tag", &self.key_tag)
2040            .field("algorithm", &self.algorithm)
2041            .field("digest_type", &self.digest_type)
2042            .field("digest", &self.digest.as_ref())
2043            .finish()
2044    }
2045}
2046
2047//--- ZonefileFmt
2048
2049impl<Octs: AsRef<[u8]>> ZonefileFmt for Ds<Octs> {
2050    fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
2051        p.block(|p| {
2052            p.write_token(self.key_tag)?;
2053            p.write_comment("key tag")?;
2054            p.write_show(self.algorithm)?;
2055            p.write_show(self.digest_type)?;
2056            p.write_token(base16::encode_display(&self.digest))
2057        })
2058    }
2059}
2060
2061//------------ RtypeBitmap ---------------------------------------------------
2062
2063#[derive(Clone)]
2064pub struct RtypeBitmap<Octs>(Octs);
2065
2066impl<Octs> RtypeBitmap<Octs> {
2067    pub fn from_octets(octets: Octs) -> Result<Self, RtypeBitmapError>
2068    where
2069        Octs: AsRef<[u8]>,
2070    {
2071        {
2072            let mut data = octets.as_ref();
2073            while !data.is_empty() {
2074                // At least bitmap number and length must be present.
2075                if data.len() < 2 {
2076                    return Err(RtypeBitmapErrorEnum::ShortInput.into());
2077                }
2078
2079                let len = (data[1] as usize) + 2;
2080                // https://tools.ietf.org/html/rfc4034#section-4.1.2:
2081                //  Blocks with no types present MUST NOT be included.
2082                if len == 2 {
2083                    return Err(RtypeBitmapErrorEnum::BadRtypeBitmap.into());
2084                }
2085                if len > 34 {
2086                    return Err(RtypeBitmapErrorEnum::BadRtypeBitmap.into());
2087                }
2088                if data.len() < len {
2089                    return Err(RtypeBitmapErrorEnum::ShortInput.into());
2090                }
2091                data = &data[len..];
2092            }
2093        }
2094        Ok(RtypeBitmap(octets))
2095    }
2096
2097    #[must_use]
2098    pub fn builder() -> RtypeBitmapBuilder<Octs::Builder>
2099    where
2100        Octs: FromBuilder,
2101        <Octs as FromBuilder>::Builder: EmptyBuilder,
2102    {
2103        RtypeBitmapBuilder::new()
2104    }
2105
2106    pub fn scan<S: Scanner<Octets = Octs>>(
2107        scanner: &mut S,
2108    ) -> Result<Self, S::Error> {
2109        let mut builder =
2110            RtypeBitmapBuilder::with_builder(scanner.octets_builder()?);
2111        while scanner.continues() {
2112            builder
2113                .add(Rtype::scan(scanner)?)
2114                .map_err(|_| S::Error::short_buf())?;
2115        }
2116        Ok(builder.finalize())
2117    }
2118
2119    pub fn as_octets(&self) -> &Octs {
2120        &self.0
2121    }
2122
2123    pub(super) fn convert_octets<Target: OctetsFrom<Octs>>(
2124        self,
2125    ) -> Result<RtypeBitmap<Target>, Target::Error> {
2126        Ok(RtypeBitmap(self.0.try_octets_into()?))
2127    }
2128}
2129
2130impl<Octs: AsRef<[u8]>> RtypeBitmap<Octs> {
2131    pub fn as_slice(&self) -> &[u8] {
2132        self.0.as_ref()
2133    }
2134
2135    pub fn iter(&self) -> RtypeBitmapIter {
2136        RtypeBitmapIter::new(self.0.as_ref())
2137    }
2138
2139    pub fn contains(&self, rtype: Rtype) -> bool {
2140        let (block, octet, mask) = split_rtype(rtype);
2141        let mut data = self.0.as_ref();
2142        while !data.is_empty() {
2143            let ((window_num, window), next_data) =
2144                read_window(data).unwrap();
2145            if window_num == block {
2146                return !(window.len() <= octet || window[octet] & mask == 0);
2147            }
2148            data = next_data;
2149        }
2150        false
2151    }
2152
2153    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
2154        parser: &mut Parser<'a, Src>,
2155    ) -> Result<Self, ParseError> {
2156        let len = parser.remaining();
2157        RtypeBitmap::from_octets(parser.parse_octets(len)?)
2158            .map_err(Into::into)
2159    }
2160
2161    pub fn compose_len(&self) -> u16 {
2162        u16::try_from(self.0.as_ref().len()).expect("long rtype bitmap")
2163    }
2164
2165    pub fn compose<Target: OctetsBuilder + ?Sized>(
2166        &self,
2167        target: &mut Target,
2168    ) -> Result<(), Target::AppendError> {
2169        target.append_slice(self.0.as_ref())
2170    }
2171
2172    #[must_use]
2173    pub fn is_empty(&self) -> bool {
2174        self.iter().next().is_none()
2175    }
2176}
2177
2178//--- AsRef
2179
2180impl<T, Octs: AsRef<T>> AsRef<T> for RtypeBitmap<Octs> {
2181    fn as_ref(&self) -> &T {
2182        self.0.as_ref()
2183    }
2184}
2185
2186//--- OctetsFrom
2187
2188impl<Octs, SrcOcts> OctetsFrom<RtypeBitmap<SrcOcts>> for RtypeBitmap<Octs>
2189where
2190    Octs: OctetsFrom<SrcOcts>,
2191{
2192    type Error = Octs::Error;
2193
2194    fn try_octets_from(
2195        source: RtypeBitmap<SrcOcts>,
2196    ) -> Result<Self, Self::Error> {
2197        Octs::try_octets_from(source.0).map(RtypeBitmap)
2198    }
2199}
2200
2201//--- PartialEq and Eq
2202
2203impl<O, OO> PartialEq<RtypeBitmap<OO>> for RtypeBitmap<O>
2204where
2205    O: AsRef<[u8]>,
2206    OO: AsRef<[u8]>,
2207{
2208    fn eq(&self, other: &RtypeBitmap<OO>) -> bool {
2209        self.0.as_ref().eq(other.0.as_ref())
2210    }
2211}
2212
2213impl<O: AsRef<[u8]>> Eq for RtypeBitmap<O> {}
2214
2215//--- PartialOrd, CanonicalOrd, and Ord
2216
2217impl<O, OO> PartialOrd<RtypeBitmap<OO>> for RtypeBitmap<O>
2218where
2219    O: AsRef<[u8]>,
2220    OO: AsRef<[u8]>,
2221{
2222    fn partial_cmp(&self, other: &RtypeBitmap<OO>) -> Option<Ordering> {
2223        self.0.as_ref().partial_cmp(other.0.as_ref())
2224    }
2225}
2226
2227impl<O, OO> CanonicalOrd<RtypeBitmap<OO>> for RtypeBitmap<O>
2228where
2229    O: AsRef<[u8]>,
2230    OO: AsRef<[u8]>,
2231{
2232    fn canonical_cmp(&self, other: &RtypeBitmap<OO>) -> Ordering {
2233        self.0.as_ref().cmp(other.0.as_ref())
2234    }
2235}
2236
2237impl<O: AsRef<[u8]>> Ord for RtypeBitmap<O> {
2238    fn cmp(&self, other: &Self) -> Ordering {
2239        self.0.as_ref().cmp(other.0.as_ref())
2240    }
2241}
2242
2243//--- Hash
2244
2245impl<O: AsRef<[u8]>> hash::Hash for RtypeBitmap<O> {
2246    fn hash<H: hash::Hasher>(&self, state: &mut H) {
2247        self.0.as_ref().hash(state)
2248    }
2249}
2250
2251//--- IntoIterator
2252
2253impl<'a, Octs: AsRef<[u8]>> IntoIterator for &'a RtypeBitmap<Octs> {
2254    type Item = Rtype;
2255    type IntoIter = RtypeBitmapIter<'a>;
2256
2257    fn into_iter(self) -> Self::IntoIter {
2258        self.iter()
2259    }
2260}
2261
2262//--- Display
2263
2264impl<Octs: AsRef<[u8]>> fmt::Display for RtypeBitmap<Octs> {
2265    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2266        let mut iter = self.iter();
2267        if let Some(rtype) = iter.next() {
2268            fmt::Display::fmt(&rtype, f)?;
2269        }
2270        for rtype in iter {
2271            write!(f, " {}", rtype)?
2272        }
2273        Ok(())
2274    }
2275}
2276
2277//--- ZonefileFmt
2278
2279impl<Octs: AsRef<[u8]>> ZonefileFmt for RtypeBitmap<Octs> {
2280    fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
2281        for rtype in self {
2282            p.write_token(rtype)?;
2283        }
2284        Ok(())
2285    }
2286}
2287
2288//--- Debug
2289
2290impl<Octs: AsRef<[u8]>> fmt::Debug for RtypeBitmap<Octs> {
2291    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2292        f.write_str("RtypeBitmap(")?;
2293        fmt::Display::fmt(self, f)?;
2294        f.write_str(")")
2295    }
2296}
2297
2298//--- Serialize and Deserialize
2299
2300#[cfg(feature = "serde")]
2301impl<Octs> serde::Serialize for RtypeBitmap<Octs>
2302where
2303    Octs: AsRef<[u8]> + SerializeOctets,
2304{
2305    fn serialize<S: serde::Serializer>(
2306        &self,
2307        serializer: S,
2308    ) -> Result<S::Ok, S::Error> {
2309        if serializer.is_human_readable() {
2310            struct Inner<'a>(&'a [u8]);
2311
2312            impl serde::Serialize for Inner<'_> {
2313                fn serialize<S: serde::Serializer>(
2314                    &self,
2315                    serializer: S,
2316                ) -> Result<S::Ok, S::Error> {
2317                    use serde::ser::SerializeSeq;
2318
2319                    let mut serializer = serializer.serialize_seq(None)?;
2320                    for item in RtypeBitmapIter::new(self.0) {
2321                        serializer.serialize_element(&item)?;
2322                    }
2323                    serializer.end()
2324                }
2325            }
2326
2327            serializer.serialize_newtype_struct(
2328                "RtypeBitmap",
2329                &Inner(self.0.as_ref()),
2330            )
2331        } else {
2332            serializer.serialize_newtype_struct(
2333                "RtypeBitmap",
2334                &self.0.as_serialized_octets(),
2335            )
2336        }
2337    }
2338}
2339
2340#[cfg(feature = "serde")]
2341impl<'de, Octs> serde::Deserialize<'de> for RtypeBitmap<Octs>
2342where
2343    Octs: FromBuilder + DeserializeOctets<'de>,
2344    <Octs as FromBuilder>::Builder:
2345        EmptyBuilder + Truncate + AsRef<[u8]> + AsMut<[u8]>,
2346{
2347    fn deserialize<D: serde::Deserializer<'de>>(
2348        deserializer: D,
2349    ) -> Result<Self, D::Error> {
2350        use core::marker::PhantomData;
2351
2352        struct InnerVisitor<'de, T: DeserializeOctets<'de>>(T::Visitor);
2353
2354        impl<'de, Octs> serde::de::Visitor<'de> for InnerVisitor<'de, Octs>
2355        where
2356            Octs: FromBuilder + DeserializeOctets<'de>,
2357            <Octs as FromBuilder>::Builder: OctetsBuilder
2358                + EmptyBuilder
2359                + Truncate
2360                + AsRef<[u8]>
2361                + AsMut<[u8]>,
2362        {
2363            type Value = RtypeBitmap<Octs>;
2364
2365            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
2366                f.write_str("a record type bitmap")
2367            }
2368
2369            fn visit_seq<A: serde::de::SeqAccess<'de>>(
2370                self,
2371                mut seq: A,
2372            ) -> Result<Self::Value, A::Error> {
2373                use serde::de::Error;
2374
2375                let mut builder = RtypeBitmap::<Octs>::builder();
2376                while let Some(element) = seq.next_element()? {
2377                    builder.add(element).map_err(|_| {
2378                        A::Error::custom(octseq::builder::ShortBuf)
2379                    })?;
2380                }
2381
2382                Ok(builder.finalize())
2383            }
2384
2385            fn visit_borrowed_bytes<E: serde::de::Error>(
2386                self,
2387                value: &'de [u8],
2388            ) -> Result<Self::Value, E> {
2389                self.0.visit_borrowed_bytes(value).and_then(|octets| {
2390                    RtypeBitmap::from_octets(octets).map_err(E::custom)
2391                })
2392            }
2393
2394            #[cfg(feature = "std")]
2395            fn visit_byte_buf<E: serde::de::Error>(
2396                self,
2397                value: std::vec::Vec<u8>,
2398            ) -> Result<Self::Value, E> {
2399                self.0.visit_byte_buf(value).and_then(|octets| {
2400                    RtypeBitmap::from_octets(octets).map_err(E::custom)
2401                })
2402            }
2403        }
2404
2405        struct NewtypeVisitor<T>(PhantomData<T>);
2406
2407        impl<'de, Octs> serde::de::Visitor<'de> for NewtypeVisitor<Octs>
2408        where
2409            Octs: FromBuilder + DeserializeOctets<'de>,
2410            <Octs as FromBuilder>::Builder: OctetsBuilder
2411                + EmptyBuilder
2412                + Truncate
2413                + AsRef<[u8]>
2414                + AsMut<[u8]>,
2415        {
2416            type Value = RtypeBitmap<Octs>;
2417
2418            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
2419                f.write_str("a record type bitmap")
2420            }
2421
2422            fn visit_newtype_struct<D: serde::Deserializer<'de>>(
2423                self,
2424                deserializer: D,
2425            ) -> Result<Self::Value, D::Error> {
2426                if deserializer.is_human_readable() {
2427                    deserializer
2428                        .deserialize_seq(InnerVisitor(Octs::visitor()))
2429                } else {
2430                    Octs::deserialize_with_visitor(
2431                        deserializer,
2432                        InnerVisitor(Octs::visitor()),
2433                    )
2434                }
2435            }
2436        }
2437
2438        deserializer.deserialize_newtype_struct(
2439            "RtypeBitmap",
2440            NewtypeVisitor(PhantomData),
2441        )
2442    }
2443}
2444
2445//------------ RtypeBitmapBuilder --------------------------------------------
2446
2447/// A builder for a record type bitmap.
2448//
2449//  Here is how this is going to work: We keep one long Builder into which
2450//  we place all added types. The buffer contains a sequence of blocks
2451//  encoded similarly to the final format but with all 32 octets of the
2452//  bitmap present. Blocks are in order and are only added when needed (which
2453//  means we may have to insert a block in the middle). When finalizing, we
2454//  compress the block buffer by dropping the unncessary octets of each
2455//  block.
2456#[derive(Clone, Debug)]
2457pub struct RtypeBitmapBuilder<Builder> {
2458    buf: Builder,
2459}
2460
2461impl<Builder: OctetsBuilder> RtypeBitmapBuilder<Builder> {
2462    #[must_use]
2463    pub fn new() -> Self
2464    where
2465        Builder: EmptyBuilder,
2466    {
2467        RtypeBitmapBuilder {
2468            // Start out with the capacity for one block.
2469            buf: Builder::with_capacity(34),
2470        }
2471    }
2472
2473    pub fn with_builder(builder: Builder) -> Self {
2474        RtypeBitmapBuilder { buf: builder }
2475    }
2476}
2477
2478#[cfg(feature = "std")]
2479impl RtypeBitmapBuilder<Vec<u8>> {
2480    #[must_use]
2481    pub fn new_vec() -> Self {
2482        Self::new()
2483    }
2484}
2485
2486impl<Builder> RtypeBitmapBuilder<Builder>
2487where
2488    Builder: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>,
2489{
2490    pub fn add(&mut self, rtype: Rtype) -> Result<(), Builder::AppendError> {
2491        let (block, octet, bit) = split_rtype(rtype);
2492        let block = self.get_block(block)?;
2493        if (block[1] as usize) < (octet + 1) {
2494            block[1] = (octet + 1) as u8
2495        }
2496        block[octet + 2] |= bit;
2497        Ok(())
2498    }
2499
2500    fn get_block(
2501        &mut self,
2502        block: u8,
2503    ) -> Result<&mut [u8], Builder::AppendError> {
2504        let mut pos = 0;
2505        while pos < self.buf.as_ref().len() {
2506            match self.buf.as_ref()[pos].cmp(&block) {
2507                Ordering::Equal => {
2508                    return Ok(&mut self.buf.as_mut()[pos..pos + 34])
2509                }
2510                Ordering::Greater => {
2511                    // We need the length from before we add the new block
2512                    let len = self.buf.as_ref().len();
2513
2514                    // Allocate space for the new block
2515                    self.buf.append_slice(&[0; 34])?;
2516
2517                    // Move everything after this block back by 34 bytes
2518                    let buf = self.buf.as_mut();
2519                    buf.copy_within(pos..len, pos + 34);
2520                    buf[pos..pos + 34].fill(0);
2521                    buf[pos] = block;
2522
2523                    return Ok(&mut buf[pos..pos + 34]);
2524                }
2525                Ordering::Less => pos += 34,
2526            }
2527        }
2528
2529        self.buf.append_slice(&[0; 34])?;
2530        self.buf.as_mut()[pos] = block;
2531        Ok(&mut self.buf.as_mut()[pos..pos + 34])
2532    }
2533
2534    pub fn finalize(mut self) -> RtypeBitmap<Builder::Octets>
2535    where
2536        Builder: FreezeBuilder + Truncate,
2537    {
2538        let mut dst_pos = 0;
2539        let buf_len = self.buf.as_ref().len();
2540        for src_pos in (0..buf_len).step_by(34) {
2541            let chunk_len = (self.buf.as_ref()[src_pos + 1] as usize) + 2;
2542            let buf = self.buf.as_mut();
2543            buf.copy_within(src_pos..src_pos + chunk_len, dst_pos);
2544            dst_pos += chunk_len;
2545        }
2546        self.buf.truncate(dst_pos);
2547        RtypeBitmap(self.buf.freeze())
2548    }
2549}
2550
2551//--- Default
2552
2553impl<Builder> Default for RtypeBitmapBuilder<Builder>
2554where
2555    Builder: OctetsBuilder + EmptyBuilder,
2556{
2557    fn default() -> Self {
2558        Self::new()
2559    }
2560}
2561
2562//------------ RtypeBitmapIter -----------------------------------------------
2563
2564pub struct RtypeBitmapIter<'a> {
2565    /// The data to iterate over.
2566    ///
2567    /// This starts with the octets of the current block without the block
2568    /// number and length.
2569    data: &'a [u8],
2570
2571    /// The base value of the current block, i.e., its upper 8 bits.
2572    block: u16,
2573
2574    /// The length of the current block’s data.
2575    len: usize,
2576
2577    /// Index of the current octet in the current block.
2578    octet: usize,
2579
2580    /// Index of the next set bit in the current octet in the current block.
2581    bit: u16,
2582}
2583
2584impl<'a> RtypeBitmapIter<'a> {
2585    fn new(data: &'a [u8]) -> Self {
2586        if data.is_empty() {
2587            RtypeBitmapIter {
2588                data,
2589                block: 0,
2590                len: 0,
2591                octet: 0,
2592                bit: 0,
2593            }
2594        } else {
2595            let mut res = RtypeBitmapIter {
2596                data: &data[2..],
2597                block: u16::from(data[0]) << 8,
2598                len: usize::from(data[1]),
2599                octet: 0,
2600                bit: 0,
2601            };
2602            if res.data[0] & 0x80 == 0 {
2603                res.advance()
2604            }
2605            res
2606        }
2607    }
2608
2609    fn advance(&mut self) {
2610        loop {
2611            self.bit += 1;
2612            if self.bit == 8 {
2613                self.bit = 0;
2614                self.octet += 1;
2615                if self.octet == self.len {
2616                    self.data = &self.data[self.len..];
2617                    if self.data.is_empty() {
2618                        return;
2619                    }
2620                    self.block = u16::from(self.data[0]) << 8;
2621                    self.len = usize::from(self.data[1]);
2622                    self.data = &self.data[2..];
2623                    self.octet = 0;
2624                }
2625            }
2626            if self.data[self.octet] & (0x80 >> self.bit) != 0 {
2627                return;
2628            }
2629        }
2630    }
2631}
2632
2633impl Iterator for RtypeBitmapIter<'_> {
2634    type Item = Rtype;
2635
2636    fn next(&mut self) -> Option<Self::Item> {
2637        if self.data.is_empty() {
2638            return None;
2639        }
2640        let res =
2641            Rtype::from_int(self.block | ((self.octet as u16) << 3) | self.bit);
2642        self.advance();
2643        Some(res)
2644    }
2645}
2646
2647//============ Error Types ===================================================
2648
2649//------------ RtypeBitmapError ----------------------------------------------
2650
2651#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2652pub struct RtypeBitmapError(RtypeBitmapErrorEnum);
2653
2654#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2655enum RtypeBitmapErrorEnum {
2656    ShortInput,
2657    BadRtypeBitmap,
2658}
2659
2660//--- From
2661
2662impl From<RtypeBitmapError> for ParseError {
2663    fn from(err: RtypeBitmapError) -> ParseError {
2664        match err.0 {
2665            RtypeBitmapErrorEnum::ShortInput => ParseError::ShortInput,
2666            RtypeBitmapErrorEnum::BadRtypeBitmap => {
2667                FormError::new("invalid NSEC bitmap").into()
2668            }
2669        }
2670    }
2671}
2672
2673impl From<RtypeBitmapErrorEnum> for RtypeBitmapError {
2674    fn from(err: RtypeBitmapErrorEnum) -> Self {
2675        Self(err)
2676    }
2677}
2678
2679//--- Display and Error
2680
2681impl fmt::Display for RtypeBitmapError {
2682    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2683        match self.0 {
2684            RtypeBitmapErrorEnum::ShortInput => ParseError::ShortInput.fmt(f),
2685            RtypeBitmapErrorEnum::BadRtypeBitmap => {
2686                f.write_str("invalid record type bitmap")
2687            }
2688        }
2689    }
2690}
2691
2692#[cfg(feature = "std")]
2693impl std::error::Error for RtypeBitmapError {}
2694
2695//============ Friendly Helper Functions =====================================
2696
2697/// Splits an Rtype value into window number, octet number, and octet mask.
2698fn split_rtype(rtype: Rtype) -> (u8, usize, u8) {
2699    let rtype = rtype.to_int();
2700    (
2701        (rtype >> 8) as u8,
2702        ((rtype & 0xFF) >> 3) as usize,
2703        0b1000_0000 >> (rtype & 0x07),
2704    )
2705}
2706
2707/// Splits the next bitmap window from the bitmap and returns None when there's no next window.
2708#[allow(clippy::type_complexity)]
2709fn read_window(data: &[u8]) -> Option<((u8, &[u8]), &[u8])> {
2710    data.split_first().and_then(|(n, data)| {
2711        data.split_first().and_then(|(l, data)| {
2712            if data.len() >= usize::from(*l) {
2713                let (window, data) = data.split_at(usize::from(*l));
2714                Some(((*n, window), data))
2715            } else {
2716                None
2717            }
2718        })
2719    })
2720}
2721
2722//============ Errors ========================================================
2723
2724#[derive(Clone, Copy, Debug)]
2725pub struct IllegalSignatureTime(());
2726
2727impl fmt::Display for IllegalSignatureTime {
2728    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2729        f.write_str("illegal signature time")
2730    }
2731}
2732
2733#[cfg(feature = "std")]
2734impl std::error::Error for IllegalSignatureTime {}
2735
2736//============ Test ==========================================================
2737
2738#[cfg(test)]
2739#[cfg(all(feature = "std", feature = "bytes"))]
2740mod test {
2741    use super::*;
2742    use crate::base::iana::Rtype;
2743    use crate::base::name::Name;
2744    use crate::base::rdata::test::{
2745        test_compose_parse, test_rdlen, test_scan,
2746    };
2747    use core::str::FromStr;
2748    use std::vec::Vec;
2749
2750    //--- Dnskey
2751
2752    #[test]
2753    #[allow(clippy::redundant_closure)] // lifetimes ...
2754    fn dnskey_compose_parse_scan() {
2755        let rdata = Dnskey::new(10, 11, SecurityAlgorithm::RSASHA1, b"key0").unwrap();
2756        test_rdlen(&rdata);
2757        test_compose_parse(&rdata, |parser| Dnskey::parse(parser));
2758        test_scan(&["10", "11", "5", "a2V5MA=="], Dnskey::scan, &rdata);
2759    }
2760
2761    //--- Rrsig
2762
2763    #[test]
2764    #[allow(clippy::redundant_closure)] // lifetimes ...
2765    fn rrsig_compose_parse_scan() {
2766        let rdata = Rrsig::new(
2767            Rtype::A,
2768            SecurityAlgorithm::RSASHA1,
2769            3,
2770            Ttl::from_secs(12),
2771            Timestamp::from(13),
2772            Timestamp::from(14),
2773            15,
2774            Name::<Vec<u8>>::from_str("example.com.").unwrap(),
2775            b"key",
2776        )
2777        .unwrap();
2778        test_rdlen(&rdata);
2779        test_compose_parse(&rdata, |parser| Rrsig::parse(parser));
2780        test_scan(
2781            &[
2782                "A",
2783                "5",
2784                "3",
2785                "12",
2786                "13",
2787                "14",
2788                "15",
2789                "example.com.",
2790                "a2V5",
2791            ],
2792            Rrsig::scan,
2793            &rdata,
2794        );
2795    }
2796
2797    //--- Nsec
2798
2799    #[test]
2800    #[allow(clippy::redundant_closure)] // lifetimes ...
2801    fn nsec_compose_parse_scan() {
2802        let mut rtype = RtypeBitmapBuilder::new_vec();
2803        rtype.add(Rtype::A).unwrap();
2804        rtype.add(Rtype::SRV).unwrap();
2805        let rdata = Nsec::new(
2806            Name::<Vec<u8>>::from_str("example.com.").unwrap(),
2807            rtype.finalize(),
2808        );
2809        test_rdlen(&rdata);
2810        test_compose_parse(&rdata, |parser| Nsec::parse(parser));
2811        test_scan(&["example.com.", "A", "SRV"], Nsec::scan, &rdata);
2812
2813        // scan empty rtype bitmap
2814        let rdata = Nsec::new(
2815            Name::<Vec<u8>>::from_str("example.com.").unwrap(),
2816            RtypeBitmapBuilder::new_vec().finalize(),
2817        );
2818        test_scan(&["example.com."], Nsec::scan, &rdata);
2819    }
2820
2821    //--- Ds
2822
2823    #[test]
2824    #[allow(clippy::redundant_closure)] // lifetimes ...
2825    fn ds_compose_parse_scan() {
2826        let rdata =
2827            Ds::new(10, SecurityAlgorithm::RSASHA1, DigestAlgorithm::SHA256, b"key").unwrap();
2828        test_rdlen(&rdata);
2829        test_compose_parse(&rdata, |parser| Ds::parse(parser));
2830        test_scan(&["10", "5", "2", "6b6579"], Ds::scan, &rdata);
2831    }
2832
2833    //--- RtypeBitmape
2834
2835    #[test]
2836    fn rtype_split() {
2837        assert_eq!(split_rtype(Rtype::A), (0, 0, 0b01000000));
2838        assert_eq!(split_rtype(Rtype::NS), (0, 0, 0b00100000));
2839        assert_eq!(split_rtype(Rtype::CAA), (1, 0, 0b01000000));
2840    }
2841
2842    #[test]
2843    fn rtype_bitmap_read_window() {
2844        let mut builder = RtypeBitmapBuilder::new_vec();
2845        builder.add(Rtype::A).unwrap();
2846        builder.add(Rtype::CAA).unwrap();
2847        let bitmap = builder.finalize();
2848
2849        let ((n, window), data) = read_window(bitmap.as_slice()).unwrap();
2850        assert_eq!((n, window), (0u8, b"\x40".as_ref()));
2851        let ((n, window), data) = read_window(data).unwrap();
2852        assert_eq!((n, window), (1u8, b"\x40".as_ref()));
2853        assert!(data.is_empty());
2854        assert!(read_window(data).is_none());
2855    }
2856
2857    #[test]
2858    fn rtype_bitmap_builder() {
2859        let mut builder = RtypeBitmapBuilder::new_vec();
2860        builder.add(Rtype::from_int(1234)).unwrap(); // 0x04D2
2861        builder.add(Rtype::A).unwrap(); // 0x0001
2862        builder.add(Rtype::MX).unwrap(); // 0x000F
2863        builder.add(Rtype::RRSIG).unwrap(); // 0x002E
2864        builder.add(Rtype::NSEC).unwrap(); // 0x002F
2865        let bitmap = builder.finalize();
2866        assert_eq!(
2867            bitmap.as_slice(),
2868            &b"\x00\x06\x40\x01\x00\x00\x00\x03\
2869                     \x04\x1b\x00\x00\x00\x00\x00\x00\
2870                     \x00\x00\x00\x00\x00\x00\x00\x00\
2871                     \x00\x00\x00\x00\x00\x00\x00\x00\
2872                     \x00\x00\x00\x00\x20"[..]
2873        );
2874
2875        assert!(bitmap.contains(Rtype::A));
2876        assert!(bitmap.contains(Rtype::MX));
2877        assert!(bitmap.contains(Rtype::RRSIG));
2878        assert!(bitmap.contains(Rtype::NSEC));
2879        assert!(bitmap.contains(Rtype::from(1234)));
2880        assert!(!bitmap.contains(Rtype::from(1235)));
2881        assert!(!bitmap.contains(Rtype::NS));
2882    }
2883
2884    #[test]
2885    fn rtype_bitmap_iter() {
2886        use std::vec::Vec;
2887
2888        let mut builder = RtypeBitmapBuilder::new_vec();
2889        let types = vec![
2890            Rtype::NS,
2891            Rtype::SOA,
2892            Rtype::MX,
2893            Rtype::TXT,
2894            Rtype::RRSIG,
2895            Rtype::DNSKEY,
2896            Rtype::NSEC3PARAM,
2897            Rtype::SPF,
2898            Rtype::CAA,
2899        ];
2900        for t in types.iter() {
2901            builder.add(*t).unwrap();
2902        }
2903
2904        let bitmap = builder.finalize();
2905        let bitmap_types: Vec<_> = bitmap.iter().collect();
2906        assert_eq!(types, bitmap_types);
2907    }
2908
2909    #[test]
2910    fn dnskey_key_tag() {
2911        assert_eq!(
2912            Dnskey::new(
2913                256,
2914                3,
2915                SecurityAlgorithm::RSASHA256,
2916                base64::decode::<Vec<u8>>(
2917                    "AwEAAcTQyaIe6nt3xSPOG2L/YfwBkOVTJN6mlnZ249O5Rtt3ZSRQHxQS\
2918                     W61AODYw6bvgxrrGq8eeOuenFjcSYgNAMcBYoEYYmKDW6e9EryW4ZaT/\
2919                     MCq+8Am06oR40xAA3fClOM6QjRcT85tP41Go946AicBGP8XOP/Aj1aI/\
2920                     oPRGzRnboUPUok/AzTNnW5npBU69+BuiIwYE7mQOiNBFePyvjQBdoiuY\
2921                     bmuD3Py0IyjlBxzZUXbqLsRL9gYFkCqeTY29Ik7usuzMTa+JRSLz6KGS\
2922                     5RSJ7CTSMjZg8aNaUbN2dvGhakJPh92HnLvMA3TefFgbKJphFNPA3BWS\
2923                     KLZ02cRWXqM="
2924                )
2925                .unwrap()
2926            ).unwrap()
2927            .key_tag(),
2928            59944
2929        );
2930        assert_eq!(
2931            Dnskey::new(
2932                257,
2933                3,
2934                SecurityAlgorithm::RSASHA256,
2935                base64::decode::<Vec<u8>>(
2936                    "AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTO\
2937                    iW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN\
2938                    7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5\
2939                    LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8\
2940                    efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7\
2941                    pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLY\
2942                    A4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws\
2943                    9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU="
2944                )
2945                .unwrap()
2946            )
2947            .unwrap()
2948            .key_tag(),
2949            20326
2950        );
2951        assert_eq!(
2952            Dnskey::new(
2953                257,
2954                3,
2955                SecurityAlgorithm::RSAMD5,
2956                base64::decode::<Vec<u8>>(
2957                    "AwEAAcVaA4jSBIGRrSzpecoJELvKE9+OMuFnL8mmUBsY\
2958                    lB6epN1CqX7NzwjDpi6VySiEXr0C4uTYkU/L1uMv2mHE\
2959                    AljThFDJ1GuozJ6gA7jf3lnaGppRg2IoVQ9IVmLORmjw\
2960                    C+7Eoi12SqybMTicD3Ezwa9XbG1iPjmjhbMrLh7MSQpX"
2961                )
2962                .unwrap()
2963            )
2964            .unwrap()
2965            .key_tag(),
2966            18698
2967        );
2968    }
2969
2970    #[test]
2971    fn dnskey_flags() {
2972        let dnskey =
2973            Dnskey::new(257, 3, SecurityAlgorithm::RSASHA256, bytes::Bytes::new())
2974                .unwrap();
2975        assert!(dnskey.is_zone_key());
2976        assert!(dnskey.is_secure_entry_point());
2977        assert!(!dnskey.is_revoked());
2978    }
2979}