Skip to main content

signstar_config/config/file/
impl_all.rs

1//! Impls for [`UserBackendConnection`] and [`Config`] when using all HSM backends.
2//!
3//! # Note
4//!
5//! This module with `impl` blocks is only used, if all HSM backend features are used:
6//!
7//! - `nethsm`: for NetHSM backends
8//! - `yubihsm2`: for YubiHSM2 backends
9
10use std::collections::HashSet;
11
12use signstar_common::backend::BackendType;
13use signstar_crypto::{
14    AdministrativeSecretHandling,
15    NonAdministrativeSecretHandling,
16    traits::UserWithPassphrase,
17};
18
19use crate::{
20    config::{
21        AuthorizedKeyEntry,
22        Config,
23        ConfigAuthorizedKeyEntries,
24        ConfigBuilder,
25        ConfigSystemUserData,
26        ConfigSystemUserIds,
27        MappingAuthorizedKeyEntry,
28        MappingBackendUserSecrets,
29        MappingSystemUserId,
30        SystemConfig,
31        SystemUserData,
32        SystemUserId,
33        UserBackendConnection,
34        UserBackendConnectionFilter,
35        traits::NonAdminBackendUserIdFilter,
36    },
37    nethsm::NetHsmUserMapping,
38    yubihsm2::YubiHsm2UserMapping,
39};
40
41impl UserBackendConnection {
42    /// Returns the administrative secret handling of this [`UserBackendConnection`].
43    pub fn admin_secret_handling(&self) -> AdministrativeSecretHandling {
44        match self {
45            Self::NetHsm {
46                admin_secret_handling,
47                ..
48            } => *admin_secret_handling,
49            Self::YubiHsm2 {
50                admin_secret_handling,
51                ..
52            } => *admin_secret_handling,
53        }
54    }
55
56    /// Returns the non-administrative secret handling of this [`UserBackendConnection`].
57    pub fn non_admin_secret_handling(&self) -> NonAdministrativeSecretHandling {
58        match self {
59            Self::NetHsm {
60                non_admin_secret_handling,
61                ..
62            } => *non_admin_secret_handling,
63            Self::YubiHsm2 {
64                non_admin_secret_handling,
65                ..
66            } => *non_admin_secret_handling,
67        }
68    }
69
70    /// Creates on-disk secrets for non-administrative backend users of the mapping.
71    ///
72    /// # Note
73    ///
74    /// Delegates to [`MappingBackendUserSecrets::create_non_admin_backend_user_secrets`].
75    ///
76    /// # Errors
77    ///
78    /// Returns an error if [`MappingBackendUserSecrets::create_non_admin_backend_user_secrets`]
79    /// fails.
80    pub fn create_non_admin_backend_user_secrets(
81        &self,
82    ) -> Result<Option<Vec<Box<dyn UserWithPassphrase>>>, crate::Error> {
83        match self {
84            Self::NetHsm {
85                non_admin_secret_handling,
86                mapping,
87                ..
88            } => mapping.create_non_admin_backend_user_secrets(*non_admin_secret_handling),
89            Self::YubiHsm2 {
90                non_admin_secret_handling,
91                mapping,
92                ..
93            } => mapping.create_non_admin_backend_user_secrets(*non_admin_secret_handling),
94        }
95    }
96
97    /// Loads secrets for each backend user matching a `filter`.
98    ///
99    /// # Note
100    ///
101    /// Delegates to [`MappingBackendUserSecrets::load_non_admin_backend_user_secrets`].
102    ///
103    /// # Errors
104    ///
105    /// Returns an error if [`MappingBackendUserSecrets::load_non_admin_backend_user_secrets`]
106    /// fails.
107    pub fn load_non_admin_backend_user_secrets(
108        &self,
109        filter: NonAdminBackendUserIdFilter,
110    ) -> Result<Option<Vec<Box<dyn UserWithPassphrase>>>, crate::Error> {
111        match self {
112            Self::NetHsm {
113                non_admin_secret_handling,
114                mapping,
115                ..
116            } => mapping.load_non_admin_backend_user_secrets(*non_admin_secret_handling, filter),
117            Self::YubiHsm2 {
118                non_admin_secret_handling,
119                mapping,
120                ..
121            } => mapping.load_non_admin_backend_user_secrets(*non_admin_secret_handling, filter),
122        }
123    }
124}
125
126impl MappingSystemUserId for UserBackendConnection {
127    fn system_user_id(&self) -> Option<&SystemUserId> {
128        match self {
129            Self::NetHsm { mapping, .. } => mapping.system_user_id(),
130            Self::YubiHsm2 { mapping, .. } => mapping.system_user_id(),
131        }
132    }
133}
134
135impl MappingAuthorizedKeyEntry for UserBackendConnection {
136    fn authorized_key_entry(&self) -> Option<&AuthorizedKeyEntry> {
137        match self {
138            Self::NetHsm { mapping, .. } => mapping.authorized_key_entry(),
139            Self::YubiHsm2 { mapping, .. } => mapping.authorized_key_entry(),
140        }
141    }
142}
143
144impl Config {
145    /// Returns the optional [`UserBackendConnection`] matching a [`SystemUserId`].
146    pub fn user_backend_connection(&self, user: &SystemUserId) -> Option<UserBackendConnection> {
147        if let Some(nethsm_config) = self.nethsm.as_ref()
148            && let Some(mapping) = nethsm_config
149                .mappings()
150                .iter()
151                .find(|mapping| mapping.system_user_id().is_some_and(|id| id == user))
152        {
153            return Some(UserBackendConnection::NetHsm {
154                admin_secret_handling: *self.system.admin_secret_handling(),
155                non_admin_secret_handling: *self.system.non_admin_secret_handling(),
156                connections: nethsm_config.connections().clone(),
157                mapping: mapping.clone(),
158            });
159        }
160
161        if let Some(yubihsm2_config) = self.yubihsm2.as_ref()
162            && let Some(mapping) = yubihsm2_config
163                .mappings()
164                .iter()
165                .find(|mapping| mapping.system_user_id().is_some_and(|id| id == user))
166        {
167            return Some(UserBackendConnection::YubiHsm2 {
168                admin_secret_handling: *self.system.admin_secret_handling(),
169                non_admin_secret_handling: *self.system.non_admin_secret_handling(),
170                connections: yubihsm2_config.connections().clone(),
171                mapping: mapping.clone(),
172            });
173        }
174
175        None
176    }
177
178    /// Returns a list of [`UserBackendConnection`] objects matching a set of `filters`.
179    ///
180    /// If no `filters` are provided, returns all available [`UserBackendConnection`] objects of all
181    /// backends.
182    ///
183    /// Beyond filtering for specific backend types, it is possible to only return administrative or
184    /// non-administrative objects.
185    pub fn user_backend_connections(
186        &self,
187        filters: &[UserBackendConnectionFilter],
188    ) -> Vec<UserBackendConnection> {
189        let mut user_backend_connections = Vec::new();
190
191        if let Some(nethsm_config) = &self.nethsm
192            && (filters.is_empty()
193                || filters.contains(&UserBackendConnectionFilter::Backend(BackendType::NetHsm))
194                || !filters
195                    .iter()
196                    .any(|filter| matches!(filter, UserBackendConnectionFilter::Backend(_))))
197        {
198            let mappings = nethsm_config
199                .mappings()
200                .iter()
201                .filter(|mapping| {
202                    filters.is_empty()
203                        || matches!(filters, &[UserBackendConnectionFilter::Backend(_)])
204                        || (matches!(mapping, NetHsmUserMapping::Admin(_))
205                            && filters.contains(&UserBackendConnectionFilter::Admin))
206                        || match mapping {
207                            NetHsmUserMapping::Backup { .. }
208                            | NetHsmUserMapping::CertificateRetrieval { .. }
209                            | NetHsmUserMapping::HermeticMetrics { .. }
210                            | NetHsmUserMapping::Metrics { .. }
211                            | NetHsmUserMapping::Signing { .. } => {
212                                filters.contains(&UserBackendConnectionFilter::NonAdmin)
213                            }
214                            NetHsmUserMapping::Admin(_) => false,
215                        }
216                })
217                .collect::<Vec<_>>();
218            for mapping in mappings {
219                user_backend_connections.push(UserBackendConnection::NetHsm {
220                    admin_secret_handling: *self.system.admin_secret_handling(),
221                    non_admin_secret_handling: *self.system.non_admin_secret_handling(),
222                    connections: nethsm_config.connections().clone(),
223                    mapping: mapping.clone(),
224                });
225            }
226        }
227
228        if let Some(yubihsm2_config) = &self.yubihsm2
229            && (filters.is_empty()
230                || filters.contains(&UserBackendConnectionFilter::Backend(BackendType::YubiHsm2))
231                || !filters
232                    .iter()
233                    .any(|filter| matches!(filter, UserBackendConnectionFilter::Backend(_))))
234        {
235            let mappings = yubihsm2_config
236                .mappings()
237                .iter()
238                .filter(|mapping| {
239                    filters.is_empty()
240                        || matches!(filters, &[UserBackendConnectionFilter::Backend(_)])
241                        || (matches!(mapping, YubiHsm2UserMapping::Admin { .. })
242                            && filters.contains(&UserBackendConnectionFilter::Admin))
243                        || match mapping {
244                            YubiHsm2UserMapping::AuditLog { .. }
245                            | YubiHsm2UserMapping::Backup { .. }
246                            | YubiHsm2UserMapping::CertificateRetrieval { .. }
247                            | YubiHsm2UserMapping::HermeticAuditLog { .. }
248                            | YubiHsm2UserMapping::Signing { .. } => {
249                                filters.contains(&UserBackendConnectionFilter::NonAdmin)
250                            }
251                            YubiHsm2UserMapping::Admin { .. } => false,
252                        }
253                })
254                .collect::<Vec<_>>();
255            for mapping in mappings {
256                user_backend_connections.push(UserBackendConnection::YubiHsm2 {
257                    admin_secret_handling: *self.system.admin_secret_handling(),
258                    non_admin_secret_handling: *self.system.non_admin_secret_handling(),
259                    connections: yubihsm2_config.connections().clone(),
260                    mapping: mapping.clone(),
261                });
262            }
263        }
264
265        user_backend_connections
266    }
267}
268
269impl ConfigAuthorizedKeyEntries for Config {
270    fn authorized_key_entries(&self) -> HashSet<&AuthorizedKeyEntry> {
271        let mut output = self.system.authorized_key_entries();
272        if let Some(nethsm) = &self.nethsm {
273            output.extend(nethsm.authorized_key_entries());
274        }
275        if let Some(yubihsm2) = &self.yubihsm2 {
276            output.extend(yubihsm2.authorized_key_entries());
277        }
278
279        output
280    }
281}
282
283impl<'a> ConfigSystemUserData<'a> for Config {
284    fn system_user_data(&'a self) -> HashSet<SystemUserData<'a>> {
285        let mut output = HashSet::new();
286
287        for mapping in self.system.mappings() {
288            output.insert(mapping.into());
289        }
290
291        if let Some(config) = self.nethsm() {
292            for mapping in config.mappings() {
293                output.insert(mapping.into());
294            }
295        }
296
297        if let Some(config) = self.yubihsm2() {
298            for mapping in config.mappings() {
299                output.insert(mapping.into());
300            }
301        }
302
303        output
304    }
305}
306
307impl ConfigSystemUserIds for Config {
308    fn system_user_ids(&self) -> HashSet<&SystemUserId> {
309        let mut output = self.system.system_user_ids();
310        if let Some(nethsm) = &self.nethsm {
311            output.extend(nethsm.system_user_ids());
312        }
313        if let Some(yubihsm2) = &self.yubihsm2 {
314            output.extend(yubihsm2.system_user_ids());
315        }
316
317        output
318    }
319}
320
321impl ConfigBuilder {
322    /// Creates a new [`ConfigBuilder`].
323    pub fn new(system: SystemConfig) -> Self {
324        Self(Config {
325            system,
326            nethsm: None,
327            yubihsm2: None,
328        })
329    }
330}