1use 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 #[error("Key error: {source}")]
16 Key { source: KeyError },
17
18 #[error("RSA error: {context}")]
20 Rsa { context: String },
21
22 #[error("invalid signature")]
24 BadSignature,
25
26 #[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#[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}