nethsm/base/
impl_key.rs

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