spiffe_rs/bundle/x509bundle/
mod.rs1use crate::internal::pemutil;
2use crate::internal::x509util;
3use crate::spiffeid::TrustDomain;
4use std::collections::HashMap;
5use std::fs;
6use std::io::Read;
7use std::sync::RwLock;
8
9#[derive(Debug, Clone)]
10pub struct Error(String);
11
12impl std::fmt::Display for Error {
13 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14 self.0.fmt(f)
15 }
16}
17
18impl std::error::Error for Error {}
19
20impl Error {
21 pub fn new(message: impl Into<String>) -> Error {
22 Error(message.into())
23 }
24}
25
26pub type Result<T> = std::result::Result<T, Error>;
27
28fn wrap_error(message: impl std::fmt::Display) -> Error {
29 Error(format!("x509bundle: {}", message))
30}
31
32#[derive(Debug)]
34pub struct Bundle {
35 trust_domain: TrustDomain,
36 x509_authorities: RwLock<Vec<Vec<u8>>>,
37}
38
39impl Bundle {
40 pub fn new(trust_domain: TrustDomain) -> Bundle {
42 Bundle {
43 trust_domain,
44 x509_authorities: RwLock::new(Vec::new()),
45 }
46 }
47
48 pub fn from_x509_authorities(trust_domain: TrustDomain, authorities: &[Vec<u8>]) -> Bundle {
50 Bundle {
51 trust_domain,
52 x509_authorities: RwLock::new(x509util::copy_x509_authorities(authorities)),
53 }
54 }
55
56 pub fn load(trust_domain: TrustDomain, path: &str) -> Result<Bundle> {
58 let bytes = fs::read(path)
59 .map_err(|err| wrap_error(format!("unable to load X.509 bundle file: {}", err)))?;
60 Bundle::parse(trust_domain, &bytes)
61 }
62
63 pub fn read(trust_domain: TrustDomain, reader: &mut dyn Read) -> Result<Bundle> {
65 let mut bytes = Vec::new();
66 reader
67 .read_to_end(&mut bytes)
68 .map_err(|err| wrap_error(format!("unable to read X.509 bundle: {}", err)))?;
69 Bundle::parse(trust_domain, &bytes)
70 }
71
72 pub fn parse(trust_domain: TrustDomain, bytes: &[u8]) -> Result<Bundle> {
74 let bundle = Bundle::new(trust_domain);
75 if bytes.is_empty() {
76 return Ok(bundle);
77 }
78 let certs = pemutil::parse_certificates(bytes)
79 .map_err(|err| wrap_error(format!("cannot parse certificate: {}", err)))?;
80 for cert in certs {
81 bundle.add_x509_authority(&cert);
82 }
83 Ok(bundle)
84 }
85
86 pub fn parse_raw(trust_domain: TrustDomain, bytes: &[u8]) -> Result<Bundle> {
88 let bundle = Bundle::new(trust_domain);
89 if bytes.is_empty() {
90 return Ok(bundle);
91 }
92 let certs = parse_raw_certificates(bytes)
93 .map_err(|err| wrap_error(format!("cannot parse certificate: {}", err)))?;
94 for cert in certs {
95 bundle.add_x509_authority(&cert);
96 }
97 Ok(bundle)
98 }
99
100 pub fn trust_domain(&self) -> TrustDomain {
102 self.trust_domain.clone()
103 }
104
105 pub fn x509_authorities(&self) -> Vec<Vec<u8>> {
107 self.x509_authorities
108 .read()
109 .map(|guard| x509util::copy_x509_authorities(&guard))
110 .unwrap_or_default()
111 }
112
113 pub fn add_x509_authority(&self, authority: &[u8]) {
115 if let Ok(mut guard) = self.x509_authorities.write() {
116 if guard.iter().any(|cert| cert == authority) {
117 return;
118 }
119 guard.push(authority.to_vec());
120 }
121 }
122
123 pub fn remove_x509_authority(&self, authority: &[u8]) {
125 if let Ok(mut guard) = self.x509_authorities.write() {
126 if let Some(index) = guard.iter().position(|cert| cert == authority) {
127 guard.remove(index);
128 }
129 }
130 }
131
132 pub fn has_x509_authority(&self, authority: &[u8]) -> bool {
134 self.x509_authorities
135 .read()
136 .map(|guard| guard.iter().any(|cert| cert == authority))
137 .unwrap_or(false)
138 }
139
140 pub fn set_x509_authorities(&self, authorities: &[Vec<u8>]) {
142 if let Ok(mut guard) = self.x509_authorities.write() {
143 *guard = x509util::copy_x509_authorities(authorities);
144 }
145 }
146
147 pub fn empty(&self) -> bool {
149 self.x509_authorities
150 .read()
151 .map(|guard| guard.is_empty())
152 .unwrap_or(true)
153 }
154
155 pub fn marshal(&self) -> Result<Vec<u8>> {
157 let certs = self.x509_authorities();
158 Ok(pemutil::encode_certificates(&certs))
159 }
160
161 pub fn equal(&self, other: &Bundle) -> bool {
163 self.trust_domain == other.trust_domain
164 && x509util::certs_equal(&self.x509_authorities(), &other.x509_authorities())
165 }
166
167 pub fn clone_bundle(&self) -> Bundle {
169 Bundle::from_x509_authorities(self.trust_domain(), &self.x509_authorities())
170 }
171
172 pub fn get_x509_bundle_for_trust_domain(&self, trust_domain: TrustDomain) -> Result<Bundle> {
174 if self.trust_domain != trust_domain {
175 return Err(wrap_error(format!(
176 "no X.509 bundle found for trust domain: \"{}\"",
177 trust_domain
178 )));
179 }
180 Ok(self.clone_bundle())
181 }
182}
183
184pub trait Source {
186 fn get_x509_bundle_for_trust_domain(&self, trust_domain: TrustDomain) -> Result<Bundle>;
188}
189
190#[derive(Debug)]
192pub struct Set {
193 bundles: RwLock<HashMap<TrustDomain, Bundle>>,
194}
195
196impl Set {
197 pub fn new(bundles: &[Bundle]) -> Set {
199 let mut map = HashMap::new();
200 for bundle in bundles {
201 map.insert(bundle.trust_domain(), bundle.clone_bundle());
202 }
203 Set {
204 bundles: RwLock::new(map),
205 }
206 }
207
208 pub fn add(&self, bundle: &Bundle) {
210 if let Ok(mut guard) = self.bundles.write() {
211 guard.insert(bundle.trust_domain(), bundle.clone_bundle());
212 }
213 }
214
215 pub fn remove(&self, trust_domain: TrustDomain) {
217 if let Ok(mut guard) = self.bundles.write() {
218 guard.remove(&trust_domain);
219 }
220 }
221
222 pub fn has(&self, trust_domain: TrustDomain) -> bool {
224 self.bundles
225 .read()
226 .map(|guard| guard.contains_key(&trust_domain))
227 .unwrap_or(false)
228 }
229
230 pub fn get(&self, trust_domain: TrustDomain) -> Option<Bundle> {
232 self.bundles
233 .read()
234 .ok()
235 .and_then(|guard| guard.get(&trust_domain).map(|b| b.clone_bundle()))
236 }
237
238 pub fn bundles(&self) -> Vec<Bundle> {
240 let mut bundles = self
241 .bundles
242 .read()
243 .map(|guard| guard.values().map(|b| b.clone_bundle()).collect::<Vec<_>>())
244 .unwrap_or_default();
245 bundles.sort_by(|a, b| a.trust_domain().compare(&b.trust_domain()));
246 bundles
247 }
248
249 pub fn len(&self) -> usize {
251 self.bundles.read().map(|guard| guard.len()).unwrap_or(0)
252 }
253
254 pub fn get_x509_bundle_for_trust_domain(&self, trust_domain: TrustDomain) -> Result<Bundle> {
256 let guard = self
257 .bundles
258 .read()
259 .map_err(|_| wrap_error("bundle store poisoned"))?;
260 let bundle = guard.get(&trust_domain).ok_or_else(|| {
261 wrap_error(format!(
262 "no X.509 bundle for trust domain \"{}\"",
263 trust_domain
264 ))
265 })?;
266 Ok(bundle.clone_bundle())
267 }
268}
269
270impl Source for Set {
271 fn get_x509_bundle_for_trust_domain(&self, trust_domain: TrustDomain) -> Result<Bundle> {
272 self.get_x509_bundle_for_trust_domain(trust_domain)
273 }
274}
275
276impl Source for Bundle {
277 fn get_x509_bundle_for_trust_domain(&self, trust_domain: TrustDomain) -> Result<Bundle> {
278 self.get_x509_bundle_for_trust_domain(trust_domain)
279 }
280}
281
282fn parse_raw_certificates(bytes: &[u8]) -> std::result::Result<Vec<Vec<u8>>, String> {
283 let mut remaining = bytes;
284 let mut certs = Vec::new();
285 while !remaining.is_empty() {
286 let (rest, _cert) = x509_parser::parse_x509_certificate(remaining)
287 .map_err(|err| err.to_string())?;
288 let consumed = remaining
289 .len()
290 .checked_sub(rest.len())
291 .ok_or_else(|| "invalid certificate length".to_string())?;
292 certs.push(remaining[..consumed].to_vec());
293 remaining = rest;
294 }
295 Ok(certs)
296}