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