Skip to main content

signstar_crypto/key/base/
mod.rs

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