1use std::process::ExitCode;
4
5use clap::Parser;
6use clap_verbosity_flag::Verbosity;
7use nethsm::{KeyId, NetHsm};
8use nethsm_config::UserMapping;
9use signstar_config::{CredentialsLoading, Error as ConfigError};
10use signstar_request_signature::{Request, Response, Sha512};
11
12#[derive(Debug, thiserror::Error)]
14enum Error {
15 #[error("No key ID set for the operator user")]
17 NoKeyId,
18
19 #[error("Loading credentials encountered errors")]
21 HasUserIdErrors,
22
23 #[error("No credentials for the system user")]
25 NoCredentials,
26
27 #[error("Unsupported signing request parameters")]
29 UnsupportedParameters,
30
31 #[error("Config error")]
33 Config(#[from] ConfigError),
34
35 #[error("NetHsm error")]
37 NetHsm(#[from] nethsm::Error),
38
39 #[error("Signing request error: {0}")]
41 SigningRequest(#[from] signstar_request_signature::Error),
42
43 #[error(transparent)]
45 SignstarCommonLogging(#[from] signstar_common::logging::Error),
46}
47
48fn load_nethsm_keyid() -> Result<(NetHsm, KeyId), Error> {
59 let credentials_loading = CredentialsLoading::from_system_user()?;
60
61 if credentials_loading.has_userid_errors() {
62 return Err(Error::HasUserIdErrors);
63 }
64
65 if !credentials_loading.has_signing_user() {
66 return Err(Error::NoCredentials);
67 }
68
69 let key_id = if let UserMapping::SystemNetHsmOperatorSigning {
70 nethsm_key_setup, ..
71 } = credentials_loading.get_mapping().get_user_mapping()
72 {
73 nethsm_key_setup.get_key_id().clone()
74 } else {
75 return Err(Error::NoKeyId);
76 };
77
78 let connection = if let Some(connection) = credentials_loading
82 .get_mapping()
83 .get_connections()
84 .iter()
85 .next()
86 {
87 connection.clone()
88 } else {
89 return Err(Error::NoCredentials);
90 };
91
92 let credentials = credentials_loading.credentials_for_signing_user()?;
93
94 Ok((
95 NetHsm::new(connection, Some(credentials.into()), None, None)?,
96 key_id,
97 ))
98}
99
100fn sign_request(reader: impl std::io::Read, writer: impl std::io::Write) -> Result<(), Error> {
115 let req = Request::from_reader(reader)?;
116
117 if !req.required.output.is_openpgp_v4() {
118 Err(Error::UnsupportedParameters)?;
119 }
120
121 if req.version.major != 1 {
122 Err(Error::UnsupportedParameters)?;
123 }
124
125 let hasher: Sha512 = req.required.input.try_into()?;
126
127 let (nethsm, key_id) = load_nethsm_keyid()?;
128
129 let signature = nethsm.openpgp_sign_state(&key_id, hasher)?;
130
131 Response::v1(signature).to_writer(writer)?;
132
133 Ok(())
134}
135
136#[derive(Debug, Parser)]
137struct Cli {
138 #[command(flatten)]
139 verbosity: Verbosity,
140}
141
142fn main() -> ExitCode {
144 let args = Cli::parse();
145
146 if let Err(error) = signstar_common::logging::setup_logging(args.verbosity) {
147 eprintln!("{error}");
148 return ExitCode::FAILURE;
149 }
150
151 let result = sign_request(std::io::stdin(), std::io::stdout());
152
153 if let Err(error) = result {
154 log::error!(error:err; "Processing signing request failed: {error:#?}");
155 ExitCode::FAILURE
156 } else {
157 ExitCode::SUCCESS
158 }
159}