|
@@ -0,0 +1,104 @@
|
|
|
+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<u8>,
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+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<Self, WireError> {
|
|
|
+
|
|
|
+ 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 {
|
|
|
+ panic!("Length too short");
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 buffer_ends_abruptly() {
|
|
|
+ let buf = &[
|
|
|
+ 0x01, // certificate_usage
|
|
|
+ ];
|
|
|
+
|
|
|
+ assert_eq!(TLSA::read(6, &mut Cursor::new(buf)),
|
|
|
+ Err(WireError::IO));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|