nethsm/
lib.rs

1//! A high-level library to interact with the API of a [Nitrokey NetHSM].
2//!
3//! Provides high-level integration with a [Nitrokey NetHSM] and the official container.
4//! As this crate is a wrapper around [`nethsm_sdk_rs`] it covers all available actions from
5//! provisioning, over key and user management to backup and restore.
6//!
7//! The NetHSM provides dedicated [user management] based on a [role] system (see [`UserRole`])
8//! which can be used to separate concerns.
9//! Each user has exactly one [role].
10//!
11//! With the help of a [namespace] concept, it is possible to segregate users and their keys into
12//! secluded groups.
13//! Notably, this introduces *R-Administrators* (system-wide users in the
14//! [`Administrator`][`UserRole::Administrator`] [role]), which have access to all system-wide
15//! actions, but can *not* modify users and keys in a [namespace] and *N-Administrators*
16//! ([namespace] users in the [`Administrator`][`UserRole::Administrator`] [role]), which have
17//! access only to actions towards users and keys in their own [namespace].
18//! [Namespace] users in the [`Operator`][`UserRole::Operator`] [role] only have access to keys in
19//! their own [namespace], while system-wide users only have access to system-wide keys.
20//!
21//! The cryptographic key material on the NetHSM can be assigned to one or several [tags].
22//! Users in the [`Operator`][`UserRole::Operator`] [role] can be assigned to the same [tags]
23//! to gain access to the respective keys.
24//!
25//! Using the central [`NetHsm`] struct it is possible to establish a TLS connection for multiple
26//! users and all available operations.
27//! TLS validation can be configured based on a variant of the [`ConnectionSecurity`] enum:
28//! - [`ConnectionSecurity::Unsafe`]: The host certificate is not validated.
29//! - [`ConnectionSecurity::Fingerprints`]: The host certificate is validated based on configurable
30//!   fingerprints.
31//! - [`ConnectionSecurity::Native`]: The host certificate is validated using the native Operating
32//!   System trust store.
33//!
34//! Apart from the crate specific documentation it is very recommended to read the canonical
35//! upstream documentation as well: <https://docs.nitrokey.com/nethsm/>
36//!
37//! ## Reexports
38//!
39//! This crate re-exports the following types, so that the respective crates do not have to be
40//! relied upon directly:
41//!
42//! * [`chrono::DateTime`]
43//! * [`chrono::Utc`]
44//! * [`nethsm_sdk_rs::models::DistinguishedName`]
45//! * [`nethsm_sdk_rs::models::InfoData`]
46//! * [`nethsm_sdk_rs::models::LoggingConfig`]
47//! * [`nethsm_sdk_rs::models::NetworkConfig`]
48//! * [`nethsm_sdk_rs::models::PublicKey`]
49//! * [`nethsm_sdk_rs::models::SystemInfo`]
50//! * [`nethsm_sdk_rs::models::SystemState`]
51//! * [`nethsm_sdk_rs::models::SystemUpdateData`]
52//! * [`nethsm_sdk_rs::models::UserData`]
53//!
54//! # Examples
55//!
56//! ```
57//! use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
58//!
59//! # fn main() -> testresult::TestResult {
60//! // Create a new connection to a NetHSM at "https://example.org" using admin credentials
61//! let nethsm = NetHsm::new(
62//!     Connection::new(
63//!         "https://example.org/api/v1".try_into()?,
64//!         ConnectionSecurity::Unsafe,
65//!     ),
66//!     Some(Credentials::new("admin".parse()?, Some(Passphrase::new("passphrase".to_string())))),
67//!     None,
68//!     None,
69//! )?;
70//!
71//! // Connections can be initialized without any credentials and more than one can be provided later on
72//! let nethsm = NetHsm::new(
73//!     Connection::new(
74//!         "https://example.org/api/v1".try_into()?,
75//!         ConnectionSecurity::Unsafe,
76//!     ),
77//!     None,
78//!     None,
79//!     None,
80//! )?;
81//!
82//! nethsm.add_credentials(Credentials::new("admin".parse()?, Some(Passphrase::new("passphrase".to_string()))));
83//! nethsm.add_credentials(Credentials::new("user1".parse()?, Some(Passphrase::new("other_passphrase".to_string()))));
84//!
85//! // A set of credentials must be used before establishing a connection with the configured NetHSM
86//! nethsm.use_credentials(&"user1".parse()?)?;
87//! # Ok(())
88//! # }
89//! ```
90//! [Nitrokey NetHSM]: https://docs.nitrokey.com/nethsm/
91//! [user management]: https://docs.nitrokey.com/nethsm/administration#user-management
92//! [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
93//! [tags]: https://docs.nitrokey.com/nethsm/operation#tags-for-keys
94//! [role]: https://docs.nitrokey.com/nethsm/administration#roles
95use std::cell::RefCell;
96use std::collections::HashMap;
97use std::io::Read;
98use std::net::Ipv4Addr;
99#[cfg(doc)]
100use std::thread::available_parallelism;
101
102use base64ct::{Base64, Encoding};
103pub use chrono::{DateTime, Utc};
104use log::{debug, trace};
105use md5::{Digest as _, Md5};
106use nethsm_sdk_rs::apis::configuration::Configuration;
107use nethsm_sdk_rs::apis::default_api::{
108    KeysPostBody,
109    config_backup_passphrase_put,
110    config_logging_get,
111    config_logging_put,
112    config_network_get,
113    config_network_put,
114    config_time_get,
115    config_time_put,
116    config_tls_cert_pem_get,
117    config_tls_cert_pem_put,
118    config_tls_csr_pem_post,
119    config_tls_generate_post,
120    config_tls_public_pem_get,
121    config_unattended_boot_get,
122    config_unattended_boot_put,
123    config_unlock_passphrase_put,
124    health_alive_get,
125    health_ready_get,
126    health_state_get,
127    info_get,
128    keys_generate_post,
129    keys_get,
130    keys_key_id_cert_delete,
131    keys_key_id_cert_get,
132    keys_key_id_cert_put,
133    keys_key_id_csr_pem_post,
134    keys_key_id_decrypt_post,
135    keys_key_id_delete,
136    keys_key_id_encrypt_post,
137    keys_key_id_get,
138    keys_key_id_public_pem_get,
139    keys_key_id_put,
140    keys_key_id_restrictions_tags_tag_delete,
141    keys_key_id_restrictions_tags_tag_put,
142    keys_key_id_sign_post,
143    keys_post,
144    lock_post,
145    metrics_get,
146    namespaces_get,
147    namespaces_namespace_id_delete,
148    namespaces_namespace_id_put,
149    provision_post,
150    random_post,
151    system_backup_post,
152    system_cancel_update_post,
153    system_commit_update_post,
154    system_factory_reset_post,
155    system_info_get,
156    system_reboot_post,
157    system_restore_post,
158    system_shutdown_post,
159    system_update_post,
160    unlock_post,
161    users_get,
162    users_post,
163    users_user_id_delete,
164    users_user_id_get,
165    users_user_id_passphrase_post,
166    users_user_id_put,
167    users_user_id_tags_get,
168    users_user_id_tags_tag_delete,
169    users_user_id_tags_tag_put,
170};
171use nethsm_sdk_rs::models::{
172    BackupPassphraseConfig,
173    DecryptRequestData,
174    EncryptRequestData,
175    KeyGenerateRequestData,
176    KeyRestrictions,
177    PrivateKey,
178    ProvisionRequestData,
179    RandomRequestData,
180    SignRequestData,
181    TimeConfig,
182    TlsKeyGenerateRequestData,
183    UnlockPassphraseConfig,
184    UnlockRequestData,
185    UserPassphrasePostData,
186    UserPostData,
187};
188// Re-export some useful types so that users do not have to use nethsm-sdk-rs directly
189pub use nethsm_sdk_rs::models::{
190    DistinguishedName,
191    InfoData,
192    LoggingConfig,
193    NetworkConfig,
194    PublicKey,
195    SystemInfo,
196    SystemState,
197    SystemUpdateData,
198    UserData,
199};
200use nethsm_sdk_rs::ureq::Agent;
201use serde_json::Value;
202use sha1::Sha1;
203use sha2::{Digest, Sha224, Sha256, Sha384, Sha512};
204
205pub mod connection;
206pub use connection::{Connection, Url};
207
208mod key;
209pub use key::{
210    CryptographicKeyContext,
211    MIN_RSA_BIT_LENGTH,
212    PrivateKeyImport,
213    SigningKeySetup,
214    key_type_and_mechanisms_match_signature_type,
215    key_type_matches_length,
216    key_type_matches_mechanisms,
217    tls_key_type_matches_length,
218};
219
220mod nethsm_sdk;
221use nethsm_sdk::NetHsmApiError;
222pub use nethsm_sdk::{
223    BootMode,
224    DecryptMode,
225    EncryptMode,
226    KeyFormat,
227    KeyMechanism,
228    KeyType,
229    LogLevel,
230    SignatureType,
231    TlsKeyType,
232    UserRole,
233};
234pub mod openpgp;
235pub use openpgp::{
236    KeyUsageFlags as OpenPgpKeyUsageFlags,
237    OpenPgpUserId,
238    OpenPgpUserIdList,
239    OpenPgpVersion,
240    extract_certificate as extract_openpgp_certificate,
241    tsk_to_private_key_import,
242};
243
244#[cfg(feature = "test-helpers")]
245pub mod test;
246
247mod tls;
248use tls::create_agent;
249pub use tls::{
250    ConnectionSecurity,
251    DEFAULT_MAX_IDLE_CONNECTIONS,
252    DEFAULT_TIMEOUT_SECONDS,
253    HostCertificateFingerprints,
254};
255
256mod user;
257pub use key::KeyId;
258pub use user::Error as UserError;
259use user::NamespaceSupport;
260pub use user::{Credentials, FullCredentials, NamespaceId, Passphrase, UserId};
261
262/// An error that may occur when using a NetHSM.
263#[derive(Debug, thiserror::Error)]
264pub enum Error {
265    /// Wraps a [`rustls::Error`] for issues with rustls based TLS setups
266    #[error("TLS error: {0}")]
267    Rustls(#[from] rustls::Error),
268
269    /// A Base64 encoded string can not be decode
270    #[error("Decoding Base64 string failed: {0}")]
271    Base64Decode(#[from] base64ct::Error),
272
273    /// A generic error with a custom message
274    #[error("NetHSM error: {0}")]
275    Default(String),
276
277    /// The loading of TLS root certificates from the platform's native certificate store failed
278    #[error("Loading system TLS certs failed: {0:?}")]
279    CertLoading(Vec<rustls_native_certs::Error>),
280
281    /// No TLS root certificates from the platform's native certificate store could be added
282    ///
283    /// Provides the number certificates that failed to be added
284    #[error("Unable to load any system TLS certs ({failed} failed)")]
285    NoSystemCertsAdded {
286        /// The number of certificates that failed to be added.
287        failed: usize,
288    },
289
290    /// A call to the NetHSM API failed
291    #[error("NetHSM API error: {0}")]
292    Api(String),
293
294    /// An error occurred in the [`connection`] module.
295    #[error("NetHSM connection error:\n{0}")]
296    Connection(#[from] connection::Error),
297
298    /// An error with a key occurred
299    #[error("Key error: {0}")]
300    Key(#[from] key::Error),
301
302    /// User data error
303    #[error("User data error: {0}")]
304    User(#[from] user::Error),
305
306    /// OpenPGP error
307    #[error("OpenPGP error: {0}")]
308    OpenPgp(#[from] openpgp::Error),
309}
310
311/// Validates a [backup].
312///
313/// Parses a previously created backup file. If `passphrase` is
314/// [`Some`], additionally decrypts the backup and verifies the
315/// encrypted backup version number.
316///
317/// # Errors
318///
319/// Returns an [`nethsm_backup::Error`] if validating a [backup] fails:
320/// * the magic number is missing in the file
321/// * the version number is unknown
322/// * the provided passphrase is incorrect
323///
324/// # Examples
325///
326/// ```no_run
327/// use nethsm::{
328///     Connection,
329///     ConnectionSecurity,
330///     Credentials,
331///     NetHsm,
332///     Passphrase,
333///     validate_backup,
334/// };
335///
336/// # fn main() -> testresult::TestResult {
337/// // create a connection with a user in the Backup role
338/// let nethsm = NetHsm::new(
339///     Connection::new(
340///         "https://example.org/api/v1".try_into()?,
341///         ConnectionSecurity::Unsafe,
342///     ),
343///     Some(Credentials::new(
344///         "backup1".parse()?,
345///         Some(Passphrase::new("passphrase".to_string())),
346///     )),
347///     None,
348///     None,
349/// )?;
350///
351/// // create a backup and write it to file
352/// std::fs::write("nethsm.bkp", nethsm.backup()?)?;
353///
354/// // check for consistency only
355/// validate_backup(&mut std::fs::File::open("nethsm.bkp")?, None)?;
356///
357/// // check for correct passphrase by decrypting and validating the encrypted backup version
358/// validate_backup(
359///     &mut std::fs::File::open("nethsm.bkp")?,
360///     Passphrase::new("a sample password".into()),
361/// )?;
362/// # Ok(())
363/// # }
364/// ```
365/// [backup]: https://docs.nitrokey.com/nethsm/administration#backup
366pub fn validate_backup(
367    reader: &mut impl Read,
368    passphrase: impl Into<Option<Passphrase>>,
369) -> Result<(), nethsm_backup::Error> {
370    let passphrase = passphrase.into();
371    let backup = nethsm_backup::Backup::parse(reader)?;
372    if let Some(passphrase) = passphrase {
373        let decryptor = backup.decrypt(passphrase.expose_borrowed().as_bytes())?;
374        let version = decryptor.version()?;
375        if version.len() != 1 || version[0] != 0 {
376            return Err(nethsm_backup::Error::BadVersion {
377                highest_supported_version: 0,
378                backup_version: version,
379            });
380        }
381    }
382    Ok(())
383}
384
385/// Creates a string for when there is a user or there is no user.
386///
387/// Creates the string `the user <user>` if `user` is [`Some`].
388/// Creates the string `no user` if `user` is [`None`].
389fn user_or_no_user_string(user: Option<&UserId>) -> String {
390    if let Some(current_credentials) = user {
391        format!("the user {current_credentials}")
392    } else {
393        "no user".to_string()
394    }
395}
396
397/// A network connection to a NetHSM.
398///
399/// Defines a network configuration for the connection and a list of user [`Credentials`] that can
400/// be used over this connection.
401#[derive(Debug)]
402pub struct NetHsm {
403    /// The agent for the requests
404    agent: RefCell<Agent>,
405    /// The URL path for the target API
406    url: RefCell<Url>,
407    /// The default [`Credentials`] to use for requests
408    current_credentials: RefCell<Option<UserId>>,
409    /// The list of all available credentials
410    credentials: RefCell<HashMap<UserId, Credentials>>,
411}
412
413impl NetHsm {
414    /// Creates a new NetHSM connection.
415    ///
416    /// Creates a new NetHSM connection based on a [`Connection`].
417    ///
418    /// Optionally initial `credentials` (used when communicating with the NetHSM),
419    /// `max_idle_connections` to set the size of the connection pool (defaults to `100`) and
420    /// `timeout_seconds` to set the timeout for a successful socket connection (defaults to `10`)
421    /// can be provided.
422    ///
423    /// # Errors
424    ///
425    /// - the TLS client configuration can not be created,
426    /// - or [`ConnectionSecurity::Native`] is provided as `tls_security`, but no certification
427    ///   authority certificates are available on the system.
428    pub fn new(
429        connection: Connection,
430        credentials: Option<Credentials>,
431        max_idle_connections: Option<usize>,
432        timeout_seconds: Option<u64>,
433    ) -> Result<Self, Error> {
434        let (current_credentials, credentials) = if let Some(credentials) = credentials {
435            debug!(
436                "Create new NetHSM connection {connection} with initial credentials {credentials}"
437            );
438            (
439                RefCell::new(Some(credentials.user_id.clone())),
440                RefCell::new(HashMap::from([(credentials.user_id.clone(), credentials)])),
441            )
442        } else {
443            debug!("Create new NetHSM connection {connection} with no initial credentials");
444            (Default::default(), Default::default())
445        };
446
447        let agent = RefCell::new(create_agent(
448            connection.tls_security,
449            max_idle_connections,
450            timeout_seconds,
451        )?);
452
453        Ok(Self {
454            agent,
455            url: RefCell::new(connection.url),
456            current_credentials,
457            credentials,
458        })
459    }
460
461    /// Validates the potential [namespace] access of a context.
462    ///
463    /// Validates, that [`current_credentials`][`NetHsm::current_credentials`] can be used in a
464    /// defined context. This function relies on [`UserId::validate_namespace_access`] and should be
465    /// used for validating the context of [`NetHsm`] methods.
466    ///
467    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
468    fn validate_namespace_access(
469        &self,
470        support: NamespaceSupport,
471        target: Option<&UserId>,
472        role: Option<&UserRole>,
473    ) -> Result<(), Error> {
474        debug!(
475            "Validate namespace access (target: {}; namespace: {support}; role: {}) for NetHSM at {}",
476            if let Some(target) = target {
477                target.to_string()
478            } else {
479                "n/a".to_string()
480            },
481            if let Some(role) = role {
482                role.to_string()
483            } else {
484                "n/a".to_string()
485            },
486            self.url.borrow()
487        );
488
489        if let Some(current_user_id) = self.current_credentials.borrow().to_owned() {
490            current_user_id.validate_namespace_access(support, target, role)?
491        }
492        Ok(())
493    }
494
495    /// Creates a connection configuration.
496    ///
497    /// Uses the [`Agent`] configured during creation of the [`NetHsm`], the current [`Url`] and
498    /// [`Credentials`] to create a [`Configuration`] for a connection to the API of a NetHSM.
499    fn create_connection_config(&self) -> Configuration {
500        debug!(
501            "Create connection config for NetHSM at {}",
502            self.url.borrow()
503        );
504
505        let current_credentials = self.current_credentials.borrow().to_owned();
506        Configuration {
507            client: self.agent.borrow().to_owned(),
508            base_path: self.url.borrow().to_string(),
509            basic_auth: if let Some(current_credentials) = current_credentials {
510                self.credentials
511                    .borrow()
512                    .get(&current_credentials)
513                    .map(Into::into)
514            } else {
515                None
516            },
517            user_agent: Some(format!(
518                "{}/{}",
519                env!("CARGO_PKG_NAME"),
520                env!("CARGO_PKG_VERSION")
521            )),
522            ..Default::default()
523        }
524    }
525
526    /// Sets the connection agent for the NetHSM connection.
527    ///
528    /// Allows setting the
529    /// - [`ConnectionSecurity`] which defines the TLS security model for the connection,
530    /// - maximum idle connections per host using the optional `max_idle_connections` (defaults to
531    ///   [`available_parallelism`] and falls back to `100` if unavailable),
532    /// - and timeout in seconds for a successful socket connection using the optional
533    ///   `timeout_seconds` (defaults to `10`).
534    ///
535    /// # Errors
536    ///
537    /// Returns an error if
538    ///
539    /// - the TLS client configuration can not be created,
540    /// - [`ConnectionSecurity::Native`] is provided as `tls_security`, but no certification
541    ///   authority certificates are available on the system.
542    ///
543    /// # Examples
544    ///
545    /// ```
546    /// use nethsm::{Connection, ConnectionSecurity, NetHsm, Url};
547    ///
548    /// # fn main() -> testresult::TestResult {
549    /// // Create a new connection for a NetHSM at "https://example.org"
550    /// let nethsm = NetHsm::new(
551    ///     Connection::new(
552    ///         "https://example.org/api/v1".try_into()?,
553    ///         ConnectionSecurity::Unsafe,
554    ///     ),
555    ///     None,
556    ///     None,
557    ///     None,
558    /// )?;
559    ///
560    /// // change the connection agent to something else
561    /// nethsm.set_agent(ConnectionSecurity::Unsafe, Some(200), Some(30))?;
562    /// # Ok(())
563    /// # }
564    /// ```
565    pub fn set_agent(
566        &self,
567        tls_security: ConnectionSecurity,
568        max_idle_connections: Option<usize>,
569        timeout_seconds: Option<u64>,
570    ) -> Result<(), Error> {
571        debug!(
572            "Set TLS agent (TLS security: {tls_security}; max idle: {}, timeout: {}) for NetHSM at {}",
573            if let Some(max_idle_connections) = max_idle_connections {
574                max_idle_connections.to_string()
575            } else {
576                DEFAULT_MAX_IDLE_CONNECTIONS.to_string()
577            },
578            if let Some(timeout_seconds) = timeout_seconds {
579                format!("{timeout_seconds}s")
580            } else {
581                format!("{DEFAULT_TIMEOUT_SECONDS}s")
582            },
583            self.url.borrow()
584        );
585
586        *self.agent.borrow_mut() =
587            create_agent(tls_security, max_idle_connections, timeout_seconds)?;
588        Ok(())
589    }
590
591    /// Sets the URL for the NetHSM connection.
592    ///
593    /// # Examples
594    ///
595    /// ```
596    /// use nethsm::{Connection, ConnectionSecurity, NetHsm, Url};
597    ///
598    /// # fn main() -> testresult::TestResult {
599    /// // Create a new connection for a NetHSM at "https://example.org"
600    /// let nethsm = NetHsm::new(
601    ///     Connection::new(
602    ///         "https://example.org/api/v1".try_into()?,
603    ///         ConnectionSecurity::Unsafe,
604    ///     ),
605    ///     None,
606    ///     None,
607    ///     None,
608    /// )?;
609    ///
610    /// // change the url to something else
611    /// nethsm.set_url(Url::new("https://other.org/api/v1")?);
612    /// # Ok(())
613    /// # }
614    /// ```
615    pub fn set_url(&self, url: Url) {
616        debug!(
617            "Set the URL to {url} for the NetHSM at {}",
618            self.url.borrow()
619        );
620
621        *self.url.borrow_mut() = url;
622    }
623
624    /// Retrieves the current URL for the NetHSM connection.
625    ///
626    /// # Examples
627    ///
628    /// ```
629    /// use nethsm::{Connection, ConnectionSecurity, NetHsm, Url};
630    ///
631    /// # fn main() -> testresult::TestResult {
632    /// // Create a new connection for a NetHSM at "https://example.org"
633    /// let nethsm = NetHsm::new(
634    ///     Connection::new(
635    ///         "https://example.org/api/v1".try_into()?,
636    ///         ConnectionSecurity::Unsafe,
637    ///     ),
638    ///     None,
639    ///     None,
640    ///     None,
641    /// )?;
642    ///
643    /// // retrieve the current URL
644    /// assert_eq!(nethsm.get_url(), "https://example.org/api/v1".try_into()?);
645    /// # Ok(())
646    /// # }
647    /// ```
648    pub fn get_url(&self) -> Url {
649        trace!("Get the URL for the NetHSM at {}", self.url.borrow());
650
651        self.url.borrow().clone()
652    }
653
654    /// Adds [`Credentials`] to the list of available ones.
655    ///
656    /// # Examples
657    ///
658    /// ```
659    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
660    ///
661    /// # fn main() -> testresult::TestResult {
662    /// let nethsm = NetHsm::new(
663    ///     Connection::new(
664    ///         "https://example.org/api/v1".try_into()?,
665    ///         ConnectionSecurity::Unsafe,
666    ///     ),
667    ///     None,
668    ///     None,
669    ///     None,
670    /// )?;
671    ///
672    /// // add credentials
673    /// nethsm.add_credentials(Credentials::new(
674    ///     "admin".parse()?,
675    ///     Some(Passphrase::new("passphrase".to_string())),
676    /// ));
677    /// nethsm.add_credentials(Credentials::new(
678    ///     "user1".parse()?,
679    ///     Some(Passphrase::new("other_passphrase".to_string())),
680    /// ));
681    /// nethsm.add_credentials(Credentials::new("user2".parse()?, None));
682    /// # Ok(())
683    /// # }
684    /// ```
685    pub fn add_credentials(&self, credentials: Credentials) {
686        debug!("Add NetHSM connection credentials for {credentials}");
687
688        self.credentials
689            .borrow_mut()
690            .insert(credentials.user_id.clone(), credentials);
691    }
692
693    /// Removes [`Credentials`] from the list of available and currently used ones.
694    ///
695    /// Removes [`Credentials`] from the list of available ones and if identical unsets the
696    /// ones used for further authentication as well.
697    ///
698    /// # Examples
699    ///
700    /// ```
701    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
702    ///
703    /// # fn main() -> testresult::TestResult {
704    /// let nethsm = NetHsm::new(
705    ///     Connection::new(
706    ///         "https://example.org/api/v1".try_into()?,
707    ///         ConnectionSecurity::Unsafe,
708    ///     ),
709    ///     Some(Credentials::new(
710    ///         "admin".parse()?,
711    ///         Some(Passphrase::new("passphrase".to_string())),
712    ///     )),
713    ///     None,
714    ///     None,
715    /// )?;
716    ///
717    /// // remove credentials
718    /// nethsm.remove_credentials(&"admin".parse()?);
719    /// # Ok(())
720    /// # }
721    /// ```
722    pub fn remove_credentials(&self, user_id: &UserId) {
723        debug!("Remove NetHSM connection credentials for {user_id}");
724
725        self.credentials.borrow_mut().remove(user_id);
726        if self
727            .current_credentials
728            .borrow()
729            .as_ref()
730            .is_some_and(|id| id == user_id)
731        {
732            *self.current_credentials.borrow_mut() = None
733        }
734    }
735
736    /// Sets [`Credentials`] to use for the next connection.
737    ///
738    /// # Errors
739    ///
740    /// An [`Error`] is returned if no [`Credentials`] with the [`UserId`] `user_id` can be found.
741    ///
742    /// # Examples
743    ///
744    /// ```
745    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
746    ///
747    /// # fn main() -> testresult::TestResult {
748    /// let nethsm = NetHsm::new(
749    ///     Connection::new(
750    ///         "https://example.org/api/v1".try_into()?,
751    ///         ConnectionSecurity::Unsafe,
752    ///     ),
753    ///     None,
754    ///     None,
755    ///     None,
756    /// )?;
757    ///
758    /// // add credentials
759    /// nethsm.add_credentials(Credentials::new(
760    ///     "admin".parse()?,
761    ///     Some(Passphrase::new("passphrase".to_string())),
762    /// ));
763    /// nethsm.add_credentials(Credentials::new(
764    ///     "user1".parse()?,
765    ///     Some(Passphrase::new("other_passphrase".to_string())),
766    /// ));
767    ///
768    /// // use admin credentials
769    /// nethsm.use_credentials(&"admin".parse()?)?;
770    ///
771    /// // use operator credentials
772    /// nethsm.use_credentials(&"user1".parse()?)?;
773    ///
774    /// // this fails, because the user has not been added yet
775    /// assert!(nethsm.use_credentials(&"user2".parse()?).is_err());
776    /// # Ok(())
777    /// # }
778    /// ```
779    pub fn use_credentials(&self, user_id: &UserId) -> Result<(), Error> {
780        debug!("Use NetHSM connection credentials of {user_id}");
781
782        if self.credentials.borrow().contains_key(user_id) {
783            if self.current_credentials.borrow().as_ref().is_none()
784                || self
785                    .current_credentials
786                    .borrow()
787                    .as_ref()
788                    .is_some_and(|id| id != user_id)
789            {
790                *self.current_credentials.borrow_mut() = Some(user_id.to_owned());
791            }
792        } else {
793            return Err(Error::Default(format!(
794                "The credentials for User ID \"{user_id}\" need to be added before they can be used!"
795            )));
796        }
797        Ok(())
798    }
799
800    /// Get the [`UserId`] of the currently used [`Credentials`] for the connection.
801    ///
802    /// # Examples
803    ///
804    /// ```
805    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm};
806    ///
807    /// # fn main() -> testresult::TestResult {
808    /// let nethsm = NetHsm::new(
809    ///     Connection::new(
810    ///         "https://example.org/api/v1".try_into()?,
811    ///         ConnectionSecurity::Unsafe,
812    ///     ),
813    ///     Some(Credentials::new(
814    ///         "admin".parse()?,
815    ///         Some("passphrase".parse()?),
816    ///     )),
817    ///     None,
818    ///     None,
819    /// )?;
820    ///
821    /// // Get current User ID
822    /// assert_eq!(nethsm.get_current_user(), Some("admin".parse()?));
823    /// # Ok(())
824    /// # }
825    /// ```
826    pub fn get_current_user(&self) -> Option<UserId> {
827        trace!(
828            "Get current User ID of NetHSM connection at {}",
829            self.url.borrow()
830        );
831
832        self.current_credentials.borrow().clone()
833    }
834
835    /// Provisions a NetHSM.
836    ///
837    /// [Provisioning] is the initial setup step for a NetHSM.
838    /// It sets the `unlock_passphrase`, which is used to [`unlock`][`NetHsm::unlock`] a device in
839    /// [`Locked`][`SystemState::Locked`] [state], the initial `admin_passphrase` for the
840    /// default [`Administrator`][`UserRole::Administrator`] account ("admin") and the
841    /// `system_time`. The unlock passphrase can later on be changed using
842    /// [`set_unlock_passphrase`][`NetHsm::set_unlock_passphrase`] and the admin passphrase using
843    /// [`set_user_passphrase`][`NetHsm::set_user_passphrase`].
844    ///
845    /// For this call no [`Credentials`] are required and if any are configured, they are ignored.
846    ///
847    /// # Errors
848    ///
849    /// Returns an [`Error::Api`] if provisioning fails:
850    /// * the NetHSM is not in [`Unprovisioned`][`SystemState::Unprovisioned`] [state]
851    /// * the provided data is malformed
852    ///
853    /// # Examples
854    ///
855    /// ```no_run
856    /// use chrono::Utc;
857    /// use nethsm::{Connection, ConnectionSecurity, NetHsm, Passphrase};
858    ///
859    /// # fn main() -> testresult::TestResult {
860    /// // no initial credentials are required
861    /// let nethsm = NetHsm::new(
862    ///     Connection::new(
863    ///         "https://example.org/api/v1".try_into()?,
864    ///         ConnectionSecurity::Unsafe,
865    ///     ),
866    ///     None,
867    ///     None,
868    ///     None,
869    /// )?;
870    ///
871    /// // provision the NetHSM
872    /// nethsm.provision(
873    ///     Passphrase::new("unlock-the-device".to_string()),
874    ///     Passphrase::new("admin-passphrase".to_string()),
875    ///     Utc::now(),
876    /// )?;
877    /// # Ok(())
878    /// # }
879    /// ```
880    /// [Provisioning]: https://docs.nitrokey.com/nethsm/getting-started#provisioning
881    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
882    pub fn provision(
883        &self,
884        unlock_passphrase: Passphrase,
885        admin_passphrase: Passphrase,
886        system_time: DateTime<Utc>,
887    ) -> Result<(), Error> {
888        debug!("Provision the NetHSM at {}", self.url.borrow());
889
890        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
891        provision_post(
892            &self.create_connection_config(),
893            ProvisionRequestData::new(
894                unlock_passphrase.expose_owned(),
895                admin_passphrase.expose_owned(),
896                system_time.to_rfc3339_opts(chrono::SecondsFormat::Secs, true),
897            ),
898        )
899        .map_err(|error| {
900            Error::Api(format!(
901                "Provisioning failed: {}",
902                NetHsmApiError::from(error)
903            ))
904        })?;
905        Ok(())
906    }
907
908    /// Returns whether the NetHSM is in [`Unprovisioned`][`SystemState::Unprovisioned`] or
909    /// [`Locked`][`SystemState::Locked`] [state].
910    ///
911    /// For this call no [`Credentials`] are required and if any are configured, they are ignored.
912    ///
913    /// # Errors
914    ///
915    /// Returns an [`Error::Api`] if the information can not be retrieved or the NetHSM is in
916    /// [`Operational`][`SystemState::Operational`] [state].
917    ///
918    /// # Examples
919    ///
920    /// ```no_run
921    /// use nethsm::{Connection, ConnectionSecurity, NetHsm};
922    ///
923    /// # fn main() -> testresult::TestResult {
924    /// // no initial credentials are required
925    /// let nethsm = NetHsm::new(
926    ///     Connection::new(
927    ///         "https://example.org/api/v1".try_into()?,
928    ///         ConnectionSecurity::Unsafe,
929    ///     ),
930    ///     None,
931    ///     None,
932    ///     None,
933    /// )?;
934    ///
935    /// // check whether the NetHSM is locked or unprovisioned
936    /// assert!(nethsm.alive().is_ok());
937    /// # Ok(())
938    /// # }
939    /// ```
940    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
941    pub fn alive(&self) -> Result<(), Error> {
942        debug!("Check whether the NetHSM at {} is alive", self.url.borrow());
943
944        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
945        health_alive_get(&self.create_connection_config()).map_err(|error| {
946            Error::Api(format!(
947                "Retrieving alive status failed: {}",
948                NetHsmApiError::from(error)
949            ))
950        })?;
951        Ok(())
952    }
953
954    /// Returns whether the NetHSM is in [`Operational`][`SystemState::Operational`] [state].
955    ///
956    /// For this call no [`Credentials`] are required and if any are configured, they are ignored.
957    ///
958    /// # Errors
959    ///
960    /// Returns an [`Error::Api`] if the information can not be retrieved or the NetHSM is in
961    /// [`Unprovisioned`][`SystemState::Unprovisioned`] or [`Locked`][`SystemState::Locked`]
962    /// [state].
963    ///
964    /// # Examples
965    ///
966    /// ```no_run
967    /// use nethsm::{Connection, ConnectionSecurity, NetHsm};
968    ///
969    /// # fn main() -> testresult::TestResult {
970    /// // no initial credentials are required
971    /// let nethsm = NetHsm::new(
972    ///     Connection::new(
973    ///         "https://example.org/api/v1".try_into()?,
974    ///         ConnectionSecurity::Unsafe,
975    ///     ),
976    ///     None,
977    ///     None,
978    ///     None,
979    /// )?;
980    ///
981    /// // check whether the NetHSM is operational
982    /// assert!(nethsm.ready().is_ok());
983    /// # Ok(())
984    /// # }
985    /// ```
986    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
987    pub fn ready(&self) -> Result<(), Error> {
988        debug!("Check whether the NetHSM at {} is ready", self.url.borrow());
989
990        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
991        health_ready_get(&self.create_connection_config()).map_err(|error| {
992            Error::Api(format!(
993                "Retrieving ready status failed: {}",
994                NetHsmApiError::from(error)
995            ))
996        })?;
997        Ok(())
998    }
999
1000    /// Returns the system [state] of the NetHSM.
1001    ///
1002    /// Returns a variant of [`SystemState`], which describes the [state] a NetHSM is currently in.
1003    ///
1004    /// For this call no [`Credentials`] are required and if any are configured, they are ignored.
1005    ///
1006    /// # Errors
1007    ///
1008    /// Returns an [`Error::Api`] if the [state] information can not be retrieved.
1009    ///
1010    /// # Examples
1011    ///
1012    /// ```no_run
1013    /// use nethsm::{Connection, ConnectionSecurity, NetHsm};
1014    ///
1015    /// # fn main() -> testresult::TestResult {
1016    /// // no initial credentials are required
1017    /// let nethsm = NetHsm::new(
1018    ///     Connection::new(
1019    ///         "https://example.org/api/v1".try_into()?,
1020    ///         ConnectionSecurity::Unsafe,
1021    ///     ),
1022    ///     None,
1023    ///     None,
1024    ///     None,
1025    /// )?;
1026    ///
1027    /// // retrieve the state
1028    /// println!("{:?}", nethsm.state()?);
1029    /// # Ok(())
1030    /// # }
1031    /// ```
1032    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1033    pub fn state(&self) -> Result<SystemState, Error> {
1034        debug!("Get the state of the NetHSM at {}", self.url.borrow());
1035
1036        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1037        let health_state = health_state_get(&self.create_connection_config()).map_err(|error| {
1038            Error::Api(format!(
1039                "Retrieving state failed: {}",
1040                NetHsmApiError::from(error)
1041            ))
1042        })?;
1043        Ok(health_state.entity.state)
1044    }
1045
1046    /// Returns [device information] for the NetHSM.
1047    ///
1048    /// Returns an [`InfoData`], which provides the [device information].
1049    ///
1050    /// For this call no [`Credentials`] are required and if any are configured, they are ignored.
1051    ///
1052    /// # Errors
1053    ///
1054    /// Returns an [`Error::Api`] if the NetHSM [device information] can not be retrieved.
1055    ///
1056    /// # Examples
1057    ///
1058    /// ```no_run
1059    /// use nethsm::{Connection, ConnectionSecurity, NetHsm};
1060    ///
1061    /// # fn main() -> testresult::TestResult {
1062    /// // no initial credentials are required
1063    /// let nethsm = NetHsm::new(
1064    ///     Connection::new(
1065    ///         "https://example.org/api/v1".try_into()?,
1066    ///         ConnectionSecurity::Unsafe,
1067    ///     ),
1068    ///     None,
1069    ///     None,
1070    ///     None,
1071    /// )?;
1072    ///
1073    /// // retrieve the NetHSM info
1074    /// println!("{:?}", nethsm.info()?);
1075    /// # Ok(())
1076    /// # }
1077    /// ```
1078    /// [device information]: https://docs.nitrokey.com/nethsm/administration#device-information
1079    pub fn info(&self) -> Result<InfoData, Error> {
1080        debug!("Get info about the NetHSM at {}", self.url.borrow());
1081
1082        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1083        let info = info_get(&self.create_connection_config()).map_err(|error| {
1084            Error::Api(format!(
1085                "Retrieving device information failed: {}",
1086                NetHsmApiError::from(error)
1087            ))
1088        })?;
1089        Ok(info.entity)
1090    }
1091
1092    /// Returns metrics for the NetHSM.
1093    ///
1094    /// Returns a [`Value`][`serde_json::Value`] which provides [metrics] for the NetHSM.
1095    ///
1096    /// This call requires using [`Credentials`] of a user in the [`Metrics`][`UserRole::Metrics`]
1097    /// [role].
1098    ///
1099    /// # Errors
1100    ///
1101    /// Returns an [`Error::Api`] if the NetHSM [metrics] can not be retrieved:
1102    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1103    /// * the used [`Credentials`] are not correct
1104    /// * the used [`Credentials`] are not that of a user in the [`Metrics`][`UserRole::Metrics`]
1105    ///   [role]
1106    ///
1107    /// # Examples
1108    ///
1109    /// ```no_run
1110    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
1111    ///
1112    /// # fn main() -> testresult::TestResult {
1113    /// // create a connection with a system-wide user in the Metrics role
1114    /// let nethsm = NetHsm::new(
1115    ///     Connection::new(
1116    ///         "https://example.org/api/v1".try_into()?,
1117    ///         ConnectionSecurity::Unsafe,
1118    ///     ),
1119    ///     Some(Credentials::new(
1120    ///         "metrics".parse()?,
1121    ///         Some(Passphrase::new("metrics-passphrase".to_string())),
1122    ///     )),
1123    ///     None,
1124    ///     None,
1125    /// )?;
1126    ///
1127    /// // retrieve the metrics
1128    /// println!("{:?}", nethsm.metrics()?);
1129    /// # Ok(())
1130    /// # }
1131    /// ```
1132    /// [metrics]: https://docs.nitrokey.com/nethsm/administration#metrics
1133    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1134    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1135    pub fn metrics(&self) -> Result<Value, Error> {
1136        debug!(
1137            "Retrieve metrics of the NetHSM at {} using {}",
1138            self.url.borrow(),
1139            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1140        );
1141
1142        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1143        let metrics = metrics_get(&self.create_connection_config()).map_err(|error| {
1144            Error::Api(format!(
1145                "Retrieving metrics failed: {}",
1146                NetHsmApiError::from(error)
1147            ))
1148        })?;
1149        Ok(metrics.entity)
1150    }
1151
1152    /// Sets the [unlock passphrase].
1153    ///
1154    /// Changes the [unlock passphrase] from `current_passphrase` to `new_passphrase`.
1155    ///
1156    /// This call requires using [`Credentials`] of a system-wide user in the
1157    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1158    ///
1159    /// # Errors
1160    ///
1161    /// Returns an [`Error::Api`] if the [unlock passphrase] can not be changed:
1162    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1163    /// * the provided `current_passphrase` is not correct
1164    /// * the used [`Credentials`] are not correct
1165    /// * the used [`Credentials`] are not that of a system-wide user in the
1166    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1167    ///
1168    /// # Examples
1169    ///
1170    /// ```no_run
1171    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1172    ///
1173    /// # fn main() -> testresult::TestResult {
1174    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1175    /// let nethsm = NetHsm::new(
1176    ///     Connection::new(
1177    ///         "https://example.org/api/v1".try_into()?,
1178    ///         ConnectionSecurity::Unsafe,
1179    ///     ),
1180    ///     Some(Credentials::new(
1181    ///         "admin".parse()?,
1182    ///         Some(Passphrase::new("passphrase".to_string())),
1183    ///     )),
1184    ///     None,
1185    ///     None,
1186    /// )?;
1187    /// // add a user in the Administrator role for a namespace (N-Administrator)
1188    /// nethsm.add_user(
1189    ///     "Namespace1 Admin".to_string(),
1190    ///     UserRole::Administrator,
1191    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1192    ///     Some("namespace1~admin1".parse()?),
1193    /// )?;
1194    /// // create accompanying namespace
1195    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1196    ///
1197    /// // R-Administrators can set the unlock passphrase
1198    /// nethsm.set_unlock_passphrase(
1199    ///     Passphrase::new("current-unlock-passphrase".to_string()),
1200    ///     Passphrase::new("new-unlock-passphrase".to_string()),
1201    /// )?;
1202    ///
1203    /// // N-Administrators can not set the unlock passphrase
1204    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1205    /// assert!(
1206    ///     nethsm
1207    ///         .set_unlock_passphrase(
1208    ///             Passphrase::new("current-unlock-passphrase".to_string()),
1209    ///             Passphrase::new("new-unlock-passphrase".to_string()),
1210    ///         )
1211    ///         .is_err()
1212    /// );
1213    /// # Ok(())
1214    /// # }
1215    /// ```
1216    /// [unlock passphrase]: https://docs.nitrokey.com/nethsm/administration#unlock-passphrase
1217    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1218    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1219    pub fn set_unlock_passphrase(
1220        &self,
1221        current_passphrase: Passphrase,
1222        new_passphrase: Passphrase,
1223    ) -> Result<(), Error> {
1224        debug!(
1225            "Set unlock passphrase for the NetHSM at {} using {}",
1226            self.url.borrow(),
1227            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1228        );
1229
1230        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1231        config_unlock_passphrase_put(
1232            &self.create_connection_config(),
1233            UnlockPassphraseConfig::new(
1234                new_passphrase.expose_owned(),
1235                current_passphrase.expose_owned(),
1236            ),
1237        )
1238        .map_err(|error| {
1239            Error::Api(format!(
1240                "Changing unlock passphrase failed: {}",
1241                NetHsmApiError::from(error)
1242            ))
1243        })?;
1244        Ok(())
1245    }
1246
1247    /// Returns the [boot mode].
1248    ///
1249    /// Returns a variant of [`BootMode`] which represents the NetHSM's [boot mode].
1250    ///
1251    /// This call requires using [`Credentials`] of a system-wide user in the
1252    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1253    ///
1254    /// # Errors
1255    ///
1256    /// Returns an [`Error::Api`] if the boot mode can not be retrieved:
1257    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1258    /// * the used [`Credentials`] are not correct
1259    /// * the used [`Credentials`] are not that of a system-wide user in the
1260    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1261    ///
1262    /// # Examples
1263    ///
1264    /// ```no_run
1265    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1266    ///
1267    /// # fn main() -> testresult::TestResult {
1268    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1269    /// let nethsm = NetHsm::new(
1270    ///     Connection::new(
1271    ///         "https://example.org/api/v1".try_into()?,
1272    ///         ConnectionSecurity::Unsafe,
1273    ///     ),
1274    ///     Some(Credentials::new(
1275    ///         "admin".parse()?,
1276    ///         Some(Passphrase::new("passphrase".to_string())),
1277    ///     )),
1278    ///     None,
1279    ///     None,
1280    /// )?;
1281    /// // add a user in the Administrator role for a namespace (N-Administrator)
1282    /// nethsm.add_user(
1283    ///     "Namespace1 Admin".to_string(),
1284    ///     UserRole::Administrator,
1285    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1286    ///     Some("namespace1~admin1".parse()?),
1287    /// )?;
1288    /// // create accompanying namespace
1289    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1290    ///
1291    /// // R-Administrators can retrieve the boot mode
1292    /// println!("{:?}", nethsm.get_boot_mode()?);
1293    ///
1294    /// // N-Administrators can not retrieve the boot mode
1295    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1296    /// assert!(nethsm.get_boot_mode().is_err());
1297    /// # Ok(())
1298    /// # }
1299    /// ```
1300    /// [boot mode]: https://docs.nitrokey.com/nethsm/administration#boot-mode
1301    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1302    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1303    pub fn get_boot_mode(&self) -> Result<BootMode, Error> {
1304        debug!(
1305            "Get the boot mode of the NetHSM at {} using {}",
1306            self.url.borrow(),
1307            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1308        );
1309
1310        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1311        Ok(BootMode::from(
1312            config_unattended_boot_get(&self.create_connection_config())
1313                .map_err(|error| {
1314                    Error::Api(format!(
1315                        "Retrieving boot mode failed: {}",
1316                        NetHsmApiError::from(error)
1317                    ))
1318                })?
1319                .entity,
1320        ))
1321    }
1322
1323    /// Sets the [boot mode].
1324    ///
1325    /// Sets the NetHSM's [boot mode] based on a [`BootMode`] variant.
1326    ///
1327    /// This call requires using [`Credentials`] of a system-wide user in the
1328    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1329    ///
1330    /// # Errors
1331    ///
1332    /// Returns an [`Error::Api`] if the boot mode can not be set:
1333    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1334    /// * the used [`Credentials`] are not correct
1335    /// * the used [`Credentials`] are not that of a system-wide user in the
1336    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1337    ///
1338    /// # Examples
1339    ///
1340    /// ```no_run
1341    /// use nethsm::{
1342    ///     BootMode,
1343    ///     Connection,
1344    ///     ConnectionSecurity,
1345    ///     Credentials,
1346    ///     NetHsm,
1347    ///     Passphrase,
1348    ///     UserRole,
1349    /// };
1350    ///
1351    /// # fn main() -> testresult::TestResult {
1352    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1353    /// let nethsm = NetHsm::new(
1354    ///     Connection::new(
1355    ///         "https://example.org/api/v1".try_into()?,
1356    ///         ConnectionSecurity::Unsafe,
1357    ///     ),
1358    ///     Some(Credentials::new(
1359    ///         "admin".parse()?,
1360    ///         Some(Passphrase::new("passphrase".to_string())),
1361    ///     )),
1362    ///     None,
1363    ///     None,
1364    /// )?;
1365    /// // add a user in the Administrator role for a namespace (N-Administrator)
1366    /// nethsm.add_user(
1367    ///     "Namespace1 Admin".to_string(),
1368    ///     UserRole::Administrator,
1369    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1370    ///     Some("namespace1~admin1".parse()?),
1371    /// )?;
1372    /// // create accompanying namespace
1373    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1374    ///
1375    /// // R-Administrators can set the boot mode
1376    /// // set the boot mode to unattended
1377    /// nethsm.set_boot_mode(BootMode::Unattended)?;
1378    /// // set the boot mode to attended
1379    /// nethsm.set_boot_mode(BootMode::Attended)?;
1380    ///
1381    /// // N-Administrators can not set the boot mode
1382    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1383    /// assert!(nethsm.set_boot_mode(BootMode::Attended).is_err());
1384    /// # Ok(())
1385    /// # }
1386    /// ```
1387    /// [boot mode]: https://docs.nitrokey.com/nethsm/administration#boot-mode
1388    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1389    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1390    pub fn set_boot_mode(&self, boot_mode: BootMode) -> Result<(), Error> {
1391        debug!(
1392            "Set the boot mode for the NetHSM at {} to {boot_mode} using {}",
1393            self.url.borrow(),
1394            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1395        );
1396
1397        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1398        config_unattended_boot_put(&self.create_connection_config(), boot_mode.into()).map_err(
1399            |error| {
1400                Error::Api(format!(
1401                    "Setting boot mode failed: {}",
1402                    NetHsmApiError::from(error)
1403                ))
1404            },
1405        )?;
1406        Ok(())
1407    }
1408
1409    /// Returns the TLS public key of the API.
1410    ///
1411    /// Returns the NetHSM's public key part of its [TLS certificate] which is used for
1412    /// communication with the API.
1413    ///
1414    /// This call requires using [`Credentials`] of a system-wide user in the
1415    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1416    ///
1417    /// # Errors
1418    ///
1419    /// Returns an [`Error::Api`] if the NetHSM's TLS public key can not be retrieved:
1420    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1421    /// * the used [`Credentials`] are not correct
1422    /// * the used [`Credentials`] are not that of a system-wide user in the
1423    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1424    ///
1425    /// # Examples
1426    ///
1427    /// ```no_run
1428    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1429    ///
1430    /// # fn main() -> testresult::TestResult {
1431    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1432    /// let nethsm = NetHsm::new(
1433    ///     Connection::new(
1434    ///         "https://example.org/api/v1".try_into()?,
1435    ///         ConnectionSecurity::Unsafe,
1436    ///     ),
1437    ///     Some(Credentials::new(
1438    ///         "admin".parse()?,
1439    ///         Some(Passphrase::new("passphrase".to_string())),
1440    ///     )),
1441    ///     None,
1442    ///     None,
1443    /// )?;
1444    /// // add a user in the Administrator role for a namespace (N-Administrator)
1445    /// nethsm.add_user(
1446    ///     "Namespace1 Admin".to_string(),
1447    ///     UserRole::Administrator,
1448    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1449    ///     Some("namespace1~admin1".parse()?),
1450    /// )?;
1451    /// // create accompanying namespace
1452    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1453    ///
1454    /// // R-Administrators can get the TLS public key
1455    /// println!("{}", nethsm.get_tls_public_key()?);
1456    ///
1457    /// // N-Administrators can not get the TLS public key
1458    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1459    /// assert!(nethsm.get_tls_public_key().is_err());
1460    /// # Ok(())
1461    /// # }
1462    /// ```
1463    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
1464    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1465    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1466    pub fn get_tls_public_key(&self) -> Result<String, Error> {
1467        debug!(
1468            "Retrieve the TLS public key for the NetHSM at {} using {}",
1469            self.url.borrow(),
1470            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1471        );
1472
1473        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1474        Ok(config_tls_public_pem_get(&self.create_connection_config())
1475            .map_err(|error| {
1476                Error::Api(format!(
1477                    "Retrieving API TLS public key failed: {}",
1478                    NetHsmApiError::from(error)
1479                ))
1480            })?
1481            .entity)
1482    }
1483
1484    /// Returns the TLS certificate of the API.
1485    ///
1486    /// Returns the NetHSM's [TLS certificate] which is used for communication with the API.
1487    ///
1488    /// This call requires using [`Credentials`] of a system-wide user in the
1489    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1490    ///
1491    /// # Errors
1492    ///
1493    /// Returns an [`Error::Api`] if the NetHSM's TLS certificate can not be retrieved:
1494    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1495    /// * the used [`Credentials`] are not correct
1496    /// * the used [`Credentials`] are not that of a system-wide user in the
1497    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1498    ///
1499    /// # Examples
1500    ///
1501    /// ```no_run
1502    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1503    ///
1504    /// # fn main() -> testresult::TestResult {
1505    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1506    /// let nethsm = NetHsm::new(
1507    ///     Connection::new(
1508    ///         "https://example.org/api/v1".try_into()?,
1509    ///         ConnectionSecurity::Unsafe,
1510    ///     ),
1511    ///     Some(Credentials::new(
1512    ///         "admin".parse()?,
1513    ///         Some(Passphrase::new("passphrase".to_string())),
1514    ///     )),
1515    ///     None,
1516    ///     None,
1517    /// )?;
1518    /// // add a user in the Administrator role for a namespace (N-Administrator)
1519    /// nethsm.add_user(
1520    ///     "Namespace1 Admin".to_string(),
1521    ///     UserRole::Administrator,
1522    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1523    ///     Some("namespace1~admin1".parse()?),
1524    /// )?;
1525    /// // create accompanying namespace
1526    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1527    ///
1528    /// // R-Administrators can get the TLS certificate
1529    /// println!("{}", nethsm.get_tls_cert()?);
1530    ///
1531    /// // N-Administrators can not get the TLS certificate
1532    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1533    /// assert!(nethsm.get_tls_cert().is_err());
1534    /// # Ok(())
1535    /// # }
1536    /// ```
1537    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
1538    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1539    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1540    pub fn get_tls_cert(&self) -> Result<String, Error> {
1541        debug!(
1542            "Retrieve the TLS certificate for the NetHSM at {} using {}",
1543            self.url.borrow(),
1544            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1545        );
1546
1547        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1548        Ok(config_tls_cert_pem_get(&self.create_connection_config())
1549            .map_err(|error| {
1550                Error::Api(format!(
1551                    "Retrieving API TLS certificate failed: {}",
1552                    NetHsmApiError::from(error)
1553                ))
1554            })?
1555            .entity)
1556    }
1557
1558    /// Returns a Certificate Signing Request ([CSR]) for the API's [TLS certificate].
1559    ///
1560    /// Based on [`DistinguishedName`] data returns a [CSR] in [PKCS#10] format for the NetHSM's
1561    /// [TLS certificate].
1562    ///
1563    /// This call requires using [`Credentials`] of a system-wide user in the
1564    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1565    ///
1566    /// # Errors
1567    ///
1568    /// Returns an [`Error::Api`] if the [CSR] can not be retrieved:
1569    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1570    /// * the used [`Credentials`] are not correct
1571    /// * the used [`Credentials`] are not that of a system-wide user in the
1572    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1573    ///
1574    /// # Examples
1575    ///
1576    /// ```no_run
1577    /// use nethsm::{
1578    ///     Connection,
1579    ///     ConnectionSecurity,
1580    ///     Credentials,
1581    ///     DistinguishedName,
1582    ///     NetHsm,
1583    ///     Passphrase,
1584    ///     UserRole,
1585    /// };
1586    ///
1587    /// # fn main() -> testresult::TestResult {
1588    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1589    /// let nethsm = NetHsm::new(
1590    ///     Connection::new(
1591    ///         "https://example.org/api/v1".try_into()?,
1592    ///         ConnectionSecurity::Unsafe,
1593    ///     ),
1594    ///     Some(Credentials::new(
1595    ///         "admin".parse()?,
1596    ///         Some(Passphrase::new("passphrase".to_string())),
1597    ///     )),
1598    ///     None,
1599    ///     None,
1600    /// )?;
1601    /// // add a user in the Administrator role for a namespace (N-Administrator)
1602    /// nethsm.add_user(
1603    ///     "Namespace1 Admin".to_string(),
1604    ///     UserRole::Administrator,
1605    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1606    ///     Some("namespace1~admin1".parse()?),
1607    /// )?;
1608    /// // create accompanying namespace
1609    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1610    ///
1611    /// // R-Administrators can get a CSR for the TLS certificate
1612    /// println!(
1613    ///     "{}",
1614    ///     nethsm.get_tls_csr(DistinguishedName {
1615    ///         country_name: Some("DE".to_string()),
1616    ///         state_or_province_name: Some("Berlin".to_string()),
1617    ///         locality_name: Some("Berlin".to_string()),
1618    ///         organization_name: Some("Foobar Inc".to_string()),
1619    ///         organizational_unit_name: Some("Department of Foo".to_string()),
1620    ///         common_name: "Foobar Inc".to_string(),
1621    ///         email_address: Some("foobar@mcfooface.com".to_string()),
1622    ///     })?
1623    /// );
1624    ///
1625    /// // N-Administrators can not get a CSR for the TLS certificate
1626    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1627    /// assert!(
1628    ///     nethsm
1629    ///         .get_tls_csr(DistinguishedName {
1630    ///             country_name: Some("DE".to_string()),
1631    ///             state_or_province_name: Some("Berlin".to_string()),
1632    ///             locality_name: Some("Berlin".to_string()),
1633    ///             organization_name: Some("Foobar Inc".to_string()),
1634    ///             organizational_unit_name: Some("Department of Foo".to_string()),
1635    ///             common_name: "Foobar Inc".to_string(),
1636    ///             email_address: Some("foobar@mcfooface.com".to_string()),
1637    ///         })
1638    ///         .is_err()
1639    /// );
1640    /// # Ok(())
1641    /// # }
1642    /// ```
1643    /// [CSR]: https://en.wikipedia.org/wiki/Certificate_signing_request
1644    /// [PKCS#10]: https://en.wikipedia.org/wiki/Certificate_signing_request#Structure_of_a_PKCS_#10_CSR
1645    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
1646    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1647    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1648    pub fn get_tls_csr(&self, distinguished_name: DistinguishedName) -> Result<String, Error> {
1649        debug!(
1650            "Retrieve a Certificate Signing Request (for {}) for the TLS certificate of the NetHSM at {} using {}",
1651            distinguished_name.common_name,
1652            self.url.borrow(),
1653            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1654        );
1655
1656        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1657        Ok(
1658            config_tls_csr_pem_post(&self.create_connection_config(), distinguished_name)
1659                .map_err(|error| {
1660                    Error::Api(format!(
1661                        "Retrieving CSR for TLS certificate failed: {}",
1662                        NetHsmApiError::from(error),
1663                    ))
1664                })?
1665                .entity,
1666        )
1667    }
1668
1669    /// Generates a new [TLS certificate] for the API.
1670    ///
1671    /// Generates a new [TLS certificate] (used for communication with the API) based on
1672    /// `tls_key_type` and `length`.
1673    ///
1674    /// This call requires using [`Credentials`] of a system-wide user in the
1675    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1676    ///
1677    /// # Errors
1678    ///
1679    /// Returns an [`Error::Api`] if the new [TLS certificate] can not be generated:
1680    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1681    /// * the `tls_key_type` and `length` combination is not valid
1682    /// * the used [`Credentials`] are not correct
1683    /// * the used [`Credentials`] are not that of a system-wide user in the
1684    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1685    ///
1686    /// # Examples
1687    ///
1688    /// ```no_run
1689    /// use nethsm::{
1690    ///     Connection,
1691    ///     ConnectionSecurity,
1692    ///     Credentials,
1693    ///     NetHsm,
1694    ///     Passphrase,
1695    ///     TlsKeyType,
1696    ///     UserRole,
1697    /// };
1698    ///
1699    /// # fn main() -> testresult::TestResult {
1700    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1701    /// let nethsm = NetHsm::new(
1702    ///     Connection::new(
1703    ///         "https://example.org/api/v1".try_into()?,
1704    ///         ConnectionSecurity::Unsafe,
1705    ///     ),
1706    ///     Some(Credentials::new(
1707    ///         "admin".parse()?,
1708    ///         Some(Passphrase::new("passphrase".to_string())),
1709    ///     )),
1710    ///     None,
1711    ///     None,
1712    /// )?;
1713    /// // add a user in the Administrator role for a namespace (N-Administrator)
1714    /// nethsm.add_user(
1715    ///     "Namespace1 Admin".to_string(),
1716    ///     UserRole::Administrator,
1717    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1718    ///     Some("namespace1~admin1".parse()?),
1719    /// )?;
1720    /// // create accompanying namespace
1721    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1722    ///
1723    /// // R-Administrators can generate a new TLS certificate
1724    /// nethsm.generate_tls_cert(TlsKeyType::Rsa, Some(4096))?;
1725    ///
1726    /// // N-Administrators can not generate a new TLS certificate
1727    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1728    /// assert!(
1729    ///     nethsm
1730    ///         .generate_tls_cert(TlsKeyType::Rsa, Some(4096))
1731    ///         .is_err()
1732    /// );
1733    /// # Ok(())
1734    /// # }
1735    /// ```
1736    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
1737    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1738    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1739    pub fn generate_tls_cert(
1740        &self,
1741        tls_key_type: TlsKeyType,
1742        length: Option<u32>,
1743    ) -> Result<(), Error> {
1744        debug!(
1745            "Generate a TLS certificate ({tls_key_type}{}) on the NetHSM at {} using {}",
1746            if let Some(length) = length {
1747                format!(" {length} bit long")
1748            } else {
1749                "{}".to_string()
1750            },
1751            self.url.borrow(),
1752            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1753        );
1754
1755        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1756        // ensure the tls_key_type - length combination is valid
1757        tls_key_type_matches_length(tls_key_type, length)?;
1758        config_tls_generate_post(
1759            &self.create_connection_config(),
1760            TlsKeyGenerateRequestData {
1761                r#type: tls_key_type.into(),
1762                length: length.map(|length| length as i32),
1763            },
1764        )
1765        .map_err(|error| {
1766            Error::Api(format!(
1767                "Generating API TLS certificate failed: {}",
1768                NetHsmApiError::from(error)
1769            ))
1770        })?;
1771        Ok(())
1772    }
1773
1774    /// Sets a new [TLS certificate] for the API.
1775    ///
1776    /// Accepts a Base64 encoded [DER] certificate provided using `certificate` which is added as
1777    /// new [TLS certificate] for communication with the API.
1778    ///
1779    /// This call requires using [`Credentials`] of a system-wide user in the
1780    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1781    ///
1782    /// # Errors
1783    ///
1784    /// Returns an [`Error::Api`] if setting a new TLS certificate fails:
1785    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1786    /// * the provided `certificate` is not valid
1787    /// * the used [`Credentials`] are not correct
1788    /// * the used [`Credentials`] are not that of a system-wide user in the
1789    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1790    ///
1791    /// # Examples
1792    ///
1793    /// ```no_run
1794    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1795    ///
1796    /// # fn main() -> testresult::TestResult {
1797    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1798    /// let nethsm = NetHsm::new(
1799    ///     Connection::new(
1800    ///         "https://example.org/api/v1".try_into()?,
1801    ///         ConnectionSecurity::Unsafe,
1802    ///     ),
1803    ///     Some(Credentials::new(
1804    ///         "admin".parse()?,
1805    ///         Some(Passphrase::new("passphrase".to_string())),
1806    ///     )),
1807    ///     None,
1808    ///     None,
1809    /// )?;
1810    /// // add a user in the Administrator role for a namespace (N-Administrator)
1811    /// nethsm.add_user(
1812    ///     "Namespace1 Admin".to_string(),
1813    ///     UserRole::Administrator,
1814    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1815    ///     Some("namespace1~admin1".parse()?),
1816    /// )?;
1817    /// // create accompanying namespace
1818    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1819    ///
1820    /// let cert = r#"-----BEGIN CERTIFICATE-----
1821    /// MIIBHjCBxKADAgECAghDngCv6xWIXDAKBggqhkjOPQQDAjAUMRIwEAYDVQQDDAlr
1822    /// ZXlmZW5kZXIwIBcNNzAwMTAxMDAwMDAwWhgPOTk5OTEyMzEyMzU5NTlaMBQxEjAQ
1823    /// BgNVBAMMCWtleWZlbmRlcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJsHIrsZ
1824    /// 6fJzrk12GK7nW6bGyTIIZiQUq0uaKbn21dgPiDCO5+iYVXAqnWu4IMVZQnkFJmte
1825    /// PRUUuM3119f8ffkwCgYIKoZIzj0EAwIDSQAwRgIhALH4fDYJ21tRecXp9IipBlil
1826    /// p+hJCj77zBvFmGYy/UnPAiEA8csj7U6BfzvK4EiQyUZa7/as+nXwj3XHU/i8LyLm
1827    /// Chw=
1828    /// -----END CERTIFICATE-----"#;
1829    ///
1830    /// // R-Administrators can set a new TLS certificate
1831    /// nethsm.set_tls_cert(cert)?;
1832    ///
1833    /// // N-Administrators can not set a new TLS certificate
1834    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1835    /// assert!(nethsm.set_tls_cert(cert).is_err());
1836    /// # Ok(())
1837    /// # }
1838    /// ```
1839    /// [DER]: https://en.wikipedia.org/wiki/X.690#DER_encoding
1840    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
1841    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1842    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1843    pub fn set_tls_cert(&self, certificate: &str) -> Result<(), Error> {
1844        debug!(
1845            "Set a new TLS certificate for the NetHSM at {} using {}",
1846            self.url.borrow(),
1847            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1848        );
1849
1850        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1851        config_tls_cert_pem_put(&self.create_connection_config(), certificate).map_err(
1852            |error| {
1853                Error::Api(format!(
1854                    "Setting API TLS certificate failed: {}",
1855                    NetHsmApiError::from(error)
1856                ))
1857            },
1858        )?;
1859        Ok(())
1860    }
1861
1862    /// Gets the [network configuration].
1863    ///
1864    /// Retrieves the [network configuration] of the NetHSM as [`NetworkConfig`].
1865    ///
1866    /// This call requires using [`Credentials`] of a system-wide user in the
1867    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1868    ///
1869    /// # Errors
1870    ///
1871    /// Returns an [`Error::Api`] if retrieving network configuration fails:
1872    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1873    /// * the used [`Credentials`] are not correct
1874    /// * the used [`Credentials`] are not that of a system-wide user in the
1875    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1876    ///
1877    /// # Examples
1878    ///
1879    /// ```no_run
1880    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1881    ///
1882    /// # fn main() -> testresult::TestResult {
1883    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1884    /// let nethsm = NetHsm::new(
1885    ///     Connection::new(
1886    ///         "https://example.org/api/v1".try_into()?,
1887    ///         ConnectionSecurity::Unsafe,
1888    ///     ),
1889    ///     Some(Credentials::new(
1890    ///         "admin".parse()?,
1891    ///         Some(Passphrase::new("passphrase".to_string())),
1892    ///     )),
1893    ///     None,
1894    ///     None,
1895    /// )?;
1896    /// // add a user in the Administrator role for a namespace (N-Administrator)
1897    /// nethsm.add_user(
1898    ///     "Namespace1 Admin".to_string(),
1899    ///     UserRole::Administrator,
1900    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1901    ///     Some("namespace1~admin1".parse()?),
1902    /// )?;
1903    /// // create accompanying namespace
1904    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1905    ///
1906    /// // R-Administrators can get the network configuration
1907    /// println!("{:?}", nethsm.get_network()?);
1908    ///
1909    /// // N-Administrators can not get the network configuration
1910    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1911    /// assert!(nethsm.get_network().is_err());
1912    /// # Ok(())
1913    /// # }
1914    /// ```
1915    /// [network configuration]: https://docs.nitrokey.com/nethsm/administration#network
1916    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1917    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1918    pub fn get_network(&self) -> Result<NetworkConfig, Error> {
1919        debug!(
1920            "Get network configuration for the NetHSM at {} using {}",
1921            self.url.borrow(),
1922            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1923        );
1924
1925        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1926        Ok(config_network_get(&self.create_connection_config())
1927            .map_err(|error| {
1928                Error::Api(format!(
1929                    "Getting network config failed: {}",
1930                    NetHsmApiError::from(error)
1931                ))
1932            })?
1933            .entity)
1934    }
1935
1936    /// Sets the [network configuration].
1937    ///
1938    /// Sets the [network configuration] of the NetHSM on the basis of a [`NetworkConfig`].
1939    ///
1940    /// This call requires using [`Credentials`] of a system-wide user in the
1941    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1942    ///
1943    /// # Errors
1944    ///
1945    /// Returns an [`Error::Api`] if setting the network configuration fails:
1946    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1947    /// * the provided `network_config` is not valid
1948    /// * the used [`Credentials`] are not correct
1949    /// * the used [`Credentials`] are not that of a system-wide user in the
1950    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1951    ///
1952    /// # Examples
1953    ///
1954    /// ```no_run
1955    /// use nethsm::{
1956    ///     Connection,
1957    ///     ConnectionSecurity,
1958    ///     Credentials,
1959    ///     NetHsm,
1960    ///     NetworkConfig,
1961    ///     Passphrase,
1962    ///     UserRole,
1963    /// };
1964    ///
1965    /// # fn main() -> testresult::TestResult {
1966    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1967    /// let nethsm = NetHsm::new(
1968    ///     Connection::new(
1969    ///         "https://example.org/api/v1".try_into()?,
1970    ///         ConnectionSecurity::Unsafe,
1971    ///     ),
1972    ///     Some(Credentials::new(
1973    ///         "admin".parse()?,
1974    ///         Some(Passphrase::new("passphrase".to_string())),
1975    ///     )),
1976    ///     None,
1977    ///     None,
1978    /// )?;
1979    /// // add a user in the Administrator role for a namespace (N-Administrator)
1980    /// nethsm.add_user(
1981    ///     "Namespace1 Admin".to_string(),
1982    ///     UserRole::Administrator,
1983    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1984    ///     Some("namespace1~admin1".parse()?),
1985    /// )?;
1986    /// // create accompanying namespace
1987    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1988    ///
1989    /// let network_config = NetworkConfig::new(
1990    ///     "192.168.1.1".to_string(),
1991    ///     "255.255.255.0".to_string(),
1992    ///     "0.0.0.0".to_string(),
1993    /// );
1994    ///
1995    /// // R-Administrators can set the network configuration
1996    /// nethsm.set_network(network_config.clone())?;
1997    ///
1998    /// // N-Administrators can not set the network configuration
1999    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2000    /// assert!(nethsm.set_network(network_config).is_err());
2001    /// # Ok(())
2002    /// # }
2003    /// ```
2004    /// [network configuration]: https://docs.nitrokey.com/nethsm/administration#network
2005    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2006    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2007    pub fn set_network(&self, network_config: NetworkConfig) -> Result<(), Error> {
2008        debug!(
2009            "Set a new network configuration (IP: {}, Netmask: {}, Gateway: {}) for the NetHSM at {} using {}",
2010            network_config.ip_address,
2011            network_config.netmask,
2012            network_config.gateway,
2013            self.url.borrow(),
2014            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2015        );
2016
2017        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2018        config_network_put(&self.create_connection_config(), network_config).map_err(|error| {
2019            Error::Api(format!(
2020                "Setting network config failed: {}",
2021                NetHsmApiError::from(error)
2022            ))
2023        })?;
2024        Ok(())
2025    }
2026
2027    /// Gets the current [time].
2028    ///
2029    /// This call requires using [`Credentials`] of a system-wide user in the
2030    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2031    ///
2032    /// # Errors
2033    ///
2034    /// Returns an [`Error::Api`] if retrieving [time] fails:
2035    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2036    /// * the used [`Credentials`] are not correct
2037    /// * the used [`Credentials`] are not that of a system-wide user in the
2038    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2039    ///
2040    /// # Examples
2041    ///
2042    /// ```no_run
2043    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2044    ///
2045    /// # fn main() -> testresult::TestResult {
2046    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2047    /// let nethsm = NetHsm::new(
2048    ///     Connection::new(
2049    ///         "https://example.org/api/v1".try_into()?,
2050    ///         ConnectionSecurity::Unsafe,
2051    ///     ),
2052    ///     Some(Credentials::new(
2053    ///         "admin".parse()?,
2054    ///         Some(Passphrase::new("passphrase".to_string())),
2055    ///     )),
2056    ///     None,
2057    ///     None,
2058    /// )?;
2059    /// // add a user in the Administrator role for a namespace (N-Administrator)
2060    /// nethsm.add_user(
2061    ///     "Namespace1 Admin".to_string(),
2062    ///     UserRole::Administrator,
2063    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2064    ///     Some("namespace1~admin1".parse()?),
2065    /// )?;
2066    /// // create accompanying namespace
2067    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2068    ///
2069    /// // R-Administrators can get the time
2070    /// println!("{:?}", nethsm.get_time()?);
2071    ///
2072    /// // N-Administrators can not get the time
2073    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2074    /// assert!(nethsm.get_time().is_err());
2075    /// # Ok(())
2076    /// # }
2077    /// ```
2078    /// [time]: https://docs.nitrokey.com/nethsm/administration#time
2079    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2080    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2081    pub fn get_time(&self) -> Result<String, Error> {
2082        debug!(
2083            "Retrieve the system time for the NetHSM at {} using {}",
2084            self.url.borrow(),
2085            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2086        );
2087
2088        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2089        Ok(config_time_get(&self.create_connection_config())
2090            .map_err(|error| {
2091                Error::Api(format!(
2092                    "Getting NetHSM system time failed: {}",
2093                    NetHsmApiError::from(error)
2094                ))
2095            })?
2096            .entity
2097            .time)
2098    }
2099
2100    /// Sets the current [time].
2101    ///
2102    /// This call requires using [`Credentials`] of a system-wide user in the
2103    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2104    ///
2105    /// # Errors
2106    ///
2107    /// Returns an [`Error::Api`] if setting [time] fails:
2108    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2109    /// * the provided `time` is not valid
2110    /// * the used [`Credentials`] are not correct
2111    /// * the used [`Credentials`] are not that of a system-wide user in the
2112    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2113    ///
2114    /// # Examples
2115    ///
2116    /// ```no_run
2117    /// use chrono::Utc;
2118    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2119    ///
2120    /// # fn main() -> testresult::TestResult {
2121    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2122    /// let nethsm = NetHsm::new(
2123    ///     Connection::new(
2124    ///         "https://example.org/api/v1".try_into()?,
2125    ///         ConnectionSecurity::Unsafe,
2126    ///     ),
2127    ///     Some(Credentials::new(
2128    ///         "admin".parse()?,
2129    ///         Some(Passphrase::new("passphrase".to_string())),
2130    ///     )),
2131    ///     None,
2132    ///     None,
2133    /// )?;
2134    /// // add a user in the Administrator role for a namespace (N-Administrator)
2135    /// nethsm.add_user(
2136    ///     "Namespace1 Admin".to_string(),
2137    ///     UserRole::Administrator,
2138    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2139    ///     Some("namespace1~admin1".parse()?),
2140    /// )?;
2141    /// // create accompanying namespace
2142    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2143    ///
2144    /// // R-Administrators can set the time
2145    /// nethsm.set_time(Utc::now())?;
2146    ///
2147    /// // N-Administrators can not set the time
2148    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2149    /// assert!(nethsm.set_time(Utc::now()).is_err());
2150    /// # Ok(())
2151    /// # }
2152    /// ```
2153    /// [time]: https://docs.nitrokey.com/nethsm/administration#time
2154    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2155    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2156    pub fn set_time(&self, time: DateTime<Utc>) -> Result<(), Error> {
2157        debug!(
2158            "Set the system time to {time} for the NetHSM at {} using {}",
2159            self.url.borrow(),
2160            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2161        );
2162
2163        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2164        config_time_put(
2165            &self.create_connection_config(),
2166            TimeConfig::new(time.to_rfc3339_opts(chrono::SecondsFormat::Secs, true)),
2167        )
2168        .map_err(|error| {
2169            Error::Api(format!(
2170                "Setting NetHSM system time failed: {}",
2171                NetHsmApiError::from(error)
2172            ))
2173        })?;
2174        Ok(())
2175    }
2176
2177    /// Gets the [logging configuration].
2178    ///
2179    /// This call requires using [`Credentials`] of a system-wide user in the
2180    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2181    ///
2182    /// # Errors
2183    ///
2184    /// Returns an [`Error::Api`] if getting the [logging configuration] fails:
2185    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2186    /// * the used [`Credentials`] are not correct
2187    /// * the used [`Credentials`] are not that of a system-wide user in the
2188    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2189    ///
2190    /// # Examples
2191    ///
2192    /// ```no_run
2193    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2194    ///
2195    /// # fn main() -> testresult::TestResult {
2196    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2197    /// let nethsm = NetHsm::new(
2198    ///     Connection::new(
2199    ///         "https://example.org/api/v1".try_into()?,
2200    ///         ConnectionSecurity::Unsafe,
2201    ///     ),
2202    ///     Some(Credentials::new(
2203    ///         "admin".parse()?,
2204    ///         Some(Passphrase::new("passphrase".to_string())),
2205    ///     )),
2206    ///     None,
2207    ///     None,
2208    /// )?;
2209    /// // add a user in the Administrator role for a namespace (N-Administrator)
2210    /// nethsm.add_user(
2211    ///     "Namespace1 Admin".to_string(),
2212    ///     UserRole::Administrator,
2213    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2214    ///     Some("namespace1~admin1".parse()?),
2215    /// )?;
2216    /// // create accompanying namespace
2217    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2218    ///
2219    /// // R-Administrators can get logging configuration
2220    /// println!("{:?}", nethsm.get_logging()?);
2221    ///
2222    /// // N-Administrators can not get logging configuration
2223    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2224    /// assert!(nethsm.get_logging().is_err());
2225    /// # Ok(())
2226    /// # }
2227    /// ```
2228    /// [logging configuration]: https://docs.nitrokey.com/nethsm/administration#logging
2229    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2230    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2231    pub fn get_logging(&self) -> Result<LoggingConfig, Error> {
2232        debug!(
2233            "Retrieve the logging information of the NetHSM at {} using {}",
2234            self.url.borrow(),
2235            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2236        );
2237
2238        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2239        Ok(config_logging_get(&self.create_connection_config())
2240            .map_err(|error| {
2241                Error::Api(format!(
2242                    "Getting logging config failed: {}",
2243                    NetHsmApiError::from(error)
2244                ))
2245            })?
2246            .entity)
2247    }
2248
2249    /// Sets the [logging configuration].
2250    ///
2251    /// Sets the NetHSM's [logging configuration] by providing `ip_address` and `port` of a host to
2252    /// send logs to. The log level is configured using `log_level`.
2253    ///
2254    /// This call requires using [`Credentials`] of a system-wide user in the
2255    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2256    ///
2257    /// # Errors
2258    ///
2259    /// Returns an [`Error::Api`] if setting the logging configuration fails:
2260    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2261    /// * the provided `ip_address`, `port` or `log_level` are not valid
2262    /// * the used [`Credentials`] are not correct
2263    /// * the used [`Credentials`] are not that of a system-wide user in the
2264    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2265    ///
2266    /// # Examples
2267    ///
2268    /// ```no_run
2269    /// use std::net::Ipv4Addr;
2270    ///
2271    /// use nethsm::{
2272    ///     Connection,
2273    ///     ConnectionSecurity,
2274    ///     Credentials,
2275    ///     LogLevel,
2276    ///     NetHsm,
2277    ///     Passphrase,
2278    ///     UserRole,
2279    /// };
2280    ///
2281    /// # fn main() -> testresult::TestResult {
2282    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2283    /// let nethsm = NetHsm::new(
2284    ///     Connection::new(
2285    ///         "https://example.org/api/v1".try_into()?,
2286    ///         ConnectionSecurity::Unsafe,
2287    ///     ),
2288    ///     Some(Credentials::new(
2289    ///         "admin".parse()?,
2290    ///         Some(Passphrase::new("passphrase".to_string())),
2291    ///     )),
2292    ///     None,
2293    ///     None,
2294    /// )?;
2295    /// // add a user in the Administrator role for a namespace (N-Administrator)
2296    /// nethsm.add_user(
2297    ///     "Namespace1 Admin".to_string(),
2298    ///     UserRole::Administrator,
2299    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2300    ///     Some("namespace1~admin1".parse()?),
2301    /// )?;
2302    /// // create accompanying namespace
2303    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2304    ///
2305    /// // R-Administrators can set logging configuration
2306    /// nethsm.set_logging(Ipv4Addr::new(192, 168, 1, 2), 513, LogLevel::Debug)?;
2307    ///
2308    /// // N-Administrators can not set logging configuration
2309    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2310    /// assert!(
2311    ///     nethsm
2312    ///         .set_logging(Ipv4Addr::new(192, 168, 1, 2), 513, LogLevel::Debug)
2313    ///         .is_err()
2314    /// );
2315    /// # Ok(())
2316    /// # }
2317    /// ```
2318    /// [logging configuration]: https://docs.nitrokey.com/nethsm/administration#logging
2319    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2320    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2321    pub fn set_logging(
2322        &self,
2323        ip_address: Ipv4Addr,
2324        port: u32,
2325        log_level: LogLevel,
2326    ) -> Result<(), Error> {
2327        debug!(
2328            "Set the logging configuration to {ip_address}:{port} ({log_level}) for the NetHSM at {} using {}",
2329            self.url.borrow(),
2330            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2331        );
2332
2333        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2334        let ip_address = ip_address.to_string();
2335        config_logging_put(
2336            &self.create_connection_config(),
2337            LoggingConfig::new(ip_address, port as i32, log_level.into()),
2338        )
2339        .map_err(|error| {
2340            Error::Api(format!(
2341                "Setting logging config failed: {}",
2342                NetHsmApiError::from(error)
2343            ))
2344        })?;
2345        Ok(())
2346    }
2347
2348    /// Sets the [backup] passphrase.
2349    ///
2350    /// Sets `current_passphrase` to `new_passphrase`, which changes the [backup] passphrase for the
2351    /// NetHSM.
2352    ///
2353    /// This call requires using [`Credentials`] of a system-wide user in the
2354    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2355    ///
2356    /// # Errors
2357    ///
2358    /// Returns an [`Error::Api`] if setting the backup passphrase fails:
2359    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2360    /// * the provided `current_passphrase` is not correct
2361    /// * the used [`Credentials`] are not correct
2362    /// * the used [`Credentials`] are not that of a system-wide user in the
2363    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2364    ///
2365    /// # Examples
2366    ///
2367    /// ```no_run
2368    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2369    ///
2370    /// # fn main() -> testresult::TestResult {
2371    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2372    /// let nethsm = NetHsm::new(
2373    ///     Connection::new(
2374    ///         "https://example.org/api/v1".try_into()?,
2375    ///         ConnectionSecurity::Unsafe,
2376    ///     ),
2377    ///     Some(Credentials::new(
2378    ///         "admin".parse()?,
2379    ///         Some(Passphrase::new("passphrase".to_string())),
2380    ///     )),
2381    ///     None,
2382    ///     None,
2383    /// )?;
2384    /// // add a user in the Administrator role for a namespace (N-Administrator)
2385    /// nethsm.add_user(
2386    ///     "Namespace1 Admin".to_string(),
2387    ///     UserRole::Administrator,
2388    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2389    ///     Some("namespace1~admin1".parse()?),
2390    /// )?;
2391    /// // create accompanying namespace
2392    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2393    ///
2394    /// // R-Administrators can set the backup passphrase
2395    /// nethsm.set_backup_passphrase(
2396    ///     Passphrase::new("current-backup-passphrase".to_string()),
2397    ///     Passphrase::new("new-backup-passphrase".to_string()),
2398    /// )?;
2399    ///
2400    /// // N-Administrators can not set logging configuration
2401    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2402    /// assert!(
2403    ///     nethsm
2404    ///         .set_backup_passphrase(
2405    ///             Passphrase::new("new-backup-passphrase".to_string()),
2406    ///             Passphrase::new("current-backup-passphrase".to_string()),
2407    ///         )
2408    ///         .is_err()
2409    /// );
2410    /// # Ok(())
2411    /// # }
2412    /// ```
2413    /// [backup]: https://docs.nitrokey.com/nethsm/administration#backup
2414    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2415    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2416    pub fn set_backup_passphrase(
2417        &self,
2418        current_passphrase: Passphrase,
2419        new_passphrase: Passphrase,
2420    ) -> Result<(), Error> {
2421        debug!(
2422            "Set the backup passphrase for the NetHSM at {} using {}",
2423            self.url.borrow(),
2424            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2425        );
2426
2427        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2428        config_backup_passphrase_put(
2429            &self.create_connection_config(),
2430            BackupPassphraseConfig::new(
2431                new_passphrase.expose_owned(),
2432                current_passphrase.expose_owned(),
2433            ),
2434        )
2435        .map_err(|error| {
2436            Error::Api(format!(
2437                "Setting backup passphrase failed: {}",
2438                NetHsmApiError::from(error),
2439            ))
2440        })?;
2441        Ok(())
2442    }
2443
2444    /// Creates a [backup].
2445    ///
2446    /// Triggers the creation and download of a [backup] of the NetHSM.
2447    /// **NOTE**: Before creating the first [backup], the [backup] passphrase must be set using
2448    /// [`set_backup_passphrase`][`NetHsm::set_backup_passphrase`].
2449    ///
2450    /// This call requires using [`Credentials`] of a user in the [`Backup`][`UserRole::Backup`]
2451    /// [role].
2452    ///
2453    /// # Errors
2454    ///
2455    /// Returns an [`Error::Api`] if creating a [backup] fails:
2456    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2457    /// * the used [`Credentials`] are not correct
2458    /// * the used [`Credentials`] are not that of a user in the [`Backup`][`UserRole::Backup`]
2459    ///   [role]
2460    /// * the [backup] passphrase has not yet been set
2461    ///
2462    /// # Examples
2463    ///
2464    /// ```no_run
2465    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
2466    ///
2467    /// # fn main() -> testresult::TestResult {
2468    /// // create a connection with a user in the Backup role
2469    /// let nethsm = NetHsm::new(
2470    ///     Connection::new(
2471    ///         "https://example.org/api/v1".try_into()?,
2472    ///         ConnectionSecurity::Unsafe,
2473    ///     ),
2474    ///     Some(Credentials::new(
2475    ///         "backup1".parse()?,
2476    ///         Some(Passphrase::new("passphrase".to_string())),
2477    ///     )),
2478    ///     None,
2479    ///     None,
2480    /// )?;
2481    ///
2482    /// // create a backup and write it to file
2483    /// std::fs::write("nethsm.bkp", nethsm.backup()?)?;
2484    /// # Ok(())
2485    /// # }
2486    /// ```
2487    /// [backup]: https://docs.nitrokey.com/nethsm/administration#backup
2488    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2489    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2490    pub fn backup(&self) -> Result<Vec<u8>, Error> {
2491        debug!(
2492            "Retrieve a backup of the NetHSM at {} using {}",
2493            self.url.borrow(),
2494            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2495        );
2496
2497        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2498        Ok(system_backup_post(&self.create_connection_config())
2499            .map_err(|error| {
2500                Error::Api(format!(
2501                    "Getting backup failed: {}",
2502                    NetHsmApiError::from(error)
2503                ))
2504            })?
2505            .entity)
2506    }
2507
2508    /// Triggers a [factory reset].
2509    ///
2510    /// Triggers a [factory reset] of the NetHSM.
2511    /// **WARNING**: This action deletes all user and system data! Make sure to create a [backup]
2512    /// using [`backup`][`NetHsm::backup`] first!
2513    ///
2514    /// This call requires using [`Credentials`] of a system-wide user in the
2515    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2516    ///
2517    /// # Errors
2518    ///
2519    /// Returns an [`Error::Api`] if resetting the NetHSM fails:
2520    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2521    /// * the used [`Credentials`] are not correct
2522    /// * the used [`Credentials`] are not that of a system-wide user in the
2523    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2524    ///
2525    /// # Examples
2526    ///
2527    /// ```no_run
2528    /// use nethsm::{
2529    ///     Connection,
2530    ///     ConnectionSecurity,
2531    ///     Credentials,
2532    ///     NetHsm,
2533    ///     Passphrase,
2534    ///     SystemState,
2535    ///     UserRole,
2536    /// };
2537    ///
2538    /// # fn main() -> testresult::TestResult {
2539    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2540    /// let nethsm = NetHsm::new(
2541    ///     Connection::new(
2542    ///         "https://example.org/api/v1".try_into()?,
2543    ///         ConnectionSecurity::Unsafe,
2544    ///     ),
2545    ///     Some(Credentials::new(
2546    ///         "admin".parse()?,
2547    ///         Some(Passphrase::new("passphrase".to_string())),
2548    ///     )),
2549    ///     None,
2550    ///     None,
2551    /// )?;
2552    /// // add a user in the Administrator role for a namespace (N-Administrator)
2553    /// nethsm.add_user(
2554    ///     "Namespace1 Admin".to_string(),
2555    ///     UserRole::Administrator,
2556    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2557    ///     Some("namespace1~admin1".parse()?),
2558    /// )?;
2559    /// // create accompanying namespace
2560    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2561    ///
2562    /// // N-Administrators can not trigger factory reset
2563    /// assert_eq!(nethsm.state()?, SystemState::Operational);
2564    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2565    /// assert!(nethsm.factory_reset().is_err());
2566    ///
2567    /// // R-Administrators are able to trigger a factory reset
2568    /// assert_eq!(nethsm.state()?, SystemState::Operational);
2569    /// nethsm.use_credentials(&"admin".parse()?)?;
2570    /// nethsm.factory_reset()?;
2571    /// assert_eq!(nethsm.state()?, SystemState::Unprovisioned);
2572    /// # Ok(())
2573    /// # }
2574    /// ```
2575    /// [factory reset]: https://docs.nitrokey.com/nethsm/administration#reset-to-factory-defaults
2576    /// [backup]: https://docs.nitrokey.com/nethsm/administration#backup
2577    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2578    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2579    pub fn factory_reset(&self) -> Result<(), Error> {
2580        debug!(
2581            "Trigger a factory reset of the NetHSM at {} using {}",
2582            self.url.borrow(),
2583            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2584        );
2585
2586        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2587        system_factory_reset_post(&self.create_connection_config()).map_err(|error| {
2588            Error::Api(format!(
2589                "Factory reset failed: {}",
2590                NetHsmApiError::from(error)
2591            ))
2592        })?;
2593        Ok(())
2594    }
2595
2596    /// Restores NetHSM from [backup].
2597    ///
2598    /// [Restores] a NetHSM from a [backup], by providing a `backup_passphrase` (see
2599    /// [`set_backup_passphrase`][`NetHsm::set_backup_passphrase`]) a new `system_time` for the
2600    /// NetHSM and a backup file (created using [`backup`][`NetHsm::backup`]).
2601    ///
2602    /// The NetHSM must be in [`Operational`][`SystemState::Operational`] or
2603    /// [`Unprovisioned`][`SystemState::Unprovisioned`] [state].
2604    ///
2605    /// Any existing user data is safely removed and replaced by that of the [backup], after which
2606    /// the NetHSM ends up in [`Locked`][`SystemState::Locked`] [state].
2607    /// If the NetHSM is in [`Unprovisioned`][`SystemState::Unprovisioned`] [state], additionally
2608    /// the system configuration from the backup is applied and leads to a
2609    /// [`reboot`][`NetHsm::reboot`] of the NetHSM.
2610    ///
2611    /// This call requires using [`Credentials`] of a system-wide user in the
2612    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2613    ///
2614    /// # Errors
2615    ///
2616    /// Returns an [`Error::Api`] if restoring the NetHSM from [backup] fails:
2617    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] or
2618    ///   [`Unprovisioned`][`SystemState::Unprovisioned`] [state]
2619    /// * the used [`Credentials`] are not correct
2620    /// * the used [`Credentials`] are not that of a system-wide user in the
2621    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2622    ///
2623    /// # Examples
2624    ///
2625    /// ```no_run
2626    /// use chrono::Utc;
2627    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2628    ///
2629    /// #
2630    /// # fn main() -> testresult::TestResult {
2631    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2632    /// let nethsm = NetHsm::new(
2633    ///     Connection::new(
2634    ///         "https://example.org/api/v1".try_into()?,
2635    ///         ConnectionSecurity::Unsafe,
2636    ///     ),
2637    ///     Some(Credentials::new(
2638    ///         "admin".parse()?,
2639    ///         Some(Passphrase::new("passphrase".to_string())),
2640    ///     )),
2641    ///     None,
2642    ///     None,
2643    /// )?;
2644    /// // add a user in the Administrator role for a namespace (N-Administrator)
2645    /// nethsm.add_user(
2646    ///     "Namespace1 Admin".to_string(),
2647    ///     UserRole::Administrator,
2648    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2649    ///     Some("namespace1~admin1".parse()?),
2650    /// )?;
2651    /// // create accompanying namespace
2652    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2653    ///
2654    /// // N-Administrators can not restore from backup
2655    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2656    /// assert!(
2657    ///     nethsm
2658    ///         .restore(
2659    ///             Passphrase::new("backup-passphrase".to_string()),
2660    ///             Utc::now(),
2661    ///             std::fs::read("nethsm.bkp")?,
2662    ///         )
2663    ///         .is_err()
2664    /// );
2665    ///
2666    /// // R-Administrators can restore from backup
2667    /// nethsm.use_credentials(&"admin".parse()?)?;
2668    /// nethsm.restore(
2669    ///     Passphrase::new("backup-passphrase".to_string()),
2670    ///     Utc::now(),
2671    ///     std::fs::read("nethsm.bkp")?,
2672    /// )?;
2673    /// # Ok(())
2674    /// # }
2675    /// ```
2676    /// [Restores]: https://docs.nitrokey.com/nethsm/administration#restore
2677    /// [backup]: https://docs.nitrokey.com/nethsm/administration#backup
2678    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2679    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2680    pub fn restore(
2681        &self,
2682        backup_passphrase: Passphrase,
2683        system_time: DateTime<Utc>,
2684        backup: Vec<u8>,
2685    ) -> Result<(), Error> {
2686        debug!(
2687            "Restore the NetHSM at {} from backup with the new system time {system_time} using {}",
2688            self.url.borrow(),
2689            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2690        );
2691
2692        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2693        system_restore_post(
2694            &self.create_connection_config(),
2695            Some(nethsm_sdk_rs::models::RestoreRequestArguments {
2696                backup_passphrase: Some(backup_passphrase.expose_owned()),
2697                system_time: Some(system_time.to_rfc3339_opts(chrono::SecondsFormat::Secs, true)),
2698            }),
2699            Some(backup),
2700        )
2701        .map_err(|error| {
2702            Error::Api(format!(
2703                "Restoring backup failed: {}",
2704                NetHsmApiError::from(error)
2705            ))
2706        })?;
2707        Ok(())
2708    }
2709
2710    /// Locks the NetHSM.
2711    ///
2712    /// Locks the NetHSM and sets its [state] to [`Locked`][`SystemState::Locked`].
2713    ///
2714    /// This call requires using [`Credentials`] of a system-wide user in the
2715    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2716    ///
2717    /// # Errors
2718    ///
2719    /// Returns an [`Error::Api`] if locking the NetHSM fails:
2720    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2721    /// * the used [`Credentials`] are not correct
2722    /// * the used [`Credentials`] are not that of a system-wide user in the
2723    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2724    ///
2725    /// # Examples
2726    ///
2727    /// ```no_run
2728    /// use nethsm::{
2729    ///     Connection,
2730    ///     ConnectionSecurity,
2731    ///     Credentials,
2732    ///     NetHsm,
2733    ///     Passphrase,
2734    ///     SystemState,
2735    ///     UserRole,
2736    /// };
2737    ///
2738    /// # fn main() -> testresult::TestResult {
2739    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2740    /// let nethsm = NetHsm::new(
2741    ///     Connection::new(
2742    ///         "https://example.org/api/v1".try_into()?,
2743    ///         ConnectionSecurity::Unsafe,
2744    ///     ),
2745    ///     Some(Credentials::new(
2746    ///         "admin".parse()?,
2747    ///         Some(Passphrase::new("passphrase".to_string())),
2748    ///     )),
2749    ///     None,
2750    ///     None,
2751    /// )?;
2752    /// // add a user in the Administrator role for a namespace (N-Administrator)
2753    /// nethsm.add_user(
2754    ///     "Namespace1 Admin".to_string(),
2755    ///     UserRole::Administrator,
2756    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2757    ///     Some("namespace1~admin1".parse()?),
2758    /// )?;
2759    /// // create accompanying namespace
2760    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2761    ///
2762    /// assert_eq!(nethsm.state()?, SystemState::Operational);
2763    ///
2764    /// // N-Administrators can not lock the NetHSM
2765    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2766    /// assert!(nethsm.lock().is_err());
2767    ///
2768    /// // R-Administrators can lock the NetHSM
2769    /// nethsm.use_credentials(&"admin".parse()?)?;
2770    /// nethsm.lock()?;
2771    /// assert_eq!(nethsm.state()?, SystemState::Locked);
2772    /// # Ok(())
2773    /// # }
2774    /// ```
2775    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2776    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2777    pub fn lock(&self) -> Result<(), Error> {
2778        debug!(
2779            "Lock the NetHSM at {} using {}",
2780            self.url.borrow(),
2781            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2782        );
2783
2784        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2785        lock_post(&self.create_connection_config()).map_err(|error| {
2786            Error::Api(format!(
2787                "Locking NetHSM failed: {}",
2788                NetHsmApiError::from(error)
2789            ))
2790        })?;
2791        Ok(())
2792    }
2793
2794    /// Unlocks the NetHSM.
2795    ///
2796    /// Unlocks the NetHSM if it is in [`Locked`][`SystemState::Locked`] [state] by providing
2797    /// `unlock_passphrase` and sets its [state] to [`Operational`][`SystemState::Operational`].
2798    ///
2799    /// For this call no [`Credentials`] are required and if any are configured, they are ignored.
2800    ///
2801    /// # Errors
2802    ///
2803    /// Returns an [`Error::Api`] if unlocking the NetHSM fails:
2804    /// * the NetHSM is not in [`Locked`][`SystemState::Locked`] [state]
2805    ///
2806    /// # Examples
2807    ///
2808    /// ```no_run
2809    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, SystemState};
2810    ///
2811    /// # fn main() -> testresult::TestResult {
2812    /// // no initial [`Credentials`] are required
2813    /// let nethsm = NetHsm::new(
2814    ///     Connection::new(
2815    ///         "https://example.org/api/v1".try_into()?,
2816    ///         ConnectionSecurity::Unsafe,
2817    ///     ),
2818    ///     None,
2819    ///     None,
2820    ///     None,
2821    /// )?;
2822    ///
2823    /// assert_eq!(nethsm.state()?, SystemState::Locked);
2824    /// // unlock the NetHSM
2825    /// nethsm.unlock(Passphrase::new("unlock-passphrase".to_string()))?;
2826    /// assert_eq!(nethsm.state()?, SystemState::Operational);
2827    /// # Ok(())
2828    /// # }
2829    /// ```
2830    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2831    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2832    pub fn unlock(&self, unlock_passphrase: Passphrase) -> Result<(), Error> {
2833        debug!(
2834            "Unlock the NetHSM at {} using {}",
2835            self.url.borrow(),
2836            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2837        );
2838
2839        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
2840        unlock_post(
2841            &self.create_connection_config(),
2842            UnlockRequestData::new(unlock_passphrase.expose_owned()),
2843        )
2844        .map_err(|error| {
2845            Error::Api(format!(
2846                "Unlocking NetHSM failed: {}",
2847                NetHsmApiError::from(error)
2848            ))
2849        })?;
2850        Ok(())
2851    }
2852
2853    /// Retrieves [system information].
2854    ///
2855    /// Returns [system information] in the form of a [`SystemInfo`], which contains various pieces
2856    /// of information such as software version, software build, firmware version, hardware
2857    /// version, device ID and information on TPM related components such as attestation key and
2858    /// relevant PCR values.
2859    ///
2860    /// This call requires using [`Credentials`] of a system-wide user in the
2861    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2862    ///
2863    /// # Errors
2864    ///
2865    /// Returns an [`Error::Api`] if retrieving the system information fails:
2866    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2867    /// * the used [`Credentials`] are not correct
2868    /// * the used [`Credentials`] are not that of a system-wide user in the
2869    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2870    ///
2871    /// # Examples
2872    ///
2873    /// ```no_run
2874    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2875    ///
2876    /// # fn main() -> testresult::TestResult {
2877    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2878    /// let nethsm = NetHsm::new(
2879    ///     Connection::new(
2880    ///         "https://example.org/api/v1".try_into()?,
2881    ///         ConnectionSecurity::Unsafe,
2882    ///     ),
2883    ///     Some(Credentials::new(
2884    ///         "admin".parse()?,
2885    ///         Some(Passphrase::new("passphrase".to_string())),
2886    ///     )),
2887    ///     None,
2888    ///     None,
2889    /// )?;
2890    /// // add a user in the Administrator role for a namespace (N-Administrator)
2891    /// nethsm.add_user(
2892    ///     "Namespace1 Admin".to_string(),
2893    ///     UserRole::Administrator,
2894    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2895    ///     Some("namespace1~admin1".parse()?),
2896    /// )?;
2897    /// // create accompanying namespace
2898    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2899    ///
2900    /// // R-Administrators can retrieve system information
2901    /// println!("{:?}", nethsm.system_info()?);
2902    ///
2903    /// // N-Administrators can not retrieve system information
2904    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2905    /// assert!(nethsm.system_info().is_err());
2906    /// # Ok(())
2907    /// # }
2908    /// ```
2909    /// [system information]: https://docs.nitrokey.com/nethsm/administration#system-information
2910    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2911    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2912    pub fn system_info(&self) -> Result<SystemInfo, Error> {
2913        debug!(
2914            "Retrieve system information about the NetHSM at {} using {}",
2915            self.url.borrow(),
2916            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2917        );
2918
2919        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2920        Ok(system_info_get(&self.create_connection_config())
2921            .map_err(|error| {
2922                Error::Api(format!(
2923                    "Retrieving system information failed: {}",
2924                    NetHsmApiError::from(error)
2925                ))
2926            })?
2927            .entity)
2928    }
2929
2930    /// [Reboots] the NetHSM.
2931    ///
2932    /// [Reboots] the NetHSM, if it is in [`Operational`][`SystemState::Operational`] [state].
2933    ///
2934    /// This call requires using [`Credentials`] of a system-wide user in the
2935    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2936    ///
2937    /// # Errors
2938    ///
2939    /// Returns an [`Error::Api`] if rebooting the NetHSM fails:
2940    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2941    /// * the used [`Credentials`] are not correct
2942    /// * the used [`Credentials`] are not that of a system-wide user in the
2943    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2944    ///
2945    /// # Examples
2946    ///
2947    /// ```no_run
2948    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2949    ///
2950    /// # fn main() -> testresult::TestResult {
2951    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2952    /// let nethsm = NetHsm::new(
2953    ///     Connection::new(
2954    ///         "https://example.org/api/v1".try_into()?,
2955    ///         ConnectionSecurity::Unsafe,
2956    ///     ),
2957    ///     Some(Credentials::new(
2958    ///         "admin".parse()?,
2959    ///         Some(Passphrase::new("passphrase".to_string())),
2960    ///     )),
2961    ///     None,
2962    ///     None,
2963    /// )?;
2964    /// // add a user in the Administrator role for a namespace (N-Administrator)
2965    /// nethsm.add_user(
2966    ///     "Namespace1 Admin".to_string(),
2967    ///     UserRole::Administrator,
2968    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2969    ///     Some("namespace1~admin1".parse()?),
2970    /// )?;
2971    /// // create accompanying namespace
2972    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2973    ///
2974    /// // N-Administrators can not reboot the NetHSM
2975    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2976    /// assert!(nethsm.reboot().is_err());
2977    ///
2978    /// // R-Administrators can reboot the NetHSM
2979    /// nethsm.use_credentials(&"admin".parse()?)?;
2980    /// nethsm.reboot()?;
2981    /// # Ok(())
2982    /// # }
2983    /// ```
2984    /// [Reboots]: https://docs.nitrokey.com/nethsm/administration#reboot-and-shutdown
2985    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2986    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2987    pub fn reboot(&self) -> Result<(), Error> {
2988        debug!(
2989            "Reboot the NetHSM at {} using {}",
2990            self.url.borrow(),
2991            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2992        );
2993
2994        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2995        system_reboot_post(&self.create_connection_config()).map_err(|error| {
2996            Error::Api(format!(
2997                "Rebooting NetHSM failed: {}",
2998                NetHsmApiError::from(error)
2999            ))
3000        })?;
3001        Ok(())
3002    }
3003
3004    /// [Shuts down] the NetHSM.
3005    ///
3006    /// [Shuts down] the NetHSM, if it is in [`Operational`][`SystemState::Operational`] [state].
3007    ///
3008    /// This call requires using [`Credentials`] of a system-wide user in the
3009    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
3010    ///
3011    /// # Errors
3012    ///
3013    /// Returns an [`Error::Api`] if shutting down the NetHSM fails:
3014    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
3015    /// * the used [`Credentials`] are not correct
3016    /// * the used [`Credentials`] are not that of a system-wide user in the
3017    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
3018    ///
3019    /// # Examples
3020    ///
3021    /// ```no_run
3022    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
3023    ///
3024    /// # fn main() -> testresult::TestResult {
3025    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
3026    /// let nethsm = NetHsm::new(
3027    ///     Connection::new(
3028    ///         "https://example.org/api/v1".try_into()?,
3029    ///         ConnectionSecurity::Unsafe,
3030    ///     ),
3031    ///     Some(Credentials::new(
3032    ///         "admin".parse()?,
3033    ///         Some(Passphrase::new("passphrase".to_string())),
3034    ///     )),
3035    ///     None,
3036    ///     None,
3037    /// )?;
3038    /// // add a user in the Administrator role for a namespace (N-Administrator)
3039    /// nethsm.add_user(
3040    ///     "Namespace1 Admin".to_string(),
3041    ///     UserRole::Administrator,
3042    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
3043    ///     Some("namespace1~admin1".parse()?),
3044    /// )?;
3045    /// // create accompanying namespace
3046    /// nethsm.add_namespace(&"namespace1".parse()?)?;
3047    ///
3048    /// // N-Administrators can not shut down the NetHSM
3049    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
3050    /// assert!(nethsm.shutdown().is_err());
3051    ///
3052    /// // R-Administrators can shut down the NetHSM
3053    /// nethsm.use_credentials(&"admin".parse()?)?;
3054    /// nethsm.shutdown()?;
3055    /// # Ok(())
3056    /// # }
3057    /// ```
3058    /// [Shuts down]: https://docs.nitrokey.com/nethsm/administration#reboot-and-shutdown
3059    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
3060    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
3061    pub fn shutdown(&self) -> Result<(), Error> {
3062        debug!(
3063            "Shut down the NetHSM at {} using {}",
3064            self.url.borrow(),
3065            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
3066        );
3067
3068        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
3069        system_shutdown_post(&self.create_connection_config()).map_err(|error| {
3070            Error::Api(format!(
3071                "Shutting down NetHSM failed: {}",
3072                NetHsmApiError::from(error)
3073            ))
3074        })?;
3075        Ok(())
3076    }
3077
3078    /// Uploads a software update.
3079    ///
3080    /// WARNING: This function has shown flaky behavior during tests with the official container!
3081    /// Upload may have to be repeated!
3082    ///
3083    /// Uploads a [software update] to the NetHSM, if it is in
3084    /// [`Operational`][`SystemState::Operational`] [state] and returns information about the
3085    /// software update as [`SystemUpdateData`].
3086    /// Software updates can successively be installed ([`commit_update`][`NetHsm::commit_update`])
3087    /// or canceled ([`cancel_update`][`NetHsm::cancel_update`]).
3088    ///
3089    /// This call requires using [`Credentials`] of a system-wide user in the
3090    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
3091    ///
3092    /// # Errors
3093    ///
3094    /// Returns an [`Error::Api`] if uploading the software update fails:
3095    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
3096    /// * the used [`Credentials`] are not correct
3097    /// * the used [`Credentials`] are not that of a system-wide user in the
3098    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
3099    ///
3100    /// # Examples
3101    ///
3102    /// ```no_run
3103    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
3104    ///
3105    /// # fn main() -> testresult::TestResult {
3106    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
3107    /// let nethsm = NetHsm::new(
3108    ///     Connection::new(
3109    ///         "https://example.org/api/v1".try_into()?,
3110    ///         ConnectionSecurity::Unsafe,
3111    ///     ),
3112    ///     Some(Credentials::new(
3113    ///         "admin".parse()?,
3114    ///         Some(Passphrase::new("passphrase".to_string())),
3115    ///     )),
3116    ///     None,
3117    ///     None,
3118    /// )?;
3119    /// // add a user in the Administrator role for a namespace (N-Administrator)
3120    /// nethsm.add_user(
3121    ///     "Namespace1 Admin".to_string(),
3122    ///     UserRole::Administrator,
3123    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
3124    ///     Some("namespace1~admin1".parse()?),
3125    /// )?;
3126    /// // create accompanying namespace
3127    /// nethsm.add_namespace(&"namespace1".parse()?)?;
3128    ///
3129    /// // N-Administrators can not upload software updates to the NetHSM
3130    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
3131    /// assert!(nethsm.upload_update(std::fs::read("update.bin")?).is_err());
3132    ///
3133    /// // R-Administrators can upload software updates to the NetHSM
3134    /// nethsm.use_credentials(&"admin".parse()?)?;
3135    /// println!("{:?}", nethsm.upload_update(std::fs::read("update.bin")?)?);
3136    /// # Ok(())
3137    /// # }
3138    /// ```
3139    /// [software update]: https://docs.nitrokey.com/nethsm/administration#software-update
3140    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
3141    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
3142    pub fn upload_update(&self, update: Vec<u8>) -> Result<SystemUpdateData, Error> {
3143        debug!(
3144            "Upload an update to the NetHSM at {} using {}",
3145            self.url.borrow(),
3146            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
3147        );
3148
3149        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
3150        Ok(system_update_post(&self.create_connection_config(), update)
3151            .map_err(|error| {
3152                println!("error during upload");
3153                Error::Api(format!(
3154                    "Uploading update failed: {}",
3155                    NetHsmApiError::from(error)
3156                ))
3157            })?
3158            .entity)
3159    }
3160
3161    /// Commits an already uploaded [software update].
3162    ///
3163    /// Commits a [software update] previously uploaded to the NetHSM (using
3164    /// [`upload_update`][`NetHsm::upload_update`]), if the NetHSM is in
3165    /// [`Operational`][`SystemState::Operational`] [state].
3166    /// Successfully committing a [software update] leads to the [reboot] of the NetHSM.
3167    ///
3168    /// This call requires using [`Credentials`] of a system-wide user in the
3169    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
3170    ///
3171    /// # Errors
3172    ///
3173    /// Returns an [`Error::Api`] if committing the software update fails:
3174    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
3175    /// * there is no software update to commit
3176    /// * the used [`Credentials`] are not correct
3177    /// * the used [`Credentials`] are not that of a system-wide user in the
3178    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
3179    ///
3180    /// # Examples
3181    ///
3182    /// ```no_run
3183    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
3184    ///
3185    /// # fn main() -> testresult::TestResult {
3186    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
3187    /// let nethsm = NetHsm::new(
3188    ///     Connection::new(
3189    ///         "https://example.org/api/v1".try_into()?,
3190    ///         ConnectionSecurity::Unsafe,
3191    ///     ),
3192    ///     Some(Credentials::new(
3193    ///         "admin".parse()?,
3194    ///         Some(Passphrase::new("passphrase".to_string())),
3195    ///     )),
3196    ///     None,
3197    ///     None,
3198    /// )?;
3199    /// // add a user in the Administrator role for a namespace (N-Administrator)
3200    /// nethsm.add_user(
3201    ///     "Namespace1 Admin".to_string(),
3202    ///     UserRole::Administrator,
3203    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
3204    ///     Some("namespace1~admin1".parse()?),
3205    /// )?;
3206    /// // create accompanying namespace
3207    /// nethsm.add_namespace(&"namespace1".parse()?)?;
3208    ///
3209    /// println!("{:?}", nethsm.upload_update(std::fs::read("update.bin")?)?);
3210    ///
3211    /// // N-Administrators can not commit software updates on a NetHSM
3212    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
3213    /// assert!(nethsm.commit_update().is_err());
3214    ///
3215    /// // R-Administrators can commit software updates on a NetHSM
3216    /// nethsm.use_credentials(&"admin".parse()?)?;
3217    /// nethsm.commit_update()?;
3218    /// # Ok(())
3219    /// # }
3220    /// ```
3221    /// [software update]: https://docs.nitrokey.com/nethsm/administration#software-update
3222    /// [reboot]: https://docs.nitrokey.com/nethsm/administration#reboot-and-shutdown
3223    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
3224    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
3225    pub fn commit_update(&self) -> Result<(), Error> {
3226        debug!(
3227            "Commit an already uploaded update on the NetHSM at {} using {}",
3228            self.url.borrow(),
3229            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
3230        );
3231
3232        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
3233        system_commit_update_post(&self.create_connection_config()).map_err(|error| {
3234            Error::Api(format!(
3235                "Committing update failed: {}",
3236                NetHsmApiError::from(error)
3237            ))
3238        })?;
3239        Ok(())
3240    }
3241
3242    /// Cancels an already uploaded [software update].
3243    ///
3244    /// Cancels a [software update] previously uploaded to the NetHSM (using
3245    /// [`upload_update`][`NetHsm::upload_update`]), if the NetHSM is in
3246    /// [`Operational`][`SystemState::Operational`] [state].
3247    ///
3248    /// This call requires using [`Credentials`] of a system-wide user in the
3249    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
3250    ///
3251    /// # Errors
3252    ///
3253    /// Returns an [`Error::Api`] if canceling the software update fails:
3254    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
3255    /// * there is no software update to cancel
3256    /// * the used [`Credentials`] are not correct
3257    /// * the used [`Credentials`] are not that of a system-wide user in the
3258    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
3259    ///
3260    /// # Examples
3261    ///
3262    /// ```no_run
3263    /// use nethsm::{
3264    ///     Connection,
3265    ///     ConnectionSecurity,
3266    ///     Credentials,
3267    ///     NetHsm,
3268    ///     Passphrase,
3269    ///     SystemState,
3270    ///     UserRole,
3271    /// };
3272    ///
3273    /// # fn main() -> testresult::TestResult {
3274    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
3275    /// let nethsm = NetHsm::new(
3276    ///     Connection::new(
3277    ///         "https://example.org/api/v1".try_into()?,
3278    ///         ConnectionSecurity::Unsafe,
3279    ///     ),
3280    ///     Some(Credentials::new(
3281    ///         "admin".parse()?,
3282    ///         Some(Passphrase::new("passphrase".to_string())),
3283    ///     )),
3284    ///     None,
3285    ///     None,
3286    /// )?;
3287    /// // add a user in the Administrator role for a namespace (N-Administrator)
3288    /// nethsm.add_user(
3289    ///     "Namespace1 Admin".to_string(),
3290    ///     UserRole::Administrator,
3291    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
3292    ///     Some("namespace1~admin1".parse()?),
3293    /// )?;
3294    /// // create accompanying namespace
3295    /// nethsm.add_namespace(&"namespace1".parse()?)?;
3296    ///
3297    /// println!("{:?}", nethsm.upload_update(std::fs::read("update.bin")?)?);
3298    /// assert_eq!(nethsm.state()?, SystemState::Operational);
3299    ///
3300    /// // N-Administrators can not cancel software updates on a NetHSM
3301    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
3302    /// assert!(nethsm.cancel_update().is_err());
3303    ///
3304    /// // R-Administrators can cancel software updates on a NetHSM
3305    /// nethsm.cancel_update()?;
3306    /// assert_eq!(nethsm.state()?, SystemState::Operational);
3307    /// # Ok(())
3308    /// # }
3309    /// ```
3310    /// [software update]: https://docs.nitrokey.com/nethsm/administration#software-update
3311    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
3312    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
3313    pub fn cancel_update(&self) -> Result<(), Error> {
3314        debug!(
3315            "Cancel an already uploaded update on the NetHSM at {} using {}",
3316            self.url.borrow(),
3317            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
3318        );
3319
3320        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
3321        system_cancel_update_post(&self.create_connection_config()).map_err(|error| {
3322            Error::Api(format!(
3323                "Cancelling update failed: {}",
3324                NetHsmApiError::from(error)
3325            ))
3326        })?;
3327        Ok(())
3328    }
3329
3330    /// Adds a new namespace.
3331    ///
3332    /// Adds a new [namespace] with the ID `namespace_id`.
3333    ///
3334    /// **WARNING**: A user in the [`Administrator`][`UserRole::Administrator`] [role] must be added
3335    /// for the [namespace] using [`add_user`][`NetHsm::add_user`] **before** creating the
3336    /// [namespace]! Otherwise there is no user to administrate the new [namespace]!
3337    ///
3338    /// This call requires using [`Credentials`] of a system-wide user in the
3339    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
3340    ///
3341    /// # Errors
3342    ///
3343    /// Returns an [`Error::Api`] if adding the namespace fails:
3344    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
3345    /// * the namespace identified by `namespace_id` exists already
3346    /// * the used [`Credentials`] are not correct
3347    /// * the used [`Credentials`] are not that of a system-wide user in the
3348    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
3349    ///
3350    /// # Examples
3351    ///
3352    /// ```no_run
3353    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
3354    ///
3355    /// # fn main() -> testresult::TestResult {
3356    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
3357    /// let nethsm = NetHsm::new(
3358    ///     Connection::new(
3359    ///         "https://example.org/api/v1".try_into()?,
3360    ///         ConnectionSecurity::Unsafe,
3361    ///     ),
3362    ///     Some(Credentials::new(
3363    ///         "admin".parse()?,
3364    ///         Some(Passphrase::new("passphrase".to_string())),
3365    ///     )),
3366    ///     None,
3367    ///     None,
3368    /// )?;
3369    ///
3370    /// // add a user in the Administrator role for a namespace (N-Administrator)
3371    /// nethsm.add_user(
3372    ///     "Namespace1 Admin".to_string(),
3373    ///     UserRole::Administrator,
3374    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
3375    ///     Some("namespace1~admin1".parse()?),
3376    /// )?;
3377    /// // create accompanying namespace
3378    /// nethsm.add_namespace(&"namespace1".parse()?)?;
3379    ///
3380    /// // N-Administrator can not create namespaces
3381    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
3382    /// assert!(nethsm.add_namespace(&"namespace2".parse()?).is_err());
3383    /// # Ok(())
3384    /// # }
3385    /// ```
3386    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
3387    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
3388    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
3389    pub fn add_namespace(&self, namespace_id: &NamespaceId) -> Result<(), Error> {
3390        debug!(
3391            "Add the namespace {namespace_id} on the NetHSM at {} using {}",
3392            self.url.borrow(),
3393            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
3394        );
3395
3396        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
3397        namespaces_namespace_id_put(&self.create_connection_config(), namespace_id.as_ref())
3398            .map_err(|error| {
3399                Error::Api(format!(
3400                    "Adding namespace failed: {}",
3401                    NetHsmApiError::from(error)
3402                ))
3403            })?;
3404        Ok(())
3405    }
3406
3407    /// Gets all available [namespaces].
3408    ///
3409    /// This call requires using [`Credentials`] of a system-wide user in the
3410    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
3411    ///
3412    /// # Errors
3413    ///
3414    /// Returns an [`Error::Api`] if getting the namespaces fails:
3415    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
3416    /// * the used [`Credentials`] are not correct
3417    /// * the used [`Credentials`] are not that of a system-wide user in the
3418    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
3419    ///
3420    /// # Examples
3421    ///
3422    /// ```no_run
3423    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
3424    ///
3425    /// # fn main() -> testresult::TestResult {
3426    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
3427    /// let nethsm = NetHsm::new(
3428    ///     Connection::new(
3429    ///         "https://example.org/api/v1".try_into()?,
3430    ///         ConnectionSecurity::Unsafe,
3431    ///     ),
3432    ///     Some(Credentials::new(
3433    ///         "admin".parse()?,
3434    ///         Some(Passphrase::new("passphrase".to_string())),
3435    ///     )),
3436    ///     None,
3437    ///     None,
3438    /// )?;
3439    ///
3440    /// // print list of all namespaces
3441    /// println!("{:?}", nethsm.get_namespaces()?);
3442    ///
3443    /// // add a user in the Administrator role for a namespace (N-Administrator)
3444    /// nethsm.add_user(
3445    ///     "Namespace1 Admin".to_string(),
3446    ///     UserRole::Administrator,
3447    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
3448    ///     Some("namespace1~admin1".parse()?),
3449    /// )?;
3450    /// // create accompanying namespace
3451    /// nethsm.add_namespace(&"namespace1".parse()?)?;
3452    ///
3453    /// // N-Administrator can not get namespaces
3454    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
3455    /// assert!(nethsm.get_namespaces().is_err());
3456    /// # Ok(())
3457    /// # }
3458    /// ```
3459    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
3460    /// [namespaces]: https://docs.nitrokey.com/nethsm/administration#namespaces
3461    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
3462    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
3463    pub fn get_namespaces(&self) -> Result<Vec<NamespaceId>, Error> {
3464        debug!(
3465            "Retrieve all available namespaces from the NetHSM at {} using {}",
3466            self.url.borrow(),
3467            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
3468        );
3469
3470        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
3471        let valid_namespaces = {
3472            let mut invalid_namespaces = Vec::new();
3473            let valid_namespaces = namespaces_get(&self.create_connection_config())
3474                .map_err(|error| {
3475                    Error::Api(format!(
3476                        "Getting namespaces failed: {}",
3477                        NetHsmApiError::from(error)
3478                    ))
3479                })?
3480                .entity
3481                .into_iter()
3482                .filter_map(|x| {
3483                    if let Ok(namespace) = NamespaceId::new(x.id.clone()) {
3484                        Some(namespace)
3485                    } else {
3486                        invalid_namespaces.push(x.id);
3487                        None
3488                    }
3489                })
3490                .collect::<Vec<NamespaceId>>();
3491
3492            if !invalid_namespaces.is_empty() {
3493                return Err(UserError::InvalidNamespaceIds {
3494                    namespace_ids: invalid_namespaces,
3495                }
3496                .into());
3497            }
3498            valid_namespaces
3499        };
3500
3501        Ok(valid_namespaces)
3502    }
3503
3504    /// Deletes an existing [namespace].
3505    ///
3506    /// Deletes the [namespace] identified by `namespace_id`.
3507    ///
3508    /// **WARNING**: This call deletes the [namespace] and all keys in it! Make sure to create a
3509    /// [`backup`][`NetHsm::backup`]!
3510    ///
3511    /// This call requires using [`Credentials`] of a system-wide user in the
3512    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
3513    ///
3514    /// # Errors
3515    ///
3516    /// Returns an [`Error::Api`] if deleting the namespace fails:
3517    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
3518    /// * the [namespace] identified by `namespace_id` does not exist
3519    /// * the used [`Credentials`] are not correct
3520    /// * the used [`Credentials`] are not that of a system-wide user in the
3521    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
3522    ///
3523    /// # Examples
3524    ///
3525    /// ```no_run
3526    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
3527    ///
3528    /// # fn main() -> testresult::TestResult {
3529    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
3530    /// let nethsm = NetHsm::new(
3531    ///     Connection::new(
3532    ///         "https://example.org/api/v1".try_into()?,
3533    ///         ConnectionSecurity::Unsafe,
3534    ///     ),
3535    ///     Some(Credentials::new(
3536    ///         "admin".parse()?,
3537    ///         Some(Passphrase::new("passphrase".to_string())),
3538    ///     )),
3539    ///     None,
3540    ///     None,
3541    /// )?;
3542    /// // add a user in the Administrator role for a namespace (N-Administrator)
3543    /// nethsm.add_user(
3544    ///     "Namespace1 Admin".to_string(),
3545    ///     UserRole::Administrator,
3546    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
3547    ///     Some("namespace1~admin1".parse()?),
3548    /// )?;
3549    /// // create accompanying namespace
3550    /// nethsm.add_namespace(&"namespace1".parse()?)?;
3551    ///
3552    /// // N-Administrators can not delete namespaces
3553    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
3554    /// assert!(nethsm.delete_namespace(&"namespace1".parse()?).is_err());
3555    ///
3556    /// // R-Administrators can delete namespaces
3557    /// nethsm.use_credentials(&"admin".parse()?)?;
3558    /// nethsm.delete_namespace(&"namespace1".parse()?)?;
3559    /// # Ok(())
3560    /// # }
3561    /// ```
3562    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
3563    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
3564    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
3565    pub fn delete_namespace(&self, namespace_id: &NamespaceId) -> Result<(), Error> {
3566        debug!(
3567            "Delete the namespace {namespace_id} from the NetHSM at {} using {}",
3568            self.url.borrow(),
3569            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
3570        );
3571
3572        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
3573        namespaces_namespace_id_delete(&self.create_connection_config(), namespace_id.as_ref())
3574            .map_err(|error| {
3575                Error::Api(format!(
3576                    "Deleting namespace failed: {}",
3577                    NetHsmApiError::from(error)
3578                ))
3579            })?;
3580        Ok(())
3581    }
3582
3583    /// [Adds a user] and returns its User ID.
3584    ///
3585    /// A new user is created by providing a `real_name` from which a User ID is derived (optionally
3586    /// a User ID can be provided with `user_id`), a `role` which describes the user's access rights
3587    /// on the NetHSM (see [`UserRole`]) and a `passphrase`.
3588    ///
3589    /// Internally, this function also calls [`add_credentials`][`NetHsm::add_credentials`] to
3590    /// add the new user to the list of available credentials.
3591    ///
3592    /// This call requires using [`Credentials`] of a user in the
3593    /// [`Administrator`][`UserRole::Administrator`] [role].
3594    /// When adding a user to a [namespace], that does not yet exist, the caller must
3595    /// be a system-wide [`Administrator`][`UserRole::Administrator`] (*R-Administrator*).
3596    /// When adding a user to an already existing [namespace], the caller must be an
3597    /// [`Administrator`][`UserRole::Administrator`] in that [namespace]
3598    /// (*N-Administrator*).
3599    ///
3600    /// ## Namespaces
3601    ///
3602    /// New users *implicitly* inherit the [namespace] of the caller.
3603    /// A [namespace] can be provided *explicitly* by prefixing the User ID with the ID of a
3604    /// [namespace] and the `~` character (e.g. `namespace1~user1`).
3605    /// When specifying a namespace as part of the User ID and the [namespace] exists already, the
3606    /// caller must be an [`Administrator`][`UserRole::Administrator`] of that [namespace]
3607    /// (*N-Administrator*).
3608    /// When specifying a [namespace] as part of the User ID and the [namespace] does not yet exist,
3609    /// the caller must be a system-wide [`Administrator`][`UserRole::Administrator`]
3610    /// (*R-Administrator*).
3611    ///
3612    /// **NOTE**: Users in the [`Backup`][`UserRole::Backup`] and [`Metrics`][`UserRole::Metrics`]
3613    /// [role] can not be created for a [namespace], as their underlying functionality can only be
3614    /// used in a system-wide context!
3615    ///
3616    /// # Errors
3617    ///
3618    /// Returns an [`Error::Api`] if adding the user fails:
3619    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
3620    /// * the provided `real_name`, `passphrase` or `user_id` are not valid
3621    /// * the provided `user_id` exists already
3622    /// * the used [`Credentials`] are not correct
3623    /// * the used [`Credentials`] are not that of a system-wide
3624    ///   [`Administrator`][`UserRole::Administrator`], when adding a user to a not yet existing
3625    ///   [namespace]
3626    /// * the used [`Credentials`] are not that of an [`Administrator`][`UserRole::Administrator`]
3627    ///   in the [namespace] the user is about to be added to
3628    ///
3629    /// # Examples
3630    ///
3631    /// ```no_run
3632    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
3633    ///
3634    /// # fn main() -> testresult::TestResult {
3635    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
3636    /// let nethsm = NetHsm::new(
3637    ///     Connection::new(
3638    ///         "https://example.org/api/v1".try_into()?,
3639    ///         ConnectionSecurity::Unsafe,
3640    ///     ),
3641    ///     Some(Credentials::new(
3642    ///         "admin".parse()?,
3643    ///         Some(Passphrase::new("passphrase".to_string())),
3644    ///     )),
3645    ///     None,
3646    ///     None,
3647    /// )?;
3648    ///
3649    /// // add a system-wide user in the Operator role
3650    /// nethsm.add_user(
3651    ///     "Operator One".to_string(),
3652    ///     UserRole::Operator,
3653    ///     Passphrase::new("operator1-passphrase".to_string()),
3654    ///     Some("user1".parse()?),
3655    /// )?;
3656    ///
3657    /// // this fails because the user exists already
3658    /// assert!(nethsm
3659    ///     .add_user(
3660    ///         "Operator One".to_string(),
3661    ///         UserRole::Operator,
3662    ///         Passphrase::new("operator1-passphrase".to_string()),
3663    ///         Some("user1".parse()?),
3664    ///     )
3665    ///     .is_err());
3666    ///
3667    /// // add a user in the Administrator role (N-Administrator) for a not yet existing namespace "namespace1"
3668    /// nethsm.add_user(
3669    ///     "Namespace1 Admin".to_string(),
3670    ///     UserRole::Administrator,
3671    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
3672    ///     Some("namespace1~admin1".parse()?),
3673    /// )?;
3674    ///
3675    /// # Ok(())
3676    /// # }
3677    /// ```
3678    /// [Adds a user]: https://docs.nitrokey.com/nethsm/administration#add-user
3679    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
3680    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
3681    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
3682    pub fn add_user(
3683        &self,
3684        real_name: String,
3685        role: UserRole,
3686        passphrase: Passphrase,
3687        user_id: Option<UserId>,
3688    ) -> Result<UserId, Error> {
3689        debug!(
3690            "Add the user \"{real_name}\"{} in the role {role} to the NetHSM at {} using {}",
3691            if let Some(user_id) = user_id.as_ref() {
3692                format!(" (\"{user_id}\")")
3693            } else {
3694                "".to_string()
3695            },
3696            self.url.borrow(),
3697            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
3698        );
3699
3700        self.validate_namespace_access(NamespaceSupport::Supported, user_id.as_ref(), Some(&role))?;
3701        let user_id = if let Some(user_id) = user_id {
3702            users_user_id_put(
3703                &self.create_connection_config(),
3704                &user_id.to_string(),
3705                UserPostData::new(real_name, role.into(), passphrase.expose_owned()),
3706            )
3707            .map_err(|error| {
3708                Error::Api(format!(
3709                    "Adding user failed: {}",
3710                    NetHsmApiError::from(error)
3711                ))
3712            })?;
3713            user_id
3714        } else {
3715            UserId::new(
3716                users_post(
3717                    &self.create_connection_config(),
3718                    UserPostData::new(real_name, role.into(), passphrase.expose_owned()),
3719                )
3720                .map_err(|error| {
3721                    Error::Api(format!(
3722                        "Adding user failed: {}",
3723                        NetHsmApiError::from(error)
3724                    ))
3725                })?
3726                .entity
3727                .id,
3728            )?
3729        };
3730
3731        // add to list of users
3732        self.add_credentials(Credentials::new(user_id.clone(), Some(passphrase)));
3733
3734        Ok(user_id)
3735    }
3736
3737    /// Deletes an existing user.
3738    ///
3739    /// [Deletes a user] identified by `user_id`.
3740    ///
3741    /// Internally, this function also calls [`remove_credentials`][`NetHsm::remove_credentials`] to
3742    /// remove the user from the list of available credentials.
3743    ///
3744    /// This call requires using [`Credentials`] of a user in the
3745    /// [`Administrator`][`UserRole::Administrator`] [role].
3746    ///
3747    /// ## Namespaces
3748    ///
3749    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
3750    ///   [namespace]) can only delete users in their own [namespace].
3751    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) can
3752    ///   only delete system-wide users, but not those in a [namespace]. To allow *R-Administrators*
3753    ///   to delete users in a [namespace], the given [namespace] has to be deleted first using
3754    ///   [`delete_namespace`][`NetHsm::delete_namespace`].
3755    ///
3756    /// # Errors
3757    ///
3758    /// Returns an [`Error::Api`] if deleting a user fails:
3759    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
3760    /// * the user identified by `user_id` does not exist
3761    /// * the used [`Credentials`] are not correct
3762    /// * the used [`Credentials`] are not that of a user in the
3763    ///   [`Administrator`][`UserRole::Administrator`] role
3764    /// * the targeted user is in an existing [namespace], but the caller is an *R-Administrator* or
3765    ///   an *N-Administrator* in a different [namespace]
3766    /// * the targeted user is a system-wide user, but the caller is not an *R-Administrator*
3767    /// * the user attempts to delete itself
3768    ///
3769    /// # Examples
3770    ///
3771    /// ```no_run
3772    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
3773    ///
3774    /// # fn main() -> testresult::TestResult {
3775    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
3776    /// let nethsm = NetHsm::new(
3777    ///     Connection::new(
3778    ///         "https://example.org/api/v1".try_into()?,
3779    ///         ConnectionSecurity::Unsafe,
3780    ///     ),
3781    ///     Some(Credentials::new(
3782    ///         "admin".parse()?,
3783    ///         Some(Passphrase::new("passphrase".to_string())),
3784    ///     )),
3785    ///     None,
3786    ///     None,
3787    /// )?;
3788    ///
3789    /// // add a system-wide user in the Operator role
3790    /// nethsm.add_user(
3791    ///     "Operator One".to_string(),
3792    ///     UserRole::Operator,
3793    ///     Passphrase::new("operator1-passphrase".to_string()),
3794    ///     Some("user1".parse()?),
3795    /// )?;
3796    ///
3797    /// // add a user in the Administrator role for a namespace (N-Administrator)
3798    /// nethsm.add_user(
3799    ///     "Namespace1 Admin".to_string(),
3800    ///     UserRole::Administrator,
3801    ///     Passphrase::new("namespce1-admin-passphrase".to_string()),
3802    ///     Some("namespace1~admin1".parse()?),
3803    /// )?;
3804    /// // add the accompanying namespace
3805    /// nethsm.add_namespace(&"namespace1".parse()?)?;
3806    ///
3807    /// // R-Administrators can not delete N-Administrators, as long as their namespace exists
3808    /// assert!(nethsm.delete_user(&"namespace1~admin1".parse()?).is_err());
3809    /// // however, after deleting the namespace, this becomes possible
3810    /// nethsm.delete_namespace(&"namespace1".parse()?)?;
3811    /// nethsm.delete_user(&"namespace1~admin1".parse()?)?;
3812    ///
3813    /// // R-Administrators can delete system-wide users
3814    /// nethsm.delete_user(&"user1".parse()?)?;
3815    /// # Ok(())
3816    /// # }
3817    /// ```
3818    /// [Deletes a user]: https://docs.nitrokey.com/nethsm/administration#delete-user
3819    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
3820    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
3821    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
3822    pub fn delete_user(&self, user_id: &UserId) -> Result<(), Error> {
3823        debug!(
3824            "Delete the user \"{user_id}\" from the NetHSM at {} using {}",
3825            self.url.borrow(),
3826            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
3827        );
3828
3829        self.validate_namespace_access(NamespaceSupport::Supported, Some(user_id), None)?;
3830        users_user_id_delete(&self.create_connection_config(), &user_id.to_string()).map_err(
3831            |error| {
3832                Error::Api(format!(
3833                    "Deleting user failed: {}",
3834                    NetHsmApiError::from(error)
3835                ))
3836            },
3837        )?;
3838
3839        // remove from list of credentials
3840        self.remove_credentials(user_id);
3841
3842        Ok(())
3843    }
3844
3845    /// Gets a [list of all User IDs].
3846    ///
3847    /// This call requires using [`Credentials`] of a user in the
3848    /// [`Administrator`][`UserRole::Administrator`] [role].
3849    ///
3850    /// ## Namespaces
3851    ///
3852    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
3853    ///   [namespace]) can only list users in their own [namespace].
3854    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) can
3855    ///   list all users on the system.
3856    ///
3857    /// # Errors
3858    ///
3859    /// Returns an [`Error::Api`] if retrieving the list of all User IDs fails:
3860    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
3861    /// * the used [`Credentials`] are not correct
3862    /// * the used [`Credentials`] are not that of a user in the
3863    ///   [`Administrator`][`UserRole::Administrator`] role
3864    ///
3865    /// # Examples
3866    ///
3867    /// ```no_run
3868    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
3869    ///
3870    /// # fn main() -> testresult::TestResult {
3871    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
3872    /// let nethsm = NetHsm::new(
3873    ///     Connection::new(
3874    ///         "https://example.org/api/v1".try_into()?,
3875    ///         ConnectionSecurity::Unsafe,
3876    ///     ),
3877    ///     Some(Credentials::new(
3878    ///         "admin".parse()?,
3879    ///         Some(Passphrase::new("passphrase".to_string())),
3880    ///     )),
3881    ///     None,
3882    ///     None,
3883    /// )?;
3884    ///
3885    /// // add a user in the Administrator role for a namespace (N-Administrator)
3886    /// nethsm.add_user(
3887    ///     "Namespace1 Admin".to_string(),
3888    ///     UserRole::Administrator,
3889    ///     Passphrase::new("namespce1-admin-passphrase".to_string()),
3890    ///     Some("namespace1~admin1".parse()?),
3891    /// )?;
3892    /// // add the accompanying namespace
3893    /// nethsm.add_namespace(&"namespace1".parse()?)?;
3894    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
3895    /// // the N-Administrator only sees itself
3896    /// assert_eq!(nethsm.get_users()?.len(), 1);
3897    ///
3898    /// // use the credentials of the R-Administrator
3899    /// nethsm.use_credentials(&"admin".parse()?)?;
3900    /// // the R-Administrator sees at least itself and the previously created N-Administrator
3901    /// assert!(nethsm.get_users()?.len() >= 2);
3902    /// # Ok(())
3903    /// # }
3904    /// ```
3905    /// [list of all User IDs]: https://docs.nitrokey.com/nethsm/administration#list-users
3906    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
3907    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
3908    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
3909    pub fn get_users(&self) -> Result<Vec<UserId>, Error> {
3910        debug!(
3911            "Get the users of the NetHSM at {} using {}",
3912            self.url.borrow(),
3913            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
3914        );
3915
3916        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
3917        let valid_users = {
3918            let mut invalid_users = Vec::new();
3919            let valid_users = users_get(&self.create_connection_config())
3920                .map_err(|error| {
3921                    Error::Api(format!(
3922                        "Getting users failed: {}",
3923                        NetHsmApiError::from(error)
3924                    ))
3925                })?
3926                .entity
3927                .into_iter()
3928                .filter_map(|x| {
3929                    if let Ok(user) = UserId::new(x.user.clone()) {
3930                        Some(user)
3931                    } else {
3932                        invalid_users.push(x.user);
3933                        None
3934                    }
3935                })
3936                .collect::<Vec<UserId>>();
3937
3938            if !invalid_users.is_empty() {
3939                return Err(UserError::InvalidUserIds {
3940                    user_ids: invalid_users,
3941                }
3942                .into());
3943            }
3944
3945            valid_users
3946        };
3947
3948        Ok(valid_users)
3949    }
3950
3951    /// Gets [information of a user].
3952    ///
3953    /// This call requires using [`Credentials`] of a user in the
3954    /// [`Administrator`][`UserRole::Administrator`] [role].
3955    ///
3956    /// ## Namespaces
3957    ///
3958    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
3959    ///   [namespace]) can only access information about users in their own [namespace].
3960    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) can
3961    ///   access information about all users on the system.
3962    ///
3963    /// # Errors
3964    ///
3965    /// Returns an [`Error::Api`] if retrieving information of the user fails:
3966    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
3967    /// * the user identified by `user_id` does not exist
3968    /// * the used [`Credentials`] are not correct
3969    /// * the used [`Credentials`] are not that of a user in the
3970    ///   [`Administrator`][`UserRole::Administrator`] role
3971    /// * the used [`Credentials`] do not provide access to information about a user in the targeted
3972    ///   [namespace] (*N-Administrator* of a different [namespace])
3973    ///
3974    /// # Examples
3975    ///
3976    /// ```no_run
3977    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
3978    ///
3979    /// # fn main() -> testresult::TestResult {
3980    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
3981    /// let nethsm = NetHsm::new(
3982    ///     Connection::new(
3983    ///         "https://example.org/api/v1".try_into()?,
3984    ///         ConnectionSecurity::Unsafe,
3985    ///     ),
3986    ///     Some(Credentials::new(
3987    ///         "admin".parse()?,
3988    ///         Some(Passphrase::new("passphrase".to_string())),
3989    ///     )),
3990    ///     None,
3991    ///     None,
3992    /// )?;
3993    ///
3994    /// // add a user in the Administrator role for a namespace (N-Administrator)
3995    /// nethsm.add_user(
3996    ///     "Namespace1 Admin".to_string(),
3997    ///     UserRole::Administrator,
3998    ///     Passphrase::new("namespce1-admin-passphrase".to_string()),
3999    ///     Some("namespace1~admin1".parse()?),
4000    /// )?;
4001    /// // add the accompanying namespace
4002    /// nethsm.add_namespace(&"namespace1".parse()?)?;
4003    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
4004    /// // the N-Administrator sees itself
4005    /// println!("{:?}", nethsm.get_user(&"namespace1~admin1".parse()?)?);
4006    /// // the N-Administrator can not see the R-Administrator
4007    /// assert!(nethsm.get_user(&"admin".parse()?).is_err());
4008    ///
4009    /// nethsm.use_credentials(&"admin".parse()?)?;
4010    /// // the R-Administrator sees itself
4011    /// println!("{:?}", nethsm.get_user(&"admin".parse()?)?);
4012    /// // the R-Administrator sees the N-Administrator
4013    /// println!("{:?}", nethsm.get_user(&"namespace1~admin1".parse()?)?);
4014    /// // this fails if the user does not exist
4015    /// assert!(nethsm.get_user(&"user1".parse()?).is_err());
4016    /// # Ok(())
4017    /// # }
4018    /// ```
4019    /// [information of a user]: https://docs.nitrokey.com/nethsm/administration#list-users
4020    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
4021    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
4022    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
4023    pub fn get_user(&self, user_id: &UserId) -> Result<UserData, Error> {
4024        debug!(
4025            "Get the information of the user \"{user_id}\" on the NetHSM at {} using {}",
4026            self.url.borrow(),
4027            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
4028        );
4029
4030        self.validate_namespace_access(NamespaceSupport::Supported, Some(user_id), None)?;
4031        Ok(
4032            users_user_id_get(&self.create_connection_config(), &user_id.to_string())
4033                .map_err(|error| {
4034                    Error::Api(format!(
4035                        "Getting user failed: {}",
4036                        NetHsmApiError::from(error)
4037                    ))
4038                })?
4039                .entity,
4040        )
4041    }
4042
4043    /// Sets the [passphrase for a user] on the NetHSM.
4044    ///
4045    /// ## Namespaces
4046    ///
4047    /// *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
4048    /// [namespace]) are only able to set the passphrases for users in their own [namespace].
4049    /// *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are only
4050    /// able to set the passphrases for system-wide users.
4051    ///
4052    /// Internally, this function also calls [`add_credentials`][`NetHsm::add_credentials`] to add
4053    /// the updated user [`Credentials`] to the list of available ones.
4054    /// If the calling user is in the [`Administrator`][`UserRole::Administrator`] [role] and
4055    /// changes their own passphrase, additionally
4056    /// [`use_credentials`][`NetHsm::use_credentials`] is called to use the updated passphrase
4057    /// after changing it.
4058    ///
4059    /// This call requires using [`Credentials`] of a user in the
4060    /// [`Administrator`][`UserRole::Administrator`] [role].
4061    ///
4062    /// # Errors
4063    ///
4064    /// Returns an [`Error::Api`] if setting the passphrase for the user fails:
4065    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
4066    /// * the user identified by `user_id` does not exist
4067    /// * the used [`Credentials`] are not correct
4068    /// * the used [`Credentials`] are not that of a user in the
4069    ///   [`Administrator`][`UserRole::Administrator`] [role]
4070    /// * the targeted user is in a [namespace], but the caller is not an
4071    ///   [`Administrator`][`UserRole::Administrator`] of that [namespace] (*N-Administrator*)
4072    /// * the targeted user is a system-wide user, but the caller is not a system-wide
4073    ///   [`Administrator`][`UserRole::Administrator`] (*R-Administrator*)
4074    ///
4075    /// # Examples
4076    ///
4077    /// ```no_run
4078    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
4079    ///
4080    /// # fn main() -> testresult::TestResult {
4081    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
4082    /// let nethsm = NetHsm::new(
4083    ///     Connection::new(
4084    ///         "https://example.org/api/v1".try_into()?,
4085    ///         ConnectionSecurity::Unsafe,
4086    ///     ),
4087    ///     Some(Credentials::new(
4088    ///         "admin".parse()?,
4089    ///         Some(Passphrase::new("passphrase".to_string())),
4090    ///     )),
4091    ///     None,
4092    ///     None,
4093    /// )?;
4094    /// // add a user in the Administrator role for a namespace (N-Administrator)
4095    /// nethsm.add_user(
4096    ///     "Namespace1 Admin".to_string(),
4097    ///     UserRole::Administrator,
4098    ///     Passphrase::new("namespce1-admin-passphrase".to_string()),
4099    ///     Some("namespace1~admin1".parse()?),
4100    /// )?;
4101    /// // add the accompanying namespace
4102    /// nethsm.add_namespace(&"namespace1".parse()?)?;
4103    ///
4104    /// // the R-Administrator can set its own passphrase
4105    /// nethsm.set_user_passphrase(
4106    ///     "admin".parse()?,
4107    ///     Passphrase::new("new-admin-passphrase".to_string()),
4108    /// )?;
4109    /// // the R-Administrator can not set the N-Administrator's passphrase
4110    /// assert!(
4111    ///     nethsm
4112    ///         .set_user_passphrase(
4113    ///             "namespace1~admin".parse()?,
4114    ///             Passphrase::new("new-admin-passphrase".to_string()),
4115    ///         )
4116    ///         .is_err()
4117    /// );
4118    ///
4119    /// // the N-Administrator can set its own passphrase
4120    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
4121    /// nethsm.set_user_passphrase(
4122    ///     "namespace1~admin1".parse()?,
4123    ///     Passphrase::new("new-admin-passphrase".to_string()),
4124    /// )?;
4125    /// // the N-Administrator can not set the R-Administrator's passphrase
4126    /// assert!(
4127    ///     nethsm
4128    ///         .set_user_passphrase(
4129    ///             "admin".parse()?,
4130    ///             Passphrase::new("new-admin-passphrase".to_string())
4131    ///         )
4132    ///         .is_err()
4133    /// );
4134    /// # Ok(())
4135    /// # }
4136    /// ```
4137    /// [passphrase for a user]: https://docs.nitrokey.com/nethsm/administration#user-passphrase
4138    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
4139    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
4140    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
4141    pub fn set_user_passphrase(
4142        &self,
4143        user_id: UserId,
4144        passphrase: Passphrase,
4145    ) -> Result<(), Error> {
4146        debug!(
4147            "Set the passphrase of the user \"{user_id}\" on the NetHSM at {} using {}",
4148            self.url.borrow(),
4149            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
4150        );
4151
4152        self.validate_namespace_access(NamespaceSupport::Supported, Some(&user_id), None)?;
4153        users_user_id_passphrase_post(
4154            &self.create_connection_config(),
4155            &user_id.to_string(),
4156            UserPassphrasePostData::new(passphrase.expose_owned()),
4157        )
4158        .map_err(|error| {
4159            Error::Api(format!(
4160                "Setting user passphrase failed: {}",
4161                NetHsmApiError::from(error)
4162            ))
4163        })?;
4164
4165        // add to list of available credentials
4166        self.add_credentials(Credentials::new(user_id, Some(passphrase)));
4167
4168        Ok(())
4169    }
4170
4171    /// [Adds a tag] to a user in the [`Operator`][`UserRole::Operator`] [role].
4172    ///
4173    /// A `tag` provides the user identified by `user_id` with access to keys in their [namespace],
4174    /// that are tagged with that same `tag`.
4175    ///
4176    /// **NOTE**: The tag for the key in the same [namespace] must be added beforehand, by calling
4177    /// [`add_key_tag`][`NetHsm::add_key_tag`].
4178    ///
4179    /// This call requires using [`Credentials`] of a user in the
4180    /// [`Administrator`][`UserRole::Administrator`] [role].
4181    ///
4182    /// ## Namespaces
4183    ///
4184    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
4185    ///   [namespace]) are only able to add tags for users in their own [namespace].
4186    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
4187    ///   only able to add tags for system-wide users.
4188    ///
4189    /// # Errors
4190    ///
4191    /// Returns an [`Error::Api`] if adding the tag for the user fails:
4192    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
4193    /// * the user identified by `user_id` does not exist
4194    /// * the user identified by `user_id` is not in the [`Operator`][`UserRole::Operator`] [role]
4195    /// * the used [`Credentials`] are not correct
4196    /// * the used [`Credentials`] are not that of a user in the
4197    ///   [`Administrator`][`UserRole::Administrator`] [role]
4198    /// * the caller does not have access to the target user's [namespace]
4199    ///
4200    /// # Examples
4201    ///
4202    /// ```no_run
4203    /// use nethsm::{
4204    ///     Connection,
4205    ///     ConnectionSecurity,
4206    ///     Credentials,
4207    ///     KeyMechanism,
4208    ///     KeyType,
4209    ///     NetHsm,
4210    ///     Passphrase,
4211    ///     UserRole,
4212    /// };
4213    ///
4214    /// # fn main() -> testresult::TestResult {
4215    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
4216    /// let nethsm = NetHsm::new(
4217    ///     Connection::new(
4218    ///         "https://example.org/api/v1".try_into()?,
4219    ///         ConnectionSecurity::Unsafe,
4220    ///     ),
4221    ///     Some(Credentials::new(
4222    ///         "admin".parse()?,
4223    ///         Some(Passphrase::new("passphrase".to_string())),
4224    ///     )),
4225    ///     None,
4226    ///     None,
4227    /// )?;
4228    /// // add a user in the Administrator role for a namespace (N-Administrator)
4229    /// nethsm.add_user(
4230    ///     "Namespace1 Admin".to_string(),
4231    ///     UserRole::Administrator,
4232    ///     Passphrase::new("namespce1-admin-passphrase".to_string()),
4233    ///     Some("namespace1~admin1".parse()?),
4234    /// )?;
4235    /// // add a user in the Operator role for a namespace
4236    /// nethsm.add_user(
4237    ///     "Namespace1 Operator".to_string(),
4238    ///     UserRole::Operator,
4239    ///     Passphrase::new("namespce1-operator-passphrase".to_string()),
4240    ///     Some("namespace1~operator1".parse()?),
4241    /// )?;
4242    /// // add the accompanying namespace
4243    /// nethsm.add_namespace(&"namespace1".parse()?)?;
4244    /// // add a system-wide user in the Operator role
4245    /// nethsm.add_user(
4246    ///     "Operator One".to_string(),
4247    ///     UserRole::Operator,
4248    ///     Passphrase::new("operator1-passphrase".to_string()),
4249    ///     Some("user1".parse()?),
4250    /// )?;
4251    /// // generate system-wide key with tag
4252    /// nethsm.generate_key(
4253    ///     KeyType::Curve25519,
4254    ///     vec![KeyMechanism::EdDsaSignature],
4255    ///     None,
4256    ///     Some("signing1".parse()?),
4257    ///     Some(vec!["tag1".to_string()]),
4258    /// )?;
4259    ///
4260    /// // R-Administrators can add tags for system-wide users
4261    /// nethsm.add_user_tag(&"user1".parse()?, "tag1")?;
4262    /// // R-Administrators can not add tags for namespace users
4263    /// assert!(
4264    ///     nethsm
4265    ///         .add_user_tag(&"namespace1~user1".parse()?, "tag1")
4266    ///         .is_err()
4267    /// );
4268    ///
4269    /// // user tags in namespaces
4270    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
4271    /// // generate key in namespace1 with tag
4272    /// nethsm.generate_key(
4273    ///     KeyType::Curve25519,
4274    ///     vec![KeyMechanism::EdDsaSignature],
4275    ///     None,
4276    ///     Some("signing2".parse()?),
4277    ///     Some(vec!["tag2".to_string()]),
4278    /// )?;
4279    /// // N-Administrators can not add tags to system-wide users
4280    /// assert!(nethsm.add_user_tag(&"user1".parse()?, "tag2").is_err());
4281    /// // N-Administrators can add tags to users in their own namespace
4282    /// nethsm.add_user_tag(&"namespace1~user1".parse()?, "tag2")?;
4283    /// # Ok(())
4284    /// # }
4285    /// ```
4286    /// [Adds a tag]: https://docs.nitrokey.com/nethsm/administration#tags-for-users
4287    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
4288    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
4289    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
4290    pub fn add_user_tag(&self, user_id: &UserId, tag: &str) -> Result<(), Error> {
4291        debug!(
4292            "Add the tag \"{tag}\" for the user \"{user_id}\" on the NetHSM at {} using {}",
4293            self.url.borrow(),
4294            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
4295        );
4296
4297        self.validate_namespace_access(NamespaceSupport::Supported, Some(user_id), None)?;
4298        users_user_id_tags_tag_put(&self.create_connection_config(), &user_id.to_string(), tag)
4299            .map_err(|error| {
4300                Error::Api(format!(
4301                    "Adding tag for user failed: {}",
4302                    NetHsmApiError::from(error)
4303                ))
4304            })?;
4305        Ok(())
4306    }
4307
4308    /// [Deletes a tag] from a user in the [`Operator`][`UserRole::Operator`] [role].
4309    ///
4310    /// Removes a `tag` from a target user identified by `user_id`, which removes its access to any
4311    /// key in their [namespace], that carries the same `tag`.
4312    ///
4313    /// This call requires using [`Credentials`] of a user in the
4314    /// [`Administrator`][`UserRole::Administrator`] [role].
4315    ///
4316    /// ## Namespaces
4317    ///
4318    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
4319    ///   [namespace]) are only able to delete tags for users in their own [namespace].
4320    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
4321    ///   only able to delete tags for system-wide users.
4322    ///
4323    /// # Errors
4324    ///
4325    /// Returns an [`Error::Api`] if deleting the tag from the user fails:
4326    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
4327    /// * the user identified by `user_id` does not exist
4328    /// * the user identified by `user_id` is not in the [`Operator`][`UserRole::Operator`] [role]
4329    /// * the `tag` is not added to user identified by `user_id`
4330    /// * the used [`Credentials`] are not correct
4331    /// * the used [`Credentials`] are not that of a user in the
4332    ///   [`Administrator`][`UserRole::Administrator`] [role]
4333    /// * the caller does not have access to the target user's [namespace]
4334    ///
4335    /// # Examples
4336    ///
4337    /// ```no_run
4338    /// use nethsm::{
4339    ///     Connection,
4340    ///     ConnectionSecurity,
4341    ///     Credentials,
4342    ///     KeyMechanism,
4343    ///     KeyType,
4344    ///     NetHsm,
4345    ///     Passphrase,
4346    ///     UserRole,
4347    /// };
4348    ///
4349    /// # fn main() -> testresult::TestResult {
4350    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
4351    /// let nethsm = NetHsm::new(
4352    ///     Connection::new(
4353    ///         "https://example.org/api/v1".try_into()?,
4354    ///         ConnectionSecurity::Unsafe,
4355    ///     ),
4356    ///     Some(Credentials::new(
4357    ///         "admin".parse()?,
4358    ///         Some(Passphrase::new("passphrase".to_string())),
4359    ///     )),
4360    ///     None,
4361    ///     None,
4362    /// )?;
4363    /// // add a user in the Administrator role for a namespace (N-Administrator)
4364    /// nethsm.add_user(
4365    ///     "Namespace1 Admin".to_string(),
4366    ///     UserRole::Administrator,
4367    ///     Passphrase::new("namespce1-admin-passphrase".to_string()),
4368    ///     Some("namespace1~admin1".parse()?),
4369    /// )?;
4370    /// // add a user in the Operator role for a namespace
4371    /// nethsm.add_user(
4372    ///     "Namespace1 Operator".to_string(),
4373    ///     UserRole::Operator,
4374    ///     Passphrase::new("namespce1-operator-passphrase".to_string()),
4375    ///     Some("namespace1~operator1".parse()?),
4376    /// )?;
4377    /// // add the accompanying namespace
4378    /// nethsm.add_namespace(&"namespace1".parse()?)?;
4379    /// // add a system-wide user in the Operator role
4380    /// nethsm.add_user(
4381    ///     "Operator One".to_string(),
4382    ///     UserRole::Operator,
4383    ///     Passphrase::new("operator1-passphrase".to_string()),
4384    ///     Some("user1".parse()?),
4385    /// )?;
4386    /// // generate system-wide key with tag
4387    /// nethsm.generate_key(
4388    ///     KeyType::Curve25519,
4389    ///     vec![KeyMechanism::EdDsaSignature],
4390    ///     None,
4391    ///     Some("signing1".parse()?),
4392    ///     Some(vec!["tag1".to_string()]),
4393    /// )?;
4394    /// // add tag for system-wide user
4395    /// nethsm.add_user_tag(&"user1".parse()?, "tag1")?;
4396    ///
4397    /// // N-Administrators can not delete tags from system-wide Operator users
4398    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
4399    /// assert!(nethsm.delete_user_tag(&"user1".parse()?, "tag2").is_err());
4400    ///
4401    /// // R-Administrators can delete tags from system-wide Operator users
4402    /// nethsm.use_credentials(&"admin".parse()?)?;
4403    /// nethsm.delete_user_tag(&"user1".parse()?, "tag1")?;
4404    /// # Ok(())
4405    /// # }
4406    /// ```
4407    /// [Deletes a tag]: https://docs.nitrokey.com/nethsm/administration#tags-for-users
4408    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
4409    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
4410    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
4411    pub fn delete_user_tag(&self, user_id: &UserId, tag: &str) -> Result<(), Error> {
4412        debug!(
4413            "Delete the tag \"{tag}\" from the user \"{user_id}\" on the NetHSM at {} using {}",
4414            self.url.borrow(),
4415            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
4416        );
4417
4418        self.validate_namespace_access(NamespaceSupport::Supported, Some(user_id), None)?;
4419        users_user_id_tags_tag_delete(&self.create_connection_config(), &user_id.to_string(), tag)
4420            .map_err(|error| {
4421                Error::Api(format!(
4422                    "Deleting tag for user failed: {}",
4423                    NetHsmApiError::from(error)
4424                ))
4425            })?;
4426        Ok(())
4427    }
4428
4429    /// [Gets all tags] of a user in the [`Operator`][`UserRole::Operator`] [role].
4430    ///
4431    /// This call requires using [`Credentials`] of a user in the
4432    /// [`Administrator`][`UserRole::Administrator`] [role].
4433    ///
4434    /// ## Namespaces
4435    ///
4436    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
4437    ///   [namespace]) are only able to get tags of users in their own [namespace].
4438    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
4439    ///   able to get tags of system-wide and all [namespace] users.
4440    ///
4441    /// # Errors
4442    ///
4443    /// Returns an [`Error::Api`] if getting the tags for the user fails:
4444    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
4445    /// * the user identified by `user_id` does not exist
4446    /// * the user identified by `user_id` is not in the [`Operator`][`UserRole::Operator`] [role]
4447    /// * the used [`Credentials`] are not correct
4448    /// * the used [`Credentials`] are not that of a user in the
4449    ///   [`Administrator`][`UserRole::Administrator`] [role]
4450    /// * the caller does not have access to the target user's [namespace]
4451    ///
4452    /// # Examples
4453    ///
4454    /// ```no_run
4455    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
4456    ///
4457    /// # fn main() -> testresult::TestResult {
4458    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
4459    /// let nethsm = NetHsm::new(
4460    ///     Connection::new(
4461    ///         "https://example.org/api/v1".try_into()?,
4462    ///         ConnectionSecurity::Unsafe,
4463    ///     ),
4464    ///     Some(Credentials::new(
4465    ///         "admin".parse()?,
4466    ///         Some(Passphrase::new("passphrase".to_string())),
4467    ///     )),
4468    ///     None,
4469    ///     None,
4470    /// )?;
4471    /// // add a user in the Administrator role for a namespace (N-Administrator)
4472    /// nethsm.add_user(
4473    ///     "Namespace1 Admin".to_string(),
4474    ///     UserRole::Administrator,
4475    ///     Passphrase::new("namespce1-admin-passphrase".to_string()),
4476    ///     Some("namespace1~admin1".parse()?),
4477    /// )?;
4478    /// // add the accompanying namespace
4479    /// nethsm.add_namespace(&"namespace1".parse()?)?;
4480    /// // add a system-wide user in the Operator role
4481    /// nethsm.add_user(
4482    ///     "Operator One".to_string(),
4483    ///     UserRole::Operator,
4484    ///     Passphrase::new("operator1-passphrase".to_string()),
4485    ///     Some("user1".parse()?),
4486    /// )?;
4487    ///
4488    /// // R-Administrators can access tags of all users
4489    /// assert!(nethsm.get_user_tags(&"user1".parse()?)?.is_empty());
4490    /// // add a tag for the user
4491    /// nethsm.add_user_tag(&"user1".parse()?, "tag1")?;
4492    /// assert_eq!(nethsm.get_user_tags(&"user1".parse()?)?.len(), 1);
4493    ///
4494    /// // N-Administrators can not access tags of system-wide users
4495    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
4496    /// assert!(nethsm.get_user_tags(&"user1".parse()?).is_err());
4497    /// # Ok(())
4498    /// # }
4499    /// ```
4500    /// [Gets all tags]: https://docs.nitrokey.com/nethsm/administration#tags-for-users
4501    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
4502    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
4503    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
4504    pub fn get_user_tags(&self, user_id: &UserId) -> Result<Vec<String>, Error> {
4505        debug!(
4506            "Get the tags of the user \"{user_id}\" on the NetHSM at {} using {}",
4507            self.url.borrow(),
4508            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
4509        );
4510
4511        self.validate_namespace_access(NamespaceSupport::Supported, Some(user_id), None)?;
4512        Ok(
4513            users_user_id_tags_get(&self.create_connection_config(), &user_id.to_string())
4514                .map_err(|error| {
4515                    Error::Api(format!(
4516                        "Getting tags of user failed: {}",
4517                        NetHsmApiError::from(error)
4518                    ))
4519                })?
4520                .entity,
4521        )
4522    }
4523
4524    /// [Generates a new key] on the NetHSM.
4525    ///
4526    /// [Generates a new key] with customizable features on the NetHSM.
4527    /// The provided [`KeyType`] and list of [`KeyMechanism`]s have to match:
4528    /// * [`KeyType::Rsa`] requires one of [`KeyMechanism::RsaDecryptionRaw`],
4529    ///   [`KeyMechanism::RsaDecryptionPkcs1`], [`KeyMechanism::RsaDecryptionOaepMd5`],
4530    ///   [`KeyMechanism::RsaDecryptionOaepSha1`], [`KeyMechanism::RsaDecryptionOaepSha224`],
4531    ///   [`KeyMechanism::RsaDecryptionOaepSha256`], [`KeyMechanism::RsaDecryptionOaepSha384`],
4532    ///   [`KeyMechanism::RsaDecryptionOaepSha512`], [`KeyMechanism::RsaSignaturePkcs1`],
4533    ///   [`KeyMechanism::RsaSignaturePssMd5`], [`KeyMechanism::RsaSignaturePssSha1`],
4534    ///   [`KeyMechanism::RsaSignaturePssSha224`], [`KeyMechanism::RsaSignaturePssSha256`],
4535    ///   [`KeyMechanism::RsaSignaturePssSha384`] or [`KeyMechanism::RsaSignaturePssSha512`]
4536    /// * [`KeyType::Curve25519`] requires [`KeyMechanism::EdDsaSignature`]
4537    /// * [`KeyType::EcP224`], [`KeyType::EcP256`], [`KeyType::EcP384`] and [`KeyType::EcP521`]
4538    ///   require [`KeyMechanism::EcdsaSignature`]
4539    /// * [`KeyType::Generic`] requires one of [`KeyMechanism::AesDecryptionCbc`] or
4540    ///   [`KeyMechanism::AesEncryptionCbc`]
4541    ///
4542    /// Optionally the key bit-length using `length`, a custom key ID using `key_id`
4543    /// and a list of `tags` to be attached to the new key can be provided.
4544    /// If no `key_id` is provided, a unique one is generated automatically.
4545    ///
4546    /// **WARNING**: If no `tags` are provided, the generated key is usable by all users in the
4547    /// [`Operator`][`UserRole::Operator`] [role] in the same scope (e.g. same [namespace]) by
4548    /// default!
4549    ///
4550    /// This call requires using [`Credentials`] of a user in the
4551    /// [`Administrator`][`UserRole::Administrator`] [role].
4552    ///
4553    /// ## Namespaces
4554    ///
4555    /// * Keys generated by *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users
4556    ///   in a given [namespace]) are only visible to users in their [namespace]. Only users in the
4557    ///   [`Operator`][`UserRole::Operator`] [role] in that same [namespace] can be granted access
4558    ///   to them.
4559    /// * Keys generated by *R-Administrators* (system-wide
4560    ///   [`Administrator`][`UserRole::Administrator`] users) are only visible to system-wide users.
4561    ///   Only system-wide users in the [`Operator`][`UserRole::Operator`] [role] (not in any
4562    ///   [namespace]) can be granted access to them.
4563    ///
4564    /// # Errors
4565    ///
4566    /// Returns an [`Error::Api`] if generating the key fails:
4567    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
4568    /// * a key identified by ` key_id` exists already
4569    /// * the chosen `length` or `tags` options are not valid
4570    /// * the used [`Credentials`] are not correct
4571    /// * the used [`Credentials`] are not that of a user in the
4572    ///   [`Administrator`][`UserRole::Administrator`] [role]
4573    ///
4574    /// Returns an [`Error::Key`] if
4575    /// * the provided combination of `key_type` and `mechanisms` is not valid.
4576    /// * the provided combination of `key_type` and `length` is not valid.
4577    ///
4578    /// # Examples
4579    ///
4580    /// ```no_run
4581    /// use nethsm::{
4582    ///     Connection,
4583    ///     ConnectionSecurity,
4584    ///     Credentials,
4585    ///     KeyMechanism,
4586    ///     KeyType,
4587    ///     NetHsm,
4588    ///     Passphrase,
4589    /// };
4590    ///
4591    /// # fn main() -> testresult::TestResult {
4592    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
4593    /// let nethsm = NetHsm::new(
4594    ///     Connection::new(
4595    ///         "https://example.org/api/v1".try_into()?,
4596    ///         ConnectionSecurity::Unsafe,
4597    ///     ),
4598    ///     Some(Credentials::new(
4599    ///         "admin".parse()?,
4600    ///         Some(Passphrase::new("passphrase".to_string())),
4601    ///     )),
4602    ///     None,
4603    ///     None,
4604    /// )?;
4605    ///
4606    /// // generate a Curve25519 key for signing with custom Key ID and tags
4607    /// nethsm.generate_key(
4608    ///     KeyType::Curve25519,
4609    ///     vec![KeyMechanism::EdDsaSignature],
4610    ///     None,
4611    ///     Some("signing1".parse()?),
4612    ///     Some(vec!["sign_tag1".to_string(), "sign_tag2".to_string()]),
4613    /// )?;
4614    ///
4615    /// // generate a generic key for symmetric encryption and decryption
4616    /// nethsm.generate_key(
4617    ///     KeyType::Generic,
4618    ///     vec![
4619    ///         KeyMechanism::AesEncryptionCbc,
4620    ///         KeyMechanism::AesDecryptionCbc,
4621    ///     ],
4622    ///     Some(128),
4623    ///     Some("encryption1".parse()?),
4624    ///     Some(vec!["encryption_tag1".to_string()]),
4625    /// )?;
4626    /// # Ok(())
4627    /// # }
4628    /// ```
4629    /// [Generates a new key]: https://docs.nitrokey.com/nethsm/operation#generate-key
4630    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
4631    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
4632    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
4633    pub fn generate_key(
4634        &self,
4635        key_type: KeyType,
4636        mechanisms: Vec<KeyMechanism>,
4637        length: Option<u32>,
4638        key_id: Option<KeyId>,
4639        tags: Option<Vec<String>>,
4640    ) -> Result<KeyId, Error> {
4641        debug!(
4642            "Generate a key (key type: {key_type}; mechanisms: {}; length: {}; ID: {}, tags: {}) on the NetHSM at {} using {}",
4643            mechanisms
4644                .iter()
4645                .map(|mechanism| mechanism.to_string())
4646                .collect::<Vec<String>>()
4647                .join(", "),
4648            if let Some(length) = length {
4649                length.to_string()
4650            } else {
4651                "n/a".to_string()
4652            },
4653            if let Some(key_id) = key_id.as_ref() {
4654                key_id.to_string()
4655            } else {
4656                "n/a".to_string()
4657            },
4658            if let Some(tags) = tags.as_ref() {
4659                tags.join(", ")
4660            } else {
4661                "n/a".to_string()
4662            },
4663            self.url.borrow(),
4664            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
4665        );
4666
4667        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
4668        // ensure the key_type - mechanisms combinations are valid
4669        key_type_matches_mechanisms(key_type, &mechanisms)?;
4670        // ensure the key_type - length combination is valid
4671        key_type_matches_length(key_type, length)?;
4672
4673        Ok(keys_generate_post(
4674            &self.create_connection_config(),
4675            KeyGenerateRequestData {
4676                mechanisms: mechanisms
4677                    .into_iter()
4678                    .map(|mechanism| mechanism.into())
4679                    .collect(),
4680                r#type: key_type.into(),
4681                length: length.map(|length| length as i32),
4682                id: key_id.map(Into::into),
4683                restrictions: tags.map(|tags| Box::new(KeyRestrictions { tags: Some(tags) })),
4684            },
4685        )
4686        .map_err(|error| {
4687            Error::Api(format!(
4688                "Creating key failed: {}",
4689                NetHsmApiError::from(error)
4690            ))
4691        })?
4692        .entity
4693        .id
4694        .parse()?)
4695    }
4696
4697    /// Imports an existing private key.
4698    ///
4699    /// [Imports an existing key] with custom features into the NetHSM.
4700    /// The [`KeyType`] implied by the provided [`PrivateKeyImport`] and the list of
4701    /// [`KeyMechanism`]s have to match:
4702    /// * [`KeyType::Rsa`] must be used with [`KeyMechanism::RsaDecryptionRaw`],
4703    ///   [`KeyMechanism::RsaDecryptionPkcs1`], [`KeyMechanism::RsaDecryptionOaepMd5`],
4704    ///   [`KeyMechanism::RsaDecryptionOaepSha1`], [`KeyMechanism::RsaDecryptionOaepSha224`],
4705    ///   [`KeyMechanism::RsaDecryptionOaepSha256`], [`KeyMechanism::RsaDecryptionOaepSha384`],
4706    ///   [`KeyMechanism::RsaDecryptionOaepSha512`], [`KeyMechanism::RsaSignaturePkcs1`],
4707    ///   [`KeyMechanism::RsaSignaturePssMd5`], [`KeyMechanism::RsaSignaturePssSha1`],
4708    ///   [`KeyMechanism::RsaSignaturePssSha224`], [`KeyMechanism::RsaSignaturePssSha256`],
4709    ///   [`KeyMechanism::RsaSignaturePssSha384`] or [`KeyMechanism::RsaSignaturePssSha512`]
4710    /// * [`KeyType::Curve25519`] must be used with [`KeyMechanism::EdDsaSignature`]
4711    /// * [`KeyType::EcP224`], [`KeyType::EcP256`], [`KeyType::EcP384`] and [`KeyType::EcP521`] must
4712    ///   be used with [`KeyMechanism::EcdsaSignature`]
4713    /// * [`KeyType::Generic`] must be used with [`KeyMechanism::AesDecryptionCbc`] or
4714    ///   [`KeyMechanism::AesEncryptionCbc`]
4715    ///
4716    /// Optionally a custom Key ID using `key_id` and a list of `tags` to be attached to the new key
4717    /// can be provided.
4718    /// If no `key_id` is provided, a unique one is generated automatically.
4719    ///
4720    /// **WARNING**: If no `tags` are provided, the imported key is usable by all users in the
4721    /// [`Operator`][`UserRole::Operator`] [role] in the same scope (e.g. same [namespace]) by
4722    /// default!
4723    ///
4724    /// This call requires using [`Credentials`] of a user in the
4725    /// [`Administrator`][`UserRole::Administrator`] [role].
4726    ///
4727    /// ## Namespaces
4728    ///
4729    /// * Keys imported by *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in
4730    ///   a given [namespace]) are only visible to users in their [namespace]. Only users in the
4731    ///   [`Operator`][`UserRole::Operator`] [role] in that same [namespace] can be granted access
4732    ///   to them.
4733    /// * Keys imported by *R-Administrators* (system-wide
4734    ///   [`Administrator`][`UserRole::Administrator`] users) are only visible to system-wide users.
4735    ///   Only system-wide users in the [`Operator`][`UserRole::Operator`] [role] (not in any
4736    ///   [namespace]) can be granted access to them.
4737    ///
4738    /// # Errors
4739    ///
4740    /// Returns an [`Error::Api`] if importing the key fails:
4741    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
4742    /// * a key identified by ` key_id` exists already
4743    /// * the chosen `tags` option is not valid
4744    /// * the used [`Credentials`] are not correct
4745    /// * the used [`Credentials`] are not that of a user in the
4746    ///   [`Administrator`][`UserRole::Administrator`] [role]
4747    ///
4748    /// Returns an [`Error::Key`] if the provided combination of `key_data` and `mechanisms` is not
4749    /// valid.
4750    ///
4751    /// # Examples
4752    ///
4753    /// ```no_run
4754    /// use nethsm::{Connection, ConnectionSecurity, Credentials, PrivateKeyImport, KeyMechanism, KeyType, NetHsm, Passphrase};
4755    /// use rsa::pkcs8::{DecodePrivateKey, EncodePrivateKey};
4756    /// use rsa::RsaPrivateKey;
4757    ///
4758    /// # fn main() -> testresult::TestResult {
4759    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
4760    /// let nethsm = NetHsm::new(
4761    ///     Connection::new(
4762    ///         "https://example.org/api/v1".try_into()?,
4763    ///         ConnectionSecurity::Unsafe,
4764    ///     ),
4765    ///     Some(Credentials::new(
4766    ///         "admin".parse()?,
4767    ///         Some(Passphrase::new("passphrase".to_string())),
4768    ///     )),
4769    ///     None,
4770    ///     None,
4771    /// )?;
4772    ///
4773    /// // create a 4096 bit RSA private key and return it as PKCS#8 private key in ASN.1 DER-encoded format
4774    /// let private_key = {
4775    ///     let mut rng = rand::thread_rng();
4776    ///     let private_key = RsaPrivateKey::new(&mut rng, 4096)?;
4777    ///     private_key.to_pkcs8_der()?
4778    /// };
4779    ///
4780    /// // import an RSA key for PKCS1 signatures
4781    /// nethsm.import_key(
4782    ///     vec![KeyMechanism::RsaSignaturePkcs1],
4783    ///     PrivateKeyImport::new(KeyType::Rsa, private_key.as_bytes())?,
4784    ///     Some("signing2".parse()?),
4785    ///     Some(vec!["signing_tag3".to_string()]),
4786    /// )?;
4787    /// # Ok(())
4788    /// # }
4789    /// ```
4790    /// [Imports an existing key]: https://docs.nitrokey.com/nethsm/operation#import-key
4791    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
4792    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
4793    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
4794    pub fn import_key(
4795        &self,
4796        mechanisms: Vec<KeyMechanism>,
4797        key_data: PrivateKeyImport,
4798        key_id: Option<KeyId>,
4799        tags: Option<Vec<String>>,
4800    ) -> Result<KeyId, Error> {
4801        debug!(
4802            "Import a key (mechanisms: {}; ID: {}, tags: {}) to the NetHSM at {} using {}",
4803            mechanisms
4804                .iter()
4805                .map(|mechanism| mechanism.to_string())
4806                .collect::<Vec<String>>()
4807                .join(", "),
4808            if let Some(key_id) = key_id.as_ref() {
4809                key_id.to_string()
4810            } else {
4811                "n/a".to_string()
4812            },
4813            if let Some(tags) = tags.as_ref() {
4814                tags.join(", ")
4815            } else {
4816                "n/a".to_string()
4817            },
4818            self.url.borrow(),
4819            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
4820        );
4821
4822        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
4823        // ensure the key_type - mechanisms combinations are valid
4824        let key_type = key_data.key_type();
4825        key_type_matches_mechanisms(key_type, &mechanisms)?;
4826
4827        let restrictions = tags.map(|tags| Box::new(KeyRestrictions { tags: Some(tags) }));
4828        let private = Box::new(key_data.into());
4829        let mechanisms = mechanisms
4830            .into_iter()
4831            .map(|mechanism| mechanism.into())
4832            .collect();
4833
4834        if let Some(key_id) = key_id {
4835            keys_key_id_put(
4836                &self.create_connection_config(),
4837                key_id.as_ref(),
4838                nethsm_sdk_rs::apis::default_api::KeysKeyIdPutBody::ApplicationJson(PrivateKey {
4839                    mechanisms,
4840                    r#type: key_type.into(),
4841                    private,
4842                    restrictions,
4843                }),
4844            )
4845            .map_err(|error| {
4846                Error::Api(format!(
4847                    "Importing key failed: {}",
4848                    NetHsmApiError::from(error)
4849                ))
4850            })?;
4851            Ok(key_id)
4852        } else {
4853            Ok(keys_post(
4854                &self.create_connection_config(),
4855                KeysPostBody::ApplicationJson(PrivateKey {
4856                    mechanisms,
4857                    r#type: key_type.into(),
4858                    private,
4859                    restrictions,
4860                }),
4861            )
4862            .map_err(|error| {
4863                Error::Api(format!(
4864                    "Importing key failed: {}",
4865                    NetHsmApiError::from(error)
4866                ))
4867            })?
4868            .entity
4869            .id
4870            .parse()?)
4871        }
4872    }
4873
4874    /// [Deletes a key] from the NetHSM.
4875    ///
4876    /// [Deletes a key] identified by `key_id` from the NetHSM.
4877    ///
4878    /// This call requires using [`Credentials`] of a user in the
4879    /// [`Administrator`][`UserRole::Administrator`] [role].
4880    ///
4881    /// ## Namespaces
4882    ///
4883    /// * Keys in a [namespace] can only be deleted by *N-Administrators*
4884    ///   ([`Administrator`][`UserRole::Administrator`] users in a given [namespace]) of that
4885    ///   [namespace] (*R-Administrators* have no access to keys in a [namespace]). **NOTE**:
4886    ///   Calling [`delete_namespace`][`NetHsm::delete_namespace`] deletes **all keys** in a
4887    ///   [namespace]!
4888    /// * System-wide keys can only be deleted by *R-Administrators* (system-wide
4889    ///   [`Administrator`][`UserRole::Administrator`] users).
4890    ///
4891    /// # Errors
4892    ///
4893    /// Returns an [`Error::Api`] if deleting the key fails:
4894    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
4895    /// * no key identified by `key_id` exists
4896    /// * the used [`Credentials`] are not correct
4897    /// * the used [`Credentials`] are not that of a user in the
4898    ///   [`Administrator`][`UserRole::Administrator`] [role]
4899    ///
4900    /// # Examples
4901    ///
4902    /// ```no_run
4903    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
4904    ///
4905    /// # fn main() -> testresult::TestResult {
4906    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
4907    /// let nethsm = NetHsm::new(
4908    ///     Connection::new(
4909    ///         "https://example.org/api/v1".try_into()?,
4910    ///         ConnectionSecurity::Unsafe,
4911    ///     ),
4912    ///     Some(Credentials::new(
4913    ///         "admin".parse()?,
4914    ///         Some(Passphrase::new("passphrase".to_string())),
4915    ///     )),
4916    ///     None,
4917    ///     None,
4918    /// )?;
4919    ///
4920    /// // delete a key with the Key ID "signing1"
4921    /// nethsm.delete_key(&"signing1".parse()?)?;
4922    /// # Ok(())
4923    /// # }
4924    /// ```
4925    /// [Deletes a key]: https://docs.nitrokey.com/nethsm/operation#delete-key
4926    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
4927    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
4928    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
4929    pub fn delete_key(&self, key_id: &KeyId) -> Result<(), Error> {
4930        debug!(
4931            "Delete the key \"{key_id}\" on the NetHSM at {} using {}",
4932            self.url.borrow(),
4933            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
4934        );
4935
4936        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
4937        keys_key_id_delete(&self.create_connection_config(), key_id.as_ref()).map_err(|error| {
4938            Error::Api(format!(
4939                "Deleting key failed: {}",
4940                NetHsmApiError::from(error)
4941            ))
4942        })?;
4943        Ok(())
4944    }
4945
4946    /// Gets [details about a key].
4947    ///
4948    /// Gets [details about a key] identified by `key_id`.
4949    ///
4950    /// This call requires using [`Credentials`] of a user in the
4951    /// [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`]
4952    /// [role].
4953    ///
4954    /// ## Namespaces
4955    ///
4956    /// * Users in a [namespace] can only get details about keys in their own [namespace].
4957    /// * System-wide users (not in a [namespace]) can only get details about system-wide keys.
4958    ///
4959    /// # Errors
4960    ///
4961    /// Returns an [`Error::Api`] if getting the key details fails:
4962    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
4963    /// * no key identified by `key_id` exists
4964    /// * the used [`Credentials`] are not correct
4965    /// * the used [`Credentials`] are not those of a user in the
4966    ///   [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`] [role]
4967    ///
4968    /// # Examples
4969    ///
4970    /// ```no_run
4971    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
4972    ///
4973    /// # fn main() -> testresult::TestResult {
4974    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
4975    /// let nethsm = NetHsm::new(
4976    ///     Connection::new(
4977    ///         "https://example.org/api/v1".try_into()?,
4978    ///         ConnectionSecurity::Unsafe,
4979    ///     ),
4980    ///     Some(Credentials::new(
4981    ///         "admin".parse()?,
4982    ///         Some(Passphrase::new("passphrase".to_string())),
4983    ///     )),
4984    ///     None,
4985    ///     None,
4986    /// )?;
4987    ///
4988    /// // get details on a key with the Key ID "signing1"
4989    /// println!("{:?}", nethsm.get_key(&"signing1".parse()?)?);
4990    /// # Ok(())
4991    /// # }
4992    /// ```
4993    /// [details about a key]: https://docs.nitrokey.com/nethsm/operation#show-key-details
4994    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
4995    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
4996    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
4997    pub fn get_key(&self, key_id: &KeyId) -> Result<PublicKey, Error> {
4998        debug!(
4999            "Retrieve details about the key \"{key_id}\" from the NetHSM at {} using {}",
5000            self.url.borrow(),
5001            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
5002        );
5003
5004        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
5005        Ok(
5006            keys_key_id_get(&self.create_connection_config(), key_id.as_ref())
5007                .map_err(|error| {
5008                    Error::Api(format!(
5009                        "Getting key failed: {}",
5010                        NetHsmApiError::from(error)
5011                    ))
5012                })?
5013                .entity,
5014        )
5015    }
5016
5017    /// Gets a [list of Key IDs] on the NetHSM.
5018    ///
5019    /// Optionally `filter` can be provided for matching against Key IDs.
5020    ///
5021    /// This call requires using [`Credentials`] of a user in the
5022    /// [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`]
5023    /// [role].
5024    ///
5025    /// ## Namespaces
5026    ///
5027    /// * Users in a [namespace] can only list key IDs of keys in their own [namespace].
5028    /// * System-wide users (not in a [namespace]) can only list key IDs of system-wide keys.
5029    ///
5030    /// # Errors
5031    ///
5032    /// Returns an [`Error::Api`] if getting the list of Key IDs fails:
5033    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
5034    /// * the used [`Credentials`] are not correct
5035    /// * the used [`Credentials`] are not those of a user in the
5036    ///   [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`] [role]
5037    ///
5038    /// # Examples
5039    ///
5040    /// ```no_run
5041    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
5042    ///
5043    /// # fn main() -> testresult::TestResult {
5044    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
5045    /// let nethsm = NetHsm::new(
5046    ///     Connection::new(
5047    ///         "https://example.org/api/v1".try_into()?,
5048    ///         ConnectionSecurity::Unsafe,
5049    ///     ),
5050    ///     Some(Credentials::new(
5051    ///         "admin".parse()?,
5052    ///         Some(Passphrase::new("passphrase".to_string())),
5053    ///     )),
5054    ///     None,
5055    ///     None,
5056    /// )?;
5057    ///
5058    /// // get all Key IDs
5059    /// println!("{:?}", nethsm.get_keys(None)?);
5060    ///
5061    /// // get all Key IDs that begin with "signing"
5062    /// println!("{:?}", nethsm.get_keys(Some("signing"))?);
5063    /// # Ok(())
5064    /// # }
5065    /// ```
5066    /// [list of Key IDs]: https://docs.nitrokey.com/nethsm/operation#list-keys
5067    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
5068    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
5069    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
5070    pub fn get_keys(&self, filter: Option<&str>) -> Result<Vec<KeyId>, Error> {
5071        debug!(
5072            "Get key IDs{} from the NetHSM at {} using {}",
5073            if let Some(filter) = filter {
5074                format!(" based on filter {filter}")
5075            } else {
5076                "".to_string()
5077            },
5078            self.url.borrow(),
5079            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
5080        );
5081
5082        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
5083        let valid_keys = {
5084            let mut invalid_keys = Vec::new();
5085            let valid_keys = keys_get(&self.create_connection_config(), filter)
5086                .map_err(|error| {
5087                    Error::Api(format!(
5088                        "Getting keys failed: {}",
5089                        NetHsmApiError::from(error)
5090                    ))
5091                })?
5092                .entity
5093                .into_iter()
5094                .filter_map(|x| {
5095                    if let Ok(key) = KeyId::new(x.id.clone()) {
5096                        Some(key)
5097                    } else {
5098                        invalid_keys.push(x.id);
5099                        None
5100                    }
5101                })
5102                .collect::<Vec<KeyId>>();
5103
5104            if !invalid_keys.is_empty() {
5105                return Err(key::Error::InvalidKeyIds {
5106                    key_ids: invalid_keys,
5107                }
5108                .into());
5109            }
5110
5111            valid_keys
5112        };
5113
5114        Ok(valid_keys)
5115    }
5116
5117    /// Gets the [public key of a key] on the NetHSM.
5118    ///
5119    /// Gets the [public key of a key] on the NetHSM, identified by `key_id`.
5120    /// The public key is returned in [X.509] Privacy-Enhanced Mail ([PEM]) format.
5121    ///
5122    /// This call requires using [`Credentials`] of a user in the
5123    /// [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`]
5124    /// [role].
5125    ///
5126    /// ## Namespaces
5127    ///
5128    /// * Users in a [namespace] can only get public keys of keys in their own [namespace].
5129    /// * System-wide users (not in a [namespace]) can only get public keys of system-wide keys.
5130    ///
5131    /// # Errors
5132    ///
5133    /// Returns an [`Error::Api`] if getting the public key fails:
5134    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
5135    /// * no key identified by `key_id` exists
5136    /// * the used [`Credentials`] are not correct
5137    /// * the used [`Credentials`] are not that of a user in the
5138    ///   [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`] [role]
5139    /// * the targeted key is a symmetric key (i.e. [`KeyType::Generic`]) and therefore can not
5140    ///   provide a public key
5141    ///
5142    /// # Examples
5143    ///
5144    /// ```no_run
5145    /// use nethsm::{
5146    ///     Connection,
5147    ///     ConnectionSecurity,
5148    ///     Credentials,
5149    ///     KeyMechanism,
5150    ///     KeyType,
5151    ///     NetHsm,
5152    ///     Passphrase,
5153    /// };
5154    ///
5155    /// # fn main() -> testresult::TestResult {
5156    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
5157    /// let nethsm = NetHsm::new(
5158    ///     Connection::new(
5159    ///         "https://example.org/api/v1".try_into()?,
5160    ///         ConnectionSecurity::Unsafe,
5161    ///     ),
5162    ///     Some(Credentials::new(
5163    ///         "admin".parse()?,
5164    ///         Some(Passphrase::new("passphrase".to_string())),
5165    ///     )),
5166    ///     None,
5167    ///     None,
5168    /// )?;
5169    /// // generate system-wide key with tag
5170    /// nethsm.generate_key(
5171    ///     KeyType::Curve25519,
5172    ///     vec![KeyMechanism::EdDsaSignature],
5173    ///     None,
5174    ///     Some("signing1".parse()?),
5175    ///     Some(vec!["tag1".to_string()]),
5176    /// )?;
5177    ///
5178    /// // get public key for a key with Key ID "signing1"
5179    /// println!("{:?}", nethsm.get_public_key(&"signing1".parse()?)?);
5180    /// # Ok(())
5181    /// # }
5182    /// ```
5183    /// [public key of a key]: https://docs.nitrokey.com/nethsm/operation#show-key-details
5184    /// [X.509]: https://en.wikipedia.org/wiki/X.509
5185    /// [PEM]: https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail
5186    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
5187    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
5188    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
5189    pub fn get_public_key(&self, key_id: &KeyId) -> Result<String, Error> {
5190        debug!(
5191            "Retrieve public key of key \"{key_id}\" from the NetHSM at {} using {}",
5192            self.url.borrow(),
5193            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
5194        );
5195
5196        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
5197        Ok(
5198            keys_key_id_public_pem_get(&self.create_connection_config(), key_id.as_ref())
5199                .map_err(|error| {
5200                    Error::Api(format!(
5201                        "Getting public key failed: {}",
5202                        NetHsmApiError::from(error)
5203                    ))
5204                })?
5205                .entity,
5206        )
5207    }
5208
5209    /// Adds a [tag for a key].
5210    ///
5211    /// Adds `tag` for a key, identified by `key_id`.
5212    ///
5213    /// A [tag for a key] is prerequisite to adding the same tag to a user in the
5214    /// [`Operator`][`UserRole::Operator`] [role] and thus granting it access to the key.
5215    ///
5216    /// This call requires using [`Credentials`] of a user in the
5217    /// [`Administrator`][`UserRole::Administrator`] [role].
5218    ///
5219    /// ## Namespaces
5220    ///
5221    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
5222    ///   [namespace]) are only able to tag keys in their own [namespace].
5223    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
5224    ///   only able to tag system-wide keys.
5225    ///
5226    /// # Errors
5227    ///
5228    /// Returns an [`Error::Api`] if adding a tag to a key fails:
5229    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
5230    /// * no key identified by `key_id` exists
5231    /// * `tag` is already associated with the key
5232    /// * `tag` is invalid
5233    /// * the used [`Credentials`] are not correct
5234    /// * the used [`Credentials`] are not that of a user in the
5235    ///   [`Administrator`][`UserRole::Administrator`] [role]
5236    /// * a key in a [namespace] is attempted to be tagged by an *R-Administrator*
5237    /// * a system-wide key is attempted to be tagged by an *N-Administrator*
5238    ///
5239    /// # Examples
5240    ///
5241    /// ```no_run
5242    /// use nethsm::{
5243    ///     Connection,
5244    ///     ConnectionSecurity,
5245    ///     Credentials,
5246    ///     KeyMechanism,
5247    ///     KeyType,
5248    ///     NetHsm,
5249    ///     Passphrase,
5250    /// };
5251    ///
5252    /// # fn main() -> testresult::TestResult {
5253    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
5254    /// let nethsm = NetHsm::new(
5255    ///     Connection::new(
5256    ///         "https://example.org/api/v1".try_into()?,
5257    ///         ConnectionSecurity::Unsafe,
5258    ///     ),
5259    ///     Some(Credentials::new(
5260    ///         "admin".parse()?,
5261    ///         Some(Passphrase::new("passphrase".to_string())),
5262    ///     )),
5263    ///     None,
5264    ///     None,
5265    /// )?;
5266    /// // generate system-wide key with tag
5267    /// nethsm.generate_key(
5268    ///     KeyType::Curve25519,
5269    ///     vec![KeyMechanism::EdDsaSignature],
5270    ///     None,
5271    ///     Some("signing1".parse()?),
5272    ///     Some(vec!["tag1".to_string()]),
5273    /// )?;
5274    ///
5275    /// // add the tag "important" to a key with Key ID "signing1"
5276    /// nethsm.add_key_tag(&"signing1".parse()?, "important")?;
5277    /// # Ok(())
5278    /// # }
5279    /// ```
5280    /// [tag for a key]: https://docs.nitrokey.com/nethsm/operation#tags-for-keys
5281    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
5282    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
5283    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
5284    pub fn add_key_tag(&self, key_id: &KeyId, tag: &str) -> Result<(), Error> {
5285        debug!(
5286            "Add tag \"{tag}\" to key \"{key_id}\" on the NetHSM at {} using {}",
5287            self.url.borrow(),
5288            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
5289        );
5290
5291        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
5292        keys_key_id_restrictions_tags_tag_put(
5293            &self.create_connection_config(),
5294            tag,
5295            key_id.as_ref(),
5296        )
5297        .map_err(|error| {
5298            Error::Api(format!(
5299                "Adding tag for key failed: {}",
5300                NetHsmApiError::from(error)
5301            ))
5302        })?;
5303        Ok(())
5304    }
5305
5306    /// Deletes a [tag from a key].
5307    ///
5308    /// Deletes `tag` from a key, identified by `key_id` on the NetHSM.
5309    ///
5310    /// Deleting a [tag from a key] removes access to it for any user in the
5311    /// [`Operator`][`UserRole::Operator`] [role], that carries the same tag.
5312    ///
5313    /// This call requires using [`Credentials`] of a user in the
5314    /// [`Administrator`][`UserRole::Administrator`] [role].
5315    ///
5316    /// ## Namespaces
5317    ///
5318    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
5319    ///   [namespace]) are only able to delete tags from keys in their own [namespace].
5320    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
5321    ///   only able to delete tags from system-wide keys.
5322    ///
5323    /// # Errors
5324    ///
5325    /// Returns an [`Error::Api`] if adding a tag to a key fails:
5326    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
5327    /// * no key identified by `key_id` exists
5328    /// * `tag` is not associated with the key
5329    /// * the used [`Credentials`] are not correct
5330    /// * the used [`Credentials`] are not that of a user in the
5331    ///   [`Administrator`][`UserRole::Administrator`] [role]
5332    /// * the tag for a key in a [namespace] is attempted to be removed by an *R-Administrator*
5333    /// * the tag for a system-wide key is attempted to be removed by an *N-Administrator*
5334    ///
5335    /// # Examples
5336    ///
5337    /// ```no_run
5338    /// use nethsm::{
5339    ///     Connection,
5340    ///     ConnectionSecurity,
5341    ///     Credentials,
5342    ///     KeyMechanism,
5343    ///     KeyType,
5344    ///     NetHsm,
5345    ///     Passphrase,
5346    /// };
5347    ///
5348    /// # fn main() -> testresult::TestResult {
5349    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
5350    /// let nethsm = NetHsm::new(
5351    ///     Connection::new(
5352    ///         "https://example.org/api/v1".try_into()?,
5353    ///         ConnectionSecurity::Unsafe,
5354    ///     ),
5355    ///     Some(Credentials::new(
5356    ///         "admin".parse()?,
5357    ///         Some(Passphrase::new("passphrase".to_string())),
5358    ///     )),
5359    ///     None,
5360    ///     None,
5361    /// )?;
5362    /// // generate system-wide key with tag
5363    /// nethsm.generate_key(
5364    ///     KeyType::Curve25519,
5365    ///     vec![KeyMechanism::EdDsaSignature],
5366    ///     None,
5367    ///     Some("signing1".parse()?),
5368    ///     Some(vec!["tag1".to_string(), "important".to_string()]),
5369    /// )?;
5370    ///
5371    /// // remove the tag "important" from a key with Key ID "signing1"
5372    /// nethsm.delete_key_tag(&"signing1".parse()?, "important")?;
5373    /// # Ok(())
5374    /// # }
5375    /// ```
5376    /// [tag from a key]: https://docs.nitrokey.com/nethsm/operation#tags-for-keys
5377    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
5378    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
5379    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
5380    pub fn delete_key_tag(&self, key_id: &KeyId, tag: &str) -> Result<(), Error> {
5381        debug!(
5382            "Delete tag \"{tag}\" from key \"{key_id}\" on the NetHSM at {} using {}",
5383            self.url.borrow(),
5384            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
5385        );
5386
5387        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
5388        keys_key_id_restrictions_tags_tag_delete(
5389            &self.create_connection_config(),
5390            tag,
5391            key_id.as_ref(),
5392        )
5393        .map_err(|error| {
5394            Error::Api(format!(
5395                "Deleting tag for key failed: {}",
5396                NetHsmApiError::from(error)
5397            ))
5398        })?;
5399        Ok(())
5400    }
5401
5402    /// Imports a [certificate for a key].
5403    ///
5404    /// Imports a [certificate for a key] identified by `key_id`.
5405    /// Certificates up to 1 MiB in size are supported.
5406    /// **NOTE**: The imported bytes are not validated!
5407    ///
5408    /// This call requires using [`Credentials`] of a user in the
5409    /// [`Administrator`][`UserRole::Administrator`] [role].
5410    ///
5411    /// ## Namespaces
5412    ///
5413    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
5414    ///   [namespace]) are only able to import certificates for keys in their own [namespace].
5415    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
5416    ///   only able to import certificates for system-wide keys.
5417    ///
5418    /// # Errors
5419    ///
5420    /// Returns an [`Error::Api`] if importing a [certificate for a key] fails:
5421    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
5422    /// * no key identified by `key_id` exists
5423    /// * the `data` is invalid
5424    /// * the used [`Credentials`] are not correct
5425    /// * the used [`Credentials`] are not that of a user in the
5426    ///   [`Administrator`][`UserRole::Administrator`] [role]
5427    ///
5428    /// # Examples
5429    ///
5430    /// ```no_run
5431    /// use std::time::SystemTime;
5432    /// use nethsm::{
5433    ///     Connection,
5434    ///     ConnectionSecurity,
5435    ///     Credentials,
5436    ///     KeyMechanism,
5437    ///     KeyType,
5438    ///     NetHsm,
5439    ///     OpenPgpKeyUsageFlags,
5440    ///     OpenPgpVersion,
5441    ///     Passphrase,
5442    ///     UserRole,
5443    /// };
5444    ///
5445    /// # fn main() -> testresult::TestResult {
5446    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
5447    /// let nethsm = NetHsm::new(
5448    ///     Connection::new(
5449    ///         "https://example.org/api/v1".try_into()?,
5450    ///         ConnectionSecurity::Unsafe,
5451    ///     ),
5452    ///     Some(Credentials::new(
5453    ///         "admin".parse()?,
5454    ///         Some(Passphrase::new("passphrase".to_string())),
5455    ///     )),
5456    ///     None,
5457    ///     None,
5458    /// )?;
5459    /// // add a system-wide user in the Operator role
5460    /// nethsm.add_user(
5461    ///     "Operator1".to_string(),
5462    ///     UserRole::Operator,
5463    ///     Passphrase::new("operator-passphrase".to_string()),
5464    ///     Some("operator1".parse()?),
5465    /// )?;
5466    /// // generate system-wide key with tag
5467    /// nethsm.generate_key(
5468    ///     KeyType::Curve25519,
5469    ///     vec![KeyMechanism::EdDsaSignature],
5470    ///     None,
5471    ///     Some("signing1".parse()?),
5472    ///     Some(vec!["tag1".to_string()]),
5473    /// )?;
5474    /// // tag system-wide user in Operator role for access to signing key
5475    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
5476    /// // use the Operator credentials to create an OpenPGP certificate for a key
5477    /// nethsm.use_credentials(&"operator1".parse()?)?;
5478    /// let openpgp_cert = nethsm.create_openpgp_cert(
5479    ///     &"signing1".parse()?,
5480    ///     OpenPgpKeyUsageFlags::default(),
5481    ///     "Test <test@example.org>".parse()?,
5482    ///     SystemTime::now().into(),
5483    ///     OpenPgpVersion::V4,
5484    /// )?;
5485    ///
5486    /// // use the Administrator credentials to import the OpenPGP certificate as certificate for the key
5487    /// nethsm.use_credentials(&"admin".parse()?)?;
5488    /// assert!(nethsm.get_key_certificate(&"signing1".parse()?).is_err());
5489    /// nethsm.import_key_certificate(&"signing1".parse()?, openpgp_cert)?;
5490    /// assert!(nethsm.get_key_certificate(&"signing1".parse()?).is_ok());
5491    /// # Ok(())
5492    /// # }
5493    /// ```
5494    /// [certificate for a key]: https://docs.nitrokey.com/nethsm/operation#key-certificates
5495    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
5496    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
5497    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
5498    pub fn import_key_certificate(&self, key_id: &KeyId, data: Vec<u8>) -> Result<(), Error> {
5499        debug!(
5500            "Import certificate for key \"{key_id}\" on the NetHSM at {} using {}",
5501            self.url.borrow(),
5502            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
5503        );
5504
5505        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
5506        keys_key_id_cert_put(&self.create_connection_config(), key_id.as_ref(), data).map_err(
5507            |error| {
5508                Error::Api(format!(
5509                    "Importing certificate for key failed: {}",
5510                    NetHsmApiError::from(error)
5511                ))
5512            },
5513        )?;
5514        Ok(())
5515    }
5516
5517    /// Gets the [certificate for a key].
5518    ///
5519    /// Gets the [certificate for a key] identified by `key_id` and returns it as a byte vector.
5520    /// Returns [`None`] if no certificate is associated with a key identified by `key_id`.
5521    ///
5522    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
5523    /// or [`Administrator`][`UserRole::Administrator`] [role].
5524    ///
5525    /// ## Namespaces
5526    ///
5527    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
5528    ///   [namespace]) are only able to get certificates for keys in their own [namespace].
5529    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
5530    ///   only able to get certificates for system-wide keys.
5531    ///
5532    /// # Errors
5533    ///
5534    /// Returns an [`Error::Api`] if getting the [certificate for a key] fails:
5535    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
5536    /// * no key identified by `key_id` exists
5537    /// * the used [`Credentials`] are not correct
5538    /// * the used [`Credentials`] are not those of a user in the [`Operator`][`UserRole::Operator`]
5539    ///   or [`Administrator`][`UserRole::Administrator`] [role]
5540    ///
5541    /// # Examples
5542    ///
5543    /// ```no_run
5544    /// use std::time::SystemTime;
5545    /// use nethsm::{
5546    ///     Connection,
5547    ///     ConnectionSecurity,
5548    ///     Credentials,
5549    ///     KeyMechanism,
5550    ///     KeyType,
5551    ///     NetHsm,
5552    ///     OpenPgpKeyUsageFlags,
5553    ///     OpenPgpVersion,
5554    ///     Passphrase,
5555    ///     UserRole,
5556    /// };
5557    ///
5558    /// # fn main() -> testresult::TestResult {
5559    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
5560    /// let nethsm = NetHsm::new(
5561    ///     Connection::new(
5562    ///         "https://example.org/api/v1".try_into()?,
5563    ///         ConnectionSecurity::Unsafe,
5564    ///     ),
5565    ///     Some(Credentials::new(
5566    ///         "admin".parse()?,
5567    ///         Some(Passphrase::new("passphrase".to_string())),
5568    ///     )),
5569    ///     None,
5570    ///     None,
5571    /// )?;
5572    /// // add a system-wide user in the Operator role
5573    /// nethsm.add_user(
5574    ///     "Operator1".to_string(),
5575    ///     UserRole::Operator,
5576    ///     Passphrase::new("operator-passphrase".to_string()),
5577    ///     Some("operator1".parse()?),
5578    /// )?;
5579    /// // generate system-wide key with tag
5580    /// nethsm.generate_key(
5581    ///     KeyType::Curve25519,
5582    ///     vec![KeyMechanism::EdDsaSignature],
5583    ///     None,
5584    ///     Some("signing1".parse()?),
5585    ///     Some(vec!["tag1".to_string()]),
5586    /// )?;
5587    /// // tag system-wide user in Operator role for access to signing key
5588    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
5589    /// // use the Operator credentials to create an OpenPGP certificate for a key
5590    /// nethsm.use_credentials(&"operator1".parse()?)?;
5591    /// let openpgp_cert = nethsm.create_openpgp_cert(
5592    ///     &"signing1".parse()?,
5593    ///     OpenPgpKeyUsageFlags::default(),
5594    ///     "Test <test@example.org>".parse()?,
5595    ///     SystemTime::now().into(),
5596    ///     OpenPgpVersion::V4,
5597    /// )?;
5598    /// // use the Administrator credentials to import the OpenPGP certificate as certificate for the key
5599    /// nethsm.use_credentials(&"admin".parse()?)?;
5600    /// nethsm.import_key_certificate(&"signing1".parse()?, openpgp_cert)?;
5601    ///
5602    /// // get the certificate associated with a key
5603    /// println!("{:?}", nethsm.get_key_certificate(&"signing1".parse()?)?);
5604    /// # Ok(())
5605    /// # }
5606    /// ```
5607    /// [certificate for a key]: https://docs.nitrokey.com/nethsm/operation#key-certificates
5608    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
5609    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
5610    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
5611    pub fn get_key_certificate(&self, key_id: &KeyId) -> Result<Option<Vec<u8>>, Error> {
5612        debug!(
5613            "Retrieve the certificate of the key \"{key_id}\" on the NetHSM at {} using {}",
5614            self.url.borrow(),
5615            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
5616        );
5617
5618        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
5619        match keys_key_id_cert_get(&self.create_connection_config(), key_id.as_ref()) {
5620            Ok(response) => Ok(Some(response.entity)),
5621            Err(nethsm_sdk_rs::apis::Error::ResponseError(error)) if error.status == 404 => {
5622                Ok(None)
5623            }
5624            Err(error) => Err(Error::Api(format!(
5625                "Getting certificate for key failed: {}",
5626                NetHsmApiError::from(error)
5627            ))),
5628        }
5629    }
5630
5631    /// Deletes the [certificate for a key].
5632    ///
5633    /// Deletes the [certificate for a key] identified by `key_id`.
5634    ///
5635    /// This call requires using [`Credentials`] of a user in the
5636    /// [`Administrator`][`UserRole::Administrator`] [role].
5637    ///
5638    /// ## Namespaces
5639    ///
5640    /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
5641    ///   [namespace]) are only able to delete certificates for keys in their own [namespace].
5642    /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
5643    ///   only able to delete certificates for system-wide keys.
5644    ///
5645    /// # Errors
5646    ///
5647    /// Returns an [`Error::Api`] if deleting the [certificate for a key] fails:
5648    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
5649    /// * no key identified by `key_id` exists
5650    /// * no certificate is associated with the key
5651    /// * the used [`Credentials`] are not correct
5652    /// * the used [`Credentials`] are not that of a user in the
5653    ///   [`Administrator`][`UserRole::Administrator`] [role]
5654    ///
5655    /// # Examples
5656    ///
5657    /// ```no_run
5658    /// use std::time::SystemTime;
5659    /// use nethsm::{
5660    ///     Connection,
5661    ///     ConnectionSecurity,
5662    ///     Credentials,
5663    ///     KeyMechanism,
5664    ///     KeyType,
5665    ///     NetHsm,
5666    ///     OpenPgpKeyUsageFlags,
5667    ///     OpenPgpVersion,
5668    ///     Passphrase,
5669    ///     UserRole,
5670    /// };
5671    ///
5672    /// # fn main() -> testresult::TestResult {
5673    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
5674    /// let nethsm = NetHsm::new(
5675    ///     Connection::new(
5676    ///         "https://example.org/api/v1".try_into()?,
5677    ///         ConnectionSecurity::Unsafe,
5678    ///     ),
5679    ///     Some(Credentials::new(
5680    ///         "admin".parse()?,
5681    ///         Some(Passphrase::new("passphrase".to_string())),
5682    ///     )),
5683    ///     None,
5684    ///     None,
5685    /// )?;
5686    /// // add a system-wide user in the Operator role
5687    /// nethsm.add_user(
5688    ///     "Operator1".to_string(),
5689    ///     UserRole::Operator,
5690    ///     Passphrase::new("operator-passphrase".to_string()),
5691    ///     Some("operator1".parse()?),
5692    /// )?;
5693    /// // generate system-wide key with tag
5694    /// nethsm.generate_key(
5695    ///     KeyType::Curve25519,
5696    ///     vec![KeyMechanism::EdDsaSignature],
5697    ///     None,
5698    ///     Some("signing1".parse()?),
5699    ///     Some(vec!["tag1".to_string()]),
5700    /// )?;
5701    /// // tag system-wide user in Operator role for access to signing key
5702    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
5703    /// // use the Operator credentials to create an OpenPGP certificate for a key
5704    /// nethsm.use_credentials(&"operator1".parse()?)?;
5705    /// let openpgp_cert = nethsm.create_openpgp_cert(
5706    ///     &"signing1".parse()?,
5707    ///     OpenPgpKeyUsageFlags::default(),
5708    ///     "Test <test@example.org>".parse()?,
5709    ///     SystemTime::now().into(),
5710    ///     OpenPgpVersion::V4,
5711    /// )?;
5712    /// // use the Administrator credentials to import the OpenPGP certificate as certificate for the key
5713    /// nethsm.use_credentials(&"admin".parse()?)?;
5714    /// nethsm.import_key_certificate(&"signing1".parse()?, openpgp_cert)?;
5715    ///
5716    /// // delete a certificate for a key with Key ID "signing1"
5717    /// assert!(nethsm.delete_key_certificate(&"signing1".parse()?).is_ok());
5718    /// nethsm.delete_key_certificate(&"signing1".parse()?)?;
5719    /// assert!(nethsm.delete_key_certificate(&"signing1".parse()?).is_err());
5720    /// # Ok(())
5721    /// # }
5722    /// ```
5723    /// [certificate for a key]: https://docs.nitrokey.com/nethsm/operation#key-certificates
5724    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
5725    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
5726    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
5727    pub fn delete_key_certificate(&self, key_id: &KeyId) -> Result<(), Error> {
5728        debug!(
5729            "Delete the certificate for the key \"{key_id}\" on the NetHSM at {} using {}",
5730            self.url.borrow(),
5731            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
5732        );
5733
5734        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
5735        keys_key_id_cert_delete(&self.create_connection_config(), key_id.as_ref()).map_err(
5736            |error| {
5737                Error::Api(format!(
5738                    "Deleting certificate for key failed: {}",
5739                    NetHsmApiError::from(error)
5740                ))
5741            },
5742        )?;
5743        Ok(())
5744    }
5745
5746    /// Gets a [Certificate Signing Request for a key].
5747    ///
5748    /// Returns a Certificate Signing Request ([CSR]) for a key, identified by `key_id` in [PKCS#10]
5749    /// format based on a provided [`DistinguishedName`].
5750    ///
5751    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
5752    /// or [`Administrator`][`UserRole::Administrator`] [role].
5753    ///
5754    /// ## Namespaces
5755    ///
5756    /// * Users in a [namespace] only have access to keys in their own [namespace]
5757    /// * System-wide users only have access to system-wide keys (not in a [namespace]).
5758    ///
5759    /// # Errors
5760    ///
5761    /// Returns an [`Error::Api`] if getting a CSR for a key fails:
5762    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
5763    /// * no key identified by `key_id` exists
5764    /// * the used [`Credentials`] are not correct
5765    /// * the used [`Credentials`] are not those of a user in the [`Operator`][`UserRole::Operator`]
5766    ///   or [`Administrator`][`UserRole::Administrator`] [role]
5767    ///
5768    /// # Examples
5769    ///
5770    /// ```no_run
5771    /// use nethsm::{
5772    ///     Connection,
5773    ///     ConnectionSecurity,
5774    ///     Credentials,
5775    ///     DistinguishedName,
5776    ///     KeyMechanism,
5777    ///     KeyType,
5778    ///     NetHsm,
5779    ///     Passphrase,
5780    /// };
5781    ///
5782    /// # fn main() -> testresult::TestResult {
5783    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
5784    /// let nethsm = NetHsm::new(
5785    ///     Connection::new(
5786    ///         "https://example.org/api/v1".try_into()?,
5787    ///         ConnectionSecurity::Unsafe,
5788    ///     ),
5789    ///     Some(Credentials::new(
5790    ///         "admin".parse()?,
5791    ///         Some(Passphrase::new("passphrase".to_string())),
5792    ///     )),
5793    ///     None,
5794    ///     None,
5795    /// )?;
5796    /// // generate system-wide key with tag
5797    /// nethsm.generate_key(
5798    ///     KeyType::Curve25519,
5799    ///     vec![KeyMechanism::EdDsaSignature],
5800    ///     None,
5801    ///     Some("signing1".parse()?),
5802    ///     Some(vec!["tag1".to_string()]),
5803    /// )?;
5804    ///
5805    /// // get a CSR for a key
5806    /// println!(
5807    ///     "{}",
5808    ///     nethsm.get_key_csr(
5809    ///         &"signing1".parse()?,
5810    ///         DistinguishedName {
5811    ///             country_name: Some("DE".to_string()),
5812    ///             state_or_province_name: Some("Berlin".to_string()),
5813    ///             locality_name: Some("Berlin".to_string()),
5814    ///             organization_name: Some("Foobar Inc".to_string()),
5815    ///             organizational_unit_name: Some("Department of Foo".to_string()),
5816    ///             common_name: "Foobar Inc".to_string(),
5817    ///             email_address: Some("foobar@mcfooface.com".to_string()),
5818    ///         }
5819    ///     )?
5820    /// );
5821    /// # Ok(())
5822    /// # }
5823    /// ```
5824    /// [Certificate Signing Request for a key]: https://docs.nitrokey.com/nethsm/operation#key-certificate-signing-requests
5825    /// [CSR]: https://en.wikipedia.org/wiki/Certificate_signing_request
5826    /// [PKCS#10]: https://en.wikipedia.org/wiki/Certificate_signing_request#Structure_of_a_PKCS_#10_CSR
5827    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
5828    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
5829    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
5830    pub fn get_key_csr(
5831        &self,
5832        key_id: &KeyId,
5833        distinguished_name: DistinguishedName,
5834    ) -> Result<String, Error> {
5835        debug!(
5836            "Retrieve a Certificate Signing Request ({}) for the key \"{key_id}\" on the NetHSM at {} using {}",
5837            distinguished_name.common_name,
5838            self.url.borrow(),
5839            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
5840        );
5841
5842        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
5843        Ok(keys_key_id_csr_pem_post(
5844            &self.create_connection_config(),
5845            key_id.as_ref(),
5846            distinguished_name,
5847        )
5848        .map_err(|error| {
5849            Error::Api(format!(
5850                "Getting CSR for key failed: {}",
5851                NetHsmApiError::from(error)
5852            ))
5853        })?
5854        .entity)
5855    }
5856
5857    /// [Signs] a digest using a key.
5858    ///
5859    /// [Signs] a `digest` using a key identified by `key_id`.
5860    ///
5861    /// **NOTE**: This function offers low-level access for signing [digests]. Use
5862    /// [`sign`][`NetHsm::sign`] for signing a message.
5863    ///
5864    /// The `digest` must be of appropriate type depending on `signature_type`:
5865    /// * [`SignatureType::Pkcs1`], [`SignatureType::PssSha256`] and [`SignatureType::EcdsaP256`]
5866    ///   require a [SHA-256] digest
5867    /// * [`SignatureType::PssMd5`] requires an [MD5] digest
5868    /// * [`SignatureType::PssSha1`] requires a [SHA-1] digest
5869    /// * [`SignatureType::PssSha224`] and [`SignatureType::EcdsaP224`] require a [SHA-224] digest
5870    /// * [`SignatureType::PssSha384`] and [`SignatureType::EcdsaP384`] require a [SHA-384] digest
5871    /// * [`SignatureType::PssSha512`] and [`SignatureType::EcdsaP521`] require a [SHA-521] digest
5872    /// * [`SignatureType::EdDsa`] requires no digest (`digest` is the message)
5873    ///
5874    /// The returned data depends on the chosen [`SignatureType`]:
5875    ///
5876    /// * [`SignatureType::Pkcs1`] returns the [PKCS 1] padded signature (no signature algorithm OID
5877    ///   prepended, since the used hash is not known).
5878    /// * [`SignatureType::PssMd5`], [`SignatureType::PssSha1`], [`SignatureType::PssSha224`],
5879    ///   [`SignatureType::PssSha256`], [`SignatureType::PssSha384`] and
5880    ///   [`SignatureType::PssSha512`] return the [EMSA-PSS] encoded signature.
5881    /// * [`SignatureType::EdDsa`] returns the encoding as specified in [RFC 8032 (5.1.6)] (`r`
5882    ///   appended with `s` (each 32 bytes), in total 64 bytes).
5883    /// * [`SignatureType::EcdsaP224`], [`SignatureType::EcdsaP256`], [`SignatureType::EcdsaP384`]
5884    ///   and [`SignatureType::EcdsaP521`] return the [ASN.1] [DER] encoded signature (a sequence of
5885    ///   integer `r` and integer `s`).
5886    ///
5887    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
5888    /// [role], which carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one
5889    /// of the tags of the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
5890    ///
5891    /// ## Namespaces
5892    ///
5893    /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
5894    ///   their own [namespace].
5895    /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
5896    ///
5897    /// # Errors
5898    ///
5899    /// Returns an [`Error::Api`] if signing the `digest` fails:
5900    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
5901    /// * no key identified by `key_id` exists on the NetHSM
5902    /// * the chosen [`SignatureType`] is incompatible with the targeted key
5903    /// * the chosen `digest` is incompatible with the [`SignatureType`]
5904    /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
5905    ///   different [namespace])
5906    /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
5907    ///   tags
5908    /// * the used [`Credentials`] are not correct
5909    /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
5910    ///   [role]
5911    ///
5912    /// # Examples
5913    ///
5914    /// ```no_run
5915    /// use nethsm::{
5916    ///     Connection,
5917    ///     ConnectionSecurity,
5918    ///     Credentials,
5919    ///     KeyMechanism,
5920    ///     KeyType,
5921    ///     NetHsm,
5922    ///     Passphrase,
5923    ///     SignatureType,
5924    ///     UserRole,
5925    /// };
5926    ///
5927    /// # fn main() -> testresult::TestResult {
5928    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
5929    /// let nethsm = NetHsm::new(
5930    ///     Connection::new(
5931    ///         "https://example.org/api/v1".try_into()?,
5932    ///         ConnectionSecurity::Unsafe,
5933    ///     ),
5934    ///     Some(Credentials::new(
5935    ///         "admin".parse()?,
5936    ///         Some(Passphrase::new("passphrase".to_string())),
5937    ///     )),
5938    ///     None,
5939    ///     None,
5940    /// )?;
5941    /// // add a system-wide user in the Operator role
5942    /// nethsm.add_user(
5943    ///     "Operator1".to_string(),
5944    ///     UserRole::Operator,
5945    ///     Passphrase::new("operator-passphrase".to_string()),
5946    ///     Some("operator1".parse()?),
5947    /// )?;
5948    /// // generate system-wide key with tag
5949    /// nethsm.generate_key(
5950    ///     KeyType::Curve25519,
5951    ///     vec![KeyMechanism::EdDsaSignature],
5952    ///     None,
5953    ///     Some("signing1".parse()?),
5954    ///     Some(vec!["tag1".to_string()]),
5955    /// )?;
5956    /// // tag system-wide user in Operator role for access to signing key
5957    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
5958    ///
5959    /// // create an ed25519 signature
5960    /// nethsm.use_credentials(&"operator1".parse()?)?;
5961    /// println!(
5962    ///     "{:?}",
5963    ///     nethsm.sign_digest(&"signing1".parse()?, SignatureType::EdDsa, &[0, 1, 2])?
5964    /// );
5965    /// # Ok(())
5966    /// # }
5967    /// ```
5968    /// [Signs]: https://docs.nitrokey.com/nethsm/operation#sign
5969    /// [digests]: https://en.wikipedia.org/wiki/Cryptographic_hash_function
5970    /// [SHA-256]: https://en.wikipedia.org/wiki/SHA-2
5971    /// [MD5]: https://en.wikipedia.org/wiki/MD5
5972    /// [SHA-1]: https://en.wikipedia.org/wiki/SHA-1
5973    /// [SHA-224]: https://en.wikipedia.org/wiki/SHA-2
5974    /// [SHA-384]: https://en.wikipedia.org/wiki/SHA-2
5975    /// [SHA-521]: https://en.wikipedia.org/wiki/SHA-2
5976    /// [PKCS 1]: https://en.wikipedia.org/wiki/PKCS_1
5977    /// [EMSA-PSS]: https://en.wikipedia.org/wiki/PKCS_1
5978    /// [RFC 8032 (5.1.6)]: https://www.rfc-editor.org/rfc/rfc8032#section-5.1.6
5979    /// [ASN.1]: https://en.wikipedia.org/wiki/ASN.1
5980    /// [DER]: https://en.wikipedia.org/wiki/X.690#DER_encoding
5981    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
5982    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
5983    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
5984    pub fn sign_digest(
5985        &self,
5986        key_id: &KeyId,
5987        signature_type: SignatureType,
5988        digest: &[u8],
5989    ) -> Result<Vec<u8>, Error> {
5990        debug!(
5991            "Sign a digest (signature type: {signature_type}) with the key \"{key_id}\" on the NetHSM at {} using {}",
5992            self.url.borrow(),
5993            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
5994        );
5995
5996        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
5997        // decode base64 encoded data from the API
5998        Base64::decode_vec(
5999            &keys_key_id_sign_post(
6000                &self.create_connection_config(),
6001                key_id.as_ref(),
6002                SignRequestData::new(signature_type.into(), Base64::encode_string(digest)),
6003            )
6004            .map_err(|error| {
6005                Error::Api(format!(
6006                    "Signing message failed: {}",
6007                    NetHsmApiError::from(error)
6008                ))
6009            })?
6010            .entity
6011            .signature,
6012        )
6013        .map_err(Error::Base64Decode)
6014    }
6015
6016    /// [Signs] a message using a key.
6017    ///
6018    /// [Signs] a `message` using a key identified by `key_id` based on a specific `signature_type`.
6019    ///
6020    /// The `message` should not be [hashed], as this function takes care of it based on the
6021    /// provided [`SignatureType`]. For lower level access, see
6022    /// [`sign_digest`][`NetHsm::sign_digest`].
6023    ///
6024    /// The returned data depends on the chosen [`SignatureType`]:
6025    ///
6026    /// * [`SignatureType::Pkcs1`] returns the [PKCS 1] padded signature (no signature algorithm OID
6027    ///   prepended, since the used hash is not known).
6028    /// * [`SignatureType::PssMd5`], [`SignatureType::PssSha1`], [`SignatureType::PssSha224`],
6029    ///   [`SignatureType::PssSha256`], [`SignatureType::PssSha384`] and
6030    ///   [`SignatureType::PssSha512`] return the [EMSA-PSS] encoded signature.
6031    /// * [`SignatureType::EdDsa`] returns the encoding as specified in [RFC 8032 (5.1.6)] (`r`
6032    ///   appended with `s` (each 32 bytes), in total 64 bytes).
6033    /// * [`SignatureType::EcdsaP224`], [`SignatureType::EcdsaP256`], [`SignatureType::EcdsaP384`]
6034    ///   and [`SignatureType::EcdsaP521`] return the [ASN.1] [DER] encoded signature (a sequence of
6035    ///   integer `r` and integer `s`).
6036    ///
6037    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
6038    /// [role], which carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one
6039    /// of the tags of the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
6040    ///
6041    /// ## Namespaces
6042    ///
6043    /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
6044    ///   their own [namespace].
6045    /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
6046    ///
6047    /// # Errors
6048    ///
6049    /// Returns an [`Error::Api`] if signing the `message` fails:
6050    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
6051    /// * no key identified by `key_id` exists on the NetHSM
6052    /// * the chosen [`SignatureType`] is incompatible with the targeted key
6053    /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
6054    ///   different [namespace])
6055    /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
6056    ///   tags
6057    /// * the used [`Credentials`] are not correct
6058    /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
6059    ///   [role]
6060    ///
6061    /// # Examples
6062    ///
6063    /// ```no_run
6064    /// use nethsm::{
6065    ///     Connection,
6066    ///     ConnectionSecurity,
6067    ///     Credentials,
6068    ///     KeyMechanism,
6069    ///     KeyType,
6070    ///     NetHsm,
6071    ///     Passphrase,
6072    ///     SignatureType,
6073    ///     UserRole,
6074    /// };
6075    ///
6076    /// # fn main() -> testresult::TestResult {
6077    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
6078    /// let nethsm = NetHsm::new(
6079    ///     Connection::new(
6080    ///         "https://example.org/api/v1".try_into()?,
6081    ///         ConnectionSecurity::Unsafe,
6082    ///     ),
6083    ///     Some(Credentials::new(
6084    ///         "admin".parse()?,
6085    ///         Some(Passphrase::new("passphrase".to_string())),
6086    ///     )),
6087    ///     None,
6088    ///     None,
6089    /// )?;
6090    /// // add a system-wide user in the Operator role
6091    /// nethsm.add_user(
6092    ///     "Operator1".to_string(),
6093    ///     UserRole::Operator,
6094    ///     Passphrase::new("operator-passphrase".to_string()),
6095    ///     Some("operator1".parse()?),
6096    /// )?;
6097    /// // generate system-wide key with tag
6098    /// nethsm.generate_key(
6099    ///     KeyType::Curve25519,
6100    ///     vec![KeyMechanism::EdDsaSignature],
6101    ///     None,
6102    ///     Some("signing1".parse()?),
6103    ///     Some(vec!["tag1".to_string()]),
6104    /// )?;
6105    /// // tag system-wide user in Operator role for access to signing key
6106    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
6107    ///
6108    /// // create an ed25519 signature
6109    /// println!(
6110    ///     "{:?}",
6111    ///     nethsm.sign(&"signing1".parse()?, SignatureType::EdDsa, b"message")?
6112    /// );
6113    /// # Ok(())
6114    /// # }
6115    /// ```
6116    /// [Signs]: https://docs.nitrokey.com/nethsm/operation#sign
6117    /// [hashed]: https://en.wikipedia.org/wiki/Cryptographic_hash_function
6118    /// [PKCS 1]: https://en.wikipedia.org/wiki/PKCS_1
6119    /// [EMSA-PSS]: https://en.wikipedia.org/wiki/PKCS_1
6120    /// [RFC 8032 (5.1.6)]: https://www.rfc-editor.org/rfc/rfc8032#section-5.1.6
6121    /// [ASN.1]: https://en.wikipedia.org/wiki/ASN.1
6122    /// [DER]: https://en.wikipedia.org/wiki/X.690#DER_encoding
6123    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
6124    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
6125    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
6126    pub fn sign(
6127        &self,
6128        key_id: &KeyId,
6129        signature_type: SignatureType,
6130        message: &[u8],
6131    ) -> Result<Vec<u8>, Error> {
6132        debug!(
6133            "Sign a message (signature type: {signature_type}) with the key \"{key_id}\" on the NetHSM at {} using {}",
6134            self.url.borrow(),
6135            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
6136        );
6137
6138        // Some algorithms require the data to be hashed first
6139        // The API requires data to be base64 encoded
6140        let message = match signature_type {
6141            SignatureType::Pkcs1 | SignatureType::PssSha256 | SignatureType::EcdsaP256 => {
6142                let mut hasher = Sha256::new();
6143                hasher.update(message);
6144                &hasher.finalize()[..]
6145            }
6146            SignatureType::PssMd5 => {
6147                let mut hasher = Md5::new();
6148                hasher.update(message);
6149                &hasher.finalize()[..]
6150            }
6151            SignatureType::PssSha1 => {
6152                let mut hasher = Sha1::new();
6153                hasher.update(message);
6154                &hasher.finalize()[..]
6155            }
6156            SignatureType::PssSha224 | SignatureType::EcdsaP224 => {
6157                let mut hasher = Sha224::new();
6158                hasher.update(message);
6159                &hasher.finalize()[..]
6160            }
6161            SignatureType::PssSha384 | SignatureType::EcdsaP384 => {
6162                let mut hasher = Sha384::new();
6163                hasher.update(message);
6164                &hasher.finalize()[..]
6165            }
6166            SignatureType::PssSha512 | SignatureType::EcdsaP521 => {
6167                let mut hasher = Sha512::new();
6168                hasher.update(message);
6169                &hasher.finalize()[..]
6170            }
6171            SignatureType::EdDsa => message,
6172        };
6173
6174        self.sign_digest(key_id, signature_type, message)
6175    }
6176
6177    /// [Encrypts] a message using a [symmetric key].
6178    ///
6179    /// [Encrypts] a `message` using a [symmetric key] identified by `key_id`, a specific
6180    /// [`EncryptMode`] `mode` and initialization vector `iv`.
6181    ///
6182    /// The targeted key must be of type [`KeyType::Generic`] and feature the mechanisms
6183    /// [`KeyMechanism::AesDecryptionCbc`] and [`KeyMechanism::AesEncryptionCbc`].
6184    ///
6185    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
6186    /// [role], which carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one
6187    /// of the tags of the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
6188    ///
6189    /// ## Namespaces
6190    ///
6191    /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
6192    ///   their own [namespace].
6193    /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
6194    ///
6195    /// # Errors
6196    ///
6197    /// Returns an [`Error::Api`] if encrypting the `message` fails:
6198    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
6199    /// * no key identified by `key_id` exists on the NetHSM
6200    /// * the chosen `mode` is incompatible with the targeted key
6201    /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
6202    ///   different [namespace])
6203    /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
6204    ///   tags
6205    /// * the used [`Credentials`] are not correct
6206    /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
6207    ///   [role]
6208    ///
6209    /// # Examples
6210    ///
6211    /// ```no_run
6212    /// use nethsm::{
6213    ///     Connection,
6214    ///     ConnectionSecurity,
6215    ///     Credentials,
6216    ///     EncryptMode,
6217    ///     KeyMechanism,
6218    ///     KeyType,
6219    ///     NetHsm,
6220    ///     Passphrase,
6221    ///     UserRole,
6222    /// };
6223    ///
6224    /// # fn main() -> testresult::TestResult {
6225    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
6226    /// let nethsm = NetHsm::new(
6227    ///     Connection::new(
6228    ///         "https://example.org/api/v1".try_into()?,
6229    ///         ConnectionSecurity::Unsafe,
6230    ///     ),
6231    ///     Some(Credentials::new(
6232    ///         "admin".parse()?,
6233    ///         Some(Passphrase::new("passphrase".to_string())),
6234    ///     )),
6235    ///     None,
6236    ///     None,
6237    /// )?;
6238    /// // add a system-wide user in the Operator role
6239    /// nethsm.add_user(
6240    ///     "Operator1".to_string(),
6241    ///     UserRole::Operator,
6242    ///     Passphrase::new("operator-passphrase".to_string()),
6243    ///     Some("operator1".parse()?),
6244    /// )?;
6245    /// // generate system-wide key with tag
6246    /// nethsm.generate_key(
6247    ///     KeyType::Generic,
6248    ///     vec![KeyMechanism::AesDecryptionCbc, KeyMechanism::AesEncryptionCbc],
6249    ///     Some(128),
6250    ///     Some("encryption1".parse()?),
6251    ///     Some(vec!["tag1".to_string()]),
6252    /// )?;
6253    /// // tag system-wide user in Operator role for access to signing key
6254    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
6255    ///
6256    /// // assuming we have an AES128 encryption key, the message must be a multiple of 32 bytes long
6257    /// let message = b"Hello World! This is a message!!";
6258    /// // we have an AES128 encryption key. the initialization vector must be a multiple of 16 bytes long
6259    /// let iv = b"This is unsafe!!";
6260    ///
6261    /// // encrypt message using
6262    /// println!(
6263    ///     "{:?}",
6264    ///     nethsm.encrypt(&"encryption1".parse()?, EncryptMode::AesCbc, message, Some(iv))?
6265    /// );
6266    /// # Ok(())
6267    /// # }
6268    /// ```
6269    /// [Encrypts]: https://docs.nitrokey.com/nethsm/operation#encrypt
6270    /// [symmetric key]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm
6271    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
6272    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
6273    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
6274    pub fn encrypt(
6275        &self,
6276        key_id: &KeyId,
6277        mode: EncryptMode,
6278        message: &[u8],
6279        iv: Option<&[u8]>,
6280    ) -> Result<Vec<u8>, Error> {
6281        debug!(
6282            "Encrypt a message (encrypt mode: {mode}) with the key \"{key_id}\" on the NetHSM at {} using {}",
6283            self.url.borrow(),
6284            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
6285        );
6286
6287        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
6288        // the API requires data to be base64 encoded
6289        let message = Base64::encode_string(message);
6290        let iv = iv.map(Base64::encode_string);
6291
6292        // decode base64 encoded data from the API
6293        Base64::decode_vec(
6294            &keys_key_id_encrypt_post(
6295                &self.create_connection_config(),
6296                key_id.as_ref(),
6297                EncryptRequestData {
6298                    mode: mode.into(),
6299                    message,
6300                    iv,
6301                },
6302            )
6303            .map_err(|error| {
6304                Error::Api(format!(
6305                    "Encrypting message failed: {}",
6306                    NetHsmApiError::from(error)
6307                ))
6308            })?
6309            .entity
6310            .encrypted,
6311        )
6312        .map_err(Error::Base64Decode)
6313    }
6314
6315    /// [Decrypts] a message using a key.
6316    ///
6317    /// [Decrypts] a `message` using a key identified by `key_id`, a specific [`DecryptMode`] `mode`
6318    /// and initialization vector `iv`.
6319    ///
6320    /// This function can be used to decrypt messages encrypted using a [symmetric key] (e.g. using
6321    /// [`encrypt`][`NetHsm::encrypt`]) by providing [`DecryptMode::AesCbc`] as `mode`. The targeted
6322    /// key must be of type [`KeyType::Generic`] and feature the mechanisms
6323    /// [`KeyMechanism::AesDecryptionCbc`] and [`KeyMechanism::AesEncryptionCbc`].
6324    ///
6325    /// Decryption for messages encrypted using an [asymmetric key] is also possible. Foreign
6326    /// entities can use the public key of an [asymmetric key] (see
6327    /// [`get_public_key`][`NetHsm::get_public_key`]) to encrypt a message and the private key
6328    /// on the NetHSM is used for decryption.
6329    ///
6330    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
6331    /// [role], which carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one
6332    /// of the tags of the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
6333    ///
6334    /// ## Namespaces
6335    ///
6336    /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
6337    ///   their own [namespace].
6338    /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
6339    ///
6340    /// # Errors
6341    ///
6342    /// Returns an [`Error::Api`] if decrypting the `message` fails:
6343    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
6344    /// * no key identified by `key_id` exists on the NetHSM
6345    /// * the chosen `mode` is incompatible with the targeted key
6346    /// * the encrypted message can not be decrypted
6347    /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
6348    ///   different [namespace])
6349    /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
6350    ///   tags
6351    /// * the used [`Credentials`] are not correct
6352    /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
6353    ///   [role]
6354    ///
6355    /// # Examples
6356    ///
6357    /// ```no_run
6358    /// use nethsm::{
6359    ///     Connection,
6360    ///     ConnectionSecurity,
6361    ///     Credentials,
6362    ///     DecryptMode,
6363    ///     EncryptMode,
6364    ///     KeyMechanism,
6365    ///     KeyType,
6366    ///     NetHsm,
6367    ///     Passphrase,
6368    ///     UserRole
6369    /// };
6370    /// use rsa::{pkcs8::DecodePublicKey, Pkcs1v15Encrypt, RsaPublicKey};
6371    ///
6372    /// # fn main() -> testresult::TestResult {
6373    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
6374    /// let nethsm = NetHsm::new(
6375    ///     Connection::new(
6376    ///         "https://example.org/api/v1".try_into()?,
6377    ///         ConnectionSecurity::Unsafe,
6378    ///     ),
6379    ///     Some(Credentials::new(
6380    ///         "admin".parse()?,
6381    ///         Some(Passphrase::new("passphrase".to_string())),
6382    ///     )),
6383    ///     None,
6384    ///     None,
6385    /// )?;
6386    /// // add a system-wide user in the Operator role
6387    /// nethsm.add_user(
6388    ///     "Operator1".to_string(),
6389    ///     UserRole::Operator,
6390    ///     Passphrase::new("operator-passphrase".to_string()),
6391    ///     Some("operator1".parse()?),
6392    /// )?;
6393    /// // generate system-wide keys with the same tag
6394    /// nethsm.generate_key(
6395    ///     KeyType::Generic,
6396    ///     vec![KeyMechanism::AesDecryptionCbc, KeyMechanism::AesEncryptionCbc],
6397    ///     Some(128),
6398    ///     Some("encryption1".parse()?),
6399    ///     Some(vec!["tag1".to_string()]),
6400    /// )?;
6401    /// nethsm.generate_key(
6402    ///     KeyType::Rsa,
6403    ///     vec![KeyMechanism::RsaDecryptionPkcs1],
6404    ///     None,
6405    ///     Some("encryption2".parse()?),
6406    ///     Some(vec!["tag1".to_string()]),
6407    /// )?;
6408    /// // tag system-wide user in Operator role for access to signing key
6409    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
6410    ///
6411    /// // assuming we have an AES128 encryption key, the message must be a multiple of 32 bytes long
6412    /// let message = "Hello World! This is a message!!".to_string();
6413    /// // we have an AES128 encryption key. the initialization vector must be a multiple of 16 bytes long
6414    /// let iv = "This is unsafe!!".to_string();
6415    ///
6416    /// // encrypt message using a symmetric key
6417    /// nethsm.use_credentials(&"operator1".parse()?)?;
6418    /// let encrypted_message = nethsm.encrypt(&"encryption1".parse()?, EncryptMode::AesCbc, message.as_bytes(), Some(iv.as_bytes()))?;
6419    ///
6420    /// // decrypt message using the same symmetric key and the same initialization vector
6421    /// assert_eq!(
6422    ///     message.as_bytes(),
6423    ///     &nethsm.decrypt(&"encryption1".parse()?, DecryptMode::AesCbc, &encrypted_message, Some(iv.as_bytes()))?
6424    /// );
6425    ///
6426    /// // get the public key of an asymmetric key and encrypt the message with it
6427    /// let pubkey = RsaPublicKey::from_public_key_pem(&nethsm.get_public_key(&"encryption2".parse()?)?)?;
6428    /// let mut rng = rand::thread_rng();
6429    /// let encrypted_message = pubkey.encrypt(&mut rng, Pkcs1v15Encrypt, message.as_bytes())?;
6430    /// println!("raw encrypted message: {:?}", encrypted_message);
6431    ///
6432    /// let decrypted_message =
6433    ///     nethsm.decrypt(&"encryption2".parse()?, DecryptMode::Pkcs1, &encrypted_message, None)?;
6434    /// println!("raw decrypted message: {:?}", decrypted_message);
6435    ///
6436    /// assert_eq!(&decrypted_message, message.as_bytes());
6437    /// # Ok(())
6438    /// # }
6439    /// ```
6440    /// [Decrypts]: https://docs.nitrokey.com/nethsm/operation#decrypt
6441    /// [symmetric key]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm
6442    /// [asymmetric key]: https://en.wikipedia.org/wiki/Public-key_cryptography
6443    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
6444    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
6445    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
6446    pub fn decrypt(
6447        &self,
6448        key_id: &KeyId,
6449        mode: DecryptMode,
6450        message: &[u8],
6451        iv: Option<&[u8]>,
6452    ) -> Result<Vec<u8>, Error> {
6453        debug!(
6454            "Decrypt a message (decrypt mode: {mode}; IV: {}) with the key \"{key_id}\" on the NetHSM at {} using {}",
6455            if iv.is_some() { "yes" } else { "no" },
6456            self.url.borrow(),
6457            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
6458        );
6459
6460        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
6461        // the API requires data to be base64 encoded
6462        let encrypted = Base64::encode_string(message);
6463        let iv = iv.map(Base64::encode_string);
6464
6465        // decode base64 encoded data from the API
6466        Base64::decode_vec(
6467            &keys_key_id_decrypt_post(
6468                &self.create_connection_config(),
6469                key_id.as_ref(),
6470                DecryptRequestData {
6471                    mode: mode.into(),
6472                    encrypted,
6473                    iv,
6474                },
6475            )
6476            .map_err(|error| {
6477                Error::Api(format!(
6478                    "Decrypting message failed: {}",
6479                    NetHsmApiError::from(error)
6480                ))
6481            })?
6482            .entity
6483            .decrypted,
6484        )
6485        .map_err(Error::Base64Decode)
6486    }
6487
6488    /// Generates [random] bytes.
6489    ///
6490    /// Retrieves `length` [random] bytes from the NetHSM, if it is in
6491    /// [`Operational`][`SystemState::Operational`] [state].
6492    ///
6493    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
6494    /// [role].
6495    ///
6496    /// # Errors
6497    ///
6498    /// Returns an [`Error::Api`] if retrieving random bytes fails:
6499    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
6500    /// * the used [`Credentials`] are not correct
6501    /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
6502    ///   [role]
6503    ///
6504    /// # Examples
6505    ///
6506    /// ```no_run
6507    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
6508    ///
6509    /// # fn main() -> testresult::TestResult {
6510    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
6511    /// let nethsm = NetHsm::new(
6512    ///     Connection::new(
6513    ///         "https://example.org/api/v1".try_into()?,
6514    ///         ConnectionSecurity::Unsafe,
6515    ///     ),
6516    ///     Some(Credentials::new(
6517    ///         "admin".parse()?,
6518    ///         Some(Passphrase::new("passphrase".to_string())),
6519    ///     )),
6520    ///     None,
6521    ///     None,
6522    /// )?;
6523    /// // add a system-wide user in the Operator role
6524    /// nethsm.add_user(
6525    ///     "Operator1".to_string(),
6526    ///     UserRole::Operator,
6527    ///     Passphrase::new("operator-passphrase".to_string()),
6528    ///     Some("operator1".parse()?),
6529    /// )?;
6530    /// nethsm.use_credentials(&"operator1".parse()?)?;
6531    ///
6532    /// // get 10 random bytes
6533    /// println!("{:#?}", nethsm.random(10)?);
6534    /// # Ok(())
6535    /// # }
6536    /// ```
6537    /// [random]: https://docs.nitrokey.com/nethsm/operation#random
6538    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
6539    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
6540    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
6541    pub fn random(&self, length: u32) -> Result<Vec<u8>, Error> {
6542        debug!(
6543            "Create {length} random bytes on the NetHSM at {} using {}",
6544            self.url.borrow(),
6545            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
6546        );
6547
6548        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
6549        let base64_bytes = random_post(
6550            &self.create_connection_config(),
6551            RandomRequestData::new(length as i32),
6552        )
6553        .map_err(|error| {
6554            Error::Api(format!(
6555                "Getting random bytes failed: {}",
6556                NetHsmApiError::from(error)
6557            ))
6558        })?
6559        .entity
6560        .random;
6561        Base64::decode_vec(&base64_bytes).map_err(Error::Base64Decode)
6562    }
6563
6564    /// Creates an [OpenPGP certificate] for an existing key.
6565    ///
6566    /// The NetHSM key identified by `key_id` is used to issue required [binding signatures] (e.g.
6567    /// those for the [User ID] defined by `user_id`).
6568    /// Using `flags` it is possible to define the key's [capabilities] and with `created_at` to
6569    /// provide the certificate's creation time.
6570    /// Using `version` the OpenPGP version is provided (currently only [`OpenPgpVersion::V4`] is
6571    /// supported).
6572    /// The resulting [OpenPGP certificate] is returned as vector of bytes.
6573    ///
6574    /// To make use of the [OpenPGP certificate] (e.g. with
6575    /// [`openpgp_sign`][`NetHsm::openpgp_sign`]), it should be added as certificate for the key
6576    /// using [`import_key_certificate`][`NetHsm::import_key_certificate`].
6577    ///
6578    /// This call requires using a user in the [`Operator`][`UserRole::Operator`] [role], which
6579    /// carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one of the tags of
6580    /// the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
6581    ///
6582    /// ## Namespaces
6583    ///
6584    /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
6585    ///   their own [namespace].
6586    /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
6587    ///
6588    /// # Errors
6589    ///
6590    /// Returns an [`Error::Api`] if creating an [OpenPGP certificate] for a key fails:
6591    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
6592    /// * no key identified by `key_id` exists on the NetHSM
6593    /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
6594    ///   different [namespace])
6595    /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
6596    ///   tags
6597    /// * the used [`Credentials`] are not correct
6598    /// * the used [`Credentials`] are not those of a user in the [`Operator`][`UserRole::Operator`]
6599    ///   [role]
6600    ///
6601    /// # Panics
6602    ///
6603    /// Panics if the currently unimplemented [`OpenPgpVersion::V6`] is provided as `version`.
6604    ///
6605    /// # Examples
6606    ///
6607    /// ```no_run
6608    /// use std::time::SystemTime;
6609    ///
6610    /// use nethsm::{
6611    ///     Connection,
6612    ///     ConnectionSecurity,
6613    ///     Credentials,
6614    ///     KeyMechanism,
6615    ///     KeyType,
6616    ///     NetHsm,
6617    ///     OpenPgpKeyUsageFlags,
6618    ///     OpenPgpVersion,
6619    ///     Passphrase,
6620    ///     UserRole,
6621    /// };
6622    ///
6623    /// # fn main() -> testresult::TestResult {
6624    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
6625    /// let nethsm = NetHsm::new(
6626    ///     Connection::new(
6627    ///         "https://example.org/api/v1".try_into()?,
6628    ///         ConnectionSecurity::Unsafe,
6629    ///     ),
6630    ///     Some(Credentials::new(
6631    ///         "admin".parse()?,
6632    ///         Some(Passphrase::new("passphrase".to_string())),
6633    ///     )),
6634    ///     None,
6635    ///     None,
6636    /// )?;
6637    /// // add a system-wide user in the Operator role
6638    /// nethsm.add_user(
6639    ///     "Operator1".to_string(),
6640    ///     UserRole::Operator,
6641    ///     Passphrase::new("operator-passphrase".to_string()),
6642    ///     Some("operator1".parse()?),
6643    /// )?;
6644    /// // generate system-wide key with tag
6645    /// nethsm.generate_key(
6646    ///     KeyType::Curve25519,
6647    ///     vec![KeyMechanism::EdDsaSignature],
6648    ///     None,
6649    ///     Some("signing1".parse()?),
6650    ///     Some(vec!["tag1".to_string()]),
6651    /// )?;
6652    /// // tag system-wide user in Operator role for access to signing key
6653    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
6654    ///
6655    /// // create an OpenPGP certificate for the key with ID "signing1"
6656    /// nethsm.use_credentials(&"operator1".parse()?)?;
6657    /// assert!(
6658    ///     !nethsm
6659    ///         .create_openpgp_cert(
6660    ///             &"signing1".parse()?,
6661    ///             OpenPgpKeyUsageFlags::default(),
6662    ///             "Test <test@example.org>".parse()?,
6663    ///             SystemTime::now().into(),
6664    ///             OpenPgpVersion::V4,
6665    ///         )?
6666    ///         .is_empty()
6667    /// );
6668    /// # Ok(())
6669    /// # }
6670    /// ```
6671    /// [OpenPGP certificate]: https://openpgp.dev/book/certificates.html
6672    /// [binding signatures]: https://openpgp.dev/book/signing_components.html#binding-signatures
6673    /// [User ID]: https://openpgp.dev/book/glossary.html#term-User-ID
6674    /// [key certificate]: https://docs.nitrokey.com/nethsm/operation#key-certificates
6675    /// [capabilities]: https://openpgp.dev/book/glossary.html#term-Capability
6676    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
6677    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
6678    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
6679    pub fn create_openpgp_cert(
6680        &self,
6681        key_id: &KeyId,
6682        flags: OpenPgpKeyUsageFlags,
6683        user_id: OpenPgpUserId,
6684        created_at: DateTime<Utc>,
6685        version: OpenPgpVersion,
6686    ) -> Result<Vec<u8>, Error> {
6687        debug!(
6688            "Create an OpenPGP certificate (User ID: {user_id}; flags: {:?}; creation date: {created_at}; version: {version}) for key \"{key_id}\" on the NetHSM at {} using {}",
6689            flags.as_ref(),
6690            self.url.borrow(),
6691            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
6692        );
6693
6694        Ok(openpgp::add_certificate(
6695            self, flags, key_id, user_id, created_at, version,
6696        )?)
6697    }
6698
6699    /// Creates an [OpenPGP signature] for a message.
6700    ///
6701    /// Signs the `message` using the key identified by `key_id` and returns a binary [OpenPGP data
6702    /// signature].
6703    ///
6704    /// This call requires using a user in the [`Operator`][`UserRole::Operator`] [role], which
6705    /// carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one of the tags of
6706    /// the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
6707    ///
6708    /// ## Namespaces
6709    ///
6710    /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
6711    ///   their own [namespace].
6712    /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
6713    ///
6714    /// # Errors
6715    ///
6716    /// Returns an [`Error::Api`] if creating an [OpenPGP signature] for the `message` fails:
6717    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
6718    /// * no key identified by `key_id` exists on the NetHSM
6719    /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
6720    ///   different [namespace])
6721    /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
6722    ///   tags
6723    /// * the used [`Credentials`] are not correct
6724    /// * the used [`Credentials`] are not those of a user in the [`Operator`][`UserRole::Operator`]
6725    ///   [role]
6726    ///
6727    /// # Examples
6728    ///
6729    /// ```no_run
6730    /// use std::time::SystemTime;
6731    ///
6732    /// use nethsm::{
6733    ///     Connection,
6734    ///     ConnectionSecurity,
6735    ///     Credentials,
6736    ///     KeyMechanism,
6737    ///     KeyType,
6738    ///     NetHsm,
6739    ///     OpenPgpKeyUsageFlags,
6740    ///     OpenPgpVersion,
6741    ///     Passphrase,
6742    ///     UserRole,
6743    /// };
6744    ///
6745    /// # fn main() -> testresult::TestResult {
6746    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
6747    /// let nethsm = NetHsm::new(
6748    ///     Connection::new(
6749    ///         "https://example.org/api/v1".try_into()?,
6750    ///         ConnectionSecurity::Unsafe,
6751    ///     ),
6752    ///     Some(Credentials::new(
6753    ///         "admin".parse()?,
6754    ///         Some(Passphrase::new("passphrase".to_string())),
6755    ///     )),
6756    ///     None,
6757    ///     None,
6758    /// )?;
6759    /// // add a system-wide user in the Operator role
6760    /// nethsm.add_user(
6761    ///     "Operator1".to_string(),
6762    ///     UserRole::Operator,
6763    ///     Passphrase::new("operator-passphrase".to_string()),
6764    ///     Some("operator1".parse()?),
6765    /// )?;
6766    /// // generate system-wide key with tag
6767    /// nethsm.generate_key(
6768    ///     KeyType::Curve25519,
6769    ///     vec![KeyMechanism::EdDsaSignature],
6770    ///     None,
6771    ///     Some("signing1".parse()?),
6772    ///     Some(vec!["tag1".to_string()]),
6773    /// )?;
6774    /// // tag system-wide user in Operator role for access to signing key
6775    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
6776    /// // create an OpenPGP certificate for the key with ID "signing1"
6777    /// nethsm.use_credentials(&"operator1".parse()?)?;
6778    /// let openpgp_cert = nethsm.create_openpgp_cert(
6779    ///     &"signing1".parse()?,
6780    ///     OpenPgpKeyUsageFlags::default(),
6781    ///     "Test <test@example.org>".parse()?,
6782    ///     SystemTime::now().into(),
6783    ///     OpenPgpVersion::V4,
6784    /// )?;
6785    /// // import the OpenPGP certificate as key certificate
6786    /// nethsm.use_credentials(&"admin".parse()?)?;
6787    /// nethsm.import_key_certificate(&"signing1".parse()?, openpgp_cert)?;
6788    ///
6789    /// // create OpenPGP signature
6790    /// nethsm.use_credentials(&"operator1".parse()?)?;
6791    /// assert!(
6792    ///     !nethsm
6793    ///         .openpgp_sign(&"signing1".parse()?, b"sample message")?
6794    ///         .is_empty()
6795    /// );
6796    /// # Ok(()) }
6797    /// ```
6798    /// [OpenPGP signature]: https://openpgp.dev/book/signing_data.html
6799    /// [OpenPGP data signature]: https://openpgp.dev/book/signing_data.html
6800    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
6801    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
6802    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
6803    pub fn openpgp_sign(&self, key_id: &KeyId, message: &[u8]) -> Result<Vec<u8>, Error> {
6804        debug!(
6805            "Create an OpenPGP signature for a message with key \"{key_id}\" on the NetHSM at {} using {}",
6806            self.url.borrow(),
6807            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
6808        );
6809
6810        Ok(openpgp::sign(self, key_id, message)?)
6811    }
6812
6813    /// Generates an armored OpenPGP signature based on provided hasher state.
6814    ///
6815    /// Signs the hasher `state` using the key identified by `key_id`
6816    /// and returns a binary [OpenPGP data signature].
6817    ///
6818    /// This call requires using a user in the [`Operator`][`UserRole::Operator`] [role], which
6819    /// carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one of the tags of
6820    /// the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
6821    ///
6822    /// ## Namespaces
6823    ///
6824    /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
6825    ///   their own [namespace].
6826    /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
6827    ///
6828    /// # Errors
6829    ///
6830    /// Returns an [`Error::Api`] if creating an [OpenPGP signature] for the hasher state fails:
6831    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
6832    /// * no key identified by `key_id` exists on the NetHSM
6833    /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
6834    ///   different [namespace])
6835    /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
6836    ///   tags
6837    /// * the used [`Credentials`] are not correct
6838    /// * the used [`Credentials`] are not those of a user in the [`Operator`][`UserRole::Operator`]
6839    ///   [role]
6840    ///
6841    /// # Examples
6842    ///
6843    /// ```no_run
6844    /// use std::time::SystemTime;
6845    ///
6846    /// use nethsm::{
6847    ///     Connection,
6848    ///     ConnectionSecurity,
6849    ///     Credentials,
6850    ///     KeyMechanism,
6851    ///     KeyType,
6852    ///     NetHsm,
6853    ///     OpenPgpKeyUsageFlags,
6854    ///     OpenPgpVersion,
6855    ///     Passphrase,
6856    ///     UserRole,
6857    /// };
6858    /// use sha2::{Digest, Sha512};
6859    ///
6860    /// # fn main() -> testresult::TestResult {
6861    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
6862    /// let nethsm = NetHsm::new(
6863    ///     Connection::new(
6864    ///         "https://example.org/api/v1".try_into()?,
6865    ///         ConnectionSecurity::Unsafe,
6866    ///     ),
6867    ///     Some(Credentials::new(
6868    ///         "admin".parse()?,
6869    ///         Some(Passphrase::new("passphrase".to_string())),
6870    ///     )),
6871    ///     None,
6872    ///     None,
6873    /// )?;
6874    /// // add a system-wide user in the Operator role
6875    /// nethsm.add_user(
6876    ///     "Operator1".to_string(),
6877    ///     UserRole::Operator,
6878    ///     Passphrase::new("operator-passphrase".to_string()),
6879    ///     Some("operator1".parse()?),
6880    /// )?;
6881    /// // generate system-wide key with tag
6882    /// nethsm.generate_key(
6883    ///     KeyType::Curve25519,
6884    ///     vec![KeyMechanism::EdDsaSignature],
6885    ///     None,
6886    ///     Some("signing1".parse()?),
6887    ///     Some(vec!["tag1".to_string()]),
6888    /// )?;
6889    /// // tag system-wide user in Operator role for access to signing key
6890    /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
6891    /// // create an OpenPGP certificate for the key with ID "signing1"
6892    /// nethsm.use_credentials(&"operator1".parse()?)?;
6893    /// let openpgp_cert = nethsm.create_openpgp_cert(
6894    ///     &"signing1".parse()?,
6895    ///     OpenPgpKeyUsageFlags::default(),
6896    ///     "Test <test@example.org>".parse()?,
6897    ///     SystemTime::now().into(),
6898    ///     OpenPgpVersion::V4,
6899    /// )?;
6900    /// // import the OpenPGP certificate as key certificate
6901    /// nethsm.use_credentials(&"admin".parse()?)?;
6902    /// nethsm.import_key_certificate(&"signing1".parse()?, openpgp_cert)?;
6903    ///
6904    /// let mut state = Sha512::new();
6905    /// state.update(b"Hello world!");
6906    ///
6907    /// // create OpenPGP signature
6908    /// nethsm.use_credentials(&"operator1".parse()?)?;
6909    /// assert!(
6910    ///     !nethsm
6911    ///         .openpgp_sign_state(&"signing1".parse()?, state)?
6912    ///         .is_empty()
6913    /// );
6914    /// # Ok(()) }
6915    /// ```
6916    /// [OpenPGP signature]: https://openpgp.dev/book/signing_data.html
6917    /// [OpenPGP data signature]: https://openpgp.dev/book/signing_data.html
6918    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
6919    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
6920    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
6921    pub fn openpgp_sign_state(
6922        &self,
6923        key_id: &KeyId,
6924        state: sha2::Sha512,
6925    ) -> Result<String, crate::Error> {
6926        debug!(
6927            "Create an OpenPGP signature for a hasher state with key \"{key_id}\" on the NetHSM at {} using {}",
6928            self.url.borrow(),
6929            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
6930        );
6931
6932        Ok(openpgp::sign_hasher_state(self, key_id, state)?)
6933    }
6934}