nethsm/
nethsm_sdk.rs

1use std::fmt::Display;
2
3use nethsm_sdk_rs::models::{SignMode, Switch, UnattendedBootConfig};
4use serde::{Deserialize, Serialize};
5use ureq::Response;
6
7/// A representation of a message body in an HTTP response
8///
9/// This type allows us to deserialize the message body when the NetHSM API triggers the return of a
10/// [`nethsm_sdk_rs::apis::Error::Ureq`].
11#[derive(Debug, Deserialize)]
12pub struct Message {
13    message: String,
14}
15
16impl From<Response> for Message {
17    fn from(value: Response) -> Self {
18        if let Ok(message) = value.into_json() {
19            message
20        } else {
21            Message {
22                message: "Deserialization error (no message in body)".to_string(),
23            }
24        }
25    }
26}
27
28impl Display for Message {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        f.write_str(&self.message)
31    }
32}
33
34#[derive(Debug)]
35pub struct ApiErrorMessage {
36    pub status_code: u16,
37    pub message: Message,
38}
39
40impl From<(u16, Message)> for ApiErrorMessage {
41    fn from(value: (u16, Message)) -> Self {
42        Self {
43            status_code: value.0,
44            message: value.1,
45        }
46    }
47}
48
49impl Display for ApiErrorMessage {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        f.write_str(&format!(
52            "{} (status code {})",
53            self.message, self.status_code
54        ))
55    }
56}
57
58/// A helper Error for more readable output for [`nethsm_sdk_rs::apis::Error`]
59///
60/// This type allows us to create more readable output for [`nethsm_sdk_rs::apis::Error::Ureq`] and
61/// reuse the upstream handling otherwise.
62pub struct NetHsmApiError<T> {
63    error: Option<nethsm_sdk_rs::apis::Error<T>>,
64    message: Option<String>,
65}
66
67impl<T> From<nethsm_sdk_rs::apis::Error<T>> for NetHsmApiError<T> {
68    fn from(value: nethsm_sdk_rs::apis::Error<T>) -> Self {
69        match value {
70            nethsm_sdk_rs::apis::Error::Ureq(error) => match error {
71                nethsm_sdk_rs::ureq::Error::Status(code, response) => Self {
72                    error: None,
73                    message: Some(ApiErrorMessage::from((code, response.into())).to_string()),
74                },
75                nethsm_sdk_rs::ureq::Error::Transport(transport) => Self {
76                    error: None,
77                    message: Some(format!("{transport}")),
78                },
79            },
80            nethsm_sdk_rs::apis::Error::ResponseError(resp) => Self {
81                error: None,
82                message: Some(format!(
83                    "Status code: {}: {}",
84                    resp.status,
85                    // First, try to deserialize the response as a `Message` object,
86                    // which is commonly returned by a majority of failures
87                    serde_json::from_slice::<Message>(&resp.content)
88                        .map(|m| m.message)
89                        // if that fails, as a last resort, try to return the response verbatim.
90                        .unwrap_or_else(|_| String::from_utf8_lossy(&resp.content).into())
91                )),
92            },
93            _ => Self {
94                error: Some(value),
95                message: None,
96            },
97        }
98    }
99}
100
101impl<T> Display for NetHsmApiError<T> {
102    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103        if let Some(message) = self.message.as_ref() {
104            write!(f, "{message}")?;
105        } else if let Some(error) = self.error.as_ref() {
106            write!(f, "{error}")?;
107        }
108        Ok(())
109    }
110}
111
112/// The type of a signature
113///
114/// This enum covers all variants of [`nethsm_sdk_rs::models::SignMode`], but instead of
115/// [`nethsm_sdk_rs::models::SignMode::Ecdsa`] covers prime size specific ECDSA modes.
116#[derive(
117    Clone,
118    Copy,
119    Debug,
120    Deserialize,
121    strum::Display,
122    strum::EnumString,
123    strum::EnumIter,
124    strum::IntoStaticStr,
125    Eq,
126    PartialEq,
127    Ord,
128    PartialOrd,
129    Hash,
130    Serialize,
131)]
132#[strum(ascii_case_insensitive)]
133pub enum SignatureType {
134    /// Elliptic Curve Digital Signature Algorithm (ECDSA) signing using a key over a prime field
135    /// for a prime of size 256 bit
136    EcdsaP256,
137
138    /// Elliptic Curve Digital Signature Algorithm (ECDSA) signing using a key over a prime field
139    /// for a prime of size 384 bit
140    EcdsaP384,
141
142    /// Elliptic Curve Digital Signature Algorithm (ECDSA) signing using a key over a prime field
143    /// for a prime of size 521 bit
144    EcdsaP521,
145
146    /// Signing following the Edwards-curve Digital Signature Algorithm (EdDSA)
147    EdDsa,
148
149    /// RSA signing following the PKCS#1 standard
150    Pkcs1,
151
152    /// RSA signing following a "probabilistic signature scheme" (PSS) using an MD-5 hash
153    PssMd5,
154
155    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-1 hash
156    PssSha1,
157
158    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-224 hash
159    PssSha224,
160
161    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-256 hash
162    PssSha256,
163
164    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-384 hash
165    PssSha384,
166
167    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-512 hash
168    PssSha512,
169}
170
171impl From<SignatureType> for SignMode {
172    fn from(value: SignatureType) -> Self {
173        match value {
174            SignatureType::Pkcs1 => SignMode::Pkcs1,
175            SignatureType::PssMd5 => SignMode::PssMd5,
176            SignatureType::PssSha1 => SignMode::PssSha1,
177            SignatureType::PssSha224 => SignMode::PssSha224,
178            SignatureType::PssSha256 => SignMode::PssSha256,
179            SignatureType::PssSha384 => SignMode::PssSha384,
180            SignatureType::PssSha512 => SignMode::PssSha512,
181            SignatureType::EdDsa => SignMode::EdDsa,
182            SignatureType::EcdsaP256 | SignatureType::EcdsaP384 | SignatureType::EcdsaP521 => {
183                SignMode::Ecdsa
184            }
185        }
186    }
187}
188
189/// The NetHSM boot mode
190///
191/// Defines in which state the NetHSM is in during boot after provisioning (see
192/// [`crate::NetHsm::provision`]) and whether an unlock passphrase has to be provided for it to be
193/// of state [`crate::SystemState::Operational`].
194#[derive(
195    Clone,
196    Copy,
197    Debug,
198    strum::Display,
199    strum::EnumString,
200    strum::EnumIter,
201    strum::IntoStaticStr,
202    Eq,
203    PartialEq,
204)]
205#[strum(ascii_case_insensitive)]
206pub enum BootMode {
207    /// The device boots into state [`crate::SystemState::Locked`] and an unlock passphrase has to
208    /// be provided
209    Attended,
210    /// The device boots into state [`crate::SystemState::Operational`] and no unlock passphrase
211    /// has to be provided
212    Unattended,
213}
214
215impl From<UnattendedBootConfig> for BootMode {
216    fn from(value: UnattendedBootConfig) -> Self {
217        match value.status {
218            Switch::On => BootMode::Unattended,
219            Switch::Off => BootMode::Attended,
220        }
221    }
222}
223
224impl From<BootMode> for UnattendedBootConfig {
225    fn from(value: BootMode) -> Self {
226        match value {
227            BootMode::Unattended => UnattendedBootConfig { status: Switch::On },
228            BootMode::Attended => UnattendedBootConfig {
229                status: Switch::Off,
230            },
231        }
232    }
233}
234
235/// A mode for decrypting a message
236#[derive(
237    Clone,
238    Copy,
239    Debug,
240    Default,
241    Deserialize,
242    strum::Display,
243    strum::EnumString,
244    strum::EnumIter,
245    strum::IntoStaticStr,
246    Eq,
247    Hash,
248    Ord,
249    PartialEq,
250    PartialOrd,
251    Serialize,
252)]
253#[strum(ascii_case_insensitive)]
254pub enum DecryptMode {
255    /// Decryption using the Advanced Encryption Standard (AES) with Cipher Block Chaining (CBC)
256    AesCbc,
257
258    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using an MD-5 hash
259    OaepMd5,
260
261    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-1 hash
262    OaepSha1,
263
264    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-224 hash
265    OaepSha224,
266
267    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-256 hash
268    OaepSha256,
269
270    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-384 hash
271    OaepSha384,
272
273    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-512 hash
274    OaepSha512,
275
276    /// RSA decryption following the PKCS#1 standard
277    Pkcs1,
278
279    /// Raw RSA decryption
280    #[default]
281    Raw,
282}
283
284impl From<DecryptMode> for nethsm_sdk_rs::models::DecryptMode {
285    fn from(value: DecryptMode) -> Self {
286        match value {
287            DecryptMode::AesCbc => Self::AesCbc,
288            DecryptMode::OaepMd5 => Self::OaepMd5,
289            DecryptMode::OaepSha1 => Self::OaepSha1,
290            DecryptMode::OaepSha224 => Self::OaepSha224,
291            DecryptMode::OaepSha256 => Self::OaepSha256,
292            DecryptMode::OaepSha384 => Self::OaepSha384,
293            DecryptMode::OaepSha512 => Self::OaepSha512,
294            DecryptMode::Pkcs1 => Self::Pkcs1,
295            DecryptMode::Raw => Self::Raw,
296        }
297    }
298}
299
300/// A mode for encrypting a message
301#[derive(
302    Clone,
303    Copy,
304    Debug,
305    Default,
306    Deserialize,
307    strum::Display,
308    strum::EnumString,
309    strum::EnumIter,
310    strum::IntoStaticStr,
311    Eq,
312    Hash,
313    Ord,
314    PartialEq,
315    PartialOrd,
316    Serialize,
317)]
318#[strum(ascii_case_insensitive)]
319pub enum EncryptMode {
320    /// Encryption using the Advanced Encryption Standard (AES) with Cipher Block Chaining (CBC)
321    #[default]
322    AesCbc,
323}
324
325impl From<EncryptMode> for nethsm_sdk_rs::models::EncryptMode {
326    fn from(value: EncryptMode) -> Self {
327        match value {
328            EncryptMode::AesCbc => Self::AesCbc,
329        }
330    }
331}
332
333/// A mechanism which can be used with a key
334#[derive(
335    Clone,
336    Copy,
337    Debug,
338    Default,
339    Deserialize,
340    strum::Display,
341    strum::EnumString,
342    strum::EnumIter,
343    strum::IntoStaticStr,
344    Hash,
345    Eq,
346    Ord,
347    PartialEq,
348    PartialOrd,
349    Serialize,
350)]
351#[strum(ascii_case_insensitive)]
352pub enum KeyMechanism {
353    /// Decryption using the Advanced Encryption Standard (AES) with Cipher Block Chaining (CBC)
354    AesDecryptionCbc,
355
356    /// Encryption using the Advanced Encryption Standard (AES) with Cipher Block Chaining (CBC)
357    AesEncryptionCbc,
358
359    /// Signing following the Elliptic Curve Digital Signature Algorithm (ECDSA)
360    EcdsaSignature,
361
362    /// Signing following the Edwards-curve Digital Signature Algorithm (EdDSA)
363    #[default]
364    EdDsaSignature,
365
366    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using an MD-5 hash
367    RsaDecryptionOaepMd5,
368
369    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-1 hash
370    RsaDecryptionOaepSha1,
371
372    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-224 hash
373    RsaDecryptionOaepSha224,
374
375    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-256 hash
376    RsaDecryptionOaepSha256,
377
378    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-384 hash
379    RsaDecryptionOaepSha384,
380
381    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-512 hash
382    RsaDecryptionOaepSha512,
383
384    /// RSA decryption following the PKCS#1 standard
385    RsaDecryptionPkcs1,
386
387    /// Raw RSA decryption
388    RsaDecryptionRaw,
389
390    /// RSA signing following the PKCS#1 standard
391    RsaSignaturePkcs1,
392
393    /// RSA signing following a "probabilistic signature scheme" (PSS) using an MD-5 hash
394    RsaSignaturePssMd5,
395
396    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-1 hash
397    RsaSignaturePssSha1,
398
399    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-224 hash
400    RsaSignaturePssSha224,
401
402    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-256 hash
403    RsaSignaturePssSha256,
404
405    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-384 hash
406    RsaSignaturePssSha384,
407
408    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-512 hash
409    RsaSignaturePssSha512,
410}
411
412impl KeyMechanism {
413    /// Returns key mechanisms specific to Curve25519 key types
414    pub fn curve25519_mechanisms() -> Vec<KeyMechanism> {
415        vec![KeyMechanism::EdDsaSignature]
416    }
417
418    /// Returns key mechanisms specific to elliptic curve key types
419    pub fn elliptic_curve_mechanisms() -> Vec<KeyMechanism> {
420        vec![KeyMechanism::EcdsaSignature]
421    }
422
423    /// Returns key mechanisms specific to generic key types
424    pub fn generic_mechanisms() -> Vec<KeyMechanism> {
425        vec![
426            KeyMechanism::AesDecryptionCbc,
427            KeyMechanism::AesEncryptionCbc,
428        ]
429    }
430
431    /// Returns key mechanisms specific to RSA key types
432    pub fn rsa_mechanisms() -> Vec<KeyMechanism> {
433        vec![
434            KeyMechanism::RsaDecryptionRaw,
435            KeyMechanism::RsaDecryptionPkcs1,
436            KeyMechanism::RsaDecryptionOaepMd5,
437            KeyMechanism::RsaDecryptionOaepSha1,
438            KeyMechanism::RsaDecryptionOaepSha224,
439            KeyMechanism::RsaDecryptionOaepSha256,
440            KeyMechanism::RsaDecryptionOaepSha384,
441            KeyMechanism::RsaDecryptionOaepSha512,
442            KeyMechanism::RsaSignaturePkcs1,
443            KeyMechanism::RsaSignaturePssMd5,
444            KeyMechanism::RsaSignaturePssSha1,
445            KeyMechanism::RsaSignaturePssSha224,
446            KeyMechanism::RsaSignaturePssSha256,
447            KeyMechanism::RsaSignaturePssSha384,
448            KeyMechanism::RsaSignaturePssSha512,
449        ]
450    }
451}
452
453impl From<&nethsm_sdk_rs::models::KeyMechanism> for KeyMechanism {
454    fn from(value: &nethsm_sdk_rs::models::KeyMechanism) -> Self {
455        match value {
456            nethsm_sdk_rs::models::KeyMechanism::AesDecryptionCbc => Self::AesDecryptionCbc,
457            nethsm_sdk_rs::models::KeyMechanism::AesEncryptionCbc => Self::AesEncryptionCbc,
458            nethsm_sdk_rs::models::KeyMechanism::EcdsaSignature => Self::EcdsaSignature,
459            nethsm_sdk_rs::models::KeyMechanism::EdDsaSignature => Self::EdDsaSignature,
460            nethsm_sdk_rs::models::KeyMechanism::RsaDecryptionOaepMd5 => Self::RsaDecryptionOaepMd5,
461            nethsm_sdk_rs::models::KeyMechanism::RsaDecryptionOaepSha1 => {
462                Self::RsaDecryptionOaepSha1
463            }
464            nethsm_sdk_rs::models::KeyMechanism::RsaDecryptionOaepSha224 => {
465                Self::RsaDecryptionOaepSha224
466            }
467            nethsm_sdk_rs::models::KeyMechanism::RsaDecryptionOaepSha256 => {
468                Self::RsaDecryptionOaepSha256
469            }
470            nethsm_sdk_rs::models::KeyMechanism::RsaDecryptionOaepSha384 => {
471                Self::RsaDecryptionOaepSha384
472            }
473            nethsm_sdk_rs::models::KeyMechanism::RsaDecryptionOaepSha512 => {
474                Self::RsaDecryptionOaepSha512
475            }
476            nethsm_sdk_rs::models::KeyMechanism::RsaDecryptionPkcs1 => Self::RsaDecryptionPkcs1,
477            nethsm_sdk_rs::models::KeyMechanism::RsaDecryptionRaw => Self::RsaDecryptionRaw,
478            nethsm_sdk_rs::models::KeyMechanism::RsaSignaturePkcs1 => Self::RsaSignaturePkcs1,
479            nethsm_sdk_rs::models::KeyMechanism::RsaSignaturePssMd5 => Self::RsaSignaturePssMd5,
480            nethsm_sdk_rs::models::KeyMechanism::RsaSignaturePssSha1 => Self::RsaSignaturePssSha1,
481            nethsm_sdk_rs::models::KeyMechanism::RsaSignaturePssSha224 => {
482                Self::RsaSignaturePssSha224
483            }
484            nethsm_sdk_rs::models::KeyMechanism::RsaSignaturePssSha256 => {
485                Self::RsaSignaturePssSha256
486            }
487            nethsm_sdk_rs::models::KeyMechanism::RsaSignaturePssSha384 => {
488                Self::RsaSignaturePssSha384
489            }
490            nethsm_sdk_rs::models::KeyMechanism::RsaSignaturePssSha512 => {
491                Self::RsaSignaturePssSha512
492            }
493        }
494    }
495}
496
497impl From<KeyMechanism> for nethsm_sdk_rs::models::KeyMechanism {
498    fn from(value: KeyMechanism) -> Self {
499        match value {
500            KeyMechanism::AesDecryptionCbc => Self::AesDecryptionCbc,
501            KeyMechanism::AesEncryptionCbc => Self::AesEncryptionCbc,
502            KeyMechanism::EcdsaSignature => Self::EcdsaSignature,
503            KeyMechanism::EdDsaSignature => Self::EdDsaSignature,
504            KeyMechanism::RsaDecryptionOaepMd5 => Self::RsaDecryptionOaepMd5,
505            KeyMechanism::RsaDecryptionOaepSha1 => Self::RsaDecryptionOaepSha1,
506            KeyMechanism::RsaDecryptionOaepSha224 => Self::RsaDecryptionOaepSha224,
507            KeyMechanism::RsaDecryptionOaepSha256 => Self::RsaDecryptionOaepSha256,
508            KeyMechanism::RsaDecryptionOaepSha384 => Self::RsaDecryptionOaepSha384,
509            KeyMechanism::RsaDecryptionOaepSha512 => Self::RsaDecryptionOaepSha512,
510            KeyMechanism::RsaDecryptionPkcs1 => Self::RsaDecryptionPkcs1,
511            KeyMechanism::RsaDecryptionRaw => Self::RsaDecryptionRaw,
512            KeyMechanism::RsaSignaturePkcs1 => Self::RsaSignaturePkcs1,
513            KeyMechanism::RsaSignaturePssMd5 => Self::RsaSignaturePssMd5,
514            KeyMechanism::RsaSignaturePssSha1 => Self::RsaSignaturePssSha1,
515            KeyMechanism::RsaSignaturePssSha224 => Self::RsaSignaturePssSha224,
516            KeyMechanism::RsaSignaturePssSha256 => Self::RsaSignaturePssSha256,
517            KeyMechanism::RsaSignaturePssSha384 => Self::RsaSignaturePssSha384,
518            KeyMechanism::RsaSignaturePssSha512 => Self::RsaSignaturePssSha512,
519        }
520    }
521}
522
523/// The algorithm type of a key
524#[derive(
525    Clone,
526    Copy,
527    Debug,
528    Default,
529    Deserialize,
530    strum::Display,
531    strum::EnumString,
532    strum::EnumIter,
533    strum::IntoStaticStr,
534    Eq,
535    Hash,
536    Ord,
537    PartialEq,
538    PartialOrd,
539    Serialize,
540)]
541#[strum(ascii_case_insensitive)]
542pub enum KeyType {
543    /// A Montgomery curve key over a prime field for the prime number 2^255-19
544    #[default]
545    Curve25519,
546
547    /// An elliptic-curve key over a prime field for a prime of size 256 bit
548    EcP256,
549
550    /// An elliptic-curve key over a prime field for a prime of size 384 bit
551    EcP384,
552
553    /// An elliptic-curve key over a prime field for a prime of size 521 bit
554    EcP521,
555
556    /// A generic key used for block ciphers
557    Generic,
558
559    /// An RSA key
560    Rsa,
561}
562
563impl From<KeyType> for nethsm_sdk_rs::models::KeyType {
564    fn from(value: KeyType) -> Self {
565        match value {
566            KeyType::Curve25519 => Self::Curve25519,
567            KeyType::EcP256 => Self::EcP256,
568            KeyType::EcP384 => Self::EcP384,
569            KeyType::EcP521 => Self::EcP521,
570            KeyType::Generic => Self::Generic,
571            KeyType::Rsa => Self::Rsa,
572        }
573    }
574}
575
576impl From<nethsm_sdk_rs::models::KeyType> for KeyType {
577    fn from(value: nethsm_sdk_rs::models::KeyType) -> Self {
578        use nethsm_sdk_rs::models::KeyType;
579        match value {
580            KeyType::Curve25519 => Self::Curve25519,
581            KeyType::EcP256 => Self::EcP256,
582            KeyType::EcP384 => Self::EcP384,
583            KeyType::EcP521 => Self::EcP521,
584            KeyType::Generic => Self::Generic,
585            KeyType::Rsa => Self::Rsa,
586            KeyType::EcP224 => unreachable!("P224 has been removed"),
587        }
588    }
589}
590
591/// The format of a key
592#[derive(
593    Clone,
594    Copy,
595    Debug,
596    Default,
597    Deserialize,
598    strum::Display,
599    strum::EnumString,
600    strum::EnumIter,
601    strum::IntoStaticStr,
602    Eq,
603    Hash,
604    Ord,
605    PartialEq,
606    PartialOrd,
607    Serialize,
608)]
609#[strum(ascii_case_insensitive)]
610pub enum KeyFormat {
611    /// Privacy-Enhanced Mail (PEM) format.
612    Pem,
613
614    /// ASN.1 DER binary format.
615    #[default]
616    Der,
617}
618
619/// A device log level
620#[derive(
621    Clone,
622    Copy,
623    Debug,
624    Default,
625    Deserialize,
626    strum::Display,
627    strum::EnumString,
628    strum::EnumIter,
629    strum::IntoStaticStr,
630    Eq,
631    Hash,
632    Ord,
633    PartialEq,
634    PartialOrd,
635    Serialize,
636)]
637#[strum(ascii_case_insensitive)]
638pub enum LogLevel {
639    /// Show debug, error, warning and info messages
640    Debug,
641
642    /// Show error, warning and info messages
643    Error,
644
645    /// Show info messages
646    #[default]
647    Info,
648
649    /// Show warning and info messages
650    Warning,
651}
652
653impl From<LogLevel> for nethsm_sdk_rs::models::LogLevel {
654    fn from(value: LogLevel) -> Self {
655        match value {
656            LogLevel::Debug => Self::Debug,
657            LogLevel::Error => Self::Error,
658            LogLevel::Info => Self::Info,
659            LogLevel::Warning => Self::Warning,
660        }
661    }
662}
663
664/// The algorithm type of a key used for TLS
665#[derive(
666    Clone,
667    Copy,
668    Debug,
669    Default,
670    Deserialize,
671    strum::Display,
672    strum::EnumString,
673    strum::EnumIter,
674    strum::IntoStaticStr,
675    Eq,
676    Hash,
677    Ord,
678    PartialEq,
679    PartialOrd,
680    Serialize,
681)]
682#[strum(ascii_case_insensitive)]
683pub enum TlsKeyType {
684    /// A Montgomery curve key over a prime field for the prime number 2^255-19
685    Curve25519,
686
687    /// An elliptic-curve key over a prime field for a prime of size 224 bit
688    EcP224,
689
690    /// An elliptic-curve key over a prime field for a prime of size 256 bit
691    EcP256,
692
693    /// An elliptic-curve key over a prime field for a prime of size 384 bit
694    EcP384,
695
696    /// An elliptic-curve key over a prime field for a prime of size 521 bit
697    EcP521,
698
699    /// An RSA key
700    #[default]
701    Rsa,
702}
703
704impl From<TlsKeyType> for nethsm_sdk_rs::models::TlsKeyType {
705    fn from(value: TlsKeyType) -> Self {
706        match value {
707            TlsKeyType::Curve25519 => Self::Curve25519,
708            TlsKeyType::EcP224 => Self::EcP224,
709            TlsKeyType::EcP256 => Self::EcP256,
710            TlsKeyType::EcP384 => Self::EcP384,
711            TlsKeyType::EcP521 => Self::EcP521,
712            TlsKeyType::Rsa => Self::Rsa,
713        }
714    }
715}
716
717/// The role of a user on a NetHSM device
718#[derive(
719    Clone,
720    Copy,
721    Debug,
722    Default,
723    Deserialize,
724    strum::Display,
725    strum::EnumString,
726    strum::EnumIter,
727    strum::IntoStaticStr,
728    Eq,
729    PartialEq,
730    Ord,
731    PartialOrd,
732    Hash,
733    Serialize,
734)]
735#[strum(ascii_case_insensitive)]
736pub enum UserRole {
737    /// A role for administrating a device, its users and keys
738    Administrator,
739    /// A role for creating backups of a device
740    Backup,
741    /// A role for reading metrics of a device
742    Metrics,
743    /// A role for using one or more keys of a device
744    #[default]
745    Operator,
746}
747
748impl From<UserRole> for nethsm_sdk_rs::models::UserRole {
749    fn from(value: UserRole) -> Self {
750        match value {
751            UserRole::Administrator => Self::Administrator,
752            UserRole::Backup => Self::Backup,
753            UserRole::Metrics => Self::Metrics,
754            UserRole::Operator => Self::Operator,
755        }
756    }
757}
758
759impl From<nethsm_sdk_rs::models::UserRole> for UserRole {
760    fn from(value: nethsm_sdk_rs::models::UserRole) -> Self {
761        match value {
762            nethsm_sdk_rs::models::UserRole::Administrator => Self::Administrator,
763            nethsm_sdk_rs::models::UserRole::Backup => Self::Backup,
764            nethsm_sdk_rs::models::UserRole::Metrics => Self::Metrics,
765            nethsm_sdk_rs::models::UserRole::Operator => Self::Operator,
766        }
767    }
768}
769
770#[cfg(test)]
771mod tests {
772    use std::str::FromStr;
773
774    use rstest::rstest;
775    use testresult::TestResult;
776
777    use super::*;
778
779    #[rstest]
780    #[case("raw", Some(DecryptMode::Raw))]
781    #[case("pkcs1", Some(DecryptMode::Pkcs1))]
782    #[case("oaepmd5", Some(DecryptMode::OaepMd5))]
783    #[case("oaepsha1", Some(DecryptMode::OaepSha1))]
784    #[case("oaepsha224", Some(DecryptMode::OaepSha224))]
785    #[case("oaepsha256", Some(DecryptMode::OaepSha256))]
786    #[case("oaepsha384", Some(DecryptMode::OaepSha384))]
787    #[case("oaepsha512", Some(DecryptMode::OaepSha512))]
788    #[case("aescbc", Some(DecryptMode::AesCbc))]
789    #[case("foo", None)]
790    fn decryptmode_fromstr(
791        #[case] input: &str,
792        #[case] expected: Option<DecryptMode>,
793    ) -> TestResult {
794        if let Some(expected) = expected {
795            assert_eq!(DecryptMode::from_str(input)?, expected);
796        } else {
797            assert!(DecryptMode::from_str(input).is_err());
798        }
799        Ok(())
800    }
801
802    #[rstest]
803    #[case("aescbc", Some(EncryptMode::AesCbc))]
804    #[case("foo", None)]
805    fn encryptmode_fromstr(
806        #[case] input: &str,
807        #[case] expected: Option<EncryptMode>,
808    ) -> TestResult {
809        if let Some(expected) = expected {
810            assert_eq!(EncryptMode::from_str(input)?, expected);
811        } else {
812            assert!(EncryptMode::from_str(input).is_err());
813        }
814        Ok(())
815    }
816
817    #[rstest]
818    #[case("rsadecryptionraw", Some(KeyMechanism::RsaDecryptionRaw))]
819    #[case("rsadecryptionpkcs1", Some(KeyMechanism::RsaDecryptionPkcs1))]
820    #[case("rsadecryptionoaepmd5", Some(KeyMechanism::RsaDecryptionOaepMd5))]
821    #[case("rsadecryptionoaepsha1", Some(KeyMechanism::RsaDecryptionOaepSha1))]
822    #[case("rsadecryptionoaepsha224", Some(KeyMechanism::RsaDecryptionOaepSha224))]
823    #[case("rsadecryptionoaepsha256", Some(KeyMechanism::RsaDecryptionOaepSha256))]
824    #[case("rsadecryptionoaepsha384", Some(KeyMechanism::RsaDecryptionOaepSha384))]
825    #[case("rsadecryptionoaepsha512", Some(KeyMechanism::RsaDecryptionOaepSha512))]
826    #[case("rsadecryptionoaepsha512", Some(KeyMechanism::RsaDecryptionOaepSha512))]
827    #[case("rsasignaturepkcs1", Some(KeyMechanism::RsaSignaturePkcs1))]
828    #[case("rsasignaturepssmd5", Some(KeyMechanism::RsaSignaturePssMd5))]
829    #[case("rsasignaturepsssha1", Some(KeyMechanism::RsaSignaturePssSha1))]
830    #[case("rsasignaturepsssha224", Some(KeyMechanism::RsaSignaturePssSha224))]
831    #[case("rsasignaturepsssha256", Some(KeyMechanism::RsaSignaturePssSha256))]
832    #[case("rsasignaturepsssha384", Some(KeyMechanism::RsaSignaturePssSha384))]
833    #[case("rsasignaturepsssha512", Some(KeyMechanism::RsaSignaturePssSha512))]
834    #[case("eddsasignature", Some(KeyMechanism::EdDsaSignature))]
835    #[case("ecdsasignature", Some(KeyMechanism::EcdsaSignature))]
836    #[case("aesencryptioncbc", Some(KeyMechanism::AesEncryptionCbc))]
837    #[case("aesdecryptioncbc", Some(KeyMechanism::AesDecryptionCbc))]
838    #[case("foo", None)]
839    fn keymechanism_fromstr(
840        #[case] input: &str,
841        #[case] expected: Option<KeyMechanism>,
842    ) -> TestResult {
843        if let Some(expected) = expected {
844            assert_eq!(KeyMechanism::from_str(input)?, expected);
845        } else {
846            assert!(KeyMechanism::from_str(input).is_err());
847        }
848        Ok(())
849    }
850
851    #[rstest]
852    #[case("rsa", Some(KeyType::Rsa))]
853    #[case("curve25519", Some(KeyType::Curve25519))]
854    #[case("ecp256", Some(KeyType::EcP256))]
855    #[case("ecp384", Some(KeyType::EcP384))]
856    #[case("ecp521", Some(KeyType::EcP521))]
857    #[case("generic", Some(KeyType::Generic))]
858    #[case("foo", None)]
859    fn keytype_fromstr(#[case] input: &str, #[case] expected: Option<KeyType>) -> TestResult {
860        if let Some(expected) = expected {
861            assert_eq!(KeyType::from_str(input)?, expected);
862        } else {
863            assert!(KeyType::from_str(input).is_err());
864        }
865        Ok(())
866    }
867
868    #[rstest]
869    #[case("ecdsap256", Some(SignatureType::EcdsaP256))]
870    #[case("ecdsap384", Some(SignatureType::EcdsaP384))]
871    #[case("ecdsap521", Some(SignatureType::EcdsaP521))]
872    #[case("eddsa", Some(SignatureType::EdDsa))]
873    #[case("pkcs1", Some(SignatureType::Pkcs1))]
874    #[case("pssmd5", Some(SignatureType::PssMd5))]
875    #[case("psssha1", Some(SignatureType::PssSha1))]
876    #[case("psssha224", Some(SignatureType::PssSha224))]
877    #[case("psssha256", Some(SignatureType::PssSha256))]
878    #[case("psssha384", Some(SignatureType::PssSha384))]
879    #[case("psssha512", Some(SignatureType::PssSha512))]
880    #[case("foo", None)]
881    fn signaturetype_fromstr(
882        #[case] input: &str,
883        #[case] expected: Option<SignatureType>,
884    ) -> TestResult {
885        if let Some(expected) = expected {
886            assert_eq!(SignatureType::from_str(input)?, expected);
887        } else {
888            assert!(SignatureType::from_str(input).is_err());
889        }
890        Ok(())
891    }
892
893    #[rstest]
894    #[case("rsa", Some(TlsKeyType::Rsa))]
895    #[case("curve25519", Some(TlsKeyType::Curve25519))]
896    #[case("ecp256", Some(TlsKeyType::EcP256))]
897    #[case("ecp384", Some(TlsKeyType::EcP384))]
898    #[case("ecp521", Some(TlsKeyType::EcP521))]
899    #[case("foo", None)]
900    fn tlskeytype_fromstr(#[case] input: &str, #[case] expected: Option<TlsKeyType>) -> TestResult {
901        if let Some(expected) = expected {
902            assert_eq!(TlsKeyType::from_str(input)?, expected);
903        } else {
904            assert!(TlsKeyType::from_str(input).is_err());
905        }
906        Ok(())
907    }
908
909    #[rstest]
910    #[case("administrator", Some(UserRole::Administrator))]
911    #[case("backup", Some(UserRole::Backup))]
912    #[case("metrics", Some(UserRole::Metrics))]
913    #[case("operator", Some(UserRole::Operator))]
914    #[case("foo", None)]
915    fn userrole_fromstr(#[case] input: &str, #[case] expected: Option<UserRole>) -> TestResult {
916        if let Some(expected) = expected {
917            assert_eq!(UserRole::from_str(input)?, expected);
918        } else {
919            assert!(UserRole::from_str(input).is_err());
920        }
921        Ok(())
922    }
923}