nethsm_cli/cli/
openpgp.rs

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/// The "nethsm openpgp" command.
17#[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    /// The "nethsm openpgp add" command.
29    Add(OpenPgpAddCommand),
30    /// The "nethsm openpgp import" command.
31    Import(OpenPgpImportCommand),
32    /// The "nethsm openpgp sign" command.
33    Sign(OpenPgpSignCommand),
34    /// The "nethsm openpgp sign-state" command.
35    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}