script/dom/subtlecrypto/
ecdsa_operation.rs

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