simple_dns/dns/rdata/
cert.rs

1use crate::{bytes_buffer::BytesBuffer, dns::WireFormat};
2use std::borrow::Cow;
3
4use super::RR;
5
6/// A Certificate record see [rfc4398](https://datatracker.ietf.org/doc/html/rfc4398)
7#[derive(Debug, PartialEq, Eq, Hash, Clone)]
8pub struct CERT<'a> {
9    /// The type of certificate (see RFC 4398 section 2.1)
10    pub type_code: u16,
11    /// The key tag value of the certificate public key
12    pub key_tag: u16,
13    /// The algorithm number describing the certificate's public key
14    pub algorithm: u8,
15    /// The certificate data in the format defined by the type_code
16    pub certificate: Cow<'a, [u8]>,
17}
18
19impl RR for CERT<'_> {
20    const TYPE_CODE: u16 = 37;
21}
22
23impl<'a> WireFormat<'a> for CERT<'a> {
24    const MINIMUM_LEN: usize = 5;
25
26    fn parse(data: &mut BytesBuffer<'a>) -> crate::Result<Self>
27    where
28        Self: Sized,
29    {
30        let type_code = data.get_u16()?;
31        let key_tag = data.get_u16()?;
32        let algorithm = data.get_u8()?;
33        let certificate = data.get_remaining();
34
35        Ok(Self {
36            type_code,
37            key_tag,
38            algorithm,
39            certificate: std::borrow::Cow::Borrowed(certificate),
40        })
41    }
42
43    fn write_to<T: std::io::Write>(&self, out: &mut T) -> crate::Result<()> {
44        out.write_all(&self.type_code.to_be_bytes())?;
45        out.write_all(&self.key_tag.to_be_bytes())?;
46        out.write_all(&[self.algorithm])?;
47        out.write_all(&self.certificate)?;
48
49        Ok(())
50    }
51
52    fn len(&self) -> usize {
53        self.certificate.len() + Self::MINIMUM_LEN
54    }
55}
56
57impl CERT<'_> {
58    /// Transforms the inner data into its owned type
59    pub fn into_owned<'b>(self) -> CERT<'b> {
60        CERT {
61            type_code: self.type_code,
62            key_tag: self.key_tag,
63            algorithm: self.algorithm,
64            certificate: self.certificate.into_owned().into(),
65        }
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use crate::{rdata::RData, ResourceRecord};
72
73    use super::*;
74
75    #[test]
76    fn parse_and_write_cert() {
77        let type_code = 12345u16;
78        let key_tag = 8u16;
79        let algorithm = 2u8;
80        let certificate = vec![1, 2, 3, 4, 5];
81        let rdata = CERT {
82            type_code,
83            key_tag,
84            algorithm,
85            certificate: Cow::Owned(certificate),
86        };
87        let mut writer = Vec::new();
88        rdata.write_to(&mut writer).unwrap();
89        let rdata = CERT::parse(&mut (&writer[..]).into()).unwrap();
90        assert_eq!(rdata.type_code, type_code);
91        assert_eq!(rdata.key_tag, key_tag);
92        assert_eq!(rdata.algorithm, algorithm);
93        assert_eq!(&*rdata.certificate, &[1, 2, 3, 4, 5]);
94    }
95
96    #[test]
97    fn parse_sample() -> Result<(), Box<dyn std::error::Error>> {
98        let sample_file = std::fs::read("samples/zonefile/CERT.sample")?;
99
100        let sample_rdata = match ResourceRecord::parse(&mut (&sample_file[..]).into())?.rdata {
101            RData::CERT(rdata) => rdata,
102            _ => unreachable!(),
103        };
104
105        assert_eq!(sample_rdata.type_code, 3);
106        assert_eq!(sample_rdata.key_tag, 0);
107        assert_eq!(sample_rdata.algorithm, 0);
108        assert_eq!(*sample_rdata.certificate, *b"\x00\x00\x00\x00\x00");
109
110        Ok(())
111    }
112}