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