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}