script_webcrypto/subtlecrypto/
ecdsa_operation.rs1use ecdsa::signature::hazmat::{PrehashVerifier, RandomizedPrehashSigner};
6use ecdsa::{Signature, SigningKey, VerifyingKey};
7use js::context::JSContext;
8use p256::NistP256;
9use p384::NistP384;
10use p521::NistP521;
11use script_bindings::codegen::GenericBindings::CryptoKeyBinding::{
12 CryptoKeyPair, KeyType, KeyUsage,
13};
14use script_bindings::codegen::GenericBindings::SubtleCryptoBinding::KeyFormat;
15use script_bindings::error::Error;
16use script_bindings::root::DomRoot;
17
18use crate::cryptokey::{CryptoKey, Handle};
19use crate::subtlecrypto::ec_common::EcAlgorithm;
20use crate::subtlecrypto::{
21 EcKeyGenParams, EcKeyImportParams, EcdsaParams, ExportedKey, KeyAlgorithmAndDerivatives,
22 NAMED_CURVE_P256, NAMED_CURVE_P384, NAMED_CURVE_P521, ec_common,
23};
24use crate::traits::Equivalence;
25
26pub(crate) fn sign<D: Equivalence>(
28 normalized_algorithm: &EcdsaParams,
29 key: &CryptoKey<D>,
30 message: &[u8],
31) -> Result<Vec<u8>, Error> {
32 key.ensure_type(KeyType::Private)?;
35
36 let hash_algorithm = &normalized_algorithm.hash;
38
39 let m = hash_algorithm.digest(message)?;
42
43 let KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm) = key.algorithm() else {
64 return Err(Error::Operation(Some(
65 "Key algorithm is not a elliptic curve key algorithm.".into(),
66 )));
67 };
68 let mut rng = rand::rng();
69 let result = match algorithm.named_curve.as_str() {
70 NAMED_CURVE_P256 => {
71 let Handle::P256PrivateKey(d) = key.handle() else {
72 return Err(Error::Operation(Some(
73 "Key handle is not a P256PrivateKey.".into(),
74 )));
75 };
76 let signing_key = SigningKey::<NistP256>::from(d);
77 let signature: Signature<NistP256> = signing_key
78 .sign_prehash_with_rng(&mut rng, &m)
79 .map_err(|_| Error::Operation(Some("ECDSA signing process failed.".into())))?;
80 signature.to_vec()
81 },
82 NAMED_CURVE_P384 => {
83 let Handle::P384PrivateKey(d) = key.handle() else {
84 return Err(Error::Operation(Some(
85 "Key handle is not a P384PrivateKey.".into(),
86 )));
87 };
88 let signing_key = SigningKey::<NistP384>::from(d);
89 let signature: Signature<NistP384> = signing_key
90 .sign_prehash_with_rng(&mut rng, &m)
91 .map_err(|_| Error::Operation(Some("ECDSA signing process failed.".into())))?;
92 signature.to_vec()
93 },
94 NAMED_CURVE_P521 => {
95 let Handle::P521PrivateKey(d) = key.handle() else {
96 return Err(Error::Operation(Some(
97 "Key handle is not a P521PrivateKey.".into(),
98 )));
99 };
100 let signing_key = SigningKey::<NistP521>::from(d);
101 let signature: Signature<NistP521> = signing_key
102 .sign_prehash_with_rng(&mut rng, &m)
103 .map_err(|_| Error::Operation(Some("ECDSA signing process failed.".into())))?;
104 signature.to_vec()
105 },
106 _ => {
107 return Err(Error::NotSupported(Some(
108 "Algorithm's curve is not supported.".into(),
109 )));
110 },
111 };
112
113 Ok(result)
115}
116
117pub(crate) fn verify<D: Equivalence>(
119 normalized_algorithm: &EcdsaParams,
120 key: &CryptoKey<D>,
121 message: &[u8],
122 signature: &[u8],
123) -> Result<bool, Error> {
124 key.ensure_type(KeyType::Public)?;
127
128 let hash_algorithm = &normalized_algorithm.hash;
130
131 let m = hash_algorithm.digest(message)?;
134
135 let KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm) = key.algorithm() else {
157 return Err(Error::Operation(Some(
158 "Key algorithm is not a elliptic curve key algorithm.".into(),
159 )));
160 };
161 let result = match algorithm.named_curve.as_str() {
162 NAMED_CURVE_P256 => {
163 let Handle::P256PublicKey(q) = key.handle() else {
164 return Err(Error::Operation(Some(
165 "Key handle is not a P256PublicKey.".into(),
166 )));
167 };
168 match Signature::<NistP256>::from_slice(signature) {
169 Ok(signature) => {
170 let verifying_key = VerifyingKey::<NistP256>::from(q);
171 verifying_key.verify_prehash(&m, &signature).is_ok()
172 },
173 Err(_) => false,
174 }
175 },
176 NAMED_CURVE_P384 => {
177 let Handle::P384PublicKey(q) = key.handle() else {
178 return Err(Error::Operation(Some(
179 "Key handle is not a P384PublicKey.".into(),
180 )));
181 };
182 match Signature::<NistP384>::from_slice(signature) {
183 Ok(signature) => {
184 let verifying_key = VerifyingKey::<NistP384>::from(q);
185 verifying_key.verify_prehash(&m, &signature).is_ok()
186 },
187 Err(_) => false,
188 }
189 },
190 NAMED_CURVE_P521 => {
191 let Handle::P521PublicKey(q) = key.handle() else {
192 return Err(Error::Operation(Some(
193 "Key handle is not a P521PublicKey.".into(),
194 )));
195 };
196 match Signature::<NistP521>::from_slice(signature) {
197 Ok(signature) => {
198 let verifying_key = VerifyingKey::<NistP521>::from(q);
199 verifying_key.verify_prehash(&m, &signature).is_ok()
200 },
201 Err(_) => false,
202 }
203 },
204 _ => {
205 return Err(Error::NotSupported(Some(
206 "Algorithm's curve is not supported.".into(),
207 )));
208 },
209 };
210
211 Ok(result)
213}
214
215pub(crate) fn generate_key<D: Equivalence>(
217 cx: &mut JSContext,
218 global: &D::GlobalScope,
219 normalized_algorithm: &EcKeyGenParams,
220 extractable: bool,
221 usages: Vec<KeyUsage>,
222) -> Result<CryptoKeyPair<D>, Error> {
223 ec_common::generate_key(
224 cx,
225 global,
226 EcAlgorithm::Ecdsa,
227 normalized_algorithm,
228 extractable,
229 usages,
230 )
231}
232
233pub(crate) fn import_key<D: Equivalence>(
235 cx: &mut JSContext,
236 global: &D::GlobalScope,
237 normalized_algorithm: &EcKeyImportParams,
238 format: KeyFormat,
239 key_data: &[u8],
240 extractable: bool,
241 usages: Vec<KeyUsage>,
242) -> Result<DomRoot<CryptoKey<D>>, Error> {
243 ec_common::import_key(
244 cx,
245 global,
246 EcAlgorithm::Ecdsa,
247 normalized_algorithm,
248 format,
249 key_data,
250 extractable,
251 usages,
252 )
253}
254
255pub(crate) fn export_key<D: Equivalence>(
257 format: KeyFormat,
258 key: &CryptoKey<D>,
259) -> Result<ExportedKey, Error> {
260 ec_common::export_key(format, key)
261}
262
263pub(crate) fn get_public_key<D: Equivalence>(
266 cx: &mut JSContext,
267 global: &D::GlobalScope,
268 key: &CryptoKey<D>,
269 algorithm: &KeyAlgorithmAndDerivatives,
270 usages: Vec<KeyUsage>,
271) -> Result<DomRoot<CryptoKey<D>>, Error> {
272 ec_common::get_public_key(cx, global, EcAlgorithm::Ecdsa, key, algorithm, usages)
273}