Skip to main content

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}