script/dom/subtlecrypto/ecdsa_operation.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use digest::Digest;
6use ecdsa::signature::hazmat::{PrehashVerifier, RandomizedPrehashSigner};
7use ecdsa::{Signature, SigningKey, VerifyingKey};
8use elliptic_curve::SecretKey;
9use elliptic_curve::rand_core::OsRng;
10use elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint, ValidatePublicKey};
11use p256::NistP256;
12use p384::NistP384;
13use p521::NistP521;
14use pkcs8::der::Decode;
15use pkcs8::spki::EncodePublicKey;
16use pkcs8::{AssociatedOid, EncodePrivateKey, PrivateKeyInfo, SubjectPublicKeyInfo};
17use sec1::der::asn1::BitString;
18use sec1::{EcParameters, EcPrivateKey, EncodedPoint};
19use sha1::Sha1;
20use sha2::{Sha256, Sha384, Sha512};
21
22use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
23 CryptoKeyMethods, CryptoKeyPair, KeyType, KeyUsage,
24};
25use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{JsonWebKey, KeyFormat};
26use crate::dom::bindings::error::Error;
27use crate::dom::bindings::root::DomRoot;
28use crate::dom::bindings::str::DOMString;
29use crate::dom::cryptokey::{CryptoKey, Handle};
30use crate::dom::globalscope::GlobalScope;
31use crate::dom::subtlecrypto::{
32 ALG_ECDSA, ALG_SHA1, ALG_SHA256, ALG_SHA384, ALG_SHA512, ExportedKey, JsonWebKeyExt,
33 JwkStringField, KeyAlgorithmAndDerivatives, NAMED_CURVE_P256, NAMED_CURVE_P384,
34 NAMED_CURVE_P521, SUPPORTED_CURVES, SubtleEcKeyAlgorithm, SubtleEcKeyGenParams,
35 SubtleEcKeyImportParams, SubtleEcdsaParams,
36};
37use crate::script_runtime::CanGc;
38
39const P256_PREHASH_LENGTH: usize = 32;
40const P384_PREHASH_LENGTH: usize = 48;
41const P521_PREHASH_LENGTH: usize = 66;
42
43/// <https://w3c.github.io/webcrypto/#ecdsa-operations-sign>
44pub(crate) fn sign(
45 normalized_algorithm: &SubtleEcdsaParams,
46 key: &CryptoKey,
47 message: &[u8],
48) -> Result<Vec<u8>, Error> {
49 // Step 1. If the [[type]] internal slot of key is not "private", then throw an
50 // InvalidAccessError.
51 if key.Type() != KeyType::Private {
52 return Err(Error::InvalidAccess(None));
53 }
54
55 // Step 2. Let hashAlgorithm be the hash member of normalizedAlgorithm.
56 let hash_algorithm = &normalized_algorithm.hash;
57
58 // Step 3. Let M be the result of performing the digest operation specified by hashAlgorithm
59 // using message.
60 let m = match hash_algorithm.name() {
61 ALG_SHA1 => Sha1::new_with_prefix(message).finalize().to_vec(),
62 ALG_SHA256 => Sha256::new_with_prefix(message).finalize().to_vec(),
63 ALG_SHA384 => Sha384::new_with_prefix(message).finalize().to_vec(),
64 ALG_SHA512 => Sha512::new_with_prefix(message).finalize().to_vec(),
65 _ => return Err(Error::NotSupported(None)),
66 };
67
68 // Step 4. Let d be the ECDSA private key associated with key.
69 // Step 5. Let params be the EC domain parameters associated with key.
70 // Step 6.
71 // If the namedCurve attribute of the [[algorithm]] internal slot of key is "P-256", "P-384" or
72 // "P-521":
73 // 1. Perform the ECDSA signing process, as specified in [RFC6090], Section 5.4.2, with M
74 // as the message, using params as the EC domain parameters, and with d as the private
75 // key.
76 // 2. Let r and s be the pair of integers resulting from performing the ECDSA signing
77 // process.
78 // 3. Let result be an empty byte sequence.
79 // 4. Let n be the smallest integer such that n * 8 is greater than the logarithm to base 2
80 // of the order of the base point of the elliptic curve identified by params.
81 // 5. Convert r to a byte sequence of length n and append it to result.
82 // 6. Convert s to a byte sequence of length n and append it to result.
83 // Otherwise, the namedCurve attribute of the [[algorithm]] internal slot of key is a value
84 // specified in an applicable specification:
85 // Perform the ECDSA signature steps specified in that specification, passing in M, params
86 // and d and resulting in result.
87 // NOTE: We currently do not support other applicable specifications.
88 let KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm) = key.algorithm() else {
89 return Err(Error::Operation(None));
90 };
91 let result = match algorithm.named_curve.as_str() {
92 NAMED_CURVE_P256 => {
93 // P-256 expects prehash with length at least 32 bytes. If M is shorter than 32 bytes,
94 // expand it by left padding with zeros.
95 let m = expand_prehash(m, P256_PREHASH_LENGTH);
96
97 let Handle::P256PrivateKey(d) = key.handle() else {
98 return Err(Error::Operation(None));
99 };
100 let signing_key = SigningKey::<NistP256>::from(d);
101 let signature: Signature<NistP256> = signing_key
102 .sign_prehash_with_rng(&mut OsRng, m.as_slice())
103 .map_err(|_| Error::Operation(None))?;
104 signature.to_vec()
105 },
106 NAMED_CURVE_P384 => {
107 // P-384 expects prehash with length at least 48 bytes. If M is shorter than 48 bytes,
108 // expand it by left padding with zeros.
109 let m = expand_prehash(m, P384_PREHASH_LENGTH);
110
111 let Handle::P384PrivateKey(d) = key.handle() else {
112 return Err(Error::Operation(None));
113 };
114 let signing_key = SigningKey::<NistP384>::from(d);
115 let signature: Signature<NistP384> = signing_key
116 .sign_prehash_with_rng(&mut OsRng, m.as_slice())
117 .map_err(|_| Error::Abort(None))?;
118 signature.to_vec()
119 },
120 NAMED_CURVE_P521 => {
121 // P-521 expects prehash with length at least 66 bytes. If M is shorter than 66 bytes,
122 // expand it by left padding with zeros.
123 let m = expand_prehash(m, P521_PREHASH_LENGTH);
124
125 let Handle::P521PrivateKey(d) = key.handle() else {
126 return Err(Error::Operation(None));
127 };
128 let signing_key = p521::ecdsa::SigningKey::from_slice(d.to_bytes().as_slice())
129 .map_err(|_| Error::Operation(None))?;
130 let signature: Signature<NistP521> = signing_key
131 .sign_prehash_with_rng(&mut OsRng, m.as_slice())
132 .map_err(|_| Error::Operation(None))?;
133 signature.to_vec()
134 },
135 _ => return Err(Error::NotSupported(None)),
136 };
137
138 // Step 7. Return result.
139 Ok(result)
140}
141
142/// <https://w3c.github.io/webcrypto/#ecdsa-operations-verify>
143pub(crate) fn verify(
144 normalized_algorithm: &SubtleEcdsaParams,
145 key: &CryptoKey,
146 message: &[u8],
147 signature: &[u8],
148) -> Result<bool, Error> {
149 // Step 1. If the [[type]] internal slot of key is not "public", then throw an
150 // InvalidAccessError.
151 if key.Type() != KeyType::Public {
152 return Err(Error::InvalidAccess(None));
153 }
154
155 // Step 2. Let hashAlgorithm be the hash member of normalizedAlgorithm.
156 let hash_algorithm = &normalized_algorithm.hash;
157
158 // Step 3. Let M be the result of performing the digest operation specified by hashAlgorithm
159 // using message.
160 let m = match hash_algorithm.name() {
161 ALG_SHA1 => Sha1::new_with_prefix(message).finalize().to_vec(),
162 ALG_SHA256 => Sha256::new_with_prefix(message).finalize().to_vec(),
163 ALG_SHA384 => Sha384::new_with_prefix(message).finalize().to_vec(),
164 ALG_SHA512 => Sha512::new_with_prefix(message).finalize().to_vec(),
165 _ => return Err(Error::NotSupported(None)),
166 };
167
168 // Step 4. Let Q be the ECDSA public key associated with key.
169 // Step 5. Let params be the EC domain parameters associated with key.
170 // Step 6.
171 // If the namedCurve attribute of the [[algorithm]] internal slot of key is "P-256", "P-384" or
172 // "P-521":
173 // 1. Let n be the smallest integer such that n * 8 is greater than the logarithm to base 2
174 // of the order of the base point of the elliptic curve identified by params.
175 // 2. If signature does not have a length of n * 2 bytes, then return false.
176 // 3. Let r be the result of converting the first n bytes of signature to an integer.
177 // 4. Let s be the result of converting the last n bytes of signature to an integer.
178 // 5. Perform the ECDSA verifying process, as specified in [RFC6090], Section 5.4.3, with M
179 // as the received message, (r, s) as the signature and using params as the EC domain
180 // parameters, and Q as the public key.
181 // Otherwise, the namedCurve attribute of the [[algorithm]] internal slot of key is a value
182 // specified in an applicable specification:
183 // Perform the ECDSA verification steps specified in that specification passing in M,
184 // signature, params and Q and resulting in an indication of whether or not the purported
185 // signature is valid.
186 // Step 7. Let result be a boolean with the value true if the signature is valid and the value
187 // false otherwise.
188 // NOTE: We currently do not support other applicable specifications.
189 let KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm) = key.algorithm() else {
190 return Err(Error::Operation(None));
191 };
192 let result = match algorithm.named_curve.as_str() {
193 NAMED_CURVE_P256 => {
194 // P-256 expects prehash with length at least 32 bytes. If M is shorter than 32 bytes,
195 // expand it by left padding with zeros.
196 let m = expand_prehash(m, P256_PREHASH_LENGTH);
197
198 let Handle::P256PublicKey(q) = key.handle() else {
199 return Err(Error::Operation(None));
200 };
201 match Signature::<NistP256>::from_slice(signature) {
202 Ok(signature) => {
203 let verifying_key = VerifyingKey::<NistP256>::from(q);
204 verifying_key.verify_prehash(&m, &signature).is_ok()
205 },
206 Err(_) => false,
207 }
208 },
209 NAMED_CURVE_P384 => {
210 // P-384 expects prehash with length at least 48 bytes. If M is shorter than 48 bytes,
211 // expand it by left padding with zeros.
212 let m = expand_prehash(m, P384_PREHASH_LENGTH);
213
214 let Handle::P384PublicKey(q) = key.handle() else {
215 return Err(Error::Operation(None));
216 };
217 match Signature::<NistP384>::from_slice(signature) {
218 Ok(signature) => {
219 let verifying_key = VerifyingKey::<NistP384>::from(q);
220 verifying_key.verify_prehash(&m, &signature).is_ok()
221 },
222 Err(_) => false,
223 }
224 },
225 NAMED_CURVE_P521 => {
226 // P-521 expects prehash with length at least 66 bytes. If M is shorter than 66 bytes,
227 // expand it by left padding with zeros.
228 let m = expand_prehash(m, P521_PREHASH_LENGTH);
229
230 let Handle::P521PublicKey(q) = key.handle() else {
231 return Err(Error::Operation(None));
232 };
233 match (
234 Signature::<NistP521>::from_slice(signature),
235 p521::ecdsa::VerifyingKey::from_sec1_bytes(q.to_sec1_bytes().to_vec().as_slice()),
236 ) {
237 (Ok(signature), Ok(verifying_key)) => {
238 verifying_key.verify_prehash(&m, &signature).is_ok()
239 },
240 _ => false,
241 }
242 },
243 _ => return Err(Error::NotSupported(None)),
244 };
245
246 // Step 8. Return result.
247 Ok(result)
248}
249
250/// <https://w3c.github.io/webcrypto/#ecdsa-operations-generate-key>
251pub(crate) fn generate_key(
252 global: &GlobalScope,
253 normalized_algorithm: &SubtleEcKeyGenParams,
254 extractable: bool,
255 usages: Vec<KeyUsage>,
256 can_gc: CanGc,
257) -> Result<CryptoKeyPair, Error> {
258 // Step 1. If usages contains a value which is not one of "sign" or "verify", then throw a
259 // SyntaxError.
260 if usages
261 .iter()
262 .any(|usage| !matches!(usage, KeyUsage::Sign | KeyUsage::Verify))
263 {
264 return Err(Error::Syntax(None));
265 }
266
267 // Step 2.
268 // If the namedCurve member of normalizedAlgorithm is "P-256", "P-384" or "P-521":
269 // Generate an Elliptic Curve key pair, as defined in [RFC6090] with domain parameters for
270 // the curve identified by the namedCurve member of normalizedAlgorithm.
271 // If the namedCurve member of normalizedAlgorithm is a value specified in an applicable
272 // specification:
273 // Perform the ECDSA generation steps specified in that specification, passing in
274 // normalizedAlgorithm and resulting in an elliptic curve key pair.
275 // Otherwise:
276 // throw a NotSupportedError
277 // Step 3. If performing the key generation operation results in an error, then throw an
278 // OperationError.
279 // NOTE: We currently do not support other applicable specifications.
280 let (private_key_handle, public_key_handle) = match normalized_algorithm.named_curve.as_str() {
281 NAMED_CURVE_P256 => {
282 let private_key = SecretKey::<NistP256>::random(&mut OsRng);
283 let public_key = private_key.public_key();
284 (
285 Handle::P256PrivateKey(private_key),
286 Handle::P256PublicKey(public_key),
287 )
288 },
289 NAMED_CURVE_P384 => {
290 let private_key = SecretKey::<NistP384>::random(&mut OsRng);
291 let public_key = private_key.public_key();
292 (
293 Handle::P384PrivateKey(private_key),
294 Handle::P384PublicKey(public_key),
295 )
296 },
297 NAMED_CURVE_P521 => {
298 let private_key = SecretKey::<NistP521>::random(&mut OsRng);
299 let public_key = private_key.public_key();
300 (
301 Handle::P521PrivateKey(private_key),
302 Handle::P521PublicKey(public_key),
303 )
304 },
305 _ => return Err(Error::NotSupported(None)),
306 };
307
308 // Step 4. Let algorithm be a new EcKeyAlgorithm object.
309 // Step 5. Set the name attribute of algorithm to "ECDSA".
310 // Step 6. Set the namedCurve attribute of algorithm to equal the namedCurve member of
311 // normalizedAlgorithm.
312 let algorithm = SubtleEcKeyAlgorithm {
313 name: ALG_ECDSA.to_string(),
314 named_curve: normalized_algorithm.named_curve.clone(),
315 };
316
317 // Step 7. Let publicKey be a new CryptoKey representing the public key of the generated key pair.
318 // Step 8. Set the [[type]] internal slot of publicKey to "public"
319 // Step 9. Set the [[algorithm]] internal slot of publicKey to algorithm.
320 // Step 10. Set the [[extractable]] internal slot of publicKey to true.
321 // Step 11. Set the [[usages]] internal slot of publicKey to be the usage intersection of
322 // usages and [ "verify" ].
323 let public_key = CryptoKey::new(
324 global,
325 KeyType::Public,
326 true,
327 KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm.clone()),
328 usages
329 .iter()
330 .filter(|usage| **usage == KeyUsage::Verify)
331 .cloned()
332 .collect(),
333 public_key_handle,
334 can_gc,
335 );
336
337 // Step 12. Let privateKey be a new CryptoKey representing the private key of the generated key pair.
338 // Step 13. Set the [[type]] internal slot of privateKey to "private"
339 // Step 14. Set the [[algorithm]] internal slot of privateKey to algorithm.
340 // Step 15. Set the [[extractable]] internal slot of privateKey to extractable.
341 // Step 16. Set the [[usages]] internal slot of privateKey to be the usage intersection of
342 // usages and [ "sign" ].
343 let private_key = CryptoKey::new(
344 global,
345 KeyType::Private,
346 extractable,
347 KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm),
348 usages
349 .iter()
350 .filter(|usage| **usage == KeyUsage::Sign)
351 .cloned()
352 .collect(),
353 private_key_handle,
354 can_gc,
355 );
356
357 // Step 17. Let result be a new CryptoKeyPair dictionary.
358 // Step 18. Set the publicKey attribute of result to be publicKey.
359 // Step 19. Set the privateKey attribute of result to be privateKey.
360 let result = CryptoKeyPair {
361 publicKey: Some(public_key),
362 privateKey: Some(private_key),
363 };
364
365 // Step 20. Return result.
366 Ok(result)
367}
368
369/// <https://w3c.github.io/webcrypto/#ecdsa-operations-import-key>
370pub(crate) fn import_key(
371 global: &GlobalScope,
372 normalized_algorithm: &SubtleEcKeyImportParams,
373 format: KeyFormat,
374 key_data: &[u8],
375 extractable: bool,
376 usages: Vec<KeyUsage>,
377 can_gc: CanGc,
378) -> Result<DomRoot<CryptoKey>, Error> {
379 // Step 1. Let keyData be the key data to be imported.
380
381 // Step 2.
382 let key = match format {
383 // If format is "spki":
384 KeyFormat::Spki => {
385 // Step 2.1. If usages contains a value which is not "verify" then throw a SyntaxError.
386 if usages.iter().any(|usage| *usage != KeyUsage::Verify) {
387 return Err(Error::Syntax(None));
388 }
389
390 // Step 2.2. Let spki be the result of running the parse a subjectPublicKeyInfo
391 // algorithm over keyData
392 // Step 2.3. If an error occurred while parsing, then throw a DataError.
393 let spki = SubjectPublicKeyInfo::<_, BitString>::from_der(key_data)
394 .map_err(|_| Error::Data(None))?;
395
396 // Step 2.4. If the algorithm object identifier field of the algorithm
397 // AlgorithmIdentifier field of spki is not equal to the id-ecPublicKey object
398 // identifier defined in [RFC5480], then throw a DataError.
399 if spki.algorithm.oid != elliptic_curve::ALGORITHM_OID {
400 return Err(Error::Data(None));
401 }
402
403 // Step 2.5. If the parameters field of the algorithm AlgorithmIdentifier field of spki
404 // is absent, then throw a DataError.
405 // Step 2.6. Let params be the parameters field of the algorithm AlgorithmIdentifier
406 // field of spki.
407 // Step 2.7. If params is not an instance of the ECParameters ASN.1 type defined in
408 // [RFC5480] that specifies a namedCurve, then throw a DataError.
409 let Some(params): Option<EcParameters> = spki.algorithm.parameters else {
410 return Err(Error::Data(None));
411 };
412
413 // Step 2.8. Let namedCurve be a string whose initial value is undefined.
414 // Step 2.9.
415 // If params is equivalent to the secp256r1 object identifier defined in [RFC5480]:
416 // Set namedCurve "P-256".
417 // If params is equivalent to the secp384r1 object identifier defined in [RFC5480]:
418 // Set namedCurve "P-384".
419 // If params is equivalent to the secp521r1 object identifier defined in [RFC5480]:
420 // Set namedCurve "P-521".
421 let named_curve = match params {
422 EcParameters::NamedCurve(NistP256::OID) => Some(NAMED_CURVE_P256),
423 EcParameters::NamedCurve(NistP384::OID) => Some(NAMED_CURVE_P384),
424 EcParameters::NamedCurve(NistP521::OID) => Some(NAMED_CURVE_P521),
425 _ => None,
426 };
427
428 // Step 2.10.
429 let handle = match named_curve {
430 // If namedCurve is not undefined:
431 Some(curve) => {
432 // Step 2.10.1. Let publicKey be the Elliptic Curve public key identified by
433 // performing the conversion steps defined in Section 2.3.4 of [SEC1] using the
434 // subjectPublicKey field of spki.
435 // Step 2.10.2. The uncompressed point format MUST be supported.
436 // Step 2.10.3. If the implementation does not support the compressed point
437 // format and a compressed point is provided, throw a DataError.
438 // Step 2.10.4. If a decode error occurs or an identity point is found, throw a
439 // DataError.
440 let sec1_bytes = spki
441 .subject_public_key
442 .as_bytes()
443 .ok_or(Error::Data(None))?;
444 match curve {
445 NAMED_CURVE_P256 => {
446 let public_key = p256::PublicKey::from_sec1_bytes(sec1_bytes)
447 .map_err(|_| Error::Data(None))?;
448 Handle::P256PublicKey(public_key)
449 },
450 NAMED_CURVE_P384 => {
451 let public_key = p384::PublicKey::from_sec1_bytes(sec1_bytes)
452 .map_err(|_| Error::Data(None))?;
453 Handle::P384PublicKey(public_key)
454 },
455 NAMED_CURVE_P521 => {
456 let public_key = p521::PublicKey::from_sec1_bytes(sec1_bytes)
457 .map_err(|_| Error::Data(None))?;
458 Handle::P521PublicKey(public_key)
459 },
460 _ => unreachable!(),
461 }
462
463 // Step 2.10.5. Let key be a new CryptoKey that represents publicKey.
464 // NOTE: CryptoKey is created in Step 2.13 - 2.17.
465 },
466 // Otherwise:
467 None => {
468 // Step 2.10.1. Perform any key import steps defined by other applicable
469 // specifications, passing format, spki and obtaining namedCurve and key.
470 // Step 2.10.2. If an error occurred or there are no applicable specifications,
471 // throw a DataError.
472 // NOTE: We currently do not support other applicable specifications.
473 return Err(Error::Data(None));
474 },
475 };
476
477 // Step 2.11. If namedCurve is defined, and not equal to the namedCurve member of
478 // normalizedAlgorithm, throw a DataError.
479 if named_curve.is_some_and(|curve| curve != normalized_algorithm.named_curve) {
480 return Err(Error::Data(None));
481 }
482
483 // Step 2.12. If the key value is not a valid point on the Elliptic Curve identified by
484 // the namedCurve member of normalizedAlgorithm throw a DataError.
485 // NOTE: Done in Step 2.10.
486
487 // Step 2.13. Set the [[type]] internal slot of key to "public"
488 // Step 2.14. Let algorithm be a new EcKeyAlgorithm.
489 // Step 2.15. Set the name attribute of algorithm to "ECDSA".
490 // Step 2.16. Set the namedCurve attribute of algorithm to namedCurve.
491 // Step 2.17. Set the [[algorithm]] internal slot of key to algorithm.
492 let algorithm = SubtleEcKeyAlgorithm {
493 name: ALG_ECDSA.to_string(),
494 named_curve: named_curve
495 .expect("named_curve must exist here")
496 .to_string(),
497 };
498 CryptoKey::new(
499 global,
500 KeyType::Public,
501 extractable,
502 KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm),
503 usages,
504 handle,
505 can_gc,
506 )
507 },
508 // If format is "pkcs8":
509 KeyFormat::Pkcs8 => {
510 // Step 2.1. If usages contains a value which is not "sign" then throw a SyntaxError.
511 if usages.iter().any(|usage| *usage != KeyUsage::Sign) {
512 return Err(Error::Syntax(None));
513 }
514
515 // Step 2.2. Let privateKeyInfo be the result of running the parse a privateKeyInfo
516 // algorithm over keyData.
517 // Step 2.3. If an error occurs while parsing, throw a DataError.
518 let private_key_info =
519 PrivateKeyInfo::from_der(key_data).map_err(|_| Error::Data(None))?;
520
521 // Step 2.4. If the algorithm object identifier field of the privateKeyAlgorithm
522 // PrivateKeyAlgorithm field of privateKeyInfo is not equal to the id-ecPublicKey
523 // object identifier defined in [RFC5480], throw a DataError.
524 if private_key_info.algorithm.oid != elliptic_curve::ALGORITHM_OID {
525 return Err(Error::Data(None));
526 }
527
528 // Step 2.5. If the parameters field of the privateKeyAlgorithm
529 // PrivateKeyAlgorithmIdentifier field of privateKeyInfo is not present, then throw a
530 // DataError.
531 // Step 2.6. Let params be the parameters field of the privateKeyAlgorithm
532 // PrivateKeyAlgorithmIdentifier field of privateKeyInfo.
533 // Step 2.7. If params is not an instance of the ECParameters ASN.1 type defined in
534 // [RFC5480] that specifies a namedCurve, then throw a DataError.
535 let params: EcParameters = if let Some(params) = private_key_info.algorithm.parameters {
536 params.decode_as().map_err(|_| Error::Data(None))?
537 } else {
538 return Err(Error::Data(None));
539 };
540
541 // Step 2.8. Let namedCurve be a string whose initial value is undefined.
542 // Step 2.9.
543 // If params is equivalent to the secp256r1 object identifier defined in [RFC5480]:
544 // Set namedCurve to "P-256".
545 // If params is equivalent to the secp384r1 object identifier defined in [RFC5480]:
546 // Set namedCurve to "P-384".
547 // If params is equivalent to the secp521r1 object identifier defined in [RFC5480]:
548 // Set namedCurve to "P-521".
549 let named_curve = match params {
550 EcParameters::NamedCurve(NistP256::OID) => Some(NAMED_CURVE_P256),
551 EcParameters::NamedCurve(NistP384::OID) => Some(NAMED_CURVE_P384),
552 EcParameters::NamedCurve(NistP521::OID) => Some(NAMED_CURVE_P521),
553 _ => None,
554 };
555
556 // Step 2.10.
557 let handle = match named_curve {
558 // If namedCurve is not undefined:
559 Some(curve) => {
560 // Step 2.10.1. Let ecPrivateKey be the result of performing the parse an ASN.1
561 // structure algorithm, with data as the privateKey field of privateKeyInfo,
562 // structure as the ASN.1 ECPrivateKey structure specified in Section 3 of
563 // [RFC5915], and exactData set to true.
564 // Step 2.10.2. If an error occurred while parsing, then throw a DataError.
565 let ec_private_key = EcPrivateKey::try_from(private_key_info.private_key)
566 .map_err(|_| Error::Data(None))?;
567
568 // Step 2.10.3. If the parameters field of ecPrivateKey is present, and is not
569 // an instance of the namedCurve ASN.1 type defined in [RFC5480], or does not
570 // contain the same object identifier as the parameters field of the
571 // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier field of privateKeyInfo,
572 // then throw a DataError.
573 if ec_private_key
574 .parameters
575 .is_some_and(|parameters| parameters != params)
576 {
577 return Err(Error::Data(None));
578 }
579
580 // Step 2.10.4. Let key be a new CryptoKey that represents the Elliptic Curve
581 // private key identified by performing the conversion steps defined in Section
582 // 3 of [RFC5915] using ecPrivateKey.
583 // NOTE: CryptoKey is created in Step 2.13 - 2.17.
584 match curve {
585 NAMED_CURVE_P256 => {
586 let private_key = p256::SecretKey::try_from(ec_private_key)
587 .map_err(|_| Error::Data(None))?;
588 Handle::P256PrivateKey(private_key)
589 },
590 NAMED_CURVE_P384 => {
591 let private_key = p384::SecretKey::try_from(ec_private_key)
592 .map_err(|_| Error::Data(None))?;
593 Handle::P384PrivateKey(private_key)
594 },
595 NAMED_CURVE_P521 => {
596 let private_key = p521::SecretKey::try_from(ec_private_key)
597 .map_err(|_| Error::Data(None))?;
598 Handle::P521PrivateKey(private_key)
599 },
600 _ => unreachable!(),
601 }
602 },
603 // Otherwise:
604 None => {
605 // Step 2.10.1. Perform any key import steps defined by other applicable
606 // specifications, passing format, privateKeyInfo and obtaining namedCurve and
607 // key.
608 // Step 2.10.2. If an error occurred or there are no applicable specifications,
609 // throw a DataError.
610 // NOTE: We currently do not support other applicable specifications.
611 return Err(Error::Data(None));
612 },
613 };
614
615 // Step 2.11. If namedCurve is defined, and not equal to the namedCurve member of
616 // normalizedAlgorithm, throw a DataError.
617 if named_curve.is_some_and(|curve| curve != normalized_algorithm.named_curve) {
618 return Err(Error::Data(None));
619 }
620
621 // Step 2.12. If the private key value is not a valid point on the Elliptic Curve
622 // identified by the namedCurve member of normalizedAlgorithm throw a DataError.
623 // NOTE: Done in Step 2.10.
624
625 // Step 2.13. Set the [[type]] internal slot of key to "private"
626 // Step 2.14. Let algorithm be a new EcKeyAlgorithm.
627 // Step 2.15. Set the name attribute of algorithm to "ECDSA".
628 // Step 2.16. Set the namedCurve attribute of algorithm to namedCurve.
629 // Step 2.17. Set the [[algorithm]] internal slot of key to algorithm.
630 let algorithm = SubtleEcKeyAlgorithm {
631 name: ALG_ECDSA.to_string(),
632 named_curve: named_curve
633 .expect("named_curve must exist here")
634 .to_string(),
635 };
636 CryptoKey::new(
637 global,
638 KeyType::Private,
639 extractable,
640 KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm),
641 usages,
642 handle,
643 can_gc,
644 )
645 },
646 // If format is "jwk":
647 KeyFormat::Jwk => {
648 // Step 2.1.
649 // If keyData is a JsonWebKey dictionary:
650 // Let jwk equal keyData.
651 // Otherwise:
652 // Throw a DataError.
653 let jwk = JsonWebKey::parse(GlobalScope::get_cx(), key_data)?;
654
655 // Step 2.2. If the d field is present and usages contains a value which is not "sign",
656 // or, if the d field is not present and usages contains a value which is not "verify"
657 // then throw a SyntaxError.
658 if (jwk.d.is_some() && usages.iter().any(|usage| *usage != KeyUsage::Sign)) ||
659 (jwk.d.is_none() && usages.iter().any(|usage| *usage != KeyUsage::Verify))
660 {
661 return Err(Error::Syntax(None));
662 }
663
664 // Step 2.3. If the kty field of jwk is not "EC", then throw a DataError.
665 if jwk.kty.as_ref().is_none_or(|kty| kty != "EC") {
666 return Err(Error::Data(None));
667 }
668
669 // Step 2.4. If usages is non-empty and the use field of jwk is present and is not
670 // "sig", then throw a DataError.
671 if !usages.is_empty() && jwk.use_.as_ref().is_some_and(|use_| use_ != "sig") {
672 return Err(Error::Data(None));
673 }
674
675 // Step 2.5. If the key_ops field of jwk is present, and is invalid according to the
676 // requirements of JSON Web Key [JWK], or it does not contain all of the specified
677 // usages values, then throw a DataError.
678 jwk.check_key_ops(&usages)?;
679
680 // Step 2.6. If the ext field of jwk is present and has the value false and extractable
681 // is true, then throw a DataError.
682 if jwk.ext.is_some_and(|ext| !ext) && extractable {
683 return Err(Error::Data(None));
684 }
685
686 // Step 2.7. Let namedCurve be a string whose value is equal to the crv field of jwk.
687 // Step 2.8. If namedCurve is not equal to the namedCurve member of
688 // normalizedAlgorithm, throw a DataError.
689 let named_curve = jwk
690 .crv
691 .as_ref()
692 .filter(|crv| **crv == normalized_algorithm.named_curve)
693 .map(|crv| crv.to_string())
694 .ok_or(Error::Data(None))?;
695
696 // Step 2.9.
697 let (handle, key_type) =
698 // If namedCurve is "P-256", "P-384" or "P-521":
699 if matches!(
700 named_curve.as_str(),
701 NAMED_CURVE_P256 | NAMED_CURVE_P384 | NAMED_CURVE_P521
702 ) {
703 // Step 2.9.1. Let algNamedCurve be a string whose initial value is undefined.
704 // Step 2.9.2.
705 // If the alg field is not present:
706 // Let algNamedCurve be undefined.
707 // If the alg field is equal to the string "ES256":
708 // Let algNamedCurve be the string "P-256".
709 // If the alg field is equal to the string "ES384":
710 // Let algNamedCurve be the string "P-384".
711 // If the alg field is equal to the string "ES512":
712 // Let algNamedCurve be the string "P-521".
713 // otherwise:
714 // throw a DataError.
715 let alg = jwk.alg.as_ref().map(|alg| alg.to_string());
716 let alg_named_curve = match alg.as_deref() {
717 None => None,
718 Some("ES256") => Some(NAMED_CURVE_P256),
719 Some("ES384") => Some(NAMED_CURVE_P384),
720 Some("ES521") => Some(NAMED_CURVE_P521),
721 _ => return Err(Error::Data(None)),
722 };
723
724 // Step 2.9.3. If algNamedCurve is defined, and is not equal to namedCurve,
725 // throw a DataError.
726 if alg_named_curve.is_some_and(|alg_named_curve| alg_named_curve != named_curve) {
727 return Err(Error::Data(None));
728 }
729
730 // Step 2.9.4.
731 // If the d field is present:
732 if jwk.d.is_some() {
733 // Step 2.9.4.1. If jwk does not meet the requirements of Section 6.2.2 of
734 // JSON Web Algorithms [JWA], then throw a DataError.
735 let x = jwk.decode_required_string_field(JwkStringField::X)?;
736 let y = jwk.decode_required_string_field(JwkStringField::Y)?;
737 let d = jwk.decode_required_string_field(JwkStringField::D)?;
738
739 // Step 2.9.4.2. Let key be a new CryptoKey object that represents the
740 // Elliptic Curve private key identified by interpreting jwk according to
741 // Section 6.2.2 of JSON Web Algorithms [JWA].
742 // NOTE: CryptoKey is created in Step 2.11 - 2.14.
743 let handle = match named_curve.as_str() {
744 NAMED_CURVE_P256 => {
745 let private_key =
746 p256::SecretKey::from_slice(&d).map_err(|_| Error::Data(None))?;
747 let mut sec1_bytes = vec![4u8];
748 sec1_bytes.extend_from_slice(&x);
749 sec1_bytes.extend_from_slice(&y);
750 let encoded_point = EncodedPoint::from_bytes(&sec1_bytes)
751 .map_err(|_| Error::Data(None))?;
752 NistP256::validate_public_key(&private_key, &encoded_point)
753 .map_err(|_| Error::Data(None))?;
754 Handle::P256PrivateKey(private_key)
755 },
756 NAMED_CURVE_P384 => {
757 let private_key =
758 p384::SecretKey::from_slice(&d).map_err(|_| Error::Data(None))?;
759 let mut sec1_bytes = vec![4u8];
760 sec1_bytes.extend_from_slice(&x);
761 sec1_bytes.extend_from_slice(&y);
762 let encoded_point = EncodedPoint::from_bytes(&sec1_bytes)
763 .map_err(|_| Error::Data(None))?;
764 NistP384::validate_public_key(&private_key, &encoded_point)
765 .map_err(|_| Error::Data(None))?;
766 Handle::P384PrivateKey(private_key)
767 },
768 NAMED_CURVE_P521 => {
769 let private_key =
770 p521::SecretKey::from_slice(&d).map_err(|_| Error::Data(None))?;
771 let mut sec1_bytes = vec![4u8];
772 sec1_bytes.extend_from_slice(&x);
773 sec1_bytes.extend_from_slice(&y);
774 let encoded_point = EncodedPoint::from_bytes(&sec1_bytes)
775 .map_err(|_| Error::Data(None))?;
776 NistP521::validate_public_key(&private_key, &encoded_point)
777 .map_err(|_| Error::Data(None))?;
778 Handle::P521PrivateKey(private_key)
779 },
780 _ => unreachable!(),
781 };
782
783 // Step 2.9.4.3. Set the [[type]] internal slot of Key to "private".
784 // NOTE: CryptoKey is created in Step 2.11 - 2.14.
785 let key_type = KeyType::Private;
786
787 (handle, key_type)
788 }
789 // Otherwise:
790 else {
791 // Step 2.9.4.1. If jwk does not meet the requirements of Section 6.2.1 of
792 // JSON Web Algorithms [JWA], then throw a DataError.
793 let x = jwk.decode_required_string_field(JwkStringField::X)?;
794 let y = jwk.decode_required_string_field(JwkStringField::Y)?;
795
796 // Step 2.9.4.2. Let key be a new CryptoKey object that represents the
797 // Elliptic Curve public key identified by interpreting jwk according to
798 // Section 6.2.1 of JSON Web Algorithms [JWA].
799 // NOTE: CryptoKey is created in Step 2.11 - 2.14.
800 let handle = match named_curve.as_str() {
801 NAMED_CURVE_P256 => {
802 let mut sec1_bytes = vec![4u8];
803 sec1_bytes.extend_from_slice(&x);
804 sec1_bytes.extend_from_slice(&y);
805 let encoded_point = EncodedPoint::from_bytes(&sec1_bytes)
806 .map_err(|_| Error::Data(None))?;
807 let public_key =
808 p256::PublicKey::from_encoded_point(&encoded_point)
809 .into_option()
810 .ok_or(Error::Data(None))?;
811 Handle::P256PublicKey(public_key)
812 },
813 NAMED_CURVE_P384 => {
814 let mut sec1_bytes = vec![4u8];
815 sec1_bytes.extend_from_slice(&x);
816 sec1_bytes.extend_from_slice(&y);
817 let encoded_point = EncodedPoint::from_bytes(&sec1_bytes)
818 .map_err(|_| Error::Data(None))?;
819 let public_key =
820 p384::PublicKey::from_encoded_point(&encoded_point)
821 .into_option()
822 .ok_or(Error::Data(None))?;
823 Handle::P384PublicKey(public_key)
824 },
825 NAMED_CURVE_P521 => {
826 let mut sec1_bytes = vec![4u8];
827 sec1_bytes.extend_from_slice(&x);
828 sec1_bytes.extend_from_slice(&y);
829 let encoded_point = EncodedPoint::from_bytes(&sec1_bytes)
830 .map_err(|_| Error::Data(None))?;
831 let public_key =
832 p521::PublicKey::from_encoded_point(&encoded_point)
833 .into_option()
834 .ok_or(Error::Data(None))?;
835 Handle::P521PublicKey(public_key)
836 },
837 _ => unreachable!(),
838 };
839
840 // Step 2.9.4.3. Set the [[type]] internal slot of Key to "public".
841 // NOTE: CryptoKey is created in Step 2.11 - 2.14.
842 let key_type = KeyType::Public;
843
844 (handle, key_type)
845 }
846 }
847 // Otherwise
848 else {
849 // Step 2.9.1. Perform any key import steps defined by other applicable
850 // specifications, passing format, jwk and obtaining key.
851 // Step 2.9.2. If an error occurred or there are no applicable specifications,
852 // throw a DataError.
853 // NOTE: We currently do not support other applicable specifications.
854 return Err(Error::Data(None));
855 };
856
857 // Step 2.10. If the key value is not a valid point on the Elliptic Curve identified by
858 // the namedCurve member of normalizedAlgorithm throw a DataError.
859 // NOTE: Done in Step 2.9.
860
861 // Step 2.11. Let algorithm be a new instance of an EcKeyAlgorithm object.
862 // Step 2.12. Set the name attribute of algorithm to "ECDSA".
863 // Step 2.13. Set the namedCurve attribute of algorithm to namedCurve.
864 // Step 2.14. Set the [[algorithm]] internal slot of key to algorithm.
865 let algorithm = SubtleEcKeyAlgorithm {
866 name: ALG_ECDSA.to_string(),
867 named_curve,
868 };
869 CryptoKey::new(
870 global,
871 key_type,
872 extractable,
873 KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm),
874 usages,
875 handle,
876 can_gc,
877 )
878 },
879 // If format is "raw":
880 KeyFormat::Raw | KeyFormat::Raw_public => {
881 // Step 2.1. If the namedCurve member of normalizedAlgorithm is not a named curve, then
882 // throw a DataError.
883 if !SUPPORTED_CURVES
884 .iter()
885 .any(|&supported_curve| supported_curve == normalized_algorithm.named_curve)
886 {
887 return Err(Error::Data(None));
888 }
889
890 // Step 2.2. If usages contains a value which is not "verify" then throw a SyntaxError.
891 if usages.iter().any(|usage| *usage != KeyUsage::Verify) {
892 return Err(Error::Syntax(None));
893 }
894
895 // Step 2.3.
896 // If namedCurve is "P-256", "P-384" or "P-521":
897 let handle = if matches!(
898 normalized_algorithm.named_curve.as_str(),
899 NAMED_CURVE_P256 | NAMED_CURVE_P384 | NAMED_CURVE_P521
900 ) {
901 // Step 2.3.1. Let Q be the elliptic curve point on the curve identified by the
902 // namedCurve member of normalizedAlgorithm identified by performing the conversion
903 // steps defined in Section 2.3.4 of [SEC1] on keyData.
904 // Step 2.3.2. The uncompressed point format MUST be supported.
905 // Step 2.3.3. If the implementation does not support the compressed point format
906 // and a compressed point is provided, throw a DataError.
907 // Step 2.3.4. If a decode error occurs or an identity point is found, throw a
908 // DataError.
909 match normalized_algorithm.named_curve.as_str() {
910 NAMED_CURVE_P256 => {
911 let q = p256::PublicKey::from_sec1_bytes(key_data)
912 .map_err(|_| Error::Data(None))?;
913 Handle::P256PublicKey(q)
914 },
915 NAMED_CURVE_P384 => {
916 let q = p384::PublicKey::from_sec1_bytes(key_data)
917 .map_err(|_| Error::Data(None))?;
918 Handle::P384PublicKey(q)
919 },
920 NAMED_CURVE_P521 => {
921 let q = p521::PublicKey::from_sec1_bytes(key_data)
922 .map_err(|_| Error::Data(None))?;
923 Handle::P521PublicKey(q)
924 },
925 _ => unreachable!(),
926 }
927
928 // Step 2.3.5. Let key be a new CryptoKey that represents Q.
929 // NOTE: CryptoKey is created in Step 2.7 - 2.8.
930 }
931 // Otherwise:
932 else {
933 // Step. 2.3.1. Perform any key import steps defined by other applicable
934 // specifications, passing format, keyData and obtaining key.
935 // Step. 2.3.2. If an error occurred or there are no applicable specifications,
936 // throw a DataError.
937 // NOTE: We currently do not support other applicable specifications.
938 return Err(Error::Data(None));
939 };
940
941 // Step 2.4. Let algorithm be a new EcKeyAlgorithm object.
942 // Step 2.5. Set the name attribute of algorithm to "ECDSA".
943 // Step 2.6. Set the namedCurve attribute of algorithm to equal the namedCurve member
944 // of normalizedAlgorithm.
945 let algorithm = SubtleEcKeyAlgorithm {
946 name: ALG_ECDSA.to_string(),
947 named_curve: normalized_algorithm.named_curve.clone(),
948 };
949
950 // Step 2.7. Set the [[type]] internal slot of key to "public"
951 // Step 2.8. Set the [[algorithm]] internal slot of key to algorithm.
952 CryptoKey::new(
953 global,
954 KeyType::Public,
955 extractable,
956 KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm),
957 usages,
958 handle,
959 can_gc,
960 )
961 },
962 // Otherwise:
963 _ => {
964 // throw a NotSupportedError.
965 return Err(Error::NotSupported(None));
966 },
967 };
968
969 // Step 3. Return key.
970 Ok(key)
971}
972
973/// <https://w3c.github.io/webcrypto/#ecdsa-operations-export-key>
974pub(crate) fn export_key(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
975 // Step 1. Let key be the CryptoKey to be exported.
976
977 // Step 2. If the underlying cryptographic key material represented by the [[handle]] internal
978 // slot of key cannot be accessed, then throw an OperationError.
979 // NOTE: Done in Step 3.
980
981 // Step 3.
982 let result = match format {
983 // If format is "spki":
984 KeyFormat::Spki => {
985 // Step 3.1. If the [[type]] internal slot of key is not "public", then throw an
986 // InvalidAccessError.
987 if key.Type() != KeyType::Public {
988 return Err(Error::InvalidAccess(None));
989 }
990
991 // Step 3.2.
992 // Let data be an instance of the SubjectPublicKeyInfo ASN.1 structure defined in
993 // [RFC5280] with the following properties:
994 // * Set the algorithm field to an AlgorithmIdentifier ASN.1 type with the
995 // following properties:
996 // * Set the algorithm field to the OID id-ecPublicKey defined in [RFC5480].
997 // * Set the parameters field to an instance of the ECParameters ASN.1 type
998 // defined in [RFC5480] as follows:
999 // If the namedCurve attribute of the [[algorithm]] internal slot of key is
1000 // "P-256", "P-384" or "P-521":
1001 // Let keyData be the byte sequence that represents the Elliptic Curve
1002 // public key represented by the [[handle]] internal slot of key
1003 // according to the encoding rules specified in Section 2.2 of
1004 // [RFC5480] and using the uncompressed form. and keyData.
1005 // If the namedCurve attribute of the [[algorithm]] internal slot
1006 // of key is "P-256":
1007 // Set parameters to the namedCurve choice with value equal to
1008 // the object identifier secp256r1 defined in [RFC5480]
1009 // If the namedCurve attribute of the [[algorithm]] internal slot
1010 // of key is "P-384":
1011 // Set parameters to the namedCurve choice with value equal to
1012 // the object identifier secp384r1 defined in [RFC5480]
1013 // If the namedCurve attribute of the [[algorithm]] internal slot
1014 // of key is "P-521":
1015 // Set parameters to the namedCurve choice with value equal to
1016 // the object identifier secp521r1 defined in [RFC5480]
1017 // Otherwise:
1018 // 1. Perform any key export steps defined by other applicable
1019 // specifications, passing format and the namedCurve attribute of
1020 // the [[algorithm]] internal slot of key and obtaining
1021 // namedCurveOid and keyData.
1022 // 2. Set parameters to the namedCurve choice with value equal to the
1023 // object identifier namedCurveOid.
1024 // * Set the subjectPublicKey field to keyData.
1025 // NOTE: We currently do not support other applicable specifications.
1026 let data = match key.handle() {
1027 Handle::P256PublicKey(public_key) => public_key.to_public_key_der(),
1028 Handle::P384PublicKey(public_key) => public_key.to_public_key_der(),
1029 Handle::P521PublicKey(public_key) => public_key.to_public_key_der(),
1030 _ => return Err(Error::Operation(None)),
1031 }
1032 .map_err(|_| Error::Operation(None))?;
1033
1034 // Step 3.3. Let result be the result of DER-encoding data.
1035 ExportedKey::Bytes(data.to_vec())
1036 },
1037 // If format is "pkcs8":
1038 KeyFormat::Pkcs8 => {
1039 // Step 3.1. If the [[type]] internal slot of key is not "private", then throw an
1040 // InvalidAccessError.
1041 if key.Type() != KeyType::Private {
1042 return Err(Error::InvalidAccess(None));
1043 }
1044
1045 // Step 3.2.
1046 // Let data be an instance of the PrivateKeyInfo ASN.1 structure defined in [RFC5208]
1047 // with the following properties:
1048 // * Set the version field to 0.
1049 // * Set the privateKeyAlgorithm field to a PrivateKeyAlgorithmIdentifier ASN.1
1050 // type with the following properties:
1051 // * Set the algorithm field to the OID id-ecPublicKey defined in [RFC5480].
1052 // * Set the parameters field to an instance of the ECParameters ASN.1 type
1053 // defined in [RFC5480] as follows:
1054 // If the namedCurve attribute of the [[algorithm]] internal slot of key is
1055 // "P-256", "P-384" or "P-521":
1056 // Let keyData be the result of DER-encoding an instance of the
1057 // ECPrivateKey structure defined in Section 3 of [RFC5915] for the
1058 // Elliptic Curve private key represented by the [[handle]] internal
1059 // slot of key and that conforms to the following:
1060 // * The parameters field is present, and is equivalent to the
1061 // parameters field of the privateKeyAlgorithm field of this
1062 // PrivateKeyInfo ASN.1 structure.
1063 // * The publicKey field is present and represents the Elliptic
1064 // Curve public key associated with the Elliptic Curve private key
1065 // represented by the [[handle]] internal slot of key.
1066 // * If the namedCurve attribute of the [[algorithm]] internal slot
1067 // of key is "P-256":
1068 // Set parameters to the namedCurve choice with value equal to
1069 // the object identifier secp256r1 defined in [RFC5480]
1070 // * If the namedCurve attribute of the [[algorithm]] internal slot
1071 // of key is "P-384":
1072 // Set parameters to the namedCurve choice with value equal to
1073 // the object identifier secp384r1 defined in [RFC5480]
1074 // * If the namedCurve attribute of the [[algorithm]] internal slot
1075 // of key is "P-521":
1076 // Set parameters to the namedCurve choice with value equal to
1077 // the object identifier secp521r1 defined in [RFC5480]
1078 // Otherwise:
1079 // 1. Perform any key export steps defined by other applicable
1080 // specifications, passing format and the namedCurve attribute of
1081 // the [[algorithm]] internal slot of key and obtaining
1082 // namedCurveOid and keyData.
1083 // 2. Set parameters to the namedCurve choice with value equal to the
1084 // object identifier namedCurveOid.
1085 // * Set the privateKey field to keyData.
1086 // NOTE: We currently do not support other applicable specifications.
1087 let data = match key.handle() {
1088 Handle::P256PrivateKey(private_key) => private_key.to_pkcs8_der(),
1089 Handle::P384PrivateKey(private_key) => private_key.to_pkcs8_der(),
1090 Handle::P521PrivateKey(private_key) => private_key.to_pkcs8_der(),
1091 _ => return Err(Error::Operation(None)),
1092 }
1093 .map_err(|_| Error::Operation(None))?;
1094
1095 // Step 3.3. Let result be the result of DER-encoding data.
1096 ExportedKey::Bytes(data.as_bytes().to_vec())
1097 },
1098 // If format is "jwk":
1099 KeyFormat::Jwk => {
1100 // Step 3.1. Let jwk be a new JsonWebKey dictionary.
1101 // Step 3.2. Set the kty attribute of jwk to "EC".
1102 let mut jwk = JsonWebKey {
1103 kty: Some(DOMString::from("EC")),
1104 ..Default::default()
1105 };
1106
1107 // Step 3.3.
1108 let KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm) = key.algorithm() else {
1109 return Err(Error::Operation(None));
1110 };
1111 // If the namedCurve attribute of the [[algorithm]] internal slot of key is "P-256",
1112 // "P-384" or "P-521":
1113 if matches!(
1114 algorithm.named_curve.as_str(),
1115 NAMED_CURVE_P256 | NAMED_CURVE_P384 | NAMED_CURVE_P521
1116 ) {
1117 // Step 3.3.1.
1118 // If the namedCurve attribute of the [[algorithm]] internal slot of key is
1119 // "P-256":
1120 // Set the crv attribute of jwk to "P-256"
1121 // If the namedCurve attribute of the [[algorithm]] internal slot of key is
1122 // "P-384":
1123 // Set the crv attribute of jwk to "P-384"
1124 // If the namedCurve attribute of the [[algorithm]] internal slot of key is
1125 // "P-521":
1126 // Set the crv attribute of jwk to "P-521"
1127 jwk.crv = Some(DOMString::from(algorithm.named_curve.as_str()));
1128
1129 // Step 3.3.2. Set the x attribute of jwk according to the definition in Section
1130 // 6.2.1.2 of JSON Web Algorithms [JWA].
1131 // Step 3.3.3. Set the y attribute of jwk according to the definition in Section
1132 // 6.2.1.3 of JSON Web Algorithms [JWA].
1133 let (x, y) = match key.handle() {
1134 Handle::P256PublicKey(public_key) => {
1135 let encoded_point = public_key.to_encoded_point(false);
1136 (
1137 encoded_point.x().ok_or(Error::Operation(None))?.to_vec(),
1138 encoded_point.y().ok_or(Error::Operation(None))?.to_vec(),
1139 )
1140 },
1141 Handle::P384PublicKey(public_key) => {
1142 let encoded_point = public_key.to_encoded_point(false);
1143 (
1144 encoded_point.x().ok_or(Error::Operation(None))?.to_vec(),
1145 encoded_point.y().ok_or(Error::Operation(None))?.to_vec(),
1146 )
1147 },
1148 Handle::P521PublicKey(public_key) => {
1149 let encoded_point = public_key.to_encoded_point(false);
1150 (
1151 encoded_point.x().ok_or(Error::Operation(None))?.to_vec(),
1152 encoded_point.y().ok_or(Error::Operation(None))?.to_vec(),
1153 )
1154 },
1155 Handle::P256PrivateKey(private_key) => {
1156 let public_key = private_key.public_key();
1157 let encoded_point = public_key.to_encoded_point(false);
1158 (
1159 encoded_point.x().ok_or(Error::Operation(None))?.to_vec(),
1160 encoded_point.y().ok_or(Error::Operation(None))?.to_vec(),
1161 )
1162 },
1163 Handle::P384PrivateKey(private_key) => {
1164 let public_key = private_key.public_key();
1165 let encoded_point = public_key.to_encoded_point(false);
1166 (
1167 encoded_point.x().ok_or(Error::Operation(None))?.to_vec(),
1168 encoded_point.y().ok_or(Error::Operation(None))?.to_vec(),
1169 )
1170 },
1171 Handle::P521PrivateKey(private_key) => {
1172 let public_key = private_key.public_key();
1173 let encoded_point = public_key.to_encoded_point(false);
1174 (
1175 encoded_point.x().ok_or(Error::Operation(None))?.to_vec(),
1176 encoded_point.y().ok_or(Error::Operation(None))?.to_vec(),
1177 )
1178 },
1179 _ => return Err(Error::Operation(None)),
1180 };
1181 jwk.encode_string_field(JwkStringField::X, &x);
1182 jwk.encode_string_field(JwkStringField::Y, &y);
1183
1184 // Step 3.3.4.
1185 // If the [[type]] internal slot of key is "private"
1186 // Set the d attribute of jwk according to the definition in Section 6.2.2.1 of
1187 // JSON Web Algorithms [JWA].
1188 if key.Type() == KeyType::Private {
1189 let d = match key.handle() {
1190 Handle::P256PrivateKey(private_key) => private_key.to_bytes().to_vec(),
1191 Handle::P384PrivateKey(private_key) => private_key.to_bytes().to_vec(),
1192 Handle::P521PrivateKey(private_key) => private_key.to_bytes().to_vec(),
1193 _ => return Err(Error::NotSupported(None)),
1194 };
1195 jwk.encode_string_field(JwkStringField::D, &d);
1196 }
1197 }
1198 // Otherwise:
1199 else {
1200 // Step 3.3.1. Perform any key export steps defined by other applicable
1201 // specifications, passing format and the namedCurve attribute of the [[algorithm]]
1202 // internal slot of key and obtaining namedCurve and a new value of jwk.
1203 // Step 3.3.2. Set the crv attribute of jwk to namedCurve.
1204 // NOTE: We currently do not support other applicable specifications.
1205 unreachable!()
1206 }
1207
1208 // Step 3.4. Set the key_ops attribute of jwk to the usages attribute of key.
1209 jwk.set_key_ops(key.usages());
1210
1211 // Step 3.4. Set the ext attribute of jwk to the [[extractable]] internal slot of key.
1212 jwk.ext = Some(key.Extractable());
1213
1214 // Step 3.4. Let result be jwk.
1215 ExportedKey::Jwk(Box::new(jwk))
1216 },
1217 // If format is "raw":
1218 KeyFormat::Raw | KeyFormat::Raw_public => {
1219 // Step 3.1. If the [[type]] internal slot of key is not "public", then throw an
1220 // InvalidAccessError.
1221 if key.Type() != KeyType::Public {
1222 return Err(Error::InvalidAccess(None));
1223 }
1224
1225 // Step 3.2.
1226 // If the namedCurve attribute of the [[algorithm]] internal slot of key is "P-256",
1227 // "P-384" or "P-521":
1228 // Let data be a byte sequence representing the Elliptic Curve point Q represented
1229 // by the [[handle]] internal slot of key according to [SEC1] 2.3.3 using the
1230 // uncompressed format.
1231 // Otherwise:
1232 // Perform any key export steps defined by other applicable specifications, passing
1233 // format and the namedCurve attribute of the [[algorithm]] internal slot of key
1234 // and obtaining namedCurve and data.
1235 // NOTE: We currently do not support other applicable specifications.
1236 let named_curve =
1237 if let KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm) = key.algorithm() {
1238 algorithm.named_curve.as_str()
1239 } else {
1240 return Err(Error::Operation(None));
1241 };
1242 let data = if matches!(
1243 named_curve,
1244 NAMED_CURVE_P256 | NAMED_CURVE_P384 | NAMED_CURVE_P521
1245 ) {
1246 match key.handle() {
1247 Handle::P256PublicKey(public_key) => public_key.to_sec1_bytes().to_vec(),
1248 Handle::P384PublicKey(public_key) => public_key.to_sec1_bytes().to_vec(),
1249 Handle::P521PublicKey(public_key) => public_key.to_sec1_bytes().to_vec(),
1250 _ => return Err(Error::Operation(None)),
1251 }
1252 } else {
1253 return Err(Error::NotSupported(None));
1254 };
1255
1256 // Step 3.3. Let result be data.
1257 ExportedKey::Bytes(data)
1258 },
1259 // Otherwise:
1260 _ => {
1261 // throw a NotSupportedError.
1262 return Err(Error::NotSupported(None));
1263 },
1264 };
1265
1266 // Step 4. Return result.
1267 Ok(result)
1268}
1269
1270/// A helper function that expand a prehash to a specified length if the prehash is shorter than
1271/// the specified length.
1272///
1273/// If the length of `prehash` is less than `length`, return a prehash with length `length`
1274/// constructed by left-padding `prehash` with zeros. Otherwire, return the unmodified `prehash`.
1275fn expand_prehash(prehash: Vec<u8>, length: usize) -> Vec<u8> {
1276 if prehash.len() < length {
1277 let mut left_padded_prehash = vec![0u8; length];
1278 left_padded_prehash[length - prehash.len()..].copy_from_slice(&prehash);
1279 left_padded_prehash
1280 } else {
1281 prehash
1282 }
1283}