hickory_proto/dnssec/
trust_anchor.rs1use alloc::{borrow::ToOwned, vec::Vec};
20#[cfg(feature = "text-parsing")]
21use core::str::FromStr;
22#[cfg(feature = "text-parsing")]
23use std::{fs, path::Path};
24
25use crate::dnssec::PublicKey;
26#[cfg(feature = "text-parsing")]
27use crate::serialize::txt::ParseError;
28#[cfg(feature = "text-parsing")]
29use crate::serialize::txt::trust_anchor::{self, Entry};
30
31#[cfg(feature = "text-parsing")]
32use super::Verifier;
33use super::{Algorithm, PublicKeyBuf};
34
35const ROOT_ANCHOR_2018: &[u8] = include_bytes!("roots/20326.rsa");
36const ROOT_ANCHOR_2024: &[u8] = include_bytes!("roots/38696.rsa");
37
38#[derive(Clone)]
40pub struct TrustAnchors {
41 pkeys: Vec<PublicKeyBuf>,
44}
45
46impl TrustAnchors {
47 #[cfg(feature = "text-parsing")]
49 pub fn from_file(path: &Path) -> Result<Self, ParseError> {
50 Self::from_str(&fs::read_to_string(path)?)
51 }
52
53 pub fn empty() -> Self {
57 Self { pkeys: vec![] }
58 }
59
60 pub fn contains<P: PublicKey + ?Sized>(&self, other_key: &P) -> bool {
62 self.pkeys.iter().any(|k| {
63 other_key.public_bytes() == k.public_bytes() && other_key.algorithm() == k.algorithm()
64 })
65 }
66
67 pub fn insert<P: PublicKey + ?Sized>(&mut self, public_key: &P) -> bool {
69 if self.contains(public_key) {
70 return false;
71 }
72
73 self.pkeys.push(PublicKeyBuf::new(
74 public_key.public_bytes().to_vec(),
75 public_key.algorithm(),
76 ));
77 true
78 }
79
80 pub fn get(&self, idx: usize) -> Option<&PublicKeyBuf> {
82 self.pkeys.get(idx)
83 }
84
85 pub fn len(&self) -> usize {
87 self.pkeys.len()
88 }
89
90 pub fn is_empty(&self) -> bool {
92 self.pkeys.is_empty()
93 }
94}
95
96#[cfg(feature = "text-parsing")]
97impl FromStr for TrustAnchors {
98 type Err = ParseError;
99
100 fn from_str(input: &str) -> Result<Self, Self::Err> {
101 let parser = trust_anchor::Parser::new(input);
102 let entries = parser.parse()?;
103
104 let mut pkeys = Vec::new();
105 for entry in entries {
106 let Entry::DNSKEY(record) = entry;
107 let dnskey = record.data();
108 let key = dnskey.key()?;
109 pkeys.push(PublicKeyBuf::new(
110 key.public_bytes().to_vec(),
111 dnskey.algorithm(),
112 ));
113 }
114
115 Ok(Self { pkeys })
116 }
117}
118
119impl Default for TrustAnchors {
120 fn default() -> Self {
121 Self {
122 pkeys: vec![
123 PublicKeyBuf::new(ROOT_ANCHOR_2018.to_owned(), Algorithm::RSASHA256),
124 PublicKeyBuf::new(ROOT_ANCHOR_2024.to_owned(), Algorithm::RSASHA256),
125 ],
126 }
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use crate::dnssec::{
133 Algorithm, PublicKey, PublicKeyBuf,
134 trust_anchor::{ROOT_ANCHOR_2024, TrustAnchors},
135 };
136 use alloc::borrow::ToOwned;
137
138 #[test]
139 fn test_contains_dnskey_bytes() {
140 let trust = TrustAnchors::default();
141 assert_eq!(trust.get(1).unwrap().public_bytes(), ROOT_ANCHOR_2024);
142 let pub_key = PublicKeyBuf::new(ROOT_ANCHOR_2024.to_owned(), Algorithm::RSASHA256);
143 assert!(trust.contains(&pub_key));
144 }
145
146 #[test]
147 #[cfg(feature = "text-parsing")]
148 fn can_load_trust_anchor_file() {
149 let input = include_str!("../../tests/test-data/root.key");
150
151 let trust_anchor = input.parse::<TrustAnchors>().unwrap();
152 assert_eq!(3, trust_anchor.len());
153 }
154}