spiffe/bundle/x509/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//! X.509 bundle types.

use crate::bundle::{Bundle, BundleRefSource};
use crate::cert::errors::CertificateError;
use crate::cert::parsing::{parse_der_encoded_bytes_as_x509_certificate, to_certificate_vec};
use crate::cert::Certificate;
use crate::spiffe_id::TrustDomain;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::error::Error;

/// This type contains a collection of trusted X.509 authorities for a [`TrustDomain`].
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct X509Bundle {
    trust_domain: TrustDomain,
    x509_authorities: Vec<Certificate>,
}

impl Bundle for X509Bundle {}

/// This type contains a set of [`X509Bundle`], keyed by [`TrustDomain`].
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct X509BundleSet {
    bundles: HashMap<TrustDomain, X509Bundle>,
}

/// An error that can arise trying to parse a [`X509Bundle`] from bytes
/// representing `DER` encoded X.509 authorities.
#[derive(Debug, thiserror::Error, PartialEq)]
#[non_exhaustive]
pub enum X509BundleError {
    /// Error processing or validating the X.509 certificates in the bundle.
    #[error(transparent)]
    Certificate(#[from] CertificateError),
}

impl X509Bundle {
    /// Creates an emtpy `X509Bundle` for the given [`TrustDomain`].
    pub fn new(trust_domain: TrustDomain) -> Self {
        X509Bundle {
            trust_domain,
            x509_authorities: Vec::new(),
        }
    }

    /// Creates a bundle from a slice of X.509 authorities as ASN.1 DER-encoded data (binary format).
    ///
    /// # Arguments
    ///
    /// * `authorities` - ASN.1 DER-encoded data (binary format) representing a list X.509 authorities.
    ///
    /// # Error
    ///
    /// If the function cannot parse the inputs, a [`X509BundleError`] variant will be returned.
    pub fn from_x509_authorities(
        trust_domain: TrustDomain,
        authorities: &[&[u8]],
    ) -> Result<Self, X509BundleError> {
        let mut x509_authorities = vec![];
        for authority in authorities
            .iter()
            .map(|&bytes| Certificate::try_from(bytes))
        {
            x509_authorities.push(authority?);
        }

        Ok(X509Bundle {
            trust_domain,
            x509_authorities,
        })
    }

    /// Parses a bundle from ASN.1 DER-encoded data (binary format) representing a list of X.509 authorities.
    ///
    /// # Arguments
    ///
    /// * `trust_domain` - A [`TrustDomain`] to associate to the bundle.
    /// * `bundle_der` - ASN.1 DER-encoded data (binary format) representing a list of X.509 authorities.
    ///
    /// # Error
    ///
    /// If the function cannot parse the inputs, a [`X509BundleError`] variant will be returned.
    pub fn parse_from_der(
        trust_domain: TrustDomain,
        bundle_der: &[u8],
    ) -> Result<Self, X509BundleError> {
        let x509_authorities = to_certificate_vec(bundle_der)?;

        // validate that all authorities are valid X.509 certificates
        for authority in x509_authorities.iter() {
            parse_der_encoded_bytes_as_x509_certificate(authority.content())?;
        }

        Ok(X509Bundle {
            trust_domain,
            x509_authorities,
        })
    }

    /// Adds an X.509 authority as ASN.1 DER-encoded data (binary format)to the bundle.
    /// It verifies that the `authorities_bytes` represents a valid DER-encoded X.509 certificate.
    ///
    /// # Arguments
    ///
    /// * `authority_bytes` - ASN.1 DER-encoded data (binary format) representing a X.509 authority.
    ///
    /// # Error
    ///
    /// If the function cannot parse the inputs, a [`X509BundleError`] variant will be returned.
    pub fn add_authority(&mut self, authority_bytes: &[u8]) -> Result<(), X509BundleError> {
        let certificate = Certificate::try_from(authority_bytes)?;
        self.x509_authorities.push(certificate);
        Ok(())
    }

    /// Returns the [`TrustDomain`]associated to the bundle.
    pub fn trust_domain(&self) -> &TrustDomain {
        &self.trust_domain
    }

    /// Returns the X.509 authorities in the bundle.
    pub fn authorities(&self) -> &Vec<Certificate> {
        &self.x509_authorities
    }
}

impl X509BundleSet {
    /// Creates a new empty `X509BundleSet`.
    pub fn new() -> Self {
        X509BundleSet {
            bundles: HashMap::new(),
        }
    }

    /// Adds a new [`X509Bundle`] into the set. If a bundle already exists for the
    /// trust domain, the existing bundle is replaced.
    pub fn add_bundle(&mut self, bundle: X509Bundle) {
        self.bundles.insert(bundle.trust_domain().clone(), bundle);
    }

    /// Returns the [`X509Bundle`] associated to the given [`TrustDomain`].
    pub fn get_bundle(&self, trust_domain: &TrustDomain) -> Option<&X509Bundle> {
        self.bundles.get(trust_domain)
    }
}

impl Default for X509BundleSet {
    fn default() -> Self {
        Self::new()
    }
}

impl BundleRefSource for X509BundleSet {
    type Item = X509Bundle;

    /// Returns the [`X509Bundle`] associated to the given [`TrustDomain`].
    fn get_bundle_for_trust_domain(
        &self,
        trust_domain: &TrustDomain,
    ) -> Result<Option<&Self::Item>, Box<dyn Error + Send + Sync + 'static>> {
        Ok(self.bundles.get(trust_domain))
    }
}