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),
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);
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);
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);
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);
183    };
184    if public_key_algorithm.named_curve != key_algorithm.named_curve {
185        return Err(Error::InvalidAccess);
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);
211            };
212            let Handle::P256PublicKey(public_key) = public_key.handle() else {
213                return Err(Error::Operation);
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);
222            };
223            let Handle::P384PublicKey(public_key) = public_key.handle() else {
224                return Err(Error::Operation);
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);
233            };
234            let Handle::P521PublicKey(public_key) = public_key.handle() else {
235                return Err(Error::Operation);
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),
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)
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)?;
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);
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);
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.subject_public_key.as_bytes().ok_or(Error::Data)?;
343                    match curve {
344                        NAMED_CURVE_P256 => {
345                            let public_key = p256::PublicKey::from_sec1_bytes(sec1_bytes)
346                                .map_err(|_| Error::Data)?;
347                            Handle::P256PublicKey(public_key)
348                        },
349                        NAMED_CURVE_P384 => {
350                            let public_key = p384::PublicKey::from_sec1_bytes(sec1_bytes)
351                                .map_err(|_| Error::Data)?;
352                            Handle::P384PublicKey(public_key)
353                        },
354                        NAMED_CURVE_P521 => {
355                            let public_key = p521::PublicKey::from_sec1_bytes(sec1_bytes)
356                                .map_err(|_| Error::Data)?;
357                            Handle::P521PublicKey(public_key)
358                        },
359                        _ => unreachable!(),
360                    }
361
362                    // Step 2.10.5. Let key be a new CryptoKey that represents publicKey.
363                    // NOTE: CryptoKey is created in Step 2.13 - 2.17.
364                },
365                // Otherwise:
366                None => {
367                    // Step 2.10.1. Perform any key import steps defined by other applicable
368                    // specifications, passing format, spki and obtaining namedCurve and key.
369                    // Step 2.10.2. If an error occurred or there are no applicable specifications,
370                    // throw a DataError.
371                    // NOTE: We currently do not support applicable specifications.
372                    return Err(Error::NotSupported);
373                },
374            };
375
376            // Step 2.11. If namedCurve is defined, and not equal to the namedCurve member of
377            // normalizedAlgorithm, throw a DataError.
378            if named_curve.is_some_and(|curve| curve != normalized_algorithm.named_curve) {
379                return Err(Error::Data);
380            }
381
382            // Step 2.12. If the key value is not a valid point on the Elliptic Curve identified by
383            // the namedCurve member of normalizedAlgorithm throw a DataError.
384            // NOTE: Done in Step 2.10.
385
386            // Step 2.13. Set the [[type]] internal slot of key to "public"
387            // Step 2.14. Let algorithm be a new EcKeyAlgorithm.
388            // Step 2.15. Set the name attribute of algorithm to "ECDH".
389            // Step 2.16. Set the namedCurve attribute of algorithm to namedCurve.
390            // Step 2.17. Set the [[algorithm]] internal slot of key to algorithm.
391            let algorithm = SubtleEcKeyAlgorithm {
392                name: ALG_ECDH.to_string(),
393                named_curve: named_curve
394                    .expect("named_curve must exist here")
395                    .to_string(),
396            };
397            CryptoKey::new(
398                global,
399                KeyType::Public,
400                extractable,
401                KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm),
402                usages,
403                handle,
404                can_gc,
405            )
406        },
407        KeyFormat::Pkcs8 => {
408            // Step 2.1. If usages contains an entry which is not "deriveKey" or "deriveBits" then
409            // throw a SyntaxError.
410            if usages
411                .iter()
412                .any(|usage| !matches!(usage, KeyUsage::DeriveKey | KeyUsage::DeriveBits))
413            {
414                return Err(Error::Syntax(None));
415            }
416
417            // Step 2.2. Let privateKeyInfo be the result of running the parse a privateKeyInfo
418            // algorithm over keyData.
419            // Step 2.3. If an error occurs while parsing, throw a DataError.
420            let private_key_info = PrivateKeyInfo::from_der(key_data).map_err(|_| Error::Data)?;
421
422            // Step 2.4. If the algorithm object identifier field of the privateKeyAlgorithm
423            // PrivateKeyAlgorithm field of privateKeyInfo is not equal to the id-ecPublicKey
424            // object identifier defined in [RFC5480], throw a DataError.
425            if private_key_info.algorithm.oid != elliptic_curve::ALGORITHM_OID {
426                return Err(Error::Data);
427            }
428
429            // Step 2.5. If the parameters field of the privateKeyAlgorithm
430            // PrivateKeyAlgorithmIdentifier field of privateKeyInfo is not present, throw a
431            // DataError.
432            // Step 2.6. Let params be the parameters field of the privateKeyAlgorithm
433            // PrivateKeyAlgorithmIdentifier field of privateKeyInfo.
434            // Step 2.7. If params is not an instance of the ECParameters ASN.1 type defined in
435            // [RFC5480] that specifies a namedCurve, then throw a DataError.
436            let params: EcParameters = if let Some(params) = private_key_info.algorithm.parameters {
437                params.decode_as().map_err(|_| Error::Data)?
438            } else {
439                return Err(Error::Data);
440            };
441
442            // Step 2.8. Let namedCurve be a string whose initial value is undefined.
443            // Step 2.9.
444            // If params is equivalent to the secp256r1 object identifier defined in [RFC5480]:
445            //     Set namedCurve to "P-256".
446            // If params is equivalent to the secp384r1 object identifier defined in [RFC5480]:
447            //     Set namedCurve to "P-384".
448            // If params is equivalent to the secp521r1 object identifier defined in [RFC5480]:
449            //     Set namedCurve to "P-521".
450            let named_curve = match params {
451                EcParameters::NamedCurve(NistP256::OID) => Some(NAMED_CURVE_P256),
452                EcParameters::NamedCurve(NistP384::OID) => Some(NAMED_CURVE_P384),
453                EcParameters::NamedCurve(NistP521::OID) => Some(NAMED_CURVE_P521),
454                _ => None,
455            };
456
457            // Step 2.10.
458            let handle = match named_curve {
459                // If namedCurve is not undefined:
460                Some(curve) => {
461                    // Step 2.10.1. Let ecPrivateKey be the result of performing the parse an ASN.1
462                    // structure algorithm, with data as the privateKey field of privateKeyInfo,
463                    // structure as the ASN.1 ECPrivateKey structure specified in Section 3 of
464                    // [RFC5915], and exactData set to true.
465                    // Step 2.10.2. If an error occurred while parsing, then throw a DataError.
466                    let ec_private_key = EcPrivateKey::try_from(private_key_info.private_key)
467                        .map_err(|_| Error::Data)?;
468
469                    // Step 2.10.3. If the parameters field of ecPrivateKey is present, and is not
470                    // an instance of the namedCurve ASN.1 type defined in [RFC5480], or does not
471                    // contain the same object identifier as the parameters field of the
472                    // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier field of privateKeyInfo,
473                    // throw a DataError.
474                    if ec_private_key
475                        .parameters
476                        .is_some_and(|parameters| parameters != params)
477                    {
478                        return Err(Error::Data);
479                    }
480
481                    // Step 2.10.4. Let key be a new CryptoKey that represents the Elliptic Curve
482                    // private key identified by performing the conversion steps defined in Section
483                    // 3 of [RFC5915] using ecPrivateKey.
484                    // NOTE: CryptoKey is created in Step 2.13 - 2.17.
485                    match curve {
486                        NAMED_CURVE_P256 => {
487                            let private_key = p256::SecretKey::try_from(ec_private_key)
488                                .map_err(|_| Error::Data)?;
489                            Handle::P256PrivateKey(private_key)
490                        },
491                        NAMED_CURVE_P384 => {
492                            let private_key = p384::SecretKey::try_from(ec_private_key)
493                                .map_err(|_| Error::Data)?;
494                            Handle::P384PrivateKey(private_key)
495                        },
496                        NAMED_CURVE_P521 => {
497                            let private_key = p521::SecretKey::try_from(ec_private_key)
498                                .map_err(|_| Error::Data)?;
499                            Handle::P521PrivateKey(private_key)
500                        },
501                        _ => unreachable!(),
502                    }
503                },
504                // Otherwise:
505                None => {
506                    // Step 2.10.1. Perform any key import steps defined by other applicable
507                    // specifications, passing format, privateKeyInfo and obtaining namedCurve and
508                    // key.
509                    // Step 2.10.2. If an error occurred or there are no applicable specifications,
510                    // throw a DataError.
511                    // NOTE: We currently do not support applicable specifications.
512                    return Err(Error::NotSupported);
513                },
514            };
515
516            // Step 2.11. If namedCurve is defined, and not equal to the namedCurve member of
517            // normalizedAlgorithm, throw a DataError.
518            if named_curve.is_some_and(|curve| curve != normalized_algorithm.named_curve) {
519                return Err(Error::Data);
520            }
521
522            // Step 2.12. If the key value is not a valid point on the Elliptic Curve identified by
523            // the namedCurve member of normalizedAlgorithm throw a DataError.
524            // NOTE: Done in Step 2.10.
525
526            // Step 2.13. Set the [[type]] internal slot of key to "private".
527            // Step 2.14. Let algorithm be a new EcKeyAlgorithm.
528            // Step 2.15. Set the name attribute of algorithm to "ECDH".
529            // Step 2.16. Set the namedCurve attribute of algorithm to namedCurve.
530            // Step 2.17. Set the [[algorithm]] internal slot of key to algorithm.
531            let algorithm = SubtleEcKeyAlgorithm {
532                name: ALG_ECDH.to_string(),
533                named_curve: named_curve
534                    .expect("named_curve must exist here")
535                    .to_string(),
536            };
537            CryptoKey::new(
538                global,
539                KeyType::Private,
540                extractable,
541                KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm),
542                usages,
543                handle,
544                can_gc,
545            )
546        },
547        KeyFormat::Jwk => {
548            // Step 2.1.
549            // If keyData is a JsonWebKey dictionary:
550            //     Let jwk equal keyData.
551            // Otherwise:
552            //     Throw a DataError.
553            let jwk = JsonWebKey::parse(GlobalScope::get_cx(), key_data)?;
554
555            // Step 2.2. If the d field is present and if usages contains an entry which is not
556            // "deriveKey" or "deriveBits" then throw a SyntaxError.
557            if jwk.d.as_ref().is_some() &&
558                usages
559                    .iter()
560                    .any(|usage| !matches!(usage, KeyUsage::DeriveKey | KeyUsage::DeriveBits))
561            {
562                return Err(Error::Syntax(None));
563            }
564
565            // Step 2.3. If the d field is not present and if usages is not empty then throw a
566            // SyntaxError.
567            if jwk.d.as_ref().is_none() && !usages.is_empty() {
568                return Err(Error::Syntax(None));
569            }
570
571            // Step 2.4. If the kty field of jwk is not "EC", then throw a DataError.
572            if jwk.kty.as_ref().is_none_or(|kty| kty != "EC") {
573                return Err(Error::Data);
574            }
575
576            // Step 2.5. If usages is non-empty and the use field of jwk is present and is not
577            // equal to "enc" then throw a DataError.
578            if !usages.is_empty() && jwk.use_.as_ref().is_some_and(|use_| use_ != "enc") {
579                return Err(Error::Data);
580            }
581
582            // Step 2.6. If the key_ops field of jwk is present, and is invalid according to the
583            // requirements of JSON Web Key [JWK], or it does not contain all of the specified
584            // usages values, then throw a DataError.
585            jwk.check_key_ops(&usages)?;
586
587            // Step 2.7. If the ext field of jwk is present and has the value false and extractable
588            // is true, then throw a DataError.
589            if jwk.ext.is_some_and(|ext| !ext) && extractable {
590                return Err(Error::Data);
591            }
592
593            // Step 2.8. Let namedCurve be a string whose value is equal to the crv field of jwk.
594            // Step 2.9. If namedCurve is not equal to the namedCurve member of
595            // normalizedAlgorithm, throw a DataError.
596            let named_curve = jwk
597                .crv
598                .filter(|crv| *crv == normalized_algorithm.named_curve)
599                .map(|crv| crv.to_string())
600                .ok_or(Error::Data)?;
601
602            // Step 2.10.
603            // If namedCurve is "P-256", "P-384" or "P-521":
604            let (handle, key_type) =
605                if matches!(
606                    named_curve.as_str(),
607                    NAMED_CURVE_P256 | NAMED_CURVE_P384 | NAMED_CURVE_P521
608                ) {
609                    match jwk.d {
610                        // If the d field is present:
611                        Some(d) => {
612                            // Step 2.10.1. If jwk does not meet the requirements of Section 6.2.2 of
613                            // JSON Web Algorithms [JWA], then throw a DataError.
614                            let x = match jwk.x {
615                                Some(x) => Base64UrlUnpadded::decode_vec(&x.str())
616                                    .map_err(|_| Error::Data)?,
617                                None => return Err(Error::Data),
618                            };
619                            let y = match jwk.y {
620                                Some(y) => Base64UrlUnpadded::decode_vec(&y.str())
621                                    .map_err(|_| Error::Data)?,
622                                None => return Err(Error::Data),
623                            };
624                            let d =
625                                Base64UrlUnpadded::decode_vec(&d.str()).map_err(|_| Error::Data)?;
626
627                            // Step 2.10.2. Let key be a new CryptoKey object that represents the
628                            // Elliptic Curve private key identified by interpreting jwk according to
629                            // Section 6.2.2 of JSON Web Algorithms [JWA].
630                            // NOTE: CryptoKey is created in Step 2.12 - 2.15.
631                            let handle = match named_curve.as_str() {
632                                NAMED_CURVE_P256 => {
633                                    let private_key =
634                                        p256::SecretKey::from_slice(&d).map_err(|_| Error::Data)?;
635                                    let mut sec1_bytes = vec![4u8];
636                                    sec1_bytes.extend_from_slice(&x);
637                                    sec1_bytes.extend_from_slice(&y);
638                                    let encoded_point = EncodedPoint::from_bytes(&sec1_bytes)
639                                        .map_err(|_| Error::Data)?;
640                                    NistP256::validate_public_key(&private_key, &encoded_point)
641                                        .map_err(|_| Error::Data)?;
642                                    Handle::P256PrivateKey(private_key)
643                                },
644                                NAMED_CURVE_P384 => {
645                                    let private_key =
646                                        p384::SecretKey::from_slice(&d).map_err(|_| Error::Data)?;
647                                    let mut sec1_bytes = vec![4u8];
648                                    sec1_bytes.extend_from_slice(&x);
649                                    sec1_bytes.extend_from_slice(&y);
650                                    let encoded_point = EncodedPoint::from_bytes(&sec1_bytes)
651                                        .map_err(|_| Error::Data)?;
652                                    NistP384::validate_public_key(&private_key, &encoded_point)
653                                        .map_err(|_| Error::Data)?;
654                                    Handle::P384PrivateKey(private_key)
655                                },
656                                NAMED_CURVE_P521 => {
657                                    let private_key =
658                                        p521::SecretKey::from_slice(&d).map_err(|_| Error::Data)?;
659                                    let mut sec1_bytes = vec![4u8];
660                                    sec1_bytes.extend_from_slice(&x);
661                                    sec1_bytes.extend_from_slice(&y);
662                                    let encoded_point = EncodedPoint::from_bytes(&sec1_bytes)
663                                        .map_err(|_| Error::Data)?;
664                                    NistP521::validate_public_key(&private_key, &encoded_point)
665                                        .map_err(|_| Error::Data)?;
666                                    Handle::P521PrivateKey(private_key)
667                                },
668                                _ => unreachable!(),
669                            };
670
671                            // Step 2.10.3. Set the [[type]] internal slot of Key to "private".
672                            let key_type = KeyType::Private;
673
674                            (handle, key_type)
675                        },
676                        // Otherwise:
677                        None => {
678                            // Step 2.10.1. If jwk does not meet the requirements of Section 6.2.1 of
679                            // JSON Web Algorithms [JWA], then throw a DataError.
680                            let x = match jwk.x {
681                                Some(x) => Base64UrlUnpadded::decode_vec(&x.str())
682                                    .map_err(|_| Error::Data)?,
683                                None => return Err(Error::Data),
684                            };
685                            let y = match jwk.y {
686                                Some(y) => Base64UrlUnpadded::decode_vec(&y.str())
687                                    .map_err(|_| Error::Data)?,
688                                None => return Err(Error::Data),
689                            };
690
691                            // Step 2.10.2. Let key be a new CryptoKey object that represents the
692                            // Elliptic Curve public key identified by interpreting jwk according to
693                            // Section 6.2.1 of JSON Web Algorithms [JWA].
694                            // NOTE: CryptoKey is created in Step 2.12 - 2.15.
695                            let handle = match named_curve.as_str() {
696                                NAMED_CURVE_P256 => {
697                                    let mut sec1_bytes = vec![4u8];
698                                    sec1_bytes.extend_from_slice(&x);
699                                    sec1_bytes.extend_from_slice(&y);
700                                    let encoded_point = EncodedPoint::from_bytes(&sec1_bytes)
701                                        .map_err(|_| Error::Data)?;
702                                    let public_key =
703                                        p256::PublicKey::from_encoded_point(&encoded_point)
704                                            .into_option()
705                                            .ok_or(Error::Data)?;
706                                    Handle::P256PublicKey(public_key)
707                                },
708                                NAMED_CURVE_P384 => {
709                                    let mut sec1_bytes = vec![4u8];
710                                    sec1_bytes.extend_from_slice(&x);
711                                    sec1_bytes.extend_from_slice(&y);
712                                    let encoded_point = EncodedPoint::from_bytes(&sec1_bytes)
713                                        .map_err(|_| Error::Data)?;
714                                    let public_key =
715                                        p384::PublicKey::from_encoded_point(&encoded_point)
716                                            .into_option()
717                                            .ok_or(Error::Data)?;
718                                    Handle::P384PublicKey(public_key)
719                                },
720                                NAMED_CURVE_P521 => {
721                                    let mut sec1_bytes = vec![4u8];
722                                    sec1_bytes.extend_from_slice(&x);
723                                    sec1_bytes.extend_from_slice(&y);
724                                    let encoded_point = EncodedPoint::from_bytes(&sec1_bytes)
725                                        .map_err(|_| Error::Data)?;
726                                    let public_key =
727                                        p521::PublicKey::from_encoded_point(&encoded_point)
728                                            .into_option()
729                                            .ok_or(Error::Data)?;
730                                    Handle::P521PublicKey(public_key)
731                                },
732                                _ => unreachable!(),
733                            };
734
735                            // Step 2.10.3. Set the [[type]] internal slot of Key to "public".
736                            let key_type = KeyType::Public;
737
738                            (handle, key_type)
739                        },
740                    }
741                }
742                // Otherwise
743                else {
744                    // Step 2.10.1. Perform any key import steps defined by other applicable
745                    // specifications, passing format, jwk and obtaining key.
746                    // Step 2.10.2. If an error occurred or there are no applicable specifications,
747                    // throw a DataError.
748                    // NOTE: We currently do not support applicable specifications.
749                    return Err(Error::NotSupported);
750                };
751
752            // Step 2.11. If the key value is not a valid point on the Elliptic Curve identified by
753            // the namedCurve member of normalizedAlgorithm throw a DataError.
754            // NOTE: Done in Step 2.10.
755
756            // Step 2.12. Let algorithm be a new instance of an EcKeyAlgorithm object.
757            // Step 2.13. Set the name attribute of algorithm to "ECDH".
758            // Step 2.14. Set the namedCurve attribute of algorithm to namedCurve.
759            // Step 2.15. Set the [[algorithm]] internal slot of key to algorithm.
760            let algorithm = SubtleEcKeyAlgorithm {
761                name: ALG_ECDH.to_string(),
762                named_curve,
763            };
764            CryptoKey::new(
765                global,
766                key_type,
767                extractable,
768                KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm),
769                usages,
770                handle,
771                can_gc,
772            )
773        },
774        KeyFormat::Raw => {
775            // Step 2.1. If the namedCurve member of normalizedAlgorithm is not a named curve, then
776            // throw a DataError.
777            if !SUPPORTED_CURVES
778                .iter()
779                .any(|&supported_curve| supported_curve == normalized_algorithm.named_curve)
780            {
781                return Err(Error::Data);
782            }
783
784            // Step 2.2. If usages is not the empty list, then throw a SyntaxError.
785            if !usages.is_empty() {
786                return Err(Error::Syntax(None));
787            }
788
789            // Step 2.3.
790            // If namedCurve is "P-256", "P-384" or "P-521":
791            let handle = if matches!(
792                normalized_algorithm.named_curve.as_str(),
793                NAMED_CURVE_P256 | NAMED_CURVE_P384 | NAMED_CURVE_P521
794            ) {
795                // Step 2.3.1. Let Q be the Elliptic Curve public key on the curve identified by
796                // the namedCurve member of normalizedAlgorithm identified by performing the
797                // conversion steps defined in Section 2.3.4 of [SEC1] to keyData.
798                // Step 2.3.1. The uncompressed point format MUST be supported.
799                // Step 2.3.1. If the implementation does not support the compressed point format
800                // and a compressed point is provided, throw a DataError.
801                // Step 2.3.1. If a decode error occurs or an identity point is found, throw a
802                // DataError.
803                match normalized_algorithm.named_curve.as_str() {
804                    NAMED_CURVE_P256 => {
805                        let q =
806                            p256::PublicKey::from_sec1_bytes(key_data).map_err(|_| Error::Data)?;
807                        Handle::P256PublicKey(q)
808                    },
809                    NAMED_CURVE_P384 => {
810                        let q =
811                            p384::PublicKey::from_sec1_bytes(key_data).map_err(|_| Error::Data)?;
812                        Handle::P384PublicKey(q)
813                    },
814                    NAMED_CURVE_P521 => {
815                        let q =
816                            p521::PublicKey::from_sec1_bytes(key_data).map_err(|_| Error::Data)?;
817                        Handle::P521PublicKey(q)
818                    },
819                    _ => unreachable!(),
820                }
821
822                // Step 2.3.1. Let key be a new CryptoKey that represents Q.
823                // NOTE: CryptoKey is created in Step 2.7 - 2.8.
824            }
825            // Otherwise:
826            else {
827                // Step. 2.3.1. Perform any key import steps defined by other applicable
828                // specifications, passing format, keyData and obtaining key.
829                // Step. 2.3.2. If an error occured or there are no applicable specifications,
830                // throw a DataError.
831                // NOTE: We currently do not support applicable specifications.
832                return Err(Error::NotSupported);
833            };
834
835            // Step 2.4. Let algorithm be a new EcKeyAlgorithm object.
836            // Step 2.5. Set the name attribute of algorithm to "ECDH".
837            // Step 2.6. Set the namedCurve attribute of algorithm to equal the namedCurve member
838            // of normalizedAlgorithm.
839            let algorithm = SubtleEcKeyAlgorithm {
840                name: ALG_ECDH.to_string(),
841                named_curve: normalized_algorithm.named_curve.clone(),
842            };
843
844            // Step 2.7. Set the [[type]] internal slot of key to "public"
845            // Step 2.8. Set the [[algorithm]] internal slot of key to algorithm.
846            CryptoKey::new(
847                global,
848                KeyType::Public,
849                extractable,
850                KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm),
851                usages,
852                handle,
853                can_gc,
854            )
855        },
856    };
857
858    // Step 3. Return key.
859    Ok(key)
860}
861
862/// <https://w3c.github.io/webcrypto/#ecdh-operations-export-key>
863pub(crate) fn export_key(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
864    // Step 1. Let key be the CryptoKey to be exported.
865
866    // Step 2. If the underlying cryptographic key material represented by the [[handle]] internal
867    // slot of key cannot be accessed, then throw an OperationError.
868    // NOTE: Done in Step 3.
869
870    // Step 3.
871    let result = match format {
872        KeyFormat::Spki => {
873            // Step 3.1. If the [[type]] internal slot of key is not "public", then throw an
874            // InvalidAccessError.
875            if key.Type() != KeyType::Public {
876                return Err(Error::InvalidAccess);
877            }
878
879            // Step 3.2.
880            // Let data be an instance of the SubjectPublicKeyInfo ASN.1 structure defined in
881            // [RFC5280] with the following properties:
882            //     * Set the algorithm field to an AlgorithmIdentifier ASN.1 type with the
883            //     following properties:
884            //         * Set the algorithm field to the OID id-ecPublicKey defined in [RFC5480].
885            //         * Set the parameters field to an instance of the ECParameters ASN.1 type
886            //         defined in [RFC5480] as follows:
887            //             If the namedCurve attribute of the [[algorithm]] internal slot of key is
888            //             "P-256", "P-384" or "P-521":
889            //                 Let keyData be the byte sequence that represents the Elliptic Curve
890            //                 public key represented by the [[handle]] internal slot of key
891            //                 according to the encoding rules specified in Section 2.3.3 of [SEC1]
892            //                 and using the uncompressed form.
893            //                     If the namedCurve attribute of the [[algorithm]] internal slot
894            //                     of key is "P-256":
895            //                         Set parameters to the namedCurve choice with value equal to
896            //                         the object identifier secp256r1 defined in [RFC5480]
897            //                     If the namedCurve attribute of the [[algorithm]] internal slot
898            //                     of key is "P-384":
899            //                         Set parameters to the namedCurve choice with value equal to
900            //                         the object identifier secp384r1 defined in [RFC5480]
901            //                     If the namedCurve attribute of the [[algorithm]] internal slot
902            //                     of key is "P-521":
903            //                         Set parameters to the namedCurve choice with value equal to
904            //                         the object identifier secp521r1 defined in [RFC5480]
905            //             Otherwise:
906            //                 1. Perform any key export steps defined by other applicable
907            //                    specifications, passing format and the namedCurve attribute of
908            //                    the [[algorithm]] internal slot of key and obtaining
909            //                    namedCurveOid and keyData.
910            //                 2. Set parameters to the namedCurve choice with value equal to the
911            //                    object identifier namedCurveOid.
912            //     * Set the subjectPublicKey field to keyData
913            let data = match key.handle() {
914                Handle::P256PublicKey(public_key) => public_key.to_public_key_der(),
915                Handle::P384PublicKey(public_key) => public_key.to_public_key_der(),
916                Handle::P521PublicKey(public_key) => public_key.to_public_key_der(),
917                _ => return Err(Error::Operation),
918            }
919            .map_err(|_| Error::Operation)?;
920
921            ExportedKey::Raw(data.to_vec())
922        },
923        KeyFormat::Pkcs8 => {
924            // Step 3.1. If the [[type]] internal slot of key is not "private", then throw an
925            // InvalidAccessError.
926            if key.Type() != KeyType::Private {
927                return Err(Error::InvalidAccess);
928            }
929
930            // Step 3.2.
931            // Let data be an instance of the PrivateKeyInfo ASN.1 structure defined in [RFC5208]
932            // with the following properties:
933            //     * Set the version field to 0.
934            //     * Set the privateKeyAlgorithm field to a PrivateKeyAlgorithmIdentifier ASN.1
935            //     type with the following properties:
936            //         * Set the algorithm field to the OID id-ecPublicKey defined in [RFC5480].
937            //         * Set the parameters field to an instance of the ECParameters ASN.1 type
938            //         defined in [RFC5480] as follows:
939            //             If the namedCurve attribute of the [[algorithm]] internal slot of key is
940            //             "P-256", "P-384" or "P-521":
941            //                 Let keyData be the result of DER-encoding an instance of the
942            //                 ECPrivateKey structure defined in Section 3 of [RFC5915] for the
943            //                 Elliptic Curve private key represented by the [[handle]] internal
944            //                 slot of key and that conforms to the following:
945            //                     * The parameters field is present, and is equivalent to the
946            //                     parameters field of the privateKeyAlgorithm field of this
947            //                     PrivateKeyInfo ASN.1 structure.
948            //                     * The publicKey field is present and represents the Elliptic
949            //                     Curve public key associated with the Elliptic Curve private key
950            //                     represented by the [[handle]] internal slot of key.
951            //                     * If the namedCurve attribute of the [[algorithm]] internal slot
952            //                     of key is "P-256":
953            //                         Set parameters to the namedCurve choice with value equal to
954            //                         the object identifier secp256r1 defined in [RFC5480]
955            //                     * If the namedCurve attribute of the [[algorithm]] internal slot
956            //                     of key is "P-384":
957            //                         Set parameters to the namedCurve choice with value equal to
958            //                         the object identifier secp384r1 defined in [RFC5480]
959            //                     * If the namedCurve attribute of the [[algorithm]] internal slot
960            //                     of key is "P-521":
961            //                         Set parameters to the namedCurve choice with value equal to
962            //                         the object identifier secp521r1 defined in [RFC5480]
963            //             Otherwise:
964            //                 1. Perform any key export steps defined by other applicable
965            //                    specifications, passing format and the namedCurve attribute of
966            //                    the [[algorithm]] internal slot of key and obtaining
967            //                    namedCurveOid and keyData.
968            //                 2. Set parameters to the namedCurve choice with value equal to the
969            //                    object identifier namedCurveOid.
970            //     * Set the privateKey field to keyData.
971            let data = match key.handle() {
972                Handle::P256PrivateKey(private_key) => private_key.to_pkcs8_der(),
973                Handle::P384PrivateKey(private_key) => private_key.to_pkcs8_der(),
974                Handle::P521PrivateKey(private_key) => private_key.to_pkcs8_der(),
975                _ => return Err(Error::Operation),
976            }
977            .map_err(|_| Error::Operation)?;
978
979            ExportedKey::Raw(data.as_bytes().to_vec())
980        },
981        KeyFormat::Jwk => {
982            // Step 3.1. Let jwk be a new JsonWebKey dictionary.
983            // Step 3.2. Set the kty attribute of jwk to "EC".
984            let mut jwk = JsonWebKey {
985                kty: Some(DOMString::from("EC")),
986                ..Default::default()
987            };
988
989            // Step 3.3.
990            let named_curve =
991                if let KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm) = key.algorithm() {
992                    algorithm.named_curve.as_str()
993                } else {
994                    return Err(Error::Operation);
995                };
996            // If the namedCurve attribute of the [[algorithm]] internal slot of key is "P-256",
997            // "P-384" or "P-521":
998            if matches!(
999                named_curve,
1000                NAMED_CURVE_P256 | NAMED_CURVE_P384 | NAMED_CURVE_P521
1001            ) {
1002                // Step 3.3.1.
1003                // If the namedCurve attribute of the [[algorithm]] internal slot of key is
1004                // "P-256":
1005                //     Set the crv attribute of jwk to "P-256"
1006                // If the namedCurve attribute of the [[algorithm]] internal slot of key is
1007                // "P-384":
1008                //     Set the crv attribute of jwk to "P-384"
1009                // If the namedCurve attribute of the [[algorithm]] internal slot of key is
1010                // "P-521":
1011                //     Set the crv attribute of jwk to "P-521"
1012                jwk.crv = Some(DOMString::from(named_curve));
1013
1014                // Step 3.3.2. Set the x attribute of jwk according to the definition in Section
1015                // 6.2.1.2 of JSON Web Algorithms [JWA].
1016                // Step 3.3.3. Set the y attribute of jwk according to the definition in Section
1017                // 6.2.1.3 of JSON Web Algorithms [JWA].
1018                let (x, y) = match key.handle() {
1019                    Handle::P256PublicKey(public_key) => {
1020                        let encoded_point = public_key.to_encoded_point(false);
1021                        (
1022                            encoded_point.x().ok_or(Error::Operation)?.to_vec(),
1023                            encoded_point.y().ok_or(Error::Operation)?.to_vec(),
1024                        )
1025                    },
1026                    Handle::P384PublicKey(public_key) => {
1027                        let encoded_point = public_key.to_encoded_point(false);
1028                        (
1029                            encoded_point.x().ok_or(Error::Operation)?.to_vec(),
1030                            encoded_point.y().ok_or(Error::Operation)?.to_vec(),
1031                        )
1032                    },
1033                    Handle::P521PublicKey(public_key) => {
1034                        let encoded_point = public_key.to_encoded_point(false);
1035                        (
1036                            encoded_point.x().ok_or(Error::Operation)?.to_vec(),
1037                            encoded_point.y().ok_or(Error::Operation)?.to_vec(),
1038                        )
1039                    },
1040                    Handle::P256PrivateKey(private_key) => {
1041                        let public_key = private_key.public_key();
1042                        let encoded_point = public_key.to_encoded_point(false);
1043                        (
1044                            encoded_point.x().ok_or(Error::Operation)?.to_vec(),
1045                            encoded_point.y().ok_or(Error::Operation)?.to_vec(),
1046                        )
1047                    },
1048                    Handle::P384PrivateKey(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)?.to_vec(),
1053                            encoded_point.y().ok_or(Error::Operation)?.to_vec(),
1054                        )
1055                    },
1056                    Handle::P521PrivateKey(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)?.to_vec(),
1061                            encoded_point.y().ok_or(Error::Operation)?.to_vec(),
1062                        )
1063                    },
1064                    _ => return Err(Error::Operation),
1065                };
1066                jwk.x = Some(Base64UrlUnpadded::encode_string(&x).into());
1067                jwk.y = Some(Base64UrlUnpadded::encode_string(&y).into());
1068
1069                // Step 3.3.4.
1070                // If the [[type]] internal slot of key is "private"
1071                //     Set the d attribute of jwk according to the definition in Section 6.2.2.1 of
1072                //     JSON Web Algorithms [JWA].
1073                if key.Type() == KeyType::Private {
1074                    let d = match key.handle() {
1075                        Handle::P256PrivateKey(private_key) => private_key.to_bytes().to_vec(),
1076                        Handle::P384PrivateKey(private_key) => private_key.to_bytes().to_vec(),
1077                        Handle::P521PrivateKey(private_key) => private_key.to_bytes().to_vec(),
1078                        _ => return Err(Error::NotSupported),
1079                    };
1080                    jwk.d = Some(Base64UrlUnpadded::encode_string(&d).into());
1081                }
1082            }
1083            // Otherwise:
1084            else {
1085                // Step 3.3.1. Perform any key export steps defined by other applicable
1086                // specifications, passing format and the namedCurve attribute of the [[algorithm]]
1087                // internal slot of key and obtaining namedCurve and a new value of jwk.
1088                // Step 3.3.2. Set the crv attribute of jwk to namedCurve.
1089                // NOTE: We currently do not support applicable specifications.
1090            }
1091
1092            // Step 3.4. Set the key_ops attribute of jwk to the usages attribute of key.
1093            jwk.key_ops = Some(
1094                key.usages()
1095                    .iter()
1096                    .map(|usage| DOMString::from(usage.as_str()))
1097                    .collect::<Vec<DOMString>>(),
1098            );
1099
1100            // Step 3.4. Set the ext attribute of jwk to the [[extractable]] internal slot of key.
1101            jwk.ext = Some(key.Extractable());
1102
1103            // Step 3.4. Let result be jwk.
1104            ExportedKey::Jwk(Box::new(jwk))
1105        },
1106        KeyFormat::Raw => {
1107            // Step 3.1. If the [[type]] internal slot of key is not "public", then throw an
1108            // InvalidAccessError.
1109            if key.Type() != KeyType::Public {
1110                return Err(Error::InvalidAccess);
1111            }
1112
1113            // Step 3.2.
1114            // If the namedCurve attribute of the [[algorithm]] internal slot of key is "P-256",
1115            // "P-384" or "P-521":
1116            //     Let data be the byte sequence that represents the Elliptic Curve public key
1117            //     represented by the [[handle]] internal slot of key according to the encoding
1118            //     rules specified in Section 2.3.3 of [SEC1] and using the uncompressed form.
1119            // Otherwise:
1120            //     Perform any key export steps defined by other applicable specifications, passing
1121            //     format and the namedCurve attribute of the [[algorithm]] internal slot of key
1122            //     and obtaining namedCurve and data.
1123            //     NOTE: We currently do not support applicable specifications.
1124            let named_curve =
1125                if let KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm) = key.algorithm() {
1126                    algorithm.named_curve.as_str()
1127                } else {
1128                    return Err(Error::Operation);
1129                };
1130            let data = if matches!(
1131                named_curve,
1132                NAMED_CURVE_P256 | NAMED_CURVE_P384 | NAMED_CURVE_P521
1133            ) {
1134                match key.handle() {
1135                    Handle::P256PublicKey(public_key) => public_key.to_sec1_bytes().to_vec(),
1136                    Handle::P384PublicKey(public_key) => public_key.to_sec1_bytes().to_vec(),
1137                    Handle::P521PublicKey(public_key) => public_key.to_sec1_bytes().to_vec(),
1138                    _ => return Err(Error::Operation),
1139                }
1140            } else {
1141                return Err(Error::NotSupported);
1142            };
1143
1144            // Step 3.3. Let result be data.
1145            ExportedKey::Raw(data)
1146        },
1147    };
1148
1149    // Step 4. Return result.
1150    Ok(result)
1151}