signstar_host/download_key_certificates/
backend.rs1use std::fmt::Display;
4#[cfg(feature = "nethsm")]
5use std::str::FromStr;
6
7use log::warn;
8#[cfg(feature = "nethsm")]
9use nethsm::{FullCredentials, NetHsm, signer::OwnedNetHsmKey};
10use signstar_common::{
11 backend::BackendType,
12 request_api::{Certificate, CertificateType},
13};
14use signstar_config::config::{
15 NonAdminBackendUserIdFilter,
16 NonAdminBackendUserIdKind,
17 SystemUserId,
18 UserBackendConnection,
19 UserBackendConnectionFilter,
20};
21#[cfg(feature = "nethsm")]
22use signstar_config::nethsm::{NetHsmUserMapping, nethsm_export::UserId};
23#[cfg(feature = "yubihsm2")]
24use signstar_config::yubihsm2::YubiHsm2UserMapping;
25use signstar_crypto::{
26 key::{CryptographicKeyContext, SigningKeySetup},
27 signer::traits::RawSigningKey,
28};
29#[cfg(feature = "yubihsm2")]
30use signstar_yubihsm2::{Connection, Credentials, YubiHsm2SigningKey};
31
32use crate::{config::load_config, download_key_certificates::Error};
33
34fn get_backend_certificates(
40 key_setup: SigningKeySetup,
41 signing_key_id: impl Display,
42 signers: &[impl RawSigningKey],
43 backend_id: BackendType,
44) -> Result<Vec<Certificate>, crate::Error> {
45 let certificate_type = if let CryptographicKeyContext::OpenPgp { .. } = key_setup.key_context()
46 {
47 CertificateType::OpenPgp
48 } else {
49 warn!("Unsupported key context for signing key {signing_key_id}");
50
51 return Ok(Vec::new());
52 };
53
54 let mut certificates = Vec::new();
55 for signer in signers.iter() {
56 if let Some(cert) = signer.certificate()? {
57 certificates.push(Certificate {
58 certificate: certificate_type.with_framing(&cert),
59 r#type: certificate_type,
60 backend_id,
61 signing_key_id: signing_key_id.to_string(),
62 });
63 }
64 }
65
66 Ok(certificates)
67}
68
69pub fn load_certificates() -> Result<Vec<Certificate>, crate::Error> {
87 let config = load_config()?;
88
89 let current_system_user = SystemUserId::from_current_unix_user().map_err(Box::new)?;
90
91 let Some(user_backend_connection) = config.user_backend_connection(¤t_system_user) else {
92 return Err(Error::NoCredentials {
93 user: current_system_user.to_string(),
94 }
95 .into());
96 };
97
98 let Some(creds) = user_backend_connection
99 .load_non_admin_backend_user_secrets(NonAdminBackendUserIdFilter {
100 backend_user_id_kind: NonAdminBackendUserIdKind::Observer,
101 })
102 .map_err(Box::new)?
103 else {
104 return Err(Error::NoCredentials {
105 user: current_system_user.to_string(),
106 }
107 .into());
108 };
109 if creds.is_empty() {
110 return Err(Error::NoCredentials {
111 user: current_system_user.to_string(),
112 }
113 .into());
114 }
115
116 let backend_type = match user_backend_connection {
117 #[cfg(feature = "nethsm")]
118 UserBackendConnection::NetHsm { .. } => BackendType::NetHsm,
119 #[cfg(feature = "yubihsm2")]
120 UserBackendConnection::YubiHsm2 { .. } => BackendType::YubiHsm2,
121 };
122
123 let mut certificates = Vec::new();
124
125 for user_backend_connection in config.user_backend_connections(&[
126 UserBackendConnectionFilter::Backend(backend_type),
127 UserBackendConnectionFilter::NonAdmin,
128 ]) {
129 match user_backend_connection {
130 #[cfg(feature = "nethsm")]
131 UserBackendConnection::NetHsm {
132 admin_secret_handling: _,
133 non_admin_secret_handling: _,
134 connections,
135 mapping:
136 NetHsmUserMapping::Signing {
137 backend_user,
138 signing_key_id,
139 key_setup,
140 ..
141 },
142 } => {
143 let connection = connections.first().cloned().ok_or(Error::NoConnection)?;
146
147 let signers = creds
148 .iter()
149 .map(|creds| {
150 Ok(FullCredentials::new(
151 UserId::from_str(&creds.user())?,
152 creds.passphrase().clone(),
153 ))
154 })
155 .collect::<Result<Vec<_>, <UserId as FromStr>::Err>>()
156 .map_err(|e| crate::Error::NetHsm(e.into()))?
157 .into_iter()
158 .filter(|cred| cred.name.namespace() == backend_user.namespace())
159 .map(|creds| {
160 OwnedNetHsmKey::new(
161 NetHsm::new(connection.clone(), Some(creds.into()), None, None)?,
162 signing_key_id.clone(),
163 )
164 })
165 .collect::<Result<Vec<_>, nethsm::Error>>()?;
166
167 certificates.extend(get_backend_certificates(
168 key_setup,
169 signing_key_id,
170 &signers,
171 BackendType::NetHsm,
172 )?)
173 }
174
175 #[cfg(feature = "yubihsm2")]
176 UserBackendConnection::YubiHsm2 {
177 admin_secret_handling: _,
178 non_admin_secret_handling: _,
179 connections,
180 mapping:
181 YubiHsm2UserMapping::Signing {
182 key_setup,
183 signing_key_id,
184 ..
185 },
186 } => {
187 let connection = connections.first().cloned().ok_or(Error::NoConnection)?;
190
191 let signers = creds
192 .iter()
193 .map(|creds| {
194 let creds = Credentials::new(
195 creds
196 .user()
197 .parse()
198 .map_err(|_| Error::InvalidUser { user: creds.user() })?,
199 creds.passphrase().clone(),
200 );
201
202 let signer = match connection {
203 #[cfg(feature = "_yubihsm2-mockhsm")]
204 Connection::Mock => YubiHsm2SigningKey::mock(signing_key_id, &creds)?,
205 Connection::Usb { serial_number } => {
206 YubiHsm2SigningKey::new_with_serial_number(
207 serial_number,
208 signing_key_id,
209 &creds,
210 )?
211 }
212 Connection::Http { ref url } => {
213 YubiHsm2SigningKey::new_remote(url.clone(), signing_key_id, &creds)?
214 }
215 };
216
217 Ok(signer)
218 })
219 .collect::<Result<Vec<_>, crate::Error>>()?;
220
221 certificates.extend(get_backend_certificates(
222 key_setup,
223 signing_key_id,
224 &signers,
225 BackendType::YubiHsm2,
226 )?)
227 }
228 _ => (),
229 }
230 }
231 Ok(certificates)
232}