Skip to main content

nethsm/base/
impl_key.rs

1//! [`NetHsm`] implementation for cryptographic key support.
2
3use base64ct::{Base64, Encoding};
4use log::debug;
5use nethsm_sdk_rs::{
6    apis::default_api::{
7        KeysKeyIdPutBody,
8        KeysPostBody,
9        keys_generate_post,
10        keys_get,
11        keys_key_id_cert_delete,
12        keys_key_id_cert_get,
13        keys_key_id_cert_put,
14        keys_key_id_csr_pem_post,
15        keys_key_id_decrypt_post,
16        keys_key_id_delete,
17        keys_key_id_encrypt_post,
18        keys_key_id_get,
19        keys_key_id_public_pem_get,
20        keys_key_id_put,
21        keys_key_id_restrictions_tags_tag_delete,
22        keys_key_id_restrictions_tags_tag_put,
23        keys_key_id_sign_post,
24        keys_post,
25    },
26    models::{
27        DecryptRequestData,
28        DistinguishedName,
29        EncryptRequestData,
30        KeyGenerateRequestData,
31        KeyRestrictions,
32        PrivateKey,
33        PublicKey,
34        SignRequestData,
35    },
36};
37use sha1::Sha1;
38use sha2::{Digest, Sha224, Sha256, Sha384, Sha512};
39
40#[cfg(doc)]
41use crate::{Credentials, SystemState, UserRole};
42use crate::{
43    DecryptMode,
44    EncryptMode,
45    Error,
46    KeyId,
47    KeyMechanism,
48    KeyType,
49    NetHsm,
50    PrivateKeyImport,
51    SignatureType,
52    base::utils::user_or_no_user_string,
53    key_type_matches_length,
54    key_type_matches_mechanisms,
55    nethsm_sdk::NetHsmApiError,
56    user::NamespaceSupport,
57};
58
59impl NetHsm {
60    /// [Generates a new key] on the NetHSM.
61    ///
62    /// [Generates a new key] with customizable features on the NetHSM.
63    /// The provided [`KeyType`] and list of [`KeyMechanism`]s have to match:
64    /// * [`KeyType::Rsa`] requires one of [`KeyMechanism::RsaDecryptionRaw`],
65    ///   [`KeyMechanism::RsaDecryptionPkcs1`], [`KeyMechanism::RsaDecryptionOaepMd5`],
66    ///   [`KeyMechanism::RsaDecryptionOaepSha1`], [`KeyMechanism::RsaDecryptionOaepSha224`],
67    ///   [`KeyMechanism::RsaDecryptionOaepSha256`], [`KeyMechanism::RsaDecryptionOaepSha384`],
68    ///   [`KeyMechanism::RsaDecryptionOaepSha512`], [`KeyMechanism::RsaSignaturePkcs1`],
69    ///   [`KeyMechanism::RsaSignaturePssSha1`], [`KeyMechanism::RsaSignaturePssSha224`],
70    ///   [`KeyMechanism::RsaSignaturePssSha256`], [`KeyMechanism::RsaSignaturePssSha384`] or
71    ///   [`KeyMechanism::RsaSignaturePssSha512`]
72    /// * [`KeyType::Curve25519`] requires [`KeyMechanism::EdDsaSignature`]
73    /// * [`KeyType::EcP256`], [`KeyType::EcP384`] and [`KeyType::EcP521`] require
74    ///   [`KeyMechanism::EcdsaSignature`]
75    /// * [`KeyType::Generic`] requires one of [`KeyMechanism::AesDecryptionCbc`] or
76    ///   [`KeyMechanism::AesEncryptionCbc`]
77    ///
78    /// Optionally the key bit-length using `length`, a custom key ID using `key_id`
79    /// and a list of `tags` to be attached to the new key can be provided.
80    /// If no `key_id` is provided, a unique one is generated automatically.
81    ///
82    /// **WARNING**: If no `tags` are provided, the generated key is usable by all users in the
83    /// [`Operator`][`UserRole::Operator`] [role] in the same scope (e.g. same [namespace]) by
84    /// default!
85    ///
86    /// This call requires using [`Credentials`] of a user in the
87    /// [`Administrator`][`UserRole::Administrator`] [role].
88    ///
89    /// ## Namespaces
90    ///
91    /// * Keys generated by *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users
92    ///   in a given [namespace]) are only visible to users in their [namespace]. Only users in the
93    ///   [`Operator`][`UserRole::Operator`] [role] in that same [namespace] can be granted access
94    ///   to them.
95    /// * Keys generated by *R-Administrators* (system-wide
96    ///   [`Administrator`][`UserRole::Administrator`] users) are only visible to system-wide users.
97    ///   Only system-wide users in the [`Operator`][`UserRole::Operator`] [role] (not in any
98    ///   [namespace]) can be granted access to them.
99    ///
100    /// # Errors
101    ///
102    /// Returns an [`Error::Api`] if generating the key fails:
103    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
104    /// * a key identified by ` key_id` exists already
105    /// * the chosen `length` or `tags` options are not valid
106    /// * the used [`Credentials`] are not correct
107    /// * the used [`Credentials`] are not that of a user in the
108    ///   [`Administrator`][`UserRole::Administrator`] [role]
109    ///
110    /// Returns an [`Error::Key`] if
111    /// * the provided combination of `key_type` and `mechanisms` is not valid.
112    /// * the provided combination of `key_type` and `length` is not valid.
113    ///
114    /// # Examples
115    ///
116    /// ```no_run
117    /// use nethsm::{
118    ///     Connection,
119    ///     ConnectionSecurity,
120    ///     Credentials,
121    ///     KeyMechanism,
122    ///     KeyType,
123    ///     NetHsm,
124    ///     Passphrase,
125    /// };
126    ///
127    /// # fn main() -> testresult::TestResult {
128    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
129    /// let nethsm = NetHsm::new(
130    ///     Connection::new(
131    ///         "https://example.org/api/v1".try_into()?,
132    ///         ConnectionSecurity::Unsafe,
133    ///     ),
134    ///     Some(Credentials::new(
135    ///         "admin".parse()?,
136    ///         Some(Passphrase::new("passphrase".to_string())),
137    ///     )),
138    ///     None,
139    ///     None,
140    /// )?;
141    ///
142    /// // generate a Curve25519 key for signing with custom Key ID and tags
143    /// nethsm.generate_key(
144    ///     KeyType::Curve25519,
145    ///     vec![KeyMechanism::EdDsaSignature],
146    ///     None,
147    ///     Some("signing1".parse()?),
148    ///     Some(vec!["sign_tag1".to_string(), "sign_tag2".to_string()]),
149    ///     Some("label1".to_string()),
150    /// )?;
151    ///
152    /// // generate a generic key for symmetric encryption and decryption
153    /// nethsm.generate_key(
154    ///     KeyType::Generic,
155    ///     vec![
156    ///         KeyMechanism::AesEncryptionCbc,
157    ///         KeyMechanism::AesDecryptionCbc,
158    ///     ],
159    ///     Some(128),
160    ///     Some("encryption1".parse()?),
161    ///     Some(vec!["encryption_tag1".to_string()]),
162    ///     Some("label2".to_string()),
163    /// )?;
164    /// # Ok(())
165    /// # }
166    /// ```
167    /// [Generates a new key]: https://docs.nitrokey.com/nethsm/operation#generate-key
168    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
169    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
170    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
171    pub fn generate_key(
172        &self,
173        key_type: KeyType,
174        mechanisms: Vec<KeyMechanism>,
175        length: Option<u32>,
176        key_id: Option<KeyId>,
177        tags: Option<Vec<String>>,
178        label: Option<String>,
179    ) -> Result<KeyId, Error> {
180        debug!(
181            "Generate a key (key type: {key_type}; mechanisms: {}; length: {}; ID: {}, tags: {}) on the NetHSM at {} using {}",
182            mechanisms
183                .iter()
184                .map(|mechanism| mechanism.to_string())
185                .collect::<Vec<String>>()
186                .join(", "),
187            if let Some(length) = length {
188                length.to_string()
189            } else {
190                "n/a".to_string()
191            },
192            if let Some(key_id) = key_id.as_ref() {
193                key_id.to_string()
194            } else {
195                "n/a".to_string()
196            },
197            if let Some(tags) = tags.as_ref() {
198                tags.join(", ")
199            } else {
200                "n/a".to_string()
201            },
202            self.url.borrow(),
203            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
204        );
205
206        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
207        // ensure the key_type - mechanisms combinations are valid
208        key_type_matches_mechanisms(key_type, &mechanisms)?;
209        // ensure the key_type - length combination is valid
210        key_type_matches_length(key_type, length)?;
211
212        // WARNING: Upstream has decided to set all models non-exhaustive.
213        //
214        // On each update to nethsm-sdk-rs, check whether KeyGenerateRequestData has gained further
215        // fields.
216        let key_generate_request_data = {
217            let mut key_generate_request_data = KeyGenerateRequestData::new(
218                mechanisms
219                    .into_iter()
220                    .map(|mechanism| mechanism.into())
221                    .collect(),
222                key_type.try_into()?,
223            );
224            key_generate_request_data.length = length.map(|length| length as i32);
225            key_generate_request_data.id = key_id.map(Into::into);
226            key_generate_request_data.restrictions = tags.map(|tags| {
227                let mut key_restrictions = KeyRestrictions::new();
228                key_restrictions.tags = Some(tags);
229                Box::new(key_restrictions)
230            });
231            key_generate_request_data.label = label;
232            key_generate_request_data
233        };
234
235        Ok(
236            keys_generate_post(&self.create_connection_config(), key_generate_request_data)
237                .map_err(|error| {
238                    Error::Api(format!(
239                        "Creating key failed: {}",
240                        NetHsmApiError::from(error)
241                    ))
242                })?
243                .entity
244                .id
245                .parse()?,
246        )
247    }
248
249    /// Imports an existing private key.
250    ///
251    /// [Imports an existing key] with custom features into the NetHSM.
252    /// The [`KeyType`] implied by the provided [`PrivateKeyImport`] and the list of
253    /// [`KeyMechanism`]s have to match:
254    /// * [`KeyType::Rsa`] must be used with [`KeyMechanism::RsaDecryptionRaw`],
255    ///   [`KeyMechanism::RsaDecryptionPkcs1`], [`KeyMechanism::RsaDecryptionOaepMd5`],
256    ///   [`KeyMechanism::RsaDecryptionOaepSha1`], [`KeyMechanism::RsaDecryptionOaepSha224`],
257    ///   [`KeyMechanism::RsaDecryptionOaepSha256`], [`KeyMechanism::RsaDecryptionOaepSha384`],
258    ///   [`KeyMechanism::RsaDecryptionOaepSha512`], [`KeyMechanism::RsaSignaturePkcs1`],
259    ///   [`KeyMechanism::RsaSignaturePssSha1`], [`KeyMechanism::RsaSignaturePssSha224`],
260    ///   [`KeyMechanism::RsaSignaturePssSha256`], [`KeyMechanism::RsaSignaturePssSha384`] or
261    ///   [`KeyMechanism::RsaSignaturePssSha512`]
262    /// * [`KeyType::Curve25519`] must be used with [`KeyMechanism::EdDsaSignature`]
263    /// * [`KeyType::EcP256`], [`KeyType::EcP384`] and [`KeyType::EcP521`] must be used with
264    ///   [`KeyMechanism::EcdsaSignature`]
265    /// * [`KeyType::Generic`] must be used with [`KeyMechanism::AesDecryptionCbc`] or
266    ///   [`KeyMechanism::AesEncryptionCbc`]
267    ///
268    /// Optionally a custom Key ID using `key_id` and a list of `tags` to be attached to the new key
269    /// can be provided.
270    /// If no `key_id` is provided, a unique one is generated automatically.
271    ///
272    /// **WARNING**: If no `tags` are provided, the imported key is usable by all users in the
273    /// [`Operator`][`UserRole::Operator`] [role] in the same scope (e.g. same [namespace]) by
274    /// default!
275    ///
276    /// This call requires using [`Credentials`] of a user in the
277    /// [`Administrator`][`UserRole::Administrator`] [role].
278    ///
279    /// ## Namespaces
280    ///
281    /// * Keys imported by *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in
282    ///   a given [namespace]) are only visible to users in their [namespace]. Only users in the
283    ///   [`Operator`][`UserRole::Operator`] [role] in that same [namespace] can be granted access
284    ///   to them.
285    /// * Keys imported by *R-Administrators* (system-wide
286    ///   [`Administrator`][`UserRole::Administrator`] users) are only visible to system-wide users.
287    ///   Only system-wide users in the [`Operator`][`UserRole::Operator`] [role] (not in any
288    ///   [namespace]) can be granted access to them.
289    ///
290    /// # Errors
291    ///
292    /// Returns an [`Error::Api`] if importing the key fails:
293    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
294    /// * a key identified by ` key_id` exists already
295    /// * the chosen `tags` option is not valid
296    /// * the used [`Credentials`] are not correct
297    /// * the used [`Credentials`] are not that of a user in the
298    ///   [`Administrator`][`UserRole::Administrator`] [role]
299    ///
300    /// Returns an [`Error::Key`] if the provided combination of `key_data` and `mechanisms` is not
301    /// valid.
302    ///
303    /// # Examples
304    ///
305    /// ```no_run
306    /// use nethsm::{Connection, ConnectionSecurity, Credentials, PrivateKeyImport, KeyMechanism, KeyType, NetHsm, Passphrase};
307    /// use rand::{SeedableRng, rngs::ChaCha20Rng, rng};
308    /// use rsa::pkcs8::{DecodePrivateKey, EncodePrivateKey};
309    /// use rsa::RsaPrivateKey;
310    ///
311    /// # fn main() -> testresult::TestResult {
312    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
313    /// let nethsm = NetHsm::new(
314    ///     Connection::new(
315    ///         "https://example.org/api/v1".try_into()?,
316    ///         ConnectionSecurity::Unsafe,
317    ///     ),
318    ///     Some(Credentials::new(
319    ///         "admin".parse()?,
320    ///         Some(Passphrase::new("passphrase".to_string())),
321    ///     )),
322    ///     None,
323    ///     None,
324    /// )?;
325    ///
326    /// // create a 4096 bit RSA private key and return it as PKCS#8 private key in ASN.1 DER-encoded format
327    /// let private_key = {
328    ///     let private_key = RsaPrivateKey::new(&mut ChaCha20Rng::from_rng(&mut rng()), 4096)?;
329    ///     private_key.to_pkcs8_der()?
330    /// };
331    ///
332    /// // import an RSA key for PKCS1 signatures
333    /// nethsm.import_key(
334    ///     vec![KeyMechanism::RsaSignaturePkcs1],
335    ///     PrivateKeyImport::new(KeyType::Rsa, private_key.as_bytes())?,
336    ///     Some("signing2".parse()?),
337    ///     Some(vec!["signing_tag3".to_string()]),
338    ///     Some("label3".to_string()),
339    /// )?;
340    /// # Ok(())
341    /// # }
342    /// ```
343    /// [Imports an existing key]: https://docs.nitrokey.com/nethsm/operation#import-key
344    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
345    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
346    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
347    pub fn import_key(
348        &self,
349        mechanisms: Vec<KeyMechanism>,
350        key_data: PrivateKeyImport,
351        key_id: Option<KeyId>,
352        tags: Option<Vec<String>>,
353        label: Option<String>,
354    ) -> Result<KeyId, Error> {
355        debug!(
356            "Import a key (mechanisms: {}; ID: {}, tags: {}) to the NetHSM at {} using {}",
357            mechanisms
358                .iter()
359                .map(|mechanism| mechanism.to_string())
360                .collect::<Vec<String>>()
361                .join(", "),
362            if let Some(key_id) = key_id.as_ref() {
363                key_id.to_string()
364            } else {
365                "n/a".to_string()
366            },
367            if let Some(tags) = tags.as_ref() {
368                tags.join(", ")
369            } else {
370                "n/a".to_string()
371            },
372            self.url.borrow(),
373            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
374        );
375
376        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
377        // ensure the key_type - mechanisms combinations are valid
378        let key_type = key_data.key_type();
379        key_type_matches_mechanisms(key_type, &mechanisms)?;
380
381        // WARNING: Upstream has decided to set all models non-exhaustive.
382        //
383        // On each update to nethsm-sdk-rs, check whether KeyRestrictions has gained further
384        // fields.
385        let restrictions = tags.map(|tags| {
386            let mut key_restrictions = KeyRestrictions::new();
387            key_restrictions.tags = Some(tags);
388            Box::new(key_restrictions)
389        });
390
391        let mechanisms = mechanisms
392            .into_iter()
393            .map(|mechanism| mechanism.into())
394            .collect();
395
396        // WARNING: Upstream has decided to set all models non-exhaustive.
397        //
398        // On each update to nethsm-sdk-rs, check whether PrivateKey has gained further
399        // fields.
400        let private_key = {
401            let mut private_key =
402                PrivateKey::new(mechanisms, key_type.try_into()?, key_data.try_into()?);
403            private_key.restrictions = restrictions;
404            private_key.label = label;
405            private_key
406        };
407
408        if let Some(key_id) = key_id {
409            keys_key_id_put(
410                &self.create_connection_config(),
411                key_id.as_ref(),
412                KeysKeyIdPutBody::ApplicationJson(private_key),
413            )
414            .map_err(|error| {
415                Error::Api(format!(
416                    "Importing key failed: {}",
417                    NetHsmApiError::from(error)
418                ))
419            })?;
420            Ok(key_id)
421        } else {
422            Ok(keys_post(
423                &self.create_connection_config(),
424                KeysPostBody::ApplicationJson(private_key),
425            )
426            .map_err(|error| {
427                Error::Api(format!(
428                    "Importing key failed: {}",
429                    NetHsmApiError::from(error)
430                ))
431            })?
432            .entity
433            .id
434            .parse()?)
435        }
436    }
437
438    /// [Deletes a key] from the NetHSM.
439    ///
440    /// [Deletes a key] identified by `key_id` from the NetHSM.
441    ///
442    /// This call requires using [`Credentials`] of a user in the
443    /// [`Administrator`][`UserRole::Administrator`] [role].
444    ///
445    /// ## Namespaces
446    ///
447    /// * Keys in a [namespace] can only be deleted by *N-Administrators*
448    ///   ([`Administrator`][`UserRole::Administrator`] users in a given [namespace]) of that
449    ///   [namespace] (*R-Administrators* have no access to keys in a [namespace]). **NOTE**:
450    ///   Calling [`delete_namespace`][`NetHsm::delete_namespace`] deletes **all keys** in a
451    ///   [namespace]!
452    /// * System-wide keys can only be deleted by *R-Administrators* (system-wide
453    ///   [`Administrator`][`UserRole::Administrator`] users).
454    ///
455    /// # Errors
456    ///
457    /// Returns an [`Error::Api`] if deleting the key fails:
458    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
459    /// * no key identified by `key_id` exists
460    /// * the used [`Credentials`] are not correct
461    /// * the used [`Credentials`] are not that of a user in the
462    ///   [`Administrator`][`UserRole::Administrator`] [role]
463    ///
464    /// # Examples
465    ///
466    /// ```no_run
467    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
468    ///
469    /// # fn main() -> testresult::TestResult {
470    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
471    /// let nethsm = NetHsm::new(
472    ///     Connection::new(
473    ///         "https://example.org/api/v1".try_into()?,
474    ///         ConnectionSecurity::Unsafe,
475    ///     ),
476    ///     Some(Credentials::new(
477    ///         "admin".parse()?,
478    ///         Some(Passphrase::new("passphrase".to_string())),
479    ///     )),
480    ///     None,
481    ///     None,
482    /// )?;
483    ///
484    /// // delete a key with the Key ID "signing1"
485    /// nethsm.delete_key(&"signing1".parse()?)?;
486    /// # Ok(())
487    /// # }
488    /// ```
489    /// [Deletes a key]: https://docs.nitrokey.com/nethsm/operation#delete-key
490    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
491    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
492    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
493    pub fn delete_key(&self, key_id: &KeyId) -> Result<(), Error> {
494        debug!(
495            "Delete the key \"{key_id}\" on the NetHSM at {} using {}",
496            self.url.borrow(),
497            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
498        );
499
500        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
501        keys_key_id_delete(&self.create_connection_config(), key_id.as_ref()).map_err(|error| {
502            Error::Api(format!(
503                "Deleting key failed: {}",
504                NetHsmApiError::from(error)
505            ))
506        })?;
507        Ok(())
508    }
509
510    /// Gets [details about a key].
511    ///
512    /// Gets [details about a key] identified by `key_id`.
513    ///
514    /// This call requires using [`Credentials`] of a user in the
515    /// [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`]
516    /// [role].
517    ///
518    /// ## Namespaces
519    ///
520    /// * Users in a [namespace] can only get details about keys in their own [namespace].
521    /// * System-wide users (not in a [namespace]) can only get details about system-wide keys.
522    ///
523    /// # Errors
524    ///
525    /// Returns an [`Error::Api`] if getting the key details fails:
526    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
527    /// * no key identified by `key_id` exists
528    /// * the used [`Credentials`] are not correct
529    /// * the used [`Credentials`] are not those of a user in the
530    ///   [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`] [role]
531    ///
532    /// # Examples
533    ///
534    /// ```no_run
535    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
536    ///
537    /// # fn main() -> testresult::TestResult {
538    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
539    /// let nethsm = NetHsm::new(
540    ///     Connection::new(
541    ///         "https://example.org/api/v1".try_into()?,
542    ///         ConnectionSecurity::Unsafe,
543    ///     ),
544    ///     Some(Credentials::new(
545    ///         "admin".parse()?,
546    ///         Some(Passphrase::new("passphrase".to_string())),
547    ///     )),
548    ///     None,
549    ///     None,
550    /// )?;
551    ///
552    /// // get details on a key with the Key ID "signing1"
553    /// println!("{:?}", nethsm.get_key(&"signing1".parse()?)?);
554    /// # Ok(())
555    /// # }
556    /// ```
557    /// [details about a key]: https://docs.nitrokey.com/nethsm/operation#show-key-details
558    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
559    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
560    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
561    pub fn get_key(&self, key_id: &KeyId) -> Result<PublicKey, Error> {
562        debug!(
563            "Retrieve details about the key \"{key_id}\" from the NetHSM at {} using {}",
564            self.url.borrow(),
565            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
566        );
567
568        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
569        Ok(
570            keys_key_id_get(&self.create_connection_config(), key_id.as_ref())
571                .map_err(|error| {
572                    Error::Api(format!(
573                        "Getting key failed: {}",
574                        NetHsmApiError::from(error)
575                    ))
576                })?
577                .entity,
578        )
579    }
580
581    /// Gets a [list of Key IDs] on the NetHSM.
582    ///
583    /// Optionally `filter` can be provided for matching against Key IDs.
584    ///
585    /// This call requires using [`Credentials`] of a user in the
586    /// [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`]
587    /// [role].
588    ///
589    /// ## Namespaces
590    ///
591    /// * Users in a [namespace] can only list key IDs of keys in their own [namespace].
592    /// * System-wide users (not in a [namespace]) can only list key IDs of system-wide keys.
593    ///
594    /// # Errors
595    ///
596    /// Returns an [`Error::Api`] if getting the list of Key IDs fails:
597    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
598    /// * the used [`Credentials`] are not correct
599    /// * the used [`Credentials`] are not those of a user in the
600    ///   [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`] [role]
601    ///
602    /// # Examples
603    ///
604    /// ```no_run
605    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
606    ///
607    /// # fn main() -> testresult::TestResult {
608    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
609    /// let nethsm = NetHsm::new(
610    ///     Connection::new(
611    ///         "https://example.org/api/v1".try_into()?,
612    ///         ConnectionSecurity::Unsafe,
613    ///     ),
614    ///     Some(Credentials::new(
615    ///         "admin".parse()?,
616    ///         Some(Passphrase::new("passphrase".to_string())),
617    ///     )),
618    ///     None,
619    ///     None,
620    /// )?;
621    ///
622    /// // get all Key IDs
623    /// println!("{:?}", nethsm.get_keys(None, None)?);
624    ///
625    /// // get all Key IDs that begin with "signing"
626    /// println!("{:?}", nethsm.get_keys(Some("signing"), None)?);
627    ///
628    /// // get all Key IDs that begin with "signing" and have the label "label"
629    /// println!("{:?}", nethsm.get_keys(Some("signing"), Some("label"))?);
630    /// # Ok(())
631    /// # }
632    /// ```
633    /// [list of Key IDs]: https://docs.nitrokey.com/nethsm/operation#list-keys
634    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
635    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
636    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
637    pub fn get_keys(&self, filter: Option<&str>, label: Option<&str>) -> Result<Vec<KeyId>, Error> {
638        debug!(
639            "Get key IDs{} from the NetHSM at {} using {}",
640            if let Some(filter) = filter {
641                format!(" based on filter {filter}")
642            } else {
643                "".to_string()
644            },
645            self.url.borrow(),
646            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
647        );
648
649        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
650        let valid_keys = {
651            let mut invalid_keys = Vec::new();
652            let valid_keys = keys_get(&self.create_connection_config(), filter, label)
653                .map_err(|error| {
654                    Error::Api(format!(
655                        "Getting keys failed: {}",
656                        NetHsmApiError::from(error)
657                    ))
658                })?
659                .entity
660                .into_iter()
661                .filter_map(|x| {
662                    if let Ok(key) = KeyId::new(x.id.clone()) {
663                        Some(key)
664                    } else {
665                        invalid_keys.push(x.id);
666                        None
667                    }
668                })
669                .collect::<Vec<KeyId>>();
670
671            if !invalid_keys.is_empty() {
672                return Err(crate::key::Error::InvalidKeyIds {
673                    key_ids: invalid_keys,
674                }
675                .into());
676            }
677
678            valid_keys
679        };
680
681        Ok(valid_keys)
682    }
683
684    /// Gets the [public key of a key] on the NetHSM.
685    ///
686    /// Gets the [public key of a key] on the NetHSM, identified by `key_id`.
687    /// The public key is returned in [X.509] Privacy-Enhanced Mail ([PEM]) format.
688    ///
689    /// This call requires using [`Credentials`] of a user in the
690    /// [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`]
691    /// [role].
692    ///
693    /// ## Namespaces
694    ///
695    /// * Users in a [namespace] can only get public keys of keys in their own [namespace].
696    /// * System-wide users (not in a [namespace]) can only get public keys of system-wide keys.
697    ///
698    /// # Errors
699    ///
700    /// Returns an [`Error::Api`] if getting the public key fails:
701    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
702    /// * no key identified by `key_id` exists
703    /// * the used [`Credentials`] are not correct
704    /// * the used [`Credentials`] are not that of a user in the
705    ///   [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`] [role]
706    /// * the targeted key is a symmetric key (i.e. [`KeyType::Generic`]) and therefore can not
707    ///   provide a public key
708    ///
709    /// # Examples
710    ///
711    /// ```no_run
712    /// use nethsm::{
713    ///     Connection,
714    ///     ConnectionSecurity,
715    ///     Credentials,
716    ///     KeyMechanism,
717    ///     KeyType,
718    ///     NetHsm,
719    ///     Passphrase,
720    /// };
721    ///
722    /// # fn main() -> testresult::TestResult {
723    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
724    /// let nethsm = NetHsm::new(
725    ///     Connection::new(
726    ///         "https://example.org/api/v1".try_into()?,
727    ///         ConnectionSecurity::Unsafe,
728    ///     ),
729    ///     Some(Credentials::new(
730    ///         "admin".parse()?,
731    ///         Some(Passphrase::new("passphrase".to_string())),
732    ///     )),
733    ///     None,
734    ///     None,
735    /// )?;
736    /// // generate system-wide key with tag
737    /// nethsm.generate_key(
738    ///     KeyType::Curve25519,
739    ///     vec![KeyMechanism::EdDsaSignature],
740    ///     None,
741    ///     Some("signing1".parse()?),
742    ///     Some(vec!["tag1".to_string()]),
743    ///     Some("label1".to_string()),
744    /// )?;
745    ///
746    /// // get public key for a key with Key ID "signing1"
747    /// println!("{:?}", nethsm.get_public_key(&"signing1".parse()?)?);
748    /// # Ok(())
749    /// # }
750    /// ```
751    /// [public key of a key]: https://docs.nitrokey.com/nethsm/operation#show-key-details
752    /// [X.509]: https://en.wikipedia.org/wiki/X.509
753    /// [PEM]: https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail
754    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
755    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
756    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
757    pub fn get_public_key(&self, key_id: &KeyId) -> Result<String, Error> {
758        debug!(
759            "Retrieve public key of key \"{key_id}\" from the NetHSM at {} using {}",
760            self.url.borrow(),
761            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
762        );
763
764        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
765        Ok(
766            keys_key_id_public_pem_get(&self.create_connection_config(), key_id.as_ref())
767                .map_err(|error| {
768                    Error::Api(format!(
769                        "Getting public key failed: {}",
770                        NetHsmApiError::from(error)
771                    ))
772                })?
773                .entity,
774        )
775    }
776
777    /// Adds a [tag for a key].
778    ///
779    /// Adds `tag` for a key, identified by `key_id`.
780    ///
781    /// A [tag for a key] is prerequisite to adding the same tag to a user in the
782    /// [`Operator`][`UserRole::Operator`] [role] and thus granting it access to the key.
783    ///
784    /// This call requires using [`Credentials`] of a user in the
785    /// [`Administrator`][`UserRole::Administrator`] [role].
786    ///
787    /// ## Namespaces
788    ///
789    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
790    ///   [namespace]) are only able to tag keys in their own [namespace].
791    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
792    ///   only able to tag system-wide keys.
793    ///
794    /// # Errors
795    ///
796    /// Returns an [`Error::Api`] if adding a tag to a key fails:
797    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
798    /// * no key identified by `key_id` exists
799    /// * `tag` is already associated with the key
800    /// * `tag` is invalid
801    /// * the used [`Credentials`] are not correct
802    /// * the used [`Credentials`] are not that of a user in the
803    ///   [`Administrator`][`UserRole::Administrator`] [role]
804    /// * a key in a [namespace] is attempted to be tagged by an *R-Administrator*
805    /// * a system-wide key is attempted to be tagged by an *N-Administrator*
806    ///
807    /// # Examples
808    ///
809    /// ```no_run
810    /// use nethsm::{
811    ///     Connection,
812    ///     ConnectionSecurity,
813    ///     Credentials,
814    ///     KeyMechanism,
815    ///     KeyType,
816    ///     NetHsm,
817    ///     Passphrase,
818    /// };
819    ///
820    /// # fn main() -> testresult::TestResult {
821    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
822    /// let nethsm = NetHsm::new(
823    ///     Connection::new(
824    ///         "https://example.org/api/v1".try_into()?,
825    ///         ConnectionSecurity::Unsafe,
826    ///     ),
827    ///     Some(Credentials::new(
828    ///         "admin".parse()?,
829    ///         Some(Passphrase::new("passphrase".to_string())),
830    ///     )),
831    ///     None,
832    ///     None,
833    /// )?;
834    /// // generate system-wide key with tag
835    /// nethsm.generate_key(
836    ///     KeyType::Curve25519,
837    ///     vec![KeyMechanism::EdDsaSignature],
838    ///     None,
839    ///     Some("signing1".parse()?),
840    ///     Some(vec!["tag1".to_string()]),
841    ///     Some("label".to_string()),
842    /// )?;
843    ///
844    /// // add the tag "important" to a key with Key ID "signing1"
845    /// nethsm.add_key_tag(&"signing1".parse()?, "important")?;
846    /// # Ok(())
847    /// # }
848    /// ```
849    /// [tag for a key]: https://docs.nitrokey.com/nethsm/operation#tags-for-keys
850    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
851    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
852    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
853    pub fn add_key_tag(&self, key_id: &KeyId, tag: &str) -> Result<(), Error> {
854        debug!(
855            "Add tag \"{tag}\" to key \"{key_id}\" on the NetHSM at {} using {}",
856            self.url.borrow(),
857            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
858        );
859
860        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
861        keys_key_id_restrictions_tags_tag_put(
862            &self.create_connection_config(),
863            tag,
864            key_id.as_ref(),
865        )
866        .map_err(|error| {
867            Error::Api(format!(
868                "Adding tag for key failed: {}",
869                NetHsmApiError::from(error)
870            ))
871        })?;
872        Ok(())
873    }
874
875    /// Deletes a [tag from a key].
876    ///
877    /// Deletes `tag` from a key, identified by `key_id` on the NetHSM.
878    ///
879    /// Deleting a [tag from a key] removes access to it for any user in the
880    /// [`Operator`][`UserRole::Operator`] [role], that carries the same tag.
881    ///
882    /// This call requires using [`Credentials`] of a user in the
883    /// [`Administrator`][`UserRole::Administrator`] [role].
884    ///
885    /// ## Namespaces
886    ///
887    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
888    ///   [namespace]) are only able to delete tags from keys in their own [namespace].
889    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
890    ///   only able to delete tags from system-wide keys.
891    ///
892    /// # Errors
893    ///
894    /// Returns an [`Error::Api`] if adding a tag to a key fails:
895    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
896    /// * no key identified by `key_id` exists
897    /// * `tag` is not associated with the key
898    /// * the used [`Credentials`] are not correct
899    /// * the used [`Credentials`] are not that of a user in the
900    ///   [`Administrator`][`UserRole::Administrator`] [role]
901    /// * the tag for a key in a [namespace] is attempted to be removed by an *R-Administrator*
902    /// * the tag for a system-wide key is attempted to be removed by an *N-Administrator*
903    ///
904    /// # Examples
905    ///
906    /// ```no_run
907    /// use nethsm::{
908    ///     Connection,
909    ///     ConnectionSecurity,
910    ///     Credentials,
911    ///     KeyMechanism,
912    ///     KeyType,
913    ///     NetHsm,
914    ///     Passphrase,
915    /// };
916    ///
917    /// # fn main() -> testresult::TestResult {
918    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
919    /// let nethsm = NetHsm::new(
920    ///     Connection::new(
921    ///         "https://example.org/api/v1".try_into()?,
922    ///         ConnectionSecurity::Unsafe,
923    ///     ),
924    ///     Some(Credentials::new(
925    ///         "admin".parse()?,
926    ///         Some(Passphrase::new("passphrase".to_string())),
927    ///     )),
928    ///     None,
929    ///     None,
930    /// )?;
931    /// // generate system-wide key with tag
932    /// nethsm.generate_key(
933    ///     KeyType::Curve25519,
934    ///     vec![KeyMechanism::EdDsaSignature],
935    ///     None,
936    ///     Some("signing1".parse()?),
937    ///     Some(vec!["tag1".to_string(), "important".to_string()]),
938    ///     Some("label1".to_string()),
939    /// )?;
940    ///
941    /// // remove the tag "important" from a key with Key ID "signing1"
942    /// nethsm.delete_key_tag(&"signing1".parse()?, "important")?;
943    /// # Ok(())
944    /// # }
945    /// ```
946    /// [tag from a key]: https://docs.nitrokey.com/nethsm/operation#tags-for-keys
947    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
948    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
949    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
950    pub fn delete_key_tag(&self, key_id: &KeyId, tag: &str) -> Result<(), Error> {
951        debug!(
952            "Delete tag \"{tag}\" from key \"{key_id}\" on the NetHSM at {} using {}",
953            self.url.borrow(),
954            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
955        );
956
957        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
958        keys_key_id_restrictions_tags_tag_delete(
959            &self.create_connection_config(),
960            tag,
961            key_id.as_ref(),
962        )
963        .map_err(|error| {
964            Error::Api(format!(
965                "Deleting tag for key failed: {}",
966                NetHsmApiError::from(error)
967            ))
968        })?;
969        Ok(())
970    }
971
972    /// Imports a [certificate for a key].
973    ///
974    /// Imports a [certificate for a key] identified by `key_id`.
975    /// Certificates up to 1 MiB in size are supported.
976    /// **NOTE**: The imported bytes are not validated!
977    ///
978    /// This call requires using [`Credentials`] of a user in the
979    /// [`Administrator`][`UserRole::Administrator`] [role].
980    ///
981    /// ## Namespaces
982    ///
983    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
984    ///   [namespace]) are only able to import certificates for keys in their own [namespace].
985    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
986    ///   only able to import certificates for system-wide keys.
987    ///
988    /// # Errors
989    ///
990    /// Returns an [`Error::Api`] if importing a [certificate for a key] fails:
991    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
992    /// * no key identified by `key_id` exists
993    /// * the `data` is invalid
994    /// * the used [`Credentials`] are not correct
995    /// * the used [`Credentials`] are not that of a user in the
996    ///   [`Administrator`][`UserRole::Administrator`] [role]
997    ///
998    /// # Examples
999    ///
1000    /// ```no_run
1001    /// use nethsm::{
1002    ///     Connection,
1003    ///     ConnectionSecurity,
1004    ///     Credentials,
1005    ///     KeyMechanism,
1006    ///     KeyType,
1007    ///     NetHsm,
1008    ///     OpenPgpKeyUsageFlags,
1009    ///     OpenPgpVersion,
1010    ///     Passphrase,
1011    ///     Timestamp,
1012    ///     UserRole,
1013    /// };
1014    ///
1015    /// # fn main() -> testresult::TestResult {
1016    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1017    /// let nethsm = NetHsm::new(
1018    ///     Connection::new(
1019    ///         "https://example.org/api/v1".try_into()?,
1020    ///         ConnectionSecurity::Unsafe,
1021    ///     ),
1022    ///     Some(Credentials::new(
1023    ///         "admin".parse()?,
1024    ///         Some(Passphrase::new("passphrase".to_string())),
1025    ///     )),
1026    ///     None,
1027    ///     None,
1028    /// )?;
1029    /// // add a system-wide user in the Operator role
1030    /// nethsm.add_user(
1031    ///     "Operator1".to_string(),
1032    ///     UserRole::Operator,
1033    ///     Passphrase::new("operator-passphrase".to_string()),
1034    ///     Some("operator1".parse()?),
1035    /// )?;
1036    /// // generate system-wide key with tag
1037    /// nethsm.generate_key(
1038    ///     KeyType::Curve25519,
1039    ///     vec![KeyMechanism::EdDsaSignature],
1040    ///     None,
1041    ///     Some("signing1".parse()?),
1042    ///     Some(vec!["tag1".to_string()]),
1043    ///     Some("label1".to_string()),
1044    /// )?;
1045    /// // tag system-wide user in Operator role for access to signing key
1046    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
1047    /// // use the Operator credentials to create an OpenPGP certificate for a key
1048    /// nethsm.use_credentials(&"operator1".parse()?)?;
1049    /// let openpgp_cert = nethsm.create_openpgp_cert(
1050    ///     &"signing1".parse()?,
1051    ///     OpenPgpKeyUsageFlags::default(),
1052    ///     &["Test <test@example.org>".parse()?],
1053    ///     Default::default(),
1054    ///     Timestamp::now(),
1055    ///     OpenPgpVersion::V4,
1056    /// )?;
1057    ///
1058    /// // use the Administrator credentials to import the OpenPGP certificate as certificate for the key
1059    /// nethsm.use_credentials(&"admin".parse()?)?;
1060    /// assert!(nethsm.get_key_certificate(&"signing1".parse()?).is_err());
1061    /// nethsm.import_key_certificate(&"signing1".parse()?, openpgp_cert)?;
1062    /// assert!(nethsm.get_key_certificate(&"signing1".parse()?).is_ok());
1063    /// # Ok(())
1064    /// # }
1065    /// ```
1066    /// [certificate for a key]: https://docs.nitrokey.com/nethsm/operation#key-certificates
1067    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1068    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1069    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1070    pub fn import_key_certificate(&self, key_id: &KeyId, data: Vec<u8>) -> Result<(), Error> {
1071        debug!(
1072            "Import certificate for key \"{key_id}\" on the NetHSM at {} using {}",
1073            self.url.borrow(),
1074            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1075        );
1076
1077        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1078        keys_key_id_cert_put(&self.create_connection_config(), key_id.as_ref(), data).map_err(
1079            |error| {
1080                Error::Api(format!(
1081                    "Importing certificate for key failed: {}",
1082                    NetHsmApiError::from(error)
1083                ))
1084            },
1085        )?;
1086        Ok(())
1087    }
1088
1089    /// Gets the [certificate for a key].
1090    ///
1091    /// Gets the [certificate for a key] identified by `key_id` and returns it as a byte vector.
1092    /// Returns [`None`] if no certificate is associated with a key identified by `key_id`.
1093    ///
1094    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
1095    /// or [`Administrator`][`UserRole::Administrator`] [role].
1096    ///
1097    /// ## Namespaces
1098    ///
1099    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
1100    ///   [namespace]) are only able to get certificates for keys in their own [namespace].
1101    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
1102    ///   only able to get certificates for system-wide keys.
1103    ///
1104    /// # Errors
1105    ///
1106    /// Returns an [`Error::Api`] if getting the [certificate for a key] fails:
1107    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1108    /// * no key identified by `key_id` exists
1109    /// * the used [`Credentials`] are not correct
1110    /// * the used [`Credentials`] are not those of a user in the [`Operator`][`UserRole::Operator`]
1111    ///   or [`Administrator`][`UserRole::Administrator`] [role]
1112    ///
1113    /// # Examples
1114    ///
1115    /// ```no_run
1116    /// use nethsm::{
1117    ///     Connection,
1118    ///     ConnectionSecurity,
1119    ///     Credentials,
1120    ///     KeyMechanism,
1121    ///     KeyType,
1122    ///     NetHsm,
1123    ///     OpenPgpKeyUsageFlags,
1124    ///     OpenPgpVersion,
1125    ///     Passphrase,
1126    ///     Timestamp,
1127    ///     UserRole,
1128    /// };
1129    ///
1130    /// # fn main() -> testresult::TestResult {
1131    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1132    /// let nethsm = NetHsm::new(
1133    ///     Connection::new(
1134    ///         "https://example.org/api/v1".try_into()?,
1135    ///         ConnectionSecurity::Unsafe,
1136    ///     ),
1137    ///     Some(Credentials::new(
1138    ///         "admin".parse()?,
1139    ///         Some(Passphrase::new("passphrase".to_string())),
1140    ///     )),
1141    ///     None,
1142    ///     None,
1143    /// )?;
1144    /// // add a system-wide user in the Operator role
1145    /// nethsm.add_user(
1146    ///     "Operator1".to_string(),
1147    ///     UserRole::Operator,
1148    ///     Passphrase::new("operator-passphrase".to_string()),
1149    ///     Some("operator1".parse()?),
1150    /// )?;
1151    /// // generate system-wide key with tag
1152    /// nethsm.generate_key(
1153    ///     KeyType::Curve25519,
1154    ///     vec![KeyMechanism::EdDsaSignature],
1155    ///     None,
1156    ///     Some("signing1".parse()?),
1157    ///     Some(vec!["tag1".to_string()]),
1158    ///     Some("label1".to_string()),
1159    /// )?;
1160    /// // tag system-wide user in Operator role for access to signing key
1161    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
1162    /// // use the Operator credentials to create an OpenPGP certificate for a key
1163    /// nethsm.use_credentials(&"operator1".parse()?)?;
1164    /// let openpgp_cert = nethsm.create_openpgp_cert(
1165    ///     &"signing1".parse()?,
1166    ///     OpenPgpKeyUsageFlags::default(),
1167    ///     &["Test <test@example.org>".parse()?],
1168    ///     Default::default(),
1169    ///     Timestamp::now(),
1170    ///     OpenPgpVersion::V4,
1171    /// )?;
1172    /// // use the Administrator credentials to import the OpenPGP certificate as certificate for the key
1173    /// nethsm.use_credentials(&"admin".parse()?)?;
1174    /// nethsm.import_key_certificate(&"signing1".parse()?, openpgp_cert)?;
1175    ///
1176    /// // get the certificate associated with a key
1177    /// println!("{:?}", nethsm.get_key_certificate(&"signing1".parse()?)?);
1178    /// # Ok(())
1179    /// # }
1180    /// ```
1181    /// [certificate for a key]: https://docs.nitrokey.com/nethsm/operation#key-certificates
1182    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1183    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1184    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1185    pub fn get_key_certificate(&self, key_id: &KeyId) -> Result<Option<Vec<u8>>, Error> {
1186        debug!(
1187            "Retrieve the certificate of the key \"{key_id}\" on the NetHSM at {} using {}",
1188            self.url.borrow(),
1189            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1190        );
1191
1192        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1193        match keys_key_id_cert_get(&self.create_connection_config(), key_id.as_ref()) {
1194            Ok(response) => Ok(Some(response.entity)),
1195            Err(nethsm_sdk_rs::apis::Error::ResponseError(error)) if error.status == 404 => {
1196                Ok(None)
1197            }
1198            Err(error) => Err(Error::Api(format!(
1199                "Getting certificate for key failed: {}",
1200                NetHsmApiError::from(error)
1201            ))),
1202        }
1203    }
1204
1205    /// Deletes the [certificate for a key].
1206    ///
1207    /// Deletes the [certificate for a key] identified by `key_id`.
1208    ///
1209    /// This call requires using [`Credentials`] of a user in the
1210    /// [`Administrator`][`UserRole::Administrator`] [role].
1211    ///
1212    /// ## Namespaces
1213    ///
1214    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
1215    ///   [namespace]) are only able to delete certificates for keys in their own [namespace].
1216    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
1217    ///   only able to delete certificates for system-wide keys.
1218    ///
1219    /// # Errors
1220    ///
1221    /// Returns an [`Error::Api`] if deleting the [certificate for a key] fails:
1222    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1223    /// * no key identified by `key_id` exists
1224    /// * no certificate is associated with the key
1225    /// * the used [`Credentials`] are not correct
1226    /// * the used [`Credentials`] are not that of a user in the
1227    ///   [`Administrator`][`UserRole::Administrator`] [role]
1228    ///
1229    /// # Examples
1230    ///
1231    /// ```no_run
1232    /// use nethsm::{
1233    ///     Connection,
1234    ///     ConnectionSecurity,
1235    ///     Credentials,
1236    ///     KeyMechanism,
1237    ///     KeyType,
1238    ///     NetHsm,
1239    ///     OpenPgpKeyUsageFlags,
1240    ///     OpenPgpVersion,
1241    ///     Passphrase,
1242    ///     Timestamp,
1243    ///     UserRole,
1244    /// };
1245    ///
1246    /// # fn main() -> testresult::TestResult {
1247    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1248    /// let nethsm = NetHsm::new(
1249    ///     Connection::new(
1250    ///         "https://example.org/api/v1".try_into()?,
1251    ///         ConnectionSecurity::Unsafe,
1252    ///     ),
1253    ///     Some(Credentials::new(
1254    ///         "admin".parse()?,
1255    ///         Some(Passphrase::new("passphrase".to_string())),
1256    ///     )),
1257    ///     None,
1258    ///     None,
1259    /// )?;
1260    /// // add a system-wide user in the Operator role
1261    /// nethsm.add_user(
1262    ///     "Operator1".to_string(),
1263    ///     UserRole::Operator,
1264    ///     Passphrase::new("operator-passphrase".to_string()),
1265    ///     Some("operator1".parse()?),
1266    /// )?;
1267    /// // generate system-wide key with tag
1268    /// nethsm.generate_key(
1269    ///     KeyType::Curve25519,
1270    ///     vec![KeyMechanism::EdDsaSignature],
1271    ///     None,
1272    ///     Some("signing1".parse()?),
1273    ///     Some(vec!["tag1".to_string()]),
1274    ///     Some("label1".to_string()),
1275    /// )?;
1276    /// // tag system-wide user in Operator role for access to signing key
1277    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
1278    /// // use the Operator credentials to create an OpenPGP certificate for a key
1279    /// nethsm.use_credentials(&"operator1".parse()?)?;
1280    /// let openpgp_cert = nethsm.create_openpgp_cert(
1281    ///     &"signing1".parse()?,
1282    ///     OpenPgpKeyUsageFlags::default(),
1283    ///     &["Test <test@example.org>".parse()?],
1284    ///     Default::default(),
1285    ///     Timestamp::now(),
1286    ///     OpenPgpVersion::V4,
1287    /// )?;
1288    /// // use the Administrator credentials to import the OpenPGP certificate as certificate for the key
1289    /// nethsm.use_credentials(&"admin".parse()?)?;
1290    /// nethsm.import_key_certificate(&"signing1".parse()?, openpgp_cert)?;
1291    ///
1292    /// // delete a certificate for a key with Key ID "signing1"
1293    /// assert!(nethsm.delete_key_certificate(&"signing1".parse()?).is_ok());
1294    /// nethsm.delete_key_certificate(&"signing1".parse()?)?;
1295    /// assert!(nethsm.delete_key_certificate(&"signing1".parse()?).is_err());
1296    /// # Ok(())
1297    /// # }
1298    /// ```
1299    /// [certificate for a key]: https://docs.nitrokey.com/nethsm/operation#key-certificates
1300    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1301    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1302    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1303    pub fn delete_key_certificate(&self, key_id: &KeyId) -> Result<(), Error> {
1304        debug!(
1305            "Delete the certificate for the key \"{key_id}\" on the NetHSM at {} using {}",
1306            self.url.borrow(),
1307            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1308        );
1309
1310        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1311        keys_key_id_cert_delete(&self.create_connection_config(), key_id.as_ref()).map_err(
1312            |error| {
1313                Error::Api(format!(
1314                    "Deleting certificate for key failed: {}",
1315                    NetHsmApiError::from(error)
1316                ))
1317            },
1318        )?;
1319        Ok(())
1320    }
1321
1322    /// Gets a [Certificate Signing Request for a key].
1323    ///
1324    /// Returns a Certificate Signing Request ([CSR]) for a key, identified by `key_id` in [PKCS#10]
1325    /// format based on a provided [`DistinguishedName`].
1326    ///
1327    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
1328    /// or [`Administrator`][`UserRole::Administrator`] [role].
1329    ///
1330    /// ## Namespaces
1331    ///
1332    /// * Users in a [namespace] only have access to keys in their own [namespace]
1333    /// * System-wide users only have access to system-wide keys (not in a [namespace]).
1334    ///
1335    /// # Errors
1336    ///
1337    /// Returns an [`Error::Api`] if getting a CSR for a key fails:
1338    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1339    /// * no key identified by `key_id` exists
1340    /// * the used [`Credentials`] are not correct
1341    /// * the used [`Credentials`] are not those of a user in the [`Operator`][`UserRole::Operator`]
1342    ///   or [`Administrator`][`UserRole::Administrator`] [role]
1343    ///
1344    /// # Examples
1345    ///
1346    /// ```no_run
1347    /// use nethsm::{
1348    ///     Connection,
1349    ///     ConnectionSecurity,
1350    ///     Credentials,
1351    ///     DistinguishedName,
1352    ///     KeyMechanism,
1353    ///     KeyType,
1354    ///     NetHsm,
1355    ///     Passphrase,
1356    /// };
1357    ///
1358    /// # fn main() -> testresult::TestResult {
1359    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1360    /// let nethsm = NetHsm::new(
1361    ///     Connection::new(
1362    ///         "https://example.org/api/v1".try_into()?,
1363    ///         ConnectionSecurity::Unsafe,
1364    ///     ),
1365    ///     Some(Credentials::new(
1366    ///         "admin".parse()?,
1367    ///         Some(Passphrase::new("passphrase".to_string())),
1368    ///     )),
1369    ///     None,
1370    ///     None,
1371    /// )?;
1372    /// // generate system-wide key with tag
1373    /// nethsm.generate_key(
1374    ///     KeyType::Curve25519,
1375    ///     vec![KeyMechanism::EdDsaSignature],
1376    ///     None,
1377    ///     Some("signing1".parse()?),
1378    ///     Some(vec!["tag1".to_string()]),
1379    ///     Some("label1".to_string()),
1380    /// )?;
1381    ///
1382    /// // get a CSR for a key
1383    /// let distinguished_name = {
1384    ///     let mut distinguished_name = DistinguishedName::new("example.org".to_string());
1385    ///     distinguished_name.country_name = Some("DE".to_string());
1386    ///     distinguished_name.state_or_province_name = Some("Berlin".to_string());
1387    ///     distinguished_name.locality_name = Some("Berlin".to_string());
1388    ///     distinguished_name.organization_name = Some("Foobar Inc".to_string());
1389    ///     distinguished_name.organizational_unit_name = Some("Department of Foo".to_string());
1390    ///     distinguished_name.email_address = Some("foobar@mcfooface.com".to_string());
1391    ///     distinguished_name.subject_alt_names = Some(vec!["other.example.org".to_string()]);
1392    ///     distinguished_name
1393    /// };
1394    /// println!(
1395    ///     "{}",
1396    ///     nethsm.get_key_csr(&"signing1".parse()?, distinguished_name)?
1397    /// );
1398    /// # Ok(())
1399    /// # }
1400    /// ```
1401    /// [Certificate Signing Request for a key]: https://docs.nitrokey.com/nethsm/operation#key-certificate-signing-requests
1402    /// [CSR]: https://en.wikipedia.org/wiki/Certificate_signing_request
1403    /// [PKCS#10]: https://en.wikipedia.org/wiki/Certificate_signing_request#Structure_of_a_PKCS_#10_CSR
1404    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1405    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1406    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1407    pub fn get_key_csr(
1408        &self,
1409        key_id: &KeyId,
1410        distinguished_name: DistinguishedName,
1411    ) -> Result<String, Error> {
1412        debug!(
1413            "Retrieve a Certificate Signing Request ({}) for the key \"{key_id}\" on the NetHSM at {} using {}",
1414            distinguished_name.common_name,
1415            self.url.borrow(),
1416            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1417        );
1418
1419        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1420        Ok(keys_key_id_csr_pem_post(
1421            &self.create_connection_config(),
1422            key_id.as_ref(),
1423            distinguished_name,
1424        )
1425        .map_err(|error| {
1426            Error::Api(format!(
1427                "Getting CSR for key failed: {}",
1428                NetHsmApiError::from(error)
1429            ))
1430        })?
1431        .entity)
1432    }
1433
1434    /// [Signs] a digest using a key.
1435    ///
1436    /// [Signs] a `digest` using a key identified by `key_id`.
1437    ///
1438    /// **NOTE**: This function offers low-level access for signing [digests]. Use
1439    /// [`sign`][`NetHsm::sign`] for signing a message.
1440    ///
1441    /// The `digest` must be of appropriate type depending on `signature_type`:
1442    /// * [`SignatureType::Pkcs1`], [`SignatureType::PssSha256`] and [`SignatureType::EcdsaP256`]
1443    ///   require a [SHA-256] digest
1444    /// * [`SignatureType::PssSha1`] requires a [SHA-1] digest
1445    /// * [`SignatureType::PssSha384`] and [`SignatureType::EcdsaP384`] require a [SHA-384] digest
1446    /// * [`SignatureType::PssSha512`] and [`SignatureType::EcdsaP521`] require a [SHA-521] digest
1447    /// * [`SignatureType::EdDsa`] requires no digest (`digest` is the message)
1448    ///
1449    /// The returned data depends on the chosen [`SignatureType`]:
1450    ///
1451    /// * [`SignatureType::Pkcs1`] returns the [PKCS 1] padded signature (no signature algorithm OID
1452    ///   prepended, since the used hash is not known).
1453    /// * [`SignatureType::PssSha1`], [`SignatureType::PssSha224`], [`SignatureType::PssSha256`],
1454    ///   [`SignatureType::PssSha384`] and [`SignatureType::PssSha512`] return the [EMSA-PSS]
1455    ///   encoded signature.
1456    /// * [`SignatureType::EdDsa`] returns the encoding as specified in [RFC 8032 (5.1.6)] (`r`
1457    ///   appended with `s` (each 32 bytes), in total 64 bytes).
1458    /// * [`SignatureType::EcdsaP256`], [`SignatureType::EcdsaP384`] and
1459    ///   [`SignatureType::EcdsaP521`] return the [ASN.1] [DER] encoded signature (a sequence of
1460    ///   integer `r` and integer `s`).
1461    ///
1462    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
1463    /// [role], which carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one
1464    /// of the tags of the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
1465    ///
1466    /// ## Namespaces
1467    ///
1468    /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
1469    ///   their own [namespace].
1470    /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
1471    ///
1472    /// # Errors
1473    ///
1474    /// Returns an [`Error::Api`] if signing the `digest` fails:
1475    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1476    /// * no key identified by `key_id` exists on the NetHSM
1477    /// * the chosen [`SignatureType`] is incompatible with the targeted key
1478    /// * the chosen `digest` is incompatible with the [`SignatureType`]
1479    /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
1480    ///   different [namespace])
1481    /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
1482    ///   tags
1483    /// * the used [`Credentials`] are not correct
1484    /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
1485    ///   [role]
1486    ///
1487    /// # Examples
1488    ///
1489    /// ```no_run
1490    /// use nethsm::{
1491    ///     Connection,
1492    ///     ConnectionSecurity,
1493    ///     Credentials,
1494    ///     KeyMechanism,
1495    ///     KeyType,
1496    ///     NetHsm,
1497    ///     Passphrase,
1498    ///     SignatureType,
1499    ///     UserRole,
1500    /// };
1501    ///
1502    /// # fn main() -> testresult::TestResult {
1503    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1504    /// let nethsm = NetHsm::new(
1505    ///     Connection::new(
1506    ///         "https://example.org/api/v1".try_into()?,
1507    ///         ConnectionSecurity::Unsafe,
1508    ///     ),
1509    ///     Some(Credentials::new(
1510    ///         "admin".parse()?,
1511    ///         Some(Passphrase::new("passphrase".to_string())),
1512    ///     )),
1513    ///     None,
1514    ///     None,
1515    /// )?;
1516    /// // add a system-wide user in the Operator role
1517    /// nethsm.add_user(
1518    ///     "Operator1".to_string(),
1519    ///     UserRole::Operator,
1520    ///     Passphrase::new("operator-passphrase".to_string()),
1521    ///     Some("operator1".parse()?),
1522    /// )?;
1523    /// // generate system-wide key with tag
1524    /// nethsm.generate_key(
1525    ///     KeyType::Curve25519,
1526    ///     vec![KeyMechanism::EdDsaSignature],
1527    ///     None,
1528    ///     Some("signing1".parse()?),
1529    ///     Some(vec!["tag1".to_string()]),
1530    ///     Some("label1".to_string()),
1531    /// )?;
1532    /// // tag system-wide user in Operator role for access to signing key
1533    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
1534    ///
1535    /// // create an ed25519 signature
1536    /// nethsm.use_credentials(&"operator1".parse()?)?;
1537    /// println!(
1538    ///     "{:?}",
1539    ///     nethsm.sign_digest(&"signing1".parse()?, SignatureType::EdDsa, &[0, 1, 2])?
1540    /// );
1541    /// # Ok(())
1542    /// # }
1543    /// ```
1544    /// [Signs]: https://docs.nitrokey.com/nethsm/operation#sign
1545    /// [digests]: https://en.wikipedia.org/wiki/Cryptographic_hash_function
1546    /// [SHA-256]: https://en.wikipedia.org/wiki/SHA-2
1547    /// [MD5]: https://en.wikipedia.org/wiki/MD5
1548    /// [SHA-1]: https://en.wikipedia.org/wiki/SHA-1
1549    /// [SHA-224]: https://en.wikipedia.org/wiki/SHA-2
1550    /// [SHA-384]: https://en.wikipedia.org/wiki/SHA-2
1551    /// [SHA-521]: https://en.wikipedia.org/wiki/SHA-2
1552    /// [PKCS 1]: https://en.wikipedia.org/wiki/PKCS_1
1553    /// [EMSA-PSS]: https://en.wikipedia.org/wiki/PKCS_1
1554    /// [RFC 8032 (5.1.6)]: https://www.rfc-editor.org/rfc/rfc8032#section-5.1.6
1555    /// [ASN.1]: https://en.wikipedia.org/wiki/ASN.1
1556    /// [DER]: https://en.wikipedia.org/wiki/X.690#DER_encoding
1557    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1558    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1559    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1560    pub fn sign_digest(
1561        &self,
1562        key_id: &KeyId,
1563        signature_type: SignatureType,
1564        digest: &[u8],
1565    ) -> Result<Vec<u8>, Error> {
1566        debug!(
1567            "Sign a digest (signature type: {signature_type}) with the key \"{key_id}\" on the NetHSM at {} using {}",
1568            self.url.borrow(),
1569            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1570        );
1571
1572        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1573        // decode base64 encoded data from the API
1574        Base64::decode_vec(
1575            &keys_key_id_sign_post(
1576                &self.create_connection_config(),
1577                key_id.as_ref(),
1578                SignRequestData::new(signature_type.try_into()?, Base64::encode_string(digest)),
1579            )
1580            .map_err(|error| {
1581                Error::Api(format!(
1582                    "Signing message failed: {}",
1583                    NetHsmApiError::from(error)
1584                ))
1585            })?
1586            .entity
1587            .signature,
1588        )
1589        .map_err(Error::Base64Decode)
1590    }
1591
1592    /// [Signs] a message using a key.
1593    ///
1594    /// [Signs] a `message` using a key identified by `key_id` based on a specific `signature_type`.
1595    ///
1596    /// The `message` should not be [hashed], as this function takes care of it based on the
1597    /// provided [`SignatureType`]. For lower level access, see
1598    /// [`sign_digest`][`NetHsm::sign_digest`].
1599    ///
1600    /// The returned data depends on the chosen [`SignatureType`]:
1601    ///
1602    /// * [`SignatureType::Pkcs1`] returns the [PKCS 1] padded signature (no signature algorithm OID
1603    ///   prepended, since the used hash is not known).
1604    /// * [`SignatureType::PssSha1`], [`SignatureType::PssSha224`], [`SignatureType::PssSha256`],
1605    ///   [`SignatureType::PssSha384`] and [`SignatureType::PssSha512`] return the [EMSA-PSS]
1606    ///   encoded signature.
1607    /// * [`SignatureType::EdDsa`] returns the encoding as specified in [RFC 8032 (5.1.6)] (`r`
1608    ///   appended with `s` (each 32 bytes), in total 64 bytes).
1609    /// * [`SignatureType::EcdsaP256`], [`SignatureType::EcdsaP384`] and
1610    ///   [`SignatureType::EcdsaP521`] return the [ASN.1] [DER] encoded signature (a sequence of
1611    ///   integer `r` and integer `s`).
1612    ///
1613    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
1614    /// [role], which carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one
1615    /// of the tags of the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
1616    ///
1617    /// ## Namespaces
1618    ///
1619    /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
1620    ///   their own [namespace].
1621    /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
1622    ///
1623    /// # Errors
1624    ///
1625    /// Returns an [`Error::Api`] if signing the `message` fails:
1626    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1627    /// * no key identified by `key_id` exists on the NetHSM
1628    /// * the chosen [`SignatureType`] is incompatible with the targeted key
1629    /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
1630    ///   different [namespace])
1631    /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
1632    ///   tags
1633    /// * the used [`Credentials`] are not correct
1634    /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
1635    ///   [role]
1636    ///
1637    /// # Examples
1638    ///
1639    /// ```no_run
1640    /// use nethsm::{
1641    ///     Connection,
1642    ///     ConnectionSecurity,
1643    ///     Credentials,
1644    ///     KeyMechanism,
1645    ///     KeyType,
1646    ///     NetHsm,
1647    ///     Passphrase,
1648    ///     SignatureType,
1649    ///     UserRole,
1650    /// };
1651    ///
1652    /// # fn main() -> testresult::TestResult {
1653    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1654    /// let nethsm = NetHsm::new(
1655    ///     Connection::new(
1656    ///         "https://example.org/api/v1".try_into()?,
1657    ///         ConnectionSecurity::Unsafe,
1658    ///     ),
1659    ///     Some(Credentials::new(
1660    ///         "admin".parse()?,
1661    ///         Some(Passphrase::new("passphrase".to_string())),
1662    ///     )),
1663    ///     None,
1664    ///     None,
1665    /// )?;
1666    /// // add a system-wide user in the Operator role
1667    /// nethsm.add_user(
1668    ///     "Operator1".to_string(),
1669    ///     UserRole::Operator,
1670    ///     Passphrase::new("operator-passphrase".to_string()),
1671    ///     Some("operator1".parse()?),
1672    /// )?;
1673    /// // generate system-wide key with tag
1674    /// nethsm.generate_key(
1675    ///     KeyType::Curve25519,
1676    ///     vec![KeyMechanism::EdDsaSignature],
1677    ///     None,
1678    ///     Some("signing1".parse()?),
1679    ///     Some(vec!["tag1".to_string()]),
1680    ///     Some("label1".to_string()),
1681    /// )?;
1682    /// // tag system-wide user in Operator role for access to signing key
1683    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
1684    ///
1685    /// // create an ed25519 signature
1686    /// println!(
1687    ///     "{:?}",
1688    ///     nethsm.sign(&"signing1".parse()?, SignatureType::EdDsa, b"message")?
1689    /// );
1690    /// # Ok(())
1691    /// # }
1692    /// ```
1693    /// [Signs]: https://docs.nitrokey.com/nethsm/operation#sign
1694    /// [hashed]: https://en.wikipedia.org/wiki/Cryptographic_hash_function
1695    /// [PKCS 1]: https://en.wikipedia.org/wiki/PKCS_1
1696    /// [EMSA-PSS]: https://en.wikipedia.org/wiki/PKCS_1
1697    /// [RFC 8032 (5.1.6)]: https://www.rfc-editor.org/rfc/rfc8032#section-5.1.6
1698    /// [ASN.1]: https://en.wikipedia.org/wiki/ASN.1
1699    /// [DER]: https://en.wikipedia.org/wiki/X.690#DER_encoding
1700    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1701    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1702    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1703    pub fn sign(
1704        &self,
1705        key_id: &KeyId,
1706        signature_type: SignatureType,
1707        message: &[u8],
1708    ) -> Result<Vec<u8>, Error> {
1709        debug!(
1710            "Sign a message (signature type: {signature_type}) with the key \"{key_id}\" on the NetHSM at {} using {}",
1711            self.url.borrow(),
1712            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1713        );
1714
1715        // Some algorithms require the data to be hashed first
1716        // The API requires data to be base64 encoded
1717        let message = match signature_type {
1718            SignatureType::Pkcs1
1719            | SignatureType::PssSha256
1720            | SignatureType::EcdsaP256
1721            | SignatureType::EcdsaK256 => {
1722                let mut hasher = Sha256::new();
1723                hasher.update(message);
1724                &hasher.finalize()[..]
1725            }
1726            SignatureType::PssSha1 => {
1727                let mut hasher = Sha1::new();
1728                hasher.update(message);
1729                &hasher.finalize()[..]
1730            }
1731            SignatureType::EcdsaP224 | SignatureType::PssSha224 => {
1732                let mut hasher = Sha224::new();
1733                hasher.update(message);
1734                &hasher.finalize()[..]
1735            }
1736            SignatureType::PssSha384 | SignatureType::EcdsaP384 => {
1737                let mut hasher = Sha384::new();
1738                hasher.update(message);
1739                &hasher.finalize()[..]
1740            }
1741            SignatureType::PssSha512 | SignatureType::EcdsaP521 => {
1742                let mut hasher = Sha512::new();
1743                hasher.update(message);
1744                &hasher.finalize()[..]
1745            }
1746            SignatureType::EdDsa => message,
1747        };
1748
1749        self.sign_digest(key_id, signature_type, message)
1750    }
1751
1752    /// [Encrypts] a message using a [symmetric key].
1753    ///
1754    /// [Encrypts] a `message` using a [symmetric key] identified by `key_id`, a specific
1755    /// [`EncryptMode`] `mode` and initialization vector `iv`.
1756    ///
1757    /// The targeted key must be of type [`KeyType::Generic`] and feature the mechanisms
1758    /// [`KeyMechanism::AesDecryptionCbc`] and [`KeyMechanism::AesEncryptionCbc`].
1759    ///
1760    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
1761    /// [role], which carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one
1762    /// of the tags of the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
1763    ///
1764    /// ## Namespaces
1765    ///
1766    /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
1767    ///   their own [namespace].
1768    /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
1769    ///
1770    /// # Errors
1771    ///
1772    /// Returns an [`Error::Api`] if encrypting the `message` fails:
1773    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1774    /// * no key identified by `key_id` exists on the NetHSM
1775    /// * the chosen `mode` is incompatible with the targeted key
1776    /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
1777    ///   different [namespace])
1778    /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
1779    ///   tags
1780    /// * the used [`Credentials`] are not correct
1781    /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
1782    ///   [role]
1783    ///
1784    /// # Examples
1785    ///
1786    /// ```no_run
1787    /// use nethsm::{
1788    ///     Connection,
1789    ///     ConnectionSecurity,
1790    ///     Credentials,
1791    ///     EncryptMode,
1792    ///     KeyMechanism,
1793    ///     KeyType,
1794    ///     NetHsm,
1795    ///     Passphrase,
1796    ///     UserRole,
1797    /// };
1798    ///
1799    /// # fn main() -> testresult::TestResult {
1800    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1801    /// let nethsm = NetHsm::new(
1802    ///     Connection::new(
1803    ///         "https://example.org/api/v1".try_into()?,
1804    ///         ConnectionSecurity::Unsafe,
1805    ///     ),
1806    ///     Some(Credentials::new(
1807    ///         "admin".parse()?,
1808    ///         Some(Passphrase::new("passphrase".to_string())),
1809    ///     )),
1810    ///     None,
1811    ///     None,
1812    /// )?;
1813    /// // add a system-wide user in the Operator role
1814    /// nethsm.add_user(
1815    ///     "Operator1".to_string(),
1816    ///     UserRole::Operator,
1817    ///     Passphrase::new("operator-passphrase".to_string()),
1818    ///     Some("operator1".parse()?),
1819    /// )?;
1820    /// // generate system-wide key with tag
1821    /// nethsm.generate_key(
1822    ///     KeyType::Generic,
1823    ///     vec![KeyMechanism::AesDecryptionCbc, KeyMechanism::AesEncryptionCbc],
1824    ///     Some(128),
1825    ///     Some("encryption1".parse()?),
1826    ///     Some(vec!["tag1".to_string()]),
1827    ///     Some("label1".to_string()),
1828    /// )?;
1829    /// // tag system-wide user in Operator role for access to signing key
1830    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
1831    ///
1832    /// // assuming we have an AES128 encryption key, the message must be a multiple of 32 bytes long
1833    /// let message = b"Hello World! This is a message!!";
1834    /// // we have an AES128 encryption key. the initialization vector must be a multiple of 16 bytes long
1835    /// let iv = b"This is unsafe!!";
1836    ///
1837    /// // encrypt message using
1838    /// println!(
1839    ///     "{:?}",
1840    ///     nethsm.encrypt(&"encryption1".parse()?, EncryptMode::AesCbc, message, Some(iv))?
1841    /// );
1842    /// # Ok(())
1843    /// # }
1844    /// ```
1845    /// [Encrypts]: https://docs.nitrokey.com/nethsm/operation#encrypt
1846    /// [symmetric key]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm
1847    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1848    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1849    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1850    pub fn encrypt(
1851        &self,
1852        key_id: &KeyId,
1853        mode: EncryptMode,
1854        message: &[u8],
1855        iv: Option<&[u8]>,
1856    ) -> Result<Vec<u8>, Error> {
1857        debug!(
1858            "Encrypt a message (encrypt mode: {mode}) with the key \"{key_id}\" on the NetHSM at {} using {}",
1859            self.url.borrow(),
1860            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1861        );
1862
1863        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1864        // the API requires data to be base64 encoded
1865        let message = Base64::encode_string(message);
1866        let iv = iv.map(Base64::encode_string);
1867
1868        // WARNING: Upstream has decided to set all models non-exhaustive.
1869        //
1870        // On each update to nethsm-sdk-rs, check whether EncryptRequestData has gained further
1871        // fields.
1872        let encrypt_request_data = {
1873            let mut encrypt_request_data = EncryptRequestData::new(mode.into(), message);
1874            encrypt_request_data.iv = iv;
1875            encrypt_request_data
1876        };
1877
1878        // decode base64 encoded data from the API
1879        Base64::decode_vec(
1880            &keys_key_id_encrypt_post(
1881                &self.create_connection_config(),
1882                key_id.as_ref(),
1883                encrypt_request_data,
1884            )
1885            .map_err(|error| {
1886                Error::Api(format!(
1887                    "Encrypting message failed: {}",
1888                    NetHsmApiError::from(error)
1889                ))
1890            })?
1891            .entity
1892            .encrypted,
1893        )
1894        .map_err(Error::Base64Decode)
1895    }
1896
1897    /// [Decrypts] a message using a key.
1898    ///
1899    /// [Decrypts] a `message` using a key identified by `key_id`, a specific [`DecryptMode`] `mode`
1900    /// and initialization vector `iv`.
1901    ///
1902    /// This function can be used to decrypt messages encrypted using a [symmetric key] (e.g. using
1903    /// [`encrypt`][`NetHsm::encrypt`]) by providing [`DecryptMode::AesCbc`] as `mode`. The targeted
1904    /// key must be of type [`KeyType::Generic`] and feature the mechanisms
1905    /// [`KeyMechanism::AesDecryptionCbc`] and [`KeyMechanism::AesEncryptionCbc`].
1906    ///
1907    /// Decryption for messages encrypted using an [asymmetric key] is also possible. Foreign
1908    /// entities can use the public key of an [asymmetric key] (see
1909    /// [`get_public_key`][`NetHsm::get_public_key`]) to encrypt a message and the private key
1910    /// on the NetHSM is used for decryption.
1911    ///
1912    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
1913    /// [role], which carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one
1914    /// of the tags of the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
1915    ///
1916    /// ## Namespaces
1917    ///
1918    /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
1919    ///   their own [namespace].
1920    /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
1921    ///
1922    /// # Errors
1923    ///
1924    /// Returns an [`Error::Api`] if decrypting the `message` fails:
1925    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1926    /// * no key identified by `key_id` exists on the NetHSM
1927    /// * the chosen `mode` is incompatible with the targeted key
1928    /// * the encrypted message can not be decrypted
1929    /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
1930    ///   different [namespace])
1931    /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
1932    ///   tags
1933    /// * the used [`Credentials`] are not correct
1934    /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
1935    ///   [role]
1936    ///
1937    /// # Examples
1938    ///
1939    /// ```no_run
1940    /// use nethsm::{
1941    ///     Connection,
1942    ///     ConnectionSecurity,
1943    ///     Credentials,
1944    ///     DecryptMode,
1945    ///     EncryptMode,
1946    ///     KeyMechanism,
1947    ///     KeyType,
1948    ///     NetHsm,
1949    ///     Passphrase,
1950    ///     UserRole
1951    /// };
1952    /// use rand::{SeedableRng, rngs::ChaCha20Rng, rng};
1953    /// use rsa::{pkcs8::DecodePublicKey, Pkcs1v15Encrypt, RsaPublicKey};
1954    ///
1955    /// # fn main() -> testresult::TestResult {
1956    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1957    /// let nethsm = NetHsm::new(
1958    ///     Connection::new(
1959    ///         "https://example.org/api/v1".try_into()?,
1960    ///         ConnectionSecurity::Unsafe,
1961    ///     ),
1962    ///     Some(Credentials::new(
1963    ///         "admin".parse()?,
1964    ///         Some(Passphrase::new("passphrase".to_string())),
1965    ///     )),
1966    ///     None,
1967    ///     None,
1968    /// )?;
1969    /// // add a system-wide user in the Operator role
1970    /// nethsm.add_user(
1971    ///     "Operator1".to_string(),
1972    ///     UserRole::Operator,
1973    ///     Passphrase::new("operator-passphrase".to_string()),
1974    ///     Some("operator1".parse()?),
1975    /// )?;
1976    /// // generate system-wide keys with the same tag
1977    /// nethsm.generate_key(
1978    ///     KeyType::Generic,
1979    ///     vec![KeyMechanism::AesDecryptionCbc, KeyMechanism::AesEncryptionCbc],
1980    ///     Some(128),
1981    ///     Some("encryption1".parse()?),
1982    ///     Some(vec!["tag1".to_string()]),
1983    ///     Some("label".to_string()),
1984    /// )?;
1985    /// nethsm.generate_key(
1986    ///     KeyType::Rsa,
1987    ///     vec![KeyMechanism::RsaDecryptionPkcs1],
1988    ///     None,
1989    ///     Some("encryption2".parse()?),
1990    ///     Some(vec!["tag2".to_string()]),
1991    ///     Some("label2".to_string()),
1992    /// )?;
1993    /// // tag system-wide user in Operator role for access to signing key
1994    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
1995    ///
1996    /// // assuming we have an AES128 encryption key, the message must be a multiple of 32 bytes long
1997    /// let message = "Hello World! This is a message!!".to_string();
1998    /// // we have an AES128 encryption key. the initialization vector must be a multiple of 16 bytes long
1999    /// let iv = "This is unsafe!!".to_string();
2000    ///
2001    /// // encrypt message using a symmetric key
2002    /// nethsm.use_credentials(&"operator1".parse()?)?;
2003    /// let encrypted_message = nethsm.encrypt(&"encryption1".parse()?, EncryptMode::AesCbc, message.as_bytes(), Some(iv.as_bytes()))?;
2004    ///
2005    /// // decrypt message using the same symmetric key and the same initialization vector
2006    /// assert_eq!(
2007    ///     message.as_bytes(),
2008    ///     &nethsm.decrypt(&"encryption1".parse()?, DecryptMode::AesCbc, &encrypted_message, Some(iv.as_bytes()))?
2009    /// );
2010    ///
2011    /// // get the public key of an asymmetric key and encrypt the message with it
2012    /// let pubkey = RsaPublicKey::from_public_key_pem(&nethsm.get_public_key(&"encryption2".parse()?)?)?;
2013    /// let encrypted_message = pubkey.encrypt(&mut ChaCha20Rng::from_rng(&mut rng()), Pkcs1v15Encrypt, message.as_bytes())?;
2014    /// println!("raw encrypted message: {:?}", encrypted_message);
2015    ///
2016    /// let decrypted_message =
2017    ///     nethsm.decrypt(&"encryption2".parse()?, DecryptMode::Pkcs1, &encrypted_message, None)?;
2018    /// println!("raw decrypted message: {:?}", decrypted_message);
2019    ///
2020    /// assert_eq!(&decrypted_message, message.as_bytes());
2021    /// # Ok(())
2022    /// # }
2023    /// ```
2024    /// [Decrypts]: https://docs.nitrokey.com/nethsm/operation#decrypt
2025    /// [symmetric key]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm
2026    /// [asymmetric key]: https://en.wikipedia.org/wiki/Public-key_cryptography
2027    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
2028    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2029    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2030    pub fn decrypt(
2031        &self,
2032        key_id: &KeyId,
2033        mode: DecryptMode,
2034        message: &[u8],
2035        iv: Option<&[u8]>,
2036    ) -> Result<Vec<u8>, Error> {
2037        debug!(
2038            "Decrypt a message (decrypt mode: {mode}; IV: {}) with the key \"{key_id}\" on the NetHSM at {} using {}",
2039            if iv.is_some() { "yes" } else { "no" },
2040            self.url.borrow(),
2041            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2042        );
2043
2044        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
2045        // the API requires data to be base64 encoded
2046        let encrypted = Base64::encode_string(message);
2047        let iv = iv.map(Base64::encode_string);
2048
2049        // WARNING: Upstream has decided to set all models non-exhaustive.
2050        //
2051        // On each update to nethsm-sdk-rs, check whether EncryptRequestData has gained further
2052        // fields.
2053        let decrypt_request_data = {
2054            let mut decrypt_request_data = DecryptRequestData::new(mode.into(), encrypted);
2055            decrypt_request_data.iv = iv;
2056            decrypt_request_data
2057        };
2058
2059        // decode base64 encoded data from the API
2060        Base64::decode_vec(
2061            &keys_key_id_decrypt_post(
2062                &self.create_connection_config(),
2063                key_id.as_ref(),
2064                decrypt_request_data,
2065            )
2066            .map_err(|error| {
2067                Error::Api(format!(
2068                    "Decrypting message failed: {}",
2069                    NetHsmApiError::from(error)
2070                ))
2071            })?
2072            .entity
2073            .decrypted,
2074        )
2075        .map_err(Error::Base64Decode)
2076    }
2077}