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