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