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