domain/base/opt/
keytag.rs

1//! EDNS options to signal the trust anchor key used in DNSSEC validation.
2//!
3//! The option in this module – [`KeyTag`] – is used by validating resolvers
4//! when querying for DNSKEY records to indicate the key tags of the trust
5//! anchor keys they will be using when validating responses. This is intended
6//! as a means to monitor key uses during root key rollovers.
7//!
8//! The option is defined in [RFC 8145](https://tools.ietf.org/html/rfc8145)
9//! along with detailed rules for who includes this option when.
10
11use super::super::iana::OptionCode;
12use super::super::message_builder::OptBuilder;
13use super::super::wire::{Composer, ParseError};
14use super::{ComposeOptData, Opt, OptData, ParseOptData};
15use core::cmp::Ordering;
16use core::convert::TryInto;
17use core::{borrow, fmt, hash, mem};
18use octseq::builder::OctetsBuilder;
19use octseq::octets::{Octets, OctetsFrom};
20use octseq::parse::Parser;
21
22//------------ KeyTag -------------------------------------------------------
23
24/// Option data for the edns-key-tag option.
25///
26/// This option allows a client to indicate the key tags of the trust anchor
27/// keys they are using to validate responses. The option contains a sequence
28/// of key tags.
29#[derive(Clone)]
30#[repr(transparent)]
31pub struct KeyTag<Octs: ?Sized> {
32    octets: Octs,
33}
34
35impl KeyTag<()> {
36    /// The option code for this option.
37    pub(super) const CODE: OptionCode = OptionCode::KEY_TAG;
38}
39
40impl<Octs> KeyTag<Octs> {
41    /// Creates a new value from its content in wire format.
42    ///
43    /// The function returns an error if the octets do not encode a valid
44    /// edns-key-tag option: the length needs to be an even number of
45    /// octets and no longer than 65,536 octets.
46    pub fn from_octets(octets: Octs) -> Result<Self, ParseError>
47    where
48        Octs: AsRef<[u8]>,
49    {
50        KeyTag::check_len(octets.as_ref().len())?;
51        Ok(unsafe { Self::from_octets_unchecked(octets) })
52    }
53
54    /// Creates a new value from its wire-format content without checking.
55    ///
56    /// # Safety
57    ///
58    /// The caller needs to ensure that `octets` is a valid key tag. The
59    /// length needs to be an even number of octets and no longer than
60    /// 65,536 octets.
61    pub unsafe fn from_octets_unchecked(octets: Octs) -> Self {
62        Self { octets }
63    }
64
65    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
66        parser: &mut Parser<'a, Src>,
67    ) -> Result<Self, ParseError> {
68        let len = parser.remaining();
69        KeyTag::check_len(len)?;
70        let octets = parser.parse_octets(len)?;
71        Ok(unsafe { Self::from_octets_unchecked(octets) })
72    }
73}
74
75impl KeyTag<[u8]> {
76    /// Creates a key tag value from a slice.
77    ///
78    /// Returns an error if `slice` does not contain a valid key tag.
79    pub fn from_slice(slice: &[u8]) -> Result<&Self, ParseError> {
80        Self::check_len(slice.len())?;
81        Ok(unsafe { Self::from_slice_unchecked(slice) })
82    }
83
84    /// Creates a key tag value from a slice without checking.
85    ///
86    /// # Safety
87    ///
88    /// The caller needs to ensure that `slice` contains a valid key tag. The
89    /// length needs to be an even number of octets and no longer than
90    /// 65,536 octets.
91    #[must_use]
92    pub unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
93        // SAFETY: KeyTag has repr(transparent)
94        mem::transmute(slice)
95    }
96
97    /// Checkes that the length of an octets sequence is valid.
98    fn check_len(len: usize) -> Result<(), ParseError> {
99        if len > usize::from(u16::MAX) {
100            Err(ParseError::form_error("long edns-key-tag option"))
101        } else if len % 2 == 1 {
102            Err(ParseError::form_error("invalid edns-key-tag option length"))
103        } else {
104            Ok(())
105        }
106    }
107}
108
109impl<Octs: ?Sized> KeyTag<Octs> {
110    /// Returns a reference to the underlying octets.
111    ///
112    /// The octets contain the key tag value in its wire format: a sequence
113    /// of `u16` in network byte order.
114    pub fn as_octets(&self) -> &Octs {
115        &self.octets
116    }
117
118    /// Converts the value to the underlying octets.
119    ///
120    /// The octets contain the key tag value in its wire format: a sequence
121    /// of `u16` in network byte order.
122    pub fn into_octets(self) -> Octs
123    where
124        Octs: Sized,
125    {
126        self.octets
127    }
128
129    /// Returns a slice of the underlying octets.
130    ///
131    /// The slice will contain the key tag value in its wire format: a
132    /// sequence of `u16` in network byte order.
133    pub fn as_slice(&self) -> &[u8]
134    where
135        Octs: AsRef<[u8]>,
136    {
137        self.octets.as_ref()
138    }
139
140    /// Returns a mutable slice of the underlying octets.
141    ///
142    /// The slice will contain the key tag value in its wire format: a
143    /// sequence of `u16` in network byte order.
144    pub fn as_slice_mut(&mut self) -> &mut [u8]
145    where
146        Octs: AsMut<[u8]>,
147    {
148        self.octets.as_mut()
149    }
150
151    /// Returns an iterator over the individual key tags.
152    pub fn iter(&self) -> KeyTagIter<'_>
153    where
154        Octs: AsRef<[u8]>,
155    {
156        KeyTagIter(self.octets.as_ref())
157    }
158}
159
160//--- OctetsFrom
161
162impl<Octs, SrcOcts> OctetsFrom<KeyTag<SrcOcts>> for KeyTag<Octs>
163where
164    Octs: OctetsFrom<SrcOcts>,
165{
166    type Error = Octs::Error;
167
168    fn try_octets_from(src: KeyTag<SrcOcts>) -> Result<Self, Self::Error> {
169        Octs::try_octets_from(src.octets)
170            .map(|octets| unsafe { Self::from_octets_unchecked(octets) })
171    }
172}
173
174//--- AsRef, AsMut, Borrow, BorrowMut
175
176impl<Octs: AsRef<[u8]> + ?Sized> AsRef<[u8]> for KeyTag<Octs> {
177    fn as_ref(&self) -> &[u8] {
178        self.as_slice()
179    }
180}
181
182impl<Octs: AsMut<[u8]> + ?Sized> AsMut<[u8]> for KeyTag<Octs> {
183    fn as_mut(&mut self) -> &mut [u8] {
184        self.as_slice_mut()
185    }
186}
187
188impl<Octs: AsRef<[u8]> + ?Sized> borrow::Borrow<[u8]> for KeyTag<Octs> {
189    fn borrow(&self) -> &[u8] {
190        self.as_slice()
191    }
192}
193
194impl<Octs> borrow::BorrowMut<[u8]> for KeyTag<Octs>
195where
196    Octs: AsMut<[u8]> + AsRef<[u8]> + ?Sized,
197{
198    fn borrow_mut(&mut self) -> &mut [u8] {
199        self.as_slice_mut()
200    }
201}
202
203//--- OptData
204
205impl<Octs: ?Sized> OptData for KeyTag<Octs> {
206    fn code(&self) -> OptionCode {
207        OptionCode::KEY_TAG
208    }
209}
210
211impl<'a, Octs: Octets> ParseOptData<'a, Octs> for KeyTag<Octs::Range<'a>> {
212    fn parse_option(
213        code: OptionCode,
214        parser: &mut Parser<'a, Octs>,
215    ) -> Result<Option<Self>, ParseError> {
216        if code == OptionCode::KEY_TAG {
217            Self::parse(parser).map(Some)
218        } else {
219            Ok(None)
220        }
221    }
222}
223
224impl<Octs: AsRef<[u8]> + ?Sized> ComposeOptData for KeyTag<Octs> {
225    fn compose_len(&self) -> u16 {
226        self.octets
227            .as_ref()
228            .len()
229            .try_into()
230            .expect("long option data")
231    }
232
233    fn compose_option<Target: OctetsBuilder + ?Sized>(
234        &self,
235        target: &mut Target,
236    ) -> Result<(), Target::AppendError> {
237        target.append_slice(self.octets.as_ref())
238    }
239}
240
241//--- IntoIterator
242
243impl<'a, Octs: AsRef<[u8]> + ?Sized> IntoIterator for &'a KeyTag<Octs> {
244    type Item = u16;
245    type IntoIter = KeyTagIter<'a>;
246
247    fn into_iter(self) -> Self::IntoIter {
248        self.iter()
249    }
250}
251
252//--- Display and Debug
253
254impl<Octets: AsRef<[u8]> + ?Sized> fmt::Display for KeyTag<Octets> {
255    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256        let mut first = true;
257
258        for v in self.octets.as_ref() {
259            if first {
260                write!(f, "{:X}", ((*v as u16) << 8) | *v as u16)?;
261                first = false;
262            } else {
263                write!(f, ", {:X}", ((*v as u16) << 8) | *v as u16)?;
264            }
265        }
266
267        Ok(())
268    }
269}
270
271impl<Octets: AsRef<[u8]> + ?Sized> fmt::Debug for KeyTag<Octets> {
272    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273        write!(f, "KeyTag([{}])", self)
274    }
275}
276
277//--- PartialEq and Eq
278
279impl<Octs, Other> PartialEq<Other> for KeyTag<Octs>
280where
281    Octs: AsRef<[u8]> + ?Sized,
282    Other: AsRef<[u8]> + ?Sized,
283{
284    fn eq(&self, other: &Other) -> bool {
285        self.as_slice().eq(other.as_ref())
286    }
287}
288
289impl<Octs: AsRef<[u8]> + ?Sized> Eq for KeyTag<Octs> {}
290
291//--- PartialOrd and Ord
292
293impl<Octs, Other> PartialOrd<Other> for KeyTag<Octs>
294where
295    Octs: AsRef<[u8]> + ?Sized,
296    Other: AsRef<[u8]> + ?Sized,
297{
298    fn partial_cmp(&self, other: &Other) -> Option<Ordering> {
299        self.as_slice().partial_cmp(other.as_ref())
300    }
301}
302
303impl<Octs: AsRef<[u8]> + ?Sized> Ord for KeyTag<Octs> {
304    fn cmp(&self, other: &Self) -> Ordering {
305        self.as_slice().cmp(other.as_slice())
306    }
307}
308
309//--- Hash
310
311impl<Octs: AsRef<[u8]> + ?Sized> hash::Hash for KeyTag<Octs> {
312    fn hash<H: hash::Hasher>(&self, state: &mut H) {
313        self.as_slice().hash(state)
314    }
315}
316
317//--- Extended Opt and OptBuilder
318
319impl<Octs: Octets> Opt<Octs> {
320    /// Returns the first edns-key-tags option if present.
321    ///
322    /// The option contains a list of the key tags of the trust anchor keys
323    /// a validating resolver is using for DNSSEC validation.
324    pub fn key_tag(&self) -> Option<KeyTag<Octs::Range<'_>>> {
325        self.first()
326    }
327}
328
329impl<Target: Composer> OptBuilder<'_, Target> {
330    /// Appends a edns-key-tag option.
331    ///
332    /// The option contains a list of the key tags of the trust anchor keys
333    /// a validating resolver is using for DNSSEC validation.
334    pub fn key_tag(
335        &mut self,
336        key_tag: &KeyTag<impl AsRef<[u8]> + ?Sized>,
337    ) -> Result<(), Target::AppendError> {
338        self.push(key_tag)
339    }
340}
341
342//--- Serialize
343
344#[cfg(feature = "serde")]
345impl<Octs: AsRef<[u8]>> serde::Serialize for KeyTag<Octs> {
346    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
347    where
348        S: serde::Serializer,
349    {
350        use serde::ser::SerializeSeq;
351
352        let mut list = serializer.serialize_seq(None)?;
353
354        for i in self.as_ref().iter() {
355            list.serialize_element(i)?;
356        }
357
358        list.end()
359    }
360}
361
362//------------ KeyTagIter ----------------------------------------------------
363
364/// An iterator over the key tags in an edns-key-tags value.
365///
366/// You can get a value of this type via [`KeyTag::iter`] or its
367/// `IntoIterator` implementation.
368#[derive(Clone, Copy, Debug)]
369pub struct KeyTagIter<'a>(&'a [u8]);
370
371impl Iterator for KeyTagIter<'_> {
372    type Item = u16;
373
374    fn next(&mut self) -> Option<Self::Item> {
375        if self.0.len() < 2 {
376            None
377        } else {
378            let (item, tail) = self.0.split_at(2);
379            self.0 = tail;
380            Some(u16::from_be_bytes(item.try_into().unwrap()))
381        }
382    }
383}
384
385//============ Testing ======================================================
386
387#[cfg(test)]
388#[cfg(all(feature = "std", feature = "bytes"))]
389mod test {
390    use super::super::test::test_option_compose_parse;
391    use super::*;
392
393    #[test]
394    #[allow(clippy::redundant_closure)] // lifetimes ...
395    fn nsid_compose_parse() {
396        test_option_compose_parse(
397            &KeyTag::from_octets("fooo").unwrap(),
398            |parser| KeyTag::parse(parser),
399        );
400    }
401}