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