1 //! Signature algorithms supported by picky
2 
3 use crate::hash::HashAlgorithm;
4 use crate::key::{KeyError, PrivateKey, PublicKey};
5 use core::convert::TryFrom;
6 use picky_asn1_x509::{oids, AlgorithmIdentifier};
7 use rsa::{PublicKey as RsaPublicKeyInterface, RSAPrivateKey, RSAPublicKey};
8 use serde::{Deserialize, Serialize};
9 use thiserror::Error;
10 
11 #[derive(Debug, Error)]
12 #[non_exhaustive]
13 pub 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 
31 impl From<rsa::errors::Error> for SignatureError {
from(e: rsa::errors::Error) -> Self32     fn from(e: rsa::errors::Error) -> Self {
33         SignatureError::Rsa { context: e.to_string() }
34     }
35 }
36 
37 impl From<KeyError> for SignatureError {
from(e: KeyError) -> Self38     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]
46 pub enum SignatureAlgorithm {
47     RsaPkcs1v15(HashAlgorithm),
48 }
49 
50 impl TryFrom<&'_ AlgorithmIdentifier> for SignatureAlgorithm {
51     type Error = SignatureError;
52 
try_from(v: &AlgorithmIdentifier) -> Result<Self, Self::Error>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 
68 impl From<SignatureAlgorithm> for AlgorithmIdentifier {
from(ty: SignatureAlgorithm) -> Self69     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 
94 impl SignatureAlgorithm {
from_algorithm_identifier(algorithm_identifier: &AlgorithmIdentifier) -> Result<Self, SignatureError>95     pub fn from_algorithm_identifier(algorithm_identifier: &AlgorithmIdentifier) -> Result<Self, SignatureError> {
96         Self::try_from(algorithm_identifier)
97     }
98 
sign(self, msg: &[u8], private_key: &PrivateKey) -> Result<Vec<u8>, SignatureError>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 
verify(self, public_key: &PublicKey, msg: &[u8], signature: &[u8]) -> Result<(), SignatureError>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 }
129