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