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