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