hickory_proto/rr/dnssec/rdata/
sig.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//! signature record for signing queries, updates, and responses
9use std::fmt;
10
11#[cfg(feature = "serde-config")]
12use serde::{Deserialize, Serialize};
13
14use crate::{
15    error::*,
16    rr::{dnssec::Algorithm, Name, RData, RecordData, RecordDataDecodable, RecordType},
17    serialize::binary::*,
18};
19
20use super::DNSSECRData;
21
22/// [RFC 2535](https://tools.ietf.org/html/rfc2535#section-4), Domain Name System Security Extensions, March 1999
23///
24/// NOTE: RFC 2535 was obsoleted with 4034+, with the exception of the
25///  usage for UPDATE, which is what this implementation is for.
26///
27/// ```text
28/// 4.1 SIG RDATA Format
29///
30///  The RDATA portion of a SIG RR is as shown below.  The integrity of
31///  the RDATA information is protected by the signature field.
32///
33///  1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
34///  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
35/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36/// |        type covered           |  algorithm    |     labels    |
37/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38/// |                         original TTL                          |
39/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40/// |                      signature expiration                     |
41/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42/// |                      signature inception                      |
43/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44/// |            key  tag           |                               |
45/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+         signer's name         +
46/// |                                                               /
47/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-/
48/// /                                                               /
49/// /                            signature                          /
50/// /                                                               /
51/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52///
53/// ```
54/// [RFC 2931](https://tools.ietf.org/html/rfc2931), DNS Request and Transaction Signatures, September 2000
55///
56/// NOTE: 2931 updates SIG0 to clarify certain particulars...
57///
58/// ```text
59/// RFC 2931                       DNS SIG(0)                 September 2000
60///
61/// 3. The SIG(0) Resource Record
62///
63///    The structure of and type number of SIG resource records (RRs) is
64///    given in [RFC 2535] Section 4.1.  However all of Section 4.1.8.1 and
65///    the parts of Sections 4.2 and 4.3 related to SIG(0) should be
66///    considered replaced by the material below.  Any conflict between [RFC
67///    2535] and this document concerning SIG(0) RRs should be resolved in
68///    favor of this document.
69///
70///    For all transaction SIG(0)s, the signer field MUST be a name of the
71///    originating host and there MUST be a KEY RR at that name with the
72///    public key corresponding to the private key used to calculate the
73///    signature.  (The host domain name used may be the inverse IP address
74///    mapping name for an IP address of the host if the relevant KEY is
75///    stored there.)
76///
77///    For all SIG(0) RRs, the owner name, class, TTL, and original TTL, are
78///    meaningless.  The TTL fields SHOULD be zero and the CLASS field
79///    SHOULD be ANY.  To conserve space, the owner name SHOULD be root (a
80///    single zero octet).  When SIG(0) authentication on a response is
81///    desired, that SIG RR MUST be considered the highest priority of any
82///    additional information for inclusion in the response. If the SIG(0)
83///    RR cannot be added without causing the message to be truncated, the
84///    server MUST alter the response so that a SIG(0) can be included.
85///    This response consists of only the question and a SIG(0) record, and
86///    has the TC bit set and RCODE 0 (NOERROR).  The client should at this
87///    point retry the request using TCP.
88///
89/// 3.1 Calculating Request and Transaction SIGs
90///
91///    A DNS request may be optionally signed by including one SIG(0)s at
92///    the end of the query additional information section.  Such a SIG is
93///    identified by having a "type covered" field of zero. It signs the
94///    preceding DNS request message including DNS header but not including
95///    the UDP/IP header and before the request RR counts have been adjusted
96///    for the inclusions of the request SIG(0).
97///
98///    It is calculated by using a "data" (see [RFC 2535], Section 4.1.8) of
99///    (1) the SIG's RDATA section entirely omitting (not just zeroing) the
100///    signature subfield itself, (2) the DNS query messages, including DNS
101///    header, but not the UDP/IP header and before the reply RR counts have
102///    been adjusted for the inclusion of the SIG(0).  That is
103///
104///       data = RDATA | request - SIG(0)
105///
106///    where "|" is concatenation and RDATA is the RDATA of the SIG(0) being
107///    calculated less the signature itself.
108///
109///    Similarly, a SIG(0) can be used to secure a response and the request
110///    that produced it.  Such transaction signatures are calculated by
111///    using a "data" of (1) the SIG's RDATA section omitting the signature
112///    itself, (2) the entire DNS query message that produced this response,
113///    including the query's DNS header but not its UDP/IP header, and (3)
114///    the entire DNS response message, including DNS header but not the
115///    UDP/IP header and before the response RR counts have been adjusted
116///    for the inclusion of the SIG(0).
117///
118///    That is
119///
120///       data = RDATA | full query | response - SIG(0)
121///
122///    where "|" is concatenation and RDATA is the RDATA of the SIG(0) being
123///    calculated less the signature itself.
124///
125///    Verification of a response SIG(0) (which is signed by the server host
126///    key, not the zone key) by the requesting resolver shows that the
127///    query and response were not tampered with in transit, that the
128///    response corresponds to the intended query, and that the response
129///    comes from the queried server.
130///
131///    In the case of a DNS message via TCP, a SIG(0) on the first data
132///    packet is calculated with "data" as above and for each subsequent
133///    packet, it is calculated as follows:
134///
135///       data = RDATA | DNS payload - SIG(0) | previous packet
136///
137///    where "|" is concatenations, RDATA is as above, and previous packet
138///    is the previous DNS payload including DNS header and the SIG(0) but
139///    not the TCP/IP header.  Support of SIG(0) for TCP is OPTIONAL.  As an
140///    alternative, TSIG may be used after, if necessary, setting up a key
141///    with TKEY [RFC 2930].
142///
143///    Except where needed to authenticate an update, TKEY, or similar
144///    privileged request, servers are not required to check a request
145///    SIG(0).
146///
147///    Note: requests and responses can either have a single TSIG or one
148///    SIG(0) but not both a TSIG and a SIG(0).
149///
150/// 3.2 Processing Responses and SIG(0) RRs
151///
152///    If a SIG RR is at the end of the additional information section of a
153///    response and has a type covered of zero, it is a transaction
154///    signature covering the response and the query that produced the
155///    response.  For TKEY responses, it MUST be checked and the message
156///    rejected if the checks fail unless otherwise specified for the TKEY
157///    mode in use.  For all other responses, it MAY be checked and the
158///    message rejected if the checks fail.
159///
160///    If a response's SIG(0) check succeed, such a transaction
161///    authentication SIG does NOT directly authenticate the validity any
162///    data-RRs in the message.  However, it authenticates that they were
163///    sent by the queried server and have not been diddled.  (Only a proper
164///    SIG(0) RR signed by the zone or a key tracing its authority to the
165///    zone or to static resolver configuration can directly authenticate
166///
167///    data-RRs, depending on resolver policy.) If a resolver or server does
168///    not implement transaction and/or request SIGs, it MUST ignore them
169///    without error where they are optional and treat them as failing where
170///    they are required.
171///
172/// 3.3 SIG(0) Lifetime and Expiration
173///
174///    The inception and expiration times in SIG(0)s are for the purpose of
175///    resisting replay attacks.  They should be set to form a time bracket
176///    such that messages outside that bracket can be ignored.  In IP
177///    networks, this time bracket should not normally extend further than 5
178///    minutes into the past and 5 minutes into the future.
179/// ```
180#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
181#[derive(Debug, PartialEq, Eq, Hash, Clone)]
182pub struct SIG {
183    type_covered: RecordType,
184    algorithm: Algorithm,
185    num_labels: u8,
186    original_ttl: u32,
187    sig_expiration: u32,
188    sig_inception: u32,
189    key_tag: u16,
190    signer_name: Name,
191    sig: Vec<u8>,
192}
193
194impl SIG {
195    /// Creates a new SIG record data, used for both RRSIG and SIG(0) records.
196    ///
197    /// # Arguments
198    ///
199    /// * `type_covered` - The `RecordType` which this signature covers, should be NULL for SIG(0).
200    /// * `algorithm` - The `Algorithm` used to generate the `signature`.
201    /// * `num_labels` - The number of labels in the name, should be less 1 for *.name labels,
202    ///                  see `Name::num_labels()`.
203    /// * `original_ttl` - The TTL for the RRSet stored in the zone, should be 0 for SIG(0).
204    /// * `sig_expiration` - Timestamp at which this signature is no longer valid, very important to
205    ///                      keep this low, < +5 minutes to limit replay attacks.
206    /// * `sig_inception` - Timestamp when this signature was generated.
207    /// * `key_tag` - See the key_tag generation in `rr::dnssec::Signer::key_tag()`.
208    /// * `signer_name` - Domain name of the server which was used to generate the signature.
209    /// * `sig` - signature stored in this record.
210    ///
211    /// # Return value
212    ///
213    /// The new SIG record data.
214    #[allow(clippy::too_many_arguments)]
215    pub fn new(
216        type_covered: RecordType,
217        algorithm: Algorithm,
218        num_labels: u8,
219        original_ttl: u32,
220        sig_expiration: u32,
221        sig_inception: u32,
222        key_tag: u16,
223        signer_name: Name,
224        sig: Vec<u8>,
225    ) -> Self {
226        Self {
227            type_covered,
228            algorithm,
229            num_labels,
230            original_ttl,
231            sig_expiration,
232            sig_inception,
233            key_tag,
234            signer_name,
235            sig,
236        }
237    }
238
239    /// Add actual signature value to existing SIG record data.
240    ///
241    /// # Arguments
242    ///
243    /// * `signature` - signature to be stored in this record.
244    ///
245    /// # Return value
246    ///
247    /// The new SIG record data.
248    pub fn set_sig(self, signature: Vec<u8>) -> Self {
249        Self {
250            type_covered: self.type_covered,
251            algorithm: self.algorithm,
252            num_labels: self.num_labels,
253            original_ttl: self.original_ttl,
254            sig_expiration: self.sig_expiration,
255            sig_inception: self.sig_inception,
256            key_tag: self.key_tag,
257            signer_name: self.signer_name,
258            sig: signature,
259        }
260    }
261
262    /// [RFC 2535](https://tools.ietf.org/html/rfc2535#section-4.1.1), Domain Name System Security Extensions, March 1999
263    ///
264    /// ```text
265    /// 4.1.1 Type Covered Field
266    ///
267    ///  The "type covered" is the type of the other RRs covered by this SIG.
268    /// ```
269    pub fn type_covered(&self) -> RecordType {
270        self.type_covered
271    }
272
273    /// [RFC 2535](https://tools.ietf.org/html/rfc2535#section-4.1.2), Domain Name System Security Extensions, March 1999
274    ///
275    /// ```text
276    /// 4.1.2 Algorithm Number Field
277    ///
278    ///  This octet is as described in section 3.2.
279    /// ```
280    pub fn algorithm(&self) -> Algorithm {
281        self.algorithm
282    }
283
284    /// [RFC 2535](https://tools.ietf.org/html/rfc2535#section-4.1.3), Domain Name System Security Extensions, March 1999
285    ///
286    /// ```text
287    /// 4.1.3 Labels Field
288    ///
289    ///  The "labels" octet is an unsigned count of how many labels there are
290    ///  in the original SIG RR owner name not counting the null label for
291    ///  root and not counting any initial "*" for a wildcard.  If a secured
292    ///  retrieval is the result of wild card substitution, it is necessary
293    ///  for the resolver to use the original form of the name in verifying
294    ///  the digital signature.  This field makes it easy to determine the
295    ///  original form.
296    ///
297    ///  If, on retrieval, the RR appears to have a longer name than indicated
298    ///  by "labels", the resolver can tell it is the result of wildcard
299    ///  substitution.  If the RR owner name appears to be shorter than the
300    ///  labels count, the SIG RR must be considered corrupt and ignored.  The
301    ///  maximum number of labels allowed in the current DNS is 127 but the
302    ///  entire octet is reserved and would be required should DNS names ever
303    ///  be expanded to 255 labels.  The following table gives some examples.
304    ///  The value of "labels" is at the top, the retrieved owner name on the
305    ///  left, and the table entry is the name to use in signature
306    ///  verification except that "bad" means the RR is corrupt.
307    ///
308    ///  labels= |  0  |   1  |    2   |      3   |      4   |
309    ///  --------+-----+------+--------+----------+----------+
310    ///         .|   . | bad  |  bad   |    bad   |    bad   |
311    ///        d.|  *. |   d. |  bad   |    bad   |    bad   |
312    ///      c.d.|  *. | *.d. |   c.d. |    bad   |    bad   |
313    ///    b.c.d.|  *. | *.d. | *.c.d. |   b.c.d. |    bad   |
314    ///  a.b.c.d.|  *. | *.d. | *.c.d. | *.b.c.d. | a.b.c.d. |
315    /// ```
316    pub fn num_labels(&self) -> u8 {
317        self.num_labels
318    }
319
320    /// [RFC 2535](https://tools.ietf.org/html/rfc2535#section-4.1.4), Domain Name System Security Extensions, March 1999
321    ///
322    /// ```text
323    /// 4.1.4 Original TTL Field
324    ///
325    ///  The "original TTL" field is included in the RDATA portion to avoid
326    ///  (1) authentication problems that caching servers would otherwise
327    ///  cause by decrementing the real TTL field and (2) security problems
328    ///  that unscrupulous servers could otherwise cause by manipulating the
329    ///  real TTL field.  This original TTL is protected by the signature
330    ///  while the current TTL field is not.
331    ///
332    ///  NOTE:  The "original TTL" must be restored into the covered RRs when
333    ///  the signature is verified (see Section 8).  This generally implies
334    ///  that all RRs for a particular type, name, and class, that is, all the
335    ///  RRs in any particular RRset, must have the same TTL to start with.
336    /// ```
337    pub fn original_ttl(&self) -> u32 {
338        self.original_ttl
339    }
340
341    /// [RFC 2535](https://tools.ietf.org/html/rfc2535#section-4.1.5), Domain Name System Security Extensions, March 1999
342    ///
343    /// ```text
344    /// 4.1.5 Signature Expiration and Inception Fields
345    ///
346    ///  The SIG is valid from the "signature inception" time until the
347    ///  "signature expiration" time.  Both are unsigned numbers of seconds
348    ///  since the start of 1 January 1970, GMT, ignoring leap seconds.  (See
349    ///  also Section 4.4.)  Ring arithmetic is used as for DNS SOA serial
350    ///  numbers [RFC 1982] which means that these times can never be more
351    ///  than about 68 years in the past or the future.  This means that these
352    ///  times are ambiguous modulo ~136.09 years.  However there is no
353    ///  security flaw because keys are required to be changed to new random
354    ///  keys by [RFC 2541] at least every five years.  This means that the
355    ///  probability that the same key is in use N*136.09 years later should
356    ///  be the same as the probability that a random guess will work.
357    ///
358    ///  A SIG RR may have an expiration time numerically less than the
359    ///  inception time if the expiration time is near the 32 bit wrap around
360    ///  point and/or the signature is long lived.
361    ///
362    ///  (To prevent misordering of network requests to update a zone
363    ///  dynamically, monotonically increasing "signature inception" times may
364    ///  be necessary.)
365    ///
366    ///  A secure zone must be considered changed for SOA serial number
367    ///  purposes not only when its data is updated but also when new SIG RRs
368    ///  are inserted (ie, the zone or any part of it is re-signed).
369    /// ```
370    pub fn sig_expiration(&self) -> u32 {
371        self.sig_expiration
372    }
373
374    /// see `get_sig_expiration`
375    pub fn sig_inception(&self) -> u32 {
376        self.sig_inception
377    }
378
379    /// [RFC 2535](https://tools.ietf.org/html/rfc2535#section-4.1.6), Domain Name System Security Extensions, March 1999
380    ///
381    /// ```text
382    /// 4.1.6 Key Tag Field
383    ///
384    ///  The "key Tag" is a two octet quantity that is used to efficiently
385    ///  select between multiple keys which may be applicable and thus check
386    ///  that a public key about to be used for the computationally expensive
387    ///  effort to check the signature is possibly valid.  For algorithm 1
388    ///  (MD5/RSA) as defined in [RFC 2537], it is the next to the bottom two
389    ///  octets of the public key modulus needed to decode the signature
390    ///  field.  That is to say, the most significant 16 of the least
391    ///  significant 24 bits of the modulus in network (big endian) order. For
392    ///  all other algorithms, including private algorithms, it is calculated
393    ///  as a simple checksum of the KEY RR as described in Appendix C.
394    /// ```
395    pub fn key_tag(&self) -> u16 {
396        self.key_tag
397    }
398
399    /// [RFC 2535](https://tools.ietf.org/html/rfc2535#section-4.1.7), Domain Name System Security Extensions, March 1999
400    ///
401    /// ```text
402    /// 4.1.7 Signer's Name Field
403    ///
404    ///  The "signer's name" field is the domain name of the signer generating
405    ///  the SIG RR.  This is the owner name of the public KEY RR that can be
406    ///  used to verify the signature.  It is frequently the zone which
407    ///  contained the RRset being authenticated.  Which signers should be
408    ///  authorized to sign what is a significant resolver policy question as
409    ///  discussed in Section 6. The signer's name may be compressed with
410    ///  standard DNS name compression when being transmitted over the
411    ///  network.
412    /// ```
413    pub fn signer_name(&self) -> &Name {
414        &self.signer_name
415    }
416
417    /// [RFC 2535](https://tools.ietf.org/html/rfc2535#section-4.1.8), Domain Name System Security Extensions, March 1999
418    ///
419    /// ```text
420    /// 4.1.8 Signature Field
421    ///
422    ///  The actual signature portion of the SIG RR binds the other RDATA
423    ///  fields to the RRset of the "type covered" RRs with that owner name
424    ///  and class.  This covered RRset is thereby authenticated.  To
425    ///  accomplish this, a data sequence is constructed as follows:
426    ///
427    ///  data = RDATA | RR(s)...
428    ///
429    ///  where "|" is concatenation,
430    ///
431    ///  RDATA is the wire format of all the RDATA fields in the SIG RR itself
432    ///  (including the canonical form of the signer's name) before but not
433    ///  including the signature, and
434    ///
435    ///  RR(s) is the RRset of the RR(s) of the type covered with the same
436    ///  owner name and class as the SIG RR in canonical form and order as
437    ///  defined in Section 8.
438    ///
439    ///  How this data sequence is processed into the signature is algorithm
440    ///  dependent.  These algorithm dependent formats and procedures are
441    ///  described in separate documents (Section 3.2).
442    ///
443    ///  SIGs SHOULD NOT be included in a zone for any "meta-type" such as
444    ///  ANY, AXFR, etc. (but see section 5.6.2 with regard to IXFR).
445    /// ```
446    pub fn sig(&self) -> &[u8] {
447        &self.sig
448    }
449}
450
451impl BinEncodable for SIG {
452    /// [RFC 4034](https://tools.ietf.org/html/rfc4034#section-6), DNSSEC Resource Records, March 2005
453    ///
454    /// This is accurate for all currently known name records.
455    ///
456    /// ```text
457    /// 6.2.  Canonical RR Form
458    ///
459    ///    For the purposes of DNS security, the canonical form of an RR is the
460    ///    wire format of the RR where:
461    ///
462    ///    ...
463    ///
464    ///    3.  if the type of the RR is NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
465    ///        HINFO, MINFO, MX, HINFO, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
466    ///        SRV, DNAME, A6, RRSIG, or (rfc6840 removes NSEC), all uppercase
467    ///        US-ASCII letters in the DNS names contained within the RDATA are replaced
468    ///        by the corresponding lowercase US-ASCII letters;
469    /// ```
470    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
471        let is_canonical_names = encoder.is_canonical_names();
472
473        self.type_covered().emit(encoder)?;
474        self.algorithm().emit(encoder)?;
475        encoder.emit(self.num_labels())?;
476        encoder.emit_u32(self.original_ttl())?;
477        encoder.emit_u32(self.sig_expiration())?;
478        encoder.emit_u32(self.sig_inception())?;
479        encoder.emit_u16(self.key_tag())?;
480        self.signer_name()
481            .emit_with_lowercase(encoder, is_canonical_names)?;
482        encoder.emit_vec(self.sig())?;
483        Ok(())
484    }
485}
486
487impl<'r> RecordDataDecodable<'r> for SIG {
488    fn read_data(decoder: &mut BinDecoder<'r>, length: Restrict<u16>) -> ProtoResult<Self> {
489        let start_idx = decoder.index();
490
491        // TODO should we verify here? or elsewhere...
492        let type_covered = RecordType::read(decoder)?;
493        let algorithm = Algorithm::read(decoder)?;
494        let num_labels = decoder.read_u8()?.unverified(/*technically valid as any u8*/);
495        let original_ttl = decoder.read_u32()?.unverified(/*valid as any u32*/);
496        let sig_expiration = decoder.read_u32()?.unverified(/*valid as any u32, in practice should be in the future*/);
497        let sig_inception = decoder.read_u32()?.unverified(/*valid as any u32, in practice should be before expiration*/);
498        let key_tag = decoder.read_u16()?.unverified(/*valid as any u16*/);
499        let signer_name = Name::read(decoder)?;
500
501        // read the signature, this will vary buy key size
502        let sig_len = length
503        .map(|u| u as usize)
504        .checked_sub(decoder.index() - start_idx)
505        .map_err(|_| ProtoError::from("invalid rdata length in SIG"))?
506        .unverified(/*used only as length safely*/);
507        let sig = decoder
508        .read_vec(sig_len)?
509        .unverified(/*will fail in usage if invalid*/);
510
511        Ok(Self::new(
512            type_covered,
513            algorithm,
514            num_labels,
515            original_ttl,
516            sig_expiration,
517            sig_inception,
518            key_tag,
519            signer_name,
520            sig,
521        ))
522    }
523}
524
525impl RecordData for SIG {
526    fn try_from_rdata(data: RData) -> Result<Self, RData> {
527        match data {
528            RData::DNSSEC(DNSSECRData::SIG(csync)) => Ok(csync),
529            _ => Err(data),
530        }
531    }
532
533    fn try_borrow(data: &RData) -> Option<&Self> {
534        match data {
535            RData::DNSSEC(DNSSECRData::SIG(csync)) => Some(csync),
536            _ => None,
537        }
538    }
539
540    fn record_type(&self) -> RecordType {
541        RecordType::SIG
542    }
543
544    fn into_rdata(self) -> RData {
545        RData::DNSSEC(DNSSECRData::SIG(self))
546    }
547}
548
549/// specifically for outputting the RData for an RRSIG, with signer_name in canonical form
550#[allow(clippy::too_many_arguments)]
551pub fn emit_pre_sig(
552    encoder: &mut BinEncoder<'_>,
553    type_covered: RecordType,
554    algorithm: Algorithm,
555    num_labels: u8,
556    original_ttl: u32,
557    sig_expiration: u32,
558    sig_inception: u32,
559    key_tag: u16,
560    signer_name: &Name,
561) -> ProtoResult<()> {
562    type_covered.emit(encoder)?;
563    algorithm.emit(encoder)?;
564    encoder.emit(num_labels)?;
565    encoder.emit_u32(original_ttl)?;
566    encoder.emit_u32(sig_expiration)?;
567    encoder.emit_u32(sig_inception)?;
568    encoder.emit_u16(key_tag)?;
569    signer_name.emit_as_canonical(encoder, true)?;
570    Ok(())
571}
572
573/// [RFC 2535](https://tools.ietf.org/html/rfc2535#section-7.2), Domain Name System Security Extensions, March 1999
574///
575/// ```text
576/// 7.2 Presentation of SIG RRs
577///
578///    A data SIG RR may be represented as a single logical line in a zone
579///    data file [RFC 1033] but there are some special considerations as
580///    described below.  (It does not make sense to include a transaction or
581///    request authenticating SIG RR in a file as they are a transient
582///    authentication that covers data including an ephemeral transaction
583///    number and so must be calculated in real time.)
584///
585///    There is no particular problem with the signer, covered type, and
586///    times.  The time fields appears in the form YYYYMMDDHHMMSS where YYYY
587///    is the year, the first MM is the month number (01-12), DD is the day
588///    of the month (01-31), HH is the hour in 24 hours notation (00-23),
589///    the second MM is the minute (00-59), and SS is the second (00-59).
590///
591///    The original TTL field appears as an unsigned integer.
592///
593///    If the original TTL, which applies to the type signed, is the same as
594///    the TTL of the SIG RR itself, it may be omitted.  The date field
595///    which follows it is larger than the maximum possible TTL so there is
596///    no ambiguity.
597///
598///    The "labels" field appears as an unsigned integer.
599///
600///    The key tag appears as an unsigned number.
601///
602///    However, the signature itself can be very long.  It is the last data
603///    field and is represented in base 64 (see Appendix A) and may be
604///    divided up into any number of white space separated substrings, down
605///    to single base 64 digits, which are concatenated to obtain the full
606///    signature.  These substrings can be split between lines using the
607///    standard parenthesis.
608///
609///   foo.nil.    SIG NXT 1 2 ( ;type-cov=NXT, alg=1, labels=2
610///     19970102030405 ;signature expiration
611///     19961211100908 ;signature inception
612///     2143           ;key identifier
613///     foo.nil.       ;signer
614///     AIYADP8d3zYNyQwW2EM4wXVFdslEJcUx/fxkfBeH1El4ixPFhpfHFElxbvKoWmvjDTCm
615///     fiYy2X+8XpFjwICHc398kzWsTMKlxovpz2FnCTM= ;signature (640 bits)
616/// ```
617impl fmt::Display for SIG {
618    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
619        write!(f, "{ty_covered} {alg} {num_labels} {original_ttl} {expire} {inception} {tag} {signer} {sig}",
620            ty_covered = self.type_covered,
621            alg = self.algorithm,
622            num_labels = self.num_labels,
623            original_ttl = self.original_ttl,
624            expire = self.sig_expiration,
625            inception = self.sig_inception,
626            tag = self.key_tag,
627            signer = self.signer_name,
628            sig = data_encoding::BASE64.encode(&self.sig)
629        )
630    }
631}
632
633#[cfg(test)]
634mod tests {
635    #![allow(clippy::dbg_macro, clippy::print_stdout)]
636
637    use super::*;
638
639    #[test]
640    fn test() {
641        use std::str::FromStr;
642
643        let rdata = SIG::new(
644            RecordType::NULL,
645            Algorithm::RSASHA256,
646            0,
647            0,
648            2,
649            1,
650            5,
651            Name::from_str("www.example.com").unwrap(),
652            vec![
653                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
654                23, 24, 25, 26, 27, 28, 29, 29, 31,
655            ], // 32 bytes for SHA256
656        );
657
658        let mut bytes = Vec::new();
659        let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
660        assert!(rdata.emit(&mut encoder).is_ok());
661        let bytes = encoder.into_bytes();
662
663        println!("bytes: {bytes:?}");
664
665        let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
666        let restrict = Restrict::new(bytes.len() as u16);
667        let read_rdata = SIG::read_data(&mut decoder, restrict).expect("Decoding error");
668        assert_eq!(rdata, read_rdata);
669    }
670}