Skip to main content

signstar_crypto/key/base/
mod.rs

1//! Cryptographic key handling.
2
3#[cfg(feature = "nethsm")]
4pub mod nethsm;
5
6#[cfg(feature = "yubihsm2")]
7pub mod yubihsm2;
8
9use std::{cmp::Ordering, collections::BTreeMap, fmt::Display};
10
11use pgp::{
12    composed::SignedPublicKey,
13    types::{KeyDetails as _, Timestamp},
14};
15use serde::{Deserialize, Serialize};
16use strum::{EnumIter, EnumString, IntoStaticStr};
17
18use crate::{
19    key::error::Error,
20    openpgp::{OpenPgpUserId, OpenPgpUserIdList, OpenPgpVersion},
21    signer::openpgp::{EmptyEd25519Signer, Notation, generate_certificate},
22};
23
24/// A mode for decrypting a message
25#[derive(
26    Clone,
27    Copy,
28    Debug,
29    Default,
30    Deserialize,
31    strum::Display,
32    strum::EnumString,
33    strum::EnumIter,
34    strum::IntoStaticStr,
35    Eq,
36    Hash,
37    Ord,
38    PartialEq,
39    PartialOrd,
40    Serialize,
41)]
42#[strum(ascii_case_insensitive)]
43pub enum DecryptMode {
44    /// Decryption using the Advanced Encryption Standard (AES) with Cipher Block Chaining (CBC)
45    AesCbc,
46
47    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using an MD-5 hash
48    OaepMd5,
49
50    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-1 hash
51    OaepSha1,
52
53    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-224 hash
54    OaepSha224,
55
56    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-256 hash
57    OaepSha256,
58
59    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-384 hash
60    OaepSha384,
61
62    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-512 hash
63    OaepSha512,
64
65    /// RSA decryption following the PKCS#1 standard
66    Pkcs1,
67
68    /// Raw RSA decryption
69    #[default]
70    Raw,
71}
72
73/// A mode for encrypting a message
74#[derive(
75    Clone,
76    Copy,
77    Debug,
78    Default,
79    Deserialize,
80    strum::Display,
81    strum::EnumString,
82    strum::EnumIter,
83    strum::IntoStaticStr,
84    Eq,
85    Hash,
86    Ord,
87    PartialEq,
88    PartialOrd,
89    Serialize,
90)]
91#[strum(ascii_case_insensitive)]
92pub enum EncryptMode {
93    /// Encryption using the Advanced Encryption Standard (AES) with Cipher Block Chaining (CBC)
94    #[default]
95    AesCbc,
96}
97
98/// The format of a key
99#[derive(
100    Clone,
101    Copy,
102    Debug,
103    Default,
104    Deserialize,
105    strum::Display,
106    EnumString,
107    EnumIter,
108    IntoStaticStr,
109    Eq,
110    Hash,
111    Ord,
112    PartialEq,
113    PartialOrd,
114    Serialize,
115)]
116#[strum(ascii_case_insensitive)]
117pub enum KeyFormat {
118    /// Privacy-Enhanced Mail (PEM) format.
119    Pem,
120
121    /// ASN.1 DER binary format.
122    #[default]
123    Der,
124}
125
126/// The minimum bit length for an RSA key
127///
128/// This follows recommendations from [NIST Special Publication 800-57 Part 3 Revision 1](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57Pt3r1.pdf) (January 2015).
129pub const MIN_RSA_BIT_LENGTH: u32 = 2048;
130
131/// The algorithm type of a key
132#[derive(
133    Clone,
134    Copy,
135    Debug,
136    Default,
137    Deserialize,
138    strum::Display,
139    EnumString,
140    EnumIter,
141    IntoStaticStr,
142    Eq,
143    Hash,
144    Ord,
145    PartialEq,
146    PartialOrd,
147    Serialize,
148)]
149#[strum(ascii_case_insensitive)]
150pub enum KeyType {
151    /// A Montgomery curve key over a prime field for the prime number 2^255-19
152    #[default]
153    Curve25519,
154
155    /// An elliptic (Brainpool) curve key over a prime field for a prime of size 256 bit
156    EcBp256,
157
158    /// An elliptic (Brainpool) curve key over a prime field for a prime of size 384 bit
159    EcBp384,
160
161    /// An elliptic (Brainpool) curve key over a prime field for a prime of size 512 bit
162    EcBp512,
163
164    /// An elliptic (Koblitz) curve key over a prime field for a prime of size 256 bit
165    EcK256,
166
167    /// An elliptic-curve key over a prime field for a prime of size 224 bit
168    EcP224,
169
170    /// An elliptic-curve key over a prime field for a prime of size 256 bit
171    EcP256,
172
173    /// An elliptic-curve key over a prime field for a prime of size 384 bit
174    EcP384,
175
176    /// An elliptic-curve key over a prime field for a prime of size 521 bit
177    EcP521,
178
179    /// A generic key used for block ciphers
180    Generic,
181
182    /// An RSA key
183    Rsa,
184}
185
186/// A mechanism which can be used with a key
187#[derive(
188    Clone,
189    Copy,
190    Debug,
191    Default,
192    Deserialize,
193    strum::Display,
194    EnumString,
195    EnumIter,
196    IntoStaticStr,
197    Hash,
198    Eq,
199    Ord,
200    PartialEq,
201    PartialOrd,
202    Serialize,
203)]
204#[strum(ascii_case_insensitive)]
205pub enum KeyMechanism {
206    /// Decryption using the Advanced Encryption Standard (AES) with Cipher Block Chaining (CBC)
207    AesDecryptionCbc,
208
209    /// Encryption using the Advanced Encryption Standard (AES) with Cipher Block Chaining (CBC)
210    AesEncryptionCbc,
211
212    /// Signing following the Elliptic Curve Digital Signature Algorithm (ECDSA)
213    EcdsaSignature,
214
215    /// Signing following the Edwards-curve Digital Signature Algorithm (EdDSA)
216    #[default]
217    EdDsaSignature,
218
219    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using an MD-5 hash
220    RsaDecryptionOaepMd5,
221
222    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-1 hash
223    RsaDecryptionOaepSha1,
224
225    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-224 hash
226    RsaDecryptionOaepSha224,
227
228    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-256 hash
229    RsaDecryptionOaepSha256,
230
231    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-384 hash
232    RsaDecryptionOaepSha384,
233
234    /// RSA decryption with Optimal Asymmetric Encryption Padding (OAEP) using a SHA-512 hash
235    RsaDecryptionOaepSha512,
236
237    /// RSA decryption following the PKCS#1 standard
238    RsaDecryptionPkcs1,
239
240    /// Raw RSA decryption
241    RsaDecryptionRaw,
242
243    /// RSA signing following the PKCS#1 standard
244    RsaSignaturePkcs1,
245
246    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-1 hash
247    RsaSignaturePssSha1,
248
249    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-224 hash
250    RsaSignaturePssSha224,
251
252    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-256 hash
253    RsaSignaturePssSha256,
254
255    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-384 hash
256    RsaSignaturePssSha384,
257
258    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-512 hash
259    RsaSignaturePssSha512,
260}
261
262impl KeyMechanism {
263    /// Returns key mechanisms specific to Curve25519 key types
264    pub fn curve25519_mechanisms() -> Vec<KeyMechanism> {
265        vec![KeyMechanism::EdDsaSignature]
266    }
267
268    /// Returns key mechanisms specific to elliptic curve key types
269    pub fn elliptic_curve_mechanisms() -> Vec<KeyMechanism> {
270        vec![KeyMechanism::EcdsaSignature]
271    }
272
273    /// Returns key mechanisms specific to generic key types
274    pub fn generic_mechanisms() -> Vec<KeyMechanism> {
275        vec![
276            KeyMechanism::AesDecryptionCbc,
277            KeyMechanism::AesEncryptionCbc,
278        ]
279    }
280
281    /// Returns key mechanisms specific to RSA key types
282    pub fn rsa_mechanisms() -> Vec<KeyMechanism> {
283        vec![
284            KeyMechanism::RsaDecryptionRaw,
285            KeyMechanism::RsaDecryptionPkcs1,
286            KeyMechanism::RsaDecryptionOaepMd5,
287            KeyMechanism::RsaDecryptionOaepSha1,
288            KeyMechanism::RsaDecryptionOaepSha224,
289            KeyMechanism::RsaDecryptionOaepSha256,
290            KeyMechanism::RsaDecryptionOaepSha384,
291            KeyMechanism::RsaDecryptionOaepSha512,
292            KeyMechanism::RsaSignaturePkcs1,
293            KeyMechanism::RsaSignaturePssSha1,
294            KeyMechanism::RsaSignaturePssSha224,
295            KeyMechanism::RsaSignaturePssSha256,
296            KeyMechanism::RsaSignaturePssSha384,
297            KeyMechanism::RsaSignaturePssSha512,
298        ]
299    }
300}
301
302/// The type of a signature.
303#[derive(
304    Clone,
305    Copy,
306    Debug,
307    Deserialize,
308    strum::Display,
309    EnumString,
310    EnumIter,
311    IntoStaticStr,
312    Eq,
313    PartialEq,
314    Ord,
315    PartialOrd,
316    Hash,
317    Serialize,
318)]
319#[strum(ascii_case_insensitive)]
320pub enum SignatureType {
321    /// Elliptic Curve Digital Signature Algorithm (ECDSA) signing using a (Koblitz) key over a
322    /// prime field for a prime of size 256 bit
323    EcdsaK256,
324
325    /// Elliptic Curve Digital Signature Algorithm (ECDSA) signing using a key over a prime field
326    /// for a prime of size 224 bit
327    EcdsaP224,
328
329    /// Elliptic Curve Digital Signature Algorithm (ECDSA) signing using a key over a prime field
330    /// for a prime of size 256 bit
331    EcdsaP256,
332
333    /// Elliptic Curve Digital Signature Algorithm (ECDSA) signing using a key over a prime field
334    /// for a prime of size 384 bit
335    EcdsaP384,
336
337    /// Elliptic Curve Digital Signature Algorithm (ECDSA) signing using a key over a prime field
338    /// for a prime of size 521 bit
339    EcdsaP521,
340
341    /// Signing following the Edwards-curve Digital Signature Algorithm (EdDSA)
342    EdDsa,
343
344    /// RSA signing following the PKCS#1 standard
345    Pkcs1,
346
347    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-1 hash
348    PssSha1,
349
350    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-224 hash
351    PssSha224,
352
353    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-256 hash
354    PssSha256,
355
356    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-384 hash
357    PssSha384,
358
359    /// RSA signing following a "probabilistic signature scheme" (PSS) using a SHA-512 hash
360    PssSha512,
361}
362
363/// The cryptographic context in which a key is used.
364#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
365pub enum CryptographicKeyContext {
366    /// A key is used in an OpenPGP context
367    #[serde(rename = "openpgp")]
368    OpenPgp {
369        /// OpenPGP notations to attach to created signatures.
370        #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
371        notations: BTreeMap<String, String>,
372
373        /// List of OpenPGP User IDs for the certificate.
374        user_ids: OpenPgpUserIdList,
375
376        /// OpenPGP version for the certificate.
377        version: OpenPgpVersion,
378    },
379
380    /// A key is used in a raw cryptographic context
381    #[serde(rename = "raw")]
382    Raw,
383}
384
385impl CryptographicKeyContext {
386    /// Validates the cryptographic context against a signing key setup
387    ///
388    /// # Errors
389    ///
390    /// Returns an error if the key setup can not be used for signing operations in the respective
391    /// cryptographic context.
392    ///
393    /// # Examples
394    ///
395    /// ```
396    /// use signstar_crypto::key::{CryptographicKeyContext, KeyMechanism, KeyType, SignatureType};
397    /// use signstar_crypto::openpgp::{OpenPgpUserIdList, OpenPgpVersion};
398    ///
399    /// # fn main() -> testresult::TestResult {
400    /// CryptographicKeyContext::Raw.validate_signing_key_setup(
401    ///     KeyType::Curve25519,
402    ///     &[KeyMechanism::EdDsaSignature],
403    ///     SignatureType::EdDsa,
404    /// )?;
405    ///
406    /// CryptographicKeyContext::OpenPgp {
407    ///     user_ids: OpenPgpUserIdList::new(vec!["Foobar McFooface <foobar@mcfooface.org>".parse()?])?,
408    ///     version: OpenPgpVersion::V4,
409    ///     notations: Default::default(),
410    /// }
411    /// .validate_signing_key_setup(
412    ///     KeyType::Curve25519,
413    ///     &[KeyMechanism::EdDsaSignature],
414    ///     SignatureType::EdDsa,
415    /// )?;
416    /// # Ok(())
417    /// # }
418    /// ```
419    pub fn validate_signing_key_setup(
420        &self,
421        key_type: KeyType,
422        key_mechanisms: &[KeyMechanism],
423        signature_type: SignatureType,
424    ) -> Result<(), crate::Error> {
425        match self {
426            Self::Raw => match (key_type, signature_type) {
427                (KeyType::Curve25519, SignatureType::EdDsa)
428                    if key_mechanisms.contains(&KeyMechanism::EdDsaSignature) => {}
429                (KeyType::EcP256, SignatureType::EcdsaP256)
430                    if key_mechanisms.contains(&KeyMechanism::EcdsaSignature) => {}
431                (KeyType::EcP384, SignatureType::EcdsaP384)
432                    if key_mechanisms.contains(&KeyMechanism::EcdsaSignature) => {}
433                (KeyType::EcP521, SignatureType::EcdsaP521)
434                    if key_mechanisms.contains(&KeyMechanism::EcdsaSignature) => {}
435                (KeyType::Rsa, SignatureType::Pkcs1)
436                    if key_mechanisms.contains(&KeyMechanism::RsaSignaturePkcs1) => {}
437                (KeyType::Rsa, SignatureType::PssSha1)
438                    if key_mechanisms.contains(&KeyMechanism::RsaSignaturePssSha1) => {}
439                (KeyType::Rsa, SignatureType::PssSha224)
440                    if key_mechanisms.contains(&KeyMechanism::RsaSignaturePssSha224) => {}
441                (KeyType::Rsa, SignatureType::PssSha256)
442                    if key_mechanisms.contains(&KeyMechanism::RsaSignaturePssSha256) => {}
443                (KeyType::Rsa, SignatureType::PssSha384)
444                    if key_mechanisms.contains(&KeyMechanism::RsaSignaturePssSha384) => {}
445                (KeyType::Rsa, SignatureType::PssSha512)
446                    if key_mechanisms.contains(&KeyMechanism::RsaSignaturePssSha512) => {}
447                _ => {
448                    return Err(Error::InvalidRawSigningKeySetup {
449                        key_type,
450                        key_mechanisms: key_mechanisms.to_vec(),
451                        signature_type,
452                    }
453                    .into());
454                }
455            },
456            Self::OpenPgp {
457                user_ids: _,
458                version: _,
459                notations: _,
460            } => match (key_type, signature_type) {
461                (KeyType::Curve25519, SignatureType::EdDsa)
462                    if key_mechanisms.contains(&KeyMechanism::EdDsaSignature) => {}
463                (KeyType::EcP256, SignatureType::EcdsaP256)
464                    if key_mechanisms.contains(&KeyMechanism::EcdsaSignature) => {}
465                (KeyType::EcP384, SignatureType::EcdsaP384)
466                    if key_mechanisms.contains(&KeyMechanism::EcdsaSignature) => {}
467                (KeyType::EcP521, SignatureType::EcdsaP521)
468                    if key_mechanisms.contains(&KeyMechanism::EcdsaSignature) => {}
469                (KeyType::Rsa, SignatureType::Pkcs1)
470                    if key_mechanisms.contains(&KeyMechanism::RsaSignaturePkcs1) => {}
471                _ => {
472                    return Err(Error::InvalidOpenPgpSigningKeySetup {
473                        key_type,
474                        key_mechanisms: key_mechanisms.to_vec(),
475                        signature_type,
476                    }
477                    .into());
478                }
479            },
480        }
481        Ok(())
482    }
483
484    /// Estimates the OpenPGP certificate size of this [`CryptographicKeyContext`].
485    ///
486    /// For non OpenPGP contexts this function returns [`Option::None`].
487    ///
488    /// # Errors
489    ///
490    /// Returns an error if the certificate creation fails.
491    ///
492    /// # Examples
493    ///
494    /// ```
495    /// use signstar_crypto::key::CryptographicKeyContext;
496    /// use signstar_crypto::openpgp::{OpenPgpUserIdList, OpenPgpVersion};
497    ///
498    /// # fn main() -> testresult::TestResult {
499    /// let cert_size = CryptographicKeyContext::OpenPgp {
500    ///     notations: Default::default(),
501    ///     user_ids: OpenPgpUserIdList::new(vec!["Foobar McFooface <foobar@mcfooface.org>".parse()?])?,
502    ///     version: OpenPgpVersion::V4,
503    /// }
504    /// .openpgp_cert_size()?;
505    ///
506    /// assert_eq!(cert_size, Some(155));
507    ///
508    /// let cert_size = CryptographicKeyContext::Raw.openpgp_cert_size()?;
509    ///
510    /// assert_eq!(cert_size, None);
511    /// # Ok(())
512    /// # }
513    /// ```
514    pub fn openpgp_cert_size(&self) -> Result<Option<usize>, crate::Error> {
515        if let CryptographicKeyContext::OpenPgp {
516            user_ids,
517            notations,
518            ..
519        } = self
520        {
521            match generate_certificate(
522                &EmptyEd25519Signer,
523                Default::default(),
524                user_ids.as_ref(),
525                notations
526                    .iter()
527                    .map(|(name, value)| Notation { name, value })
528                    .collect::<Vec<_>>()
529                    .as_slice(),
530                Timestamp::now(),
531                Default::default(),
532            ) {
533                Err(error) => Err(error),
534                Ok(cert) => Ok(Some(cert.len())),
535            }
536        } else {
537            Ok(None)
538        }
539    }
540}
541
542impl Display for CryptographicKeyContext {
543    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
544        match self {
545            Self::OpenPgp {
546                user_ids,
547                version,
548                notations,
549            } => {
550                write!(
551                    f,
552                    "OpenPGP (Version: {version}; User IDs: {}",
553                    user_ids
554                        .iter()
555                        .map(|user_id| format!("\"{user_id}\""))
556                        .collect::<Vec<String>>()
557                        .join(", ")
558                )?;
559                if !notations.is_empty() {
560                    write!(
561                        f,
562                        "; Notations: {}",
563                        notations
564                            .iter()
565                            .map(|(key, value)| format!("\"{key}={value}\""))
566                            .collect::<Vec<String>>()
567                            .join(", ")
568                    )?;
569                }
570                write!(f, ")")
571            }
572            Self::Raw => {
573                write!(f, "Raw")
574            }
575        }
576    }
577}
578
579impl Ord for CryptographicKeyContext {
580    fn cmp(&self, other: &Self) -> Ordering {
581        match (self, other) {
582            (
583                CryptographicKeyContext::OpenPgp {
584                    notations: self_notations,
585                    user_ids: self_user_ids,
586                    version: self_version,
587                },
588                CryptographicKeyContext::OpenPgp {
589                    notations: other_notations,
590                    user_ids: other_user_ids,
591                    version: other_version,
592                },
593            ) => (self_version, self_user_ids, self_notations).cmp(&(
594                other_version,
595                other_user_ids,
596                other_notations,
597            )),
598            (CryptographicKeyContext::OpenPgp { .. }, CryptographicKeyContext::Raw) => {
599                Ordering::Less
600            }
601            (CryptographicKeyContext::Raw, CryptographicKeyContext::OpenPgp { .. }) => {
602                Ordering::Greater
603            }
604            (CryptographicKeyContext::Raw, CryptographicKeyContext::Raw) => Ordering::Equal,
605        }
606    }
607}
608
609impl PartialOrd for CryptographicKeyContext {
610    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
611        Some(self.cmp(other))
612    }
613}
614
615impl TryFrom<SignedPublicKey> for CryptographicKeyContext {
616    type Error = crate::Error;
617
618    /// Creates a [`CryptographicKeyContext`] from [`SignedPublicKey`].
619    ///
620    /// Drops any invalid OpenPGP User ID (e.g. non-UTF-8).
621    ///
622    /// # Errors
623    ///
624    /// Returns an error if
625    ///
626    /// - duplicate OpenPGP User IDs are encountered in `value`,
627    /// - or no valid OpenPGP version can be derived from the OpenPGP primary key in `value`.
628    fn try_from(value: SignedPublicKey) -> Result<Self, Self::Error> {
629        let user_ids: Vec<OpenPgpUserId> = value
630            .details
631            .users
632            .iter()
633            .filter_map(|signed_user| signed_user.try_into().ok())
634            .collect();
635
636        let notations = value
637            .details
638            .users
639            .iter()
640            .flat_map(|user| &user.signatures)
641            .flat_map(|sig| sig.notations())
642            .fold(BTreeMap::new(), |mut acc, notation| {
643                acc.entry(String::from_utf8_lossy(&notation.name).into())
644                    .or_insert(String::from_utf8_lossy(&notation.value).into());
645                acc
646            });
647
648        Ok(Self::OpenPgp {
649            user_ids: OpenPgpUserIdList::new(user_ids)?,
650            version: value.primary_key.version().try_into()?,
651            notations,
652        })
653    }
654}
655
656/// Ensures that a [`KeyType`] is compatible with a list of [`KeyMechanism`]s
657///
658/// # Errors
659///
660/// Returns an error if any of the `mechanisms` is incompatible with the `key_type`.
661///
662/// # Examples
663///
664/// ```
665/// use signstar_crypto::key::{KeyMechanism, KeyType, key_type_matches_mechanisms};
666///
667/// # fn main() -> testresult::TestResult {
668/// key_type_matches_mechanisms(KeyType::Curve25519, &[KeyMechanism::EdDsaSignature])?;
669/// key_type_matches_mechanisms(
670///     KeyType::Rsa,
671///     &[
672///         KeyMechanism::RsaDecryptionPkcs1,
673///         KeyMechanism::RsaSignaturePkcs1,
674///     ],
675/// )?;
676/// key_type_matches_mechanisms(
677///     KeyType::Generic,
678///     &[
679///         KeyMechanism::AesDecryptionCbc,
680///         KeyMechanism::AesEncryptionCbc,
681///     ],
682/// )?;
683///
684/// // this fails because Curve25519 is not compatible with the Elliptic Curve Digital Signature Algorithm (ECDSA),
685/// // but instead requires the use of the Edwards-curve Digital Signature Algorithm (EdDSA)
686/// assert!(
687///     key_type_matches_mechanisms(KeyType::Curve25519, &[KeyMechanism::EcdsaSignature]).is_err()
688/// );
689///
690/// // this fails because RSA key mechanisms are not compatible with block ciphers
691/// assert!(key_type_matches_mechanisms(
692///     KeyType::Generic,
693///     &[
694///         KeyMechanism::RsaDecryptionPkcs1,
695///         KeyMechanism::RsaSignaturePkcs1,
696///     ]
697/// )
698/// .is_err());
699///
700/// // this fails because RSA keys do not support Curve25519's Edwards-curve Digital Signature Algorithm (EdDSA)
701/// assert!(key_type_matches_mechanisms(
702///     KeyType::Rsa,
703///     &[
704///         KeyMechanism::AesDecryptionCbc,
705///         KeyMechanism::AesEncryptionCbc,
706///         KeyMechanism::EcdsaSignature
707///     ]
708/// )
709/// .is_err());
710/// # Ok(())
711/// # }
712/// ```
713pub fn key_type_matches_mechanisms(
714    key_type: KeyType,
715    mechanisms: &[KeyMechanism],
716) -> Result<(), crate::Error> {
717    let valid_mechanisms: &[KeyMechanism] = match key_type {
718        KeyType::Curve25519 => &KeyMechanism::curve25519_mechanisms(),
719        KeyType::EcBp256
720        | KeyType::EcBp384
721        | KeyType::EcBp512
722        | KeyType::EcK256
723        | KeyType::EcP224
724        | KeyType::EcP256
725        | KeyType::EcP384
726        | KeyType::EcP521 => &KeyMechanism::elliptic_curve_mechanisms(),
727        KeyType::Generic => &KeyMechanism::generic_mechanisms(),
728        KeyType::Rsa => &KeyMechanism::rsa_mechanisms(),
729    };
730
731    let invalid_mechanisms = mechanisms
732        .iter()
733        .filter(|mechanism| !valid_mechanisms.contains(mechanism))
734        .cloned()
735        .collect::<Vec<KeyMechanism>>();
736
737    if invalid_mechanisms.is_empty() {
738        Ok(())
739    } else {
740        Err(Error::InvalidKeyMechanism {
741            key_type,
742            invalid_mechanisms,
743        }
744        .into())
745    }
746}
747
748/// Ensures that a [`KeyType`] and a list of [`KeyMechanism`]s is compatible with a
749/// [`SignatureType`]
750///
751/// # Errors
752///
753/// Returns an error if the provided `signature_type` is incompatible with the `key_type` or
754/// `mechanisms`.
755///
756/// # Examples
757///
758/// ```
759/// use signstar_crypto::key::{KeyMechanism, KeyType, SignatureType, key_type_and_mechanisms_match_signature_type};
760///
761/// # fn main() -> testresult::TestResult {
762/// key_type_and_mechanisms_match_signature_type(KeyType::Curve25519, &[KeyMechanism::EdDsaSignature], SignatureType::EdDsa)?;
763/// key_type_and_mechanisms_match_signature_type(KeyType::EcP256, &[KeyMechanism::EcdsaSignature], SignatureType::EcdsaP256)?;
764/// key_type_and_mechanisms_match_signature_type(KeyType::Rsa, &[KeyMechanism::RsaSignaturePkcs1],SignatureType::Pkcs1)?;
765///
766/// // this fails because Curve25519 is not compatible with the Elliptic Curve Digital Signature Algorithm (ECDSA),
767/// // but instead requires the use of the Edwards-curve Digital Signature Algorithm (EdDSA)
768/// assert!(
769///     key_type_and_mechanisms_match_signature_type(KeyType::Curve25519, &[KeyMechanism::EdDsaSignature], SignatureType::EcdsaP256).is_err()
770/// );
771/// # Ok(())
772/// # }
773/// ```
774pub fn key_type_and_mechanisms_match_signature_type(
775    key_type: KeyType,
776    mechanisms: &[KeyMechanism],
777    signature_type: SignatureType,
778) -> Result<(), crate::Error> {
779    match signature_type {
780        SignatureType::EcdsaK256 => {
781            if key_type != KeyType::EcK256 {
782                return Err(Error::InvalidKeyTypeForSignatureType {
783                    key_type,
784                    signature_type,
785                }
786                .into());
787            } else if !mechanisms.contains(&KeyMechanism::EcdsaSignature) {
788                return Err(Error::InvalidKeyMechanismsForSignatureType {
789                    required_key_mechanism: KeyMechanism::EcdsaSignature,
790                    signature_type,
791                }
792                .into());
793            }
794        }
795        SignatureType::EcdsaP224 => {
796            if key_type != KeyType::EcP224 {
797                return Err(Error::InvalidKeyTypeForSignatureType {
798                    key_type,
799                    signature_type,
800                }
801                .into());
802            } else if !mechanisms.contains(&KeyMechanism::EcdsaSignature) {
803                return Err(Error::InvalidKeyMechanismsForSignatureType {
804                    required_key_mechanism: KeyMechanism::EcdsaSignature,
805                    signature_type,
806                }
807                .into());
808            }
809        }
810        SignatureType::EcdsaP256 => {
811            if key_type != KeyType::EcP256 {
812                return Err(Error::InvalidKeyTypeForSignatureType {
813                    key_type,
814                    signature_type,
815                }
816                .into());
817            } else if !mechanisms.contains(&KeyMechanism::EcdsaSignature) {
818                return Err(Error::InvalidKeyMechanismsForSignatureType {
819                    required_key_mechanism: KeyMechanism::EcdsaSignature,
820                    signature_type,
821                }
822                .into());
823            }
824        }
825        SignatureType::EcdsaP384 => {
826            if key_type != KeyType::EcP384 {
827                return Err(Error::InvalidKeyTypeForSignatureType {
828                    key_type,
829                    signature_type,
830                }
831                .into());
832            } else if !mechanisms.contains(&KeyMechanism::EcdsaSignature) {
833                return Err(Error::InvalidKeyMechanismsForSignatureType {
834                    required_key_mechanism: KeyMechanism::EcdsaSignature,
835                    signature_type,
836                }
837                .into());
838            }
839        }
840        SignatureType::EcdsaP521 => {
841            if key_type != KeyType::EcP521 {
842                return Err(Error::InvalidKeyTypeForSignatureType {
843                    key_type,
844                    signature_type,
845                }
846                .into());
847            } else if !mechanisms.contains(&KeyMechanism::EcdsaSignature) {
848                return Err(Error::InvalidKeyMechanismsForSignatureType {
849                    required_key_mechanism: KeyMechanism::EcdsaSignature,
850                    signature_type,
851                }
852                .into());
853            }
854        }
855        SignatureType::EdDsa => {
856            if key_type != KeyType::Curve25519 {
857                return Err(Error::InvalidKeyTypeForSignatureType {
858                    key_type,
859                    signature_type,
860                }
861                .into());
862            } else if !mechanisms.contains(&KeyMechanism::EdDsaSignature) {
863                return Err(Error::InvalidKeyMechanismsForSignatureType {
864                    required_key_mechanism: KeyMechanism::EdDsaSignature,
865                    signature_type,
866                }
867                .into());
868            }
869        }
870        SignatureType::Pkcs1 => {
871            if key_type != KeyType::Rsa {
872                return Err(Error::InvalidKeyTypeForSignatureType {
873                    key_type,
874                    signature_type,
875                }
876                .into());
877            } else if !mechanisms.contains(&KeyMechanism::RsaSignaturePkcs1) {
878                return Err(Error::InvalidKeyMechanismsForSignatureType {
879                    required_key_mechanism: KeyMechanism::RsaSignaturePkcs1,
880                    signature_type,
881                }
882                .into());
883            }
884        }
885        SignatureType::PssSha1 => {
886            if key_type != KeyType::Rsa {
887                return Err(Error::InvalidKeyTypeForSignatureType {
888                    key_type,
889                    signature_type,
890                }
891                .into());
892            } else if !mechanisms.contains(&KeyMechanism::RsaSignaturePssSha1) {
893                return Err(Error::InvalidKeyMechanismsForSignatureType {
894                    required_key_mechanism: KeyMechanism::RsaSignaturePssSha1,
895                    signature_type,
896                }
897                .into());
898            }
899        }
900        SignatureType::PssSha224 => {
901            if key_type != KeyType::Rsa {
902                return Err(Error::InvalidKeyTypeForSignatureType {
903                    key_type,
904                    signature_type,
905                }
906                .into());
907            } else if !mechanisms.contains(&KeyMechanism::RsaSignaturePssSha224) {
908                return Err(Error::InvalidKeyMechanismsForSignatureType {
909                    required_key_mechanism: KeyMechanism::RsaSignaturePssSha224,
910                    signature_type,
911                }
912                .into());
913            }
914        }
915        SignatureType::PssSha256 => {
916            if key_type != KeyType::Rsa {
917                return Err(Error::InvalidKeyTypeForSignatureType {
918                    key_type,
919                    signature_type,
920                }
921                .into());
922            } else if !mechanisms.contains(&KeyMechanism::RsaSignaturePssSha256) {
923                return Err(Error::InvalidKeyMechanismsForSignatureType {
924                    required_key_mechanism: KeyMechanism::RsaSignaturePssSha256,
925                    signature_type,
926                }
927                .into());
928            }
929        }
930        SignatureType::PssSha384 => {
931            if key_type != KeyType::Rsa {
932                return Err(Error::InvalidKeyTypeForSignatureType {
933                    key_type,
934                    signature_type,
935                }
936                .into());
937            } else if !mechanisms.contains(&KeyMechanism::RsaSignaturePssSha384) {
938                return Err(Error::InvalidKeyMechanismsForSignatureType {
939                    required_key_mechanism: KeyMechanism::RsaSignaturePssSha384,
940                    signature_type,
941                }
942                .into());
943            }
944        }
945        SignatureType::PssSha512 => {
946            if key_type != KeyType::Rsa {
947                return Err(Error::InvalidKeyTypeForSignatureType {
948                    key_type,
949                    signature_type,
950                }
951                .into());
952            } else if !mechanisms.contains(&KeyMechanism::RsaSignaturePssSha512) {
953                return Err(Error::InvalidKeyMechanismsForSignatureType {
954                    required_key_mechanism: KeyMechanism::RsaSignaturePssSha512,
955                    signature_type,
956                }
957                .into());
958            }
959        }
960    }
961    Ok(())
962}
963
964/// Ensures that a [`KeyType`] is compatible with an optional key length
965///
966/// # Errors
967///
968/// Returns an error if
969/// * `key_type` is one of [`KeyType::Curve25519`], [`KeyType::EcP256`], [`KeyType::EcP384`] or
970///   [`KeyType::EcP521`] and `length` is [`Some`].
971/// * `key_type` is [`KeyType::Generic`] or [`KeyType::Rsa`] and `length` is [`None`].
972/// * `key_type` is [`KeyType::Generic`] and `length` is not [`Some`] value of `128`, `192` or
973///   `256`.
974/// * `key_type` is [`KeyType::Rsa`] and `length` is not [`Some`] value equal to or greater than
975///   [`MIN_RSA_BIT_LENGTH`].
976///
977/// # Examples
978///
979/// ```
980/// use signstar_crypto::key::{KeyType, key_type_matches_length};
981///
982/// # fn main() -> testresult::TestResult {
983/// key_type_matches_length(KeyType::Curve25519, None)?;
984/// key_type_matches_length(KeyType::EcP256, None)?;
985/// key_type_matches_length(KeyType::Rsa, Some(2048))?;
986/// key_type_matches_length(KeyType::Generic, Some(256))?;
987///
988/// // this fails because elliptic curve keys have their length set intrinsically
989/// assert!(key_type_matches_length(KeyType::Curve25519, Some(2048)).is_err());
990/// // this fails because a bit length of 2048 is not defined for AES block ciphers
991/// assert!(key_type_matches_length(KeyType::Generic, Some(2048)).is_err());
992/// // this fails because a bit length of 1024 is unsafe to use for RSA keys
993/// assert!(key_type_matches_length(KeyType::Rsa, Some(1024)).is_err());
994/// # Ok(())
995/// # }
996/// ```
997pub fn key_type_matches_length(key_type: KeyType, length: Option<u32>) -> Result<(), crate::Error> {
998    match key_type {
999        KeyType::Curve25519
1000        | KeyType::EcBp256
1001        | KeyType::EcBp384
1002        | KeyType::EcBp512
1003        | KeyType::EcK256
1004        | KeyType::EcP224
1005        | KeyType::EcP256
1006        | KeyType::EcP384
1007        | KeyType::EcP521 => {
1008            if length.is_some() {
1009                Err(Error::KeyLengthUnsupported { key_type }.into())
1010            } else {
1011                Ok(())
1012            }
1013        }
1014        KeyType::Generic => match length {
1015            None => Err(Error::KeyLengthRequired { key_type }.into()),
1016            Some(length) => {
1017                if ![128, 192, 256].contains(&length) {
1018                    Err(Error::InvalidKeyLengthAes { key_length: length }.into())
1019                } else {
1020                    Ok(())
1021                }
1022            }
1023        },
1024        KeyType::Rsa => match length {
1025            None => Err(Error::KeyLengthRequired { key_type }.into()),
1026            Some(length) => {
1027                if length < MIN_RSA_BIT_LENGTH {
1028                    Err(Error::InvalidKeyLengthRsa { key_length: length }.into())
1029                } else {
1030                    Ok(())
1031                }
1032            }
1033        },
1034    }
1035}
1036
1037#[cfg(test)]
1038mod tests {
1039    use std::str::FromStr;
1040
1041    use rstest::rstest;
1042    use testresult::TestResult;
1043
1044    use super::*;
1045
1046    #[rstest]
1047    #[case(KeyType::Curve25519, &[KeyMechanism::EdDsaSignature], SignatureType::EdDsa, None)]
1048    #[case(KeyType::EcP256, &[KeyMechanism::EcdsaSignature], SignatureType::EcdsaP256, None)]
1049    #[case(KeyType::EcP384, &[KeyMechanism::EcdsaSignature], SignatureType::EcdsaP384, None)]
1050    #[case(KeyType::EcP521, &[KeyMechanism::EcdsaSignature], SignatureType::EcdsaP521, None)]
1051    #[case(KeyType::Rsa, &[KeyMechanism::RsaSignaturePkcs1], SignatureType::Pkcs1, None)]
1052    #[case(KeyType::Rsa, &[KeyMechanism::RsaSignaturePssSha1], SignatureType::PssSha1, None)]
1053    #[case(KeyType::Rsa, &[KeyMechanism::RsaSignaturePssSha224], SignatureType::PssSha224, None)]
1054    #[case(KeyType::Rsa, &[KeyMechanism::RsaSignaturePssSha256], SignatureType::PssSha256, None)]
1055    #[case(KeyType::Rsa, &[KeyMechanism::RsaSignaturePssSha384], SignatureType::PssSha384, None)]
1056    #[case(KeyType::Rsa, &[KeyMechanism::RsaSignaturePssSha512], SignatureType::PssSha512, None)]
1057    #[case(
1058        KeyType::Curve25519,
1059        &[KeyMechanism::EdDsaSignature],
1060        SignatureType::EcdsaP256,
1061        Some(Box::new(crate::Error::Key(Error::InvalidKeyTypeForSignatureType {
1062            key_type: KeyType::Curve25519,
1063            signature_type: SignatureType::EcdsaP256
1064        }))
1065    ))]
1066    #[case(
1067        KeyType::Curve25519,
1068        &[KeyMechanism::EcdsaSignature],
1069        SignatureType::EdDsa,
1070        Some(Box::new(crate::Error::Key(Error::InvalidKeyMechanismsForSignatureType {
1071            signature_type: SignatureType::EdDsa,
1072            required_key_mechanism: KeyMechanism::EdDsaSignature,
1073        }))
1074    ))]
1075    #[case(
1076        KeyType::EcP256,
1077        &[KeyMechanism::EcdsaSignature],
1078        SignatureType::EdDsa,
1079        Some(Box::new(crate::Error::Key(Error::InvalidKeyTypeForSignatureType {
1080            key_type: KeyType::EcP256,
1081            signature_type: SignatureType::EdDsa,
1082        }))
1083    ))]
1084    #[case(
1085        KeyType::EcP256,
1086        &[KeyMechanism::EdDsaSignature],
1087        SignatureType::EcdsaP256,
1088        Some(Box::new(crate::Error::Key(Error::InvalidKeyMechanismsForSignatureType {
1089            signature_type: SignatureType::EcdsaP256,
1090            required_key_mechanism: KeyMechanism::EcdsaSignature,
1091        }))
1092    ))]
1093    #[case(
1094        KeyType::EcP384,
1095        &[KeyMechanism::EcdsaSignature],
1096        SignatureType::EdDsa,
1097        Some(Box::new(crate::Error::Key(Error::InvalidKeyTypeForSignatureType {
1098            key_type: KeyType::EcP384,
1099            signature_type: SignatureType::EdDsa,
1100        }))
1101    ))]
1102    #[case(
1103        KeyType::EcP384,
1104        &[KeyMechanism::EdDsaSignature],
1105        SignatureType::EcdsaP384,
1106        Some(Box::new(crate::Error::Key(Error::InvalidKeyMechanismsForSignatureType {
1107            signature_type: SignatureType::EcdsaP384,
1108            required_key_mechanism: KeyMechanism::EcdsaSignature,
1109        }))
1110    ))]
1111    #[case(
1112        KeyType::EcP521,
1113        &[KeyMechanism::EcdsaSignature],
1114        SignatureType::EdDsa,
1115        Some(Box::new(crate::Error::Key(Error::InvalidKeyTypeForSignatureType {
1116            key_type: KeyType::EcP521,
1117            signature_type: SignatureType::EdDsa,
1118        }))
1119    ))]
1120    #[case(
1121        KeyType::EcP521,
1122        &[KeyMechanism::EdDsaSignature],
1123        SignatureType::EcdsaP521,
1124        Some(Box::new(crate::Error::Key(Error::InvalidKeyMechanismsForSignatureType {
1125            signature_type: SignatureType::EcdsaP521,
1126            required_key_mechanism: KeyMechanism::EcdsaSignature,
1127        }))
1128    ))]
1129    #[case(
1130        KeyType::Rsa,
1131        &[KeyMechanism::RsaSignaturePkcs1],
1132        SignatureType::EdDsa,
1133        Some(Box::new(crate::Error::Key(Error::InvalidKeyTypeForSignatureType {
1134            key_type: KeyType::Rsa,
1135            signature_type: SignatureType::EdDsa,
1136        }))
1137    ))]
1138    fn test_key_type_and_mechanisms_match_signature_type(
1139        #[case] key_type: KeyType,
1140        #[case] key_mechanisms: &[KeyMechanism],
1141        #[case] signature_type: SignatureType,
1142        #[case] result: Option<Box<crate::Error>>,
1143    ) -> TestResult {
1144        if let Some(error) = result {
1145            if let Err(fn_error) = key_type_and_mechanisms_match_signature_type(
1146                key_type,
1147                key_mechanisms,
1148                signature_type,
1149            ) {
1150                assert_eq!(fn_error.to_string(), error.to_string());
1151            } else {
1152                panic!("Did not return an Error!");
1153            }
1154        } else {
1155            key_type_and_mechanisms_match_signature_type(key_type, key_mechanisms, signature_type)?;
1156        }
1157
1158        Ok(())
1159    }
1160
1161    #[rstest]
1162    #[case("raw", Some(DecryptMode::Raw))]
1163    #[case("pkcs1", Some(DecryptMode::Pkcs1))]
1164    #[case("oaepmd5", Some(DecryptMode::OaepMd5))]
1165    #[case("oaepsha1", Some(DecryptMode::OaepSha1))]
1166    #[case("oaepsha224", Some(DecryptMode::OaepSha224))]
1167    #[case("oaepsha256", Some(DecryptMode::OaepSha256))]
1168    #[case("oaepsha384", Some(DecryptMode::OaepSha384))]
1169    #[case("oaepsha512", Some(DecryptMode::OaepSha512))]
1170    #[case("aescbc", Some(DecryptMode::AesCbc))]
1171    #[case("foo", None)]
1172    fn decryptmode_fromstr(
1173        #[case] input: &str,
1174        #[case] expected: Option<DecryptMode>,
1175    ) -> TestResult {
1176        if let Some(expected) = expected {
1177            assert_eq!(DecryptMode::from_str(input)?, expected);
1178        } else {
1179            assert!(DecryptMode::from_str(input).is_err());
1180        }
1181        Ok(())
1182    }
1183
1184    #[rstest]
1185    #[case("aescbc", Some(EncryptMode::AesCbc))]
1186    #[case("foo", None)]
1187    fn encryptmode_fromstr(
1188        #[case] input: &str,
1189        #[case] expected: Option<EncryptMode>,
1190    ) -> TestResult {
1191        if let Some(expected) = expected {
1192            assert_eq!(EncryptMode::from_str(input)?, expected);
1193        } else {
1194            assert!(EncryptMode::from_str(input).is_err());
1195        }
1196        Ok(())
1197    }
1198
1199    #[rstest]
1200    #[case("rsadecryptionraw", Some(KeyMechanism::RsaDecryptionRaw))]
1201    #[case("rsadecryptionpkcs1", Some(KeyMechanism::RsaDecryptionPkcs1))]
1202    #[case("rsadecryptionoaepmd5", Some(KeyMechanism::RsaDecryptionOaepMd5))]
1203    #[case("rsadecryptionoaepsha1", Some(KeyMechanism::RsaDecryptionOaepSha1))]
1204    #[case("rsadecryptionoaepsha224", Some(KeyMechanism::RsaDecryptionOaepSha224))]
1205    #[case("rsadecryptionoaepsha256", Some(KeyMechanism::RsaDecryptionOaepSha256))]
1206    #[case("rsadecryptionoaepsha384", Some(KeyMechanism::RsaDecryptionOaepSha384))]
1207    #[case("rsadecryptionoaepsha512", Some(KeyMechanism::RsaDecryptionOaepSha512))]
1208    #[case("rsadecryptionoaepsha512", Some(KeyMechanism::RsaDecryptionOaepSha512))]
1209    #[case("rsasignaturepkcs1", Some(KeyMechanism::RsaSignaturePkcs1))]
1210    #[case("rsasignaturepsssha1", Some(KeyMechanism::RsaSignaturePssSha1))]
1211    #[case("rsasignaturepsssha224", Some(KeyMechanism::RsaSignaturePssSha224))]
1212    #[case("rsasignaturepsssha256", Some(KeyMechanism::RsaSignaturePssSha256))]
1213    #[case("rsasignaturepsssha384", Some(KeyMechanism::RsaSignaturePssSha384))]
1214    #[case("rsasignaturepsssha512", Some(KeyMechanism::RsaSignaturePssSha512))]
1215    #[case("eddsasignature", Some(KeyMechanism::EdDsaSignature))]
1216    #[case("ecdsasignature", Some(KeyMechanism::EcdsaSignature))]
1217    #[case("aesencryptioncbc", Some(KeyMechanism::AesEncryptionCbc))]
1218    #[case("aesdecryptioncbc", Some(KeyMechanism::AesDecryptionCbc))]
1219    #[case("foo", None)]
1220    fn keymechanism_fromstr(
1221        #[case] input: &str,
1222        #[case] expected: Option<KeyMechanism>,
1223    ) -> TestResult {
1224        if let Some(expected) = expected {
1225            assert_eq!(KeyMechanism::from_str(input)?, expected);
1226        } else {
1227            assert!(KeyMechanism::from_str(input).is_err());
1228        }
1229        Ok(())
1230    }
1231
1232    #[rstest]
1233    #[case("rsa", Some(KeyType::Rsa))]
1234    #[case("curve25519", Some(KeyType::Curve25519))]
1235    #[case("ecp256", Some(KeyType::EcP256))]
1236    #[case("ecp384", Some(KeyType::EcP384))]
1237    #[case("ecp521", Some(KeyType::EcP521))]
1238    #[case("generic", Some(KeyType::Generic))]
1239    #[case("foo", None)]
1240    fn keytype_fromstr(#[case] input: &str, #[case] expected: Option<KeyType>) -> TestResult {
1241        if let Some(expected) = expected {
1242            assert_eq!(KeyType::from_str(input)?, expected);
1243        } else {
1244            assert!(KeyType::from_str(input).is_err());
1245        }
1246        Ok(())
1247    }
1248
1249    #[rstest]
1250    #[case("ecdsap256", Some(SignatureType::EcdsaP256))]
1251    #[case("ecdsap384", Some(SignatureType::EcdsaP384))]
1252    #[case("ecdsap521", Some(SignatureType::EcdsaP521))]
1253    #[case("eddsa", Some(SignatureType::EdDsa))]
1254    #[case("pkcs1", Some(SignatureType::Pkcs1))]
1255    #[case("psssha1", Some(SignatureType::PssSha1))]
1256    #[case("psssha224", Some(SignatureType::PssSha224))]
1257    #[case("psssha256", Some(SignatureType::PssSha256))]
1258    #[case("psssha384", Some(SignatureType::PssSha384))]
1259    #[case("psssha512", Some(SignatureType::PssSha512))]
1260    #[case("foo", None)]
1261    fn signaturetype_fromstr(
1262        #[case] input: &str,
1263        #[case] expected: Option<SignatureType>,
1264    ) -> TestResult {
1265        if let Some(expected) = expected {
1266            assert_eq!(SignatureType::from_str(input)?, expected);
1267        } else {
1268            assert!(SignatureType::from_str(input).is_err());
1269        }
1270        Ok(())
1271    }
1272}