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