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}