hickory_proto/dnssec/rdata/
cdnskey.rs1use alloc::vec::Vec;
11use core::fmt;
12
13#[cfg(feature = "serde")]
14use serde::{Deserialize, Serialize};
15
16use crate::{
17 ProtoError, ProtoErrorKind,
18 dnssec::{Algorithm, PublicKeyBuf},
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 CDNSKEY {
30 flags: u16,
31 algorithm: Option<Algorithm>,
32 public_key: Vec<u8>,
33}
34
35impl CDNSKEY {
36 pub fn new(
50 zone_key: bool,
51 secure_entry_point: bool,
52 revoke: bool,
53 algorithm: Option<Algorithm>,
54 public_key: Vec<u8>,
55 ) -> Self {
56 let mut flags: u16 = 0;
57 if zone_key {
58 flags |= 0b0000_0001_0000_0000;
59 }
60 if secure_entry_point {
61 flags |= 0b0000_0000_0000_0001;
62 }
63 if revoke {
64 flags |= 0b0000_0000_1000_0000;
65 }
66 Self::with_flags(flags, algorithm, public_key)
67 }
68
69 pub fn with_flags(flags: u16, algorithm: Option<Algorithm>, public_key: Vec<u8>) -> Self {
81 Self {
82 flags,
83 algorithm,
84 public_key,
85 }
86 }
87
88 pub fn zone_key(&self) -> bool {
90 self.flags & 0b0000_0001_0000_0000 != 0
91 }
92
93 pub fn secure_entry_point(&self) -> bool {
95 self.flags & 0b0000_0000_0000_0001 != 0
96 }
97
98 pub fn revoke(&self) -> bool {
100 self.flags & 0b0000_0000_1000_0000 != 0
101 }
102
103 pub fn algorithm(&self) -> Option<Algorithm> {
106 self.algorithm
107 }
108
109 pub fn is_delete(&self) -> bool {
111 self.algorithm.is_none()
112 }
113
114 pub fn public_key(&self) -> Option<PublicKeyBuf> {
116 Some(PublicKeyBuf::new(self.public_key.clone(), self.algorithm?))
117 }
118
119 pub fn flags(&self) -> u16 {
121 self.flags
122 }
123}
124
125impl From<CDNSKEY> for RData {
126 fn from(value: CDNSKEY) -> Self {
127 Self::DNSSEC(DNSSECRData::CDNSKEY(value))
128 }
129}
130
131impl BinEncodable for CDNSKEY {
132 fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
133 encoder.emit_u16(self.flags())?;
134 encoder.emit(3)?;
135 match self.algorithm() {
136 Some(algorithm) => algorithm.emit(encoder)?,
137 None => encoder.emit_u8(0)?,
138 }
139 encoder.emit_vec(&self.public_key)?;
140
141 Ok(())
142 }
143}
144
145impl<'r> RecordDataDecodable<'r> for CDNSKEY {
146 fn read_data(decoder: &mut BinDecoder<'r>, length: Restrict<u16>) -> ProtoResult<Self> {
147 let flags = decoder.read_u16()?.unverified();
148
149 let _protocol = decoder
151 .read_u8()?
152 .verify_unwrap(|protocol| *protocol == 3)
153 .map_err(|protocol| ProtoError::from(ProtoErrorKind::DnsKeyProtocolNot3(protocol)))?;
154
155 let algorithm_value = decoder.read_u8()?.unverified();
156 let algorithm = match algorithm_value {
157 0 => None,
158 _ => Some(Algorithm::from_u8(algorithm_value)),
159 };
160
161 let key_len = length
165 .map(|u| u as usize)
166 .checked_sub(4)
167 .map_err(|_| ProtoError::from("invalid rdata length in DNSKEY"))?
168 .unverified();
169 let public_key = decoder
170 .read_vec(key_len)?
171 .unverified();
172
173 Ok(Self::with_flags(flags, algorithm, public_key))
174 }
175}
176
177impl RecordData for CDNSKEY {
178 fn try_from_rdata(data: RData) -> Result<Self, RData> {
179 match data {
180 RData::DNSSEC(DNSSECRData::CDNSKEY(cdnskey)) => Ok(cdnskey),
181 _ => Err(data),
182 }
183 }
184
185 fn try_borrow(data: &RData) -> Option<&Self> {
186 match data {
187 RData::DNSSEC(DNSSECRData::CDNSKEY(cdnskey)) => Some(cdnskey),
188 _ => None,
189 }
190 }
191
192 fn record_type(&self) -> RecordType {
193 RecordType::CDNSKEY
194 }
195
196 fn into_rdata(self) -> RData {
197 RData::DNSSEC(DNSSECRData::CDNSKEY(self))
198 }
199}
200
201impl fmt::Display for CDNSKEY {
202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
203 write!(
204 f,
205 "{flags} 3 {alg} {key}",
206 flags = self.flags,
207 alg = self.algorithm.map(u8::from).unwrap_or(0),
208 key = data_encoding::BASE64.encode(&self.public_key)
209 )
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 #![allow(clippy::dbg_macro, clippy::print_stdout)]
216
217 use alloc::vec::Vec;
218 use std::println;
219
220 use crate::{
221 dnssec::Algorithm,
222 rr::RecordDataDecodable,
223 serialize::binary::{BinDecoder, BinEncodable, BinEncoder, Restrict},
224 };
225
226 use super::CDNSKEY;
227
228 #[test]
229 fn test() {
230 let rdata = CDNSKEY::new(
231 true,
232 true,
233 false,
234 Some(Algorithm::ECDSAP256SHA256),
235 vec![1u8, 2u8, 3u8, 4u8],
236 );
237
238 let mut bytes = Vec::new();
239 let mut encoder = BinEncoder::new(&mut bytes);
240 rdata.emit(&mut encoder).expect("error encoding");
241 let bytes = encoder.into_bytes();
242
243 println!("bytes: {bytes:?}");
244
245 let mut decoder = BinDecoder::new(bytes);
246 let read_rdata = CDNSKEY::read_data(&mut decoder, Restrict::new(bytes.len() as u16))
247 .expect("error decoding");
248
249 assert_eq!(rdata, read_rdata);
250 }
251
252 #[test]
253 fn test_delete() {
254 let rdata = CDNSKEY::with_flags(0, None, vec![0u8]);
255
256 let mut bytes = Vec::new();
257 let mut encoder = BinEncoder::new(&mut bytes);
258 rdata.emit(&mut encoder).expect("error encoding");
259 let bytes = encoder.into_bytes();
260
261 println!("bytes: {bytes:?}");
262
263 let mut decoder = BinDecoder::new(bytes);
264 let read_rdata = CDNSKEY::read_data(&mut decoder, Restrict::new(bytes.len() as u16))
265 .expect("error decoding");
266
267 assert_eq!(rdata, read_rdata);
268 }
269}