script/dom/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;
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::ec_common::EcAlgorithm;
21use crate::dom::subtlecrypto::{
22 ExportedKey, KeyAlgorithmAndDerivatives, NAMED_CURVE_P256, NAMED_CURVE_P384, NAMED_CURVE_P521,
23 SubtleEcKeyGenParams, SubtleEcKeyImportParams, SubtleEcdsaParams, ec_common,
24};
25
26pub(crate) fn sign(
28 normalized_algorithm: &SubtleEcdsaParams,
29 key: &CryptoKey,
30 message: &[u8],
31) -> Result<Vec<u8>, Error> {
32 if key.Type() != KeyType::Private {
35 return Err(Error::InvalidAccess(Some(
36 "The key type is not private.".into(),
37 )));
38 }
39
40 let hash_algorithm = &normalized_algorithm.hash;
42
43 let m = hash_algorithm.digest(message)?;
46
47 let KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm) = key.algorithm() else {
68 return Err(Error::Operation(Some(
69 "Key algorithm is not a elliptic curve key algorithm.".into(),
70 )));
71 };
72 let mut rng = rand::rng();
73 let result = match algorithm.named_curve.as_str() {
74 NAMED_CURVE_P256 => {
75 let Handle::P256PrivateKey(d) = key.handle() else {
76 return Err(Error::Operation(Some(
77 "Key handle is not a P256PrivateKey.".into(),
78 )));
79 };
80 let signing_key = SigningKey::<NistP256>::from(d);
81 let signature: Signature<NistP256> = signing_key
82 .sign_prehash_with_rng(&mut rng, &m)
83 .map_err(|_| Error::Operation(Some("ECDSA signing process failed.".into())))?;
84 signature.to_vec()
85 },
86 NAMED_CURVE_P384 => {
87 let Handle::P384PrivateKey(d) = key.handle() else {
88 return Err(Error::Operation(Some(
89 "Key handle is not a P384PrivateKey.".into(),
90 )));
91 };
92 let signing_key = SigningKey::<NistP384>::from(d);
93 let signature: Signature<NistP384> = signing_key
94 .sign_prehash_with_rng(&mut rng, &m)
95 .map_err(|_| Error::Operation(Some("ECDSA signing process failed.".into())))?;
96 signature.to_vec()
97 },
98 NAMED_CURVE_P521 => {
99 let Handle::P521PrivateKey(d) = key.handle() else {
100 return Err(Error::Operation(Some(
101 "Key handle is not a P521PrivateKey.".into(),
102 )));
103 };
104 let signing_key = SigningKey::<NistP521>::from(d);
105 let signature: Signature<NistP521> = signing_key
106 .sign_prehash_with_rng(&mut rng, &m)
107 .map_err(|_| Error::Operation(Some("ECDSA signing process failed.".into())))?;
108 signature.to_vec()
109 },
110 _ => {
111 return Err(Error::NotSupported(Some(
112 "Algorithm's curve is not supported.".into(),
113 )));
114 },
115 };
116
117 Ok(result)
119}
120
121pub(crate) fn verify(
123 normalized_algorithm: &SubtleEcdsaParams,
124 key: &CryptoKey,
125 message: &[u8],
126 signature: &[u8],
127) -> Result<bool, Error> {
128 if key.Type() != KeyType::Public {
131 return Err(Error::InvalidAccess(Some("Key type is not public".into())));
132 }
133
134 let hash_algorithm = &normalized_algorithm.hash;
136
137 let m = hash_algorithm.digest(message)?;
140
141 let KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm) = key.algorithm() else {
163 return Err(Error::Operation(Some(
164 "Key algorithm is not a elliptic curve key algorithm.".into(),
165 )));
166 };
167 let result = match algorithm.named_curve.as_str() {
168 NAMED_CURVE_P256 => {
169 let Handle::P256PublicKey(q) = key.handle() else {
170 return Err(Error::Operation(Some(
171 "Key handle is not a P256PublicKey.".into(),
172 )));
173 };
174 match Signature::<NistP256>::from_slice(signature) {
175 Ok(signature) => {
176 let verifying_key = VerifyingKey::<NistP256>::from(q);
177 verifying_key.verify_prehash(&m, &signature).is_ok()
178 },
179 Err(_) => false,
180 }
181 },
182 NAMED_CURVE_P384 => {
183 let Handle::P384PublicKey(q) = key.handle() else {
184 return Err(Error::Operation(Some(
185 "Key handle is not a P384PublicKey.".into(),
186 )));
187 };
188 match Signature::<NistP384>::from_slice(signature) {
189 Ok(signature) => {
190 let verifying_key = VerifyingKey::<NistP384>::from(q);
191 verifying_key.verify_prehash(&m, &signature).is_ok()
192 },
193 Err(_) => false,
194 }
195 },
196 NAMED_CURVE_P521 => {
197 let Handle::P521PublicKey(q) = key.handle() else {
198 return Err(Error::Operation(Some(
199 "Key handle is not a P521PublicKey.".into(),
200 )));
201 };
202 match Signature::<NistP521>::from_slice(signature) {
203 Ok(signature) => {
204 let verifying_key = VerifyingKey::<NistP521>::from(q);
205 verifying_key.verify_prehash(&m, &signature).is_ok()
206 },
207 Err(_) => false,
208 }
209 },
210 _ => {
211 return Err(Error::NotSupported(Some(
212 "Algorithm's curve is not supported.".into(),
213 )));
214 },
215 };
216
217 Ok(result)
219}
220
221pub(crate) fn generate_key(
223 cx: &mut JSContext,
224 global: &GlobalScope,
225 normalized_algorithm: &SubtleEcKeyGenParams,
226 extractable: bool,
227 usages: Vec<KeyUsage>,
228) -> Result<CryptoKeyPair, Error> {
229 ec_common::generate_key(
230 EcAlgorithm::Ecdsa,
231 cx,
232 global,
233 normalized_algorithm,
234 extractable,
235 usages,
236 )
237}
238
239pub(crate) fn import_key(
241 cx: &mut JSContext,
242 global: &GlobalScope,
243 normalized_algorithm: &SubtleEcKeyImportParams,
244 format: KeyFormat,
245 key_data: &[u8],
246 extractable: bool,
247 usages: Vec<KeyUsage>,
248) -> Result<DomRoot<CryptoKey>, Error> {
249 ec_common::import_key(
250 EcAlgorithm::Ecdsa,
251 cx,
252 global,
253 normalized_algorithm,
254 format,
255 key_data,
256 extractable,
257 usages,
258 )
259}
260
261pub(crate) fn export_key(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
263 ec_common::export_key(format, key)
264}
265
266pub(crate) fn get_public_key(
269 cx: &mut JSContext,
270 global: &GlobalScope,
271 key: &CryptoKey,
272 algorithm: &KeyAlgorithmAndDerivatives,
273 usages: Vec<KeyUsage>,
274) -> Result<DomRoot<CryptoKey>, Error> {
275 ec_common::get_public_key(cx, global, key, algorithm, usages)
276}