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