hickory_proto/dnssec/
trust_anchor.rs

1/*
2 * Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//! Allows for the root trust_anchor to either be added to or replaced for dns_sec validation.
18
19use 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/// The root set of trust anchors for validating DNSSEC, anything in this set will be trusted
39#[derive(Clone)]
40pub struct TrustAnchors {
41    // TODO: these should also store some information, or more specifically, metadata from the signed
42    //  public certificate.
43    pkeys: Vec<PublicKeyBuf>,
44}
45
46impl TrustAnchors {
47    /// loads a trust anchor from a file of DNSKEY records
48    #[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    /// Creates a new empty trust anchor set
54    ///
55    /// If you want to use the default root anchors, use `TrustAnchor::default()`.
56    pub fn empty() -> Self {
57        Self { pkeys: vec![] }
58    }
59
60    /// determines if the key is in the trust anchor set
61    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    /// inserts the trust_anchor to the trusted chain
68    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    /// get the trust anchor at the specified index
81    pub fn get(&self, idx: usize) -> Option<&PublicKeyBuf> {
82        self.pkeys.get(idx)
83    }
84
85    /// number of keys in trust_anchor
86    pub fn len(&self) -> usize {
87        self.pkeys.len()
88    }
89
90    /// returns true if there are no keys in the trust_anchor
91    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}