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