@@ -6,14 +6,20 @@ use super::show::ShowCertCmd;
66use crate :: certificate_is_self_signed;
77use crate :: cli:: certificate:: c8y;
88use crate :: cli:: certificate:: create_csr:: Key ;
9+ use crate :: cli:: certificate:: create_key:: CreateKeyHsmCmd ;
10+ use crate :: cli:: certificate:: create_key:: EcCurve ;
11+ use crate :: cli:: certificate:: create_key:: KeyType ;
12+ use crate :: cli:: certificate:: create_key:: RsaBits ;
913use crate :: cli:: common:: Cloud ;
1014use crate :: cli:: common:: CloudArg ;
1115use crate :: command:: BuildCommand ;
1216use crate :: command:: Command ;
1317use crate :: CertificateShift ;
1418use crate :: ConfigError ;
1519use anyhow:: anyhow;
20+ use anyhow:: Context ;
1621use c8y_api:: http_proxy:: C8yEndPoint ;
22+ use camino:: Utf8Path ;
1723use camino:: Utf8PathBuf ;
1824use certificate:: CsrTemplate ;
1925use clap:: ValueHint ;
@@ -51,6 +57,73 @@ pub enum TEdgeCertCli {
5157 cloud : Option < CloudArg > ,
5258 } ,
5359
60+ /// Generate a new keypair on the PKCS #11 token and select it to be used.
61+ ///
62+ /// Can be used to generate a keypair on the TOKEN. If TOKEN argument is not provided, the
63+ /// command prints the available tokens.
64+ ///
65+ /// If TOKEN is provided, the command generates an RSA or an ECDSA keypair on the token. When
66+ /// using RSA, `--bits` is used to set the size of the key, when using ECDSA, `--curve` is used.
67+ ///
68+ /// After the key is generated, tedge config is updated to use the new key using
69+ /// `device.key_uri` property. Depending on the selected cloud, we use `device.key_uri` setting
70+ /// for that cloud, e.g. `create-key-hsm c8y` will write to `c8y.device.key_uri`.
71+ CreateKeyHsm {
72+ /// Human readable description (CKA_LABEL attribute) for the key.
73+ #[ arg( long, default_value = "tedge" ) ]
74+ label : String ,
75+
76+ /// Key identifier for the keypair (CKA_ID attribute).
77+ ///
78+ /// If provided and no object exists on the token with the same ID, this will be the ID of
79+ /// the new keypair. If an object with this ID already exists, the operation will return an
80+ /// error. If not provided, a random ID will be generated and used by the keypair.
81+ ///
82+ /// The id shall be provided as a sequence of hex digits without `0x` prefix, optionally
83+ /// separated by spaces, e.g. `--id 010203` or `--id "01 02 03"`.
84+ #[ arg( long) ]
85+ id : Option < String > ,
86+
87+ /// The type of the key.
88+ #[ arg( long, default_value = "ecdsa" ) ]
89+ r#type : KeyType ,
90+
91+ /// The size of the RSA keys in bits. Should only be used with --type rsa.
92+ #[ arg( long, default_value = "2048" , group = "key_params" ) ]
93+ bits : RsaBits ,
94+
95+ /// The curve (size) of the ECDSA key. Should only be used with --type ecdsa.
96+ #[ arg( long, default_value = "p256" , group = "key_params" ) ]
97+ curve : EcCurve ,
98+
99+ /// User PIN value for logging into the PKCS #11 token.
100+ ///
101+ /// This flag can be used to provide a PIN when creating a new key without needing to update
102+ /// tedge-config, which can be helpful when initializing keys on new tokens.
103+ ///
104+ /// Note that in contrast to the URI of the key, which will be written to tedge-config
105+ /// automatically when the keypair is created, PIN will not be written automatically and may
106+ /// be needed to written manually using tedge config set (if not using tedge-p11-server with
107+ /// the correct default PIN).
108+ #[ arg( long) ]
109+ pin : Option < String > ,
110+
111+ /// Path where public key will be saved when a keypair is generated.
112+ #[ arg( long) ]
113+ outfile_pubkey : Option < Box < Utf8Path > > ,
114+
115+ // can't document subcommands here because one would have to document variants of the enum
116+ // but this type is used in other places
117+ #[ clap( subcommand) ]
118+ cloud : Option < CloudArg > ,
119+
120+ /// The URI of the token where the keypair should be created.
121+ ///
122+ /// If this argument is missing, a list of available initialized tokens will be shown. The
123+ /// token needs to be initialized to be able to generate keys.
124+ token : Option < String > ,
125+ } ,
126+
54127 /// Renew the device certificate
55128 ///
56129 /// The current certificate is left unchanged and a new certificate file is created,
@@ -214,6 +287,42 @@ impl BuildCommand for TEdgeCertCli {
214287 cmd. into_boxed ( )
215288 }
216289
290+ TEdgeCertCli :: CreateKeyHsm {
291+ bits,
292+ label,
293+ r#type,
294+ curve,
295+ id,
296+ pin,
297+ outfile_pubkey,
298+
299+ cloud,
300+ token,
301+ } => {
302+ let cloud: Option < Cloud > = cloud. map ( <_ >:: try_into) . transpose ( ) ?;
303+ let cloud_config = cloud
304+ . as_ref ( )
305+ . map ( |c| config. as_cloud_config ( ( c) . into ( ) ) )
306+ . transpose ( ) ?;
307+ let cryptoki_config = config
308+ . device
309+ . cryptoki_config ( cloud_config) ?
310+ . context ( "Cryptoki config is not enabled" ) ?;
311+
312+ CreateKeyHsmCmd {
313+ cryptoki_config,
314+ label,
315+ r#type,
316+ bits,
317+ curve,
318+ id,
319+ pin,
320+ outfile_pubkey,
321+ cloud,
322+ token,
323+ }
324+ . into_boxed ( )
325+ }
217326 TEdgeCertCli :: Show {
218327 cloud,
219328 cert_path,
0 commit comments