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