caa.rs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. use log::*;
  2. use crate::wire::*;
  3. /// A **CAA** _(certification authority authorization)_ record. These allow
  4. /// domain names to specify which Certificate Authorities are allowed to issue
  5. /// certificates for the domain.
  6. ///
  7. /// # References
  8. ///
  9. /// - [RFC 6844](https://tools.ietf.org/html/rfc6844) — DNS Certification
  10. /// Authority Authorization Resource Record (January 2013)
  11. #[derive(PartialEq, Debug)]
  12. pub struct CAA {
  13. /// Whether this record is marked as “critical” or not.
  14. pub critical: bool,
  15. /// The “tag” part of the CAA record.
  16. pub tag: Box<[u8]>,
  17. /// The “value” part of the CAA record.
  18. pub value: Box<[u8]>,
  19. }
  20. impl Wire for CAA {
  21. const NAME: &'static str = "CAA";
  22. const RR_TYPE: u16 = 257;
  23. #[cfg_attr(feature = "with_mutagen", ::mutagen::mutate)]
  24. fn read(stated_length: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
  25. // flags
  26. let flags = c.read_u8()?;
  27. trace!("Parsed flags -> {:#08b}", flags);
  28. let has_bit = |bit| { flags & bit == bit };
  29. let critical = has_bit(0b_1000_0000);
  30. trace!("Parsed critical flag -> {:?}", critical);
  31. // tag
  32. let tag_length = c.read_u8()?;
  33. trace!("Parsed tag length -> {:?}", tag_length);
  34. let mut tag = vec![0_u8; usize::from(tag_length)].into_boxed_slice();
  35. c.read_exact(&mut tag)?;
  36. trace!("Parsed tag -> {:?}", String::from_utf8_lossy(&tag));
  37. // value
  38. let remaining_length = stated_length.saturating_sub(u16::from(tag_length)).saturating_sub(2);
  39. trace!("Remaining length -> {:?}", remaining_length);
  40. let mut value = vec![0_u8; usize::from(remaining_length)].into_boxed_slice();
  41. c.read_exact(&mut value)?;
  42. trace!("Parsed value -> {:?}", String::from_utf8_lossy(&value));
  43. Ok(Self { critical, tag, value })
  44. }
  45. }
  46. #[cfg(test)]
  47. mod test {
  48. use super::*;
  49. use pretty_assertions::assert_eq;
  50. #[test]
  51. fn parses_non_critical() {
  52. let buf = &[
  53. 0x00, // flags (all unset)
  54. 0x09, // tag length
  55. 0x69, 0x73, 0x73, 0x75, 0x65, 0x77, 0x69, 0x6c, 0x64, // tag
  56. 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, // value
  57. ];
  58. assert_eq!(CAA::read(buf.len() as _, &mut Cursor::new(buf)).unwrap(),
  59. CAA {
  60. critical: false,
  61. tag: Box::new(*b"issuewild"),
  62. value: Box::new(*b"entrust.net"),
  63. });
  64. }
  65. #[test]
  66. fn parses_critical() {
  67. let buf = &[
  68. 0x80, // flags (critical bit set)
  69. 0x09, // tag length
  70. 0x69, 0x73, 0x73, 0x75, 0x65, 0x77, 0x69, 0x6c, 0x64, // tag
  71. 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, // value
  72. ];
  73. assert_eq!(CAA::read(buf.len() as _, &mut Cursor::new(buf)).unwrap(),
  74. CAA {
  75. critical: true,
  76. tag: Box::new(*b"issuewild"),
  77. value: Box::new(*b"entrust.net"),
  78. });
  79. }
  80. #[test]
  81. fn ignores_other_flags() {
  82. let buf = &[
  83. 0x7F, // flags (all except critical bit set)
  84. 0x01, // tag length
  85. 0x65, // tag
  86. 0x45, // value
  87. ];
  88. assert_eq!(CAA::read(buf.len() as _, &mut Cursor::new(buf)).unwrap(),
  89. CAA {
  90. critical: false,
  91. tag: Box::new(*b"e"),
  92. value: Box::new(*b"E"),
  93. });
  94. }
  95. #[test]
  96. fn record_empty() {
  97. assert_eq!(CAA::read(0, &mut Cursor::new(&[])),
  98. Err(WireError::IO));
  99. }
  100. #[test]
  101. fn buffer_ends_abruptly() {
  102. let buf = &[
  103. 0x00, // flags
  104. ];
  105. assert_eq!(CAA::read(23, &mut Cursor::new(buf)),
  106. Err(WireError::IO));
  107. }
  108. }