hickory_proto/dnssec/rdata/
cds.rs1use alloc::vec::Vec;
11use core::fmt;
12
13#[cfg(feature = "serde")]
14use serde::{Deserialize, Serialize};
15
16use crate::{
17 dnssec::{Algorithm, DigestType},
18 error::ProtoResult,
19 rr::{RData, RecordData, RecordDataDecodable, RecordType},
20 serialize::binary::{
21 BinDecoder, BinEncodable, BinEncoder, DecodeError, Restrict, RestrictedMath,
22 },
23};
24
25use super::DNSSECRData;
26
27#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
29#[derive(Debug, PartialEq, Eq, Hash, Clone)]
30pub struct CDS {
31 key_tag: u16,
32 algorithm: Option<Algorithm>,
35 digest_type: DigestType,
36 digest: Vec<u8>,
37}
38
39impl CDS {
40 pub fn new(
53 key_tag: u16,
54 algorithm: Option<Algorithm>,
55 digest_type: DigestType,
56 digest: Vec<u8>,
57 ) -> Self {
58 Self {
59 key_tag,
60 algorithm,
61 digest_type,
62 digest,
63 }
64 }
65
66 pub fn key_tag(&self) -> u16 {
68 self.key_tag
69 }
70
71 pub fn algorithm(&self) -> Option<Algorithm> {
74 self.algorithm
75 }
76
77 pub fn is_delete(&self) -> bool {
79 self.algorithm.is_none()
80 }
81
82 pub fn digest_type(&self) -> DigestType {
84 self.digest_type
85 }
86
87 pub fn digest(&self) -> &[u8] {
89 &self.digest
90 }
91}
92
93impl From<CDS> for RData {
94 fn from(value: CDS) -> Self {
95 Self::DNSSEC(DNSSECRData::CDS(value))
96 }
97}
98
99impl BinEncodable for CDS {
100 fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
101 encoder.emit_u16(self.key_tag())?;
102 match self.algorithm() {
103 Some(algorithm) => algorithm.emit(encoder)?,
104 None => encoder.emit_u8(0)?,
105 }
106 encoder.emit(self.digest_type().into())?;
107 encoder.emit_vec(self.digest())?;
108
109 Ok(())
110 }
111}
112
113impl<'r> RecordDataDecodable<'r> for CDS {
114 fn read_data(decoder: &mut BinDecoder<'r>, length: Restrict<u16>) -> Result<Self, DecodeError> {
115 let start_idx = decoder.index();
116
117 let key_tag = decoder.read_u16()?.unverified();
118
119 let algorithm_value = decoder.read_u8()?.unverified();
120 let algorithm = match algorithm_value {
121 0 => None,
122 _ => Some(Algorithm::from_u8(algorithm_value)),
123 };
124
125 let digest_type =
126 DigestType::from(decoder.read_u8()?.unverified());
127
128 let bytes_read = decoder.index() - start_idx;
129 let left = length
130 .map(|u| u as usize)
131 .checked_sub(bytes_read)
132 .map_err(|len| DecodeError::IncorrectRDataLengthRead { read: bytes_read, len })?
133 .unverified();
134 let digest =
135 decoder.read_vec(left)?.unverified();
136
137 Ok(Self::new(key_tag, algorithm, digest_type, digest))
138 }
139}
140
141impl RecordData for CDS {
142 fn try_borrow(data: &RData) -> Option<&Self> {
143 match data {
144 RData::DNSSEC(DNSSECRData::CDS(cds)) => Some(cds),
145 _ => None,
146 }
147 }
148
149 fn record_type(&self) -> RecordType {
150 RecordType::CDS
151 }
152
153 fn into_rdata(self) -> RData {
154 RData::DNSSEC(DNSSECRData::CDS(self))
155 }
156}
157
158impl fmt::Display for CDS {
159 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
160 write!(
161 f,
162 "{tag} {alg} {ty} {digest}",
163 tag = self.key_tag,
164 alg = self.algorithm.map(u8::from).unwrap_or(0),
165 ty = u8::from(self.digest_type),
166 digest = data_encoding::HEXUPPER_PERMISSIVE.encode(&self.digest)
167 )
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 #![allow(clippy::dbg_macro, clippy::print_stdout)]
174
175 use alloc::vec::Vec;
176 use std::println;
177
178 use crate::{
179 dnssec::{Algorithm, DigestType},
180 rr::RecordDataDecodable,
181 serialize::binary::{BinDecoder, BinEncodable, BinEncoder, Restrict},
182 };
183
184 use super::CDS;
185
186 #[test]
187 fn test() {
188 let rdata = CDS::new(
189 0xF00F,
190 Some(Algorithm::RSASHA256),
191 DigestType::SHA256,
192 vec![5, 6, 7, 8],
193 );
194
195 let mut bytes = Vec::new();
196 let mut encoder = BinEncoder::new(&mut bytes);
197 rdata.emit(&mut encoder).expect("error encoding");
198 let bytes = encoder.into_bytes();
199
200 println!("bytes: {bytes:?}");
201
202 let mut decoder = BinDecoder::new(bytes);
203 let read_rdata = CDS::read_data(&mut decoder, Restrict::new(bytes.len() as u16))
204 .expect("error decoding");
205 assert_eq!(rdata, read_rdata);
206 }
207
208 #[test]
209 fn test_delete() {
210 let rdata = CDS::new(0, None, DigestType::Unknown(0), vec![0]);
211
212 let mut bytes = Vec::new();
213 let mut encoder = BinEncoder::new(&mut bytes);
214 rdata.emit(&mut encoder).expect("error encoding");
215 let bytes = encoder.into_bytes();
216
217 println!("bytes: {bytes:?}");
218
219 let mut decoder = BinDecoder::new(bytes);
220 let read_rdata = CDS::read_data(&mut decoder, Restrict::new(bytes.len() as u16))
221 .expect("error decoding");
222 assert_eq!(rdata, read_rdata);
223 }
224}