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