hickory_proto/rr/dnssec/
supported_algorithm.rs

1/*
2 * Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//! bitmap for expressing the set of supported algorithms in edns.
18
19use std::fmt::{self, Display, Formatter};
20
21#[cfg(feature = "serde-config")]
22use serde::{Deserialize, Serialize};
23
24use tracing::warn;
25
26use crate::error::*;
27use crate::rr::dnssec::Algorithm;
28use crate::serialize::binary::{BinEncodable, BinEncoder};
29
30/// Used to specify the set of SupportedAlgorithms between a client and server
31#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
32#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
33pub struct SupportedAlgorithms {
34    // right now the number of Algorithms supported are fewer than 16..
35    bit_map: u8,
36}
37
38impl SupportedAlgorithms {
39    /// Return a new set of Supported algorithms
40    pub fn new() -> Self {
41        Self { bit_map: 0 }
42    }
43
44    /// Specify the entire set is supported
45    pub fn all() -> Self {
46        Self {
47            bit_map: 0b0111_1111,
48        }
49    }
50
51    /// Based on the set of Algorithms, return the supported set
52    pub fn from_vec(algorithms: &[Algorithm]) -> Self {
53        let mut supported = Self::new();
54
55        for a in algorithms {
56            supported.set(*a);
57        }
58
59        supported
60    }
61
62    fn pos(algorithm: Algorithm) -> Option<u8> {
63        // not using the values from the RFC's to keep the bit_map space condensed
64        #[allow(deprecated)]
65        let bit_pos: Option<u8> = match algorithm {
66            Algorithm::RSASHA1 => Some(0),
67            Algorithm::RSASHA256 => Some(1),
68            Algorithm::RSASHA1NSEC3SHA1 => Some(2),
69            Algorithm::RSASHA512 => Some(3),
70            Algorithm::ECDSAP256SHA256 => Some(4),
71            Algorithm::ECDSAP384SHA384 => Some(5),
72            Algorithm::ED25519 => Some(6),
73            Algorithm::RSAMD5 | Algorithm::DSA | Algorithm::Unknown(_) => None,
74        };
75
76        bit_pos.map(|b| 1u8 << b)
77    }
78
79    fn from_pos(pos: u8) -> Option<Algorithm> {
80        // TODO: should build a code generator or possibly a macro for deriving these inversions
81        #[allow(deprecated)]
82        match pos {
83            0 => Some(Algorithm::RSASHA1),
84            1 => Some(Algorithm::RSASHA256),
85            2 => Some(Algorithm::RSASHA1NSEC3SHA1),
86            3 => Some(Algorithm::RSASHA512),
87            4 => Some(Algorithm::ECDSAP256SHA256),
88            5 => Some(Algorithm::ECDSAP384SHA384),
89            6 => Some(Algorithm::ED25519),
90            _ => None,
91        }
92    }
93
94    /// Set the specified algorithm as supported
95    pub fn set(&mut self, algorithm: Algorithm) {
96        if let Some(bit_pos) = Self::pos(algorithm) {
97            self.bit_map |= bit_pos;
98        }
99    }
100
101    /// Returns true if the algorithm is supported
102    pub fn has(self, algorithm: Algorithm) -> bool {
103        if let Some(bit_pos) = Self::pos(algorithm) {
104            (bit_pos & self.bit_map) == bit_pos
105        } else {
106            false
107        }
108    }
109
110    /// Return an Iterator over the supported set.
111    pub fn iter(&self) -> SupportedAlgorithmsIter<'_> {
112        SupportedAlgorithmsIter::new(self)
113    }
114
115    /// Return the count of supported algorithms
116    pub fn len(self) -> u16 {
117        // this is pretty much guaranteed to be less that u16::MAX
118        self.iter().count() as u16
119    }
120
121    /// Return true if no SupportedAlgorithms are set, this implies the option is not supported
122    pub fn is_empty(self) -> bool {
123        self.bit_map == 0
124    }
125}
126
127impl Default for SupportedAlgorithms {
128    fn default() -> Self {
129        Self::new()
130    }
131}
132
133impl Display for SupportedAlgorithms {
134    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
135        for a in self.iter() {
136            a.fmt(f)?;
137            f.write_str(", ")?;
138        }
139
140        Ok(())
141    }
142}
143
144impl<'a> From<&'a [u8]> for SupportedAlgorithms {
145    fn from(values: &'a [u8]) -> Self {
146        let mut supported = Self::new();
147
148        for a in values.iter().map(|i| Algorithm::from_u8(*i)) {
149            match a {
150                Algorithm::Unknown(v) => warn!("unrecognized algorithm: {}", v),
151                a => supported.set(a),
152            }
153        }
154
155        supported
156    }
157}
158
159impl<'a> From<&'a SupportedAlgorithms> for Vec<u8> {
160    fn from(value: &'a SupportedAlgorithms) -> Self {
161        let mut bytes = Self::with_capacity(8); // today this is less than 8
162
163        for a in value.iter() {
164            bytes.push(a.into());
165        }
166
167        bytes.shrink_to_fit();
168        bytes
169    }
170}
171
172impl From<Algorithm> for SupportedAlgorithms {
173    fn from(algorithm: Algorithm) -> Self {
174        Self::from_vec(&[algorithm])
175    }
176}
177
178pub struct SupportedAlgorithmsIter<'a> {
179    algorithms: &'a SupportedAlgorithms,
180    current: usize,
181}
182
183impl<'a> SupportedAlgorithmsIter<'a> {
184    pub fn new(algorithms: &'a SupportedAlgorithms) -> Self {
185        SupportedAlgorithmsIter {
186            algorithms,
187            current: 0,
188        }
189    }
190}
191
192impl Iterator for SupportedAlgorithmsIter<'_> {
193    type Item = Algorithm;
194    fn next(&mut self) -> Option<Self::Item> {
195        // some quick bounds checking
196        if self.current > u8::MAX as usize {
197            return None;
198        }
199
200        while let Some(algorithm) = SupportedAlgorithms::from_pos(self.current as u8) {
201            self.current += 1;
202            if self.algorithms.has(algorithm) {
203                return Some(algorithm);
204            }
205        }
206
207        None
208    }
209}
210
211impl BinEncodable for SupportedAlgorithms {
212    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
213        for a in self.iter() {
214            encoder.emit_u8(a.into())?;
215        }
216        Ok(())
217    }
218}
219
220#[test]
221#[allow(deprecated)]
222fn test_has() {
223    let mut supported = SupportedAlgorithms::new();
224
225    supported.set(Algorithm::RSASHA1);
226
227    assert!(supported.has(Algorithm::RSASHA1));
228    assert!(!supported.has(Algorithm::RSASHA1NSEC3SHA1));
229
230    let mut supported = SupportedAlgorithms::new();
231
232    supported.set(Algorithm::RSASHA256);
233    assert!(!supported.has(Algorithm::RSASHA1));
234    assert!(!supported.has(Algorithm::RSASHA1NSEC3SHA1));
235    assert!(supported.has(Algorithm::RSASHA256));
236}
237
238#[test]
239#[allow(deprecated)]
240fn test_iterator() {
241    let supported = SupportedAlgorithms::all();
242    assert_eq!(supported.iter().count(), 7);
243
244    // it just so happens that the iterator has a fixed order...
245    let supported = SupportedAlgorithms::all();
246    let mut iter = supported.iter();
247    assert_eq!(iter.next(), Some(Algorithm::RSASHA1));
248    assert_eq!(iter.next(), Some(Algorithm::RSASHA256));
249    assert_eq!(iter.next(), Some(Algorithm::RSASHA1NSEC3SHA1));
250    assert_eq!(iter.next(), Some(Algorithm::RSASHA512));
251    assert_eq!(iter.next(), Some(Algorithm::ECDSAP256SHA256));
252    assert_eq!(iter.next(), Some(Algorithm::ECDSAP384SHA384));
253    assert_eq!(iter.next(), Some(Algorithm::ED25519));
254
255    let mut supported = SupportedAlgorithms::new();
256    supported.set(Algorithm::RSASHA256);
257    supported.set(Algorithm::RSASHA512);
258
259    let mut iter = supported.iter();
260    assert_eq!(iter.next(), Some(Algorithm::RSASHA256));
261    assert_eq!(iter.next(), Some(Algorithm::RSASHA512));
262}
263
264#[test]
265#[allow(deprecated)]
266fn test_vec() {
267    let supported = SupportedAlgorithms::all();
268    let array: Vec<u8> = (&supported).into();
269    let decoded: SupportedAlgorithms = (&array as &[_]).into();
270
271    assert_eq!(supported, decoded);
272
273    let mut supported = SupportedAlgorithms::new();
274    supported.set(Algorithm::RSASHA256);
275    supported.set(Algorithm::ECDSAP256SHA256);
276    supported.set(Algorithm::ECDSAP384SHA384);
277    supported.set(Algorithm::ED25519);
278    let array: Vec<u8> = (&supported).into();
279    let decoded: SupportedAlgorithms = (&array as &[_]).into();
280
281    assert_eq!(supported, decoded);
282    assert!(!supported.has(Algorithm::RSASHA1));
283    assert!(!supported.has(Algorithm::RSASHA1NSEC3SHA1));
284    assert!(supported.has(Algorithm::RSASHA256));
285    assert!(supported.has(Algorithm::ECDSAP256SHA256));
286    assert!(supported.has(Algorithm::ECDSAP384SHA384));
287    assert!(supported.has(Algorithm::ED25519));
288}