Skip to main content

nethsm/base/
impl_system.rs

1//! [`NetHsm`] implementation for system functionality.
2
3use std::{collections::HashMap, io::Read, net::Ipv4Addr};
4
5use base64ct::{Base64, Encoding};
6use chrono::{DateTime, Utc};
7use log::debug;
8use nethsm_sdk_rs::{
9    apis::{
10        ResponseContent,
11        configuration::Configuration,
12        default_api::{
13            ConfigTlsCertPemPutError,
14            config_backup_passphrase_put,
15            config_logging_get,
16            config_logging_put,
17            config_network_get,
18            config_network_put,
19            config_time_get,
20            config_time_put,
21            config_tls_cert_pem_get,
22            config_tls_csr_pem_post,
23            config_tls_generate_post,
24            config_tls_public_pem_get,
25            config_unattended_boot_get,
26            config_unattended_boot_put,
27            config_unlock_passphrase_put,
28            lock_post,
29            metrics_get,
30            provision_post,
31            random_post,
32            system_backup_post,
33            system_cancel_update_post,
34            system_commit_update_post,
35            system_factory_reset_post,
36            system_info_get,
37            system_reboot_post,
38            system_restore_post,
39            system_shutdown_post,
40            system_update_post,
41            unlock_post,
42        },
43    },
44    models::{
45        BackupPassphraseConfig,
46        DistinguishedName,
47        LoggingConfig,
48        NetworkConfigInput,
49        NetworkConfigOutput,
50        ProvisionRequestData,
51        RandomRequestData,
52        RestoreRequestArguments,
53        SystemInfo,
54        SystemUpdateData,
55        TimeConfig,
56        TlsKeyGenerateRequestData,
57        UnlockPassphraseConfig,
58        UnlockRequestData,
59    },
60};
61use serde_json::Value;
62
63use crate::{
64    BootMode,
65    Error,
66    LogLevel,
67    NetHsm,
68    Passphrase,
69    TlsKeyType,
70    base::utils::user_or_no_user_string,
71    nethsm_sdk::NetHsmApiError,
72    tls_key_type_matches_length,
73    user::NamespaceSupport,
74};
75#[cfg(doc)]
76use crate::{Credentials, SystemState, UserRole};
77
78impl NetHsm {
79    /// Provisions a NetHSM.
80    ///
81    /// [Provisioning] is the initial setup step for a NetHSM.
82    /// It sets the `unlock_passphrase`, which is used to [`unlock`][`NetHsm::unlock`] a device in
83    /// [`Locked`][`SystemState::Locked`] [state], the initial `admin_passphrase` for the
84    /// default [`Administrator`][`UserRole::Administrator`] account ("admin") and the
85    /// `system_time`. The unlock passphrase can later on be changed using
86    /// [`set_unlock_passphrase`][`NetHsm::set_unlock_passphrase`] and the admin passphrase using
87    /// [`set_user_passphrase`][`NetHsm::set_user_passphrase`].
88    ///
89    /// For this call no [`Credentials`] are required and if any are configured, they are ignored.
90    ///
91    /// # Errors
92    ///
93    /// Returns an [`Error::Api`] if provisioning fails:
94    /// * the NetHSM is not in [`Unprovisioned`][`SystemState::Unprovisioned`] [state]
95    /// * the provided data is malformed
96    ///
97    /// # Examples
98    ///
99    /// ```no_run
100    /// use chrono::Utc;
101    /// use nethsm::{Connection, ConnectionSecurity, NetHsm, Passphrase};
102    ///
103    /// # fn main() -> testresult::TestResult {
104    /// // no initial credentials are required
105    /// let nethsm = NetHsm::new(
106    ///     Connection::new(
107    ///         "https://example.org/api/v1".try_into()?,
108    ///         ConnectionSecurity::Unsafe,
109    ///     ),
110    ///     None,
111    ///     None,
112    ///     None,
113    /// )?;
114    ///
115    /// // provision the NetHSM
116    /// nethsm.provision(
117    ///     Passphrase::new("unlock-the-device".to_string()),
118    ///     Passphrase::new("admin-passphrase".to_string()),
119    ///     Utc::now(),
120    /// )?;
121    /// # Ok(())
122    /// # }
123    /// ```
124    /// [Provisioning]: https://docs.nitrokey.com/nethsm/getting-started#provisioning
125    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
126    pub fn provision(
127        &self,
128        unlock_passphrase: Passphrase,
129        admin_passphrase: Passphrase,
130        system_time: DateTime<Utc>,
131    ) -> Result<(), Error> {
132        debug!("Provision the NetHSM at {}", self.url.borrow());
133
134        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
135        provision_post(
136            &self.create_connection_config(),
137            ProvisionRequestData::new(
138                unlock_passphrase.expose_owned(),
139                admin_passphrase.expose_owned(),
140                system_time.to_rfc3339_opts(chrono::SecondsFormat::Secs, true),
141            ),
142        )
143        .map_err(|error| {
144            Error::Api(format!(
145                "Provisioning failed: {}",
146                NetHsmApiError::from(error)
147            ))
148        })?;
149        Ok(())
150    }
151
152    /// Returns metrics for the NetHSM.
153    ///
154    /// Returns a [`Value`][`serde_json::Value`] which provides [metrics] for the NetHSM.
155    ///
156    /// This call requires using [`Credentials`] of a user in the [`Metrics`][`UserRole::Metrics`]
157    /// [role].
158    ///
159    /// # Errors
160    ///
161    /// Returns an [`Error::Api`] if the NetHSM [metrics] can not be retrieved:
162    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
163    /// * the used [`Credentials`] are not correct
164    /// * the used [`Credentials`] are not that of a user in the [`Metrics`][`UserRole::Metrics`]
165    ///   [role]
166    ///
167    /// # Examples
168    ///
169    /// ```no_run
170    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
171    ///
172    /// # fn main() -> testresult::TestResult {
173    /// // create a connection with a system-wide user in the Metrics role
174    /// let nethsm = NetHsm::new(
175    ///     Connection::new(
176    ///         "https://example.org/api/v1".try_into()?,
177    ///         ConnectionSecurity::Unsafe,
178    ///     ),
179    ///     Some(Credentials::new(
180    ///         "metrics".parse()?,
181    ///         Some(Passphrase::new("metrics-passphrase".to_string())),
182    ///     )),
183    ///     None,
184    ///     None,
185    /// )?;
186    ///
187    /// // retrieve the metrics
188    /// println!("{:?}", nethsm.metrics()?);
189    /// # Ok(())
190    /// # }
191    /// ```
192    /// [metrics]: https://docs.nitrokey.com/nethsm/administration#metrics
193    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
194    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
195    pub fn metrics(&self) -> Result<Value, Error> {
196        debug!(
197            "Retrieve metrics of the NetHSM at {} using {}",
198            self.url.borrow(),
199            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
200        );
201
202        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
203        let metrics = metrics_get(&self.create_connection_config()).map_err(|error| {
204            Error::Api(format!(
205                "Retrieving metrics failed: {}",
206                NetHsmApiError::from(error)
207            ))
208        })?;
209        Ok(metrics.entity)
210    }
211
212    /// Sets the [unlock passphrase].
213    ///
214    /// Changes the [unlock passphrase] from `current_passphrase` to `new_passphrase`.
215    ///
216    /// This call requires using [`Credentials`] of a system-wide user in the
217    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
218    ///
219    /// # Errors
220    ///
221    /// Returns an [`Error::Api`] if the [unlock passphrase] can not be changed:
222    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
223    /// * the provided `current_passphrase` is not correct
224    /// * the used [`Credentials`] are not correct
225    /// * the used [`Credentials`] are not that of a system-wide user in the
226    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
227    ///
228    /// # Examples
229    ///
230    /// ```no_run
231    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
232    ///
233    /// # fn main() -> testresult::TestResult {
234    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
235    /// let nethsm = NetHsm::new(
236    ///     Connection::new(
237    ///         "https://example.org/api/v1".try_into()?,
238    ///         ConnectionSecurity::Unsafe,
239    ///     ),
240    ///     Some(Credentials::new(
241    ///         "admin".parse()?,
242    ///         Some(Passphrase::new("passphrase".to_string())),
243    ///     )),
244    ///     None,
245    ///     None,
246    /// )?;
247    /// // add a user in the Administrator role for a namespace (N-Administrator)
248    /// nethsm.add_user(
249    ///     "Namespace1 Admin".to_string(),
250    ///     UserRole::Administrator,
251    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
252    ///     Some("namespace1~admin1".parse()?),
253    /// )?;
254    /// // create accompanying namespace
255    /// nethsm.add_namespace(&"namespace1".parse()?)?;
256    ///
257    /// // R-Administrators can set the unlock passphrase
258    /// nethsm.set_unlock_passphrase(
259    ///     Passphrase::new("current-unlock-passphrase".to_string()),
260    ///     Passphrase::new("new-unlock-passphrase".to_string()),
261    /// )?;
262    ///
263    /// // N-Administrators can not set the unlock passphrase
264    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
265    /// assert!(
266    ///     nethsm
267    ///         .set_unlock_passphrase(
268    ///             Passphrase::new("current-unlock-passphrase".to_string()),
269    ///             Passphrase::new("new-unlock-passphrase".to_string()),
270    ///         )
271    ///         .is_err()
272    /// );
273    /// # Ok(())
274    /// # }
275    /// ```
276    /// [unlock passphrase]: https://docs.nitrokey.com/nethsm/administration#unlock-passphrase
277    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
278    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
279    pub fn set_unlock_passphrase(
280        &self,
281        current_passphrase: Passphrase,
282        new_passphrase: Passphrase,
283    ) -> Result<(), Error> {
284        debug!(
285            "Set unlock passphrase for the NetHSM at {} using {}",
286            self.url.borrow(),
287            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
288        );
289
290        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
291        config_unlock_passphrase_put(
292            &self.create_connection_config(),
293            UnlockPassphraseConfig::new(
294                new_passphrase.expose_owned(),
295                current_passphrase.expose_owned(),
296            ),
297        )
298        .map_err(|error| {
299            Error::Api(format!(
300                "Changing unlock passphrase failed: {}",
301                NetHsmApiError::from(error)
302            ))
303        })?;
304        Ok(())
305    }
306
307    /// Returns the [boot mode].
308    ///
309    /// Returns a variant of [`BootMode`] which represents the NetHSM's [boot mode].
310    ///
311    /// This call requires using [`Credentials`] of a system-wide user in the
312    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
313    ///
314    /// # Errors
315    ///
316    /// Returns an [`Error::Api`] if the boot mode can not be retrieved:
317    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
318    /// * the used [`Credentials`] are not correct
319    /// * the used [`Credentials`] are not that of a system-wide user in the
320    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
321    ///
322    /// # Examples
323    ///
324    /// ```no_run
325    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
326    ///
327    /// # fn main() -> testresult::TestResult {
328    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
329    /// let nethsm = NetHsm::new(
330    ///     Connection::new(
331    ///         "https://example.org/api/v1".try_into()?,
332    ///         ConnectionSecurity::Unsafe,
333    ///     ),
334    ///     Some(Credentials::new(
335    ///         "admin".parse()?,
336    ///         Some(Passphrase::new("passphrase".to_string())),
337    ///     )),
338    ///     None,
339    ///     None,
340    /// )?;
341    /// // add a user in the Administrator role for a namespace (N-Administrator)
342    /// nethsm.add_user(
343    ///     "Namespace1 Admin".to_string(),
344    ///     UserRole::Administrator,
345    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
346    ///     Some("namespace1~admin1".parse()?),
347    /// )?;
348    /// // create accompanying namespace
349    /// nethsm.add_namespace(&"namespace1".parse()?)?;
350    ///
351    /// // R-Administrators can retrieve the boot mode
352    /// println!("{:?}", nethsm.get_boot_mode()?);
353    ///
354    /// // N-Administrators can not retrieve the boot mode
355    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
356    /// assert!(nethsm.get_boot_mode().is_err());
357    /// # Ok(())
358    /// # }
359    /// ```
360    /// [boot mode]: https://docs.nitrokey.com/nethsm/administration#boot-mode
361    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
362    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
363    pub fn get_boot_mode(&self) -> Result<BootMode, Error> {
364        debug!(
365            "Get the boot mode of the NetHSM at {} using {}",
366            self.url.borrow(),
367            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
368        );
369
370        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
371        BootMode::try_from(
372            config_unattended_boot_get(&self.create_connection_config())
373                .map_err(|error| {
374                    Error::Api(format!(
375                        "Retrieving boot mode failed: {}",
376                        NetHsmApiError::from(error)
377                    ))
378                })?
379                .entity,
380        )
381    }
382
383    /// Sets the [boot mode].
384    ///
385    /// Sets the NetHSM's [boot mode] based on a [`BootMode`] variant.
386    ///
387    /// This call requires using [`Credentials`] of a system-wide user in the
388    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
389    ///
390    /// # Errors
391    ///
392    /// Returns an [`Error::Api`] if the boot mode can not be set:
393    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
394    /// * the used [`Credentials`] are not correct
395    /// * the used [`Credentials`] are not that of a system-wide user in the
396    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
397    ///
398    /// # Examples
399    ///
400    /// ```no_run
401    /// use nethsm::{
402    ///     BootMode,
403    ///     Connection,
404    ///     ConnectionSecurity,
405    ///     Credentials,
406    ///     NetHsm,
407    ///     Passphrase,
408    ///     UserRole,
409    /// };
410    ///
411    /// # fn main() -> testresult::TestResult {
412    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
413    /// let nethsm = NetHsm::new(
414    ///     Connection::new(
415    ///         "https://example.org/api/v1".try_into()?,
416    ///         ConnectionSecurity::Unsafe,
417    ///     ),
418    ///     Some(Credentials::new(
419    ///         "admin".parse()?,
420    ///         Some(Passphrase::new("passphrase".to_string())),
421    ///     )),
422    ///     None,
423    ///     None,
424    /// )?;
425    /// // add a user in the Administrator role for a namespace (N-Administrator)
426    /// nethsm.add_user(
427    ///     "Namespace1 Admin".to_string(),
428    ///     UserRole::Administrator,
429    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
430    ///     Some("namespace1~admin1".parse()?),
431    /// )?;
432    /// // create accompanying namespace
433    /// nethsm.add_namespace(&"namespace1".parse()?)?;
434    ///
435    /// // R-Administrators can set the boot mode
436    /// // set the boot mode to unattended
437    /// nethsm.set_boot_mode(BootMode::Unattended)?;
438    /// // set the boot mode to attended
439    /// nethsm.set_boot_mode(BootMode::Attended)?;
440    ///
441    /// // N-Administrators can not set the boot mode
442    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
443    /// assert!(nethsm.set_boot_mode(BootMode::Attended).is_err());
444    /// # Ok(())
445    /// # }
446    /// ```
447    /// [boot mode]: https://docs.nitrokey.com/nethsm/administration#boot-mode
448    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
449    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
450    pub fn set_boot_mode(&self, boot_mode: BootMode) -> Result<(), Error> {
451        debug!(
452            "Set the boot mode for the NetHSM at {} to {boot_mode} using {}",
453            self.url.borrow(),
454            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
455        );
456
457        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
458        config_unattended_boot_put(&self.create_connection_config(), boot_mode.into()).map_err(
459            |error| {
460                Error::Api(format!(
461                    "Setting boot mode failed: {}",
462                    NetHsmApiError::from(error)
463                ))
464            },
465        )?;
466        Ok(())
467    }
468
469    /// Returns the TLS public key of the API.
470    ///
471    /// Returns the NetHSM's public key part of its [TLS certificate] which is used for
472    /// communication with the API.
473    ///
474    /// This call requires using [`Credentials`] of a system-wide user in the
475    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
476    ///
477    /// # Errors
478    ///
479    /// Returns an [`Error::Api`] if the NetHSM's TLS public key can not be retrieved:
480    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
481    /// * the used [`Credentials`] are not correct
482    /// * the used [`Credentials`] are not that of a system-wide user in the
483    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
484    ///
485    /// # Examples
486    ///
487    /// ```no_run
488    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
489    ///
490    /// # fn main() -> testresult::TestResult {
491    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
492    /// let nethsm = NetHsm::new(
493    ///     Connection::new(
494    ///         "https://example.org/api/v1".try_into()?,
495    ///         ConnectionSecurity::Unsafe,
496    ///     ),
497    ///     Some(Credentials::new(
498    ///         "admin".parse()?,
499    ///         Some(Passphrase::new("passphrase".to_string())),
500    ///     )),
501    ///     None,
502    ///     None,
503    /// )?;
504    /// // add a user in the Administrator role for a namespace (N-Administrator)
505    /// nethsm.add_user(
506    ///     "Namespace1 Admin".to_string(),
507    ///     UserRole::Administrator,
508    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
509    ///     Some("namespace1~admin1".parse()?),
510    /// )?;
511    /// // create accompanying namespace
512    /// nethsm.add_namespace(&"namespace1".parse()?)?;
513    ///
514    /// // R-Administrators can get the TLS public key
515    /// println!("{}", nethsm.get_tls_public_key()?);
516    ///
517    /// // N-Administrators can not get the TLS public key
518    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
519    /// assert!(nethsm.get_tls_public_key().is_err());
520    /// # Ok(())
521    /// # }
522    /// ```
523    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
524    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
525    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
526    pub fn get_tls_public_key(&self) -> Result<String, Error> {
527        debug!(
528            "Retrieve the TLS public key for the NetHSM at {} using {}",
529            self.url.borrow(),
530            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
531        );
532
533        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
534        Ok(config_tls_public_pem_get(&self.create_connection_config())
535            .map_err(|error| {
536                Error::Api(format!(
537                    "Retrieving API TLS public key failed: {}",
538                    NetHsmApiError::from(error)
539                ))
540            })?
541            .entity)
542    }
543
544    /// Returns the TLS certificate of the API.
545    ///
546    /// Returns the NetHSM's [TLS certificate] which is used for communication with the API.
547    ///
548    /// This call requires using [`Credentials`] of a system-wide user in the
549    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
550    ///
551    /// # Errors
552    ///
553    /// Returns an [`Error::Api`] if the NetHSM's TLS certificate can not be retrieved:
554    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
555    /// * the used [`Credentials`] are not correct
556    /// * the used [`Credentials`] are not that of a system-wide user in the
557    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
558    ///
559    /// # Examples
560    ///
561    /// ```no_run
562    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
563    ///
564    /// # fn main() -> testresult::TestResult {
565    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
566    /// let nethsm = NetHsm::new(
567    ///     Connection::new(
568    ///         "https://example.org/api/v1".try_into()?,
569    ///         ConnectionSecurity::Unsafe,
570    ///     ),
571    ///     Some(Credentials::new(
572    ///         "admin".parse()?,
573    ///         Some(Passphrase::new("passphrase".to_string())),
574    ///     )),
575    ///     None,
576    ///     None,
577    /// )?;
578    /// // add a user in the Administrator role for a namespace (N-Administrator)
579    /// nethsm.add_user(
580    ///     "Namespace1 Admin".to_string(),
581    ///     UserRole::Administrator,
582    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
583    ///     Some("namespace1~admin1".parse()?),
584    /// )?;
585    /// // create accompanying namespace
586    /// nethsm.add_namespace(&"namespace1".parse()?)?;
587    ///
588    /// // R-Administrators can get the TLS certificate
589    /// println!("{}", nethsm.get_tls_cert()?);
590    ///
591    /// // N-Administrators can not get the TLS certificate
592    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
593    /// assert!(nethsm.get_tls_cert().is_err());
594    /// # Ok(())
595    /// # }
596    /// ```
597    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
598    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
599    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
600    pub fn get_tls_cert(&self) -> Result<String, Error> {
601        debug!(
602            "Retrieve the TLS certificate for the NetHSM at {} using {}",
603            self.url.borrow(),
604            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
605        );
606
607        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
608        Ok(config_tls_cert_pem_get(&self.create_connection_config())
609            .map_err(|error| {
610                Error::Api(format!(
611                    "Retrieving API TLS certificate failed: {}",
612                    NetHsmApiError::from(error)
613                ))
614            })?
615            .entity)
616    }
617
618    /// Returns a Certificate Signing Request ([CSR]) for the API's [TLS certificate].
619    ///
620    /// Based on [`DistinguishedName`] data returns a [CSR] in [PKCS#10] format for the NetHSM's
621    /// [TLS certificate].
622    ///
623    /// This call requires using [`Credentials`] of a system-wide user in the
624    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
625    ///
626    /// # Errors
627    ///
628    /// Returns an [`Error::Api`] if the [CSR] can not be retrieved:
629    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
630    /// * the used [`Credentials`] are not correct
631    /// * the used [`Credentials`] are not that of a system-wide user in the
632    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
633    ///
634    /// # Examples
635    ///
636    /// ```no_run
637    /// use nethsm::{
638    ///     Connection,
639    ///     ConnectionSecurity,
640    ///     Credentials,
641    ///     DistinguishedName,
642    ///     NetHsm,
643    ///     Passphrase,
644    ///     UserRole,
645    /// };
646    ///
647    /// # fn main() -> testresult::TestResult {
648    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
649    /// let nethsm = NetHsm::new(
650    ///     Connection::new(
651    ///         "https://example.org/api/v1".try_into()?,
652    ///         ConnectionSecurity::Unsafe,
653    ///     ),
654    ///     Some(Credentials::new(
655    ///         "admin".parse()?,
656    ///         Some(Passphrase::new("passphrase".to_string())),
657    ///     )),
658    ///     None,
659    ///     None,
660    /// )?;
661    /// // add a user in the Administrator role for a namespace (N-Administrator)
662    /// nethsm.add_user(
663    ///     "Namespace1 Admin".to_string(),
664    ///     UserRole::Administrator,
665    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
666    ///     Some("namespace1~admin1".parse()?),
667    /// )?;
668    /// // create accompanying namespace
669    /// nethsm.add_namespace(&"namespace1".parse()?)?;
670    ///
671    /// // R-Administrators can get a CSR for the TLS certificate
672    /// let distinguished_name = {
673    ///     let mut distinguished_name = DistinguishedName::new("example.org".to_string());
674    ///     distinguished_name.country_name = Some("DE".to_string());
675    ///     distinguished_name.state_or_province_name = Some("Berlin".to_string());
676    ///     distinguished_name.locality_name = Some("Berlin".to_string());
677    ///     distinguished_name.organization_name = Some("Foobar Inc".to_string());
678    ///     distinguished_name.organizational_unit_name = Some("Department of Foo".to_string());
679    ///     distinguished_name.email_address = Some("foobar@mcfooface.com".to_string());
680    ///     distinguished_name.subject_alt_names = Some(vec!["other.example.org".to_string()]);
681    ///     distinguished_name
682    /// };
683    /// println!("{}", nethsm.get_tls_csr(distinguished_name.clone())?);
684    ///
685    /// // N-Administrators can not get a CSR for the TLS certificate
686    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
687    /// assert!(nethsm.get_tls_csr(distinguished_name).is_err());
688    /// # Ok(())
689    /// # }
690    /// ```
691    /// [CSR]: https://en.wikipedia.org/wiki/Certificate_signing_request
692    /// [PKCS#10]: https://en.wikipedia.org/wiki/Certificate_signing_request#Structure_of_a_PKCS_#10_CSR
693    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
694    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
695    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
696    pub fn get_tls_csr(&self, distinguished_name: DistinguishedName) -> Result<String, Error> {
697        debug!(
698            "Retrieve a Certificate Signing Request (for {}) for the TLS certificate of the NetHSM at {} using {}",
699            distinguished_name.common_name,
700            self.url.borrow(),
701            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
702        );
703
704        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
705        Ok(
706            config_tls_csr_pem_post(&self.create_connection_config(), distinguished_name)
707                .map_err(|error| {
708                    Error::Api(format!(
709                        "Retrieving CSR for TLS certificate failed: {}",
710                        NetHsmApiError::from(error),
711                    ))
712                })?
713                .entity,
714        )
715    }
716
717    /// Generates a new [TLS certificate] for the API.
718    ///
719    /// Generates a new [TLS certificate] (used for communication with the API) based on
720    /// `tls_key_type` and `length`.
721    ///
722    /// This call requires using [`Credentials`] of a system-wide user in the
723    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
724    ///
725    /// # Errors
726    ///
727    /// Returns an [`Error::Api`] if the new [TLS certificate] can not be generated:
728    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
729    /// * the `tls_key_type` and `length` combination is not valid
730    /// * the used [`Credentials`] are not correct
731    /// * the used [`Credentials`] are not that of a system-wide user in the
732    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
733    ///
734    /// # Examples
735    ///
736    /// ```no_run
737    /// use nethsm::{
738    ///     Connection,
739    ///     ConnectionSecurity,
740    ///     Credentials,
741    ///     NetHsm,
742    ///     Passphrase,
743    ///     TlsKeyType,
744    ///     UserRole,
745    /// };
746    ///
747    /// # fn main() -> testresult::TestResult {
748    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
749    /// let nethsm = NetHsm::new(
750    ///     Connection::new(
751    ///         "https://example.org/api/v1".try_into()?,
752    ///         ConnectionSecurity::Unsafe,
753    ///     ),
754    ///     Some(Credentials::new(
755    ///         "admin".parse()?,
756    ///         Some(Passphrase::new("passphrase".to_string())),
757    ///     )),
758    ///     None,
759    ///     None,
760    /// )?;
761    /// // add a user in the Administrator role for a namespace (N-Administrator)
762    /// nethsm.add_user(
763    ///     "Namespace1 Admin".to_string(),
764    ///     UserRole::Administrator,
765    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
766    ///     Some("namespace1~admin1".parse()?),
767    /// )?;
768    /// // create accompanying namespace
769    /// nethsm.add_namespace(&"namespace1".parse()?)?;
770    ///
771    /// // R-Administrators can generate a new TLS certificate
772    /// nethsm.generate_tls_cert(TlsKeyType::Rsa, Some(4096))?;
773    ///
774    /// // N-Administrators can not generate a new TLS certificate
775    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
776    /// assert!(
777    ///     nethsm
778    ///         .generate_tls_cert(TlsKeyType::Rsa, Some(4096))
779    ///         .is_err()
780    /// );
781    /// # Ok(())
782    /// # }
783    /// ```
784    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
785    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
786    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
787    pub fn generate_tls_cert(
788        &self,
789        tls_key_type: TlsKeyType,
790        length: Option<u32>,
791    ) -> Result<(), Error> {
792        debug!(
793            "Generate a TLS certificate ({tls_key_type}{}) on the NetHSM at {} using {}",
794            if let Some(length) = length {
795                format!(" {length} bit long")
796            } else {
797                "{}".to_string()
798            },
799            self.url.borrow(),
800            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
801        );
802
803        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
804        // ensure the tls_key_type - length combination is valid
805        tls_key_type_matches_length(tls_key_type, length)?;
806
807        // WARNING: Upstream has decided to set all models non-exhaustive.
808        //
809        // On each update to nethsm-sdk-rs, check whether TlsKeyGenerateRequestData has gained
810        // further fields.
811        let tls_keygenerate_request_data = {
812            let mut tls_keygenerate_request_data =
813                TlsKeyGenerateRequestData::new(tls_key_type.try_into()?);
814            tls_keygenerate_request_data.length = length.map(|length| length as i32);
815            tls_keygenerate_request_data
816        };
817
818        config_tls_generate_post(
819            &self.create_connection_config(),
820            tls_keygenerate_request_data,
821        )
822        .map_err(|error| {
823            Error::Api(format!(
824                "Generating API TLS certificate failed: {}",
825                NetHsmApiError::from(error)
826            ))
827        })?;
828        Ok(())
829    }
830
831    /// Sets a new [TLS certificate] for the API.
832    ///
833    /// Accepts a Base64 encoded [DER] certificate provided using `certificate` which is added as
834    /// new [TLS certificate] for communication with the API.
835    ///
836    /// This call requires using [`Credentials`] of a system-wide user in the
837    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
838    ///
839    /// # Errors
840    ///
841    /// Returns an [`Error::Api`] if setting a new TLS certificate fails:
842    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
843    /// * the provided `certificate` is not valid
844    /// * the used [`Credentials`] are not correct
845    /// * the used [`Credentials`] are not that of a system-wide user in the
846    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
847    ///
848    /// # Examples
849    ///
850    /// ```no_run
851    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
852    ///
853    /// # fn main() -> testresult::TestResult {
854    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
855    /// let nethsm = NetHsm::new(
856    ///     Connection::new(
857    ///         "https://example.org/api/v1".try_into()?,
858    ///         ConnectionSecurity::Unsafe,
859    ///     ),
860    ///     Some(Credentials::new(
861    ///         "admin".parse()?,
862    ///         Some(Passphrase::new("passphrase".to_string())),
863    ///     )),
864    ///     None,
865    ///     None,
866    /// )?;
867    /// // add a user in the Administrator role for a namespace (N-Administrator)
868    /// nethsm.add_user(
869    ///     "Namespace1 Admin".to_string(),
870    ///     UserRole::Administrator,
871    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
872    ///     Some("namespace1~admin1".parse()?),
873    /// )?;
874    /// // create accompanying namespace
875    /// nethsm.add_namespace(&"namespace1".parse()?)?;
876    ///
877    /// let cert = r#"-----BEGIN CERTIFICATE-----
878    /// MIIBHjCBxKADAgECAghDngCv6xWIXDAKBggqhkjOPQQDAjAUMRIwEAYDVQQDDAlr
879    /// ZXlmZW5kZXIwIBcNNzAwMTAxMDAwMDAwWhgPOTk5OTEyMzEyMzU5NTlaMBQxEjAQ
880    /// BgNVBAMMCWtleWZlbmRlcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJsHIrsZ
881    /// 6fJzrk12GK7nW6bGyTIIZiQUq0uaKbn21dgPiDCO5+iYVXAqnWu4IMVZQnkFJmte
882    /// PRUUuM3119f8ffkwCgYIKoZIzj0EAwIDSQAwRgIhALH4fDYJ21tRecXp9IipBlil
883    /// p+hJCj77zBvFmGYy/UnPAiEA8csj7U6BfzvK4EiQyUZa7/as+nXwj3XHU/i8LyLm
884    /// Chw=
885    /// -----END CERTIFICATE-----"#;
886    ///
887    /// // R-Administrators can set a new TLS certificate
888    /// nethsm.set_tls_cert(cert)?;
889    ///
890    /// // N-Administrators can not set a new TLS certificate
891    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
892    /// assert!(nethsm.set_tls_cert(cert).is_err());
893    /// # Ok(())
894    /// # }
895    /// ```
896    /// [DER]: https://en.wikipedia.org/wiki/X.690#DER_encoding
897    /// [TLS certificate]: https://docs.nitrokey.com/nethsm/administration#tls-certificate
898    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
899    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
900    pub fn set_tls_cert(&self, certificate: &str) -> Result<(), Error> {
901        debug!(
902            "Set a new TLS certificate for the NetHSM at {} using {}",
903            self.url.borrow(),
904            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
905        );
906
907        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
908
909        // NOTE: The function `nethsm_sdk_rs::apis::default_api::config_tls_cert_pem_put` is
910        // defective, so we replicate a somewhat fixed version of it, inline.
911        //
912        // See <https://github.com/Nitrokey/nethsm-sdk-rs/issues/61>
913        //
914        // The below can be removed, once we have a released upstream fix and we can start using
915        // `nethsm_sdk_rs::apis::default_api::config_tls_cert_pem_put` again.
916
917        /// Set certificate for NetHSMs https API e.g. to replace self-signed initial certificate.
918        fn config_tls_cert_pem_put(
919            configuration: &Configuration,
920            body: &str,
921        ) -> Result<ResponseContent<()>, nethsm_sdk_rs::apis::Error<ConfigTlsCertPemPutError>>
922        {
923            let client = &configuration.client;
924
925            let request_builder = {
926                let mut request_builder = client
927                    .put(&format!("{}/config/tls/cert.pem", configuration.base_path))
928                    .config()
929                    .http_status_as_error(false)
930                    .build();
931
932                if let Some(user_agent) = &configuration.user_agent {
933                    request_builder = request_builder.header("user-agent", user_agent);
934                }
935
936                if let Some((user, passphrase)) = &configuration.basic_auth {
937                    request_builder = request_builder.header(
938                        "authorization",
939                        &format!(
940                            "Basic {}",
941                            Base64::encode_string(
942                                format!("{user}:{}", passphrase.as_deref().unwrap_or(""))
943                                    .as_bytes()
944                            )
945                        ),
946                    );
947                };
948
949                request_builder = request_builder.header("content-type", "application/x-pem-file");
950
951                request_builder
952            };
953
954            let response = request_builder.send(body)?;
955            let status = response.status().as_u16();
956            let headers = {
957                let mut headers = HashMap::new();
958
959                let names = response.headers();
960                for (name, value) in names {
961                    if let Ok(value) = value.to_str() {
962                        headers.insert(name.as_str().into(), value.into());
963                    }
964                }
965
966                headers
967            };
968            let content = {
969                let mut content = Vec::new();
970                response
971                    .into_body()
972                    .into_reader()
973                    .read_to_end(&mut content)?;
974
975                content
976            };
977
978            if status < 400 {
979                Ok(ResponseContent {
980                    status,
981                    content,
982                    entity: (),
983                    headers,
984                })
985            } else {
986                let error = match status {
987                    400 => ConfigTlsCertPemPutError::Status400(serde_json::from_slice(
988                        content.as_slice(),
989                    )?),
990                    401 => ConfigTlsCertPemPutError::Status401(),
991                    403 => ConfigTlsCertPemPutError::Status403(),
992                    406 => ConfigTlsCertPemPutError::Status406(),
993                    _ => ConfigTlsCertPemPutError::UnknownValue(if content.is_empty() {
994                        serde_json::Value::Null
995                    } else {
996                        serde_json::from_slice(content.as_slice())?
997                    }),
998                };
999
1000                Err(nethsm_sdk_rs::apis::Error::ResponseError(ResponseContent {
1001                    status,
1002                    content,
1003                    entity: error,
1004                    headers,
1005                }))
1006            }
1007        }
1008
1009        config_tls_cert_pem_put(&self.create_connection_config(), certificate).map_err(
1010            |error| {
1011                Error::Api(format!(
1012                    "Setting API TLS certificate failed: {}",
1013                    NetHsmApiError::from(error)
1014                ))
1015            },
1016        )?;
1017        Ok(())
1018    }
1019
1020    /// Gets the [network configuration].
1021    ///
1022    /// Retrieves the [network configuration] of the NetHSM as [`NetworkConfigOutput`].
1023    ///
1024    /// This call requires using [`Credentials`] of a system-wide user in the
1025    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1026    ///
1027    /// # Errors
1028    ///
1029    /// Returns an [`Error::Api`] if retrieving network configuration fails:
1030    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1031    /// * the used [`Credentials`] are not correct
1032    /// * the used [`Credentials`] are not that of a system-wide user in the
1033    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1034    ///
1035    /// # Examples
1036    ///
1037    /// ```no_run
1038    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1039    ///
1040    /// # fn main() -> testresult::TestResult {
1041    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1042    /// let nethsm = NetHsm::new(
1043    ///     Connection::new(
1044    ///         "https://example.org/api/v1".try_into()?,
1045    ///         ConnectionSecurity::Unsafe,
1046    ///     ),
1047    ///     Some(Credentials::new(
1048    ///         "admin".parse()?,
1049    ///         Some(Passphrase::new("passphrase".to_string())),
1050    ///     )),
1051    ///     None,
1052    ///     None,
1053    /// )?;
1054    /// // add a user in the Administrator role for a namespace (N-Administrator)
1055    /// nethsm.add_user(
1056    ///     "Namespace1 Admin".to_string(),
1057    ///     UserRole::Administrator,
1058    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1059    ///     Some("namespace1~admin1".parse()?),
1060    /// )?;
1061    /// // create accompanying namespace
1062    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1063    ///
1064    /// // R-Administrators can get the network configuration
1065    /// println!("{:?}", nethsm.get_network()?);
1066    ///
1067    /// // N-Administrators can not get the network configuration
1068    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1069    /// assert!(nethsm.get_network().is_err());
1070    /// # Ok(())
1071    /// # }
1072    /// ```
1073    /// [network configuration]: https://docs.nitrokey.com/nethsm/administration#network
1074    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1075    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1076    pub fn get_network(&self) -> Result<NetworkConfigOutput, Error> {
1077        debug!(
1078            "Get network configuration for the NetHSM at {} using {}",
1079            self.url.borrow(),
1080            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1081        );
1082
1083        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1084        Ok(config_network_get(&self.create_connection_config())
1085            .map_err(|error| {
1086                Error::Api(format!(
1087                    "Getting network config failed: {}",
1088                    NetHsmApiError::from(error)
1089                ))
1090            })?
1091            .entity)
1092    }
1093
1094    /// Sets the [network configuration].
1095    ///
1096    /// Sets the [network configuration] of the NetHSM on the basis of a [`NetworkConfigInput`].
1097    ///
1098    /// This call requires using [`Credentials`] of a system-wide user in the
1099    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1100    ///
1101    /// # Errors
1102    ///
1103    /// Returns an [`Error::Api`] if setting the network configuration fails:
1104    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1105    /// * the provided `network_config` is not valid
1106    /// * the used [`Credentials`] are not correct
1107    /// * the used [`Credentials`] are not that of a system-wide user in the
1108    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1109    ///
1110    /// # Examples
1111    ///
1112    /// ```no_run
1113    /// use nethsm::{
1114    ///     Connection,
1115    ///     ConnectionSecurity,
1116    ///     Credentials,
1117    ///     NetHsm,
1118    ///     NetworkConfigInput,
1119    ///     Passphrase,
1120    ///     UserRole,
1121    /// };
1122    ///
1123    /// # fn main() -> testresult::TestResult {
1124    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1125    /// let nethsm = NetHsm::new(
1126    ///     Connection::new(
1127    ///         "https://example.org/api/v1".try_into()?,
1128    ///         ConnectionSecurity::Unsafe,
1129    ///     ),
1130    ///     Some(Credentials::new(
1131    ///         "admin".parse()?,
1132    ///         Some(Passphrase::new("passphrase".to_string())),
1133    ///     )),
1134    ///     None,
1135    ///     None,
1136    /// )?;
1137    /// // add a user in the Administrator role for a namespace (N-Administrator)
1138    /// nethsm.add_user(
1139    ///     "Namespace1 Admin".to_string(),
1140    ///     UserRole::Administrator,
1141    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1142    ///     Some("namespace1~admin1".parse()?),
1143    /// )?;
1144    /// // create accompanying namespace
1145    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1146    ///
1147    /// let network_config_input = {
1148    ///     let mut network_config_input =
1149    ///         NetworkConfigInput::new("192.168.1.1".to_string(), "255.255.255.0".to_string());
1150    ///     network_config_input.gateway = Some("0.0.0.0".to_string());
1151    ///     network_config_input
1152    /// };
1153    ///
1154    /// // R-Administrators can set the network configuration
1155    /// nethsm.set_network(network_config_input.clone())?;
1156    ///
1157    /// // N-Administrators can not set the network configuration
1158    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1159    /// assert!(nethsm.set_network(network_config_input).is_err());
1160    /// # Ok(())
1161    /// # }
1162    /// ```
1163    /// [network configuration]: https://docs.nitrokey.com/nethsm/administration#network
1164    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1165    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1166    pub fn set_network(&self, network_config: NetworkConfigInput) -> Result<(), Error> {
1167        debug!(
1168            "Set a new network configuration (IP: {}, Netmask: {}, Gateway: {}) for the NetHSM at {} using {}",
1169            network_config.ip_address,
1170            network_config.netmask,
1171            network_config.gateway.as_deref().unwrap_or_default(),
1172            self.url.borrow(),
1173            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1174        );
1175
1176        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1177        config_network_put(&self.create_connection_config(), network_config).map_err(|error| {
1178            Error::Api(format!(
1179                "Setting network config failed: {}",
1180                NetHsmApiError::from(error)
1181            ))
1182        })?;
1183        Ok(())
1184    }
1185
1186    /// Gets the current [time].
1187    ///
1188    /// This call requires using [`Credentials`] of a system-wide user in the
1189    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1190    ///
1191    /// # Errors
1192    ///
1193    /// Returns an [`Error::Api`] if retrieving [time] fails:
1194    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1195    /// * the used [`Credentials`] are not correct
1196    /// * the used [`Credentials`] are not that of a system-wide user in the
1197    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1198    ///
1199    /// # Examples
1200    ///
1201    /// ```no_run
1202    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1203    ///
1204    /// # fn main() -> testresult::TestResult {
1205    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1206    /// let nethsm = NetHsm::new(
1207    ///     Connection::new(
1208    ///         "https://example.org/api/v1".try_into()?,
1209    ///         ConnectionSecurity::Unsafe,
1210    ///     ),
1211    ///     Some(Credentials::new(
1212    ///         "admin".parse()?,
1213    ///         Some(Passphrase::new("passphrase".to_string())),
1214    ///     )),
1215    ///     None,
1216    ///     None,
1217    /// )?;
1218    /// // add a user in the Administrator role for a namespace (N-Administrator)
1219    /// nethsm.add_user(
1220    ///     "Namespace1 Admin".to_string(),
1221    ///     UserRole::Administrator,
1222    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1223    ///     Some("namespace1~admin1".parse()?),
1224    /// )?;
1225    /// // create accompanying namespace
1226    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1227    ///
1228    /// // R-Administrators can get the time
1229    /// println!("{:?}", nethsm.get_time()?);
1230    ///
1231    /// // N-Administrators can not get the time
1232    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1233    /// assert!(nethsm.get_time().is_err());
1234    /// # Ok(())
1235    /// # }
1236    /// ```
1237    /// [time]: https://docs.nitrokey.com/nethsm/administration#time
1238    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1239    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1240    pub fn get_time(&self) -> Result<String, Error> {
1241        debug!(
1242            "Retrieve the system time for the NetHSM at {} using {}",
1243            self.url.borrow(),
1244            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1245        );
1246
1247        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1248        Ok(config_time_get(&self.create_connection_config())
1249            .map_err(|error| {
1250                Error::Api(format!(
1251                    "Getting NetHSM system time failed: {}",
1252                    NetHsmApiError::from(error)
1253                ))
1254            })?
1255            .entity
1256            .time)
1257    }
1258
1259    /// Sets the current [time].
1260    ///
1261    /// This call requires using [`Credentials`] of a system-wide user in the
1262    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1263    ///
1264    /// # Errors
1265    ///
1266    /// Returns an [`Error::Api`] if setting [time] fails:
1267    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1268    /// * the provided `time` is not valid
1269    /// * the used [`Credentials`] are not correct
1270    /// * the used [`Credentials`] are not that of a system-wide user in the
1271    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1272    ///
1273    /// # Examples
1274    ///
1275    /// ```no_run
1276    /// use chrono::Utc;
1277    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1278    ///
1279    /// # fn main() -> testresult::TestResult {
1280    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1281    /// let nethsm = NetHsm::new(
1282    ///     Connection::new(
1283    ///         "https://example.org/api/v1".try_into()?,
1284    ///         ConnectionSecurity::Unsafe,
1285    ///     ),
1286    ///     Some(Credentials::new(
1287    ///         "admin".parse()?,
1288    ///         Some(Passphrase::new("passphrase".to_string())),
1289    ///     )),
1290    ///     None,
1291    ///     None,
1292    /// )?;
1293    /// // add a user in the Administrator role for a namespace (N-Administrator)
1294    /// nethsm.add_user(
1295    ///     "Namespace1 Admin".to_string(),
1296    ///     UserRole::Administrator,
1297    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1298    ///     Some("namespace1~admin1".parse()?),
1299    /// )?;
1300    /// // create accompanying namespace
1301    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1302    ///
1303    /// // R-Administrators can set the time
1304    /// nethsm.set_time(Utc::now())?;
1305    ///
1306    /// // N-Administrators can not set the time
1307    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1308    /// assert!(nethsm.set_time(Utc::now()).is_err());
1309    /// # Ok(())
1310    /// # }
1311    /// ```
1312    /// [time]: https://docs.nitrokey.com/nethsm/administration#time
1313    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1314    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1315    pub fn set_time(&self, time: DateTime<Utc>) -> Result<(), Error> {
1316        debug!(
1317            "Set the system time to {time} for the NetHSM at {} using {}",
1318            self.url.borrow(),
1319            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1320        );
1321
1322        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1323        config_time_put(
1324            &self.create_connection_config(),
1325            TimeConfig::new(time.to_rfc3339_opts(chrono::SecondsFormat::Secs, true)),
1326        )
1327        .map_err(|error| {
1328            Error::Api(format!(
1329                "Setting NetHSM system time failed: {}",
1330                NetHsmApiError::from(error)
1331            ))
1332        })?;
1333        Ok(())
1334    }
1335
1336    /// Gets the [logging configuration].
1337    ///
1338    /// This call requires using [`Credentials`] of a system-wide user in the
1339    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1340    ///
1341    /// # Errors
1342    ///
1343    /// Returns an [`Error::Api`] if getting the [logging configuration] fails:
1344    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1345    /// * the used [`Credentials`] are not correct
1346    /// * the used [`Credentials`] are not that of a system-wide user in the
1347    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1348    ///
1349    /// # Examples
1350    ///
1351    /// ```no_run
1352    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1353    ///
1354    /// # fn main() -> testresult::TestResult {
1355    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1356    /// let nethsm = NetHsm::new(
1357    ///     Connection::new(
1358    ///         "https://example.org/api/v1".try_into()?,
1359    ///         ConnectionSecurity::Unsafe,
1360    ///     ),
1361    ///     Some(Credentials::new(
1362    ///         "admin".parse()?,
1363    ///         Some(Passphrase::new("passphrase".to_string())),
1364    ///     )),
1365    ///     None,
1366    ///     None,
1367    /// )?;
1368    /// // add a user in the Administrator role for a namespace (N-Administrator)
1369    /// nethsm.add_user(
1370    ///     "Namespace1 Admin".to_string(),
1371    ///     UserRole::Administrator,
1372    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1373    ///     Some("namespace1~admin1".parse()?),
1374    /// )?;
1375    /// // create accompanying namespace
1376    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1377    ///
1378    /// // R-Administrators can get logging configuration
1379    /// println!("{:?}", nethsm.get_logging()?);
1380    ///
1381    /// // N-Administrators can not get logging configuration
1382    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1383    /// assert!(nethsm.get_logging().is_err());
1384    /// # Ok(())
1385    /// # }
1386    /// ```
1387    /// [logging configuration]: https://docs.nitrokey.com/nethsm/administration#logging
1388    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1389    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1390    pub fn get_logging(&self) -> Result<LoggingConfig, Error> {
1391        debug!(
1392            "Retrieve the logging information of the NetHSM at {} using {}",
1393            self.url.borrow(),
1394            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1395        );
1396
1397        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1398        Ok(config_logging_get(&self.create_connection_config())
1399            .map_err(|error| {
1400                Error::Api(format!(
1401                    "Getting logging config failed: {}",
1402                    NetHsmApiError::from(error)
1403                ))
1404            })?
1405            .entity)
1406    }
1407
1408    /// Sets the [logging configuration].
1409    ///
1410    /// Sets the NetHSM's [logging configuration] by providing `ip_address` and `port` of a host to
1411    /// send logs to. The log level is configured using `log_level`.
1412    ///
1413    /// This call requires using [`Credentials`] of a system-wide user in the
1414    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1415    ///
1416    /// # Errors
1417    ///
1418    /// Returns an [`Error::Api`] if setting the logging configuration fails:
1419    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1420    /// * the provided `ip_address`, `port` or `log_level` are not valid
1421    /// * the used [`Credentials`] are not correct
1422    /// * the used [`Credentials`] are not that of a system-wide user in the
1423    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1424    ///
1425    /// # Examples
1426    ///
1427    /// ```no_run
1428    /// use std::net::Ipv4Addr;
1429    ///
1430    /// use nethsm::{
1431    ///     Connection,
1432    ///     ConnectionSecurity,
1433    ///     Credentials,
1434    ///     LogLevel,
1435    ///     NetHsm,
1436    ///     Passphrase,
1437    ///     UserRole,
1438    /// };
1439    ///
1440    /// # fn main() -> testresult::TestResult {
1441    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1442    /// let nethsm = NetHsm::new(
1443    ///     Connection::new(
1444    ///         "https://example.org/api/v1".try_into()?,
1445    ///         ConnectionSecurity::Unsafe,
1446    ///     ),
1447    ///     Some(Credentials::new(
1448    ///         "admin".parse()?,
1449    ///         Some(Passphrase::new("passphrase".to_string())),
1450    ///     )),
1451    ///     None,
1452    ///     None,
1453    /// )?;
1454    /// // add a user in the Administrator role for a namespace (N-Administrator)
1455    /// nethsm.add_user(
1456    ///     "Namespace1 Admin".to_string(),
1457    ///     UserRole::Administrator,
1458    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1459    ///     Some("namespace1~admin1".parse()?),
1460    /// )?;
1461    /// // create accompanying namespace
1462    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1463    ///
1464    /// // R-Administrators can set logging configuration
1465    /// nethsm.set_logging(Ipv4Addr::new(192, 168, 1, 2), 513, LogLevel::Debug)?;
1466    ///
1467    /// // N-Administrators can not set logging configuration
1468    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1469    /// assert!(
1470    ///     nethsm
1471    ///         .set_logging(Ipv4Addr::new(192, 168, 1, 2), 513, LogLevel::Debug)
1472    ///         .is_err()
1473    /// );
1474    /// # Ok(())
1475    /// # }
1476    /// ```
1477    /// [logging configuration]: https://docs.nitrokey.com/nethsm/administration#logging
1478    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1479    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1480    pub fn set_logging(
1481        &self,
1482        ip_address: Ipv4Addr,
1483        port: u32,
1484        log_level: LogLevel,
1485    ) -> Result<(), Error> {
1486        debug!(
1487            "Set the logging configuration to {ip_address}:{port} ({log_level}) for the NetHSM at {} using {}",
1488            self.url.borrow(),
1489            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1490        );
1491
1492        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1493        let ip_address = ip_address.to_string();
1494        config_logging_put(
1495            &self.create_connection_config(),
1496            LoggingConfig::new(ip_address, port as i32, log_level.into()),
1497        )
1498        .map_err(|error| {
1499            Error::Api(format!(
1500                "Setting logging config failed: {}",
1501                NetHsmApiError::from(error)
1502            ))
1503        })?;
1504        Ok(())
1505    }
1506
1507    /// Sets the [backup] passphrase.
1508    ///
1509    /// Sets `current_passphrase` to `new_passphrase`, which changes the [backup] passphrase for the
1510    /// NetHSM.
1511    ///
1512    /// This call requires using [`Credentials`] of a system-wide user in the
1513    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1514    ///
1515    /// # Errors
1516    ///
1517    /// Returns an [`Error::Api`] if setting the backup passphrase fails:
1518    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1519    /// * the provided `current_passphrase` is not correct
1520    /// * the used [`Credentials`] are not correct
1521    /// * the used [`Credentials`] are not that of a system-wide user in the
1522    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1523    ///
1524    /// # Examples
1525    ///
1526    /// ```no_run
1527    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1528    ///
1529    /// # fn main() -> testresult::TestResult {
1530    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1531    /// let nethsm = NetHsm::new(
1532    ///     Connection::new(
1533    ///         "https://example.org/api/v1".try_into()?,
1534    ///         ConnectionSecurity::Unsafe,
1535    ///     ),
1536    ///     Some(Credentials::new(
1537    ///         "admin".parse()?,
1538    ///         Some(Passphrase::new("passphrase".to_string())),
1539    ///     )),
1540    ///     None,
1541    ///     None,
1542    /// )?;
1543    /// // add a user in the Administrator role for a namespace (N-Administrator)
1544    /// nethsm.add_user(
1545    ///     "Namespace1 Admin".to_string(),
1546    ///     UserRole::Administrator,
1547    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1548    ///     Some("namespace1~admin1".parse()?),
1549    /// )?;
1550    /// // create accompanying namespace
1551    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1552    ///
1553    /// // R-Administrators can set the backup passphrase
1554    /// nethsm.set_backup_passphrase(
1555    ///     Passphrase::new("current-backup-passphrase".to_string()),
1556    ///     Passphrase::new("new-backup-passphrase".to_string()),
1557    /// )?;
1558    ///
1559    /// // N-Administrators can not set logging configuration
1560    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1561    /// assert!(
1562    ///     nethsm
1563    ///         .set_backup_passphrase(
1564    ///             Passphrase::new("new-backup-passphrase".to_string()),
1565    ///             Passphrase::new("current-backup-passphrase".to_string()),
1566    ///         )
1567    ///         .is_err()
1568    /// );
1569    /// # Ok(())
1570    /// # }
1571    /// ```
1572    /// [backup]: https://docs.nitrokey.com/nethsm/administration#backup
1573    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1574    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1575    pub fn set_backup_passphrase(
1576        &self,
1577        current_passphrase: Passphrase,
1578        new_passphrase: Passphrase,
1579    ) -> Result<(), Error> {
1580        debug!(
1581            "Set the backup passphrase for the NetHSM at {} using {}",
1582            self.url.borrow(),
1583            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1584        );
1585
1586        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1587        config_backup_passphrase_put(
1588            &self.create_connection_config(),
1589            BackupPassphraseConfig::new(
1590                new_passphrase.expose_owned(),
1591                current_passphrase.expose_owned(),
1592            ),
1593        )
1594        .map_err(|error| {
1595            Error::Api(format!(
1596                "Setting backup passphrase failed: {}",
1597                NetHsmApiError::from(error),
1598            ))
1599        })?;
1600        Ok(())
1601    }
1602
1603    /// Creates a [backup].
1604    ///
1605    /// Triggers the creation and download of a [backup] of the NetHSM.
1606    /// **NOTE**: Before creating the first [backup], the [backup] passphrase must be set using
1607    /// [`set_backup_passphrase`][`NetHsm::set_backup_passphrase`].
1608    ///
1609    /// This call requires using [`Credentials`] of a user in the [`Backup`][`UserRole::Backup`]
1610    /// [role].
1611    ///
1612    /// # Errors
1613    ///
1614    /// Returns an [`Error::Api`] if creating a [backup] fails:
1615    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1616    /// * the used [`Credentials`] are not correct
1617    /// * the used [`Credentials`] are not that of a user in the [`Backup`][`UserRole::Backup`]
1618    ///   [role]
1619    /// * the [backup] passphrase has not yet been set
1620    ///
1621    /// # Examples
1622    ///
1623    /// ```no_run
1624    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
1625    ///
1626    /// # fn main() -> testresult::TestResult {
1627    /// // create a connection with a user in the Backup role
1628    /// let nethsm = NetHsm::new(
1629    ///     Connection::new(
1630    ///         "https://example.org/api/v1".try_into()?,
1631    ///         ConnectionSecurity::Unsafe,
1632    ///     ),
1633    ///     Some(Credentials::new(
1634    ///         "backup1".parse()?,
1635    ///         Some(Passphrase::new("passphrase".to_string())),
1636    ///     )),
1637    ///     None,
1638    ///     None,
1639    /// )?;
1640    ///
1641    /// // create a backup and write it to file
1642    /// std::fs::write("nethsm.bkp", nethsm.backup()?)?;
1643    /// # Ok(())
1644    /// # }
1645    /// ```
1646    /// [backup]: https://docs.nitrokey.com/nethsm/administration#backup
1647    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1648    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1649    pub fn backup(&self) -> Result<Vec<u8>, Error> {
1650        debug!(
1651            "Retrieve a backup of the NetHSM at {} using {}",
1652            self.url.borrow(),
1653            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1654        );
1655
1656        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1657        Ok(system_backup_post(&self.create_connection_config())
1658            .map_err(|error| {
1659                Error::Api(format!(
1660                    "Getting backup failed: {}",
1661                    NetHsmApiError::from(error)
1662                ))
1663            })?
1664            .entity)
1665    }
1666
1667    /// Triggers a [factory reset].
1668    ///
1669    /// Triggers a [factory reset] of the NetHSM.
1670    /// **WARNING**: This action deletes all user and system data! Make sure to create a [backup]
1671    /// using [`backup`][`NetHsm::backup`] first!
1672    ///
1673    /// This call requires using [`Credentials`] of a system-wide user in the
1674    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1675    ///
1676    /// # Errors
1677    ///
1678    /// Returns an [`Error::Api`] if resetting the NetHSM fails:
1679    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1680    /// * the used [`Credentials`] are not correct
1681    /// * the used [`Credentials`] are not that of a system-wide user in the
1682    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1683    ///
1684    /// # Examples
1685    ///
1686    /// ```no_run
1687    /// use nethsm::{
1688    ///     Connection,
1689    ///     ConnectionSecurity,
1690    ///     Credentials,
1691    ///     NetHsm,
1692    ///     Passphrase,
1693    ///     SystemState,
1694    ///     UserRole,
1695    /// };
1696    ///
1697    /// # fn main() -> testresult::TestResult {
1698    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1699    /// let nethsm = NetHsm::new(
1700    ///     Connection::new(
1701    ///         "https://example.org/api/v1".try_into()?,
1702    ///         ConnectionSecurity::Unsafe,
1703    ///     ),
1704    ///     Some(Credentials::new(
1705    ///         "admin".parse()?,
1706    ///         Some(Passphrase::new("passphrase".to_string())),
1707    ///     )),
1708    ///     None,
1709    ///     None,
1710    /// )?;
1711    /// // add a user in the Administrator role for a namespace (N-Administrator)
1712    /// nethsm.add_user(
1713    ///     "Namespace1 Admin".to_string(),
1714    ///     UserRole::Administrator,
1715    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1716    ///     Some("namespace1~admin1".parse()?),
1717    /// )?;
1718    /// // create accompanying namespace
1719    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1720    ///
1721    /// // N-Administrators can not trigger factory reset
1722    /// assert_eq!(nethsm.state()?, SystemState::Operational);
1723    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1724    /// assert!(nethsm.factory_reset().is_err());
1725    ///
1726    /// // R-Administrators are able to trigger a factory reset
1727    /// assert_eq!(nethsm.state()?, SystemState::Operational);
1728    /// nethsm.use_credentials(&"admin".parse()?)?;
1729    /// nethsm.factory_reset()?;
1730    /// assert_eq!(nethsm.state()?, SystemState::Unprovisioned);
1731    /// # Ok(())
1732    /// # }
1733    /// ```
1734    /// [factory reset]: https://docs.nitrokey.com/nethsm/administration#reset-to-factory-defaults
1735    /// [backup]: https://docs.nitrokey.com/nethsm/administration#backup
1736    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1737    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1738    pub fn factory_reset(&self) -> Result<(), Error> {
1739        debug!(
1740            "Trigger a factory reset of the NetHSM at {} using {}",
1741            self.url.borrow(),
1742            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1743        );
1744
1745        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1746        system_factory_reset_post(&self.create_connection_config()).map_err(|error| {
1747            Error::Api(format!(
1748                "Factory reset failed: {}",
1749                NetHsmApiError::from(error)
1750            ))
1751        })?;
1752        Ok(())
1753    }
1754
1755    /// Restores NetHSM from [backup].
1756    ///
1757    /// [Restores] a NetHSM from a [backup], by providing a `backup_passphrase` (see
1758    /// [`set_backup_passphrase`][`NetHsm::set_backup_passphrase`]) a new `system_time` for the
1759    /// NetHSM and a backup file (created using [`backup`][`NetHsm::backup`]).
1760    ///
1761    /// The NetHSM must be in [`Operational`][`SystemState::Operational`] or
1762    /// [`Unprovisioned`][`SystemState::Unprovisioned`] [state].
1763    ///
1764    /// Any existing user data is safely removed and replaced by that of the [backup], after which
1765    /// the NetHSM ends up in [`Locked`][`SystemState::Locked`] [state].
1766    /// If the NetHSM is in [`Unprovisioned`][`SystemState::Unprovisioned`] [state], additionally
1767    /// the system configuration from the backup is applied and leads to a
1768    /// [`reboot`][`NetHsm::reboot`] of the NetHSM.
1769    ///
1770    /// This call requires using [`Credentials`] of a system-wide user in the
1771    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1772    ///
1773    /// # Errors
1774    ///
1775    /// Returns an [`Error::Api`] if restoring the NetHSM from [backup] fails:
1776    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] or
1777    ///   [`Unprovisioned`][`SystemState::Unprovisioned`] [state]
1778    /// * the used [`Credentials`] are not correct
1779    /// * the used [`Credentials`] are not that of a system-wide user in the
1780    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1781    ///
1782    /// # Examples
1783    ///
1784    /// ```no_run
1785    /// use chrono::Utc;
1786    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
1787    ///
1788    /// #
1789    /// # fn main() -> testresult::TestResult {
1790    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1791    /// let nethsm = NetHsm::new(
1792    ///     Connection::new(
1793    ///         "https://example.org/api/v1".try_into()?,
1794    ///         ConnectionSecurity::Unsafe,
1795    ///     ),
1796    ///     Some(Credentials::new(
1797    ///         "admin".parse()?,
1798    ///         Some(Passphrase::new("passphrase".to_string())),
1799    ///     )),
1800    ///     None,
1801    ///     None,
1802    /// )?;
1803    /// // add a user in the Administrator role for a namespace (N-Administrator)
1804    /// nethsm.add_user(
1805    ///     "Namespace1 Admin".to_string(),
1806    ///     UserRole::Administrator,
1807    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1808    ///     Some("namespace1~admin1".parse()?),
1809    /// )?;
1810    /// // create accompanying namespace
1811    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1812    ///
1813    /// // N-Administrators can not restore from backup
1814    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1815    /// assert!(
1816    ///     nethsm
1817    ///         .restore(
1818    ///             Passphrase::new("backup-passphrase".to_string()),
1819    ///             Utc::now(),
1820    ///             std::fs::read("nethsm.bkp")?,
1821    ///         )
1822    ///         .is_err()
1823    /// );
1824    ///
1825    /// // R-Administrators can restore from backup
1826    /// nethsm.use_credentials(&"admin".parse()?)?;
1827    /// nethsm.restore(
1828    ///     Passphrase::new("backup-passphrase".to_string()),
1829    ///     Utc::now(),
1830    ///     std::fs::read("nethsm.bkp")?,
1831    /// )?;
1832    /// # Ok(())
1833    /// # }
1834    /// ```
1835    /// [Restores]: https://docs.nitrokey.com/nethsm/administration#restore
1836    /// [backup]: https://docs.nitrokey.com/nethsm/administration#backup
1837    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1838    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1839    pub fn restore(
1840        &self,
1841        backup_passphrase: Passphrase,
1842        system_time: DateTime<Utc>,
1843        backup: Vec<u8>,
1844    ) -> Result<(), Error> {
1845        debug!(
1846            "Restore the NetHSM at {} from backup with the new system time {system_time} using {}",
1847            self.url.borrow(),
1848            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1849        );
1850
1851        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1852
1853        // WARNING: Upstream has decided to set all models non-exhaustive.
1854        //
1855        // On each update to nethsm-sdk-rs, check whether RestoreRequestArguments has gained further
1856        // fields.
1857        let restore_request_arguments = {
1858            let mut restore_request_arguments = RestoreRequestArguments::default();
1859            restore_request_arguments.backup_passphrase = Some(backup_passphrase.expose_owned());
1860            restore_request_arguments.system_time =
1861                Some(system_time.to_rfc3339_opts(chrono::SecondsFormat::Secs, true));
1862            restore_request_arguments
1863        };
1864
1865        system_restore_post(
1866            &self.create_connection_config(),
1867            Some(restore_request_arguments),
1868            Some(backup),
1869        )
1870        .map_err(|error| {
1871            Error::Api(format!(
1872                "Restoring backup failed: {}",
1873                NetHsmApiError::from(error)
1874            ))
1875        })?;
1876        Ok(())
1877    }
1878
1879    /// Locks the NetHSM.
1880    ///
1881    /// Locks the NetHSM and sets its [state] to [`Locked`][`SystemState::Locked`].
1882    ///
1883    /// This call requires using [`Credentials`] of a system-wide user in the
1884    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
1885    ///
1886    /// # Errors
1887    ///
1888    /// Returns an [`Error::Api`] if locking the NetHSM fails:
1889    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1890    /// * the used [`Credentials`] are not correct
1891    /// * the used [`Credentials`] are not that of a system-wide user in the
1892    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
1893    ///
1894    /// # Examples
1895    ///
1896    /// ```no_run
1897    /// use nethsm::{
1898    ///     Connection,
1899    ///     ConnectionSecurity,
1900    ///     Credentials,
1901    ///     NetHsm,
1902    ///     Passphrase,
1903    ///     SystemState,
1904    ///     UserRole,
1905    /// };
1906    ///
1907    /// # fn main() -> testresult::TestResult {
1908    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1909    /// let nethsm = NetHsm::new(
1910    ///     Connection::new(
1911    ///         "https://example.org/api/v1".try_into()?,
1912    ///         ConnectionSecurity::Unsafe,
1913    ///     ),
1914    ///     Some(Credentials::new(
1915    ///         "admin".parse()?,
1916    ///         Some(Passphrase::new("passphrase".to_string())),
1917    ///     )),
1918    ///     None,
1919    ///     None,
1920    /// )?;
1921    /// // add a user in the Administrator role for a namespace (N-Administrator)
1922    /// nethsm.add_user(
1923    ///     "Namespace1 Admin".to_string(),
1924    ///     UserRole::Administrator,
1925    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
1926    ///     Some("namespace1~admin1".parse()?),
1927    /// )?;
1928    /// // create accompanying namespace
1929    /// nethsm.add_namespace(&"namespace1".parse()?)?;
1930    ///
1931    /// assert_eq!(nethsm.state()?, SystemState::Operational);
1932    ///
1933    /// // N-Administrators can not lock the NetHSM
1934    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
1935    /// assert!(nethsm.lock().is_err());
1936    ///
1937    /// // R-Administrators can lock the NetHSM
1938    /// nethsm.use_credentials(&"admin".parse()?)?;
1939    /// nethsm.lock()?;
1940    /// assert_eq!(nethsm.state()?, SystemState::Locked);
1941    /// # Ok(())
1942    /// # }
1943    /// ```
1944    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1945    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1946    pub fn lock(&self) -> Result<(), Error> {
1947        debug!(
1948            "Lock the NetHSM at {} using {}",
1949            self.url.borrow(),
1950            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1951        );
1952
1953        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
1954        lock_post(&self.create_connection_config()).map_err(|error| {
1955            Error::Api(format!(
1956                "Locking NetHSM failed: {}",
1957                NetHsmApiError::from(error)
1958            ))
1959        })?;
1960        Ok(())
1961    }
1962
1963    /// Unlocks the NetHSM.
1964    ///
1965    /// Unlocks the NetHSM if it is in [`Locked`][`SystemState::Locked`] [state] by providing
1966    /// `unlock_passphrase` and sets its [state] to [`Operational`][`SystemState::Operational`].
1967    ///
1968    /// For this call no [`Credentials`] are required and if any are configured, they are ignored.
1969    ///
1970    /// # Errors
1971    ///
1972    /// Returns an [`Error::Api`] if unlocking the NetHSM fails:
1973    /// * the NetHSM is not in [`Locked`][`SystemState::Locked`] [state]
1974    ///
1975    /// # Examples
1976    ///
1977    /// ```no_run
1978    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, SystemState};
1979    ///
1980    /// # fn main() -> testresult::TestResult {
1981    /// // no initial [`Credentials`] are required
1982    /// let nethsm = NetHsm::new(
1983    ///     Connection::new(
1984    ///         "https://example.org/api/v1".try_into()?,
1985    ///         ConnectionSecurity::Unsafe,
1986    ///     ),
1987    ///     None,
1988    ///     None,
1989    ///     None,
1990    /// )?;
1991    ///
1992    /// assert_eq!(nethsm.state()?, SystemState::Locked);
1993    /// // unlock the NetHSM
1994    /// nethsm.unlock(Passphrase::new("unlock-passphrase".to_string()))?;
1995    /// assert_eq!(nethsm.state()?, SystemState::Operational);
1996    /// # Ok(())
1997    /// # }
1998    /// ```
1999    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2000    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2001    pub fn unlock(&self, unlock_passphrase: Passphrase) -> Result<(), Error> {
2002        debug!(
2003            "Unlock the NetHSM at {} using {}",
2004            self.url.borrow(),
2005            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2006        );
2007
2008        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
2009        unlock_post(
2010            &self.create_connection_config(),
2011            UnlockRequestData::new(unlock_passphrase.expose_owned()),
2012        )
2013        .map_err(|error| {
2014            Error::Api(format!(
2015                "Unlocking NetHSM failed: {}",
2016                NetHsmApiError::from(error)
2017            ))
2018        })?;
2019        Ok(())
2020    }
2021
2022    /// Retrieves [system information].
2023    ///
2024    /// Returns [system information] in the form of a [`SystemInfo`], which contains various pieces
2025    /// of information such as software version, software build, firmware version, hardware
2026    /// version, device ID and information on TPM related components such as attestation key and
2027    /// relevant PCR values.
2028    ///
2029    /// This call requires using [`Credentials`] of a system-wide user in the
2030    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2031    ///
2032    /// # Errors
2033    ///
2034    /// Returns an [`Error::Api`] if retrieving the system information fails:
2035    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2036    /// * the used [`Credentials`] are not correct
2037    /// * the used [`Credentials`] are not that of a system-wide user in the
2038    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2039    ///
2040    /// # Examples
2041    ///
2042    /// ```no_run
2043    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2044    ///
2045    /// # fn main() -> testresult::TestResult {
2046    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2047    /// let nethsm = NetHsm::new(
2048    ///     Connection::new(
2049    ///         "https://example.org/api/v1".try_into()?,
2050    ///         ConnectionSecurity::Unsafe,
2051    ///     ),
2052    ///     Some(Credentials::new(
2053    ///         "admin".parse()?,
2054    ///         Some(Passphrase::new("passphrase".to_string())),
2055    ///     )),
2056    ///     None,
2057    ///     None,
2058    /// )?;
2059    /// // add a user in the Administrator role for a namespace (N-Administrator)
2060    /// nethsm.add_user(
2061    ///     "Namespace1 Admin".to_string(),
2062    ///     UserRole::Administrator,
2063    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2064    ///     Some("namespace1~admin1".parse()?),
2065    /// )?;
2066    /// // create accompanying namespace
2067    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2068    ///
2069    /// // R-Administrators can retrieve system information
2070    /// println!("{:?}", nethsm.system_info()?);
2071    ///
2072    /// // N-Administrators can not retrieve system information
2073    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2074    /// assert!(nethsm.system_info().is_err());
2075    /// # Ok(())
2076    /// # }
2077    /// ```
2078    /// [system information]: https://docs.nitrokey.com/nethsm/administration#system-information
2079    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2080    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2081    pub fn system_info(&self) -> Result<SystemInfo, Error> {
2082        debug!(
2083            "Retrieve system information about the NetHSM at {} using {}",
2084            self.url.borrow(),
2085            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2086        );
2087
2088        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2089        Ok(system_info_get(&self.create_connection_config())
2090            .map_err(|error| {
2091                Error::Api(format!(
2092                    "Retrieving system information failed: {}",
2093                    NetHsmApiError::from(error)
2094                ))
2095            })?
2096            .entity)
2097    }
2098
2099    /// [Reboots] the NetHSM.
2100    ///
2101    /// [Reboots] the NetHSM, if it is in [`Operational`][`SystemState::Operational`] [state].
2102    ///
2103    /// This call requires using [`Credentials`] of a system-wide user in the
2104    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2105    ///
2106    /// # Errors
2107    ///
2108    /// Returns an [`Error::Api`] if rebooting the NetHSM fails:
2109    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2110    /// * the used [`Credentials`] are not correct
2111    /// * the used [`Credentials`] are not that of a system-wide user in the
2112    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2113    ///
2114    /// # Examples
2115    ///
2116    /// ```no_run
2117    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2118    ///
2119    /// # fn main() -> testresult::TestResult {
2120    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2121    /// let nethsm = NetHsm::new(
2122    ///     Connection::new(
2123    ///         "https://example.org/api/v1".try_into()?,
2124    ///         ConnectionSecurity::Unsafe,
2125    ///     ),
2126    ///     Some(Credentials::new(
2127    ///         "admin".parse()?,
2128    ///         Some(Passphrase::new("passphrase".to_string())),
2129    ///     )),
2130    ///     None,
2131    ///     None,
2132    /// )?;
2133    /// // add a user in the Administrator role for a namespace (N-Administrator)
2134    /// nethsm.add_user(
2135    ///     "Namespace1 Admin".to_string(),
2136    ///     UserRole::Administrator,
2137    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2138    ///     Some("namespace1~admin1".parse()?),
2139    /// )?;
2140    /// // create accompanying namespace
2141    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2142    ///
2143    /// // N-Administrators can not reboot the NetHSM
2144    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2145    /// assert!(nethsm.reboot().is_err());
2146    ///
2147    /// // R-Administrators can reboot the NetHSM
2148    /// nethsm.use_credentials(&"admin".parse()?)?;
2149    /// nethsm.reboot()?;
2150    /// # Ok(())
2151    /// # }
2152    /// ```
2153    /// [Reboots]: https://docs.nitrokey.com/nethsm/administration#reboot-and-shutdown
2154    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2155    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2156    pub fn reboot(&self) -> Result<(), Error> {
2157        debug!(
2158            "Reboot the NetHSM at {} using {}",
2159            self.url.borrow(),
2160            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2161        );
2162
2163        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2164        system_reboot_post(&self.create_connection_config()).map_err(|error| {
2165            Error::Api(format!(
2166                "Rebooting NetHSM failed: {}",
2167                NetHsmApiError::from(error)
2168            ))
2169        })?;
2170        Ok(())
2171    }
2172
2173    /// [Shuts down] the NetHSM.
2174    ///
2175    /// [Shuts down] the NetHSM, if it is in [`Operational`][`SystemState::Operational`] [state].
2176    ///
2177    /// This call requires using [`Credentials`] of a system-wide user in the
2178    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2179    ///
2180    /// # Errors
2181    ///
2182    /// Returns an [`Error::Api`] if shutting down the NetHSM fails:
2183    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2184    /// * the used [`Credentials`] are not correct
2185    /// * the used [`Credentials`] are not that of a system-wide user in the
2186    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2187    ///
2188    /// # Examples
2189    ///
2190    /// ```no_run
2191    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2192    ///
2193    /// # fn main() -> testresult::TestResult {
2194    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2195    /// let nethsm = NetHsm::new(
2196    ///     Connection::new(
2197    ///         "https://example.org/api/v1".try_into()?,
2198    ///         ConnectionSecurity::Unsafe,
2199    ///     ),
2200    ///     Some(Credentials::new(
2201    ///         "admin".parse()?,
2202    ///         Some(Passphrase::new("passphrase".to_string())),
2203    ///     )),
2204    ///     None,
2205    ///     None,
2206    /// )?;
2207    /// // add a user in the Administrator role for a namespace (N-Administrator)
2208    /// nethsm.add_user(
2209    ///     "Namespace1 Admin".to_string(),
2210    ///     UserRole::Administrator,
2211    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2212    ///     Some("namespace1~admin1".parse()?),
2213    /// )?;
2214    /// // create accompanying namespace
2215    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2216    ///
2217    /// // N-Administrators can not shut down the NetHSM
2218    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2219    /// assert!(nethsm.shutdown().is_err());
2220    ///
2221    /// // R-Administrators can shut down the NetHSM
2222    /// nethsm.use_credentials(&"admin".parse()?)?;
2223    /// nethsm.shutdown()?;
2224    /// # Ok(())
2225    /// # }
2226    /// ```
2227    /// [Shuts down]: https://docs.nitrokey.com/nethsm/administration#reboot-and-shutdown
2228    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2229    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2230    pub fn shutdown(&self) -> Result<(), Error> {
2231        debug!(
2232            "Shut down the NetHSM at {} using {}",
2233            self.url.borrow(),
2234            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2235        );
2236
2237        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2238        system_shutdown_post(&self.create_connection_config()).map_err(|error| {
2239            Error::Api(format!(
2240                "Shutting down NetHSM failed: {}",
2241                NetHsmApiError::from(error)
2242            ))
2243        })?;
2244        Ok(())
2245    }
2246
2247    /// Uploads a software update.
2248    ///
2249    /// WARNING: This function has shown flaky behavior during tests with the official container!
2250    /// Upload may have to be repeated!
2251    ///
2252    /// Uploads a [software update] to the NetHSM, if it is in
2253    /// [`Operational`][`SystemState::Operational`] [state] and returns information about the
2254    /// software update as [`SystemUpdateData`].
2255    /// Software updates can successively be installed ([`commit_update`][`NetHsm::commit_update`])
2256    /// or canceled ([`cancel_update`][`NetHsm::cancel_update`]).
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 uploading the software update 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::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2273    ///
2274    /// # fn main() -> testresult::TestResult {
2275    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2276    /// let nethsm = NetHsm::new(
2277    ///     Connection::new(
2278    ///         "https://example.org/api/v1".try_into()?,
2279    ///         ConnectionSecurity::Unsafe,
2280    ///     ),
2281    ///     Some(Credentials::new(
2282    ///         "admin".parse()?,
2283    ///         Some(Passphrase::new("passphrase".to_string())),
2284    ///     )),
2285    ///     None,
2286    ///     None,
2287    /// )?;
2288    /// // add a user in the Administrator role for a namespace (N-Administrator)
2289    /// nethsm.add_user(
2290    ///     "Namespace1 Admin".to_string(),
2291    ///     UserRole::Administrator,
2292    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2293    ///     Some("namespace1~admin1".parse()?),
2294    /// )?;
2295    /// // create accompanying namespace
2296    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2297    ///
2298    /// // N-Administrators can not upload software updates to the NetHSM
2299    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2300    /// assert!(nethsm.upload_update(std::fs::read("update.bin")?).is_err());
2301    ///
2302    /// // R-Administrators can upload software updates to the NetHSM
2303    /// nethsm.use_credentials(&"admin".parse()?)?;
2304    /// println!("{:?}", nethsm.upload_update(std::fs::read("update.bin")?)?);
2305    /// # Ok(())
2306    /// # }
2307    /// ```
2308    /// [software update]: https://docs.nitrokey.com/nethsm/administration#software-update
2309    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2310    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2311    pub fn upload_update(&self, update: Vec<u8>) -> Result<SystemUpdateData, Error> {
2312        debug!(
2313            "Upload an update to the NetHSM at {} using {}",
2314            self.url.borrow(),
2315            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2316        );
2317
2318        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2319        Ok(system_update_post(&self.create_connection_config(), update)
2320            .map_err(|error| {
2321                println!("error during upload");
2322                Error::Api(format!(
2323                    "Uploading update failed: {}",
2324                    NetHsmApiError::from(error)
2325                ))
2326            })?
2327            .entity)
2328    }
2329
2330    /// Commits an already uploaded [software update].
2331    ///
2332    /// Commits a [software update] previously uploaded to the NetHSM (using
2333    /// [`upload_update`][`NetHsm::upload_update`]), if the NetHSM is in
2334    /// [`Operational`][`SystemState::Operational`] [state].
2335    /// Successfully committing a [software update] leads to the [reboot] of the NetHSM.
2336    ///
2337    /// This call requires using [`Credentials`] of a system-wide user in the
2338    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2339    ///
2340    /// # Errors
2341    ///
2342    /// Returns an [`Error::Api`] if committing the software update fails:
2343    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2344    /// * there is no software update to commit
2345    /// * the used [`Credentials`] are not correct
2346    /// * the used [`Credentials`] are not that of a system-wide user in the
2347    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2348    ///
2349    /// # Examples
2350    ///
2351    /// ```no_run
2352    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2353    ///
2354    /// # fn main() -> testresult::TestResult {
2355    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2356    /// let nethsm = NetHsm::new(
2357    ///     Connection::new(
2358    ///         "https://example.org/api/v1".try_into()?,
2359    ///         ConnectionSecurity::Unsafe,
2360    ///     ),
2361    ///     Some(Credentials::new(
2362    ///         "admin".parse()?,
2363    ///         Some(Passphrase::new("passphrase".to_string())),
2364    ///     )),
2365    ///     None,
2366    ///     None,
2367    /// )?;
2368    /// // add a user in the Administrator role for a namespace (N-Administrator)
2369    /// nethsm.add_user(
2370    ///     "Namespace1 Admin".to_string(),
2371    ///     UserRole::Administrator,
2372    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2373    ///     Some("namespace1~admin1".parse()?),
2374    /// )?;
2375    /// // create accompanying namespace
2376    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2377    ///
2378    /// println!("{:?}", nethsm.upload_update(std::fs::read("update.bin")?)?);
2379    ///
2380    /// // N-Administrators can not commit software updates on a NetHSM
2381    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2382    /// assert!(nethsm.commit_update().is_err());
2383    ///
2384    /// // R-Administrators can commit software updates on a NetHSM
2385    /// nethsm.use_credentials(&"admin".parse()?)?;
2386    /// nethsm.commit_update()?;
2387    /// # Ok(())
2388    /// # }
2389    /// ```
2390    /// [software update]: https://docs.nitrokey.com/nethsm/administration#software-update
2391    /// [reboot]: https://docs.nitrokey.com/nethsm/administration#reboot-and-shutdown
2392    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2393    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2394    pub fn commit_update(&self) -> Result<(), Error> {
2395        debug!(
2396            "Commit an already uploaded update on the NetHSM at {} using {}",
2397            self.url.borrow(),
2398            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2399        );
2400
2401        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2402        system_commit_update_post(&self.create_connection_config()).map_err(|error| {
2403            Error::Api(format!(
2404                "Committing update failed: {}",
2405                NetHsmApiError::from(error)
2406            ))
2407        })?;
2408        Ok(())
2409    }
2410
2411    /// Cancels an already uploaded [software update].
2412    ///
2413    /// Cancels a [software update] previously uploaded to the NetHSM (using
2414    /// [`upload_update`][`NetHsm::upload_update`]), if the NetHSM is in
2415    /// [`Operational`][`SystemState::Operational`] [state].
2416    ///
2417    /// This call requires using [`Credentials`] of a system-wide user in the
2418    /// [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*).
2419    ///
2420    /// # Errors
2421    ///
2422    /// Returns an [`Error::Api`] if canceling the software update fails:
2423    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2424    /// * there is no software update to cancel
2425    /// * the used [`Credentials`] are not correct
2426    /// * the used [`Credentials`] are not that of a system-wide user in the
2427    ///   [`Administrator`][`UserRole::Administrator`] [role] (*R-Administrator*)
2428    ///
2429    /// # Examples
2430    ///
2431    /// ```no_run
2432    /// use nethsm::{
2433    ///     Connection,
2434    ///     ConnectionSecurity,
2435    ///     Credentials,
2436    ///     NetHsm,
2437    ///     Passphrase,
2438    ///     SystemState,
2439    ///     UserRole,
2440    /// };
2441    ///
2442    /// # fn main() -> testresult::TestResult {
2443    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2444    /// let nethsm = NetHsm::new(
2445    ///     Connection::new(
2446    ///         "https://example.org/api/v1".try_into()?,
2447    ///         ConnectionSecurity::Unsafe,
2448    ///     ),
2449    ///     Some(Credentials::new(
2450    ///         "admin".parse()?,
2451    ///         Some(Passphrase::new("passphrase".to_string())),
2452    ///     )),
2453    ///     None,
2454    ///     None,
2455    /// )?;
2456    /// // add a user in the Administrator role for a namespace (N-Administrator)
2457    /// nethsm.add_user(
2458    ///     "Namespace1 Admin".to_string(),
2459    ///     UserRole::Administrator,
2460    ///     Passphrase::new("namespace1-admin-passphrase".to_string()),
2461    ///     Some("namespace1~admin1".parse()?),
2462    /// )?;
2463    /// // create accompanying namespace
2464    /// nethsm.add_namespace(&"namespace1".parse()?)?;
2465    ///
2466    /// println!("{:?}", nethsm.upload_update(std::fs::read("update.bin")?)?);
2467    /// assert_eq!(nethsm.state()?, SystemState::Operational);
2468    ///
2469    /// // N-Administrators can not cancel software updates on a NetHSM
2470    /// nethsm.use_credentials(&"namespace1~admin1".parse()?)?;
2471    /// assert!(nethsm.cancel_update().is_err());
2472    ///
2473    /// // R-Administrators can cancel software updates on a NetHSM
2474    /// nethsm.cancel_update()?;
2475    /// assert_eq!(nethsm.state()?, SystemState::Operational);
2476    /// # Ok(())
2477    /// # }
2478    /// ```
2479    /// [software update]: https://docs.nitrokey.com/nethsm/administration#software-update
2480    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2481    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2482    pub fn cancel_update(&self) -> Result<(), Error> {
2483        debug!(
2484            "Cancel an already uploaded update on the NetHSM at {} using {}",
2485            self.url.borrow(),
2486            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2487        );
2488
2489        self.validate_namespace_access(NamespaceSupport::Unsupported, None, None)?;
2490        system_cancel_update_post(&self.create_connection_config()).map_err(|error| {
2491            Error::Api(format!(
2492                "Cancelling update failed: {}",
2493                NetHsmApiError::from(error)
2494            ))
2495        })?;
2496        Ok(())
2497    }
2498
2499    /// Generates [random] bytes.
2500    ///
2501    /// Retrieves `length` [random] bytes from the NetHSM, if it is in
2502    /// [`Operational`][`SystemState::Operational`] [state].
2503    ///
2504    /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
2505    /// [role].
2506    ///
2507    /// # Errors
2508    ///
2509    /// Returns an [`Error::Api`] if retrieving random bytes fails:
2510    /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
2511    /// * the used [`Credentials`] are not correct
2512    /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
2513    ///   [role]
2514    ///
2515    /// # Examples
2516    ///
2517    /// ```no_run
2518    /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase, UserRole};
2519    ///
2520    /// # fn main() -> testresult::TestResult {
2521    /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
2522    /// let nethsm = NetHsm::new(
2523    ///     Connection::new(
2524    ///         "https://example.org/api/v1".try_into()?,
2525    ///         ConnectionSecurity::Unsafe,
2526    ///     ),
2527    ///     Some(Credentials::new(
2528    ///         "admin".parse()?,
2529    ///         Some(Passphrase::new("passphrase".to_string())),
2530    ///     )),
2531    ///     None,
2532    ///     None,
2533    /// )?;
2534    /// // add a system-wide user in the Operator role
2535    /// nethsm.add_user(
2536    ///     "Operator1".to_string(),
2537    ///     UserRole::Operator,
2538    ///     Passphrase::new("operator-passphrase".to_string()),
2539    ///     Some("operator1".parse()?),
2540    /// )?;
2541    /// nethsm.use_credentials(&"operator1".parse()?)?;
2542    ///
2543    /// // get 10 random bytes
2544    /// println!("{:#?}", nethsm.random(10)?);
2545    /// # Ok(())
2546    /// # }
2547    /// ```
2548    /// [random]: https://docs.nitrokey.com/nethsm/operation#random
2549    /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
2550    /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
2551    /// [state]: https://docs.nitrokey.com/nethsm/administration#state
2552    pub fn random(&self, length: u32) -> Result<Vec<u8>, Error> {
2553        debug!(
2554            "Create {length} random bytes on the NetHSM at {} using {}",
2555            self.url.borrow(),
2556            user_or_no_user_string(self.current_credentials.borrow().as_ref()),
2557        );
2558
2559        self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
2560        let base64_bytes = random_post(
2561            &self.create_connection_config(),
2562            RandomRequestData::new(length as i32),
2563        )
2564        .map_err(|error| {
2565            Error::Api(format!(
2566                "Getting random bytes failed: {}",
2567                NetHsmApiError::from(error)
2568            ))
2569        })?
2570        .entity
2571        .random;
2572        Base64::decode_vec(&base64_bytes).map_err(Error::Base64Decode)
2573    }
2574}