script/dom/webcrypto/subtlecrypto/
rsa_pss_operation.rs1use js::context::JSContext;
6use rsa::pss::{Signature, SigningKey, VerifyingKey};
7use rsa::signature::{RandomizedSigner, SignatureEncoding, Verifier};
8use sha1::Sha1;
9use sha2::{Sha256, Sha384, Sha512};
10
11use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
12 CryptoKeyMethods, CryptoKeyPair, KeyType, KeyUsage,
13};
14use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::KeyFormat;
15use crate::dom::bindings::error::Error;
16use crate::dom::bindings::root::DomRoot;
17use crate::dom::cryptokey::{CryptoKey, Handle};
18use crate::dom::globalscope::GlobalScope;
19use crate::dom::subtlecrypto::rsa_common::{self, RsaAlgorithm};
20use crate::dom::subtlecrypto::{
21 CryptoAlgorithm, ExportedKey, KeyAlgorithmAndDerivatives, NormalizedAlgorithm,
22 SubtleRsaHashedImportParams, SubtleRsaHashedKeyGenParams, SubtleRsaPssParams,
23};
24
25pub(crate) fn sign(
27 normalized_algorithm: &SubtleRsaPssParams,
28 key: &CryptoKey,
29 message: &[u8],
30) -> Result<Vec<u8>, Error> {
31 if key.Type() != KeyType::Private {
34 return Err(Error::InvalidAccess(Some(
35 "[[type]] internal slot of key is not \"private\"".to_string(),
36 )));
37 }
38
39 let Handle::RsaPrivateKey(private_key) = key.handle() else {
48 return Err(Error::Operation(Some(
49 "[[handle]] internal slot of key is not an RSA private key".to_string(),
50 )));
51 };
52 let KeyAlgorithmAndDerivatives::RsaHashedKeyAlgorithm(algorithm) = key.algorithm() else {
53 return Err(Error::Operation(Some(
54 "[[algorithm]] internal slot of key is not an RsaHashedKeyAlgorithm".to_string(),
55 )));
56 };
57 let mut rng = rand::rng();
58 let signature = match algorithm.hash.name() {
59 CryptoAlgorithm::Sha1 => {
60 let signing_key = SigningKey::<Sha1>::new_with_salt_len(
61 private_key.clone(),
62 normalized_algorithm.salt_length as usize,
63 );
64 signing_key.try_sign_with_rng(&mut rng, message)
65 },
66 CryptoAlgorithm::Sha256 => {
67 let signing_key = SigningKey::<Sha256>::new_with_salt_len(
68 private_key.clone(),
69 normalized_algorithm.salt_length as usize,
70 );
71 signing_key.try_sign_with_rng(&mut rng, message)
72 },
73 CryptoAlgorithm::Sha384 => {
74 let signing_key = SigningKey::<Sha384>::new_with_salt_len(
75 private_key.clone(),
76 normalized_algorithm.salt_length as usize,
77 );
78 signing_key.try_sign_with_rng(&mut rng, message)
79 },
80 CryptoAlgorithm::Sha512 => {
81 let signing_key = SigningKey::<Sha512>::new_with_salt_len(
82 private_key.clone(),
83 normalized_algorithm.salt_length as usize,
84 );
85 signing_key.try_sign_with_rng(&mut rng, message)
86 },
87 _ => {
88 return Err(Error::Operation(Some(format!(
89 "Unsupported \"{}\" hash for RSA-PSS",
90 algorithm.hash.name().as_str()
91 ))));
92 },
93 }
94 .map_err(|_| Error::Operation(Some("RSA-PSS failed to sign message".to_string())))?;
95
96 Ok(signature.to_vec())
98}
99
100pub(crate) fn verify(
102 normalized_algorithm: &SubtleRsaPssParams,
103 key: &CryptoKey,
104 message: &[u8],
105 signature: &[u8],
106) -> Result<bool, Error> {
107 if key.Type() != KeyType::Public {
110 return Err(Error::InvalidAccess(Some(
111 "[[type]] internal slot of key is not \"public\"".to_string(),
112 )));
113 }
114
115 let Handle::RsaPublicKey(public_key) = key.handle() else {
124 return Err(Error::Operation(Some(
125 "[[handle]] internal slot of key is not an RSA public key".to_string(),
126 )));
127 };
128 let KeyAlgorithmAndDerivatives::RsaHashedKeyAlgorithm(algorithm) = key.algorithm() else {
129 return Err(Error::Operation(Some(
130 "[[algorithm]] internal slot of key is not an RsaHashedKeyAlgorithm".to_string(),
131 )));
132 };
133 let signature = Signature::try_from(signature)
134 .map_err(|_| Error::Operation(Some("Failed to parse RSA signature".to_string())))?;
135 let result = match algorithm.hash.name() {
136 CryptoAlgorithm::Sha1 => {
137 let verifying_key = VerifyingKey::<Sha1>::new_with_salt_len(
138 public_key.clone(),
139 normalized_algorithm.salt_length as usize,
140 );
141 verifying_key.verify(message, &signature)
142 },
143 CryptoAlgorithm::Sha256 => {
144 let verifying_key = VerifyingKey::<Sha256>::new_with_salt_len(
145 public_key.clone(),
146 normalized_algorithm.salt_length as usize,
147 );
148 verifying_key.verify(message, &signature)
149 },
150 CryptoAlgorithm::Sha384 => {
151 let verifying_key = VerifyingKey::<Sha384>::new_with_salt_len(
152 public_key.clone(),
153 normalized_algorithm.salt_length as usize,
154 );
155 verifying_key.verify(message, &signature)
156 },
157 CryptoAlgorithm::Sha512 => {
158 let verifying_key = VerifyingKey::<Sha512>::new_with_salt_len(
159 public_key.clone(),
160 normalized_algorithm.salt_length as usize,
161 );
162 verifying_key.verify(message, &signature)
163 },
164 _ => {
165 return Err(Error::Operation(Some(format!(
166 "Unsupported \"{}\" hash for RSASSA-PKCS1-v1_5",
167 algorithm.hash.name().as_str()
168 ))));
169 },
170 }
171 .is_ok();
172
173 Ok(result)
175}
176
177pub(crate) fn generate_key(
179 cx: &mut JSContext,
180 global: &GlobalScope,
181 normalized_algorithm: &SubtleRsaHashedKeyGenParams,
182 extractable: bool,
183 usages: Vec<KeyUsage>,
184) -> Result<CryptoKeyPair, Error> {
185 rsa_common::generate_key(
186 RsaAlgorithm::RsaPss,
187 cx,
188 global,
189 normalized_algorithm,
190 extractable,
191 usages,
192 )
193}
194
195pub(crate) fn import_key(
197 cx: &mut JSContext,
198 global: &GlobalScope,
199 normalized_algorithm: &SubtleRsaHashedImportParams,
200 format: KeyFormat,
201 key_data: &[u8],
202 extractable: bool,
203 usages: Vec<KeyUsage>,
204) -> Result<DomRoot<CryptoKey>, Error> {
205 rsa_common::import_key(
206 RsaAlgorithm::RsaPss,
207 cx,
208 global,
209 normalized_algorithm,
210 format,
211 key_data,
212 extractable,
213 usages,
214 )
215}
216
217pub(crate) fn export_key(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
219 rsa_common::export_key(RsaAlgorithm::RsaPss, format, key)
220}
221
222pub(crate) fn get_public_key(
225 cx: &mut JSContext,
226 global: &GlobalScope,
227 key: &CryptoKey,
228 algorithm: &KeyAlgorithmAndDerivatives,
229 usages: Vec<KeyUsage>,
230) -> Result<DomRoot<CryptoKey>, Error> {
231 rsa_common::get_public_key(RsaAlgorithm::RsaPss, cx, global, key, algorithm, usages)
232}