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