picky/
signature.rs

1//! Signature algorithms supported by picky
2
3use crate::hash::HashAlgorithm;
4use crate::key::{KeyError, PrivateKey, PublicKey};
5use core::convert::TryFrom;
6use picky_asn1_x509::{oids, AlgorithmIdentifier};
7use rsa::{PublicKey as RsaPublicKeyInterface, RSAPrivateKey, RSAPublicKey};
8use serde::{Deserialize, Serialize};
9use thiserror::Error;
10
11#[derive(Debug, Error)]
12#[non_exhaustive]
13pub enum SignatureError {
14    /// Key error
15    #[error("Key error: {source}")]
16    Key { source: KeyError },
17
18    /// RSA error
19    #[error("RSA error: {context}")]
20    Rsa { context: String },
21
22    /// invalid signature
23    #[error("invalid signature")]
24    BadSignature,
25
26    /// unsupported algorithm
27    #[error("unsupported algorithm: {algorithm}")]
28    UnsupportedAlgorithm { algorithm: String },
29}
30
31impl From<rsa::errors::Error> for SignatureError {
32    fn from(e: rsa::errors::Error) -> Self {
33        SignatureError::Rsa { context: e.to_string() }
34    }
35}
36
37impl From<KeyError> for SignatureError {
38    fn from(e: KeyError) -> Self {
39        SignatureError::Key { source: e }
40    }
41}
42
43/// Supported signature algorithms
44#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
45#[non_exhaustive]
46pub enum SignatureAlgorithm {
47    RsaPkcs1v15(HashAlgorithm),
48}
49
50impl TryFrom<&'_ AlgorithmIdentifier> for SignatureAlgorithm {
51    type Error = SignatureError;
52
53    fn try_from(v: &AlgorithmIdentifier) -> Result<Self, Self::Error> {
54        let oid_string: String = v.oid().into();
55        match oid_string.as_str() {
56            oids::SHA1_WITH_RSA_ENCRYPTION => Ok(Self::RsaPkcs1v15(HashAlgorithm::SHA1)),
57            oids::SHA224_WITH_RSA_ENCRYPTION => Ok(Self::RsaPkcs1v15(HashAlgorithm::SHA2_224)),
58            oids::SHA256_WITH_RSA_ENCRYPTION => Ok(Self::RsaPkcs1v15(HashAlgorithm::SHA2_256)),
59            oids::SHA384_WITH_RSA_ENCRYPTION => Ok(Self::RsaPkcs1v15(HashAlgorithm::SHA2_384)),
60            oids::SHA512_WITH_RSA_ENCRYPTION => Ok(Self::RsaPkcs1v15(HashAlgorithm::SHA2_512)),
61            oids::ID_RSASSA_PKCS1_V1_5_WITH_SHA3_384 => Ok(Self::RsaPkcs1v15(HashAlgorithm::SHA3_384)),
62            oids::ID_RSASSA_PKCS1_V1_5_WITH_SHA3_512 => Ok(Self::RsaPkcs1v15(HashAlgorithm::SHA3_512)),
63            _ => Err(SignatureError::UnsupportedAlgorithm { algorithm: oid_string }),
64        }
65    }
66}
67
68impl From<SignatureAlgorithm> for AlgorithmIdentifier {
69    fn from(ty: SignatureAlgorithm) -> Self {
70        match ty {
71            SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA1) => AlgorithmIdentifier::new_sha1_with_rsa_encryption(),
72            SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA2_224) => {
73                AlgorithmIdentifier::new_sha224_with_rsa_encryption()
74            }
75            SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA2_256) => {
76                AlgorithmIdentifier::new_sha256_with_rsa_encryption()
77            }
78            SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA2_384) => {
79                AlgorithmIdentifier::new_sha384_with_rsa_encryption()
80            }
81            SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA2_512) => {
82                AlgorithmIdentifier::new_sha512_with_rsa_encryption()
83            }
84            SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA3_384) => {
85                AlgorithmIdentifier::new_sha3_384_with_rsa_encryption()
86            }
87            SignatureAlgorithm::RsaPkcs1v15(HashAlgorithm::SHA3_512) => {
88                AlgorithmIdentifier::new_sha3_512_with_rsa_encryption()
89            }
90        }
91    }
92}
93
94impl SignatureAlgorithm {
95    pub fn from_algorithm_identifier(algorithm_identifier: &AlgorithmIdentifier) -> Result<Self, SignatureError> {
96        Self::try_from(algorithm_identifier)
97    }
98
99    pub fn sign(self, msg: &[u8], private_key: &PrivateKey) -> Result<Vec<u8>, SignatureError> {
100        let signature = match self {
101            SignatureAlgorithm::RsaPkcs1v15(picky_hash_algo) => {
102                let rsa_private_key = RSAPrivateKey::try_from(private_key)?;
103                let digest = picky_hash_algo.digest(msg);
104                let rsa_hash_algo = rsa::Hash::from(picky_hash_algo);
105                let padding_scheme = rsa::PaddingScheme::new_pkcs1v15_sign(Some(rsa_hash_algo));
106                rsa_private_key.sign_blinded(&mut rand::rngs::OsRng, padding_scheme, &digest)?
107            }
108        };
109
110        Ok(signature)
111    }
112
113    pub fn verify(self, public_key: &PublicKey, msg: &[u8], signature: &[u8]) -> Result<(), SignatureError> {
114        match self {
115            SignatureAlgorithm::RsaPkcs1v15(picky_hash_algo) => {
116                let rsa_public_key = RSAPublicKey::try_from(public_key)?;
117                let digest = picky_hash_algo.digest(msg);
118                let rsa_hash_algo = rsa::Hash::from(picky_hash_algo);
119                let padding_scheme = rsa::PaddingScheme::new_pkcs1v15_sign(Some(rsa_hash_algo));
120                rsa_public_key
121                    .verify(padding_scheme, &digest, signature)
122                    .map_err(|_| SignatureError::BadSignature)?;
123            }
124        }
125
126        Ok(())
127    }
128}