nethsm/base/impl_key.rs
1//! [`NetHsm`] implementation for cryptographic key support.
2
3use base64ct::{Base64, Encoding};
4use log::debug;
5use md5::{Digest as _, Md5};
6use nethsm_sdk_rs::{
7 apis::default_api::{
8 KeysPostBody,
9 keys_generate_post,
10 keys_get,
11 keys_key_id_cert_delete,
12 keys_key_id_cert_get,
13 keys_key_id_cert_put,
14 keys_key_id_csr_pem_post,
15 keys_key_id_decrypt_post,
16 keys_key_id_delete,
17 keys_key_id_encrypt_post,
18 keys_key_id_get,
19 keys_key_id_public_pem_get,
20 keys_key_id_put,
21 keys_key_id_restrictions_tags_tag_delete,
22 keys_key_id_restrictions_tags_tag_put,
23 keys_key_id_sign_post,
24 keys_post,
25 },
26 models::{
27 DecryptRequestData,
28 DistinguishedName,
29 EncryptRequestData,
30 KeyGenerateRequestData,
31 KeyRestrictions,
32 PrivateKey,
33 PublicKey,
34 SignRequestData,
35 },
36};
37use sha1::Sha1;
38use sha2::{Digest, Sha224, Sha256, Sha384, Sha512};
39
40#[cfg(doc)]
41use crate::{Credentials, SystemState, UserRole};
42use crate::{
43 DecryptMode,
44 EncryptMode,
45 Error,
46 KeyId,
47 KeyMechanism,
48 KeyType,
49 NetHsm,
50 PrivateKeyImport,
51 SignatureType,
52 base::utils::user_or_no_user_string,
53 key_type_matches_length,
54 key_type_matches_mechanisms,
55 nethsm_sdk::NetHsmApiError,
56 user::NamespaceSupport,
57};
58
59impl NetHsm {
60 /// [Generates a new key] on the NetHSM.
61 ///
62 /// [Generates a new key] with customizable features on the NetHSM.
63 /// The provided [`KeyType`] and list of [`KeyMechanism`]s have to match:
64 /// * [`KeyType::Rsa`] requires one of [`KeyMechanism::RsaDecryptionRaw`],
65 /// [`KeyMechanism::RsaDecryptionPkcs1`], [`KeyMechanism::RsaDecryptionOaepMd5`],
66 /// [`KeyMechanism::RsaDecryptionOaepSha1`], [`KeyMechanism::RsaDecryptionOaepSha224`],
67 /// [`KeyMechanism::RsaDecryptionOaepSha256`], [`KeyMechanism::RsaDecryptionOaepSha384`],
68 /// [`KeyMechanism::RsaDecryptionOaepSha512`], [`KeyMechanism::RsaSignaturePkcs1`],
69 /// [`KeyMechanism::RsaSignaturePssMd5`], [`KeyMechanism::RsaSignaturePssSha1`],
70 /// [`KeyMechanism::RsaSignaturePssSha224`], [`KeyMechanism::RsaSignaturePssSha256`],
71 /// [`KeyMechanism::RsaSignaturePssSha384`] or [`KeyMechanism::RsaSignaturePssSha512`]
72 /// * [`KeyType::Curve25519`] requires [`KeyMechanism::EdDsaSignature`]
73 /// * [`KeyType::EcP256`], [`KeyType::EcP384`] and [`KeyType::EcP521`] require
74 /// [`KeyMechanism::EcdsaSignature`]
75 /// * [`KeyType::Generic`] requires one of [`KeyMechanism::AesDecryptionCbc`] or
76 /// [`KeyMechanism::AesEncryptionCbc`]
77 ///
78 /// Optionally the key bit-length using `length`, a custom key ID using `key_id`
79 /// and a list of `tags` to be attached to the new key can be provided.
80 /// If no `key_id` is provided, a unique one is generated automatically.
81 ///
82 /// **WARNING**: If no `tags` are provided, the generated key is usable by all users in the
83 /// [`Operator`][`UserRole::Operator`] [role] in the same scope (e.g. same [namespace]) by
84 /// default!
85 ///
86 /// This call requires using [`Credentials`] of a user in the
87 /// [`Administrator`][`UserRole::Administrator`] [role].
88 ///
89 /// ## Namespaces
90 ///
91 /// * Keys generated by *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users
92 /// in a given [namespace]) are only visible to users in their [namespace]. Only users in the
93 /// [`Operator`][`UserRole::Operator`] [role] in that same [namespace] can be granted access
94 /// to them.
95 /// * Keys generated by *R-Administrators* (system-wide
96 /// [`Administrator`][`UserRole::Administrator`] users) are only visible to system-wide users.
97 /// Only system-wide users in the [`Operator`][`UserRole::Operator`] [role] (not in any
98 /// [namespace]) can be granted access to them.
99 ///
100 /// # Errors
101 ///
102 /// Returns an [`Error::Api`] if generating the key fails:
103 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
104 /// * a key identified by ` key_id` exists already
105 /// * the chosen `length` or `tags` options are not valid
106 /// * the used [`Credentials`] are not correct
107 /// * the used [`Credentials`] are not that of a user in the
108 /// [`Administrator`][`UserRole::Administrator`] [role]
109 ///
110 /// Returns an [`Error::Key`] if
111 /// * the provided combination of `key_type` and `mechanisms` is not valid.
112 /// * the provided combination of `key_type` and `length` is not valid.
113 ///
114 /// # Examples
115 ///
116 /// ```no_run
117 /// use nethsm::{
118 /// Connection,
119 /// ConnectionSecurity,
120 /// Credentials,
121 /// KeyMechanism,
122 /// KeyType,
123 /// NetHsm,
124 /// Passphrase,
125 /// };
126 ///
127 /// # fn main() -> testresult::TestResult {
128 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
129 /// let nethsm = NetHsm::new(
130 /// Connection::new(
131 /// "https://example.org/api/v1".try_into()?,
132 /// ConnectionSecurity::Unsafe,
133 /// ),
134 /// Some(Credentials::new(
135 /// "admin".parse()?,
136 /// Some(Passphrase::new("passphrase".to_string())),
137 /// )),
138 /// None,
139 /// None,
140 /// )?;
141 ///
142 /// // generate a Curve25519 key for signing with custom Key ID and tags
143 /// nethsm.generate_key(
144 /// KeyType::Curve25519,
145 /// vec![KeyMechanism::EdDsaSignature],
146 /// None,
147 /// Some("signing1".parse()?),
148 /// Some(vec!["sign_tag1".to_string(), "sign_tag2".to_string()]),
149 /// )?;
150 ///
151 /// // generate a generic key for symmetric encryption and decryption
152 /// nethsm.generate_key(
153 /// KeyType::Generic,
154 /// vec![
155 /// KeyMechanism::AesEncryptionCbc,
156 /// KeyMechanism::AesDecryptionCbc,
157 /// ],
158 /// Some(128),
159 /// Some("encryption1".parse()?),
160 /// Some(vec!["encryption_tag1".to_string()]),
161 /// )?;
162 /// # Ok(())
163 /// # }
164 /// ```
165 /// [Generates a new key]: https://docs.nitrokey.com/nethsm/operation#generate-key
166 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
167 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
168 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
169 pub fn generate_key(
170 &self,
171 key_type: KeyType,
172 mechanisms: Vec<KeyMechanism>,
173 length: Option<u32>,
174 key_id: Option<KeyId>,
175 tags: Option<Vec<String>>,
176 ) -> Result<KeyId, Error> {
177 debug!(
178 "Generate a key (key type: {key_type}; mechanisms: {}; length: {}; ID: {}, tags: {}) on the NetHSM at {} using {}",
179 mechanisms
180 .iter()
181 .map(|mechanism| mechanism.to_string())
182 .collect::<Vec<String>>()
183 .join(", "),
184 if let Some(length) = length {
185 length.to_string()
186 } else {
187 "n/a".to_string()
188 },
189 if let Some(key_id) = key_id.as_ref() {
190 key_id.to_string()
191 } else {
192 "n/a".to_string()
193 },
194 if let Some(tags) = tags.as_ref() {
195 tags.join(", ")
196 } else {
197 "n/a".to_string()
198 },
199 self.url.borrow(),
200 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
201 );
202
203 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
204 // ensure the key_type - mechanisms combinations are valid
205 key_type_matches_mechanisms(key_type, &mechanisms)?;
206 // ensure the key_type - length combination is valid
207 key_type_matches_length(key_type, length)?;
208
209 Ok(keys_generate_post(
210 &self.create_connection_config(),
211 KeyGenerateRequestData {
212 mechanisms: mechanisms
213 .into_iter()
214 .map(|mechanism| mechanism.into())
215 .collect(),
216 r#type: key_type.into(),
217 length: length.map(|length| length as i32),
218 id: key_id.map(Into::into),
219 restrictions: tags.map(|tags| Box::new(KeyRestrictions { tags: Some(tags) })),
220 },
221 )
222 .map_err(|error| {
223 Error::Api(format!(
224 "Creating key failed: {}",
225 NetHsmApiError::from(error)
226 ))
227 })?
228 .entity
229 .id
230 .parse()?)
231 }
232
233 /// Imports an existing private key.
234 ///
235 /// [Imports an existing key] with custom features into the NetHSM.
236 /// The [`KeyType`] implied by the provided [`PrivateKeyImport`] and the list of
237 /// [`KeyMechanism`]s have to match:
238 /// * [`KeyType::Rsa`] must be used with [`KeyMechanism::RsaDecryptionRaw`],
239 /// [`KeyMechanism::RsaDecryptionPkcs1`], [`KeyMechanism::RsaDecryptionOaepMd5`],
240 /// [`KeyMechanism::RsaDecryptionOaepSha1`], [`KeyMechanism::RsaDecryptionOaepSha224`],
241 /// [`KeyMechanism::RsaDecryptionOaepSha256`], [`KeyMechanism::RsaDecryptionOaepSha384`],
242 /// [`KeyMechanism::RsaDecryptionOaepSha512`], [`KeyMechanism::RsaSignaturePkcs1`],
243 /// [`KeyMechanism::RsaSignaturePssMd5`], [`KeyMechanism::RsaSignaturePssSha1`],
244 /// [`KeyMechanism::RsaSignaturePssSha224`], [`KeyMechanism::RsaSignaturePssSha256`],
245 /// [`KeyMechanism::RsaSignaturePssSha384`] or [`KeyMechanism::RsaSignaturePssSha512`]
246 /// * [`KeyType::Curve25519`] must be used with [`KeyMechanism::EdDsaSignature`]
247 /// * [`KeyType::EcP256`], [`KeyType::EcP384`] and [`KeyType::EcP521`] must be used with
248 /// [`KeyMechanism::EcdsaSignature`]
249 /// * [`KeyType::Generic`] must be used with [`KeyMechanism::AesDecryptionCbc`] or
250 /// [`KeyMechanism::AesEncryptionCbc`]
251 ///
252 /// Optionally a custom Key ID using `key_id` and a list of `tags` to be attached to the new key
253 /// can be provided.
254 /// If no `key_id` is provided, a unique one is generated automatically.
255 ///
256 /// **WARNING**: If no `tags` are provided, the imported key is usable by all users in the
257 /// [`Operator`][`UserRole::Operator`] [role] in the same scope (e.g. same [namespace]) by
258 /// default!
259 ///
260 /// This call requires using [`Credentials`] of a user in the
261 /// [`Administrator`][`UserRole::Administrator`] [role].
262 ///
263 /// ## Namespaces
264 ///
265 /// * Keys imported by *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in
266 /// a given [namespace]) are only visible to users in their [namespace]. Only users in the
267 /// [`Operator`][`UserRole::Operator`] [role] in that same [namespace] can be granted access
268 /// to them.
269 /// * Keys imported by *R-Administrators* (system-wide
270 /// [`Administrator`][`UserRole::Administrator`] users) are only visible to system-wide users.
271 /// Only system-wide users in the [`Operator`][`UserRole::Operator`] [role] (not in any
272 /// [namespace]) can be granted access to them.
273 ///
274 /// # Errors
275 ///
276 /// Returns an [`Error::Api`] if importing the key fails:
277 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
278 /// * a key identified by ` key_id` exists already
279 /// * the chosen `tags` option is not valid
280 /// * the used [`Credentials`] are not correct
281 /// * the used [`Credentials`] are not that of a user in the
282 /// [`Administrator`][`UserRole::Administrator`] [role]
283 ///
284 /// Returns an [`Error::Key`] if the provided combination of `key_data` and `mechanisms` is not
285 /// valid.
286 ///
287 /// # Examples
288 ///
289 /// ```no_run
290 /// use nethsm::{Connection, ConnectionSecurity, Credentials, PrivateKeyImport, KeyMechanism, KeyType, NetHsm, Passphrase};
291 /// use rsa::pkcs8::{DecodePrivateKey, EncodePrivateKey};
292 /// use rsa::RsaPrivateKey;
293 ///
294 /// # fn main() -> testresult::TestResult {
295 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
296 /// let nethsm = NetHsm::new(
297 /// Connection::new(
298 /// "https://example.org/api/v1".try_into()?,
299 /// ConnectionSecurity::Unsafe,
300 /// ),
301 /// Some(Credentials::new(
302 /// "admin".parse()?,
303 /// Some(Passphrase::new("passphrase".to_string())),
304 /// )),
305 /// None,
306 /// None,
307 /// )?;
308 ///
309 /// // create a 4096 bit RSA private key and return it as PKCS#8 private key in ASN.1 DER-encoded format
310 /// let private_key = {
311 /// let mut rng = rand::thread_rng();
312 /// let private_key = RsaPrivateKey::new(&mut rng, 4096)?;
313 /// private_key.to_pkcs8_der()?
314 /// };
315 ///
316 /// // import an RSA key for PKCS1 signatures
317 /// nethsm.import_key(
318 /// vec![KeyMechanism::RsaSignaturePkcs1],
319 /// PrivateKeyImport::new(KeyType::Rsa, private_key.as_bytes())?,
320 /// Some("signing2".parse()?),
321 /// Some(vec!["signing_tag3".to_string()]),
322 /// )?;
323 /// # Ok(())
324 /// # }
325 /// ```
326 /// [Imports an existing key]: https://docs.nitrokey.com/nethsm/operation#import-key
327 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
328 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
329 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
330 pub fn import_key(
331 &self,
332 mechanisms: Vec<KeyMechanism>,
333 key_data: PrivateKeyImport,
334 key_id: Option<KeyId>,
335 tags: Option<Vec<String>>,
336 ) -> Result<KeyId, Error> {
337 debug!(
338 "Import a key (mechanisms: {}; ID: {}, tags: {}) to the NetHSM at {} using {}",
339 mechanisms
340 .iter()
341 .map(|mechanism| mechanism.to_string())
342 .collect::<Vec<String>>()
343 .join(", "),
344 if let Some(key_id) = key_id.as_ref() {
345 key_id.to_string()
346 } else {
347 "n/a".to_string()
348 },
349 if let Some(tags) = tags.as_ref() {
350 tags.join(", ")
351 } else {
352 "n/a".to_string()
353 },
354 self.url.borrow(),
355 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
356 );
357
358 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
359 // ensure the key_type - mechanisms combinations are valid
360 let key_type = key_data.key_type();
361 key_type_matches_mechanisms(key_type, &mechanisms)?;
362
363 let restrictions = tags.map(|tags| Box::new(KeyRestrictions { tags: Some(tags) }));
364 let private = Box::new(key_data.into());
365 let mechanisms = mechanisms
366 .into_iter()
367 .map(|mechanism| mechanism.into())
368 .collect();
369
370 if let Some(key_id) = key_id {
371 keys_key_id_put(
372 &self.create_connection_config(),
373 key_id.as_ref(),
374 nethsm_sdk_rs::apis::default_api::KeysKeyIdPutBody::ApplicationJson(PrivateKey {
375 mechanisms,
376 r#type: key_type.into(),
377 private,
378 restrictions,
379 }),
380 )
381 .map_err(|error| {
382 Error::Api(format!(
383 "Importing key failed: {}",
384 NetHsmApiError::from(error)
385 ))
386 })?;
387 Ok(key_id)
388 } else {
389 Ok(keys_post(
390 &self.create_connection_config(),
391 KeysPostBody::ApplicationJson(PrivateKey {
392 mechanisms,
393 r#type: key_type.into(),
394 private,
395 restrictions,
396 }),
397 )
398 .map_err(|error| {
399 Error::Api(format!(
400 "Importing key failed: {}",
401 NetHsmApiError::from(error)
402 ))
403 })?
404 .entity
405 .id
406 .parse()?)
407 }
408 }
409
410 /// [Deletes a key] from the NetHSM.
411 ///
412 /// [Deletes a key] identified by `key_id` from the NetHSM.
413 ///
414 /// This call requires using [`Credentials`] of a user in the
415 /// [`Administrator`][`UserRole::Administrator`] [role].
416 ///
417 /// ## Namespaces
418 ///
419 /// * Keys in a [namespace] can only be deleted by *N-Administrators*
420 /// ([`Administrator`][`UserRole::Administrator`] users in a given [namespace]) of that
421 /// [namespace] (*R-Administrators* have no access to keys in a [namespace]). **NOTE**:
422 /// Calling [`delete_namespace`][`NetHsm::delete_namespace`] deletes **all keys** in a
423 /// [namespace]!
424 /// * System-wide keys can only be deleted by *R-Administrators* (system-wide
425 /// [`Administrator`][`UserRole::Administrator`] users).
426 ///
427 /// # Errors
428 ///
429 /// Returns an [`Error::Api`] if deleting the key fails:
430 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
431 /// * no key identified by `key_id` exists
432 /// * the used [`Credentials`] are not correct
433 /// * the used [`Credentials`] are not that of a user in the
434 /// [`Administrator`][`UserRole::Administrator`] [role]
435 ///
436 /// # Examples
437 ///
438 /// ```no_run
439 /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
440 ///
441 /// # fn main() -> testresult::TestResult {
442 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
443 /// let nethsm = NetHsm::new(
444 /// Connection::new(
445 /// "https://example.org/api/v1".try_into()?,
446 /// ConnectionSecurity::Unsafe,
447 /// ),
448 /// Some(Credentials::new(
449 /// "admin".parse()?,
450 /// Some(Passphrase::new("passphrase".to_string())),
451 /// )),
452 /// None,
453 /// None,
454 /// )?;
455 ///
456 /// // delete a key with the Key ID "signing1"
457 /// nethsm.delete_key(&"signing1".parse()?)?;
458 /// # Ok(())
459 /// # }
460 /// ```
461 /// [Deletes a key]: https://docs.nitrokey.com/nethsm/operation#delete-key
462 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
463 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
464 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
465 pub fn delete_key(&self, key_id: &KeyId) -> Result<(), Error> {
466 debug!(
467 "Delete the key \"{key_id}\" on the NetHSM at {} using {}",
468 self.url.borrow(),
469 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
470 );
471
472 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
473 keys_key_id_delete(&self.create_connection_config(), key_id.as_ref()).map_err(|error| {
474 Error::Api(format!(
475 "Deleting key failed: {}",
476 NetHsmApiError::from(error)
477 ))
478 })?;
479 Ok(())
480 }
481
482 /// Gets [details about a key].
483 ///
484 /// Gets [details about a key] identified by `key_id`.
485 ///
486 /// This call requires using [`Credentials`] of a user in the
487 /// [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`]
488 /// [role].
489 ///
490 /// ## Namespaces
491 ///
492 /// * Users in a [namespace] can only get details about keys in their own [namespace].
493 /// * System-wide users (not in a [namespace]) can only get details about system-wide keys.
494 ///
495 /// # Errors
496 ///
497 /// Returns an [`Error::Api`] if getting the key details fails:
498 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
499 /// * no key identified by `key_id` exists
500 /// * the used [`Credentials`] are not correct
501 /// * the used [`Credentials`] are not those of a user in the
502 /// [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`] [role]
503 ///
504 /// # Examples
505 ///
506 /// ```no_run
507 /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
508 ///
509 /// # fn main() -> testresult::TestResult {
510 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
511 /// let nethsm = NetHsm::new(
512 /// Connection::new(
513 /// "https://example.org/api/v1".try_into()?,
514 /// ConnectionSecurity::Unsafe,
515 /// ),
516 /// Some(Credentials::new(
517 /// "admin".parse()?,
518 /// Some(Passphrase::new("passphrase".to_string())),
519 /// )),
520 /// None,
521 /// None,
522 /// )?;
523 ///
524 /// // get details on a key with the Key ID "signing1"
525 /// println!("{:?}", nethsm.get_key(&"signing1".parse()?)?);
526 /// # Ok(())
527 /// # }
528 /// ```
529 /// [details about a key]: https://docs.nitrokey.com/nethsm/operation#show-key-details
530 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
531 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
532 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
533 pub fn get_key(&self, key_id: &KeyId) -> Result<PublicKey, Error> {
534 debug!(
535 "Retrieve details about the key \"{key_id}\" from the NetHSM at {} using {}",
536 self.url.borrow(),
537 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
538 );
539
540 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
541 Ok(
542 keys_key_id_get(&self.create_connection_config(), key_id.as_ref())
543 .map_err(|error| {
544 Error::Api(format!(
545 "Getting key failed: {}",
546 NetHsmApiError::from(error)
547 ))
548 })?
549 .entity,
550 )
551 }
552
553 /// Gets a [list of Key IDs] on the NetHSM.
554 ///
555 /// Optionally `filter` can be provided for matching against Key IDs.
556 ///
557 /// This call requires using [`Credentials`] of a user in the
558 /// [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`]
559 /// [role].
560 ///
561 /// ## Namespaces
562 ///
563 /// * Users in a [namespace] can only list key IDs of keys in their own [namespace].
564 /// * System-wide users (not in a [namespace]) can only list key IDs of system-wide keys.
565 ///
566 /// # Errors
567 ///
568 /// Returns an [`Error::Api`] if getting the list of Key IDs fails:
569 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
570 /// * the used [`Credentials`] are not correct
571 /// * the used [`Credentials`] are not those of a user in the
572 /// [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`] [role]
573 ///
574 /// # Examples
575 ///
576 /// ```no_run
577 /// use nethsm::{Connection, ConnectionSecurity, Credentials, NetHsm, Passphrase};
578 ///
579 /// # fn main() -> testresult::TestResult {
580 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
581 /// let nethsm = NetHsm::new(
582 /// Connection::new(
583 /// "https://example.org/api/v1".try_into()?,
584 /// ConnectionSecurity::Unsafe,
585 /// ),
586 /// Some(Credentials::new(
587 /// "admin".parse()?,
588 /// Some(Passphrase::new("passphrase".to_string())),
589 /// )),
590 /// None,
591 /// None,
592 /// )?;
593 ///
594 /// // get all Key IDs
595 /// println!("{:?}", nethsm.get_keys(None)?);
596 ///
597 /// // get all Key IDs that begin with "signing"
598 /// println!("{:?}", nethsm.get_keys(Some("signing"))?);
599 /// # Ok(())
600 /// # }
601 /// ```
602 /// [list of Key IDs]: https://docs.nitrokey.com/nethsm/operation#list-keys
603 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
604 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
605 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
606 pub fn get_keys(&self, filter: Option<&str>) -> Result<Vec<KeyId>, Error> {
607 debug!(
608 "Get key IDs{} from the NetHSM at {} using {}",
609 if let Some(filter) = filter {
610 format!(" based on filter {filter}")
611 } else {
612 "".to_string()
613 },
614 self.url.borrow(),
615 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
616 );
617
618 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
619 let valid_keys = {
620 let mut invalid_keys = Vec::new();
621 let valid_keys = keys_get(&self.create_connection_config(), filter)
622 .map_err(|error| {
623 Error::Api(format!(
624 "Getting keys failed: {}",
625 NetHsmApiError::from(error)
626 ))
627 })?
628 .entity
629 .into_iter()
630 .filter_map(|x| {
631 if let Ok(key) = KeyId::new(x.id.clone()) {
632 Some(key)
633 } else {
634 invalid_keys.push(x.id);
635 None
636 }
637 })
638 .collect::<Vec<KeyId>>();
639
640 if !invalid_keys.is_empty() {
641 return Err(crate::key::Error::InvalidKeyIds {
642 key_ids: invalid_keys,
643 }
644 .into());
645 }
646
647 valid_keys
648 };
649
650 Ok(valid_keys)
651 }
652
653 /// Gets the [public key of a key] on the NetHSM.
654 ///
655 /// Gets the [public key of a key] on the NetHSM, identified by `key_id`.
656 /// The public key is returned in [X.509] Privacy-Enhanced Mail ([PEM]) format.
657 ///
658 /// This call requires using [`Credentials`] of a user in the
659 /// [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`]
660 /// [role].
661 ///
662 /// ## Namespaces
663 ///
664 /// * Users in a [namespace] can only get public keys of keys in their own [namespace].
665 /// * System-wide users (not in a [namespace]) can only get public keys of system-wide keys.
666 ///
667 /// # Errors
668 ///
669 /// Returns an [`Error::Api`] if getting the public key fails:
670 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
671 /// * no key identified by `key_id` exists
672 /// * the used [`Credentials`] are not correct
673 /// * the used [`Credentials`] are not that of a user in the
674 /// [`Administrator`][`UserRole::Administrator`] or [`Operator`][`UserRole::Operator`] [role]
675 /// * the targeted key is a symmetric key (i.e. [`KeyType::Generic`]) and therefore can not
676 /// provide a public key
677 ///
678 /// # Examples
679 ///
680 /// ```no_run
681 /// use nethsm::{
682 /// Connection,
683 /// ConnectionSecurity,
684 /// Credentials,
685 /// KeyMechanism,
686 /// KeyType,
687 /// NetHsm,
688 /// Passphrase,
689 /// };
690 ///
691 /// # fn main() -> testresult::TestResult {
692 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
693 /// let nethsm = NetHsm::new(
694 /// Connection::new(
695 /// "https://example.org/api/v1".try_into()?,
696 /// ConnectionSecurity::Unsafe,
697 /// ),
698 /// Some(Credentials::new(
699 /// "admin".parse()?,
700 /// Some(Passphrase::new("passphrase".to_string())),
701 /// )),
702 /// None,
703 /// None,
704 /// )?;
705 /// // generate system-wide key with tag
706 /// nethsm.generate_key(
707 /// KeyType::Curve25519,
708 /// vec![KeyMechanism::EdDsaSignature],
709 /// None,
710 /// Some("signing1".parse()?),
711 /// Some(vec!["tag1".to_string()]),
712 /// )?;
713 ///
714 /// // get public key for a key with Key ID "signing1"
715 /// println!("{:?}", nethsm.get_public_key(&"signing1".parse()?)?);
716 /// # Ok(())
717 /// # }
718 /// ```
719 /// [public key of a key]: https://docs.nitrokey.com/nethsm/operation#show-key-details
720 /// [X.509]: https://en.wikipedia.org/wiki/X.509
721 /// [PEM]: https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail
722 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
723 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
724 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
725 pub fn get_public_key(&self, key_id: &KeyId) -> Result<String, Error> {
726 debug!(
727 "Retrieve public key of key \"{key_id}\" from the NetHSM at {} using {}",
728 self.url.borrow(),
729 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
730 );
731
732 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
733 Ok(
734 keys_key_id_public_pem_get(&self.create_connection_config(), key_id.as_ref())
735 .map_err(|error| {
736 Error::Api(format!(
737 "Getting public key failed: {}",
738 NetHsmApiError::from(error)
739 ))
740 })?
741 .entity,
742 )
743 }
744
745 /// Adds a [tag for a key].
746 ///
747 /// Adds `tag` for a key, identified by `key_id`.
748 ///
749 /// A [tag for a key] is prerequisite to adding the same tag to a user in the
750 /// [`Operator`][`UserRole::Operator`] [role] and thus granting it access to the key.
751 ///
752 /// This call requires using [`Credentials`] of a user in the
753 /// [`Administrator`][`UserRole::Administrator`] [role].
754 ///
755 /// ## Namespaces
756 ///
757 /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
758 /// [namespace]) are only able to tag keys in their own [namespace].
759 /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
760 /// only able to tag system-wide keys.
761 ///
762 /// # Errors
763 ///
764 /// Returns an [`Error::Api`] if adding a tag to a key fails:
765 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
766 /// * no key identified by `key_id` exists
767 /// * `tag` is already associated with the key
768 /// * `tag` is invalid
769 /// * the used [`Credentials`] are not correct
770 /// * the used [`Credentials`] are not that of a user in the
771 /// [`Administrator`][`UserRole::Administrator`] [role]
772 /// * a key in a [namespace] is attempted to be tagged by an *R-Administrator*
773 /// * a system-wide key is attempted to be tagged by an *N-Administrator*
774 ///
775 /// # Examples
776 ///
777 /// ```no_run
778 /// use nethsm::{
779 /// Connection,
780 /// ConnectionSecurity,
781 /// Credentials,
782 /// KeyMechanism,
783 /// KeyType,
784 /// NetHsm,
785 /// Passphrase,
786 /// };
787 ///
788 /// # fn main() -> testresult::TestResult {
789 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
790 /// let nethsm = NetHsm::new(
791 /// Connection::new(
792 /// "https://example.org/api/v1".try_into()?,
793 /// ConnectionSecurity::Unsafe,
794 /// ),
795 /// Some(Credentials::new(
796 /// "admin".parse()?,
797 /// Some(Passphrase::new("passphrase".to_string())),
798 /// )),
799 /// None,
800 /// None,
801 /// )?;
802 /// // generate system-wide key with tag
803 /// nethsm.generate_key(
804 /// KeyType::Curve25519,
805 /// vec![KeyMechanism::EdDsaSignature],
806 /// None,
807 /// Some("signing1".parse()?),
808 /// Some(vec!["tag1".to_string()]),
809 /// )?;
810 ///
811 /// // add the tag "important" to a key with Key ID "signing1"
812 /// nethsm.add_key_tag(&"signing1".parse()?, "important")?;
813 /// # Ok(())
814 /// # }
815 /// ```
816 /// [tag for a key]: https://docs.nitrokey.com/nethsm/operation#tags-for-keys
817 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
818 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
819 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
820 pub fn add_key_tag(&self, key_id: &KeyId, tag: &str) -> Result<(), Error> {
821 debug!(
822 "Add tag \"{tag}\" to key \"{key_id}\" on the NetHSM at {} using {}",
823 self.url.borrow(),
824 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
825 );
826
827 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
828 keys_key_id_restrictions_tags_tag_put(
829 &self.create_connection_config(),
830 tag,
831 key_id.as_ref(),
832 )
833 .map_err(|error| {
834 Error::Api(format!(
835 "Adding tag for key failed: {}",
836 NetHsmApiError::from(error)
837 ))
838 })?;
839 Ok(())
840 }
841
842 /// Deletes a [tag from a key].
843 ///
844 /// Deletes `tag` from a key, identified by `key_id` on the NetHSM.
845 ///
846 /// Deleting a [tag from a key] removes access to it for any user in the
847 /// [`Operator`][`UserRole::Operator`] [role], that carries the same tag.
848 ///
849 /// This call requires using [`Credentials`] of a user in the
850 /// [`Administrator`][`UserRole::Administrator`] [role].
851 ///
852 /// ## Namespaces
853 ///
854 /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
855 /// [namespace]) are only able to delete tags from keys in their own [namespace].
856 /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
857 /// only able to delete tags from system-wide keys.
858 ///
859 /// # Errors
860 ///
861 /// Returns an [`Error::Api`] if adding a tag to a key fails:
862 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
863 /// * no key identified by `key_id` exists
864 /// * `tag` is not associated with the key
865 /// * the used [`Credentials`] are not correct
866 /// * the used [`Credentials`] are not that of a user in the
867 /// [`Administrator`][`UserRole::Administrator`] [role]
868 /// * the tag for a key in a [namespace] is attempted to be removed by an *R-Administrator*
869 /// * the tag for a system-wide key is attempted to be removed by an *N-Administrator*
870 ///
871 /// # Examples
872 ///
873 /// ```no_run
874 /// use nethsm::{
875 /// Connection,
876 /// ConnectionSecurity,
877 /// Credentials,
878 /// KeyMechanism,
879 /// KeyType,
880 /// NetHsm,
881 /// Passphrase,
882 /// };
883 ///
884 /// # fn main() -> testresult::TestResult {
885 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
886 /// let nethsm = NetHsm::new(
887 /// Connection::new(
888 /// "https://example.org/api/v1".try_into()?,
889 /// ConnectionSecurity::Unsafe,
890 /// ),
891 /// Some(Credentials::new(
892 /// "admin".parse()?,
893 /// Some(Passphrase::new("passphrase".to_string())),
894 /// )),
895 /// None,
896 /// None,
897 /// )?;
898 /// // generate system-wide key with tag
899 /// nethsm.generate_key(
900 /// KeyType::Curve25519,
901 /// vec![KeyMechanism::EdDsaSignature],
902 /// None,
903 /// Some("signing1".parse()?),
904 /// Some(vec!["tag1".to_string(), "important".to_string()]),
905 /// )?;
906 ///
907 /// // remove the tag "important" from a key with Key ID "signing1"
908 /// nethsm.delete_key_tag(&"signing1".parse()?, "important")?;
909 /// # Ok(())
910 /// # }
911 /// ```
912 /// [tag from a key]: https://docs.nitrokey.com/nethsm/operation#tags-for-keys
913 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
914 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
915 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
916 pub fn delete_key_tag(&self, key_id: &KeyId, tag: &str) -> Result<(), Error> {
917 debug!(
918 "Delete tag \"{tag}\" from key \"{key_id}\" on the NetHSM at {} using {}",
919 self.url.borrow(),
920 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
921 );
922
923 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
924 keys_key_id_restrictions_tags_tag_delete(
925 &self.create_connection_config(),
926 tag,
927 key_id.as_ref(),
928 )
929 .map_err(|error| {
930 Error::Api(format!(
931 "Deleting tag for key failed: {}",
932 NetHsmApiError::from(error)
933 ))
934 })?;
935 Ok(())
936 }
937
938 /// Imports a [certificate for a key].
939 ///
940 /// Imports a [certificate for a key] identified by `key_id`.
941 /// Certificates up to 1 MiB in size are supported.
942 /// **NOTE**: The imported bytes are not validated!
943 ///
944 /// This call requires using [`Credentials`] of a user in the
945 /// [`Administrator`][`UserRole::Administrator`] [role].
946 ///
947 /// ## Namespaces
948 ///
949 /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
950 /// [namespace]) are only able to import certificates for keys in their own [namespace].
951 /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
952 /// only able to import certificates for system-wide keys.
953 ///
954 /// # Errors
955 ///
956 /// Returns an [`Error::Api`] if importing a [certificate for a key] fails:
957 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
958 /// * no key identified by `key_id` exists
959 /// * the `data` is invalid
960 /// * the used [`Credentials`] are not correct
961 /// * the used [`Credentials`] are not that of a user in the
962 /// [`Administrator`][`UserRole::Administrator`] [role]
963 ///
964 /// # Examples
965 ///
966 /// ```no_run
967 /// use std::time::SystemTime;
968 /// use nethsm::{
969 /// Connection,
970 /// ConnectionSecurity,
971 /// Credentials,
972 /// KeyMechanism,
973 /// KeyType,
974 /// NetHsm,
975 /// OpenPgpKeyUsageFlags,
976 /// OpenPgpVersion,
977 /// Passphrase,
978 /// UserRole,
979 /// };
980 ///
981 /// # fn main() -> testresult::TestResult {
982 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
983 /// let nethsm = NetHsm::new(
984 /// Connection::new(
985 /// "https://example.org/api/v1".try_into()?,
986 /// ConnectionSecurity::Unsafe,
987 /// ),
988 /// Some(Credentials::new(
989 /// "admin".parse()?,
990 /// Some(Passphrase::new("passphrase".to_string())),
991 /// )),
992 /// None,
993 /// None,
994 /// )?;
995 /// // add a system-wide user in the Operator role
996 /// nethsm.add_user(
997 /// "Operator1".to_string(),
998 /// UserRole::Operator,
999 /// Passphrase::new("operator-passphrase".to_string()),
1000 /// Some("operator1".parse()?),
1001 /// )?;
1002 /// // generate system-wide key with tag
1003 /// nethsm.generate_key(
1004 /// KeyType::Curve25519,
1005 /// vec![KeyMechanism::EdDsaSignature],
1006 /// None,
1007 /// Some("signing1".parse()?),
1008 /// Some(vec!["tag1".to_string()]),
1009 /// )?;
1010 /// // tag system-wide user in Operator role for access to signing key
1011 /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
1012 /// // use the Operator credentials to create an OpenPGP certificate for a key
1013 /// nethsm.use_credentials(&"operator1".parse()?)?;
1014 /// let openpgp_cert = nethsm.create_openpgp_cert(
1015 /// &"signing1".parse()?,
1016 /// OpenPgpKeyUsageFlags::default(),
1017 /// "Test <test@example.org>".parse()?,
1018 /// SystemTime::now().into(),
1019 /// OpenPgpVersion::V4,
1020 /// )?;
1021 ///
1022 /// // use the Administrator credentials to import the OpenPGP certificate as certificate for the key
1023 /// nethsm.use_credentials(&"admin".parse()?)?;
1024 /// assert!(nethsm.get_key_certificate(&"signing1".parse()?).is_err());
1025 /// nethsm.import_key_certificate(&"signing1".parse()?, openpgp_cert)?;
1026 /// assert!(nethsm.get_key_certificate(&"signing1".parse()?).is_ok());
1027 /// # Ok(())
1028 /// # }
1029 /// ```
1030 /// [certificate for a key]: https://docs.nitrokey.com/nethsm/operation#key-certificates
1031 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1032 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1033 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1034 pub fn import_key_certificate(&self, key_id: &KeyId, data: Vec<u8>) -> Result<(), Error> {
1035 debug!(
1036 "Import certificate for key \"{key_id}\" on the NetHSM at {} using {}",
1037 self.url.borrow(),
1038 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1039 );
1040
1041 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1042 keys_key_id_cert_put(&self.create_connection_config(), key_id.as_ref(), data).map_err(
1043 |error| {
1044 Error::Api(format!(
1045 "Importing certificate for key failed: {}",
1046 NetHsmApiError::from(error)
1047 ))
1048 },
1049 )?;
1050 Ok(())
1051 }
1052
1053 /// Gets the [certificate for a key].
1054 ///
1055 /// Gets the [certificate for a key] identified by `key_id` and returns it as a byte vector.
1056 /// Returns [`None`] if no certificate is associated with a key identified by `key_id`.
1057 ///
1058 /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
1059 /// or [`Administrator`][`UserRole::Administrator`] [role].
1060 ///
1061 /// ## Namespaces
1062 ///
1063 /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
1064 /// [namespace]) are only able to get certificates for keys in their own [namespace].
1065 /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
1066 /// only able to get certificates for system-wide keys.
1067 ///
1068 /// # Errors
1069 ///
1070 /// Returns an [`Error::Api`] if getting the [certificate for a key] fails:
1071 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1072 /// * no key identified by `key_id` exists
1073 /// * the used [`Credentials`] are not correct
1074 /// * the used [`Credentials`] are not those of a user in the [`Operator`][`UserRole::Operator`]
1075 /// or [`Administrator`][`UserRole::Administrator`] [role]
1076 ///
1077 /// # Examples
1078 ///
1079 /// ```no_run
1080 /// use std::time::SystemTime;
1081 /// use nethsm::{
1082 /// Connection,
1083 /// ConnectionSecurity,
1084 /// Credentials,
1085 /// KeyMechanism,
1086 /// KeyType,
1087 /// NetHsm,
1088 /// OpenPgpKeyUsageFlags,
1089 /// OpenPgpVersion,
1090 /// Passphrase,
1091 /// UserRole,
1092 /// };
1093 ///
1094 /// # fn main() -> testresult::TestResult {
1095 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1096 /// let nethsm = NetHsm::new(
1097 /// Connection::new(
1098 /// "https://example.org/api/v1".try_into()?,
1099 /// ConnectionSecurity::Unsafe,
1100 /// ),
1101 /// Some(Credentials::new(
1102 /// "admin".parse()?,
1103 /// Some(Passphrase::new("passphrase".to_string())),
1104 /// )),
1105 /// None,
1106 /// None,
1107 /// )?;
1108 /// // add a system-wide user in the Operator role
1109 /// nethsm.add_user(
1110 /// "Operator1".to_string(),
1111 /// UserRole::Operator,
1112 /// Passphrase::new("operator-passphrase".to_string()),
1113 /// Some("operator1".parse()?),
1114 /// )?;
1115 /// // generate system-wide key with tag
1116 /// nethsm.generate_key(
1117 /// KeyType::Curve25519,
1118 /// vec![KeyMechanism::EdDsaSignature],
1119 /// None,
1120 /// Some("signing1".parse()?),
1121 /// Some(vec!["tag1".to_string()]),
1122 /// )?;
1123 /// // tag system-wide user in Operator role for access to signing key
1124 /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
1125 /// // use the Operator credentials to create an OpenPGP certificate for a key
1126 /// nethsm.use_credentials(&"operator1".parse()?)?;
1127 /// let openpgp_cert = nethsm.create_openpgp_cert(
1128 /// &"signing1".parse()?,
1129 /// OpenPgpKeyUsageFlags::default(),
1130 /// "Test <test@example.org>".parse()?,
1131 /// SystemTime::now().into(),
1132 /// OpenPgpVersion::V4,
1133 /// )?;
1134 /// // use the Administrator credentials to import the OpenPGP certificate as certificate for the key
1135 /// nethsm.use_credentials(&"admin".parse()?)?;
1136 /// nethsm.import_key_certificate(&"signing1".parse()?, openpgp_cert)?;
1137 ///
1138 /// // get the certificate associated with a key
1139 /// println!("{:?}", nethsm.get_key_certificate(&"signing1".parse()?)?);
1140 /// # Ok(())
1141 /// # }
1142 /// ```
1143 /// [certificate for a key]: https://docs.nitrokey.com/nethsm/operation#key-certificates
1144 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1145 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1146 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1147 pub fn get_key_certificate(&self, key_id: &KeyId) -> Result<Option<Vec<u8>>, Error> {
1148 debug!(
1149 "Retrieve the certificate of the key \"{key_id}\" on the NetHSM at {} using {}",
1150 self.url.borrow(),
1151 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1152 );
1153
1154 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1155 match keys_key_id_cert_get(&self.create_connection_config(), key_id.as_ref()) {
1156 Ok(response) => Ok(Some(response.entity)),
1157 Err(nethsm_sdk_rs::apis::Error::ResponseError(error)) if error.status == 404 => {
1158 Ok(None)
1159 }
1160 Err(error) => Err(Error::Api(format!(
1161 "Getting certificate for key failed: {}",
1162 NetHsmApiError::from(error)
1163 ))),
1164 }
1165 }
1166
1167 /// Deletes the [certificate for a key].
1168 ///
1169 /// Deletes the [certificate for a key] identified by `key_id`.
1170 ///
1171 /// This call requires using [`Credentials`] of a user in the
1172 /// [`Administrator`][`UserRole::Administrator`] [role].
1173 ///
1174 /// ## Namespaces
1175 ///
1176 /// * *N-Administrators* ([`Administrator`][`UserRole::Administrator`] users in a given
1177 /// [namespace]) are only able to delete certificates for keys in their own [namespace].
1178 /// * *R-Administrators* (system-wide [`Administrator`][`UserRole::Administrator`] users) are
1179 /// only able to delete certificates for system-wide keys.
1180 ///
1181 /// # Errors
1182 ///
1183 /// Returns an [`Error::Api`] if deleting the [certificate for a key] fails:
1184 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1185 /// * no key identified by `key_id` exists
1186 /// * no certificate is associated with the key
1187 /// * the used [`Credentials`] are not correct
1188 /// * the used [`Credentials`] are not that of a user in the
1189 /// [`Administrator`][`UserRole::Administrator`] [role]
1190 ///
1191 /// # Examples
1192 ///
1193 /// ```no_run
1194 /// use std::time::SystemTime;
1195 /// use nethsm::{
1196 /// Connection,
1197 /// ConnectionSecurity,
1198 /// Credentials,
1199 /// KeyMechanism,
1200 /// KeyType,
1201 /// NetHsm,
1202 /// OpenPgpKeyUsageFlags,
1203 /// OpenPgpVersion,
1204 /// Passphrase,
1205 /// UserRole,
1206 /// };
1207 ///
1208 /// # fn main() -> testresult::TestResult {
1209 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1210 /// let nethsm = NetHsm::new(
1211 /// Connection::new(
1212 /// "https://example.org/api/v1".try_into()?,
1213 /// ConnectionSecurity::Unsafe,
1214 /// ),
1215 /// Some(Credentials::new(
1216 /// "admin".parse()?,
1217 /// Some(Passphrase::new("passphrase".to_string())),
1218 /// )),
1219 /// None,
1220 /// None,
1221 /// )?;
1222 /// // add a system-wide user in the Operator role
1223 /// nethsm.add_user(
1224 /// "Operator1".to_string(),
1225 /// UserRole::Operator,
1226 /// Passphrase::new("operator-passphrase".to_string()),
1227 /// Some("operator1".parse()?),
1228 /// )?;
1229 /// // generate system-wide key with tag
1230 /// nethsm.generate_key(
1231 /// KeyType::Curve25519,
1232 /// vec![KeyMechanism::EdDsaSignature],
1233 /// None,
1234 /// Some("signing1".parse()?),
1235 /// Some(vec!["tag1".to_string()]),
1236 /// )?;
1237 /// // tag system-wide user in Operator role for access to signing key
1238 /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
1239 /// // use the Operator credentials to create an OpenPGP certificate for a key
1240 /// nethsm.use_credentials(&"operator1".parse()?)?;
1241 /// let openpgp_cert = nethsm.create_openpgp_cert(
1242 /// &"signing1".parse()?,
1243 /// OpenPgpKeyUsageFlags::default(),
1244 /// "Test <test@example.org>".parse()?,
1245 /// SystemTime::now().into(),
1246 /// OpenPgpVersion::V4,
1247 /// )?;
1248 /// // use the Administrator credentials to import the OpenPGP certificate as certificate for the key
1249 /// nethsm.use_credentials(&"admin".parse()?)?;
1250 /// nethsm.import_key_certificate(&"signing1".parse()?, openpgp_cert)?;
1251 ///
1252 /// // delete a certificate for a key with Key ID "signing1"
1253 /// assert!(nethsm.delete_key_certificate(&"signing1".parse()?).is_ok());
1254 /// nethsm.delete_key_certificate(&"signing1".parse()?)?;
1255 /// assert!(nethsm.delete_key_certificate(&"signing1".parse()?).is_err());
1256 /// # Ok(())
1257 /// # }
1258 /// ```
1259 /// [certificate for a key]: https://docs.nitrokey.com/nethsm/operation#key-certificates
1260 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1261 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1262 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1263 pub fn delete_key_certificate(&self, key_id: &KeyId) -> Result<(), Error> {
1264 debug!(
1265 "Delete the certificate for the key \"{key_id}\" on the NetHSM at {} using {}",
1266 self.url.borrow(),
1267 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1268 );
1269
1270 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1271 keys_key_id_cert_delete(&self.create_connection_config(), key_id.as_ref()).map_err(
1272 |error| {
1273 Error::Api(format!(
1274 "Deleting certificate for key failed: {}",
1275 NetHsmApiError::from(error)
1276 ))
1277 },
1278 )?;
1279 Ok(())
1280 }
1281
1282 /// Gets a [Certificate Signing Request for a key].
1283 ///
1284 /// Returns a Certificate Signing Request ([CSR]) for a key, identified by `key_id` in [PKCS#10]
1285 /// format based on a provided [`DistinguishedName`].
1286 ///
1287 /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
1288 /// or [`Administrator`][`UserRole::Administrator`] [role].
1289 ///
1290 /// ## Namespaces
1291 ///
1292 /// * Users in a [namespace] only have access to keys in their own [namespace]
1293 /// * System-wide users only have access to system-wide keys (not in a [namespace]).
1294 ///
1295 /// # Errors
1296 ///
1297 /// Returns an [`Error::Api`] if getting a CSR for a key fails:
1298 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1299 /// * no key identified by `key_id` exists
1300 /// * the used [`Credentials`] are not correct
1301 /// * the used [`Credentials`] are not those of a user in the [`Operator`][`UserRole::Operator`]
1302 /// or [`Administrator`][`UserRole::Administrator`] [role]
1303 ///
1304 /// # Examples
1305 ///
1306 /// ```no_run
1307 /// use nethsm::{
1308 /// Connection,
1309 /// ConnectionSecurity,
1310 /// Credentials,
1311 /// DistinguishedName,
1312 /// KeyMechanism,
1313 /// KeyType,
1314 /// NetHsm,
1315 /// Passphrase,
1316 /// };
1317 ///
1318 /// # fn main() -> testresult::TestResult {
1319 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1320 /// let nethsm = NetHsm::new(
1321 /// Connection::new(
1322 /// "https://example.org/api/v1".try_into()?,
1323 /// ConnectionSecurity::Unsafe,
1324 /// ),
1325 /// Some(Credentials::new(
1326 /// "admin".parse()?,
1327 /// Some(Passphrase::new("passphrase".to_string())),
1328 /// )),
1329 /// None,
1330 /// None,
1331 /// )?;
1332 /// // generate system-wide key with tag
1333 /// nethsm.generate_key(
1334 /// KeyType::Curve25519,
1335 /// vec![KeyMechanism::EdDsaSignature],
1336 /// None,
1337 /// Some("signing1".parse()?),
1338 /// Some(vec!["tag1".to_string()]),
1339 /// )?;
1340 ///
1341 /// // get a CSR for a key
1342 /// println!(
1343 /// "{}",
1344 /// nethsm.get_key_csr(
1345 /// &"signing1".parse()?,
1346 /// DistinguishedName {
1347 /// country_name: Some("DE".to_string()),
1348 /// state_or_province_name: Some("Berlin".to_string()),
1349 /// locality_name: Some("Berlin".to_string()),
1350 /// organization_name: Some("Foobar Inc".to_string()),
1351 /// organizational_unit_name: Some("Department of Foo".to_string()),
1352 /// common_name: "Foobar Inc".to_string(),
1353 /// email_address: Some("foobar@mcfooface.com".to_string()),
1354 /// }
1355 /// )?
1356 /// );
1357 /// # Ok(())
1358 /// # }
1359 /// ```
1360 /// [Certificate Signing Request for a key]: https://docs.nitrokey.com/nethsm/operation#key-certificate-signing-requests
1361 /// [CSR]: https://en.wikipedia.org/wiki/Certificate_signing_request
1362 /// [PKCS#10]: https://en.wikipedia.org/wiki/Certificate_signing_request#Structure_of_a_PKCS_#10_CSR
1363 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1364 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1365 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1366 pub fn get_key_csr(
1367 &self,
1368 key_id: &KeyId,
1369 distinguished_name: DistinguishedName,
1370 ) -> Result<String, Error> {
1371 debug!(
1372 "Retrieve a Certificate Signing Request ({}) for the key \"{key_id}\" on the NetHSM at {} using {}",
1373 distinguished_name.common_name,
1374 self.url.borrow(),
1375 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1376 );
1377
1378 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1379 Ok(keys_key_id_csr_pem_post(
1380 &self.create_connection_config(),
1381 key_id.as_ref(),
1382 distinguished_name,
1383 )
1384 .map_err(|error| {
1385 Error::Api(format!(
1386 "Getting CSR for key failed: {}",
1387 NetHsmApiError::from(error)
1388 ))
1389 })?
1390 .entity)
1391 }
1392
1393 /// [Signs] a digest using a key.
1394 ///
1395 /// [Signs] a `digest` using a key identified by `key_id`.
1396 ///
1397 /// **NOTE**: This function offers low-level access for signing [digests]. Use
1398 /// [`sign`][`NetHsm::sign`] for signing a message.
1399 ///
1400 /// The `digest` must be of appropriate type depending on `signature_type`:
1401 /// * [`SignatureType::Pkcs1`], [`SignatureType::PssSha256`] and [`SignatureType::EcdsaP256`]
1402 /// require a [SHA-256] digest
1403 /// * [`SignatureType::PssMd5`] requires an [MD5] digest
1404 /// * [`SignatureType::PssSha1`] requires a [SHA-1] digest
1405 /// * [`SignatureType::PssSha384`] and [`SignatureType::EcdsaP384`] require a [SHA-384] digest
1406 /// * [`SignatureType::PssSha512`] and [`SignatureType::EcdsaP521`] require a [SHA-521] digest
1407 /// * [`SignatureType::EdDsa`] requires no digest (`digest` is the message)
1408 ///
1409 /// The returned data depends on the chosen [`SignatureType`]:
1410 ///
1411 /// * [`SignatureType::Pkcs1`] returns the [PKCS 1] padded signature (no signature algorithm OID
1412 /// prepended, since the used hash is not known).
1413 /// * [`SignatureType::PssMd5`], [`SignatureType::PssSha1`], [`SignatureType::PssSha224`],
1414 /// [`SignatureType::PssSha256`], [`SignatureType::PssSha384`] and
1415 /// [`SignatureType::PssSha512`] return the [EMSA-PSS] encoded signature.
1416 /// * [`SignatureType::EdDsa`] returns the encoding as specified in [RFC 8032 (5.1.6)] (`r`
1417 /// appended with `s` (each 32 bytes), in total 64 bytes).
1418 /// * [`SignatureType::EcdsaP256`], [`SignatureType::EcdsaP384`] and
1419 /// [`SignatureType::EcdsaP521`] return the [ASN.1] [DER] encoded signature (a sequence of
1420 /// integer `r` and integer `s`).
1421 ///
1422 /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
1423 /// [role], which carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one
1424 /// of the tags of the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
1425 ///
1426 /// ## Namespaces
1427 ///
1428 /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
1429 /// their own [namespace].
1430 /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
1431 ///
1432 /// # Errors
1433 ///
1434 /// Returns an [`Error::Api`] if signing the `digest` fails:
1435 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1436 /// * no key identified by `key_id` exists on the NetHSM
1437 /// * the chosen [`SignatureType`] is incompatible with the targeted key
1438 /// * the chosen `digest` is incompatible with the [`SignatureType`]
1439 /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
1440 /// different [namespace])
1441 /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
1442 /// tags
1443 /// * the used [`Credentials`] are not correct
1444 /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
1445 /// [role]
1446 ///
1447 /// # Examples
1448 ///
1449 /// ```no_run
1450 /// use nethsm::{
1451 /// Connection,
1452 /// ConnectionSecurity,
1453 /// Credentials,
1454 /// KeyMechanism,
1455 /// KeyType,
1456 /// NetHsm,
1457 /// Passphrase,
1458 /// SignatureType,
1459 /// UserRole,
1460 /// };
1461 ///
1462 /// # fn main() -> testresult::TestResult {
1463 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1464 /// let nethsm = NetHsm::new(
1465 /// Connection::new(
1466 /// "https://example.org/api/v1".try_into()?,
1467 /// ConnectionSecurity::Unsafe,
1468 /// ),
1469 /// Some(Credentials::new(
1470 /// "admin".parse()?,
1471 /// Some(Passphrase::new("passphrase".to_string())),
1472 /// )),
1473 /// None,
1474 /// None,
1475 /// )?;
1476 /// // add a system-wide user in the Operator role
1477 /// nethsm.add_user(
1478 /// "Operator1".to_string(),
1479 /// UserRole::Operator,
1480 /// Passphrase::new("operator-passphrase".to_string()),
1481 /// Some("operator1".parse()?),
1482 /// )?;
1483 /// // generate system-wide key with tag
1484 /// nethsm.generate_key(
1485 /// KeyType::Curve25519,
1486 /// vec![KeyMechanism::EdDsaSignature],
1487 /// None,
1488 /// Some("signing1".parse()?),
1489 /// Some(vec!["tag1".to_string()]),
1490 /// )?;
1491 /// // tag system-wide user in Operator role for access to signing key
1492 /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
1493 ///
1494 /// // create an ed25519 signature
1495 /// nethsm.use_credentials(&"operator1".parse()?)?;
1496 /// println!(
1497 /// "{:?}",
1498 /// nethsm.sign_digest(&"signing1".parse()?, SignatureType::EdDsa, &[0, 1, 2])?
1499 /// );
1500 /// # Ok(())
1501 /// # }
1502 /// ```
1503 /// [Signs]: https://docs.nitrokey.com/nethsm/operation#sign
1504 /// [digests]: https://en.wikipedia.org/wiki/Cryptographic_hash_function
1505 /// [SHA-256]: https://en.wikipedia.org/wiki/SHA-2
1506 /// [MD5]: https://en.wikipedia.org/wiki/MD5
1507 /// [SHA-1]: https://en.wikipedia.org/wiki/SHA-1
1508 /// [SHA-224]: https://en.wikipedia.org/wiki/SHA-2
1509 /// [SHA-384]: https://en.wikipedia.org/wiki/SHA-2
1510 /// [SHA-521]: https://en.wikipedia.org/wiki/SHA-2
1511 /// [PKCS 1]: https://en.wikipedia.org/wiki/PKCS_1
1512 /// [EMSA-PSS]: https://en.wikipedia.org/wiki/PKCS_1
1513 /// [RFC 8032 (5.1.6)]: https://www.rfc-editor.org/rfc/rfc8032#section-5.1.6
1514 /// [ASN.1]: https://en.wikipedia.org/wiki/ASN.1
1515 /// [DER]: https://en.wikipedia.org/wiki/X.690#DER_encoding
1516 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1517 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1518 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1519 pub fn sign_digest(
1520 &self,
1521 key_id: &KeyId,
1522 signature_type: SignatureType,
1523 digest: &[u8],
1524 ) -> Result<Vec<u8>, Error> {
1525 debug!(
1526 "Sign a digest (signature type: {signature_type}) with the key \"{key_id}\" on the NetHSM at {} using {}",
1527 self.url.borrow(),
1528 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1529 );
1530
1531 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1532 // decode base64 encoded data from the API
1533 Base64::decode_vec(
1534 &keys_key_id_sign_post(
1535 &self.create_connection_config(),
1536 key_id.as_ref(),
1537 SignRequestData::new(signature_type.into(), Base64::encode_string(digest)),
1538 )
1539 .map_err(|error| {
1540 Error::Api(format!(
1541 "Signing message failed: {}",
1542 NetHsmApiError::from(error)
1543 ))
1544 })?
1545 .entity
1546 .signature,
1547 )
1548 .map_err(Error::Base64Decode)
1549 }
1550
1551 /// [Signs] a message using a key.
1552 ///
1553 /// [Signs] a `message` using a key identified by `key_id` based on a specific `signature_type`.
1554 ///
1555 /// The `message` should not be [hashed], as this function takes care of it based on the
1556 /// provided [`SignatureType`]. For lower level access, see
1557 /// [`sign_digest`][`NetHsm::sign_digest`].
1558 ///
1559 /// The returned data depends on the chosen [`SignatureType`]:
1560 ///
1561 /// * [`SignatureType::Pkcs1`] returns the [PKCS 1] padded signature (no signature algorithm OID
1562 /// prepended, since the used hash is not known).
1563 /// * [`SignatureType::PssMd5`], [`SignatureType::PssSha1`], [`SignatureType::PssSha224`],
1564 /// [`SignatureType::PssSha256`], [`SignatureType::PssSha384`] and
1565 /// [`SignatureType::PssSha512`] return the [EMSA-PSS] encoded signature.
1566 /// * [`SignatureType::EdDsa`] returns the encoding as specified in [RFC 8032 (5.1.6)] (`r`
1567 /// appended with `s` (each 32 bytes), in total 64 bytes).
1568 /// * [`SignatureType::EcdsaP256`], [`SignatureType::EcdsaP384`] and
1569 /// [`SignatureType::EcdsaP521`] return the [ASN.1] [DER] encoded signature (a sequence of
1570 /// integer `r` and integer `s`).
1571 ///
1572 /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
1573 /// [role], which carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one
1574 /// of the tags of the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
1575 ///
1576 /// ## Namespaces
1577 ///
1578 /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
1579 /// their own [namespace].
1580 /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
1581 ///
1582 /// # Errors
1583 ///
1584 /// Returns an [`Error::Api`] if signing the `message` fails:
1585 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1586 /// * no key identified by `key_id` exists on the NetHSM
1587 /// * the chosen [`SignatureType`] is incompatible with the targeted key
1588 /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
1589 /// different [namespace])
1590 /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
1591 /// tags
1592 /// * the used [`Credentials`] are not correct
1593 /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
1594 /// [role]
1595 ///
1596 /// # Examples
1597 ///
1598 /// ```no_run
1599 /// use nethsm::{
1600 /// Connection,
1601 /// ConnectionSecurity,
1602 /// Credentials,
1603 /// KeyMechanism,
1604 /// KeyType,
1605 /// NetHsm,
1606 /// Passphrase,
1607 /// SignatureType,
1608 /// UserRole,
1609 /// };
1610 ///
1611 /// # fn main() -> testresult::TestResult {
1612 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1613 /// let nethsm = NetHsm::new(
1614 /// Connection::new(
1615 /// "https://example.org/api/v1".try_into()?,
1616 /// ConnectionSecurity::Unsafe,
1617 /// ),
1618 /// Some(Credentials::new(
1619 /// "admin".parse()?,
1620 /// Some(Passphrase::new("passphrase".to_string())),
1621 /// )),
1622 /// None,
1623 /// None,
1624 /// )?;
1625 /// // add a system-wide user in the Operator role
1626 /// nethsm.add_user(
1627 /// "Operator1".to_string(),
1628 /// UserRole::Operator,
1629 /// Passphrase::new("operator-passphrase".to_string()),
1630 /// Some("operator1".parse()?),
1631 /// )?;
1632 /// // generate system-wide key with tag
1633 /// nethsm.generate_key(
1634 /// KeyType::Curve25519,
1635 /// vec![KeyMechanism::EdDsaSignature],
1636 /// None,
1637 /// Some("signing1".parse()?),
1638 /// Some(vec!["tag1".to_string()]),
1639 /// )?;
1640 /// // tag system-wide user in Operator role for access to signing key
1641 /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
1642 ///
1643 /// // create an ed25519 signature
1644 /// println!(
1645 /// "{:?}",
1646 /// nethsm.sign(&"signing1".parse()?, SignatureType::EdDsa, b"message")?
1647 /// );
1648 /// # Ok(())
1649 /// # }
1650 /// ```
1651 /// [Signs]: https://docs.nitrokey.com/nethsm/operation#sign
1652 /// [hashed]: https://en.wikipedia.org/wiki/Cryptographic_hash_function
1653 /// [PKCS 1]: https://en.wikipedia.org/wiki/PKCS_1
1654 /// [EMSA-PSS]: https://en.wikipedia.org/wiki/PKCS_1
1655 /// [RFC 8032 (5.1.6)]: https://www.rfc-editor.org/rfc/rfc8032#section-5.1.6
1656 /// [ASN.1]: https://en.wikipedia.org/wiki/ASN.1
1657 /// [DER]: https://en.wikipedia.org/wiki/X.690#DER_encoding
1658 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1659 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1660 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1661 pub fn sign(
1662 &self,
1663 key_id: &KeyId,
1664 signature_type: SignatureType,
1665 message: &[u8],
1666 ) -> Result<Vec<u8>, Error> {
1667 debug!(
1668 "Sign a message (signature type: {signature_type}) with the key \"{key_id}\" on the NetHSM at {} using {}",
1669 self.url.borrow(),
1670 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1671 );
1672
1673 // Some algorithms require the data to be hashed first
1674 // The API requires data to be base64 encoded
1675 let message = match signature_type {
1676 SignatureType::Pkcs1 | SignatureType::PssSha256 | SignatureType::EcdsaP256 => {
1677 let mut hasher = Sha256::new();
1678 hasher.update(message);
1679 &hasher.finalize()[..]
1680 }
1681 SignatureType::PssMd5 => {
1682 let mut hasher = Md5::new();
1683 hasher.update(message);
1684 &hasher.finalize()[..]
1685 }
1686 SignatureType::PssSha1 => {
1687 let mut hasher = Sha1::new();
1688 hasher.update(message);
1689 &hasher.finalize()[..]
1690 }
1691 SignatureType::PssSha224 => {
1692 let mut hasher = Sha224::new();
1693 hasher.update(message);
1694 &hasher.finalize()[..]
1695 }
1696 SignatureType::PssSha384 | SignatureType::EcdsaP384 => {
1697 let mut hasher = Sha384::new();
1698 hasher.update(message);
1699 &hasher.finalize()[..]
1700 }
1701 SignatureType::PssSha512 | SignatureType::EcdsaP521 => {
1702 let mut hasher = Sha512::new();
1703 hasher.update(message);
1704 &hasher.finalize()[..]
1705 }
1706 SignatureType::EdDsa => message,
1707 };
1708
1709 self.sign_digest(key_id, signature_type, message)
1710 }
1711
1712 /// [Encrypts] a message using a [symmetric key].
1713 ///
1714 /// [Encrypts] a `message` using a [symmetric key] identified by `key_id`, a specific
1715 /// [`EncryptMode`] `mode` and initialization vector `iv`.
1716 ///
1717 /// The targeted key must be of type [`KeyType::Generic`] and feature the mechanisms
1718 /// [`KeyMechanism::AesDecryptionCbc`] and [`KeyMechanism::AesEncryptionCbc`].
1719 ///
1720 /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
1721 /// [role], which carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one
1722 /// of the tags of the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
1723 ///
1724 /// ## Namespaces
1725 ///
1726 /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
1727 /// their own [namespace].
1728 /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
1729 ///
1730 /// # Errors
1731 ///
1732 /// Returns an [`Error::Api`] if encrypting the `message` fails:
1733 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1734 /// * no key identified by `key_id` exists on the NetHSM
1735 /// * the chosen `mode` is incompatible with the targeted key
1736 /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
1737 /// different [namespace])
1738 /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
1739 /// tags
1740 /// * the used [`Credentials`] are not correct
1741 /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
1742 /// [role]
1743 ///
1744 /// # Examples
1745 ///
1746 /// ```no_run
1747 /// use nethsm::{
1748 /// Connection,
1749 /// ConnectionSecurity,
1750 /// Credentials,
1751 /// EncryptMode,
1752 /// KeyMechanism,
1753 /// KeyType,
1754 /// NetHsm,
1755 /// Passphrase,
1756 /// UserRole,
1757 /// };
1758 ///
1759 /// # fn main() -> testresult::TestResult {
1760 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1761 /// let nethsm = NetHsm::new(
1762 /// Connection::new(
1763 /// "https://example.org/api/v1".try_into()?,
1764 /// ConnectionSecurity::Unsafe,
1765 /// ),
1766 /// Some(Credentials::new(
1767 /// "admin".parse()?,
1768 /// Some(Passphrase::new("passphrase".to_string())),
1769 /// )),
1770 /// None,
1771 /// None,
1772 /// )?;
1773 /// // add a system-wide user in the Operator role
1774 /// nethsm.add_user(
1775 /// "Operator1".to_string(),
1776 /// UserRole::Operator,
1777 /// Passphrase::new("operator-passphrase".to_string()),
1778 /// Some("operator1".parse()?),
1779 /// )?;
1780 /// // generate system-wide key with tag
1781 /// nethsm.generate_key(
1782 /// KeyType::Generic,
1783 /// vec![KeyMechanism::AesDecryptionCbc, KeyMechanism::AesEncryptionCbc],
1784 /// Some(128),
1785 /// Some("encryption1".parse()?),
1786 /// Some(vec!["tag1".to_string()]),
1787 /// )?;
1788 /// // tag system-wide user in Operator role for access to signing key
1789 /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
1790 ///
1791 /// // assuming we have an AES128 encryption key, the message must be a multiple of 32 bytes long
1792 /// let message = b"Hello World! This is a message!!";
1793 /// // we have an AES128 encryption key. the initialization vector must be a multiple of 16 bytes long
1794 /// let iv = b"This is unsafe!!";
1795 ///
1796 /// // encrypt message using
1797 /// println!(
1798 /// "{:?}",
1799 /// nethsm.encrypt(&"encryption1".parse()?, EncryptMode::AesCbc, message, Some(iv))?
1800 /// );
1801 /// # Ok(())
1802 /// # }
1803 /// ```
1804 /// [Encrypts]: https://docs.nitrokey.com/nethsm/operation#encrypt
1805 /// [symmetric key]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm
1806 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1807 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1808 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1809 pub fn encrypt(
1810 &self,
1811 key_id: &KeyId,
1812 mode: EncryptMode,
1813 message: &[u8],
1814 iv: Option<&[u8]>,
1815 ) -> Result<Vec<u8>, Error> {
1816 debug!(
1817 "Encrypt a message (encrypt mode: {mode}) with the key \"{key_id}\" on the NetHSM at {} using {}",
1818 self.url.borrow(),
1819 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1820 );
1821
1822 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1823 // the API requires data to be base64 encoded
1824 let message = Base64::encode_string(message);
1825 let iv = iv.map(Base64::encode_string);
1826
1827 // decode base64 encoded data from the API
1828 Base64::decode_vec(
1829 &keys_key_id_encrypt_post(
1830 &self.create_connection_config(),
1831 key_id.as_ref(),
1832 EncryptRequestData {
1833 mode: mode.into(),
1834 message,
1835 iv,
1836 },
1837 )
1838 .map_err(|error| {
1839 Error::Api(format!(
1840 "Encrypting message failed: {}",
1841 NetHsmApiError::from(error)
1842 ))
1843 })?
1844 .entity
1845 .encrypted,
1846 )
1847 .map_err(Error::Base64Decode)
1848 }
1849
1850 /// [Decrypts] a message using a key.
1851 ///
1852 /// [Decrypts] a `message` using a key identified by `key_id`, a specific [`DecryptMode`] `mode`
1853 /// and initialization vector `iv`.
1854 ///
1855 /// This function can be used to decrypt messages encrypted using a [symmetric key] (e.g. using
1856 /// [`encrypt`][`NetHsm::encrypt`]) by providing [`DecryptMode::AesCbc`] as `mode`. The targeted
1857 /// key must be of type [`KeyType::Generic`] and feature the mechanisms
1858 /// [`KeyMechanism::AesDecryptionCbc`] and [`KeyMechanism::AesEncryptionCbc`].
1859 ///
1860 /// Decryption for messages encrypted using an [asymmetric key] is also possible. Foreign
1861 /// entities can use the public key of an [asymmetric key] (see
1862 /// [`get_public_key`][`NetHsm::get_public_key`]) to encrypt a message and the private key
1863 /// on the NetHSM is used for decryption.
1864 ///
1865 /// This call requires using [`Credentials`] of a user in the [`Operator`][`UserRole::Operator`]
1866 /// [role], which carries a tag (see [`add_user_tag`][`NetHsm::add_user_tag`]) matching one
1867 /// of the tags of the targeted key (see [`add_key_tag`][`NetHsm::add_key_tag`]).
1868 ///
1869 /// ## Namespaces
1870 ///
1871 /// * [`Operator`][`UserRole::Operator`] users in a [namespace] only have access to keys in
1872 /// their own [namespace].
1873 /// * System-wide [`Operator`][`UserRole::Operator`] users only have access to system-wide keys.
1874 ///
1875 /// # Errors
1876 ///
1877 /// Returns an [`Error::Api`] if decrypting the `message` fails:
1878 /// * the NetHSM is not in [`Operational`][`SystemState::Operational`] [state]
1879 /// * no key identified by `key_id` exists on the NetHSM
1880 /// * the chosen `mode` is incompatible with the targeted key
1881 /// * the encrypted message can not be decrypted
1882 /// * the [`Operator`][`UserRole::Operator`] user does not have access to the key (e.g.
1883 /// different [namespace])
1884 /// * the [`Operator`][`UserRole::Operator`] user does not carry a tag matching one of the key
1885 /// tags
1886 /// * the used [`Credentials`] are not correct
1887 /// * the used [`Credentials`] are not that of a user in the [`Operator`][`UserRole::Operator`]
1888 /// [role]
1889 ///
1890 /// # Examples
1891 ///
1892 /// ```no_run
1893 /// use nethsm::{
1894 /// Connection,
1895 /// ConnectionSecurity,
1896 /// Credentials,
1897 /// DecryptMode,
1898 /// EncryptMode,
1899 /// KeyMechanism,
1900 /// KeyType,
1901 /// NetHsm,
1902 /// Passphrase,
1903 /// UserRole
1904 /// };
1905 /// use rsa::{pkcs8::DecodePublicKey, Pkcs1v15Encrypt, RsaPublicKey};
1906 ///
1907 /// # fn main() -> testresult::TestResult {
1908 /// // create a connection with a system-wide user in the Administrator role (R-Administrator)
1909 /// let nethsm = NetHsm::new(
1910 /// Connection::new(
1911 /// "https://example.org/api/v1".try_into()?,
1912 /// ConnectionSecurity::Unsafe,
1913 /// ),
1914 /// Some(Credentials::new(
1915 /// "admin".parse()?,
1916 /// Some(Passphrase::new("passphrase".to_string())),
1917 /// )),
1918 /// None,
1919 /// None,
1920 /// )?;
1921 /// // add a system-wide user in the Operator role
1922 /// nethsm.add_user(
1923 /// "Operator1".to_string(),
1924 /// UserRole::Operator,
1925 /// Passphrase::new("operator-passphrase".to_string()),
1926 /// Some("operator1".parse()?),
1927 /// )?;
1928 /// // generate system-wide keys with the same tag
1929 /// nethsm.generate_key(
1930 /// KeyType::Generic,
1931 /// vec![KeyMechanism::AesDecryptionCbc, KeyMechanism::AesEncryptionCbc],
1932 /// Some(128),
1933 /// Some("encryption1".parse()?),
1934 /// Some(vec!["tag1".to_string()]),
1935 /// )?;
1936 /// nethsm.generate_key(
1937 /// KeyType::Rsa,
1938 /// vec![KeyMechanism::RsaDecryptionPkcs1],
1939 /// None,
1940 /// Some("encryption2".parse()?),
1941 /// Some(vec!["tag1".to_string()]),
1942 /// )?;
1943 /// // tag system-wide user in Operator role for access to signing key
1944 /// nethsm.add_user_tag(&"operator1".parse()?, "tag1")?;
1945 ///
1946 /// // assuming we have an AES128 encryption key, the message must be a multiple of 32 bytes long
1947 /// let message = "Hello World! This is a message!!".to_string();
1948 /// // we have an AES128 encryption key. the initialization vector must be a multiple of 16 bytes long
1949 /// let iv = "This is unsafe!!".to_string();
1950 ///
1951 /// // encrypt message using a symmetric key
1952 /// nethsm.use_credentials(&"operator1".parse()?)?;
1953 /// let encrypted_message = nethsm.encrypt(&"encryption1".parse()?, EncryptMode::AesCbc, message.as_bytes(), Some(iv.as_bytes()))?;
1954 ///
1955 /// // decrypt message using the same symmetric key and the same initialization vector
1956 /// assert_eq!(
1957 /// message.as_bytes(),
1958 /// &nethsm.decrypt(&"encryption1".parse()?, DecryptMode::AesCbc, &encrypted_message, Some(iv.as_bytes()))?
1959 /// );
1960 ///
1961 /// // get the public key of an asymmetric key and encrypt the message with it
1962 /// let pubkey = RsaPublicKey::from_public_key_pem(&nethsm.get_public_key(&"encryption2".parse()?)?)?;
1963 /// let mut rng = rand::thread_rng();
1964 /// let encrypted_message = pubkey.encrypt(&mut rng, Pkcs1v15Encrypt, message.as_bytes())?;
1965 /// println!("raw encrypted message: {:?}", encrypted_message);
1966 ///
1967 /// let decrypted_message =
1968 /// nethsm.decrypt(&"encryption2".parse()?, DecryptMode::Pkcs1, &encrypted_message, None)?;
1969 /// println!("raw decrypted message: {:?}", decrypted_message);
1970 ///
1971 /// assert_eq!(&decrypted_message, message.as_bytes());
1972 /// # Ok(())
1973 /// # }
1974 /// ```
1975 /// [Decrypts]: https://docs.nitrokey.com/nethsm/operation#decrypt
1976 /// [symmetric key]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm
1977 /// [asymmetric key]: https://en.wikipedia.org/wiki/Public-key_cryptography
1978 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
1979 /// [role]: https://docs.nitrokey.com/nethsm/administration#roles
1980 /// [state]: https://docs.nitrokey.com/nethsm/administration#state
1981 pub fn decrypt(
1982 &self,
1983 key_id: &KeyId,
1984 mode: DecryptMode,
1985 message: &[u8],
1986 iv: Option<&[u8]>,
1987 ) -> Result<Vec<u8>, Error> {
1988 debug!(
1989 "Decrypt a message (decrypt mode: {mode}; IV: {}) with the key \"{key_id}\" on the NetHSM at {} using {}",
1990 if iv.is_some() { "yes" } else { "no" },
1991 self.url.borrow(),
1992 user_or_no_user_string(self.current_credentials.borrow().as_ref()),
1993 );
1994
1995 self.validate_namespace_access(NamespaceSupport::Supported, None, None)?;
1996 // the API requires data to be base64 encoded
1997 let encrypted = Base64::encode_string(message);
1998 let iv = iv.map(Base64::encode_string);
1999
2000 // decode base64 encoded data from the API
2001 Base64::decode_vec(
2002 &keys_key_id_decrypt_post(
2003 &self.create_connection_config(),
2004 key_id.as_ref(),
2005 DecryptRequestData {
2006 mode: mode.into(),
2007 encrypted,
2008 iv,
2009 },
2010 )
2011 .map_err(|error| {
2012 Error::Api(format!(
2013 "Decrypting message failed: {}",
2014 NetHsmApiError::from(error)
2015 ))
2016 })?
2017 .entity
2018 .decrypted,
2019 )
2020 .map_err(Error::Base64Decode)
2021 }
2022}