hickory_proto/rr/rdata/tlsa.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//! TLSA records for storing TLS certificate validation information
9
10use alloc::{string::String, vec::Vec};
11use core::fmt;
12
13#[cfg(feature = "serde")]
14use serde::{Deserialize, Serialize};
15
16use super::sshfp;
17use crate::{
18 error::ProtoResult,
19 rr::{RData, RecordData, RecordDataDecodable, RecordType},
20 serialize::{
21 binary::{BinDecoder, BinEncodable, BinEncoder, DecodeError, Restrict, RestrictedMath},
22 txt::ParseError,
23 },
24};
25
26/// [RFC 6698, DNS-Based Authentication for TLS](https://tools.ietf.org/html/rfc6698#section-2.1)
27///
28/// ```text
29/// 2.1. TLSA RDATA Wire Format
30///
31/// The RDATA for a TLSA RR consists of a one-octet certificate usage
32/// field, a one-octet selector field, a one-octet matching type field,
33/// and the certificate association data field.
34///
35/// 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
36/// 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
37/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38/// | Cert. Usage | Selector | Matching Type | /
39/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ /
40/// / /
41/// / Certificate Association Data /
42/// / /
43/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44/// ```
45#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
46#[derive(Debug, PartialEq, Eq, Hash, Clone)]
47#[non_exhaustive]
48pub struct TLSA {
49 /// Specifies the provided association that will be used to match the certificate
50 /// presented in the TLS handshake
51 pub cert_usage: CertUsage,
52
53 /// Specifies which part of the TLS certificate presented by the server will be
54 /// matched against the association data
55 pub selector: Selector,
56
57 /// Specifies how the certificate association is presented
58 pub matching: Matching,
59
60 /// Binary data for validating the cert, see other members to understand format
61 pub cert_data: Vec<u8>,
62}
63
64/// [RFC 6698, DNS-Based Authentication for TLS](https://tools.ietf.org/html/rfc6698#section-2.1.1)
65///
66/// ```text
67/// 2.1.1. The Certificate Usage Field
68///
69/// A one-octet value, called "certificate usage", specifies the provided
70/// association that will be used to match the certificate presented in
71/// the TLS handshake. This value is defined in a new IANA registry (see
72/// Section 7.2) in order to make it easier to add additional certificate
73/// usages in the future. The certificate usages defined in this
74/// document are:
75///
76/// 0 -- CA
77///
78/// 1 -- Service
79///
80/// 2 -- TrustAnchor
81///
82/// 3 -- DomainIssued
83///
84/// The certificate usages defined in this document explicitly only apply
85/// to PKIX-formatted certificates in DER encoding [X.690]. If TLS
86/// allows other formats later, or if extensions to this RRtype are made
87/// that accept other formats for certificates, those certificates will
88/// need their own certificate usage values.
89/// ```
90///
91/// [RFC 7218, Adding Acronyms to DANE Registries](https://datatracker.ietf.org/doc/html/rfc7218#section-2.1)
92///
93/// ```text
94/// 2.1. TLSA Certificate Usages Registry
95///
96/// The reference for this registry has been updated to include both
97/// [RFC6698] and this document.
98///
99/// +-------+----------+--------------------------------+-------------+
100/// | Value | Acronym | Short Description | Reference |
101/// +-------+----------+--------------------------------+-------------+
102/// | 0 | PKIX-TA | CA constraint | [RFC6698] |
103/// | 1 | PKIX-EE | Service certificate constraint | [RFC6698] |
104/// | 2 | DANE-TA | Trust anchor assertion | [RFC6698] |
105/// | 3 | DANE-EE | Domain-issued certificate | [RFC6698] |
106/// | 4-254 | | Unassigned | |
107/// | 255 | PrivCert | Reserved for Private Use | [RFC6698] |
108/// +-------+----------+--------------------------------+-------------+
109/// ```
110#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
111#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
112pub enum CertUsage {
113 /// ```text
114 /// 0 -- Certificate usage 0 is used to specify a CA certificate, or
115 /// the public key of such a certificate, that MUST be found in any of
116 /// the PKIX certification paths for the end entity certificate given
117 /// by the server in TLS. This certificate usage is sometimes
118 /// referred to as "CA constraint" because it limits which CA can be
119 /// used to issue certificates for a given service on a host. The
120 /// presented certificate MUST pass PKIX certification path
121 /// validation, and a CA certificate that matches the TLSA record MUST
122 /// be included as part of a valid certification path. Because this
123 /// certificate usage allows both trust anchors and CA certificates,
124 /// the certificate might or might not have the basicConstraints
125 /// extension present.
126 /// ```
127 #[cfg_attr(feature = "serde", serde(rename = "PKIX-TA"))]
128 PkixTa,
129
130 /// ```text
131 /// 1 -- Certificate usage 1 is used to specify an end entity
132 /// certificate, or the public key of such a certificate, that MUST be
133 /// matched with the end entity certificate given by the server in
134 /// TLS. This certificate usage is sometimes referred to as "service
135 /// certificate constraint" because it limits which end entity
136 /// certificate can be used by a given service on a host. The target
137 /// certificate MUST pass PKIX certification path validation and MUST
138 /// match the TLSA record.
139 /// ```
140 #[cfg_attr(feature = "serde", serde(rename = "PKIX-EE"))]
141 PkixEe,
142
143 /// ```text
144 /// 2 -- Certificate usage 2 is used to specify a certificate, or the
145 /// public key of such a certificate, that MUST be used as the trust
146 /// anchor when validating the end entity certificate given by the
147 /// server in TLS. This certificate usage is sometimes referred to as
148 /// "trust anchor assertion" and allows a domain name administrator to
149 /// specify a new trust anchor -- for example, if the domain issues
150 /// its own certificates under its own CA that is not expected to be
151 /// in the end users' collection of trust anchors. The target
152 /// certificate MUST pass PKIX certification path validation, with any
153 /// certificate matching the TLSA record considered to be a trust
154 /// anchor for this certification path validation.
155 /// ```
156 #[cfg_attr(feature = "serde", serde(rename = "DANE-TA"))]
157 DaneTa,
158
159 /// ```text
160 /// 3 -- Certificate usage 3 is used to specify a certificate, or the
161 /// public key of such a certificate, that MUST match the end entity
162 /// certificate given by the server in TLS. This certificate usage is
163 /// sometimes referred to as "domain-issued certificate" because it
164 /// allows for a domain name administrator to issue certificates for a
165 /// domain without involving a third-party CA. The target certificate
166 /// MUST match the TLSA record. The difference between certificate
167 /// usage 1 and certificate usage 3 is that certificate usage 1
168 /// requires that the certificate pass PKIX validation, but PKIX
169 /// validation is not tested for certificate usage 3.
170 /// ```
171 #[cfg_attr(feature = "serde", serde(rename = "DANE-EE"))]
172 DaneEe,
173
174 /// Unassigned at the time of this implementation
175 Unassigned(u8),
176
177 /// Private usage
178 Private,
179}
180
181impl From<u8> for CertUsage {
182 fn from(usage: u8) -> Self {
183 match usage {
184 0 => Self::PkixTa,
185 1 => Self::PkixEe,
186 2 => Self::DaneTa,
187 3 => Self::DaneEe,
188 4..=254 => Self::Unassigned(usage),
189 255 => Self::Private,
190 }
191 }
192}
193
194impl From<CertUsage> for u8 {
195 fn from(usage: CertUsage) -> Self {
196 match usage {
197 CertUsage::PkixTa => 0,
198 CertUsage::PkixEe => 1,
199 CertUsage::DaneTa => 2,
200 CertUsage::DaneEe => 3,
201 CertUsage::Unassigned(usage) => usage,
202 CertUsage::Private => 255,
203 }
204 }
205}
206
207/// [RFC 6698, DNS-Based Authentication for TLS](https://tools.ietf.org/html/rfc6698#section-2.1.1)
208///
209/// ```text
210/// 2.1.2. The Selector Field
211///
212/// A one-octet value, called "selector", specifies which part of the TLS
213/// certificate presented by the server will be matched against the
214/// association data. This value is defined in a new IANA registry (see
215/// Section 7.3). The selectors defined in this document are:
216///
217/// 0 -- Full
218///
219/// 1 -- Spki
220///
221/// (Note that the use of "selector" in this document is completely
222/// unrelated to the use of "selector" in DomainKeys Identified Mail
223/// (DKIM) [RFC6376].)
224/// ```
225#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
226#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
227pub enum Selector {
228 /// Full certificate: the Certificate binary structure as defined in [RFC5280](https://tools.ietf.org/html/rfc5280)
229 #[cfg_attr(feature = "serde", serde(rename = "Cert"))]
230 Full,
231
232 /// SubjectPublicKeyInfo: DER-encoded binary structure as defined in [RFC5280](https://tools.ietf.org/html/rfc5280)
233 #[cfg_attr(feature = "serde", serde(rename = "SPKI"))]
234 Spki,
235
236 /// Unassigned at the time of this writing
237 Unassigned(u8),
238
239 /// Private usage
240 #[cfg_attr(feature = "serde", serde(rename = "PrivSel"))]
241 Private,
242}
243
244impl From<u8> for Selector {
245 fn from(selector: u8) -> Self {
246 match selector {
247 0 => Self::Full,
248 1 => Self::Spki,
249 2..=254 => Self::Unassigned(selector),
250 255 => Self::Private,
251 }
252 }
253}
254
255impl From<Selector> for u8 {
256 fn from(selector: Selector) -> Self {
257 match selector {
258 Selector::Full => 0,
259 Selector::Spki => 1,
260 Selector::Unassigned(selector) => selector,
261 Selector::Private => 255,
262 }
263 }
264}
265
266/// [RFC 6698, DNS-Based Authentication for TLS](https://tools.ietf.org/html/rfc6698#section-2.1.3)
267///
268/// ```text
269/// 2.1.3. The Matching Type Field
270///
271/// A one-octet value, called "matching type", specifies how the
272/// certificate association is presented. This value is defined in a new
273/// IANA registry (see Section 7.4). The types defined in this document
274/// are:
275///
276/// 0 -- Raw
277///
278/// 1 -- Sha256
279///
280/// 2 -- Sha512
281///
282/// If the TLSA record's matching type is a hash, having the record use
283/// the same hash algorithm that was used in the signature in the
284/// certificate (if possible) will assist clients that support a small
285/// number of hash algorithms.
286/// ```
287#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
288#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
289pub enum Matching {
290 /// Exact match on selected content
291 #[cfg_attr(feature = "serde", serde(rename = "Full"))]
292 Raw,
293
294 /// SHA-256 hash of selected content [RFC6234](https://tools.ietf.org/html/rfc6234)
295 #[cfg_attr(feature = "serde", serde(rename = "SHA2-256"))]
296 Sha256,
297
298 /// SHA-512 hash of selected content [RFC6234](https://tools.ietf.org/html/rfc6234)
299 #[cfg_attr(feature = "serde", serde(rename = "SHA2-512"))]
300 Sha512,
301
302 /// Unassigned at the time of this writing
303 Unassigned(u8),
304
305 /// Private usage
306 #[cfg_attr(feature = "serde", serde(rename = "PrivMatch"))]
307 Private,
308}
309
310impl From<u8> for Matching {
311 fn from(matching: u8) -> Self {
312 match matching {
313 0 => Self::Raw,
314 1 => Self::Sha256,
315 2 => Self::Sha512,
316 3..=254 => Self::Unassigned(matching),
317 255 => Self::Private,
318 }
319 }
320}
321
322impl From<Matching> for u8 {
323 fn from(matching: Matching) -> Self {
324 match matching {
325 Matching::Raw => 0,
326 Matching::Sha256 => 1,
327 Matching::Sha512 => 2,
328 Matching::Unassigned(matching) => matching,
329 Matching::Private => 255,
330 }
331 }
332}
333
334impl TLSA {
335 /// Constructs a new TLSA
336 ///
337 /// [RFC 6698, DNS-Based Authentication for TLS](https://tools.ietf.org/html/rfc6698#section-2)
338 ///
339 /// ```text
340 /// 2. The TLSA Resource Record
341 ///
342 /// The TLSA DNS resource record (RR) is used to associate a TLS server
343 /// certificate or public key with the domain name where the record is
344 /// found, thus forming a "TLSA certificate association". The semantics
345 /// of how the TLSA RR is interpreted are given later in this document.
346 ///
347 /// The type value for the TLSA RR type is defined in Section 7.1.
348 ///
349 /// The TLSA RR is class independent.
350 ///
351 /// The TLSA RR has no special Time to Live (TTL) requirements.
352 /// ```
353 pub fn new(
354 cert_usage: CertUsage,
355 selector: Selector,
356 matching: Matching,
357 cert_data: Vec<u8>,
358 ) -> Self {
359 Self {
360 cert_usage,
361 selector,
362 matching,
363 cert_data,
364 }
365 }
366
367 /// Parse the RData from a set of Tokens
368 ///
369 /// [RFC 6698, DNS-Based Authentication for TLS](https://tools.ietf.org/html/rfc6698#section-2.2)
370 ///
371 /// ```text
372 /// 2.2. TLSA RR Presentation Format
373 ///
374 /// The presentation format of the RDATA portion (as defined in
375 /// [RFC1035]) is as follows:
376 ///
377 /// o The certificate usage field MUST be represented as an 8-bit
378 /// unsigned integer.
379 ///
380 /// o The selector field MUST be represented as an 8-bit unsigned
381 /// integer.
382 ///
383 /// o The matching type field MUST be represented as an 8-bit unsigned
384 /// integer.
385 ///
386 /// o The certificate association data field MUST be represented as a
387 /// string of hexadecimal characters. Whitespace is allowed within
388 /// the string of hexadecimal characters, as described in [RFC1035].
389 /// ```
390 pub(crate) fn from_tokens<'i, I: Iterator<Item = &'i str>>(
391 tokens: I,
392 ) -> Result<Self, ParseError> {
393 let mut iter = tokens;
394
395 let token: &str = iter
396 .next()
397 .ok_or(ParseError::Message("TLSA usage field missing"))?;
398 let cert_usage = CertUsage::from(to_u8(token)?);
399
400 let token = iter
401 .next()
402 .ok_or(ParseError::Message("TLSA selector field missing"))?;
403 let selector = to_u8(token)?.into();
404
405 let token = iter
406 .next()
407 .ok_or(ParseError::Message("TLSA matching field missing"))?;
408 let matching = to_u8(token)?.into();
409
410 // these are all in hex: "a string of hexadecimal characters"
411 // aside: personally I find it funny that the other fields are decimal, while this is hex encoded...
412 let cert_data = iter.fold(String::new(), |mut cert_data, data| {
413 cert_data.push_str(data);
414 cert_data
415 });
416 let cert_data = sshfp::HEX.decode(cert_data.as_bytes())?;
417
418 if !cert_data.is_empty() {
419 Ok(Self {
420 cert_usage,
421 selector,
422 matching,
423 cert_data,
424 })
425 } else {
426 Err(ParseError::Message("TLSA data field missing"))
427 }
428 }
429}
430
431impl BinEncodable for TLSA {
432 fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
433 encoder.emit_u8(self.cert_usage.into())?;
434 encoder.emit_u8(self.selector.into())?;
435 encoder.emit_u8(self.matching.into())?;
436 encoder.emit_vec(&self.cert_data)?;
437 Ok(())
438 }
439}
440
441impl RecordDataDecodable<'_> for TLSA {
442 /// Read the RData from the given Decoder
443 ///
444 /// ```text
445 /// 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
446 /// 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
447 /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
448 /// | Cert. Usage | Selector | Matching Type | /
449 /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ /
450 /// / /
451 /// / Certificate Association Data /
452 /// / /
453 /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
454 /// ```
455 fn read_data(
456 decoder: &mut BinDecoder<'_>,
457 rdata_length: Restrict<u16>,
458 ) -> Result<Self, DecodeError> {
459 let cert_usage = decoder.read_u8()?.unverified(/*CertUsage is verified*/).into();
460 let selector = decoder.read_u8()?.unverified(/*Selector is verified*/).into();
461 let matching = decoder.read_u8()?.unverified(/*Matching is verified*/).into();
462
463 // the remaining data is for the cert
464 let cert_len = rdata_length
465 .map(|u| u as usize)
466 .checked_sub(3)
467 .map_err(|len| DecodeError::IncorrectRDataLengthRead { read: 3, len })?
468 .unverified(/*used purely as length safely*/);
469 let cert_data = decoder.read_vec(cert_len)?.unverified(/*will fail in usage if invalid*/);
470
471 Ok(Self {
472 cert_usage,
473 selector,
474 matching,
475 cert_data,
476 })
477 }
478}
479
480impl RecordData for TLSA {
481 fn try_borrow(data: &RData) -> Option<&Self> {
482 match data {
483 RData::TLSA(data) => Some(data),
484 _ => None,
485 }
486 }
487
488 fn record_type(&self) -> RecordType {
489 RecordType::TLSA
490 }
491
492 fn into_rdata(self) -> RData {
493 RData::TLSA(self)
494 }
495}
496
497/// [RFC 6698, DNS-Based Authentication for TLS](https://tools.ietf.org/html/rfc6698#section-2.2)
498///
499/// ```text
500/// 2.2. TLSA RR Presentation Format
501///
502/// The presentation format of the RDATA portion (as defined in
503/// [RFC1035]) is as follows:
504///
505/// o The certificate usage field MUST be represented as an 8-bit
506/// unsigned integer.
507///
508/// o The selector field MUST be represented as an 8-bit unsigned
509/// integer.
510///
511/// o The matching type field MUST be represented as an 8-bit unsigned
512/// integer.
513///
514/// o The certificate association data field MUST be represented as a
515/// string of hexadecimal characters. Whitespace is allowed within
516/// the string of hexadecimal characters, as described in [RFC1035].
517///
518/// 2.3. TLSA RR Examples
519///
520/// In the following examples, the domain name is formed using the rules
521/// in Section 3.
522///
523/// An example of a hashed (SHA-256) association of a PKIX CA
524/// certificate:
525///
526/// _443._tcp.www.example.com. IN TLSA (
527/// 0 0 1 d2abde240d7cd3ee6b4b28c54df034b9
528/// 7983a1d16e8a410e4561cb106618e971 )
529///
530/// An example of a hashed (SHA-512) subject public key association of a
531/// PKIX end entity certificate:
532///
533/// _443._tcp.www.example.com. IN TLSA (
534/// 1 1 2 92003ba34942dc74152e2f2c408d29ec
535/// a5a520e7f2e06bb944f4dca346baf63c
536/// 1b177615d466f6c4b71c216a50292bd5
537/// 8c9ebdd2f74e38fe51ffd48c43326cbc )
538///
539/// An example of a full certificate association of a PKIX end entity
540/// certificate:
541///
542/// _443._tcp.www.example.com. IN TLSA (
543/// 3 0 0 30820307308201efa003020102020... )
544/// ```
545impl fmt::Display for TLSA {
546 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
547 write!(
548 f,
549 "{usage} {selector} {matching} {cert}",
550 usage = u8::from(self.cert_usage),
551 selector = u8::from(self.selector),
552 matching = u8::from(self.matching),
553 cert = sshfp::HEX.encode(&self.cert_data),
554 )
555 }
556}
557
558fn to_u8(data: &str) -> Result<u8, ParseError> {
559 data.parse().map_err(ParseError::from)
560}
561
562#[cfg(test)]
563mod tests {
564 #![allow(clippy::dbg_macro, clippy::print_stdout)]
565
566 #[cfg(feature = "std")]
567 use std::println;
568
569 use super::*;
570
571 #[test]
572 fn read_cert_usage() {
573 assert_eq!(CertUsage::PkixTa, CertUsage::from(0));
574 assert_eq!(CertUsage::PkixEe, CertUsage::from(1));
575 assert_eq!(CertUsage::DaneTa, CertUsage::from(2));
576 assert_eq!(CertUsage::DaneEe, CertUsage::from(3));
577 assert_eq!(CertUsage::Unassigned(4), CertUsage::from(4));
578 assert_eq!(CertUsage::Unassigned(254), CertUsage::from(254));
579 assert_eq!(CertUsage::Private, CertUsage::from(255));
580
581 assert_eq!(u8::from(CertUsage::PkixTa), 0);
582 assert_eq!(u8::from(CertUsage::PkixEe), 1);
583 assert_eq!(u8::from(CertUsage::DaneTa), 2);
584 assert_eq!(u8::from(CertUsage::DaneEe), 3);
585 assert_eq!(u8::from(CertUsage::Unassigned(4)), 4);
586 assert_eq!(u8::from(CertUsage::Unassigned(254)), 254);
587 assert_eq!(u8::from(CertUsage::Private), 255);
588 }
589
590 #[test]
591 fn read_selector() {
592 assert_eq!(Selector::Full, Selector::from(0));
593 assert_eq!(Selector::Spki, Selector::from(1));
594 assert_eq!(Selector::Unassigned(2), Selector::from(2));
595 assert_eq!(Selector::Unassigned(254), Selector::from(254));
596 assert_eq!(Selector::Private, Selector::from(255));
597
598 assert_eq!(u8::from(Selector::Full), 0);
599 assert_eq!(u8::from(Selector::Spki), 1);
600 assert_eq!(u8::from(Selector::Unassigned(2)), 2);
601 assert_eq!(u8::from(Selector::Unassigned(254)), 254);
602 assert_eq!(u8::from(Selector::Private), 255);
603 }
604
605 #[test]
606 fn read_matching() {
607 assert_eq!(Matching::Raw, Matching::from(0));
608 assert_eq!(Matching::Sha256, Matching::from(1));
609 assert_eq!(Matching::Sha512, Matching::from(2));
610 assert_eq!(Matching::Unassigned(3), Matching::from(3));
611 assert_eq!(Matching::Unassigned(254), Matching::from(254));
612 assert_eq!(Matching::Private, Matching::from(255));
613
614 assert_eq!(u8::from(Matching::Raw), 0);
615 assert_eq!(u8::from(Matching::Sha256), 1);
616 assert_eq!(u8::from(Matching::Sha512), 2);
617 assert_eq!(u8::from(Matching::Unassigned(3)), 3);
618 assert_eq!(u8::from(Matching::Unassigned(254)), 254);
619 assert_eq!(u8::from(Matching::Private), 255);
620 }
621
622 fn test_encode_decode(rdata: TLSA) {
623 let mut bytes = Vec::new();
624 let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
625 rdata.emit(&mut encoder).expect("failed to emit tlsa");
626 let bytes = encoder.into_bytes();
627
628 #[cfg(feature = "std")]
629 println!("bytes: {bytes:?}");
630
631 let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
632 let read_rdata = TLSA::read_data(&mut decoder, Restrict::new(bytes.len() as u16))
633 .expect("failed to read back");
634 assert_eq!(rdata, read_rdata);
635 }
636
637 #[test]
638 fn test_encode_decode_tlsa() {
639 test_encode_decode(TLSA::new(
640 CertUsage::PkixEe,
641 Selector::Spki,
642 Matching::Sha256,
643 vec![1, 2, 3, 4, 5, 6, 7, 8],
644 ));
645 test_encode_decode(TLSA::new(
646 CertUsage::PkixTa,
647 Selector::Full,
648 Matching::Raw,
649 vec![1, 2, 3, 4, 5, 6, 7, 8],
650 ));
651 test_encode_decode(TLSA::new(
652 CertUsage::DaneEe,
653 Selector::Full,
654 Matching::Sha512,
655 vec![1, 2, 3, 4, 5, 6, 7, 8],
656 ));
657 test_encode_decode(TLSA::new(
658 CertUsage::Unassigned(40),
659 Selector::Unassigned(39),
660 Matching::Unassigned(6),
661 vec![1, 2, 3, 4, 5, 6, 7, 8],
662 ));
663 }
664
665 #[test]
666 fn test_parsing() {
667 assert!(
668 TLSA::from_tokens(
669 vec![
670 "0",
671 "0",
672 "1",
673 "d2abde240d7cd3ee6b4b28c54df034b9",
674 "7983a1d16e8a410e4561cb106618e971",
675 ]
676 .into_iter()
677 )
678 .is_ok()
679 );
680 assert!(
681 TLSA::from_tokens(
682 vec![
683 "1",
684 "1",
685 "2",
686 "92003ba34942dc74152e2f2c408d29ec",
687 "a5a520e7f2e06bb944f4dca346baf63c",
688 "1b177615d466f6c4b71c216a50292bd5",
689 "8c9ebdd2f74e38fe51ffd48c43326cbc",
690 ]
691 .into_iter()
692 )
693 .is_ok()
694 );
695 }
696}