1use std::path::PathBuf;
2
3use chrono::{DateTime, Utc};
4use clap::{Parser, Subcommand};
5use expression_format::ex_format;
6use nethsm::{
7 KeyId,
8 OpenPgpUserId,
9 OpenPgpVersion,
10 UserRole::{Administrator, Operator},
11};
12use strum::IntoEnumIterator;
13
14use super::BIN_NAME;
15
16#[derive(Debug, Subcommand)]
18#[command(
19 about = "OpenPGP operations",
20 long_about = ex_format!("OpenPGP operations
21
22Supports creating OpenPGP certificates for existing keys, as well as cryptographic operations using those keys.
23
24Keys may exist in specific scopes: system-wide or in namespaces (see \"{BIN_NAME} namespace\").
25While system-wide users only have access to system-wide keys, namespaced users only have access to keys in their own namespace.")
26)]
27pub enum OpenPgpCommand {
28 Add(OpenPgpAddCommand),
30 Import(OpenPgpImportCommand),
32 Sign(OpenPgpSignCommand),
34 SignState(OpenPgpSignStateCommand),
36}
37
38#[derive(Debug, Parser)]
39#[command(
40 about = "Add an OpenPGP certificate for a key",
41 long_about = ex_format!("Add an OpenPGP certificate for a key
42
43Creates an OpenPGP certificate for an existing key.
44The created certificate is then added as the key's certificate (see \"{BIN_NAME} key cert import\").
45
46System-wide users in the \"{Administrator}\" and \"{Operator}\" role can only add OpenPGP certificates for system-wide keys.
47Namespaced users in the \"{Administrator}\" and \"{Operator}\" role can only add OpenPGP certificates for keys in their own namespace.
48
49Requires authentication of a user in the \"{Operator}\" role, that has access to the targeted key (see \"{BIN_NAME} key tag\" and \"{BIN_NAME} user tag\").
50Additionally, authentication of a user in the \"{Administrator}\" role is needed to import the certificate.")
51)]
52pub struct OpenPgpAddCommand {
53 #[arg(env = "NETHSM_KEY_ID", help = "The ID of the key to use")]
54 pub key_id: KeyId,
55
56 #[arg(env = "NETHSM_OPENPGP_USERID", help = "The User ID to use for the key")]
57 pub user_id: OpenPgpUserId,
58
59 #[arg(
60 env = "NETHSM_OPENPGP_CREATED_AT",
61 help = "The optional creation time of the certificate (defaults to now)",
62 long,
63 short
64 )]
65 pub time: Option<DateTime<Utc>>,
66
67 #[arg(
68 env = "NETHSM_OPENPGP_VERSION",
69 help = ex_format!("The OpenPGP version the certificate is created with (defaults to \"{OpenPgpVersion::default()}\")"),
70 long_help = ex_format!(
71 "The OpenPGP version the certificate is created with (defaults to \"{OpenPgpVersion::default()}\")
72
73One of {:?OpenPgpVersion::iter().map(Into::into).collect::<Vec<&'static str>>()}."
74 ),
75 long,
76 short
77 )]
78 pub version: Option<OpenPgpVersion>,
79
80 #[arg(
81 env = "NETHSM_OPENPGP_CERT_GENERATE_CAN_SIGN",
82 help = "Sets the signing key flag (default to set)",
83 long_help = "Sets the signing key flag (default to set)
84
85If this option is used, the key is created with a component key that has the signing key flag set.",
86 group = "sign-group",
87 long,
88 default_value_t = true
89 )]
90 pub can_sign: bool,
91
92 #[arg(
93 env = "NETHSM_OPENPGP_CERT_GENERATE_CANNOT_SIGN",
94 help = "Clears the signing key flag",
95 long_help = "Clears the signing key flag
96
97If this option is used, the key is created without a component key that has the signing key flag set.",
98 group = "sign-group",
99 long
100 )]
101 pub cannot_sign: bool,
102}
103
104#[derive(Debug, Parser)]
105#[command(
106 about = "Create an OpenPGP signature for a message",
107 long_about = ex_format!("Create an OpenPGP signature for a message
108
109The signature is written to stdout, unless a specific path to a file is provided.
110
111System-wide users in the \"{Operator}\" role can only create OpenPGP signatures for a message using system-wide keys.
112Namespaced users in the \"{Operator}\" role can only create OpenPGP signatures for a message using keys in their own namespace.
113
114Requires authentication of a user in the \"{Operator}\" role that has access to the targeted key (see \"{BIN_NAME} key tag\" and \"{BIN_NAME} user tag\").")
115)]
116pub struct OpenPgpSignCommand {
117 #[arg(env = "NETHSM_KEY_ID", help = "The ID of the key to use")]
118 pub key_id: KeyId,
119
120 #[arg(
121 env = "NETHSM_FORCE",
122 help = "Write to output file even if it exists already",
123 long,
124 short
125 )]
126 pub force: bool,
127
128 #[arg(
129 env = "NETHSM_OPENPGP_SIGNATURE_MESSAGE",
130 help = "The path to a message for which to create a signature"
131 )]
132 pub message: PathBuf,
133
134 #[arg(
135 env = "NETHSM_OPENPGP_SIGNATURE_OUTPUT_FILE",
136 help = "The optional path to a specific output file",
137 long,
138 short
139 )]
140 pub output: Option<PathBuf>,
141}
142
143#[derive(Debug, Parser)]
144#[command(
145 about = "Create an OpenPGP signature for a hasher state",
146 long_about = ex_format!("Create an OpenPGP signature for a hasher's state
147
148Requires a valid hasher state payload on stdin as produced by the `signstar-request-signature` binary.
149
150The signature is written to stdout, unless a specific path to a file is provided.
151
152Requires authentication of a user in the \"{Operator}\" role that has access to the targeted key.")
153)]
154pub struct OpenPgpSignStateCommand {
155 #[arg(env = "NETHSM_KEY_ID", help = "The ID of the key to use")]
156 pub key_id: KeyId,
157
158 #[arg(
159 env = "NETHSM_OPENPGP_REQUEST_SIGNATURE_FILE",
160 help = "The path to a valid signature request file"
161 )]
162 pub input: PathBuf,
163
164 #[arg(
165 env = "NETHSM_FORCE",
166 help = "Write to output file even if it exists already",
167 long,
168 short
169 )]
170 pub force: bool,
171
172 #[arg(
173 env = "NETHSM_OPENPGP_SIGNATURE_OUTPUT_FILE",
174 help = "The optional path to a specific output file",
175 long,
176 short
177 )]
178 pub output: Option<PathBuf>,
179}
180
181#[derive(Debug, Parser)]
182#[command(
183 about = "Import OpenPGP TSK-formatted private key",
184 long_about = ex_format!("Import OpenPGP Transferable Secret Key (TSK) formatted private key
185
186Only TSKs with a single component key are supported.
187
188System-wide users in the \"{Administrator}\" role can only import TSKs as system-wide keys.
189Namespaced users in the \"{Administrator}\" role can only import TSKs as keys in their own namespace.
190
191Note: Although assigning tags to the new key is optional, it is highly recommended as not doing so means that all users in the same scope have access to it!
192
193Requires authentication of a user in the \"{Administrator}\" role.")
194)]
195pub struct OpenPgpImportCommand {
196 #[arg(
197 env = "NETHSM_OPENPGP_TSK_FILE",
198 help = "The path to the Transferable Secret Key file to import"
199 )]
200 pub tsk_file: PathBuf,
201
202 #[arg(
203 env = "NETHSM_OPENPGP_KEY_ID",
204 help = "An optional unique ID that is assigned to the imported key",
205 long_help = "An optional unique ID that is assigned to the imported key
206
207If none is provided a generic one is generated for the key.",
208 long,
209 short
210 )]
211 pub key_id: Option<KeyId>,
212
213 #[arg(
214 env = "NETHSM_OPENPGP_KEY_TAGS",
215 help = "An optional list of tags that are assigned to the imported key",
216 long_help = "An optional list of tags that are assigned to the imported key
217
218Tags on keys are used to grant access to those keys for users that carry the same tags.",
219 long,
220 short
221 )]
222 pub tags: Option<Vec<String>>,
223}