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