1#![allow(clippy::use_self)]
10
11use std::fmt;
12
13#[cfg(feature = "serde-config")]
14use serde::{Deserialize, Serialize};
15
16use data_encoding::{Encoding, Specification};
17use once_cell::sync::Lazy;
18
19use crate::{
20 error::{ProtoError, ProtoResult},
21 rr::{RData, RecordData, RecordDataDecodable, RecordType},
22 serialize::binary::{BinDecoder, BinEncodable, BinEncoder, Restrict, RestrictedMath},
23};
24
25pub static HEX: Lazy<Encoding> = Lazy::new(|| {
27 let mut spec = Specification::new();
28 spec.symbols.push_str("0123456789abcdef");
29 spec.ignore.push_str(" \t\r\n");
30 spec.translate.from.push_str("ABCDEF");
31 spec.translate.to.push_str("abcdef");
32 spec.encoding().expect("error in sshfp HEX encoding")
33});
34
35#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
62#[derive(Debug, PartialEq, Eq, Hash, Clone)]
63pub struct SSHFP {
64 algorithm: Algorithm,
65 fingerprint_type: FingerprintType,
66 fingerprint: Vec<u8>,
67}
68
69impl SSHFP {
70 pub fn new(
78 algorithm: Algorithm,
79 fingerprint_type: FingerprintType,
80 fingerprint: Vec<u8>,
81 ) -> Self {
82 Self {
83 algorithm,
84 fingerprint_type,
85 fingerprint,
86 }
87 }
88
89 pub fn algorithm(&self) -> Algorithm {
91 self.algorithm
92 }
93
94 pub fn fingerprint_type(&self) -> FingerprintType {
96 self.fingerprint_type
97 }
98
99 pub fn fingerprint(&self) -> &[u8] {
101 &self.fingerprint
102 }
103}
104
105#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
125#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
126pub enum Algorithm {
127 Reserved,
129
130 RSA,
132
133 DSA,
135
136 ECDSA,
138
139 Ed25519,
141
142 Ed448,
144
145 Unassigned(u8),
147}
148
149impl From<u8> for Algorithm {
150 fn from(alg: u8) -> Self {
151 match alg {
152 0 => Self::Reserved,
153 1 => Self::RSA,
154 2 => Self::DSA,
155 3 => Self::ECDSA,
156 4 => Self::Ed25519, 6 => Self::Ed448,
158 _ => Self::Unassigned(alg),
159 }
160 }
161}
162
163impl From<Algorithm> for u8 {
164 fn from(algorithm: Algorithm) -> Self {
165 match algorithm {
166 Algorithm::Reserved => 0,
167 Algorithm::RSA => 1,
168 Algorithm::DSA => 2,
169 Algorithm::ECDSA => 3,
170 Algorithm::Ed25519 => 4,
171 Algorithm::Ed448 => 6,
172 Algorithm::Unassigned(alg) => alg,
173 }
174 }
175}
176
177#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
199#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
200pub enum FingerprintType {
201 Reserved,
203
204 SHA1,
206
207 SHA256,
209
210 Unassigned(u8),
212}
213
214impl From<u8> for FingerprintType {
215 fn from(ft: u8) -> Self {
216 match ft {
217 0 => Self::Reserved,
218 1 => Self::SHA1,
219 2 => Self::SHA256,
220 _ => Self::Unassigned(ft),
221 }
222 }
223}
224
225impl From<FingerprintType> for u8 {
226 fn from(fingerprint_type: FingerprintType) -> Self {
227 match fingerprint_type {
228 FingerprintType::Reserved => 0,
229 FingerprintType::SHA1 => 1,
230 FingerprintType::SHA256 => 2,
231 FingerprintType::Unassigned(ft) => ft,
232 }
233 }
234}
235
236impl BinEncodable for SSHFP {
237 fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
238 encoder.emit_u8(self.algorithm().into())?;
239 encoder.emit_u8(self.fingerprint_type().into())?;
240 encoder.emit_vec(self.fingerprint())
241 }
242}
243
244impl<'r> RecordDataDecodable<'r> for SSHFP {
245 fn read_data(decoder: &mut BinDecoder<'r>, length: Restrict<u16>) -> ProtoResult<Self> {
246 let algorithm = decoder.read_u8()?.unverified().into();
247 let fingerprint_type = decoder.read_u8()?.unverified().into();
248 let fingerprint_len = length
249 .map(|l| l as usize)
250 .checked_sub(2)
251 .map_err(|_| ProtoError::from("invalid rdata length in SSHFP"))?
252 .unverified();
253 let fingerprint = decoder.read_vec(fingerprint_len)?.unverified();
254 Ok(SSHFP::new(algorithm, fingerprint_type, fingerprint))
255 }
256}
257
258impl RecordData for SSHFP {
259 fn try_from_rdata(data: RData) -> Result<Self, RData> {
260 match data {
261 RData::SSHFP(data) => Ok(data),
262 _ => Err(data),
263 }
264 }
265
266 fn try_borrow(data: &RData) -> Option<&Self> {
267 match data {
268 RData::SSHFP(data) => Some(data),
269 _ => None,
270 }
271 }
272
273 fn record_type(&self) -> RecordType {
274 RecordType::SSHFP
275 }
276
277 fn into_rdata(self) -> RData {
278 RData::SSHFP(self)
279 }
280}
281
282impl fmt::Display for SSHFP {
296 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
297 write!(
298 f,
299 "{algorithm} {ty} {fingerprint}",
300 algorithm = u8::from(self.algorithm),
301 ty = u8::from(self.fingerprint_type),
302 fingerprint = HEX.encode(&self.fingerprint),
303 )
304 }
305}
306
307#[cfg(test)]
308mod tests {
309 use super::*;
310
311 #[test]
312 fn read_algorithm() {
313 assert_eq!(Algorithm::Reserved, 0.into());
314 assert_eq!(Algorithm::RSA, 1.into());
315 assert_eq!(Algorithm::DSA, 2.into());
316 assert_eq!(Algorithm::ECDSA, 3.into());
317 assert_eq!(Algorithm::Ed25519, 4.into());
318 assert_eq!(Algorithm::Ed448, 6.into());
319 assert_eq!(Algorithm::Unassigned(17), 17.into());
320 assert_eq!(Algorithm::Unassigned(42), 42.into());
321
322 assert_eq!(0u8, Algorithm::Reserved.into());
323 assert_eq!(1u8, Algorithm::RSA.into());
324 assert_eq!(2u8, Algorithm::DSA.into());
325 assert_eq!(3u8, Algorithm::ECDSA.into());
326 assert_eq!(4u8, Algorithm::Ed25519.into());
327 assert_eq!(6u8, Algorithm::Ed448.into());
328 assert_eq!(17u8, Algorithm::Unassigned(17).into());
329 assert_eq!(42u8, Algorithm::Unassigned(42).into());
330 }
331
332 #[test]
333 fn read_fingerprint_type() {
334 assert_eq!(FingerprintType::Reserved, 0.into());
335 assert_eq!(FingerprintType::SHA1, 1.into());
336 assert_eq!(FingerprintType::SHA256, 2.into());
337 assert_eq!(FingerprintType::Unassigned(12), 12.into());
338 assert_eq!(FingerprintType::Unassigned(89), 89.into());
339
340 assert_eq!(0u8, FingerprintType::Reserved.into());
341 assert_eq!(1u8, FingerprintType::SHA1.into());
342 assert_eq!(2u8, FingerprintType::SHA256.into());
343 assert_eq!(12u8, FingerprintType::Unassigned(12).into());
344 assert_eq!(89u8, FingerprintType::Unassigned(89).into());
345 }
346
347 fn test_encode_decode(rdata: SSHFP, result: &[u8]) {
348 let mut bytes = Vec::new();
349 let mut encoder = BinEncoder::new(&mut bytes);
350 rdata.emit(&mut encoder).expect("failed to emit SSHFP");
351 let bytes = encoder.into_bytes();
352 assert_eq!(bytes, &result);
353
354 let mut decoder = BinDecoder::new(result);
355 let read_rdata = SSHFP::read_data(&mut decoder, Restrict::new(result.len() as u16))
356 .expect("failed to read SSHFP");
357 assert_eq!(read_rdata, rdata)
358 }
359
360 #[test]
361 fn test_encode_decode_sshfp() {
362 test_encode_decode(
363 SSHFP::new(Algorithm::RSA, FingerprintType::SHA256, vec![]),
364 &[1, 2],
365 );
366 test_encode_decode(
367 SSHFP::new(
368 Algorithm::ECDSA,
369 FingerprintType::SHA1,
370 vec![115, 115, 104, 102, 112],
371 ),
372 &[3, 1, 115, 115, 104, 102, 112],
373 );
374 test_encode_decode(
375 SSHFP::new(
376 Algorithm::Reserved,
377 FingerprintType::Reserved,
378 b"ssh fingerprint".to_vec(),
379 ),
380 &[
381 0, 0, 115, 115, 104, 32, 102, 105, 110, 103, 101, 114, 112, 114, 105, 110, 116,
382 ],
383 );
384 test_encode_decode(
385 SSHFP::new(
386 Algorithm::Unassigned(255),
387 FingerprintType::Unassigned(13),
388 vec![100, 110, 115, 115, 101, 99, 32, 100, 97, 110, 101],
389 ),
390 &[255, 13, 100, 110, 115, 115, 101, 99, 32, 100, 97, 110, 101],
391 );
392 }
393}