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