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