1use js_sys::{Array, Object, Reflect};
60use std::convert::TryFrom;
61use wasm_bindgen::prelude::*;
62use wasm_bindgen_futures::JsFuture;
63#[cfg(all(feature = "cloudflare", target_arch = "wasm32"))]
64use web_sys::Crypto;
65use web_sys::{CryptoKey, SubtleCrypto};
66
67use crate::error::{Error, Result};
68use crate::jwk::{Algorithm, EcCurve, Key, KeyOperation, KeyParams};
69#[cfg(test)]
70use crate::jwks::KeyMatcher;
71
72pub fn get_subtle_crypto() -> Result<SubtleCrypto> {
90 #[cfg(all(feature = "cloudflare", target_arch = "wasm32"))]
91 {
92 let global = js_sys::global();
95 let crypto_field_name = JsValue::from_str("crypto");
96 if let Ok(crypto_field) = Reflect::get(&global, &crypto_field_name)
97 && let Ok(crypto) = crypto_field.dyn_into::<Crypto>()
98 {
99 return Ok(crypto.subtle());
100 }
101 }
102
103 if let Some(window) = web_sys::window()
105 && let Ok(crypto) = window.crypto()
106 {
107 return Ok(crypto.subtle());
108 }
109
110 let global = js_sys::global();
112 if let Ok(worker_scope) = global.dyn_into::<web_sys::WorkerGlobalScope>()
113 && let Ok(crypto) = worker_scope.crypto()
114 {
115 return Ok(crypto.subtle());
116 }
117
118 Err(Error::WebCrypto(
119 "crypto API not available in this context".to_string(),
120 ))
121}
122
123impl TryFrom<&Key> for web_sys::JsonWebKey {
152 type Error = Error;
153
154 fn try_from(key: &Key) -> Result<Self> {
155 key.params().validate()?;
160
161 validate_webcrypto_support(key)?;
163
164 let jwk = web_sys::JsonWebKey::new(key.kty().as_str());
165
166 if let Some(alg) = key.alg() {
171 jwk.set_alg(alg.as_str());
172 }
173
174 if let Some(key_use) = key.key_use() {
175 jwk.set_use(key_use.as_str());
176 }
177
178 if let Some(key_ops) = key.key_ops() {
179 let ops = Array::new();
180 for op in key_ops {
181 ops.push(&JsValue::from_str(op.as_str()));
182 }
183 jwk.set_key_ops(&ops);
184 }
185
186 match key.params() {
188 KeyParams::Rsa(params) => {
189 jwk.set_n(¶ms.n.to_base64url());
191 jwk.set_e(¶ms.e.to_base64url());
192
193 if let Some(d) = ¶ms.d {
195 jwk.set_d(&d.to_base64url());
196 }
197 if let Some(p) = ¶ms.p {
198 jwk.set_p(&p.to_base64url());
199 }
200 if let Some(q) = ¶ms.q {
201 jwk.set_q(&q.to_base64url());
202 }
203 if let Some(dp) = ¶ms.dp {
204 jwk.set_dp(&dp.to_base64url());
205 }
206 if let Some(dq) = ¶ms.dq {
207 jwk.set_dq(&dq.to_base64url());
208 }
209 if let Some(qi) = ¶ms.qi {
210 jwk.set_qi(&qi.to_base64url());
211 }
212 }
214 KeyParams::Ec(params) => {
215 jwk.set_crv(params.crv.as_str());
216 jwk.set_x(¶ms.x.to_base64url());
217 jwk.set_y(¶ms.y.to_base64url());
218
219 if let Some(d) = ¶ms.d {
220 jwk.set_d(&d.to_base64url());
221 }
222 }
223 KeyParams::Symmetric(params) => {
224 jwk.set_k(¶ms.k.to_base64url());
225 }
226 KeyParams::Okp(_) => {
227 return Err(Error::UnsupportedForWebCrypto {
229 reason: "OKP keys (Ed25519, Ed448, X25519, X448) are not supported by WebCrypto",
230 });
231 }
232 }
233
234 Ok(jwk)
235 }
236}
237
238fn validate_webcrypto_support(key: &Key) -> Result<()> {
240 match key.params() {
241 KeyParams::Okp(_) => Err(Error::UnsupportedForWebCrypto {
242 reason: "OKP keys (Ed25519, Ed448, X25519, X448) are not supported by WebCrypto",
243 }),
244 KeyParams::Ec(params) => {
245 if params.crv == EcCurve::Secp256k1 {
246 Err(Error::UnsupportedForWebCrypto {
247 reason: "secp256k1 curve is not supported by WebCrypto",
248 })
249 } else {
250 Ok(())
251 }
252 }
253 KeyParams::Rsa(_) | KeyParams::Symmetric(_) => Ok(()),
254 }
255}
256
257fn build_algorithm_object(key: &Key, usage: KeyUsage) -> Result<Object> {
265 build_algorithm_object_with_alg(key, usage, None)
266}
267
268fn build_algorithm_object_for_alg(key: &Key, alg: &Algorithm, usage: KeyUsage) -> Result<Object> {
269 build_algorithm_object_with_alg(key, usage, Some(alg))
270}
271
272fn build_algorithm_object_with_alg(
273 key: &Key,
274 usage: KeyUsage,
275 alg_override: Option<&Algorithm>,
276) -> Result<Object> {
277 match key.params() {
278 KeyParams::Rsa(_) => build_rsa_algorithm(key, usage, alg_override),
279 KeyParams::Ec(params) => {
280 if let Some(alg) = alg_override {
286 let expected_curve = match alg {
287 Algorithm::Es256 => Some(EcCurve::P256),
288 Algorithm::Es384 => Some(EcCurve::P384),
289 Algorithm::Es512 => Some(EcCurve::P521),
290 _ => None,
291 };
292 match expected_curve {
293 Some(curve) if curve != params.crv => {
294 return Err(Error::WebCrypto(format!(
295 "algorithm {} requires curve {}, but the key uses {}",
296 alg.as_str(),
297 curve.as_str(),
298 params.crv.as_str(),
299 )));
300 }
301 None => {
302 return Err(Error::WebCrypto(format!(
303 "algorithm {} is not supported for EC key import in WebCrypto",
304 alg.as_str(),
305 )));
306 }
307 _ => {} }
309 }
310 build_ec_algorithm(params.crv, usage)
311 }
312 KeyParams::Symmetric(_) => build_symmetric_algorithm(key, usage, alg_override),
313 KeyParams::Okp(_) => Err(Error::UnsupportedForWebCrypto {
314 reason: "OKP keys are not supported by WebCrypto",
315 }),
316 }
317}
318
319fn validate_usage_algorithm_compatibility(usage: KeyUsage, alg: &Algorithm) -> Result<()> {
320 let allowed = match usage {
321 KeyUsage::Verify => 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::Sign => matches!(
337 alg,
338 Algorithm::Rs256
339 | Algorithm::Rs384
340 | Algorithm::Rs512
341 | Algorithm::Ps256
342 | Algorithm::Ps384
343 | Algorithm::Ps512
344 | Algorithm::Es256
345 | Algorithm::Es384
346 | Algorithm::Es512
347 | Algorithm::Hs256
348 | Algorithm::Hs384
349 | Algorithm::Hs512
350 ),
351 KeyUsage::Encrypt => matches!(
352 alg,
353 Algorithm::RsaOaep
354 | Algorithm::RsaOaep256
355 | Algorithm::RsaOaep384
356 | Algorithm::RsaOaep512
357 | Algorithm::A128gcm
358 | Algorithm::A192gcm
359 | Algorithm::A256gcm
360 ),
361 KeyUsage::Decrypt => matches!(
362 alg,
363 Algorithm::RsaOaep
364 | Algorithm::RsaOaep256
365 | Algorithm::RsaOaep384
366 | Algorithm::RsaOaep512
367 | Algorithm::A128gcm
368 | Algorithm::A192gcm
369 | Algorithm::A256gcm
370 ),
371 KeyUsage::WrapKey => matches!(
372 alg,
373 Algorithm::RsaOaep
374 | Algorithm::RsaOaep256
375 | Algorithm::RsaOaep384
376 | Algorithm::RsaOaep512
377 | Algorithm::A128kw
378 | Algorithm::A192kw
379 | Algorithm::A256kw
380 ),
381 KeyUsage::UnwrapKey => matches!(
382 alg,
383 Algorithm::RsaOaep
384 | Algorithm::RsaOaep256
385 | Algorithm::RsaOaep384
386 | Algorithm::RsaOaep512
387 | Algorithm::A128kw
388 | Algorithm::A192kw
389 | Algorithm::A256kw
390 ),
391 };
392
393 if allowed {
394 Ok(())
395 } else {
396 Err(Error::UnsupportedForWebCrypto {
397 reason: "algorithm is not compatible with requested key usage",
398 })
399 }
400}
401
402fn validate_key_for_webcrypto_usage_with_alg(
403 key: &Key,
404 usage: KeyUsage,
405 alg: &Algorithm,
406) -> Result<()> {
407 validate_usage_algorithm_compatibility(usage, alg)?;
408 key.validate_for_use_with_alg_override(alg, [key_operation_for_usage(usage)])
412}
413
414fn validate_key_for_webcrypto_usage(key: &Key, usage: KeyUsage) -> Result<()> {
415 let requested_op = key_operation_for_usage(usage);
416
417 if let Some(alg) = key.alg() {
418 validate_usage_algorithm_compatibility(usage, alg)?;
419 key.validate_for_use(alg, [requested_op])?;
420 return Ok(());
421 }
422
423 key.validate()?;
427 key.check_operation_capability(std::slice::from_ref(&requested_op))?;
428 key.validate_operation_intent_for_all(std::slice::from_ref(&requested_op))?;
429
430 Ok(())
431}
432
433fn key_operation_for_usage(usage: KeyUsage) -> KeyOperation {
434 match usage {
435 KeyUsage::Sign => KeyOperation::Sign,
436 KeyUsage::Verify => KeyOperation::Verify,
437 KeyUsage::Encrypt => KeyOperation::Encrypt,
438 KeyUsage::Decrypt => KeyOperation::Decrypt,
439 KeyUsage::WrapKey => KeyOperation::WrapKey,
440 KeyUsage::UnwrapKey => KeyOperation::UnwrapKey,
441 }
442}
443
444#[derive(Debug, Clone, Copy, PartialEq, Eq)]
450#[non_exhaustive]
451pub enum KeyUsage {
452 Sign,
454 Verify,
456 Encrypt,
458 Decrypt,
460 WrapKey,
462 UnwrapKey,
464}
465
466fn usage_strings_for_usage(usage: KeyUsage) -> &'static [&'static str] {
467 match usage {
468 KeyUsage::Sign => &["sign"],
469 KeyUsage::Verify => &["verify"],
470 KeyUsage::Encrypt => &["encrypt"],
471 KeyUsage::Decrypt => &["decrypt"],
472 KeyUsage::WrapKey => &["wrapKey"],
473 KeyUsage::UnwrapKey => &["unwrapKey"],
474 }
475}
476
477fn build_rsa_algorithm(
488 key: &Key,
489 _usage: KeyUsage,
490 alg_override: Option<&Algorithm>,
491) -> Result<Object> {
492 let obj = Object::new();
493
494 let effective_alg = alg_override.or(key.alg());
496
497 let (alg_name, hash) = match effective_alg {
499 Some(Algorithm::Rs256) => ("RSASSA-PKCS1-v1_5", "SHA-256"),
500 Some(Algorithm::Rs384) => ("RSASSA-PKCS1-v1_5", "SHA-384"),
501 Some(Algorithm::Rs512) => ("RSASSA-PKCS1-v1_5", "SHA-512"),
502 Some(Algorithm::Ps256) => ("RSA-PSS", "SHA-256"),
503 Some(Algorithm::Ps384) => ("RSA-PSS", "SHA-384"),
504 Some(Algorithm::Ps512) => ("RSA-PSS", "SHA-512"),
505 Some(Algorithm::RsaOaep) => ("RSA-OAEP", "SHA-1"),
506 Some(Algorithm::RsaOaep256) => ("RSA-OAEP", "SHA-256"),
507 Some(Algorithm::RsaOaep384) => ("RSA-OAEP", "SHA-384"),
508 Some(Algorithm::RsaOaep512) => ("RSA-OAEP", "SHA-512"),
509 _ => {
510 return Err(Error::WebCrypto(
511 "RSA key import requires an algorithm to determine the hash function; \
512 set the `alg` field on the key or use an import function that accepts \
513 an explicit algorithm (e.g., `import_verify_key_for_alg`)"
514 .to_string(),
515 ));
516 }
517 };
518
519 Reflect::set(&obj, &"name".into(), &alg_name.into())
520 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
521
522 let hash_obj = Object::new();
524 Reflect::set(&hash_obj, &"name".into(), &hash.into())
525 .map_err(|e| Error::WebCrypto(format!("failed to set hash name: {:?}", e)))?;
526 Reflect::set(&obj, &"hash".into(), &hash_obj.into())
527 .map_err(|e| Error::WebCrypto(format!("failed to set hash: {:?}", e)))?;
528
529 Ok(obj)
530}
531
532fn build_ec_algorithm(curve: EcCurve, usage: KeyUsage) -> Result<Object> {
534 let obj = Object::new();
535
536 let alg_name = match usage {
537 KeyUsage::Sign | KeyUsage::Verify => "ECDSA",
538 KeyUsage::Encrypt | KeyUsage::Decrypt | KeyUsage::WrapKey | KeyUsage::UnwrapKey => {
539 return Err(Error::UnsupportedForWebCrypto {
540 reason: "EC key derivation (ECDH) and direct encrypt/decrypt/wrap/unwrap \
541 are not yet supported by this library; \
542 only ECDSA sign/verify is currently implemented for EC keys",
543 });
544 }
545 };
546
547 Reflect::set(&obj, &"name".into(), &alg_name.into())
548 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
549
550 let named_curve = match curve {
551 EcCurve::P256 => "P-256",
552 EcCurve::P384 => "P-384",
553 EcCurve::P521 => "P-521",
554 EcCurve::Secp256k1 => {
555 return Err(Error::UnsupportedForWebCrypto {
556 reason: "secp256k1 curve is not supported by WebCrypto",
557 });
558 }
559 };
560
561 Reflect::set(&obj, &"namedCurve".into(), &named_curve.into())
562 .map_err(|e| Error::WebCrypto(format!("failed to set namedCurve: {:?}", e)))?;
563
564 Ok(obj)
565}
566
567fn build_symmetric_algorithm(
577 key: &Key,
578 _usage: KeyUsage,
579 alg_override: Option<&Algorithm>,
580) -> Result<Object> {
581 let obj = Object::new();
582
583 let effective_alg = alg_override.or(key.alg());
585
586 let (alg_name, extra) = match effective_alg {
587 Some(Algorithm::Hs256) => ("HMAC", Some(("hash", "SHA-256"))),
588 Some(Algorithm::Hs384) => ("HMAC", Some(("hash", "SHA-384"))),
589 Some(Algorithm::Hs512) => ("HMAC", Some(("hash", "SHA-512"))),
590 Some(Algorithm::A128kw) | Some(Algorithm::A192kw) | Some(Algorithm::A256kw) => {
594 ("AES-KW", None)
595 }
596 Some(Algorithm::A128gcm) | Some(Algorithm::A192gcm) | Some(Algorithm::A256gcm) => {
597 ("AES-GCM", None)
598 }
599 Some(Algorithm::A128cbcHs256)
600 | Some(Algorithm::A192cbcHs384)
601 | Some(Algorithm::A256cbcHs512) => {
602 return Err(Error::UnsupportedForWebCrypto {
603 reason: "AES-CBC-HS algorithms (A128CBC-HS256, A192CBC-HS384, A256CBC-HS512) \
604 are composite authenticated encryption algorithms requiring split-key \
605 handling (AES-CBC + HMAC) which WebCrypto does not natively support",
606 });
607 }
608 _ => {
609 return Err(Error::WebCrypto(
610 "symmetric key import requires an algorithm to determine the operation; \
611 set the `alg` field on the key or use an import function that accepts \
612 an explicit algorithm (e.g., `import_verify_key_for_alg`)"
613 .to_string(),
614 ));
615 }
616 };
617
618 Reflect::set(&obj, &"name".into(), &alg_name.into())
619 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
620
621 if let Some((prop, val)) = extra {
622 debug_assert_eq!(prop, "hash", "only HMAC uses extra parameters");
623 let hash_obj = Object::new();
624 Reflect::set(&hash_obj, &"name".into(), &val.into())
625 .map_err(|e| Error::WebCrypto(format!("failed to set hash name: {:?}", e)))?;
626 Reflect::set(&obj, &"hash".into(), &hash_obj.into())
627 .map_err(|e| Error::WebCrypto(format!("failed to set hash: {:?}", e)))?;
628 }
629
630 Ok(obj)
631}
632
633pub fn build_verify_algorithm(alg: &Algorithm) -> Result<Object> {
668 let obj = Object::new();
669
670 match alg {
671 Algorithm::Rs256 | Algorithm::Rs384 | Algorithm::Rs512 => {
673 Reflect::set(&obj, &"name".into(), &"RSASSA-PKCS1-v1_5".into())
674 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
675 }
676
677 Algorithm::Ps256 => {
679 Reflect::set(&obj, &"name".into(), &"RSA-PSS".into())
680 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
681 Reflect::set(&obj, &"saltLength".into(), &32.into())
682 .map_err(|e| Error::WebCrypto(format!("failed to set saltLength: {:?}", e)))?;
683 }
684 Algorithm::Ps384 => {
685 Reflect::set(&obj, &"name".into(), &"RSA-PSS".into())
686 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
687 Reflect::set(&obj, &"saltLength".into(), &48.into())
688 .map_err(|e| Error::WebCrypto(format!("failed to set saltLength: {:?}", e)))?;
689 }
690 Algorithm::Ps512 => {
691 Reflect::set(&obj, &"name".into(), &"RSA-PSS".into())
692 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
693 Reflect::set(&obj, &"saltLength".into(), &64.into())
694 .map_err(|e| Error::WebCrypto(format!("failed to set saltLength: {:?}", e)))?;
695 }
696
697 Algorithm::Es256 | Algorithm::Es384 | Algorithm::Es512 => {
699 Reflect::set(&obj, &"name".into(), &"ECDSA".into())
700 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
701
702 let hash = match alg {
703 Algorithm::Es256 => "SHA-256",
704 Algorithm::Es384 => "SHA-384",
705 Algorithm::Es512 => "SHA-512",
706 _ => unreachable!(),
707 };
708
709 let hash_obj = Object::new();
710 Reflect::set(&hash_obj, &"name".into(), &hash.into())
711 .map_err(|e| Error::WebCrypto(format!("failed to set hash name: {:?}", e)))?;
712 Reflect::set(&obj, &"hash".into(), &hash_obj.into())
713 .map_err(|e| Error::WebCrypto(format!("failed to set hash: {:?}", e)))?;
714 }
715
716 Algorithm::Hs256 | Algorithm::Hs384 | Algorithm::Hs512 => {
718 Reflect::set(&obj, &"name".into(), &"HMAC".into())
719 .map_err(|e| Error::WebCrypto(format!("failed to set algorithm name: {:?}", e)))?;
720 }
721
722 _ => {
723 return Err(Error::UnsupportedForWebCrypto {
724 reason: "algorithm not supported for WebCrypto verify",
725 });
726 }
727 }
728
729 Ok(obj)
730}
731
732pub async fn import_verify_key(key: &Key) -> Result<CryptoKey> {
769 import_key_for_usage(key, KeyUsage::Verify).await
770}
771
772pub async fn import_sign_key(key: &Key) -> Result<CryptoKey> {
792 import_key_for_usage(key, KeyUsage::Sign).await
793}
794
795pub async fn import_encrypt_key(key: &Key) -> Result<CryptoKey> {
812 if matches!(key.params(), KeyParams::Ec(_)) {
813 return Err(Error::UnsupportedForWebCrypto {
814 reason: "EC keys do not support direct encryption; \
815 use ECDH key agreement (deriveKey/deriveBits) instead",
816 });
817 }
818 import_key_for_usage(key, KeyUsage::Encrypt).await
819}
820
821pub async fn import_decrypt_key(key: &Key) -> Result<CryptoKey> {
834 if matches!(key.params(), KeyParams::Ec(_)) {
835 return Err(Error::UnsupportedForWebCrypto {
836 reason: "EC keys do not support direct decryption; \
837 use ECDH key agreement (deriveKey/deriveBits) instead",
838 });
839 }
840 import_key_for_usage(key, KeyUsage::Decrypt).await
841}
842
843pub async fn import_wrap_key(key: &Key) -> Result<CryptoKey> {
855 if matches!(key.params(), KeyParams::Ec(_)) {
856 return Err(Error::UnsupportedForWebCrypto {
857 reason: "EC keys do not support direct key wrapping; \
858 use ECDH key agreement (deriveKey/deriveBits) instead",
859 });
860 }
861 import_key_for_usage(key, KeyUsage::WrapKey).await
862}
863
864pub async fn import_unwrap_key(key: &Key) -> Result<CryptoKey> {
876 if matches!(key.params(), KeyParams::Ec(_)) {
877 return Err(Error::UnsupportedForWebCrypto {
878 reason: "EC keys do not support direct key unwrapping; \
879 use ECDH key agreement (deriveKey/deriveBits) instead",
880 });
881 }
882 import_key_for_usage(key, KeyUsage::UnwrapKey).await
883}
884
885pub async fn import_verify_key_for_alg(key: &Key, alg: &Algorithm) -> Result<CryptoKey> {
914 import_key_for_usage_with_alg(key, KeyUsage::Verify, alg).await
915}
916
917pub async fn import_sign_key_for_alg(key: &Key, alg: &Algorithm) -> Result<CryptoKey> {
927 import_key_for_usage_with_alg(key, KeyUsage::Sign, alg).await
928}
929
930pub async fn import_key_for_usage(key: &Key, usage: KeyUsage) -> Result<CryptoKey> {
942 validate_key_for_webcrypto_usage(key, usage)?;
943
944 let jwk = web_sys::JsonWebKey::try_from(key)?;
945 let algorithm = build_algorithm_object(key, usage)?;
946
947 import_crypto_key(jwk, &algorithm, usage_strings_for_usage(usage)).await
948}
949
950pub async fn import_key_for_usage_with_alg(
960 key: &Key,
961 usage: KeyUsage,
962 alg: &Algorithm,
963) -> Result<CryptoKey> {
964 validate_key_for_webcrypto_usage_with_alg(key, usage, alg)?;
965 let jwk = web_sys::JsonWebKey::try_from(key)?;
966
967 jwk.set_alg(alg.as_str());
973
974 let algorithm = build_algorithm_object_for_alg(key, alg, usage)?;
975
976 import_crypto_key(jwk, &algorithm, usage_strings_for_usage(usage)).await
977}
978
979async fn import_crypto_key(
981 jwk: web_sys::JsonWebKey,
982 algorithm: &Object,
983 usages: &[&str],
984) -> Result<CryptoKey> {
985 let key_usages = Array::new();
986 for u in usages {
987 key_usages.push(&JsValue::from_str(u));
988 }
989
990 let subtle = get_subtle_crypto()?;
991
992 let promise = subtle
994 .import_key_with_object("jwk", &jwk.into(), algorithm, false, &key_usages)
995 .map_err(|e| Error::WebCrypto(format!("import_key failed: {:?}", e)))?;
996
997 let result = JsFuture::from(promise)
998 .await
999 .map_err(|e| Error::WebCrypto(format!("import_key promise rejected: {:?}", e)))?;
1000
1001 Ok(result.unchecked_into())
1002}
1003
1004impl Key {
1009 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
1021 pub fn is_web_crypto_compatible(&self) -> bool {
1022 validate_webcrypto_support(self).is_ok()
1023 }
1024
1025 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
1037 pub async fn import_as_verify_key(&self) -> Result<CryptoKey> {
1038 import_verify_key(self).await
1039 }
1040
1041 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
1052 pub async fn import_as_sign_key(&self) -> Result<CryptoKey> {
1053 import_sign_key(self).await
1054 }
1055
1056 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
1063 pub async fn import_as_encrypt_key(&self) -> Result<CryptoKey> {
1064 import_encrypt_key(self).await
1065 }
1066
1067 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
1074 pub async fn import_as_decrypt_key(&self) -> Result<CryptoKey> {
1075 import_decrypt_key(self).await
1076 }
1077
1078 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
1090 pub async fn import_as_verify_key_for_alg(&self, alg: &Algorithm) -> Result<CryptoKey> {
1091 import_verify_key_for_alg(self, alg).await
1092 }
1093
1094 #[cfg_attr(docsrs, doc(cfg(feature = "web-crypto")))]
1104 pub async fn import_as_sign_key_for_alg(&self, alg: &Algorithm) -> Result<CryptoKey> {
1105 import_sign_key_for_alg(self, alg).await
1106 }
1107}
1108
1109#[cfg(test)]
1115mod validation_tests {
1116 use super::*;
1117 use crate::jwks::KeySet;
1118
1119 const RFC_RSA_PUBLIC_KEY: &str = r#"{
1120 "kty": "RSA",
1121 "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
1122 "e": "AQAB"
1123 }"#;
1124
1125 const RFC_EC_P256_PUBLIC_KEY: &str = r#"{
1126 "kty": "EC",
1127 "crv": "P-256",
1128 "x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
1129 "y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM"
1130 }"#;
1131
1132 const EC_SECP256K1_KEY: &str = r#"{
1133 "kty": "EC",
1134 "crv": "secp256k1",
1135 "x": "WbbXwISW8TLWM3IDLGm1cX_3IrYgWl_bzcLe0tSCDj4",
1136 "y": "KGk8DRQHPeV4S3Oq2jVJLNSV_3ngGgbfHTKsS5aw30c"
1137 }"#;
1138
1139 const OKP_ED25519_KEY: &str = r#"{
1140 "kty": "OKP",
1141 "crv": "Ed25519",
1142 "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
1143 }"#;
1144
1145 const SYMMETRIC_KEY: &str = r#"{
1146 "kty": "oct",
1147 "k": "AyM32w-8O0TGsGDYX0MlWy-9XQP-xrryrP7gkXKfY5WhoLxmT3fzfVr7LXqgDDFSfowWBY-u6bSH5f9kBZ_n7Q",
1148 "alg": "HS256"
1149 }"#;
1150
1151 #[test]
1152 fn test_validate_rsa_supported() {
1153 let key: Key = serde_json::from_str(RFC_RSA_PUBLIC_KEY).unwrap();
1154 assert!(validate_webcrypto_support(&key).is_ok());
1155 }
1156
1157 #[test]
1158 fn test_validate_ec_p256_supported() {
1159 let key: Key = serde_json::from_str(RFC_EC_P256_PUBLIC_KEY).unwrap();
1160 assert!(validate_webcrypto_support(&key).is_ok());
1161 }
1162
1163 #[test]
1164 fn test_validate_symmetric_supported() {
1165 let key: Key = serde_json::from_str(SYMMETRIC_KEY).unwrap();
1166 assert!(validate_webcrypto_support(&key).is_ok());
1167 }
1168
1169 #[test]
1170 fn test_validate_okp_unsupported() {
1171 let key: Key = serde_json::from_str(OKP_ED25519_KEY).unwrap();
1172 let result = validate_webcrypto_support(&key);
1173 assert!(matches!(result, Err(Error::UnsupportedForWebCrypto { .. })));
1174 }
1175
1176 #[test]
1177 fn test_validate_secp256k1_unsupported() {
1178 let key: Key = serde_json::from_str(EC_SECP256K1_KEY).unwrap();
1179 let result = validate_webcrypto_support(&key);
1180 assert!(matches!(result, Err(Error::UnsupportedForWebCrypto { .. })));
1181 }
1182
1183 #[test]
1184 fn test_is_web_crypto_compatible_rsa() {
1185 let key: Key = serde_json::from_str(RFC_RSA_PUBLIC_KEY).unwrap();
1186 assert!(key.is_web_crypto_compatible());
1187 }
1188
1189 #[test]
1190 fn test_is_web_crypto_compatible_okp() {
1191 let key: Key = serde_json::from_str(OKP_ED25519_KEY).unwrap();
1192 assert!(!key.is_web_crypto_compatible());
1193 }
1194
1195 #[test]
1196 fn test_is_web_crypto_compatible_secp256k1() {
1197 let key: Key = serde_json::from_str(EC_SECP256K1_KEY).unwrap();
1198 assert!(!key.is_web_crypto_compatible());
1199 }
1200
1201 #[test]
1202 fn test_usage_algorithm_compatibility_rejects_mismatch() {
1203 let result = validate_usage_algorithm_compatibility(KeyUsage::Encrypt, &Algorithm::Rs256);
1204 assert!(matches!(result, Err(Error::UnsupportedForWebCrypto { .. })));
1205
1206 let result =
1207 validate_usage_algorithm_compatibility(KeyUsage::Verify, &Algorithm::RsaOaep256);
1208 assert!(matches!(result, Err(Error::UnsupportedForWebCrypto { .. })));
1209 }
1210
1211 #[test]
1212 fn test_usage_algorithm_compatibility_accepts_valid_pairs() {
1213 assert!(
1214 validate_usage_algorithm_compatibility(KeyUsage::Verify, &Algorithm::Rs256).is_ok()
1215 );
1216 assert!(
1217 validate_usage_algorithm_compatibility(KeyUsage::Encrypt, &Algorithm::RsaOaep256)
1218 .is_ok()
1219 );
1220 assert!(
1221 validate_usage_algorithm_compatibility(KeyUsage::WrapKey, &Algorithm::A128kw).is_ok()
1222 );
1223 }
1224
1225 #[test]
1226 fn test_import_usage_validation_enforces_metadata_when_alg_present() {
1227 let key: Key = serde_json::from_str(SYMMETRIC_KEY).unwrap();
1228 let key = key.with_key_ops([crate::KeyOperation::Sign, crate::KeyOperation::Sign]);
1229
1230 let result = validate_key_for_webcrypto_usage(&key, KeyUsage::Sign);
1231 assert!(result.is_err(), "duplicate key_ops must be rejected");
1232 }
1233
1234 #[test]
1235 fn test_validate_key_for_webcrypto_usage_rejects_incompatible_use() {
1236 let json = r#"{
1237 "kty": "RSA",
1238 "use": "enc",
1239 "alg": "RS256",
1240 "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
1241 "e": "AQAB"
1242 }"#;
1243
1244 let key: Key = serde_json::from_str(json).unwrap();
1245 let result = validate_key_for_webcrypto_usage(&key, KeyUsage::Verify);
1246 assert!(result.is_err());
1247 }
1248
1249 #[test]
1250 fn test_validate_key_for_webcrypto_usage_allows_missing_optional_metadata() {
1251 let json = r#"{
1252 "kty": "RSA",
1253 "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
1254 "e": "AQAB"
1255 }"#;
1256
1257 let key: Key = serde_json::from_str(json).unwrap();
1258 let result = validate_key_for_webcrypto_usage(&key, KeyUsage::Verify);
1259 assert!(result.is_ok());
1260 }
1261
1262 #[test]
1263 fn test_validate_key_for_webcrypto_usage_rejects_incompatible_use_without_alg() {
1264 let json = r#"{
1265 "kty": "RSA",
1266 "use": "enc",
1267 "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
1268 "e": "AQAB"
1269 }"#;
1270
1271 let key: Key = serde_json::from_str(json).unwrap();
1272 let result = validate_key_for_webcrypto_usage(&key, KeyUsage::Verify);
1273 assert!(result.is_err());
1274 }
1275
1276 #[test]
1277 fn test_validate_key_for_webcrypto_usage_with_alg_allows_declared_algorithm_override() {
1278 let key: Key = serde_json::from_str(SYMMETRIC_KEY).unwrap();
1284
1285 let result =
1286 validate_key_for_webcrypto_usage_with_alg(&key, KeyUsage::Verify, &Algorithm::Hs384);
1287 assert!(
1288 result.is_ok(),
1289 "explicit alg override should skip declared-algorithm mismatch check: {result:?}"
1290 );
1291 }
1292
1293 #[test]
1294 fn test_validate_key_for_webcrypto_usage_rejects_public_sign_key_without_alg() {
1295 let json = r#"{
1296 "kty": "RSA",
1297 "use": "sig",
1298 "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
1299 "e": "AQAB"
1300 }"#;
1301
1302 let key: Key = serde_json::from_str(json).unwrap();
1303 let result = validate_key_for_webcrypto_usage(&key, KeyUsage::Sign);
1304 assert!(result.is_err());
1305 }
1306
1307 #[test]
1308 fn test_select_verify_key_strict_for_web_crypto_flow() {
1309 let json = r#"{"keys": [
1310 {"kty": "RSA", "kid": "rsa-verify", "use": "sig", "alg": "RS256", "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", "e": "AQAB"}
1311 ]}"#;
1312
1313 let jwks: KeySet = serde_json::from_str(json).unwrap();
1314 let key = jwks
1315 .selector(&[Algorithm::Rs256])
1316 .select(KeyMatcher::new(KeyOperation::Verify, Algorithm::Rs256).with_kid("rsa-verify"))
1317 .unwrap();
1318
1319 assert_eq!(key.kid(), Some("rsa-verify"));
1320 }
1321
1322 #[test]
1323 fn test_select_signing_key_strict_for_web_crypto_flow() {
1324 let json = r#"{"keys": [
1325 {"kty": "EC", "kid": "ec-sign", "use": "sig", "alg": "ES256", "crv": "P-256", "x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", "y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM", "d": "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE"}
1326 ]}"#;
1327
1328 let jwks: KeySet = serde_json::from_str(json).unwrap();
1329 let key = jwks
1330 .selector(&[])
1331 .select(KeyMatcher::new(KeyOperation::Sign, Algorithm::Es256).with_kid("ec-sign"))
1332 .unwrap();
1333
1334 assert_eq!(key.kid(), Some("ec-sign"));
1335 }
1336}
1337
1338#[cfg(all(test, target_arch = "wasm32"))]
1341mod tests {
1342 use super::*;
1343
1344 const RFC_RSA_PUBLIC_KEY: &str = r#"{
1346 "kty": "RSA",
1347 "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
1348 "e": "AQAB"
1349 }"#;
1350
1351 const RFC_EC_P256_PUBLIC_KEY: &str = r#"{
1353 "kty": "EC",
1354 "crv": "P-256",
1355 "x": "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
1356 "y": "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM"
1357 }"#;
1358
1359 const EC_SECP256K1_KEY: &str = r#"{
1361 "kty": "EC",
1362 "crv": "secp256k1",
1363 "x": "WbbXwISW8TLWM3IDLGm1cX_3IrYgWl_bzcLe0tSCDj4",
1364 "y": "KGk8DRQHPeV4S3Oq2jVJLNSV_3ngGgbfHTKsS5aw30c"
1365 }"#;
1366
1367 const OKP_ED25519_KEY: &str = r#"{
1369 "kty": "OKP",
1370 "crv": "Ed25519",
1371 "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
1372 }"#;
1373
1374 const SYMMETRIC_KEY: &str = r#"{
1376 "kty": "oct",
1377 "k": "AyM32w-8O0TGsGDYX0MlWy-9XQP-xrryrP7gkXKfY5WhoLxmT3fzfVr7LXqgDDFSfowWBY-u6bSH5f9kBZ_n7Q",
1378 "alg": "HS256"
1379 }"#;
1380
1381 #[test]
1382 fn test_rsa_key_to_json_web_key() {
1383 let key: Key = serde_json::from_str(RFC_RSA_PUBLIC_KEY).unwrap();
1384 let jwk = web_sys::JsonWebKey::try_from(&key).unwrap();
1385 assert_eq!(jwk.get_kty(), "RSA");
1386 assert!(jwk.get_n().is_some());
1387 assert!(jwk.get_e().is_some());
1388 assert!(jwk.get_d().is_none()); }
1390
1391 #[test]
1392 fn test_ec_p256_key_to_json_web_key() {
1393 let key: Key = serde_json::from_str(RFC_EC_P256_PUBLIC_KEY).unwrap();
1394 let jwk = web_sys::JsonWebKey::try_from(&key).unwrap();
1395 assert_eq!(jwk.get_kty(), "EC");
1396 assert_eq!(jwk.get_crv(), Some("P-256".to_string()));
1397 assert!(jwk.get_x().is_some());
1398 assert!(jwk.get_y().is_some());
1399 }
1400
1401 #[test]
1402 fn test_symmetric_key_to_json_web_key() {
1403 let key: Key = serde_json::from_str(SYMMETRIC_KEY).unwrap();
1404 let jwk = web_sys::JsonWebKey::try_from(&key).unwrap();
1405 assert_eq!(jwk.get_kty(), "oct");
1406 assert!(jwk.get_k().is_some());
1407 }
1408
1409 #[test]
1410 fn test_okp_key_unsupported() {
1411 let key: Key = serde_json::from_str(OKP_ED25519_KEY).unwrap();
1412 let result = web_sys::JsonWebKey::try_from(&key);
1413 assert!(matches!(result, Err(Error::UnsupportedForWebCrypto { .. })));
1414 }
1415
1416 #[test]
1417 fn test_secp256k1_key_unsupported() {
1418 let key: Key = serde_json::from_str(EC_SECP256K1_KEY).unwrap();
1419 let result = web_sys::JsonWebKey::try_from(&key);
1420 assert!(matches!(result, Err(Error::UnsupportedForWebCrypto { .. })));
1421 }
1422
1423 #[test]
1424 fn test_is_web_crypto_compatible() {
1425 let rsa_key: Key = serde_json::from_str(RFC_RSA_PUBLIC_KEY).unwrap();
1426 assert!(rsa_key.is_web_crypto_compatible());
1427
1428 let ec_key: Key = serde_json::from_str(RFC_EC_P256_PUBLIC_KEY).unwrap();
1429 assert!(ec_key.is_web_crypto_compatible());
1430
1431 let okp_key: Key = serde_json::from_str(OKP_ED25519_KEY).unwrap();
1432 assert!(!okp_key.is_web_crypto_compatible());
1433
1434 let secp256k1_key: Key = serde_json::from_str(EC_SECP256K1_KEY).unwrap();
1435 assert!(!secp256k1_key.is_web_crypto_compatible());
1436 }
1437
1438 #[test]
1439 fn test_validate_webcrypto_support_rsa() {
1440 let key: Key = serde_json::from_str(RFC_RSA_PUBLIC_KEY).unwrap();
1441 assert!(validate_webcrypto_support(&key).is_ok());
1442 }
1443
1444 #[test]
1445 fn test_validate_webcrypto_support_ec_p256() {
1446 let key: Key = serde_json::from_str(RFC_EC_P256_PUBLIC_KEY).unwrap();
1447 assert!(validate_webcrypto_support(&key).is_ok());
1448 }
1449
1450 #[test]
1451 fn test_validate_webcrypto_support_symmetric() {
1452 let key: Key = serde_json::from_str(SYMMETRIC_KEY).unwrap();
1453 assert!(validate_webcrypto_support(&key).is_ok());
1454 }
1455
1456 #[test]
1457 fn test_build_rsa_algorithm_with_explicit_alg() {
1458 let key: Key = serde_json::from_str(RFC_RSA_PUBLIC_KEY).unwrap();
1459 let alg =
1460 build_algorithm_object_for_alg(&key, &Algorithm::Rs256, KeyUsage::Verify).unwrap();
1461
1462 let name = Reflect::get(&alg, &"name".into()).unwrap();
1463 assert_eq!(name.as_string().unwrap(), "RSASSA-PKCS1-v1_5");
1464 }
1465
1466 #[test]
1467 fn test_build_rsa_algorithm_without_alg_errors() {
1468 let key: Key = serde_json::from_str(RFC_RSA_PUBLIC_KEY).unwrap();
1469 let result = build_algorithm_object(&key, KeyUsage::Verify);
1470 assert!(result.is_err(), "RSA key without alg should error");
1471 }
1472
1473 #[test]
1474 fn test_build_ec_algorithm() {
1475 let key: Key = serde_json::from_str(RFC_EC_P256_PUBLIC_KEY).unwrap();
1476 let alg = build_algorithm_object(&key, KeyUsage::Verify).unwrap();
1477
1478 let name = Reflect::get(&alg, &"name".into()).unwrap();
1479 assert_eq!(name.as_string().unwrap(), "ECDSA");
1480
1481 let curve = Reflect::get(&alg, &"namedCurve".into()).unwrap();
1482 assert_eq!(curve.as_string().unwrap(), "P-256");
1483 }
1484
1485 #[test]
1486 fn test_build_hmac_algorithm() {
1487 let key: Key = serde_json::from_str(SYMMETRIC_KEY).unwrap();
1488 let alg = build_algorithm_object(&key, KeyUsage::Sign).unwrap();
1489
1490 let name = Reflect::get(&alg, &"name".into()).unwrap();
1491 assert_eq!(name.as_string().unwrap(), "HMAC");
1492 }
1493
1494 #[test]
1495 fn test_build_verify_algorithm_rs256() {
1496 let alg = Algorithm::Rs256;
1497 let obj = build_verify_algorithm(&alg).unwrap();
1498
1499 let name = Reflect::get(&obj, &"name".into()).unwrap();
1500 assert_eq!(name.as_string().unwrap(), "RSASSA-PKCS1-v1_5");
1501
1502 let hash = Reflect::get(&obj, &"hash".into()).unwrap();
1504 assert!(hash.is_undefined());
1505 }
1506
1507 #[test]
1508 fn test_build_verify_algorithm_ps256() {
1509 let alg = Algorithm::Ps256;
1510 let obj = build_verify_algorithm(&alg).unwrap();
1511
1512 let name = Reflect::get(&obj, &"name".into()).unwrap();
1513 assert_eq!(name.as_string().unwrap(), "RSA-PSS");
1514
1515 let salt_length = Reflect::get(&obj, &"saltLength".into()).unwrap();
1516 assert_eq!(salt_length.as_f64().unwrap() as u32, 32);
1517 }
1518
1519 #[test]
1520 fn test_build_verify_algorithm_ps384() {
1521 let alg = Algorithm::Ps384;
1522 let obj = build_verify_algorithm(&alg).unwrap();
1523
1524 let salt_length = Reflect::get(&obj, &"saltLength".into()).unwrap();
1525 assert_eq!(salt_length.as_f64().unwrap() as u32, 48);
1526 }
1527
1528 #[test]
1529 fn test_build_verify_algorithm_ps512() {
1530 let alg = Algorithm::Ps512;
1531 let obj = build_verify_algorithm(&alg).unwrap();
1532
1533 let salt_length = Reflect::get(&obj, &"saltLength".into()).unwrap();
1534 assert_eq!(salt_length.as_f64().unwrap() as u32, 64);
1535 }
1536
1537 #[test]
1538 fn test_build_verify_algorithm_es256() {
1539 let alg = Algorithm::Es256;
1540 let obj = build_verify_algorithm(&alg).unwrap();
1541
1542 let name = Reflect::get(&obj, &"name".into()).unwrap();
1543 assert_eq!(name.as_string().unwrap(), "ECDSA");
1544
1545 let hash = Reflect::get(&obj, &"hash".into()).unwrap();
1546 let hash_name = Reflect::get(&hash, &"name".into()).unwrap();
1547 assert_eq!(hash_name.as_string().unwrap(), "SHA-256");
1548 }
1549
1550 #[test]
1551 fn test_build_verify_algorithm_es384() {
1552 let alg = Algorithm::Es384;
1553 let obj = build_verify_algorithm(&alg).unwrap();
1554
1555 let hash = Reflect::get(&obj, &"hash".into()).unwrap();
1556 let hash_name = Reflect::get(&hash, &"name".into()).unwrap();
1557 assert_eq!(hash_name.as_string().unwrap(), "SHA-384");
1558 }
1559
1560 #[test]
1561 fn test_build_verify_algorithm_es512() {
1562 let alg = Algorithm::Es512;
1563 let obj = build_verify_algorithm(&alg).unwrap();
1564
1565 let hash = Reflect::get(&obj, &"hash".into()).unwrap();
1566 let hash_name = Reflect::get(&hash, &"name".into()).unwrap();
1567 assert_eq!(hash_name.as_string().unwrap(), "SHA-512");
1568 }
1569
1570 #[test]
1571 fn test_build_verify_algorithm_hs256() {
1572 let alg = Algorithm::Hs256;
1573 let obj = build_verify_algorithm(&alg).unwrap();
1574
1575 let name = Reflect::get(&obj, &"name".into()).unwrap();
1576 assert_eq!(name.as_string().unwrap(), "HMAC");
1577 }
1578
1579 #[test]
1580 fn test_build_verify_algorithm_unsupported() {
1581 let alg = Algorithm::EdDsa;
1582 let result = build_verify_algorithm(&alg);
1583 assert!(result.is_err());
1584
1585 let alg = Algorithm::Ed25519;
1586 let result = build_verify_algorithm(&alg);
1587 assert!(result.is_err());
1588
1589 let alg = Algorithm::Ed448;
1590 let result = build_verify_algorithm(&alg);
1591 assert!(result.is_err());
1592 }
1593}