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