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