hickory_proto/rr/dnssec/rdata/
rrsig.rs

1// Copyright 2015-2023 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// https://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! RRSIG type and related implementations
9
10use std::{fmt, ops::Deref};
11
12#[cfg(feature = "serde-config")]
13use serde::{Deserialize, Serialize};
14
15use crate::{
16    error::ProtoResult,
17    rr::{dnssec::Algorithm, Name, RData, RecordData, RecordDataDecodable, RecordType},
18    serialize::binary::{BinDecoder, BinEncodable, BinEncoder, Restrict},
19};
20
21use super::{DNSSECRData, SIG};
22
23/// RRSIG is really a derivation of the original SIG record data. See SIG for more documentation
24#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
25#[derive(Debug, PartialEq, Eq, Hash, Clone)]
26pub struct RRSIG(SIG);
27
28impl RRSIG {
29    /// Creates a new SIG record data, used for both RRSIG and SIG(0) records.
30    ///
31    /// # Arguments
32    ///
33    /// * `type_covered` - The `RecordType` which this signature covers, should be NULL for SIG(0).
34    /// * `algorithm` - The `Algorithm` used to generate the `signature`.
35    /// * `num_labels` - The number of labels in the name, should be less 1 for *.name labels,
36    ///                  see `Name::num_labels()`.
37    /// * `original_ttl` - The TTL for the RRSet stored in the zone, should be 0 for SIG(0).
38    /// * `sig_expiration` - Timestamp at which this signature is no longer valid, very important to
39    ///                      keep this low, < +5 minutes to limit replay attacks.
40    /// * `sig_inception` - Timestamp when this signature was generated.
41    /// * `key_tag` - See the key_tag generation in `rr::dnssec::Signer::key_tag()`.
42    /// * `signer_name` - Domain name of the server which was used to generate the signature.
43    /// * `sig` - signature stored in this record.
44    ///
45    /// # Return value
46    ///
47    /// The new SIG record data.
48    #[allow(clippy::too_many_arguments)]
49    pub fn new(
50        type_covered: RecordType,
51        algorithm: Algorithm,
52        num_labels: u8,
53        original_ttl: u32,
54        sig_expiration: u32,
55        sig_inception: u32,
56        key_tag: u16,
57        signer_name: Name,
58        sig: Vec<u8>,
59    ) -> Self {
60        Self(SIG::new(
61            type_covered,
62            algorithm,
63            num_labels,
64            original_ttl,
65            sig_expiration,
66            sig_inception,
67            key_tag,
68            signer_name,
69            sig,
70        ))
71    }
72}
73
74impl Deref for RRSIG {
75    type Target = SIG;
76
77    fn deref(&self) -> &Self::Target {
78        &self.0
79    }
80}
81
82impl BinEncodable for RRSIG {
83    /// [RFC 4034](https://tools.ietf.org/html/rfc4034#section-6), DNSSEC Resource Records, March 2005
84    ///
85    /// This is accurate for all currently known name records.
86    ///
87    /// ```text
88    /// 6.2.  Canonical RR Form
89    ///
90    ///    For the purposes of DNS security, the canonical form of an RR is the
91    ///    wire format of the RR where:
92    ///
93    ///    ...
94    ///
95    ///    3.  if the type of the RR is NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
96    ///        HINFO, MINFO, MX, HINFO, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
97    ///        SRV, DNAME, A6, RRSIG, or (rfc6840 removes NSEC), all uppercase
98    ///        US-ASCII letters in the DNS names contained within the RDATA are replaced
99    ///        by the corresponding lowercase US-ASCII letters;
100    /// ```
101    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
102        self.0.emit(encoder)
103    }
104}
105
106impl<'r> RecordDataDecodable<'r> for RRSIG {
107    fn read_data(decoder: &mut BinDecoder<'r>, length: Restrict<u16>) -> ProtoResult<Self> {
108        SIG::read_data(decoder, length).map(Self)
109    }
110}
111
112impl RecordData for RRSIG {
113    fn try_from_rdata(data: RData) -> Result<Self, RData> {
114        match data {
115            RData::DNSSEC(DNSSECRData::RRSIG(csync)) => Ok(csync),
116            _ => Err(data),
117        }
118    }
119
120    fn try_borrow(data: &RData) -> Option<&Self> {
121        match data {
122            RData::DNSSEC(DNSSECRData::RRSIG(csync)) => Some(csync),
123            _ => None,
124        }
125    }
126
127    fn record_type(&self) -> RecordType {
128        RecordType::RRSIG
129    }
130
131    fn into_rdata(self) -> RData {
132        RData::DNSSEC(DNSSECRData::RRSIG(self))
133    }
134}
135
136impl fmt::Display for RRSIG {
137    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
138        write!(f, "{}", self.0)
139    }
140}