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