hickory_proto/rr/dnssec/algorithm.rs
1// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// https://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8// needed for the derive statements on algorithm
9// this issue in rustc would help narrow the statement: https://github.com/rust-lang/rust/issues/62398
10#![allow(deprecated, clippy::use_self)]
11
12use std::fmt;
13use std::fmt::{Display, Formatter};
14
15#[cfg(feature = "serde-config")]
16use serde::{Deserialize, Serialize};
17
18use crate::error::*;
19use crate::serialize::binary::*;
20
21/// DNSSEC signing and validation algorithms.
22///
23/// For [reference](https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml)
24/// the iana documents have all the officially registered algorithms.
25///
26/// [RFC 6944](https://tools.ietf.org/html/rfc6944), DNSSEC DNSKEY Algorithm Status, April 2013
27///
28/// ```text
29///
30/// 2.2. Algorithm Implementation Status Assignment Rationale
31///
32/// RSASHA1 has an implementation status of Must Implement, consistent
33/// with [RFC4034]. RSAMD5 has an implementation status of Must Not
34/// Implement because of known weaknesses in MD5.
35///
36/// The status of RSASHA1-NSEC3-SHA1 is set to Recommended to Implement
37/// as many deployments use NSEC3. The status of RSA/SHA-256 and RSA/
38/// SHA-512 are also set to Recommended to Implement as major deployments
39/// (such as the root zone) use these algorithms [ROOTDPS]. It is
40/// believed that RSA/SHA-256 or RSA/SHA-512 algorithms will replace
41/// older algorithms (e.g., RSA/SHA-1) that have a perceived weakness.
42///
43/// Likewise, ECDSA with the two identified curves (ECDSAP256SHA256 and
44/// ECDSAP384SHA384) is an algorithm that may see widespread use due to
45/// the perceived similar level of security offered with smaller key size
46/// compared to the key sizes of algorithms such as RSA. Therefore,
47/// ECDSAP256SHA256 and ECDSAP384SHA384 are Recommended to Implement.
48///
49/// All other algorithms used in DNSSEC specified without an
50/// implementation status are currently set to Optional.
51///
52/// 2.3. DNSSEC Implementation Status Table
53///
54/// The DNSSEC algorithm implementation status table is listed below.
55/// Only the algorithms already specified for use with DNSSEC at the time
56/// of writing are listed.
57///
58/// +------------+------------+-------------------+-------------------+
59/// | Must | Must Not | Recommended | Optional |
60/// | Implement | Implement | to Implement | |
61/// +------------+------------+-------------------+-------------------+
62/// | | | | |
63/// | RSASHA1 | RSAMD5 | RSASHA256 | Any |
64/// | | | RSASHA1-NSEC3 | registered |
65/// | | | -SHA1 | algorithm |
66/// | | | RSASHA512 | not listed in |
67/// | | | ECDSAP256SHA256 | this table |
68/// | | | ECDSAP384SHA384 | |
69/// +------------+------------+-------------------+-------------------+
70///
71/// This table does not list the Reserved values in the IANA registry
72/// table or the values for INDIRECT (252), PRIVATE (253), and PRIVATEOID
73/// (254). These values may relate to more than one algorithm and are
74/// therefore up to the implementer's discretion. As noted, any
75/// algorithm not listed in the table is Optional. As of this writing,
76/// the Optional algorithms are DSASHA1, DH, DSA-NSEC3-SHA1, and GOST-
77/// ECC, but in general, anything not explicitly listed is Optional.
78///
79/// 2.4. Specifying New Algorithms and Updating the Status of Existing
80/// Entries
81///
82/// [RFC6014] establishes a parallel procedure for adding a registry
83/// entry for a new algorithm other than a standards track document.
84/// Because any algorithm not listed in the foregoing table is Optional,
85/// algorithms entered into the registry using the [RFC6014] procedure
86/// are automatically Optional.
87///
88/// It has turned out to be useful for implementations to refer to a
89/// single document that specifies the implementation status of every
90/// algorithm. Accordingly, when a new algorithm is to be registered
91/// with a status other than Optional, this document shall be made
92/// obsolete by a new document that adds the new algorithm to the table
93/// in Section 2.3. Similarly, if the status of any algorithm in the
94/// table in Section 2.3 changes, a new document shall make this document
95/// obsolete; that document shall include a replacement of the table in
96/// Section 2.3. This way, the goal of having one authoritative document
97/// to specify all the status values is achieved.
98///
99/// This document cannot be updated, only made obsolete and replaced by a
100/// successor document.
101/// ```
102#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
103#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
104#[non_exhaustive]
105pub enum Algorithm {
106 /// DO NOT USE, MD5 is a compromised hashing function, it is here for backward compatibility
107 #[deprecated(
108 note = "this is a compromised hashing function, it is here for backward compatibility"
109 )]
110 RSAMD5,
111 /// DO NOT USE, DSA is a compromised hashing function, it is here for backward compatibility
112 #[deprecated(
113 note = "this is a compromised hashing function, it is here for backward compatibility"
114 )]
115 DSA,
116 /// DO NOT USE, SHA1 is a compromised hashing function, it is here for backward compatibility
117 #[deprecated(
118 note = "this is a compromised hashing function, it is here for backward compatibility"
119 )]
120 RSASHA1,
121 /// DO NOT USE, SHA1 is a compromised hashing function, it is here for backward compatibility
122 #[deprecated(
123 note = "this is a compromised hashing function, it is here for backward compatibility"
124 )]
125 RSASHA1NSEC3SHA1,
126 /// RSA public key with SHA256 hash
127 RSASHA256,
128 /// RSA public key with SHA512 hash
129 RSASHA512,
130 /// [rfc6605](https://tools.ietf.org/html/rfc6605)
131 ECDSAP256SHA256,
132 /// [rfc6605](https://tools.ietf.org/html/rfc6605)
133 ECDSAP384SHA384,
134 /// [draft-ietf-curdle-dnskey-eddsa-03](https://tools.ietf.org/html/draft-ietf-curdle-dnskey-eddsa-03)
135 ED25519,
136 /// An unknown algorithm identifier
137 Unknown(u8),
138}
139
140impl Algorithm {
141 /// <https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml>
142 pub fn from_u8(value: u8) -> Self {
143 #[allow(deprecated)]
144 match value {
145 1 => Self::RSAMD5,
146 3 => Self::DSA,
147 5 => Self::RSASHA1,
148 7 => Self::RSASHA1NSEC3SHA1,
149 8 => Self::RSASHA256,
150 10 => Self::RSASHA512,
151 13 => Self::ECDSAP256SHA256,
152 14 => Self::ECDSAP384SHA384,
153 15 => Self::ED25519,
154 _ => Self::Unknown(value),
155 }
156 }
157
158 /// length in bytes that the hash portion of this function will produce
159 pub fn hash_len(self) -> Option<usize> {
160 match self {
161 Self::RSAMD5 => Some(16), // 128 bits
162 Self::DSA | Self::RSASHA1 | Self::RSASHA1NSEC3SHA1 => Some(20), // 160 bits
163 Self::RSASHA256 | Self::ECDSAP256SHA256 | Self::ED25519 => Some(32), // 256 bits
164 Self::ECDSAP384SHA384 => Some(48),
165 Self::RSASHA512 => Some(64), // 512 bites
166 Self::Unknown(_) => None,
167 }
168 }
169
170 /// Convert to string form
171 #[deprecated(note = "use as_str instead")]
172 pub fn to_str(self) -> &'static str {
173 self.as_str()
174 }
175
176 /// Convert to string form
177 pub fn as_str(self) -> &'static str {
178 match self {
179 Self::RSAMD5 => "RSAMD5",
180 Self::DSA => "DSA",
181 Self::RSASHA1 => "RSASHA1",
182 Self::RSASHA256 => "RSASHA256",
183 Self::RSASHA1NSEC3SHA1 => "RSASHA1-NSEC3-SHA1",
184 Self::RSASHA512 => "RSASHA512",
185 Self::ECDSAP256SHA256 => "ECDSAP256SHA256",
186 Self::ECDSAP384SHA384 => "ECDSAP384SHA384",
187 Self::ED25519 => "ED25519",
188 Self::Unknown(_) => "Unknown",
189 }
190 }
191}
192
193impl BinEncodable for Algorithm {
194 fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
195 encoder.emit(u8::from(*self))
196 }
197}
198
199impl<'r> BinDecodable<'r> for Algorithm {
200 // https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
201 fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
202 let algorithm_id =
203 decoder.read_u8()?.unverified(/*Algorithm is verified as safe in processing this*/);
204 Ok(Self::from_u8(algorithm_id))
205 }
206}
207
208impl From<Algorithm> for &'static str {
209 fn from(a: Algorithm) -> &'static str {
210 a.as_str()
211 }
212}
213
214impl From<Algorithm> for u8 {
215 fn from(a: Algorithm) -> Self {
216 match a {
217 Algorithm::RSAMD5 => 1,
218 Algorithm::DSA => 3,
219 Algorithm::RSASHA1 => 5,
220 Algorithm::RSASHA1NSEC3SHA1 => 7,
221 Algorithm::RSASHA256 => 8,
222 Algorithm::RSASHA512 => 10,
223 Algorithm::ECDSAP256SHA256 => 13,
224 Algorithm::ECDSAP384SHA384 => 14,
225 Algorithm::ED25519 => 15,
226 Algorithm::Unknown(v) => v,
227 }
228 }
229}
230
231impl Display for Algorithm {
232 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
233 f.write_str(self.as_str())
234 }
235}
236
237#[test]
238fn test_into() {
239 for algorithm in &[
240 Algorithm::RSAMD5,
241 Algorithm::DSA,
242 Algorithm::RSASHA1,
243 Algorithm::RSASHA256,
244 Algorithm::RSASHA1NSEC3SHA1,
245 Algorithm::RSASHA512,
246 Algorithm::ECDSAP256SHA256,
247 Algorithm::ECDSAP384SHA384,
248 Algorithm::ED25519,
249 ] {
250 assert_eq!(*algorithm, Algorithm::from_u8(Into::<u8>::into(*algorithm)))
251 }
252}
253
254#[test]
255fn test_order() {
256 let mut algorithms = [
257 Algorithm::RSAMD5,
258 Algorithm::DSA,
259 Algorithm::RSASHA1,
260 Algorithm::RSASHA256,
261 Algorithm::RSASHA1NSEC3SHA1,
262 Algorithm::RSASHA512,
263 Algorithm::ECDSAP256SHA256,
264 Algorithm::ECDSAP384SHA384,
265 Algorithm::ED25519,
266 ];
267
268 algorithms.sort();
269
270 for (got, expect) in algorithms.iter().zip(
271 [
272 Algorithm::RSAMD5,
273 Algorithm::DSA,
274 Algorithm::RSASHA1,
275 Algorithm::RSASHA1NSEC3SHA1,
276 Algorithm::RSASHA256,
277 Algorithm::RSASHA512,
278 Algorithm::ECDSAP256SHA256,
279 Algorithm::ECDSAP384SHA384,
280 Algorithm::ED25519,
281 ]
282 .iter(),
283 ) {
284 assert_eq!(got, expect);
285 }
286}