Skip to main content

hickory_proto/rr/rdata/
smimea.rs

1//! SMIMEA records for storing S/MIME certificate validation information
2
3use alloc::vec::Vec;
4use core::{fmt, ops::Deref};
5
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9use super::tlsa::{CertUsage, Matching, Selector, TLSA};
10use crate::{
11    error::ProtoResult,
12    rr::{RData, RecordData, RecordDataDecodable, RecordType},
13    serialize::{
14        binary::{BinDecoder, BinEncodable, BinEncoder, DecodeError, Restrict},
15        txt::ParseError,
16    },
17};
18
19/// [RFC 8162](https://datatracker.ietf.org/doc/html/rfc8162#section-2)
20///
21/// > The SMIMEA wire format and presentation format are the same as for
22/// > the [TLSA] record
23#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
24#[derive(Debug, PartialEq, Eq, Hash, Clone)]
25pub struct SMIMEA(pub TLSA);
26
27impl SMIMEA {
28    /// Construct a new SMIMEA
29    ///
30    /// [RFC 8162](https://datatracker.ietf.org/doc/html/rfc8162#section-2)
31    ///
32    /// ```text
33    /// 2.  The SMIMEA Resource Record
34    ///
35    ///    The SMIMEA DNS resource record (RR) is used to associate an end
36    ///    entity certificate or public key with the associated email address,
37    ///    thus forming a "SMIMEA certificate association".  The semantics of
38    ///    how the SMIMEA resource record is interpreted are given later in this
39    ///    document.  Note that the information returned in the SMIMEA record
40    ///    might be for the end entity certificate, or it might be for the trust
41    ///    anchor or an intermediate certificate.  This mechanism is similar to
42    ///    the one given in [RFC7929] for OpenPGP.
43    ///
44    ///    The type value for the SMIMEA RRtype is defined in Section 8.  The
45    ///    SMIMEA resource record is class independent.
46    /// ```
47    pub fn new(
48        cert_usage: CertUsage,
49        selector: Selector,
50        matching: Matching,
51        cert_data: Vec<u8>,
52    ) -> Self {
53        Self(TLSA::new(cert_usage, selector, matching, cert_data))
54    }
55
56    /// Parse the RData from a set of Tokens
57    pub(crate) fn from_tokens<'i, I: Iterator<Item = &'i str>>(
58        tokens: I,
59    ) -> Result<Self, ParseError> {
60        TLSA::from_tokens(tokens).map(Self)
61    }
62}
63
64/// This implementation allows calling the associated functions of [TLSA] on [SMIMEA].
65/// Since they contain exactly the same data, duplicating them would be pointless.
66impl Deref for SMIMEA {
67    type Target = TLSA;
68
69    fn deref(&self) -> &Self::Target {
70        &self.0
71    }
72}
73
74impl BinEncodable for SMIMEA {
75    #[inline]
76    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
77        BinEncodable::emit(&self.0, encoder)
78    }
79}
80
81impl RecordDataDecodable<'_> for SMIMEA {
82    #[inline]
83    fn read_data(decoder: &mut BinDecoder<'_>, length: Restrict<u16>) -> Result<Self, DecodeError> {
84        TLSA::read_data(decoder, length).map(Self)
85    }
86}
87
88impl RecordData for SMIMEA {
89    fn try_borrow(data: &RData) -> Option<&Self> {
90        match data {
91            RData::SMIMEA(data) => Some(data),
92            _ => None,
93        }
94    }
95
96    fn record_type(&self) -> RecordType {
97        RecordType::SMIMEA
98    }
99
100    fn into_rdata(self) -> RData {
101        RData::SMIMEA(self)
102    }
103}
104
105impl fmt::Display for SMIMEA {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
107        fmt::Display::fmt(&self.0, f)
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn test_parsing() {
117        assert!(
118            SMIMEA::from_tokens(
119                vec![
120                    "0",
121                    "0",
122                    "1",
123                    "d2abde240d7cd3ee6b4b28c54df034b9",
124                    "7983a1d16e8a410e4561cb106618e971",
125                ]
126                .into_iter()
127            )
128            .is_ok()
129        );
130        assert!(
131            SMIMEA::from_tokens(
132                vec![
133                    "1",
134                    "1",
135                    "2",
136                    "92003ba34942dc74152e2f2c408d29ec",
137                    "a5a520e7f2e06bb944f4dca346baf63c",
138                    "1b177615d466f6c4b71c216a50292bd5",
139                    "8c9ebdd2f74e38fe51ffd48c43326cbc",
140                ]
141                .into_iter()
142            )
143            .is_ok()
144        );
145    }
146}