1use js_sys::{Array, Object, Reflect};
60use std::convert::TryFrom;
61use wasm_bindgen::prelude::*;
62use wasm_bindgen_futures::JsFuture;
63use web_sys::{CryptoKey, SubtleCrypto};
64
65use crate::error::{Error, Result};
66use crate::jwk::{Algorithm, EcCurve, Key, KeyOperation, KeyParams};
67#[cfg(test)]
68use crate::jwks::KeyMatcher;
69
70pub fn get_subtle_crypto() -> Result<SubtleCrypto> {
88 if let Some(window) = web_sys::window()
90 && let Ok(crypto) = window.crypto()
91 {
92 return Ok(crypto.subtle());
93 }
94
95 let global = js_sys::global();
97 if let Ok(worker_scope) = global.dyn_into::<web_sys::WorkerGlobalScope>()
98 && let Ok(crypto) = worker_scope.crypto()
99 {
100 return Ok(crypto.subtle());
101 }
102
103 Err(Error::WebCrypto(
104 "crypto API not available in this context".to_string(),
105 ))
106}
107
108impl TryFrom<&Key> for web_sys::JsonWebKey {
137 type Error = Error;
138
139 fn try_from(key: &Key) -> Result<Self> {
140 key.params().validate()?;
145
146 validate_webcrypto_support(key)?;
148
149 let jwk = web_sys::JsonWebKey::new(key.kty().as_str());
150
151 if let Some(alg) = key.alg() {
156 jwk.set_alg(alg.as_str());
157 }
158
159 if let Some(key_use) = key.key_use() {
160 jwk.set_use(key_use.as_str());
161 }
162
163 if let Some(key_ops) = key.key_ops() {
164 let ops = Array::new();
165 for op in key_ops {
166 ops.push(&JsValue::from_str(op.as_str()));
167 }
168 jwk.set_key_ops(&ops);
169 }
170
171 match key.params() {
173 KeyParams::Rsa(params) => {
174 jwk.set_n(¶ms.n.to_base64url());
176 jwk.set_e(¶ms.e.to_base64url());
177
178 if let Some(d) = ¶ms.d {
180 jwk.set_d(&d.to_base64url());
181 }
182 if let Some(p) = ¶ms.p {
183 jwk.set_p(&p.to_base64url());
184 }
185 if let Some(q) = ¶ms.q {
186 jwk.set_q(&q.to_base64url());
187 }
188 if let Some(dp) = ¶ms.dp {
189 jwk.set_dp(&dp.to_base64url());
190 }
191 if let Some(dq) = ¶ms.dq {
192 jwk.set_dq(&dq.to_base64url());
193 }
194 if let Some(qi) = ¶ms.qi {
195 jwk.set_qi(&qi.to_base64url());
196 }
197 }
199 KeyParams::Ec(params) => {
200 jwk.set_crv(params.crv.as_str());
201 jwk.set_x(¶ms.x.to_base64url());
202 jwk.set_y(¶ms.y.to_base64url());
203
204 if let Some(d) = ¶ms.d {
205 jwk.set_d(&d.to_base64url());
206 }
207 }
208 KeyParams::Symmetric(params) => {
209 jwk.set_k(¶ms.k.to_base64url());
210 }
211 KeyParams::Okp(_) => {
212 return Err(Error::UnsupportedForWebCrypto {
214 reason: "OKP keys (Ed25519, Ed448, X25519, X448) are not supported by WebCrypto",
215 });
216 }
217 }
218
219 Ok(jwk)
220 }
221}
222
223fn validate_webcrypto_support(key: &Key) -> Result<()> {
225 match key.params() {
226 KeyParams::Okp(_) => Err(Error::UnsupportedForWebCrypto {
227 reason: "OKP keys (Ed25519, Ed448, X25519, X448) are not supported by WebCrypto",
228 }),
229 KeyParams::Ec(params) => {
230 if params.crv == EcCurve::Secp256k1 {
231 Err(Error::UnsupportedForWebCrypto {
232 reason: "secp256k1 curve is not supported by WebCrypto",
233 })
234 } else {
235 Ok(())
236 }
237 }
238 KeyParams::Rsa(_) | KeyParams::Symmetric(_) => Ok(()),
239 }
240}
241
242fn build_algorithm_object(key: &Key, usage: KeyUsage) -> Result<Object> {
250 build_algorithm_object_with_alg(key, usage, None)
251}
252
253fn build_algorithm_object_for_alg(key: &Key, alg: &Algorithm, usage: KeyUsage) -> Result<Object> {
254 build_algorithm_object_with_alg(key, usage, Some(alg))
255}
256
257fn build_algorithm_object_with_alg(
258 key: &Key,
259 usage: KeyUsage,
260 alg_override: Option<&Algorithm>,
261) -> Result<Object> {
262 match key.params() {
263 KeyParams::Rsa(_) => build_rsa_algorithm(key, usage, alg_override),
264 KeyParams::Ec(params) => {
265 if let Some(alg) = alg_override {
271 let expected_curve = match alg {
272 Algorithm::Es256 => Some(EcCurve::P256),
273 Algorithm::Es384 => Some(EcCurve::P384),
274 Algorithm::Es512 => Some(EcCurve::P521),
275 _ => None,
276 };
277 match expected_curve {
278 Some(curve) if curve != params.crv => {
279 return Err(Error::WebCrypto(format!(
280 "algorithm {} requires curve {}, but the key uses {}",
281 alg.as_str(),
282 curve.as_str(),
283 params.crv.as_str(),
284 )));
285 }
286 None => {
287 return Err(Error::WebCrypto(format!(
288 "algorithm {} is not supported for EC key import in WebCrypto",
289 alg.as_str(),
290 )));
291 }
292 _ => {} }
294 }
295 build_ec_algorithm(params.crv, usage)
296 }
297 KeyParams::Symmetric(_) => build_symmetric_algorithm(key, usage, alg_override),
298 KeyParams::Okp(_) => Err(Error::UnsupportedForWebCrypto {
299 reason: "OKP keys are not supported by WebCrypto",
300 }),
301 }
302}
303
304fn validate_usage_algorithm_compatibility(usage: KeyUsage, alg: &Algorithm) -> Result<()> {
305 let allowed = match usage {
306 KeyUsage::Verify => matches!(
307 alg,
308 Algorithm::Rs256
309 | Algorithm::Rs384
310 | Algorithm::Rs512
311 | Algorithm::Ps256
312 | Algorithm::Ps384
313 | Algorithm::Ps512
314 | Algorithm::Es256
315 | Algorithm::Es384
316 | Algorithm::Es512
317 | Algorithm::Hs256
318 | Algorithm::Hs384
319 | Algorithm::Hs512
320 ),
321 KeyUsage::Sign => matches!(
322 alg,
323 Algorithm::Rs256
324 | Algorithm::Rs384
325 | Algorithm::Rs512
326 | Algorithm::Ps256
327 | Algorithm::Ps384
328 | Algorithm::Ps512
329 | Algorithm::Es256
330 | Algorithm::Es384
331 | Algorithm::Es512
332 | Algorithm::Hs256
333 | Algorithm::Hs384
334 | Algorithm::Hs512
335 ),
336 KeyUsage::Encrypt => matches!(
337 alg,
338 Algorithm::RsaOaep
339 | Algorithm::RsaOaep256
340 | Algorithm::RsaOaep384
341 | Algorithm::RsaOaep512
342 | Algorithm::A128gcm
343 | Algorithm::A192gcm
344 | Algorithm::A256gcm
345 ),
346 KeyUsage::Decrypt => matches!(
347 alg,
348 Algorithm::RsaOaep
349 | Algorithm::RsaOaep256
350 | Algorithm::RsaOaep384
351 | Algorithm::RsaOaep512
352 | Algorithm::A128gcm
353 | Algorithm::A192gcm
354 | Algorithm::A256gcm
355 ),
356 KeyUsage::WrapKey => matches!(
357 alg,
358 Algorithm::RsaOaep
359 | Algorithm::RsaOaep256
360 | Algorithm::RsaOaep384
361 | Algorithm::RsaOaep512
362 | Algorithm::A128kw
363 | Algorithm::A192kw
364 | Algorithm::A256kw
365 ),
366 KeyUsage::UnwrapKey => matches!(
367 alg,
368 Algorithm::RsaOaep
369 | Algorithm::RsaOaep256
370 | Algorithm::RsaOaep384
371 | Algorithm::RsaOaep512
372 | Algorithm::A128kw
373 | Algorithm::A192kw
374 | Algorithm::A256kw
375 ),
376 };
377
378 if allowed {
379 Ok(())
380 } else {
381 Err(Error::UnsupportedForWebCrypto {
382 reason: "algorithm is not compatible with requested key usage",
383 })
384 }
385}
386
387fn validate_key_for_webcrypto_usage_with_alg(
388 key: &Key,
389 usage: KeyUsage,
390 alg: &Algorithm,
391) -> Result<()> {
392 validate_usage_algorithm_compatibility(usage, alg)?;
393 key.validate_for_use_with_alg_override(alg, [key_operation_for_usage(usage)])
397}
398
399fn validate_key_for_webcrypto_usage(key: &Key, usage: KeyUsage) -> Result<()> {
400 let requested_op = key_operation_for_usage(usage);
401
402 if let Some(alg) = key.alg() {
403 validate_usage_algorithm_compatibility(usage, alg)?;
404 key.validate_for_use(alg, [requested_op])?;
405 return Ok(());
406 }
407
408 key.validate()?;
412 key.check_operation_capability(std::slice::from_ref(&requested_op))?;
413 key.validate_operation_intent_for_all(std::slice::from_ref(&requested_op))?;
414
415 Ok(())
416}
417
418fn key_operation_for_usage(usage: KeyUsage) -> KeyOperation {
419 match usage {
420 KeyUsage::Sign => KeyOperation::Sign,
421 KeyUsage::Verify => KeyOperation::Verify,
422 KeyUsage::Encrypt => KeyOperation::Encrypt,
423 KeyUsage::Decrypt => KeyOperation::Decrypt,
424 KeyUsage::WrapKey => KeyOperation::WrapKey,
425 KeyUsage::UnwrapKey => KeyOperation::UnwrapKey,
426 }
427}
428
429#[derive(Debug, Clone, Copy, PartialEq, Eq)]
435#[non_exhaustive]
436pub enum KeyUsage {
437 Sign,
439 Verify,
441 Encrypt,
443 Decrypt,
445 WrapKey,
447 UnwrapKey,
449}
450
451fn usage_strings_for_usage(usage: KeyUsage) -> &'static [&'static str] {
452 match usage {
453 KeyUsage::Sign => &["sign"],
454 KeyUsage::Verify => &["verify"],
455 KeyUsage::Encrypt => &["encrypt"],
456 KeyUsage::Decrypt => &["decrypt"],
457 KeyUsage::WrapKey => &["wrapKey"],
458 KeyUsage::UnwrapKey => &["unwrapKey"],
459 }
460}
461
462fn build_rsa_algorithm(
473 key: &Key,
474 _usage: KeyUsage,
475 alg_override: Option<&Algorithm>,
476) -> Result<Object> {
477 let obj = Object::new();
478
479 let effective_alg = alg_override.or(key.alg());
481
482 let (alg_name, hash) = match effective_alg {
484 Some(Algorithm::Rs256) => ("RSASSA-PKCS1-v1_5", "SHA-256"),
485 Some(Algorithm::Rs384) => ("RSASSA-PKCS1-v1_5", "SHA-384"),
486 Some(Algorithm::Rs512) => ("RSASSA-PKCS1-v1_5", "SHA-512"),
487 Some(Algorithm::Ps256) => ("RSA-PSS", "SHA-256"),
488 Some(Algorithm::Ps384) => ("RSA-PSS", "SHA-384"),
489 Some(Algorithm::Ps512) => ("RSA-PSS", "SHA-512"),
490 Some(Algorithm::RsaOaep) => ("RSA-OAEP", "SHA-1"),
491 Some(Algorithm::RsaOaep256) => ("RSA-OAEP", "SHA-256"),
492 Some(Algorithm::RsaOaep384) => ("RSA-OAEP", "SHA-384"),
493 Some(Algorithm::RsaOaep512) => ("RSA-OAEP", "SHA-512"),
494 _ => {
495 return Err(Error::WebCrypto(
496 "RSA key import requires an algorithm to determine the hash function; \
497 set the `alg` field on the key or use an import function that accepts \
498 an explicit algorithm (e.g., `import_verify_key_for_alg`)"
499 .to_string(),
500 ));
501 }
502 };
503
504 Reflect::set(&obj, &"name".into(), &alg_name.into())
505 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
506
507 let hash_obj = Object::new();
509 Reflect::set(&hash_obj, &"name".into(), &hash.into())
510 .map_err(|e| Error::WebCrypto(format!("failed to set hash name: {:?}", e)))?;
511 Reflect::set(&obj, &"hash".into(), &hash_obj.into())
512 .map_err(|e| Error::WebCrypto(format!("failed to set hash: {:?}", e)))?;
513
514 Ok(obj)
515}
516
517fn build_ec_algorithm(curve: EcCurve, usage: KeyUsage) -> Result<Object> {
519 let obj = Object::new();
520
521 let alg_name = match usage {
522 KeyUsage::Sign | KeyUsage::Verify => "ECDSA",
523 KeyUsage::Encrypt | KeyUsage::Decrypt | KeyUsage::WrapKey | KeyUsage::UnwrapKey => {
524 return Err(Error::UnsupportedForWebCrypto {
525 reason: "EC key derivation (ECDH) and direct encrypt/decrypt/wrap/unwrap \
526 are not yet supported by this library; \
527 only ECDSA sign/verify is currently implemented for EC keys",
528 });
529 }
530 };
531
532 Reflect::set(&obj, &"name".into(), &alg_name.into())
533 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
534
535 let named_curve = match curve {
536 EcCurve::P256 => "P-256",
537 EcCurve::P384 => "P-384",
538 EcCurve::P521 => "P-521",
539 EcCurve::Secp256k1 => {
540 return Err(Error::UnsupportedForWebCrypto {
541 reason: "secp256k1 curve is not supported by WebCrypto",
542 });
543 }
544 };
545
546 Reflect::set(&obj, &"namedCurve".into(), &named_curve.into())
547 .map_err(|e| Error::WebCrypto(format!("failed to set namedCurve: {:?}", e)))?;
548
549 Ok(obj)
550}
551
552fn build_symmetric_algorithm(
562 key: &Key,
563 _usage: KeyUsage,
564 alg_override: Option<&Algorithm>,
565) -> Result<Object> {
566 let obj = Object::new();
567
568 let effective_alg = alg_override.or(key.alg());
570
571 let (alg_name, extra) = match effective_alg {
572 Some(Algorithm::Hs256) => ("HMAC", Some(("hash", "SHA-256"))),
573 Some(Algorithm::Hs384) => ("HMAC", Some(("hash", "SHA-384"))),
574 Some(Algorithm::Hs512) => ("HMAC", Some(("hash", "SHA-512"))),
575 Some(Algorithm::A128kw) | Some(Algorithm::A192kw) | Some(Algorithm::A256kw) => {
579 ("AES-KW", None)
580 }
581 Some(Algorithm::A128gcm) | Some(Algorithm::A192gcm) | Some(Algorithm::A256gcm) => {
582 ("AES-GCM", None)
583 }
584 Some(Algorithm::A128cbcHs256)
585 | Some(Algorithm::A192cbcHs384)
586 | Some(Algorithm::A256cbcHs512) => {
587 return Err(Error::UnsupportedForWebCrypto {
588 reason: "AES-CBC-HS algorithms (A128CBC-HS256, A192CBC-HS384, A256CBC-HS512) \
589 are composite authenticated encryption algorithms requiring split-key \
590 handling (AES-CBC + HMAC) which WebCrypto does not natively support",
591 });
592 }
593 _ => {
594 return Err(Error::WebCrypto(
595 "symmetric key import requires an algorithm to determine the operation; \
596 set the `alg` field on the key or use an import function that accepts \
597 an explicit algorithm (e.g., `import_verify_key_for_alg`)"
598 .to_string(),
599 ));
600 }
601 };
602
603 Reflect::set(&obj, &"name".into(), &alg_name.into())
604 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
605
606 if let Some((prop, val)) = extra {
607 debug_assert_eq!(prop, "hash", "only HMAC uses extra parameters");
608 let hash_obj = Object::new();
609 Reflect::set(&hash_obj, &"name".into(), &val.into())
610 .map_err(|e| Error::WebCrypto(format!("failed to set hash name: {:?}", e)))?;
611 Reflect::set(&obj, &"hash".into(), &hash_obj.into())
612 .map_err(|e| Error::WebCrypto(format!("failed to set hash: {:?}", e)))?;
613 }
614
615 Ok(obj)
616}
617
618pub fn build_verify_algorithm(alg: &Algorithm) -> Result<Object> {
653 let obj = Object::new();
654
655 match alg {
656 Algorithm::Rs256 | Algorithm::Rs384 | Algorithm::Rs512 => {
658 Reflect::set(&obj, &"name".into(), &"RSASSA-PKCS1-v1_5".into())
659 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
660 }
661
662 Algorithm::Ps256 => {
664 Reflect::set(&obj, &"name".into(), &"RSA-PSS".into())
665 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
666 Reflect::set(&obj, &"saltLength".into(), &32.into())
667 .map_err(|e| Error::WebCrypto(format!("failed to set saltLength: {:?}", e)))?;
668 }
669 Algorithm::Ps384 => {
670 Reflect::set(&obj, &"name".into(), &"RSA-PSS".into())
671 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
672 Reflect::set(&obj, &"saltLength".into(), &48.into())
673 .map_err(|e| Error::WebCrypto(format!("failed to set saltLength: {:?}", e)))?;
674 }
675 Algorithm::Ps512 => {
676 Reflect::set(&obj, &"name".into(), &"RSA-PSS".into())
677 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
678 Reflect::set(&obj, &"saltLength".into(), &64.into())
679 .map_err(|e| Error::WebCrypto(format!("failed to set saltLength: {:?}", e)))?;
680 }
681
682 Algorithm::Es256 | Algorithm::Es384 | Algorithm::Es512 => {
684 Reflect::set(&obj, &"name".into(), &"ECDSA".into())
685 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
686
687 let hash = match alg {
688 Algorithm::Es256 => "SHA-256",
689 Algorithm::Es384 => "SHA-384",
690 Algorithm::Es512 => "SHA-512",
691 _ => unreachable!(),
692 };
693
694 let hash_obj = Object::new();
695 Reflect::set(&hash_obj, &"name".into(), &hash.into())
696 .map_err(|e| Error::WebCrypto(format!("failed to set hash name: {:?}", e)))?;
697 Reflect::set(&obj, &"hash".into(), &hash_obj.into())
698 .map_err(|e| Error::WebCrypto(format!("failed to set hash: {:?}", e)))?;
699 }
700
701 Algorithm::Hs256 | Algorithm::Hs384 | Algorithm::Hs512 => {
703 Reflect::set(&obj, &"name".into(), &"HMAC".into())
704 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
705 }
706
707 _ => {
708 return Err(Error::UnsupportedForWebCrypto {
709 reason: "algorithm not supported for WebCrypto verify",
710 });
711 }
712 }
713
714 Ok(obj)
715}
716
717pub async fn import_verify_key(key: &Key) -> Result<CryptoKey> {
754 import_key_for_usage(key, KeyUsage::Verify).await
755}
756
757pub async fn import_sign_key(key: &Key) -> Result<CryptoKey> {
777 import_key_for_usage(key, KeyUsage::Sign).await
778}
779
780pub async fn import_encrypt_key(key: &Key) -> Result<CryptoKey> {
797 if matches!(key.params(), KeyParams::Ec(_)) {
798 return Err(Error::UnsupportedForWebCrypto {
799 reason: "EC keys do not support direct encryption; \
800 use ECDH key agreement (deriveKey/deriveBits) instead",
801 });
802 }
803 import_key_for_usage(key, KeyUsage::Encrypt).await
804}
805
806pub async fn import_decrypt_key(key: &Key) -> Result<CryptoKey> {
819 if matches!(key.params(), KeyParams::Ec(_)) {
820 return Err(Error::UnsupportedForWebCrypto {
821 reason: "EC keys do not support direct decryption; \
822 use ECDH key agreement (deriveKey/deriveBits) instead",
823 });
824 }
825 import_key_for_usage(key, KeyUsage::Decrypt).await
826}
827
828pub async fn import_wrap_key(key: &Key) -> Result<CryptoKey> {
840 if matches!(key.params(), KeyParams::Ec(_)) {
841 return Err(Error::UnsupportedForWebCrypto {
842 reason: "EC keys do not support direct key wrapping; \
843 use ECDH key agreement (deriveKey/deriveBits) instead",
844 });
845 }
846 import_key_for_usage(key, KeyUsage::WrapKey).await
847}
848
849pub async fn import_unwrap_key(key: &Key) -> Result<CryptoKey> {
861 if matches!(key.params(), KeyParams::Ec(_)) {
862 return Err(Error::UnsupportedForWebCrypto {
863 reason: "EC keys do not support direct key unwrapping; \
864 use ECDH key agreement (deriveKey/deriveBits) instead",
865 });
866 }
867 import_key_for_usage(key, KeyUsage::UnwrapKey).await
868}
869
870pub async fn import_verify_key_for_alg(key: &Key, alg: &Algorithm) -> Result<CryptoKey> {
899 import_key_for_usage_with_alg(key, KeyUsage::Verify, alg).await
900}
901
902pub async fn import_sign_key_for_alg(key: &Key, alg: &Algorithm) -> Result<CryptoKey> {
912 import_key_for_usage_with_alg(key, KeyUsage::Sign, alg).await
913}
914
915pub async fn import_key_for_usage(key: &Key, usage: KeyUsage) -> Result<CryptoKey> {
927 validate_key_for_webcrypto_usage(key, usage)?;
928
929 let jwk = web_sys::JsonWebKey::try_from(key)?;
930 let algorithm = build_algorithm_object(key, usage)?;
931
932 import_crypto_key(jwk, &algorithm, usage_strings_for_usage(usage)).await
933}
934
935pub async fn import_key_for_usage_with_alg(
945 key: &Key,
946 usage: KeyUsage,
947 alg: &Algorithm,
948) -> Result<CryptoKey> {
949 validate_key_for_webcrypto_usage_with_alg(key, usage, alg)?;
950 let jwk = web_sys::JsonWebKey::try_from(key)?;
951
952 jwk.set_alg(alg.as_str());
958
959 let algorithm = build_algorithm_object_for_alg(key, alg, usage)?;
960
961 import_crypto_key(jwk, &algorithm, usage_strings_for_usage(usage)).await
962}
963
964async fn import_crypto_key(
966 jwk: web_sys::JsonWebKey,
967 algorithm: &Object,
968 usages: &[&str],
969) -> Result<CryptoKey> {
970 let key_usages = Array::new();
971 for u in usages {
972 key_usages.push(&JsValue::from_str(u));
973 }
974
975 let subtle = get_subtle_crypto()?;
976
977 let promise = subtle
979 .import_key_with_object("jwk", &jwk.into(), algorithm, false, &key_usages)
980 .map_err(|e| Error::WebCrypto(format!("import_key failed: {:?}", e)))?;
981
982 let result = JsFuture::from(promise)
983 .await
984 .map_err(|e| Error::WebCrypto(format!("import_key promise rejected: {:?}", e)))?;
985
986 Ok(result.unchecked_into())
987}
988
989impl Key {
994 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
1006 pub fn is_web_crypto_compatible(&self) -> bool {
1007 validate_webcrypto_support(self).is_ok()
1008 }
1009
1010 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
1022 pub async fn import_as_verify_key(&self) -> Result<CryptoKey> {
1023 import_verify_key(self).await
1024 }
1025
1026 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
1037 pub async fn import_as_sign_key(&self) -> Result<CryptoKey> {
1038 import_sign_key(self).await
1039 }
1040
1041 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
1048 pub async fn import_as_encrypt_key(&self) -> Result<CryptoKey> {
1049 import_encrypt_key(self).await
1050 }
1051
1052 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
1059 pub async fn import_as_decrypt_key(&self) -> Result<CryptoKey> {
1060 import_decrypt_key(self).await
1061 }
1062
1063 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
1075 pub async fn import_as_verify_key_for_alg(&self, alg: &Algorithm) -> Result<CryptoKey> {
1076 import_verify_key_for_alg(self, alg).await
1077 }
1078
1079 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
1089 pub async fn import_as_sign_key_for_alg(&self, alg: &Algorithm) -> Result<CryptoKey> {
1090 import_sign_key_for_alg(self, alg).await
1091 }
1092}
1093
1094#[cfg(test)]
1100mod validation_tests {
1101 use super::*;
1102 use crate::jwks::KeySet;
1103
1104 const RFC_RSA_PUBLIC_KEY: &str = r#"{
1105 "kty": "RSA",
1106 "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
1107 "e": "AQAB"
1108 }"#;
1109
1110 const RFC_EC_P256_PUBLIC_KEY: &str = r#"{
1111 "kty": "EC",
1112 "crv": "P-256",
1113 "x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
1114 "y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM"
1115 }"#;
1116
1117 const EC_SECP256K1_KEY: &str = r#"{
1118 "kty": "EC",
1119 "crv": "secp256k1",
1120 "x": "WbbXwISW8TLWM3IDLGm1cX_3IrYgWl_bzcLe0tSCDj4",
1121 "y": "KGk8DRQHPeV4S3Oq2jVJLNSV_3ngGgbfHTKsS5aw30c"
1122 }"#;
1123
1124 const OKP_ED25519_KEY: &str = r#"{
1125 "kty": "OKP",
1126 "crv": "Ed25519",
1127 "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
1128 }"#;
1129
1130 const SYMMETRIC_KEY: &str = r#"{
1131 "kty": "oct",
1132 "k": "AyM32w-8O0TGsGDYX0MlWy-9XQP-xrryrP7gkXKfY5WhoLxmT3fzfVr7LXqgDDFSfowWBY-u6bSH5f9kBZ_n7Q",
1133 "alg": "HS256"
1134 }"#;
1135
1136 #[test]
1137 fn test_validate_rsa_supported() {
1138 let key: Key = serde_json::from_str(RFC_RSA_PUBLIC_KEY).unwrap();
1139 assert!(validate_webcrypto_support(&key).is_ok());
1140 }
1141
1142 #[test]
1143 fn test_validate_ec_p256_supported() {
1144 let key: Key = serde_json::from_str(RFC_EC_P256_PUBLIC_KEY).unwrap();
1145 assert!(validate_webcrypto_support(&key).is_ok());
1146 }
1147
1148 #[test]
1149 fn test_validate_symmetric_supported() {
1150 let key: Key = serde_json::from_str(SYMMETRIC_KEY).unwrap();
1151 assert!(validate_webcrypto_support(&key).is_ok());
1152 }
1153
1154 #[test]
1155 fn test_validate_okp_unsupported() {
1156 let key: Key = serde_json::from_str(OKP_ED25519_KEY).unwrap();
1157 let result = validate_webcrypto_support(&key);
1158 assert!(matches!(result, Err(Error::UnsupportedForWebCrypto { .. })));
1159 }
1160
1161 #[test]
1162 fn test_validate_secp256k1_unsupported() {
1163 let key: Key = serde_json::from_str(EC_SECP256K1_KEY).unwrap();
1164 let result = validate_webcrypto_support(&key);
1165 assert!(matches!(result, Err(Error::UnsupportedForWebCrypto { .. })));
1166 }
1167
1168 #[test]
1169 fn test_is_web_crypto_compatible_rsa() {
1170 let key: Key = serde_json::from_str(RFC_RSA_PUBLIC_KEY).unwrap();
1171 assert!(key.is_web_crypto_compatible());
1172 }
1173
1174 #[test]
1175 fn test_is_web_crypto_compatible_okp() {
1176 let key: Key = serde_json::from_str(OKP_ED25519_KEY).unwrap();
1177 assert!(!key.is_web_crypto_compatible());
1178 }
1179
1180 #[test]
1181 fn test_is_web_crypto_compatible_secp256k1() {
1182 let key: Key = serde_json::from_str(EC_SECP256K1_KEY).unwrap();
1183 assert!(!key.is_web_crypto_compatible());
1184 }
1185
1186 #[test]
1187 fn test_usage_algorithm_compatibility_rejects_mismatch() {
1188 let result = validate_usage_algorithm_compatibility(KeyUsage::Encrypt, &Algorithm::Rs256);
1189 assert!(matches!(result, Err(Error::UnsupportedForWebCrypto { .. })));
1190
1191 let result =
1192 validate_usage_algorithm_compatibility(KeyUsage::Verify, &Algorithm::RsaOaep256);
1193 assert!(matches!(result, Err(Error::UnsupportedForWebCrypto { .. })));
1194 }
1195
1196 #[test]
1197 fn test_usage_algorithm_compatibility_accepts_valid_pairs() {
1198 assert!(
1199 validate_usage_algorithm_compatibility(KeyUsage::Verify, &Algorithm::Rs256).is_ok()
1200 );
1201 assert!(
1202 validate_usage_algorithm_compatibility(KeyUsage::Encrypt, &Algorithm::RsaOaep256)
1203 .is_ok()
1204 );
1205 assert!(
1206 validate_usage_algorithm_compatibility(KeyUsage::WrapKey, &Algorithm::A128kw).is_ok()
1207 );
1208 }
1209
1210 #[test]
1211 fn test_import_usage_validation_enforces_metadata_when_alg_present() {
1212 let key: Key = serde_json::from_str(SYMMETRIC_KEY).unwrap();
1213 let key = key.with_key_ops([crate::KeyOperation::Sign, crate::KeyOperation::Sign]);
1214
1215 let result = validate_key_for_webcrypto_usage(&key, KeyUsage::Sign);
1216 assert!(result.is_err(), "duplicate key_ops must be rejected");
1217 }
1218
1219 #[test]
1220 fn test_validate_key_for_webcrypto_usage_rejects_incompatible_use() {
1221 let json = r#"{
1222 "kty": "RSA",
1223 "use": "enc",
1224 "alg": "RS256",
1225 "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
1226 "e": "AQAB"
1227 }"#;
1228
1229 let key: Key = serde_json::from_str(json).unwrap();
1230 let result = validate_key_for_webcrypto_usage(&key, KeyUsage::Verify);
1231 assert!(result.is_err());
1232 }
1233
1234 #[test]
1235 fn test_validate_key_for_webcrypto_usage_allows_missing_optional_metadata() {
1236 let json = r#"{
1237 "kty": "RSA",
1238 "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
1239 "e": "AQAB"
1240 }"#;
1241
1242 let key: Key = serde_json::from_str(json).unwrap();
1243 let result = validate_key_for_webcrypto_usage(&key, KeyUsage::Verify);
1244 assert!(result.is_ok());
1245 }
1246
1247 #[test]
1248 fn test_validate_key_for_webcrypto_usage_rejects_incompatible_use_without_alg() {
1249 let json = r#"{
1250 "kty": "RSA",
1251 "use": "enc",
1252 "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
1253 "e": "AQAB"
1254 }"#;
1255
1256 let key: Key = serde_json::from_str(json).unwrap();
1257 let result = validate_key_for_webcrypto_usage(&key, KeyUsage::Verify);
1258 assert!(result.is_err());
1259 }
1260
1261 #[test]
1262 fn test_validate_key_for_webcrypto_usage_with_alg_allows_declared_algorithm_override() {
1263 let key: Key = serde_json::from_str(SYMMETRIC_KEY).unwrap();
1269
1270 let result =
1271 validate_key_for_webcrypto_usage_with_alg(&key, KeyUsage::Verify, &Algorithm::Hs384);
1272 assert!(
1273 result.is_ok(),
1274 "explicit alg override should skip declared-algorithm mismatch check: {result:?}"
1275 );
1276 }
1277
1278 #[test]
1279 fn test_validate_key_for_webcrypto_usage_rejects_public_sign_key_without_alg() {
1280 let json = r#"{
1281 "kty": "RSA",
1282 "use": "sig",
1283 "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
1284 "e": "AQAB"
1285 }"#;
1286
1287 let key: Key = serde_json::from_str(json).unwrap();
1288 let result = validate_key_for_webcrypto_usage(&key, KeyUsage::Sign);
1289 assert!(result.is_err());
1290 }
1291
1292 #[test]
1293 fn test_select_verify_key_strict_for_web_crypto_flow() {
1294 let json = r#"{"keys": [
1295 {"kty": "RSA", "kid": "rsa-verify", "use": "sig", "alg": "RS256", "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", "e": "AQAB"}
1296 ]}"#;
1297
1298 let jwks: KeySet = serde_json::from_str(json).unwrap();
1299 let key = jwks
1300 .selector(&[Algorithm::Rs256])
1301 .select(KeyMatcher::new(KeyOperation::Verify, Algorithm::Rs256).with_kid("rsa-verify"))
1302 .unwrap();
1303
1304 assert_eq!(key.kid(), Some("rsa-verify"));
1305 }
1306
1307 #[test]
1308 fn test_select_signing_key_strict_for_web_crypto_flow() {
1309 let json = r#"{"keys": [
1310 {"kty": "EC", "kid": "ec-sign", "use": "sig", "alg": "ES256", "crv": "P-256", "x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", "y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM", "d": "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE"}
1311 ]}"#;
1312
1313 let jwks: KeySet = serde_json::from_str(json).unwrap();
1314 let key = jwks
1315 .selector(&[])
1316 .select(KeyMatcher::new(KeyOperation::Sign, Algorithm::Es256).with_kid("ec-sign"))
1317 .unwrap();
1318
1319 assert_eq!(key.kid(), Some("ec-sign"));
1320 }
1321}
1322
1323#[cfg(all(test, target_arch = "wasm32"))]
1326mod tests {
1327 use super::*;
1328
1329 const RFC_RSA_PUBLIC_KEY: &str = r#"{
1331 "kty": "RSA",
1332 "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
1333 "e": "AQAB"
1334 }"#;
1335
1336 const RFC_EC_P256_PUBLIC_KEY: &str = r#"{
1338 "kty": "EC",
1339 "crv": "P-256",
1340 "x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
1341 "y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM"
1342 }"#;
1343
1344 const EC_SECP256K1_KEY: &str = r#"{
1346 "kty": "EC",
1347 "crv": "secp256k1",
1348 "x": "WbbXwISW8TLWM3IDLGm1cX_3IrYgWl_bzcLe0tSCDj4",
1349 "y": "KGk8DRQHPeV4S3Oq2jVJLNSV_3ngGgbfHTKsS5aw30c"
1350 }"#;
1351
1352 const OKP_ED25519_KEY: &str = r#"{
1354 "kty": "OKP",
1355 "crv": "Ed25519",
1356 "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
1357 }"#;
1358
1359 const SYMMETRIC_KEY: &str = r#"{
1361 "kty": "oct",
1362 "k": "AyM32w-8O0TGsGDYX0MlWy-9XQP-xrryrP7gkXKfY5WhoLxmT3fzfVr7LXqgDDFSfowWBY-u6bSH5f9kBZ_n7Q",
1363 "alg": "HS256"
1364 }"#;
1365
1366 #[test]
1367 fn test_rsa_key_to_json_web_key() {
1368 let key: Key = serde_json::from_str(RFC_RSA_PUBLIC_KEY).unwrap();
1369 let jwk = web_sys::JsonWebKey::try_from(&key).unwrap();
1370 assert_eq!(jwk.get_kty(), "RSA");
1371 assert!(jwk.get_n().is_some());
1372 assert!(jwk.get_e().is_some());
1373 assert!(jwk.get_d().is_none()); }
1375
1376 #[test]
1377 fn test_ec_p256_key_to_json_web_key() {
1378 let key: Key = serde_json::from_str(RFC_EC_P256_PUBLIC_KEY).unwrap();
1379 let jwk = web_sys::JsonWebKey::try_from(&key).unwrap();
1380 assert_eq!(jwk.get_kty(), "EC");
1381 assert_eq!(jwk.get_crv(), Some("P-256".to_string()));
1382 assert!(jwk.get_x().is_some());
1383 assert!(jwk.get_y().is_some());
1384 }
1385
1386 #[test]
1387 fn test_symmetric_key_to_json_web_key() {
1388 let key: Key = serde_json::from_str(SYMMETRIC_KEY).unwrap();
1389 let jwk = web_sys::JsonWebKey::try_from(&key).unwrap();
1390 assert_eq!(jwk.get_kty(), "oct");
1391 assert!(jwk.get_k().is_some());
1392 }
1393
1394 #[test]
1395 fn test_okp_key_unsupported() {
1396 let key: Key = serde_json::from_str(OKP_ED25519_KEY).unwrap();
1397 let result = web_sys::JsonWebKey::try_from(&key);
1398 assert!(matches!(result, Err(Error::UnsupportedForWebCrypto { .. })));
1399 }
1400
1401 #[test]
1402 fn test_secp256k1_key_unsupported() {
1403 let key: Key = serde_json::from_str(EC_SECP256K1_KEY).unwrap();
1404 let result = web_sys::JsonWebKey::try_from(&key);
1405 assert!(matches!(result, Err(Error::UnsupportedForWebCrypto { .. })));
1406 }
1407
1408 #[test]
1409 fn test_is_web_crypto_compatible() {
1410 let rsa_key: Key = serde_json::from_str(RFC_RSA_PUBLIC_KEY).unwrap();
1411 assert!(rsa_key.is_web_crypto_compatible());
1412
1413 let ec_key: Key = serde_json::from_str(RFC_EC_P256_PUBLIC_KEY).unwrap();
1414 assert!(ec_key.is_web_crypto_compatible());
1415
1416 let okp_key: Key = serde_json::from_str(OKP_ED25519_KEY).unwrap();
1417 assert!(!okp_key.is_web_crypto_compatible());
1418
1419 let secp256k1_key: Key = serde_json::from_str(EC_SECP256K1_KEY).unwrap();
1420 assert!(!secp256k1_key.is_web_crypto_compatible());
1421 }
1422
1423 #[test]
1424 fn test_validate_webcrypto_support_rsa() {
1425 let key: Key = serde_json::from_str(RFC_RSA_PUBLIC_KEY).unwrap();
1426 assert!(validate_webcrypto_support(&key).is_ok());
1427 }
1428
1429 #[test]
1430 fn test_validate_webcrypto_support_ec_p256() {
1431 let key: Key = serde_json::from_str(RFC_EC_P256_PUBLIC_KEY).unwrap();
1432 assert!(validate_webcrypto_support(&key).is_ok());
1433 }
1434
1435 #[test]
1436 fn test_validate_webcrypto_support_symmetric() {
1437 let key: Key = serde_json::from_str(SYMMETRIC_KEY).unwrap();
1438 assert!(validate_webcrypto_support(&key).is_ok());
1439 }
1440
1441 #[test]
1442 fn test_build_rsa_algorithm_with_explicit_alg() {
1443 let key: Key = serde_json::from_str(RFC_RSA_PUBLIC_KEY).unwrap();
1444 let alg =
1445 build_algorithm_object_for_alg(&key, &Algorithm::Rs256, KeyUsage::Verify).unwrap();
1446
1447 let name = Reflect::get(&alg, &"name".into()).unwrap();
1448 assert_eq!(name.as_string().unwrap(), "RSASSA-PKCS1-v1_5");
1449 }
1450
1451 #[test]
1452 fn test_build_rsa_algorithm_without_alg_errors() {
1453 let key: Key = serde_json::from_str(RFC_RSA_PUBLIC_KEY).unwrap();
1454 let result = build_algorithm_object(&key, KeyUsage::Verify);
1455 assert!(result.is_err(), "RSA key without alg should error");
1456 }
1457
1458 #[test]
1459 fn test_build_ec_algorithm() {
1460 let key: Key = serde_json::from_str(RFC_EC_P256_PUBLIC_KEY).unwrap();
1461 let alg = build_algorithm_object(&key, KeyUsage::Verify).unwrap();
1462
1463 let name = Reflect::get(&alg, &"name".into()).unwrap();
1464 assert_eq!(name.as_string().unwrap(), "ECDSA");
1465
1466 let curve = Reflect::get(&alg, &"namedCurve".into()).unwrap();
1467 assert_eq!(curve.as_string().unwrap(), "P-256");
1468 }
1469
1470 #[test]
1471 fn test_build_hmac_algorithm() {
1472 let key: Key = serde_json::from_str(SYMMETRIC_KEY).unwrap();
1473 let alg = build_algorithm_object(&key, KeyUsage::Sign).unwrap();
1474
1475 let name = Reflect::get(&alg, &"name".into()).unwrap();
1476 assert_eq!(name.as_string().unwrap(), "HMAC");
1477 }
1478
1479 #[test]
1480 fn test_build_verify_algorithm_rs256() {
1481 let alg = Algorithm::Rs256;
1482 let obj = build_verify_algorithm(&alg).unwrap();
1483
1484 let name = Reflect::get(&obj, &"name".into()).unwrap();
1485 assert_eq!(name.as_string().unwrap(), "RSASSA-PKCS1-v1_5");
1486
1487 let hash = Reflect::get(&obj, &"hash".into()).unwrap();
1489 assert!(hash.is_undefined());
1490 }
1491
1492 #[test]
1493 fn test_build_verify_algorithm_ps256() {
1494 let alg = Algorithm::Ps256;
1495 let obj = build_verify_algorithm(&alg).unwrap();
1496
1497 let name = Reflect::get(&obj, &"name".into()).unwrap();
1498 assert_eq!(name.as_string().unwrap(), "RSA-PSS");
1499
1500 let salt_length = Reflect::get(&obj, &"saltLength".into()).unwrap();
1501 assert_eq!(salt_length.as_f64().unwrap() as u32, 32);
1502 }
1503
1504 #[test]
1505 fn test_build_verify_algorithm_ps384() {
1506 let alg = Algorithm::Ps384;
1507 let obj = build_verify_algorithm(&alg).unwrap();
1508
1509 let salt_length = Reflect::get(&obj, &"saltLength".into()).unwrap();
1510 assert_eq!(salt_length.as_f64().unwrap() as u32, 48);
1511 }
1512
1513 #[test]
1514 fn test_build_verify_algorithm_ps512() {
1515 let alg = Algorithm::Ps512;
1516 let obj = build_verify_algorithm(&alg).unwrap();
1517
1518 let salt_length = Reflect::get(&obj, &"saltLength".into()).unwrap();
1519 assert_eq!(salt_length.as_f64().unwrap() as u32, 64);
1520 }
1521
1522 #[test]
1523 fn test_build_verify_algorithm_es256() {
1524 let alg = Algorithm::Es256;
1525 let obj = build_verify_algorithm(&alg).unwrap();
1526
1527 let name = Reflect::get(&obj, &"name".into()).unwrap();
1528 assert_eq!(name.as_string().unwrap(), "ECDSA");
1529
1530 let hash = Reflect::get(&obj, &"hash".into()).unwrap();
1531 let hash_name = Reflect::get(&hash, &"name".into()).unwrap();
1532 assert_eq!(hash_name.as_string().unwrap(), "SHA-256");
1533 }
1534
1535 #[test]
1536 fn test_build_verify_algorithm_es384() {
1537 let alg = Algorithm::Es384;
1538 let obj = build_verify_algorithm(&alg).unwrap();
1539
1540 let hash = Reflect::get(&obj, &"hash".into()).unwrap();
1541 let hash_name = Reflect::get(&hash, &"name".into()).unwrap();
1542 assert_eq!(hash_name.as_string().unwrap(), "SHA-384");
1543 }
1544
1545 #[test]
1546 fn test_build_verify_algorithm_es512() {
1547 let alg = Algorithm::Es512;
1548 let obj = build_verify_algorithm(&alg).unwrap();
1549
1550 let hash = Reflect::get(&obj, &"hash".into()).unwrap();
1551 let hash_name = Reflect::get(&hash, &"name".into()).unwrap();
1552 assert_eq!(hash_name.as_string().unwrap(), "SHA-512");
1553 }
1554
1555 #[test]
1556 fn test_build_verify_algorithm_hs256() {
1557 let alg = Algorithm::Hs256;
1558 let obj = build_verify_algorithm(&alg).unwrap();
1559
1560 let name = Reflect::get(&obj, &"name".into()).unwrap();
1561 assert_eq!(name.as_string().unwrap(), "HMAC");
1562 }
1563
1564 #[test]
1565 fn test_build_verify_algorithm_unsupported() {
1566 let alg = Algorithm::EdDsa;
1567 let result = build_verify_algorithm(&alg);
1568 assert!(result.is_err());
1569
1570 let alg = Algorithm::Ed25519;
1571 let result = build_verify_algorithm(&alg);
1572 assert!(result.is_err());
1573
1574 let alg = Algorithm::Ed448;
1575 let result = build_verify_algorithm(&alg);
1576 assert!(result.is_err());
1577 }
1578}