use log::*; use crate::wire::*; /// A **TLSA** _(TLS authentication)_ record, which contains a TLS certificate /// (or a public key, or its hash), associating it with a domain. /// /// # References /// /// [RFC 6698](https://tools.ietf.org/html/rfc6698) — The DNS-Based Authentication of Named Entities (DANE) Transport Layer Security Protocol: TLSA (August 2012) #[derive(PartialEq, Debug)] pub struct TLSA { /// A number representing the purpose of the certificate. pub certificate_usage: u8, /// A number representing which part of the certificate is returned in the /// data. This could be the full certificate, or just the public key. pub selector: u8, /// A number representing whether a certificate should be associated with /// the exact data, or with a hash of it. pub matching_type: u8, /// A series of bytes representing the certificate. pub certificate_data: Vec, } impl Wire for TLSA { const NAME: &'static str = "TLSA"; const RR_TYPE: u16 = 52; #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)] fn read(stated_length: u16, c: &mut Cursor<&[u8]>) -> Result { let certificate_usage = c.read_u8()?; trace!("Parsed certificate_usage -> {:?}", certificate_usage); let selector = c.read_u8()?; trace!("Parsed selector -> {:?}", selector); let matching_type = c.read_u8()?; trace!("Parsed matching type -> {:?}", matching_type); if stated_length <= 3 { let mandated_length = MandatedLength::AtLeast(4); return Err(WireError::WrongRecordLength { stated_length, mandated_length }); } let certificate_data_length = stated_length - 1 - 1 - 1; let mut certificate_data = Vec::new(); for _ in 0 .. certificate_data_length { certificate_data.push(c.read_u8()?); } Ok(Self { certificate_usage, selector, matching_type, certificate_data }) } } impl TLSA { /// Returns the hexadecimal representation of the fingerprint. pub fn hex_certificate_data(&self) -> String { self.certificate_data.iter() .map(|byte| format!("{:02x}", byte)) .collect() } } #[cfg(test)] mod test { use super::*; #[test] fn parses() { let buf = &[ 0x03, // certificate usage 0x01, // selector 0x01, // matching type 0x05, 0x95, 0x98, // data ]; assert_eq!(TLSA::read(buf.len() as _, &mut Cursor::new(buf)).unwrap(), TLSA { certificate_usage: 3, selector: 1, matching_type: 1, certificate_data: vec![ 0x05, 0x95, 0x98 ], }); } #[test] fn record_too_short() { let buf = &[ 0x03, // certificate usage 0x01, // selector 0x01, // matching type ]; assert_eq!(TLSA::read(buf.len() as _, &mut Cursor::new(buf)), Err(WireError::WrongRecordLength { stated_length: 3, mandated_length: MandatedLength::AtLeast(4) })); } #[test] fn record_empty() { assert_eq!(TLSA::read(0, &mut Cursor::new(&[])), Err(WireError::IO)); } #[test] fn buffer_ends_abruptly() { let buf = &[ 0x01, // certificate_usage ]; assert_eq!(TLSA::read(6, &mut Cursor::new(buf)), Err(WireError::IO)); } }