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