1use polymorph_webcrypto_core::{
17 served_sha2, AeadKeyMaterial, DecryptionKeyMaterial, DigestKind, EncryptionKeyMaterial,
18 KwKeyMaterial, MacKeyMaterial, Sha1Posture, SigPublic, SigningKeyMaterial, WrapFormat,
19 WrapInputMaterial, HMAC_NAME,
20};
21use wasmtime::component::{Accessor, Resource, StreamReader};
22use wasmtime::Result;
23
24use crate::bindings::webcrypto::aead::{self, HostAeadKey, HostAeadKeyWithStore};
25use crate::bindings::webcrypto::cipher::{
26 self as cipher_iface, HostCipherKey, HostCipherKeyWithStore,
27};
28use crate::bindings::webcrypto::derivation::{
29 self as derivation_iface, HostDeriveInput, HostDeriveInputWithStore,
30};
31use crate::bindings::webcrypto::digest::{HostDigest, HostDigestWithStore};
32use crate::bindings::webcrypto::hkdf::{self as hkdf_iface, HostIkm, HostIkmWithStore};
33use crate::bindings::webcrypto::key_agreement::{
34 self as key_agreement_iface, HostPublicKey, HostPublicKeyWithStore, HostSecretKey,
35 HostSecretKeyWithStore,
36};
37use crate::bindings::webcrypto::key_wrap::{
38 self as key_wrap_iface, HostKwKey, HostKwKeyOptionsWithStore, HostKwKeyWithStore,
39};
40use crate::bindings::webcrypto::mac::{self, HostMacKey, HostMacKeyWithStore};
41use crate::bindings::webcrypto::pbkdf2::{
42 self as pbkdf2_iface, HostPassword, HostPasswordWithStore,
43};
44use crate::bindings::webcrypto::public_encryption::{
45 self as public_encryption_iface, HostDecryptionKey, HostDecryptionKeyWithStore,
46 HostEncryptionKey, HostEncryptionKeyWithStore,
47};
48use crate::bindings::webcrypto::types::{self, Error};
49use crate::bindings::webcrypto::wrapping::{
50 self as wrapping_iface, HostUnwrapInput, HostUnwrapInputWithStore, HostWrapInput,
51 HostWrapInputWithStore,
52};
53use crate::bindings::webcrypto::{
54 aes_cbc as aes_cbc_iface, aes_ctr as aes_ctr_iface, aes_gcm as aes_gcm_iface,
55 aes_kw as aes_kw_iface, digest as digest_iface, ecdh as ecdh_iface,
56 ecdsa_sign as ecdsa_sign_iface, ecdsa_verify as ecdsa_verify_iface,
57 ed25519_sign as ed25519_sign_iface, ed25519_verify as ed25519_verify_iface,
58 hkdf_sha1 as hkdf_sha1_iface, hkdf_sha2 as hkdf_sha2_iface, hmac_sha1 as hmac_sha1_iface,
59 hmac_sha2 as hmac_sha2_iface, pbkdf2_sha1 as pbkdf2_sha1_iface,
60 pbkdf2_sha2 as pbkdf2_sha2_iface, rsa as rsa_iface, rsa_oaep_decrypt as rsa_oaep_decrypt_iface,
61 rsa_oaep_encrypt as rsa_oaep_encrypt_iface, rsa_pss_sign as rsa_pss_sign_iface,
62 rsa_pss_verify as rsa_pss_verify_iface, rsassa_pkcs1_v15_sign as rsassa_sign_iface,
63 rsassa_pkcs1_v15_verify as rsassa_verify_iface, sha1_checked as sha1_checked_iface,
64 sha2 as sha2_iface, signature as signature_iface, x25519 as x25519_iface,
65};
66use crate::limits::{admit_input, Reservation};
67use crate::streams::{drain_stream, GuardedOutput};
68use crate::{
69 AeadKey, AgreementPublicKey, AgreementSecretKey, CipherKey, DecryptionKey, DeriveInput, Digest,
70 EncryptionKey, Ikm, KwKey, MacKey, Minted, Password, SigningKey, UnwrapInput, VerifyingKey,
71 WasiWebcrypto, WasiWebcryptoCtxView, WrapInput,
72};
73
74polymorph_webcrypto_core::impl_conversions! {
77 error: Error,
78 extension: types::ExtensionError,
79 sha2: sha2_iface::Sha2Variant,
80 aes: aes_gcm_iface::AesVariant,
81 ecdsa: ecdsa_verify_iface::EcdsaVariant,
82 ecdh: ecdh_iface::EcdhVariant,
83 rsa: rsa_iface::RsaVariant,
84}
85
86fn rng_trap(what: &str) -> impl Fn(polymorph_webcrypto_core::RngError) -> wasmtime::Error + '_ {
90 move |err| wasmtime::Error::msg(format!("{what} failed: {err}"))
91}
92
93fn retention_message(limit: u64) -> String {
97 format!(
98 "minted resources exceed the retention limit ({limit} bytes); see \
99 WasiWebcryptoCtx::set_retention_limit"
100 )
101}
102
103fn retention_exhausted(limit: u64) -> Error {
106 Error::Other(retention_message(limit))
107}
108
109fn charge_floor_or_trap(ctx: &crate::WasiWebcryptoCtx) -> Result<Reservation> {
113 ctx.charge_retention(0)
114 .ok_or_else(|| wasmtime::Error::msg(retention_message(ctx.retention_limit_bytes())))
115}
116
117async fn take_options<T: Send, O: Send + 'static>(
120 accessor: &Accessor<T, WasiWebcrypto>,
121 options: Resource<O>,
122) -> Result<O> {
123 accessor.with(|mut access| Ok(access.get().table.delete(options)?))
124}
125
126async fn mint<T: Send, R: Minted + Send + 'static>(
133 accessor: &Accessor<T, WasiWebcrypto>,
134 minted: std::result::Result<R::Payload, polymorph_webcrypto_core::Error>,
135) -> Result<std::result::Result<Resource<R>, Error>> {
136 let payload = match minted {
137 Ok(payload) => payload,
138 Err(err) => return Ok(Err(err.into())),
139 };
140 accessor.with(|mut access| {
141 let view = access.get();
142 match view.ctx.charge_retention(R::payload_bytes(&payload)) {
143 Some(retention) => Ok(Ok(view.table.push(R::minted(payload, retention))?)),
144 None => Ok(Err(retention_exhausted(view.ctx.retention_limit_bytes()))),
145 }
146 })
147}
148
149async fn mint_key_pair<T: Send, A, B>(
153 accessor: &Accessor<T, WasiWebcrypto>,
154 first: A::Payload,
155 second: B::Payload,
156) -> Result<std::result::Result<(Resource<A>, Resource<B>), Error>>
157where
158 A: Minted + Send + 'static,
159 B: Minted + Send + 'static,
160{
161 accessor.with(|mut access| {
162 let view = access.get();
163 let (Some(r1), Some(r2)) = (view.ctx.charge_retention(0), view.ctx.charge_retention(0))
164 else {
165 return Ok(Err(retention_exhausted(view.ctx.retention_limit_bytes())));
166 };
167 let a = view.table.push(A::minted(first, r1))?;
168 let b = view.table.push(B::minted(second, r2))?;
169 Ok(Ok((a, b)))
170 })
171}
172
173async fn with_resource<T: Send, R: 'static, O>(
175 accessor: &Accessor<T, WasiWebcrypto>,
176 self_: Resource<R>,
177 op: impl FnOnce(&R) -> O,
178) -> Result<O> {
179 accessor.with(|mut access| Ok(op(access.get().table.get(&self_)?)))
180}
181
182async fn to_wrap_input<T: Send, R: 'static>(
185 accessor: &Accessor<T, WasiWebcrypto>,
186 self_: Resource<R>,
187 format: WrapFormat,
188 serialize: impl FnOnce(&R) -> std::result::Result<Vec<u8>, polymorph_webcrypto_core::Error>,
189) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
190 let material = with_resource(accessor, self_, |key| {
191 serialize(key).map(|bytes| WrapInputMaterial::new(format, bytes))
192 })
193 .await?;
194 mint(accessor, material).await
195}
196
197async fn drop_resource<T: Send, R: 'static>(
200 accessor: &Accessor<T, WasiWebcrypto>,
201 rep: Resource<R>,
202) -> Result<()> {
203 accessor.with(|mut access| {
204 access.get().table.delete(rep)?;
205 Ok(())
206 })
207}
208
209macro_rules! host_options {
215 (
216 $iface:ident::{$host:ident, $host_with_store:ident} for $ty:ty {
217 $($method:ident => $field:ident),+ $(,)?
218 }
219 ) => {
220 impl $iface::$host for WasiWebcryptoCtxView<'_> {
221 fn new(&mut self) -> Result<Resource<$ty>> {
222 let retention = charge_floor_or_trap(self.ctx)?;
223 Ok(self
224 .table
225 .push(<$ty>::minted(Default::default(), retention))?)
226 }
227
228 $(
229 fn $method(&mut self, self_: Resource<$ty>, allowed: bool) -> Result<()> {
230 self.table.get_mut(&self_)?.policy.$field = allowed;
231 Ok(())
232 }
233 )+
234 }
235
236 impl<T: Send> $iface::$host_with_store<T> for WasiWebcrypto {
237 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<$ty>) -> Result<()> {
238 drop_resource(accessor, rep).await
239 }
240 }
241 };
242}
243
244async fn drain_then<T: Send, R: 'static, O>(
250 accessor: &Accessor<T, WasiWebcrypto>,
251 self_: Resource<R>,
252 data: StreamReader<u8>,
253 op: impl FnOnce(&R, &[u8]) -> std::result::Result<O, Error>,
254) -> Result<std::result::Result<O, Error>> {
255 let (_reservation, cap) = admit_input(accessor).await?;
256 let bytes = match drain_stream(accessor, data, cap).await? {
257 Ok(bytes) => bytes,
258 Err(err) => return Ok(Err(err)),
259 };
260 accessor.with(|mut access| Ok(op(access.get().table.get(&self_)?, &bytes)))
261}
262
263async fn drain_then_stream<T: Send, R: 'static>(
270 accessor: &Accessor<T, WasiWebcrypto>,
271 self_: Resource<R>,
272 input: StreamReader<u8>,
273 op: impl FnOnce(&mut R, &[u8]) -> Result<std::result::Result<Vec<u8>, Error>>,
274) -> Result<std::result::Result<StreamReader<u8>, Error>> {
275 let (reservation, cap) = admit_input(accessor).await?;
276 let msg = match drain_stream(accessor, input, cap).await? {
277 Ok(msg) => msg,
278 Err(err) => return Ok(Err(err)),
279 };
280 let out = accessor.with(|mut access| op(access.get().table.get_mut(&self_)?, &msg))?;
281 let out = match out {
282 Ok(out) => out,
283 Err(err) => return Ok(Err(err)),
284 };
285 let reader =
286 accessor.with(|access| StreamReader::new(access, GuardedOutput::new(out, reservation)))?;
287 Ok(Ok(reader))
288}
289
290impl types::Host for WasiWebcryptoCtxView<'_> {}
293
294impl mac::Host for WasiWebcryptoCtxView<'_> {}
297
298impl HostMacKey for WasiWebcryptoCtxView<'_> {
299 fn algorithm_name(&mut self, self_: Resource<MacKey>) -> Result<String> {
300 self.table.get(&self_)?;
301 Ok(HMAC_NAME.to_string())
302 }
303
304 fn algorithm_hash(&mut self, self_: Resource<MacKey>) -> Result<Option<String>> {
305 Ok(Some(
306 self.table.get(&self_)?.material.hash_name().to_string(),
307 ))
308 }
309
310 fn algorithm_length(&mut self, self_: Resource<MacKey>) -> Result<u32> {
311 Ok(self.table.get(&self_)?.material.length_bits())
312 }
313
314 fn extractable(&mut self, self_: Resource<MacKey>) -> Result<bool> {
315 Ok(self.table.get(&self_)?.material.extractable())
316 }
317
318 fn can_sign(&mut self, self_: Resource<MacKey>) -> Result<bool> {
319 Ok(self.table.get(&self_)?.material.can_sign())
320 }
321
322 fn can_verify(&mut self, self_: Resource<MacKey>) -> Result<bool> {
323 Ok(self.table.get(&self_)?.material.can_verify())
324 }
325}
326
327host_options! {
328 mac::{HostMacKeyOptions, HostMacKeyOptionsWithStore} for crate::MacKeyOptions {
329 can_sign => sign,
330 can_verify => verify,
331 extractable => extractable,
332 }
333}
334
335impl<T: Send> HostMacKeyWithStore<T> for WasiWebcrypto {
336 async fn sign(
337 accessor: &Accessor<T, Self>,
338 self_: Resource<MacKey>,
339 data: StreamReader<u8>,
340 ) -> Result<std::result::Result<Vec<u8>, Error>> {
341 drain_then(accessor, self_, data, |key, bytes| {
344 key.material.sign(bytes).map_err(Error::from)
345 })
346 .await
347 }
348
349 async fn verify(
350 accessor: &Accessor<T, Self>,
351 self_: Resource<MacKey>,
352 data: StreamReader<u8>,
353 tag: Vec<u8>,
354 ) -> Result<std::result::Result<(), Error>> {
355 drain_then(accessor, self_, data, |key, bytes| {
356 key.material.verify(bytes, &tag).map_err(Error::from)
357 })
358 .await
359 }
360
361 async fn export_key_raw(
362 accessor: &Accessor<T, Self>,
363 self_: Resource<MacKey>,
364 ) -> Result<std::result::Result<Vec<u8>, Error>> {
365 with_resource(accessor, self_, |key| {
366 key.material.export().map_err(Error::from)
367 })
368 .await
369 }
370
371 async fn export_key_jwk(
372 accessor: &Accessor<T, Self>,
373 self_: Resource<MacKey>,
374 ) -> Result<std::result::Result<String, Error>> {
375 with_resource(accessor, self_, |key| {
376 key.material.export_jwk().map_err(Error::from)
377 })
378 .await
379 }
380
381 async fn to_wrap_input_raw(
382 accessor: &Accessor<T, Self>,
383 self_: Resource<MacKey>,
384 ) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
385 to_wrap_input(accessor, self_, WrapFormat::Raw, |key| {
386 key.material.export()
387 })
388 .await
389 }
390
391 async fn to_wrap_input_jwk(
392 accessor: &Accessor<T, Self>,
393 self_: Resource<MacKey>,
394 ) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
395 to_wrap_input(accessor, self_, WrapFormat::Jwk, |key| {
396 key.material.export_jwk().map(String::into_bytes)
397 })
398 .await
399 }
400
401 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<MacKey>) -> Result<()> {
402 drop_resource(accessor, rep).await
403 }
404}
405
406impl aead::Host for WasiWebcryptoCtxView<'_> {}
409
410impl HostAeadKey for WasiWebcryptoCtxView<'_> {
411 fn algorithm_name(&mut self, self_: Resource<AeadKey>) -> Result<String> {
412 Ok(self.table.get(&self_)?.material.name().to_string())
413 }
414
415 fn algorithm_length(&mut self, self_: Resource<AeadKey>) -> Result<u32> {
416 Ok(self.table.get(&self_)?.material.length_bits())
417 }
418
419 fn nonce_size(&mut self, self_: Resource<AeadKey>) -> Result<u32> {
420 Ok(self.table.get(&self_)?.material.nonce_len() as u32)
421 }
422
423 fn tag_size(&mut self, self_: Resource<AeadKey>) -> Result<u32> {
424 Ok(self.table.get(&self_)?.material.tag_len() as u32)
425 }
426
427 fn extractable(&mut self, self_: Resource<AeadKey>) -> Result<bool> {
428 Ok(self.table.get(&self_)?.material.extractable())
429 }
430
431 fn can_seal(&mut self, self_: Resource<AeadKey>) -> Result<bool> {
432 Ok(self.table.get(&self_)?.material.can_seal())
433 }
434
435 fn can_open(&mut self, self_: Resource<AeadKey>) -> Result<bool> {
436 Ok(self.table.get(&self_)?.material.can_open())
437 }
438
439 fn can_wrap(&mut self, self_: Resource<AeadKey>) -> Result<bool> {
440 Ok(self.table.get(&self_)?.material.can_wrap())
441 }
442
443 fn can_unwrap(&mut self, self_: Resource<AeadKey>) -> Result<bool> {
444 Ok(self.table.get(&self_)?.material.can_unwrap())
445 }
446}
447
448host_options! {
449 aead::{HostAeadKeyOptions, HostAeadKeyOptionsWithStore} for crate::AeadKeyOptions {
450 can_seal => seal,
451 can_open => open,
452 can_wrap => wrap,
453 can_unwrap => unwrap,
454 extractable => extractable,
455 }
456}
457
458impl<T: Send> HostAeadKeyWithStore<T> for WasiWebcrypto {
459 async fn seal(
460 accessor: &Accessor<T, Self>,
461 self_: Resource<AeadKey>,
462 nonce: Vec<u8>,
463 aad: Vec<u8>,
464 tag_size: Option<u8>,
465 plaintext: StreamReader<u8>,
466 ) -> Result<std::result::Result<StreamReader<u8>, Error>> {
467 drain_then_stream(accessor, self_, plaintext, |key, msg| {
468 Ok(key
469 .material
470 .seal(&nonce, &aad, tag_size, msg)
471 .map_err(Error::from))
472 })
473 .await
474 }
475
476 async fn open(
477 accessor: &Accessor<T, Self>,
478 self_: Resource<AeadKey>,
479 nonce: Vec<u8>,
480 aad: Vec<u8>,
481 tag_size: Option<u8>,
482 ciphertext: StreamReader<u8>,
483 ) -> Result<std::result::Result<StreamReader<u8>, Error>> {
484 drain_then_stream(accessor, self_, ciphertext, |key, msg| {
485 Ok(key
486 .material
487 .open(&nonce, &aad, tag_size, msg)
488 .map_err(Error::from))
489 })
490 .await
491 }
492
493 async fn export_key_raw(
494 accessor: &Accessor<T, Self>,
495 self_: Resource<AeadKey>,
496 ) -> Result<std::result::Result<Vec<u8>, Error>> {
497 with_resource(accessor, self_, |key| {
498 key.material.export().map_err(Error::from)
499 })
500 .await
501 }
502
503 async fn export_key_jwk(
504 accessor: &Accessor<T, Self>,
505 self_: Resource<AeadKey>,
506 ) -> Result<std::result::Result<String, Error>> {
507 with_resource(accessor, self_, |key| {
508 key.material.export_jwk().map_err(Error::from)
509 })
510 .await
511 }
512
513 async fn wrap(
514 accessor: &Accessor<T, Self>,
515 self_: Resource<AeadKey>,
516 nonce: Vec<u8>,
517 aad: Vec<u8>,
518 tag_size: Option<u8>,
519 input: Resource<WrapInput>,
520 ) -> Result<std::result::Result<Vec<u8>, Error>> {
521 let input = take_options(accessor, input).await?.material;
522 with_resource(accessor, self_, |key| {
523 key.material
524 .wrap(&nonce, &aad, tag_size, input)
525 .map_err(Error::from)
526 })
527 .await
528 }
529
530 async fn unwrap(
531 accessor: &Accessor<T, Self>,
532 self_: Resource<AeadKey>,
533 nonce: Vec<u8>,
534 aad: Vec<u8>,
535 tag_size: Option<u8>,
536 wrapped: Vec<u8>,
537 ) -> Result<std::result::Result<Resource<UnwrapInput>, Error>> {
538 let material = with_resource(accessor, self_, |key| {
539 key.material
540 .unwrap_wrapped(&nonce, &aad, tag_size, &wrapped)
541 })
542 .await?;
543 mint(accessor, material).await
544 }
545
546 async fn to_wrap_input_raw(
547 accessor: &Accessor<T, Self>,
548 self_: Resource<AeadKey>,
549 ) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
550 to_wrap_input(accessor, self_, WrapFormat::Raw, |key| {
551 key.material.export()
552 })
553 .await
554 }
555
556 async fn to_wrap_input_jwk(
557 accessor: &Accessor<T, Self>,
558 self_: Resource<AeadKey>,
559 ) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
560 to_wrap_input(accessor, self_, WrapFormat::Jwk, |key| {
561 key.material.export_jwk().map(String::into_bytes)
562 })
563 .await
564 }
565
566 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<AeadKey>) -> Result<()> {
567 drop_resource(accessor, rep).await
568 }
569}
570
571impl cipher_iface::Host for WasiWebcryptoCtxView<'_> {}
574
575impl HostCipherKey for WasiWebcryptoCtxView<'_> {
576 fn algorithm_name(&mut self, self_: Resource<CipherKey>) -> Result<String> {
577 Ok(self.table.get(&self_)?.material.name().to_string())
578 }
579
580 fn algorithm_length(&mut self, self_: Resource<CipherKey>) -> Result<u32> {
581 Ok(self.table.get(&self_)?.material.length_bits())
582 }
583
584 fn iv_size(&mut self, self_: Resource<CipherKey>) -> Result<u32> {
585 let _ = self.table.get(&self_)?;
586 Ok(16)
587 }
588
589 fn extractable(&mut self, self_: Resource<CipherKey>) -> Result<bool> {
590 Ok(self.table.get(&self_)?.material.policy().extractable)
591 }
592
593 fn can_encrypt(&mut self, self_: Resource<CipherKey>) -> Result<bool> {
594 Ok(self.table.get(&self_)?.material.policy().encrypt)
595 }
596
597 fn can_decrypt(&mut self, self_: Resource<CipherKey>) -> Result<bool> {
598 Ok(self.table.get(&self_)?.material.policy().decrypt)
599 }
600
601 fn can_wrap(&mut self, self_: Resource<CipherKey>) -> Result<bool> {
602 Ok(self.table.get(&self_)?.material.policy().wrap)
603 }
604
605 fn can_unwrap(&mut self, self_: Resource<CipherKey>) -> Result<bool> {
606 Ok(self.table.get(&self_)?.material.policy().unwrap)
607 }
608}
609
610host_options! {
611 cipher_iface::{HostCipherKeyOptions, HostCipherKeyOptionsWithStore}
612 for crate::CipherKeyOptions {
613 can_encrypt => encrypt,
614 can_decrypt => decrypt,
615 can_wrap => wrap,
616 can_unwrap => unwrap,
617 extractable => extractable,
618 }
619}
620
621impl<T: Send> HostCipherKeyWithStore<T> for WasiWebcrypto {
622 async fn encrypt(
623 accessor: &Accessor<T, Self>,
624 self_: Resource<CipherKey>,
625 iv: Vec<u8>,
626 counter_length: Option<u8>,
627 plaintext: StreamReader<u8>,
628 ) -> Result<std::result::Result<StreamReader<u8>, Error>> {
629 drain_then_stream(accessor, self_, plaintext, |key, msg| {
630 Ok(key
631 .material
632 .encrypt(&iv, counter_length, msg)
633 .map_err(Error::from))
634 })
635 .await
636 }
637
638 async fn decrypt(
639 accessor: &Accessor<T, Self>,
640 self_: Resource<CipherKey>,
641 iv: Vec<u8>,
642 counter_length: Option<u8>,
643 ciphertext: StreamReader<u8>,
644 ) -> Result<std::result::Result<StreamReader<u8>, Error>> {
645 drain_then_stream(accessor, self_, ciphertext, |key, msg| {
646 Ok(key
647 .material
648 .decrypt(&iv, counter_length, msg)
649 .map_err(Error::from))
650 })
651 .await
652 }
653
654 async fn export_key_raw(
655 accessor: &Accessor<T, Self>,
656 self_: Resource<CipherKey>,
657 ) -> Result<std::result::Result<Vec<u8>, Error>> {
658 with_resource(accessor, self_, |key| {
659 key.material.export().map_err(Error::from)
660 })
661 .await
662 }
663
664 async fn export_key_jwk(
665 accessor: &Accessor<T, Self>,
666 self_: Resource<CipherKey>,
667 ) -> Result<std::result::Result<String, Error>> {
668 with_resource(accessor, self_, |key| {
669 key.material.export_jwk().map_err(Error::from)
670 })
671 .await
672 }
673
674 async fn wrap(
675 accessor: &Accessor<T, Self>,
676 self_: Resource<CipherKey>,
677 iv: Vec<u8>,
678 counter_length: Option<u8>,
679 input: Resource<WrapInput>,
680 ) -> Result<std::result::Result<Vec<u8>, Error>> {
681 let input = take_options(accessor, input).await?.material;
682 with_resource(accessor, self_, |key| {
683 key.material
684 .wrap(&iv, counter_length, input)
685 .map_err(Error::from)
686 })
687 .await
688 }
689
690 async fn unwrap(
691 accessor: &Accessor<T, Self>,
692 self_: Resource<CipherKey>,
693 iv: Vec<u8>,
694 counter_length: Option<u8>,
695 wrapped: Vec<u8>,
696 ) -> Result<std::result::Result<Resource<UnwrapInput>, Error>> {
697 let material = with_resource(accessor, self_, |key| {
698 key.material.unwrap_wrapped(&iv, counter_length, &wrapped)
699 })
700 .await?;
701 mint(accessor, material).await
702 }
703
704 async fn to_wrap_input_raw(
705 accessor: &Accessor<T, Self>,
706 self_: Resource<CipherKey>,
707 ) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
708 to_wrap_input(accessor, self_, WrapFormat::Raw, |key| {
709 key.material.export()
710 })
711 .await
712 }
713
714 async fn to_wrap_input_jwk(
715 accessor: &Accessor<T, Self>,
716 self_: Resource<CipherKey>,
717 ) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
718 to_wrap_input(accessor, self_, WrapFormat::Jwk, |key| {
719 key.material.export_jwk().map(String::into_bytes)
720 })
721 .await
722 }
723
724 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<CipherKey>) -> Result<()> {
725 drop_resource(accessor, rep).await
726 }
727}
728
729macro_rules! cipher_minting {
734 ($iface:path, $mode:expr) => {
735 const _: () = {
736 use $iface as iface;
737
738 impl iface::Host for WasiWebcryptoCtxView<'_> {}
739
740 impl<T: Send> iface::HostWithStore<T> for WasiWebcrypto {
741 async fn import_key_raw(
742 accessor: &Accessor<T, Self>,
743 variant: iface::AesVariant,
744 raw: Vec<u8>,
745 options: Resource<crate::CipherKeyOptions>,
746 ) -> Result<std::result::Result<Resource<CipherKey>, Error>> {
747 let policy = take_options(accessor, options).await?.policy;
748 let material = polymorph_webcrypto_core::CipherKeyMaterial::import(
749 $mode,
750 variant.into(),
751 raw,
752 policy,
753 );
754 mint(accessor, material).await
755 }
756
757 async fn import_key_jwk(
758 accessor: &Accessor<T, Self>,
759 variant: iface::AesVariant,
760 jwk: String,
761 options: Resource<crate::CipherKeyOptions>,
762 ) -> Result<std::result::Result<Resource<CipherKey>, Error>> {
763 let policy = take_options(accessor, options).await?.policy;
764 let material = polymorph_webcrypto_core::CipherKeyMaterial::import_jwk(
765 $mode,
766 variant.into(),
767 &jwk,
768 policy,
769 );
770 mint(accessor, material).await
771 }
772
773 async fn generate_key(
774 accessor: &Accessor<T, Self>,
775 variant: iface::AesVariant,
776 options: Resource<crate::CipherKeyOptions>,
777 ) -> Result<std::result::Result<Resource<CipherKey>, Error>> {
778 let policy = take_options(accessor, options).await?.policy;
779 let material = polymorph_webcrypto_core::CipherKeyMaterial::generate(
780 $mode,
781 variant.into(),
782 policy,
783 )
784 .map_err(rng_trap("random key generation"))?;
785 mint(accessor, material).await
786 }
787
788 async fn derive_key(
789 accessor: &Accessor<T, Self>,
790 variant: iface::AesVariant,
791 input: Resource<DeriveInput>,
792 options: Resource<crate::CipherKeyOptions>,
793 ) -> Result<std::result::Result<Resource<CipherKey>, Error>> {
794 let policy = take_options(accessor, options).await?.policy;
795 let material = with_resource(accessor, input, |input| {
796 polymorph_webcrypto_core::derive_cipher_key(
797 &input.material,
798 $mode,
799 variant.into(),
800 policy,
801 )
802 })
803 .await?;
804 mint(accessor, material).await
805 }
806
807 async fn unwrap_key_raw(
808 accessor: &Accessor<T, Self>,
809 variant: iface::AesVariant,
810 input: Resource<UnwrapInput>,
811 options: Resource<crate::CipherKeyOptions>,
812 ) -> Result<std::result::Result<Resource<CipherKey>, Error>> {
813 let policy = take_options(accessor, options).await?.policy;
814 let input = take_options(accessor, input).await?.material;
815 let material = polymorph_webcrypto_core::unwrap_cipher_key(
816 $mode,
817 variant.into(),
818 input,
819 policy,
820 );
821 mint(accessor, material).await
822 }
823
824 async fn unwrap_key_jwk(
825 accessor: &Accessor<T, Self>,
826 variant: iface::AesVariant,
827 input: Resource<UnwrapInput>,
828 options: Resource<crate::CipherKeyOptions>,
829 ) -> Result<std::result::Result<Resource<CipherKey>, Error>> {
830 let policy = take_options(accessor, options).await?.policy;
831 let input = take_options(accessor, input).await?.material;
832 let material = polymorph_webcrypto_core::unwrap_cipher_key_jwk(
833 $mode,
834 variant.into(),
835 input,
836 policy,
837 );
838 mint(accessor, material).await
839 }
840 }
841 };
842 };
843}
844
845cipher_minting!(aes_cbc_iface, polymorph_webcrypto_core::CipherMode::Cbc);
846cipher_minting!(aes_ctr_iface, polymorph_webcrypto_core::CipherMode::Ctr);
847
848impl wrapping_iface::Host for WasiWebcryptoCtxView<'_> {}
851
852impl HostWrapInput for WasiWebcryptoCtxView<'_> {}
853
854impl HostUnwrapInput for WasiWebcryptoCtxView<'_> {}
855
856impl<T: Send> HostWrapInputWithStore<T> for WasiWebcrypto {
857 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<WrapInput>) -> Result<()> {
858 drop_resource(accessor, rep).await
859 }
860}
861
862impl<T: Send> HostUnwrapInputWithStore<T> for WasiWebcrypto {
863 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<UnwrapInput>) -> Result<()> {
864 drop_resource(accessor, rep).await
865 }
866}
867
868impl key_wrap_iface::Host for WasiWebcryptoCtxView<'_> {}
871
872impl HostKwKey for WasiWebcryptoCtxView<'_> {
873 fn algorithm_name(&mut self, self_: Resource<KwKey>) -> Result<String> {
874 Ok(self.table.get(&self_)?.material.name().to_string())
875 }
876
877 fn algorithm_length(&mut self, self_: Resource<KwKey>) -> Result<u32> {
878 Ok(self.table.get(&self_)?.material.length_bits())
879 }
880
881 fn extractable(&mut self, self_: Resource<KwKey>) -> Result<bool> {
882 Ok(self.table.get(&self_)?.material.extractable())
883 }
884
885 fn can_wrap(&mut self, self_: Resource<KwKey>) -> Result<bool> {
886 Ok(self.table.get(&self_)?.material.can_wrap())
887 }
888
889 fn can_unwrap(&mut self, self_: Resource<KwKey>) -> Result<bool> {
890 Ok(self.table.get(&self_)?.material.can_unwrap())
891 }
892}
893
894impl key_wrap_iface::HostKwKeyOptions for WasiWebcryptoCtxView<'_> {
895 fn new(&mut self) -> Result<Resource<crate::KwKeyOptions>> {
896 let retention = charge_floor_or_trap(self.ctx)?;
897 Ok(self
898 .table
899 .push(crate::KwKeyOptions::minted(Default::default(), retention))?)
900 }
901
902 fn can_wrap(&mut self, self_: Resource<crate::KwKeyOptions>, allowed: bool) -> Result<()> {
903 self.table.get_mut(&self_)?.policy.wrap = allowed;
904 Ok(())
905 }
906
907 fn can_unwrap(&mut self, self_: Resource<crate::KwKeyOptions>, allowed: bool) -> Result<()> {
908 self.table.get_mut(&self_)?.policy.unwrap = allowed;
909 Ok(())
910 }
911
912 fn extractable(&mut self, self_: Resource<crate::KwKeyOptions>, allowed: bool) -> Result<()> {
913 self.table.get_mut(&self_)?.policy.extractable = allowed;
914 Ok(())
915 }
916}
917
918impl<T: Send> HostKwKeyOptionsWithStore<T> for WasiWebcrypto {
919 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<crate::KwKeyOptions>) -> Result<()> {
920 drop_resource(accessor, rep).await
921 }
922}
923
924impl<T: Send> HostKwKeyWithStore<T> for WasiWebcrypto {
925 async fn wrap(
926 accessor: &Accessor<T, Self>,
927 self_: Resource<KwKey>,
928 input: Resource<WrapInput>,
929 ) -> Result<std::result::Result<Vec<u8>, Error>> {
930 let input = take_options(accessor, input).await?.material;
931 with_resource(accessor, self_, |key| {
932 key.material.wrap(input).map_err(Error::from)
933 })
934 .await
935 }
936
937 async fn unwrap(
938 accessor: &Accessor<T, Self>,
939 self_: Resource<KwKey>,
940 wrapped: Vec<u8>,
941 ) -> Result<std::result::Result<Resource<UnwrapInput>, Error>> {
942 let material = with_resource(accessor, self_, |key| key.material.unwrap(&wrapped)).await?;
943 mint(accessor, material).await
944 }
945
946 async fn to_wrap_input_raw(
947 accessor: &Accessor<T, Self>,
948 self_: Resource<KwKey>,
949 ) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
950 to_wrap_input(accessor, self_, WrapFormat::Raw, |key| {
951 key.material.export()
952 })
953 .await
954 }
955
956 async fn to_wrap_input_jwk(
957 accessor: &Accessor<T, Self>,
958 self_: Resource<KwKey>,
959 ) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
960 to_wrap_input(accessor, self_, WrapFormat::Jwk, |key| {
961 key.material.export_jwk().map(String::into_bytes)
962 })
963 .await
964 }
965
966 async fn export_key_raw(
967 accessor: &Accessor<T, Self>,
968 self_: Resource<KwKey>,
969 ) -> Result<std::result::Result<Vec<u8>, Error>> {
970 with_resource(accessor, self_, |key| {
971 key.material.export().map_err(Error::from)
972 })
973 .await
974 }
975
976 async fn export_key_jwk(
977 accessor: &Accessor<T, Self>,
978 self_: Resource<KwKey>,
979 ) -> Result<std::result::Result<String, Error>> {
980 with_resource(accessor, self_, |key| {
981 key.material.export_jwk().map_err(Error::from)
982 })
983 .await
984 }
985
986 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<KwKey>) -> Result<()> {
987 drop_resource(accessor, rep).await
988 }
989}
990
991impl aes_kw_iface::Host for WasiWebcryptoCtxView<'_> {}
994
995impl<T: Send> aes_kw_iface::HostWithStore<T> for WasiWebcrypto {
996 async fn import_key_raw(
997 accessor: &Accessor<T, Self>,
998 variant: aes_kw_iface::AesVariant,
999 raw: Vec<u8>,
1000 options: Resource<crate::KwKeyOptions>,
1001 ) -> Result<std::result::Result<Resource<KwKey>, Error>> {
1002 let policy = take_options(accessor, options).await?.policy;
1003 let material = KwKeyMaterial::import(variant.into(), raw, policy);
1004 mint(accessor, material).await
1005 }
1006
1007 async fn import_key_jwk(
1008 accessor: &Accessor<T, Self>,
1009 variant: aes_kw_iface::AesVariant,
1010 jwk: String,
1011 options: Resource<crate::KwKeyOptions>,
1012 ) -> Result<std::result::Result<Resource<KwKey>, Error>> {
1013 let policy = take_options(accessor, options).await?.policy;
1014 let material = KwKeyMaterial::import_jwk(variant.into(), &jwk, policy);
1015 mint(accessor, material).await
1016 }
1017
1018 async fn generate_key(
1019 accessor: &Accessor<T, Self>,
1020 variant: aes_kw_iface::AesVariant,
1021 options: Resource<crate::KwKeyOptions>,
1022 ) -> Result<std::result::Result<Resource<KwKey>, Error>> {
1023 let policy = take_options(accessor, options).await?.policy;
1024 let material = KwKeyMaterial::generate(variant.into(), policy)
1025 .map_err(rng_trap("random key generation"))?;
1026 mint(accessor, material).await
1027 }
1028
1029 async fn derive_key(
1030 accessor: &Accessor<T, Self>,
1031 variant: aes_kw_iface::AesVariant,
1032 input: Resource<DeriveInput>,
1033 options: Resource<crate::KwKeyOptions>,
1034 ) -> Result<std::result::Result<Resource<KwKey>, Error>> {
1035 let policy = take_options(accessor, options).await?.policy;
1036 let material = with_resource(accessor, input, |input| {
1037 polymorph_webcrypto_core::derive_kw_key(variant.into(), &input.material, policy)
1038 })
1039 .await?;
1040 mint(accessor, material).await
1041 }
1042
1043 async fn unwrap_key_raw(
1044 accessor: &Accessor<T, Self>,
1045 variant: aes_kw_iface::AesVariant,
1046 input: Resource<UnwrapInput>,
1047 options: Resource<crate::KwKeyOptions>,
1048 ) -> Result<std::result::Result<Resource<KwKey>, Error>> {
1049 let policy = take_options(accessor, options).await?.policy;
1050 let input = take_options(accessor, input).await?.material;
1051 let material = polymorph_webcrypto_core::unwrap_kw_key(variant.into(), input, policy);
1052 mint(accessor, material).await
1053 }
1054
1055 async fn unwrap_key_jwk(
1056 accessor: &Accessor<T, Self>,
1057 variant: aes_kw_iface::AesVariant,
1058 input: Resource<UnwrapInput>,
1059 options: Resource<crate::KwKeyOptions>,
1060 ) -> Result<std::result::Result<Resource<KwKey>, Error>> {
1061 let policy = take_options(accessor, options).await?.policy;
1062 let input = take_options(accessor, input).await?.material;
1063 let material = polymorph_webcrypto_core::unwrap_kw_key_jwk(variant.into(), input, policy);
1064 mint(accessor, material).await
1065 }
1066}
1067
1068impl derivation_iface::Host for WasiWebcryptoCtxView<'_> {}
1071
1072host_options! {
1073 derivation_iface::{HostDeriveOptions, HostDeriveOptionsWithStore} for crate::DeriveOptions {
1074 can_derive_bits => derive_bits,
1075 can_derive_key => derive_key,
1076 }
1077}
1078
1079impl HostDeriveInput for WasiWebcryptoCtxView<'_> {
1080 fn can_derive_bits(&mut self, self_: Resource<DeriveInput>) -> Result<bool> {
1081 Ok(self.table.get(&self_)?.material.policy().derive_bits)
1082 }
1083
1084 fn can_derive_key(&mut self, self_: Resource<DeriveInput>) -> Result<bool> {
1085 Ok(self.table.get(&self_)?.material.policy().derive_key)
1086 }
1087}
1088
1089impl<T: Send> HostDeriveInputWithStore<T> for WasiWebcrypto {
1090 async fn derive_bits(
1091 accessor: &Accessor<T, Self>,
1092 self_: Resource<DeriveInput>,
1093 length: Option<u32>,
1094 ) -> Result<std::result::Result<Vec<u8>, Error>> {
1095 with_resource(accessor, self_, |input| {
1096 input
1097 .material
1098 .derive_bits(length)
1099 .map(|okm| okm.to_vec())
1100 .map_err(Error::from)
1101 })
1102 .await
1103 }
1104
1105 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<DeriveInput>) -> Result<()> {
1106 drop_resource(accessor, rep).await
1107 }
1108}
1109
1110impl hkdf_iface::Host for WasiWebcryptoCtxView<'_> {}
1113
1114impl HostIkm for WasiWebcryptoCtxView<'_> {
1115 fn can_derive_bits(&mut self, self_: Resource<Ikm>) -> Result<bool> {
1116 Ok(self.table.get(&self_)?.material.policy().derive_bits)
1117 }
1118
1119 fn can_derive_key(&mut self, self_: Resource<Ikm>) -> Result<bool> {
1120 Ok(self.table.get(&self_)?.material.policy().derive_key)
1121 }
1122}
1123
1124impl<T: Send> HostIkmWithStore<T> for WasiWebcrypto {
1125 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<Ikm>) -> Result<()> {
1126 drop_resource(accessor, rep).await
1127 }
1128}
1129
1130impl<T: Send> hkdf_iface::HostWithStore<T> for WasiWebcrypto {
1131 async fn import_ikm(
1132 accessor: &Accessor<T, Self>,
1133 raw: Vec<u8>,
1134 options: Resource<crate::DeriveOptions>,
1135 ) -> Result<std::result::Result<Resource<Ikm>, Error>> {
1136 let policy = take_options(accessor, options).await?.policy;
1137 let material = polymorph_webcrypto_core::IkmMaterial::import(raw, policy);
1138 mint(accessor, material).await
1139 }
1140
1141 async fn unwrap_ikm(
1142 accessor: &Accessor<T, Self>,
1143 input: Resource<UnwrapInput>,
1144 options: Resource<crate::DeriveOptions>,
1145 ) -> Result<std::result::Result<Resource<Ikm>, Error>> {
1146 let policy = take_options(accessor, options).await?.policy;
1147 let input = take_options(accessor, input).await?.material;
1148 let material = polymorph_webcrypto_core::unwrap_ikm(input, policy);
1149 mint(accessor, material).await
1150 }
1151}
1152
1153impl hkdf_sha2_iface::Host for WasiWebcryptoCtxView<'_> {}
1154
1155impl<T: Send> hkdf_sha2_iface::HostWithStore<T> for WasiWebcrypto {
1156 async fn prepare(
1157 accessor: &Accessor<T, Self>,
1158 variant: hkdf_sha2_iface::Sha2Variant,
1159 input: Resource<Ikm>,
1160 salt: Vec<u8>,
1161 info: Vec<u8>,
1162 ) -> Result<std::result::Result<Resource<DeriveInput>, Error>> {
1163 let material = with_resource(accessor, input, |ikm| {
1164 polymorph_webcrypto_core::DeriveInputMaterial::prepare(
1165 variant.into(),
1166 &ikm.material,
1167 &salt,
1168 info,
1169 )
1170 })
1171 .await?;
1172 mint(accessor, material).await
1173 }
1174
1175 async fn prepare_from(
1176 accessor: &Accessor<T, Self>,
1177 variant: hkdf_sha2_iface::Sha2Variant,
1178 input: Resource<DeriveInput>,
1179 salt: Vec<u8>,
1180 info: Vec<u8>,
1181 ) -> Result<std::result::Result<Resource<DeriveInput>, Error>> {
1182 let material = with_resource(accessor, input, |upstream| {
1183 polymorph_webcrypto_core::DeriveInputMaterial::prepare_from(
1184 variant.into(),
1185 &upstream.material,
1186 &salt,
1187 info,
1188 )
1189 })
1190 .await?;
1191 mint(accessor, material).await
1192 }
1193}
1194
1195impl hmac_sha1_iface::Host for WasiWebcryptoCtxView<'_> {}
1198
1199impl<T: Send> hmac_sha1_iface::HostWithStore<T> for WasiWebcrypto {
1200 async fn import_key_raw(
1201 accessor: &Accessor<T, Self>,
1202 raw: Vec<u8>,
1203 options: Resource<crate::MacKeyOptions>,
1204 ) -> Result<std::result::Result<Resource<MacKey>, Error>> {
1205 let policy = take_options(accessor, options).await?.policy;
1206 let material = MacKeyMaterial::import_sha1(raw, policy);
1207 mint(accessor, material).await
1208 }
1209
1210 async fn import_key_jwk(
1211 accessor: &Accessor<T, Self>,
1212 jwk: String,
1213 options: Resource<crate::MacKeyOptions>,
1214 ) -> Result<std::result::Result<Resource<MacKey>, Error>> {
1215 let policy = take_options(accessor, options).await?.policy;
1216 let material = MacKeyMaterial::import_jwk_sha1(&jwk, policy);
1217 mint(accessor, material).await
1218 }
1219
1220 async fn generate_key(
1221 accessor: &Accessor<T, Self>,
1222 length: Option<u32>,
1223 options: Resource<crate::MacKeyOptions>,
1224 ) -> Result<std::result::Result<Resource<MacKey>, Error>> {
1225 let policy = take_options(accessor, options).await?.policy;
1226 let material = MacKeyMaterial::generate_sha1(length, policy)
1227 .map_err(rng_trap("random key generation"))?;
1228 mint(accessor, material).await
1229 }
1230
1231 async fn derive_key(
1232 accessor: &Accessor<T, Self>,
1233 input: Resource<DeriveInput>,
1234 length: Option<u32>,
1235 options: Resource<crate::MacKeyOptions>,
1236 ) -> Result<std::result::Result<Resource<MacKey>, Error>> {
1237 let policy = take_options(accessor, options).await?.policy;
1238 let material = with_resource(accessor, input, |input| {
1239 polymorph_webcrypto_core::derive_mac_key_sha1(&input.material, length, policy)
1240 })
1241 .await?;
1242 mint(accessor, material).await
1243 }
1244
1245 async fn unwrap_key_raw(
1246 accessor: &Accessor<T, Self>,
1247 input: Resource<UnwrapInput>,
1248 options: Resource<crate::MacKeyOptions>,
1249 ) -> Result<std::result::Result<Resource<MacKey>, Error>> {
1250 let policy = take_options(accessor, options).await?.policy;
1251 let input = take_options(accessor, input).await?.material;
1252 let material = polymorph_webcrypto_core::unwrap_mac_key_sha1(input, policy);
1253 mint(accessor, material).await
1254 }
1255
1256 async fn unwrap_key_jwk(
1257 accessor: &Accessor<T, Self>,
1258 input: Resource<UnwrapInput>,
1259 options: Resource<crate::MacKeyOptions>,
1260 ) -> Result<std::result::Result<Resource<MacKey>, Error>> {
1261 let policy = take_options(accessor, options).await?.policy;
1262 let input = take_options(accessor, input).await?.material;
1263 let material = polymorph_webcrypto_core::unwrap_mac_key_jwk_sha1(input, policy);
1264 mint(accessor, material).await
1265 }
1266}
1267
1268impl hkdf_sha1_iface::Host for WasiWebcryptoCtxView<'_> {}
1269
1270impl<T: Send> hkdf_sha1_iface::HostWithStore<T> for WasiWebcrypto {
1271 async fn prepare(
1272 accessor: &Accessor<T, Self>,
1273 input: Resource<Ikm>,
1274 salt: Vec<u8>,
1275 info: Vec<u8>,
1276 ) -> Result<std::result::Result<Resource<DeriveInput>, Error>> {
1277 let material = with_resource(accessor, input, |ikm| {
1278 polymorph_webcrypto_core::DeriveInputMaterial::prepare_sha1(&ikm.material, &salt, info)
1279 })
1280 .await?;
1281 mint(accessor, material).await
1282 }
1283
1284 async fn prepare_from(
1285 accessor: &Accessor<T, Self>,
1286 input: Resource<DeriveInput>,
1287 salt: Vec<u8>,
1288 info: Vec<u8>,
1289 ) -> Result<std::result::Result<Resource<DeriveInput>, Error>> {
1290 let material = with_resource(accessor, input, |upstream| {
1291 polymorph_webcrypto_core::DeriveInputMaterial::prepare_from_sha1(
1292 &upstream.material,
1293 &salt,
1294 info,
1295 )
1296 })
1297 .await?;
1298 mint(accessor, material).await
1299 }
1300}
1301
1302impl pbkdf2_sha1_iface::Host for WasiWebcryptoCtxView<'_> {}
1303
1304impl<T: Send> pbkdf2_sha1_iface::HostWithStore<T> for WasiWebcrypto {
1305 async fn prepare(
1306 accessor: &Accessor<T, Self>,
1307 input: Resource<Password>,
1308 salt: Vec<u8>,
1309 iterations: u32,
1310 ) -> Result<std::result::Result<Resource<DeriveInput>, Error>> {
1311 let material = with_resource(accessor, input, |password| {
1312 polymorph_webcrypto_core::DeriveInputMaterial::prepare_pbkdf2_sha1(
1313 &password.material,
1314 salt.clone(),
1315 iterations,
1316 )
1317 })
1318 .await?;
1319 mint(accessor, material).await
1320 }
1321}
1322
1323impl pbkdf2_iface::Host for WasiWebcryptoCtxView<'_> {}
1326
1327impl HostPassword for WasiWebcryptoCtxView<'_> {
1328 fn can_derive_bits(&mut self, self_: Resource<Password>) -> Result<bool> {
1329 Ok(self.table.get(&self_)?.material.policy().derive_bits)
1330 }
1331
1332 fn can_derive_key(&mut self, self_: Resource<Password>) -> Result<bool> {
1333 Ok(self.table.get(&self_)?.material.policy().derive_key)
1334 }
1335}
1336
1337impl<T: Send> HostPasswordWithStore<T> for WasiWebcrypto {
1338 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<Password>) -> Result<()> {
1339 drop_resource(accessor, rep).await
1340 }
1341}
1342
1343impl<T: Send> pbkdf2_iface::HostWithStore<T> for WasiWebcrypto {
1344 async fn import_password(
1345 accessor: &Accessor<T, Self>,
1346 raw: Vec<u8>,
1347 options: Resource<crate::DeriveOptions>,
1348 ) -> Result<std::result::Result<Resource<Password>, Error>> {
1349 let policy = take_options(accessor, options).await?.policy;
1350 let material = polymorph_webcrypto_core::PasswordMaterial::import(raw, policy);
1351 mint(accessor, material).await
1352 }
1353
1354 async fn unwrap_password(
1355 accessor: &Accessor<T, Self>,
1356 input: Resource<UnwrapInput>,
1357 options: Resource<crate::DeriveOptions>,
1358 ) -> Result<std::result::Result<Resource<Password>, Error>> {
1359 let policy = take_options(accessor, options).await?.policy;
1360 let input = take_options(accessor, input).await?.material;
1361 let material = polymorph_webcrypto_core::unwrap_password(input, policy);
1362 mint(accessor, material).await
1363 }
1364}
1365
1366impl pbkdf2_sha2_iface::Host for WasiWebcryptoCtxView<'_> {}
1367
1368impl<T: Send> pbkdf2_sha2_iface::HostWithStore<T> for WasiWebcrypto {
1369 async fn prepare(
1370 accessor: &Accessor<T, Self>,
1371 variant: pbkdf2_sha2_iface::Sha2Variant,
1372 input: Resource<Password>,
1373 salt: Vec<u8>,
1374 iterations: u32,
1375 ) -> Result<std::result::Result<Resource<DeriveInput>, Error>> {
1376 let material = with_resource(accessor, input, |password| {
1377 polymorph_webcrypto_core::DeriveInputMaterial::prepare_pbkdf2(
1378 variant.into(),
1379 &password.material,
1380 salt,
1381 iterations,
1382 )
1383 })
1384 .await?;
1385 mint(accessor, material).await
1386 }
1387}
1388
1389impl key_agreement_iface::Host for WasiWebcryptoCtxView<'_> {}
1392
1393host_options! {
1394 key_agreement_iface::{HostAgreementKeyOptions, HostAgreementKeyOptionsWithStore}
1395 for crate::AgreementKeyOptions {
1396 can_derive_bits => derive_bits,
1397 can_derive_key => derive_key,
1398 extractable => extractable,
1399 }
1400}
1401
1402impl HostPublicKey for WasiWebcryptoCtxView<'_> {
1403 fn algorithm_name(&mut self, self_: Resource<AgreementPublicKey>) -> Result<String> {
1404 Ok(self.table.get(&self_)?.material.name().to_string())
1405 }
1406}
1407
1408impl<T: Send> HostPublicKeyWithStore<T> for WasiWebcrypto {
1409 async fn export_key_raw(
1410 accessor: &Accessor<T, Self>,
1411 self_: Resource<AgreementPublicKey>,
1412 ) -> Result<std::result::Result<Vec<u8>, Error>> {
1413 with_resource(accessor, self_, |key| Ok(key.material.export())).await
1414 }
1415
1416 async fn export_key_jwk(
1417 accessor: &Accessor<T, Self>,
1418 self_: Resource<AgreementPublicKey>,
1419 ) -> Result<std::result::Result<String, Error>> {
1420 with_resource(accessor, self_, |key| Ok(key.material.export_jwk())).await
1421 }
1422
1423 async fn export_key_spki(
1424 accessor: &Accessor<T, Self>,
1425 self_: Resource<AgreementPublicKey>,
1426 ) -> Result<std::result::Result<Vec<u8>, Error>> {
1427 with_resource(accessor, self_, |key| Ok(key.material.export_spki())).await
1428 }
1429
1430 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<AgreementPublicKey>) -> Result<()> {
1431 drop_resource(accessor, rep).await
1432 }
1433}
1434
1435impl HostSecretKey for WasiWebcryptoCtxView<'_> {
1436 fn algorithm_name(&mut self, self_: Resource<AgreementSecretKey>) -> Result<String> {
1437 Ok(self.table.get(&self_)?.material.name().to_string())
1438 }
1439
1440 fn can_derive_bits(&mut self, self_: Resource<AgreementSecretKey>) -> Result<bool> {
1441 Ok(self.table.get(&self_)?.material.policy().derive_bits)
1442 }
1443
1444 fn can_derive_key(&mut self, self_: Resource<AgreementSecretKey>) -> Result<bool> {
1445 Ok(self.table.get(&self_)?.material.policy().derive_key)
1446 }
1447
1448 fn extractable(&mut self, self_: Resource<AgreementSecretKey>) -> Result<bool> {
1449 Ok(self.table.get(&self_)?.material.policy().extractable)
1450 }
1451}
1452
1453impl<T: Send> HostSecretKeyWithStore<T> for WasiWebcrypto {
1454 async fn agree(
1455 accessor: &Accessor<T, Self>,
1456 self_: Resource<AgreementSecretKey>,
1457 peer: Resource<AgreementPublicKey>,
1458 ) -> Result<std::result::Result<Resource<DeriveInput>, Error>> {
1459 let material = accessor.with(|mut access| -> Result<_> {
1460 let view = access.get();
1461 let secret = view.table.get(&self_)?;
1462 let peer = view.table.get(&peer)?;
1463 Ok(secret.material.agree(&peer.material))
1464 })?;
1465 mint(accessor, material).await
1466 }
1467
1468 async fn export_key_jwk(
1469 accessor: &Accessor<T, Self>,
1470 self_: Resource<AgreementSecretKey>,
1471 ) -> Result<std::result::Result<String, Error>> {
1472 with_resource(accessor, self_, |key| {
1473 key.material.export_jwk().map_err(Error::from)
1474 })
1475 .await
1476 }
1477
1478 async fn export_key_pkcs8(
1479 accessor: &Accessor<T, Self>,
1480 self_: Resource<AgreementSecretKey>,
1481 ) -> Result<std::result::Result<Vec<u8>, Error>> {
1482 with_resource(accessor, self_, |key| {
1483 key.material.export_pkcs8().map_err(Error::from)
1484 })
1485 .await
1486 }
1487
1488 async fn to_wrap_input_jwk(
1489 accessor: &Accessor<T, Self>,
1490 self_: Resource<AgreementSecretKey>,
1491 ) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
1492 to_wrap_input(accessor, self_, WrapFormat::Jwk, |key| {
1493 key.material.export_jwk().map(String::into_bytes)
1494 })
1495 .await
1496 }
1497
1498 async fn to_wrap_input_pkcs8(
1499 accessor: &Accessor<T, Self>,
1500 self_: Resource<AgreementSecretKey>,
1501 ) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
1502 to_wrap_input(accessor, self_, WrapFormat::Pkcs8, |key| {
1503 key.material.export_pkcs8()
1504 })
1505 .await
1506 }
1507
1508 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<AgreementSecretKey>) -> Result<()> {
1509 drop_resource(accessor, rep).await
1510 }
1511}
1512
1513impl x25519_iface::Host for WasiWebcryptoCtxView<'_> {}
1516
1517impl<T: Send> x25519_iface::HostWithStore<T> for WasiWebcrypto {
1518 async fn import_public_key_raw(
1519 accessor: &Accessor<T, Self>,
1520 raw: Vec<u8>,
1521 ) -> Result<std::result::Result<Resource<AgreementPublicKey>, Error>> {
1522 let material = polymorph_webcrypto_core::AgreementPublicMaterial::import_x25519(&raw);
1523 mint(accessor, material).await
1524 }
1525
1526 async fn import_public_key_spki(
1527 accessor: &Accessor<T, Self>,
1528 spki: Vec<u8>,
1529 ) -> Result<std::result::Result<Resource<AgreementPublicKey>, Error>> {
1530 let material = polymorph_webcrypto_core::AgreementPublicMaterial::import_x25519_spki(&spki);
1531 mint(accessor, material).await
1532 }
1533
1534 async fn import_public_key_jwk(
1535 accessor: &Accessor<T, Self>,
1536 jwk: String,
1537 ) -> Result<std::result::Result<Resource<AgreementPublicKey>, Error>> {
1538 let material = polymorph_webcrypto_core::AgreementPublicMaterial::import_x25519_jwk(&jwk);
1539 mint(accessor, material).await
1540 }
1541
1542 async fn import_secret_key_pkcs8(
1543 accessor: &Accessor<T, Self>,
1544 pkcs8: Vec<u8>,
1545 options: Resource<crate::AgreementKeyOptions>,
1546 ) -> Result<std::result::Result<Resource<AgreementSecretKey>, Error>> {
1547 let policy = take_options(accessor, options).await?.policy;
1548 let material =
1549 polymorph_webcrypto_core::AgreementSecretMaterial::import_x25519_pkcs8(&pkcs8, policy);
1550 mint(accessor, material).await
1551 }
1552
1553 async fn import_secret_key_jwk(
1554 accessor: &Accessor<T, Self>,
1555 jwk: String,
1556 options: Resource<crate::AgreementKeyOptions>,
1557 ) -> Result<std::result::Result<Resource<AgreementSecretKey>, Error>> {
1558 let policy = take_options(accessor, options).await?.policy;
1559 let material =
1560 polymorph_webcrypto_core::AgreementSecretMaterial::import_x25519_jwk(&jwk, policy);
1561 mint(accessor, material).await
1562 }
1563
1564 async fn generate_key(
1565 accessor: &Accessor<T, Self>,
1566 options: Resource<crate::AgreementKeyOptions>,
1567 ) -> Result<
1568 std::result::Result<(Resource<AgreementSecretKey>, Resource<AgreementPublicKey>), Error>,
1569 > {
1570 let policy = take_options(accessor, options).await?.policy;
1571 let material = polymorph_webcrypto_core::AgreementSecretMaterial::generate_x25519(policy)
1572 .map_err(rng_trap("random key generation"))?;
1573 match material {
1574 Ok((secret, public)) => mint_key_pair(accessor, secret, public).await,
1575 Err(err) => Ok(Err(err.into())),
1576 }
1577 }
1578
1579 async fn unwrap_secret_key_jwk(
1580 accessor: &Accessor<T, Self>,
1581 input: Resource<UnwrapInput>,
1582 options: Resource<crate::AgreementKeyOptions>,
1583 ) -> Result<std::result::Result<Resource<AgreementSecretKey>, Error>> {
1584 let policy = take_options(accessor, options).await?.policy;
1585 let input = take_options(accessor, input).await?.material;
1586 let material = polymorph_webcrypto_core::unwrap_x25519_secret_key_jwk(input, policy);
1587 mint(accessor, material).await
1588 }
1589
1590 async fn unwrap_secret_key_pkcs8(
1591 accessor: &Accessor<T, Self>,
1592 input: Resource<UnwrapInput>,
1593 options: Resource<crate::AgreementKeyOptions>,
1594 ) -> Result<std::result::Result<Resource<AgreementSecretKey>, Error>> {
1595 let policy = take_options(accessor, options).await?.policy;
1596 let input = take_options(accessor, input).await?.material;
1597 let material = polymorph_webcrypto_core::unwrap_x25519_secret_key_pkcs8(input, policy);
1598 mint(accessor, material).await
1599 }
1600}
1601
1602impl ecdh_iface::Host for WasiWebcryptoCtxView<'_> {}
1605
1606impl<T: Send> ecdh_iface::HostWithStore<T> for WasiWebcrypto {
1607 async fn import_public_key_raw(
1608 accessor: &Accessor<T, Self>,
1609 variant: ecdh_iface::EcdhVariant,
1610 raw: Vec<u8>,
1611 ) -> Result<std::result::Result<Resource<AgreementPublicKey>, Error>> {
1612 let material =
1613 polymorph_webcrypto_core::AgreementPublicMaterial::import_ecdh(variant.into(), &raw);
1614 mint(accessor, material).await
1615 }
1616
1617 async fn import_public_key_spki(
1618 accessor: &Accessor<T, Self>,
1619 variant: ecdh_iface::EcdhVariant,
1620 spki: Vec<u8>,
1621 ) -> Result<std::result::Result<Resource<AgreementPublicKey>, Error>> {
1622 let material = polymorph_webcrypto_core::AgreementPublicMaterial::import_ecdh_spki(
1623 variant.into(),
1624 &spki,
1625 );
1626 mint(accessor, material).await
1627 }
1628
1629 async fn import_public_key_jwk(
1630 accessor: &Accessor<T, Self>,
1631 variant: ecdh_iface::EcdhVariant,
1632 jwk: String,
1633 ) -> Result<std::result::Result<Resource<AgreementPublicKey>, Error>> {
1634 let material = polymorph_webcrypto_core::AgreementPublicMaterial::import_ecdh_jwk(
1635 variant.into(),
1636 &jwk,
1637 );
1638 mint(accessor, material).await
1639 }
1640
1641 async fn import_secret_key_jwk(
1642 accessor: &Accessor<T, Self>,
1643 variant: ecdh_iface::EcdhVariant,
1644 jwk: String,
1645 options: Resource<crate::AgreementKeyOptions>,
1646 ) -> Result<std::result::Result<Resource<AgreementSecretKey>, Error>> {
1647 let policy = take_options(accessor, options).await?.policy;
1648 let material = polymorph_webcrypto_core::AgreementSecretMaterial::import_ecdh_jwk(
1649 variant.into(),
1650 &jwk,
1651 policy,
1652 );
1653 mint(accessor, material).await
1654 }
1655
1656 async fn import_secret_key_pkcs8(
1657 accessor: &Accessor<T, Self>,
1658 variant: ecdh_iface::EcdhVariant,
1659 pkcs8: Vec<u8>,
1660 options: Resource<crate::AgreementKeyOptions>,
1661 ) -> Result<std::result::Result<Resource<AgreementSecretKey>, Error>> {
1662 let policy = take_options(accessor, options).await?.policy;
1663 let material = polymorph_webcrypto_core::AgreementSecretMaterial::import_ecdh_pkcs8(
1664 variant.into(),
1665 &pkcs8,
1666 policy,
1667 );
1668 mint(accessor, material).await
1669 }
1670
1671 async fn generate_key(
1672 accessor: &Accessor<T, Self>,
1673 variant: ecdh_iface::EcdhVariant,
1674 options: Resource<crate::AgreementKeyOptions>,
1675 ) -> Result<
1676 std::result::Result<(Resource<AgreementSecretKey>, Resource<AgreementPublicKey>), Error>,
1677 > {
1678 let policy = take_options(accessor, options).await?.policy;
1679 let material = polymorph_webcrypto_core::AgreementSecretMaterial::generate_ecdh(
1680 variant.into(),
1681 policy,
1682 )
1683 .map_err(rng_trap("random key generation"))?;
1684 match material {
1685 Ok((secret, public)) => mint_key_pair(accessor, secret, public).await,
1686 Err(err) => Ok(Err(err.into())),
1687 }
1688 }
1689
1690 async fn unwrap_secret_key_jwk(
1691 accessor: &Accessor<T, Self>,
1692 variant: ecdh_iface::EcdhVariant,
1693 input: Resource<UnwrapInput>,
1694 options: Resource<crate::AgreementKeyOptions>,
1695 ) -> Result<std::result::Result<Resource<AgreementSecretKey>, Error>> {
1696 let policy = take_options(accessor, options).await?.policy;
1697 let input = take_options(accessor, input).await?.material;
1698 let material =
1699 polymorph_webcrypto_core::unwrap_ecdh_secret_key_jwk(variant.into(), input, policy);
1700 mint(accessor, material).await
1701 }
1702
1703 async fn unwrap_secret_key_pkcs8(
1704 accessor: &Accessor<T, Self>,
1705 variant: ecdh_iface::EcdhVariant,
1706 input: Resource<UnwrapInput>,
1707 options: Resource<crate::AgreementKeyOptions>,
1708 ) -> Result<std::result::Result<Resource<AgreementSecretKey>, Error>> {
1709 let policy = take_options(accessor, options).await?.policy;
1710 let input = take_options(accessor, input).await?.material;
1711 let material =
1712 polymorph_webcrypto_core::unwrap_ecdh_secret_key_pkcs8(variant.into(), input, policy);
1713 mint(accessor, material).await
1714 }
1715}
1716
1717impl digest_iface::Host for WasiWebcryptoCtxView<'_> {}
1720
1721impl HostDigest for WasiWebcryptoCtxView<'_> {
1722 fn algorithm_name(&mut self, self_: Resource<Digest>) -> Result<String> {
1723 Ok(self.table.get(&self_)?.variant.hash_name().to_string())
1724 }
1725}
1726
1727impl<T: Send> HostDigestWithStore<T> for WasiWebcrypto {
1728 async fn compute(
1729 accessor: &Accessor<T, Self>,
1730 self_: Resource<Digest>,
1731 data: StreamReader<u8>,
1732 ) -> Result<std::result::Result<Vec<u8>, Error>> {
1733 drain_then(accessor, self_, data, |digest, bytes| {
1738 digest.variant.digest(bytes).map_err(Into::into)
1739 })
1740 .await
1741 }
1742
1743 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<Digest>) -> Result<()> {
1744 drop_resource(accessor, rep).await
1745 }
1746}
1747
1748impl sha2_iface::Host for WasiWebcryptoCtxView<'_> {
1751 fn make_digest(
1752 &mut self,
1753 variant: sha2_iface::Sha2Variant,
1754 ) -> Result<std::result::Result<Resource<Digest>, Error>> {
1755 let variant = match served_sha2(variant.into()) {
1756 Ok(variant) => variant,
1757 Err(err) => return Ok(Err(err.into())),
1758 };
1759 let Some(retention) = self.ctx.charge_retention(0) else {
1760 return Ok(Err(retention_exhausted(self.ctx.retention_limit_bytes())));
1761 };
1762 Ok(Ok(self.table.push(Digest::minted(
1763 DigestKind::Sha2(variant),
1764 retention,
1765 ))?))
1766 }
1767}
1768
1769impl sha1_checked_iface::Host for WasiWebcryptoCtxView<'_> {
1772 fn make_rejecting_digest(&mut self) -> Result<std::result::Result<Resource<Digest>, Error>> {
1773 let Some(retention) = self.ctx.charge_retention(0) else {
1774 return Ok(Err(retention_exhausted(self.ctx.retention_limit_bytes())));
1775 };
1776 Ok(Ok(self.table.push(Digest::minted(
1777 DigestKind::Sha1Checked(Sha1Posture::Reject),
1778 retention,
1779 ))?))
1780 }
1781
1782 fn make_mitigating_digest(&mut self) -> Result<std::result::Result<Resource<Digest>, Error>> {
1783 let Some(retention) = self.ctx.charge_retention(0) else {
1784 return Ok(Err(retention_exhausted(self.ctx.retention_limit_bytes())));
1785 };
1786 Ok(Ok(self.table.push(Digest::minted(
1787 DigestKind::Sha1Checked(Sha1Posture::Mitigate),
1788 retention,
1789 ))?))
1790 }
1791}
1792
1793impl hmac_sha2_iface::Host for WasiWebcryptoCtxView<'_> {}
1796
1797impl<T: Send> hmac_sha2_iface::HostWithStore<T> for WasiWebcrypto {
1798 async fn import_key_raw(
1799 accessor: &Accessor<T, Self>,
1800 variant: hmac_sha2_iface::Sha2Variant,
1801 raw: Vec<u8>,
1802 options: Resource<crate::MacKeyOptions>,
1803 ) -> Result<std::result::Result<Resource<MacKey>, Error>> {
1804 let policy = take_options(accessor, options).await?.policy;
1805 let material = MacKeyMaterial::import(variant.into(), raw, policy);
1806 mint(accessor, material).await
1807 }
1808
1809 async fn import_key_jwk(
1810 accessor: &Accessor<T, Self>,
1811 variant: hmac_sha2_iface::Sha2Variant,
1812 jwk: String,
1813 options: Resource<crate::MacKeyOptions>,
1814 ) -> Result<std::result::Result<Resource<MacKey>, Error>> {
1815 let policy = take_options(accessor, options).await?.policy;
1816 let material = MacKeyMaterial::import_jwk(variant.into(), &jwk, policy);
1817 mint(accessor, material).await
1818 }
1819
1820 async fn generate_key(
1821 accessor: &Accessor<T, Self>,
1822 variant: hmac_sha2_iface::Sha2Variant,
1823 length: Option<u32>,
1824 options: Resource<crate::MacKeyOptions>,
1825 ) -> Result<std::result::Result<Resource<MacKey>, Error>> {
1826 let policy = take_options(accessor, options).await?.policy;
1827 let material = MacKeyMaterial::generate(variant.into(), length, policy)
1828 .map_err(rng_trap("random key generation"))?;
1829 mint(accessor, material).await
1830 }
1831
1832 async fn derive_key(
1833 accessor: &Accessor<T, Self>,
1834 variant: hmac_sha2_iface::Sha2Variant,
1835 input: Resource<DeriveInput>,
1836 length: Option<u32>,
1837 options: Resource<crate::MacKeyOptions>,
1838 ) -> Result<std::result::Result<Resource<MacKey>, Error>> {
1839 let policy = take_options(accessor, options).await?.policy;
1840 let material = with_resource(accessor, input, |input| {
1841 polymorph_webcrypto_core::derive_mac_key(
1842 &input.material,
1843 variant.into(),
1844 length,
1845 policy,
1846 )
1847 })
1848 .await?;
1849 mint(accessor, material).await
1850 }
1851
1852 async fn unwrap_key_raw(
1853 accessor: &Accessor<T, Self>,
1854 variant: hmac_sha2_iface::Sha2Variant,
1855 input: Resource<UnwrapInput>,
1856 options: Resource<crate::MacKeyOptions>,
1857 ) -> Result<std::result::Result<Resource<MacKey>, Error>> {
1858 let policy = take_options(accessor, options).await?.policy;
1859 let input = take_options(accessor, input).await?.material;
1860 let material = polymorph_webcrypto_core::unwrap_mac_key(variant.into(), input, policy);
1861 mint(accessor, material).await
1862 }
1863
1864 async fn unwrap_key_jwk(
1865 accessor: &Accessor<T, Self>,
1866 variant: hmac_sha2_iface::Sha2Variant,
1867 input: Resource<UnwrapInput>,
1868 options: Resource<crate::MacKeyOptions>,
1869 ) -> Result<std::result::Result<Resource<MacKey>, Error>> {
1870 let policy = take_options(accessor, options).await?.policy;
1871 let input = take_options(accessor, input).await?.material;
1872 let material = polymorph_webcrypto_core::unwrap_mac_key_jwk(variant.into(), input, policy);
1873 mint(accessor, material).await
1874 }
1875}
1876
1877impl aes_gcm_iface::Host for WasiWebcryptoCtxView<'_> {}
1880
1881impl<T: Send> aes_gcm_iface::HostWithStore<T> for WasiWebcrypto {
1882 async fn import_key_raw(
1883 accessor: &Accessor<T, Self>,
1884 variant: aes_gcm_iface::AesVariant,
1885 raw: Vec<u8>,
1886 options: Resource<crate::AeadKeyOptions>,
1887 ) -> Result<std::result::Result<Resource<AeadKey>, Error>> {
1888 let policy = take_options(accessor, options).await?.policy;
1889 let material = AeadKeyMaterial::import_aes_gcm(variant.into(), raw, policy);
1890 mint(accessor, material).await
1891 }
1892
1893 async fn import_key_jwk(
1894 accessor: &Accessor<T, Self>,
1895 variant: aes_gcm_iface::AesVariant,
1896 jwk: String,
1897 options: Resource<crate::AeadKeyOptions>,
1898 ) -> Result<std::result::Result<Resource<AeadKey>, Error>> {
1899 let policy = take_options(accessor, options).await?.policy;
1900 let material = AeadKeyMaterial::import_aes_gcm_jwk(variant.into(), &jwk, policy);
1901 mint(accessor, material).await
1902 }
1903
1904 async fn generate_key(
1905 accessor: &Accessor<T, Self>,
1906 variant: aes_gcm_iface::AesVariant,
1907 options: Resource<crate::AeadKeyOptions>,
1908 ) -> Result<std::result::Result<Resource<AeadKey>, Error>> {
1909 let policy = take_options(accessor, options).await?.policy;
1910 let material = AeadKeyMaterial::generate_aes_gcm(variant.into(), policy)
1911 .map_err(rng_trap("random key generation"))?;
1912 mint(accessor, material).await
1913 }
1914
1915 async fn derive_key(
1916 accessor: &Accessor<T, Self>,
1917 variant: aes_gcm_iface::AesVariant,
1918 input: Resource<DeriveInput>,
1919 options: Resource<crate::AeadKeyOptions>,
1920 ) -> Result<std::result::Result<Resource<AeadKey>, Error>> {
1921 let policy = take_options(accessor, options).await?.policy;
1922 let material = with_resource(accessor, input, |input| {
1923 polymorph_webcrypto_core::derive_aes_gcm_key(&input.material, variant.into(), policy)
1924 })
1925 .await?;
1926 mint(accessor, material).await
1927 }
1928
1929 async fn unwrap_key_raw(
1930 accessor: &Accessor<T, Self>,
1931 variant: aes_gcm_iface::AesVariant,
1932 input: Resource<UnwrapInput>,
1933 options: Resource<crate::AeadKeyOptions>,
1934 ) -> Result<std::result::Result<Resource<AeadKey>, Error>> {
1935 let policy = take_options(accessor, options).await?.policy;
1936 let input = take_options(accessor, input).await?.material;
1937 let material = polymorph_webcrypto_core::unwrap_aes_gcm_key(variant.into(), input, policy);
1938 mint(accessor, material).await
1939 }
1940
1941 async fn unwrap_key_jwk(
1942 accessor: &Accessor<T, Self>,
1943 variant: aes_gcm_iface::AesVariant,
1944 input: Resource<UnwrapInput>,
1945 options: Resource<crate::AeadKeyOptions>,
1946 ) -> Result<std::result::Result<Resource<AeadKey>, Error>> {
1947 let policy = take_options(accessor, options).await?.policy;
1948 let input = take_options(accessor, input).await?.material;
1949 let material =
1950 polymorph_webcrypto_core::unwrap_aes_gcm_key_jwk(variant.into(), input, policy);
1951 mint(accessor, material).await
1952 }
1953}
1954
1955impl signature_iface::Host for WasiWebcryptoCtxView<'_> {}
1958
1959impl signature_iface::HostVerifyingKey for WasiWebcryptoCtxView<'_> {
1960 fn algorithm_name(&mut self, self_: Resource<VerifyingKey>) -> Result<String> {
1961 Ok(self.table.get(&self_)?.public.name().to_string())
1962 }
1963
1964 fn algorithm_curve(&mut self, self_: Resource<VerifyingKey>) -> Result<Option<String>> {
1965 Ok(self.table.get(&self_)?.public.curve().map(str::to_string))
1966 }
1967
1968 fn algorithm_hash(&mut self, self_: Resource<VerifyingKey>) -> Result<Option<String>> {
1969 Ok(self.table.get(&self_)?.public.hash().map(str::to_string))
1970 }
1971
1972 fn algorithm_length(&mut self, self_: Resource<VerifyingKey>) -> Result<Option<u32>> {
1973 Ok(self.table.get(&self_)?.public.length())
1974 }
1975
1976 fn algorithm_public_exponent(
1977 &mut self,
1978 self_: Resource<VerifyingKey>,
1979 ) -> Result<Option<Vec<u8>>> {
1980 Ok(self.table.get(&self_)?.public.public_exponent())
1981 }
1982}
1983
1984impl<T: Send> signature_iface::HostVerifyingKeyWithStore<T> for WasiWebcrypto {
1985 async fn verify(
1986 accessor: &Accessor<T, Self>,
1987 self_: Resource<VerifyingKey>,
1988 data: StreamReader<u8>,
1989 sig: Vec<u8>,
1990 ) -> Result<std::result::Result<(), Error>> {
1991 drain_then(accessor, self_, data, |key, bytes| {
1992 key.public.verify(bytes, &sig).map_err(Error::from)
1993 })
1994 .await
1995 }
1996
1997 async fn export_key_raw(
1998 accessor: &Accessor<T, Self>,
1999 self_: Resource<VerifyingKey>,
2000 ) -> Result<std::result::Result<Vec<u8>, Error>> {
2001 with_resource(accessor, self_, |key| {
2002 key.public.export().map_err(Error::from)
2003 })
2004 .await
2005 }
2006
2007 async fn export_key_spki(
2008 accessor: &Accessor<T, Self>,
2009 self_: Resource<VerifyingKey>,
2010 ) -> Result<std::result::Result<Vec<u8>, Error>> {
2011 with_resource(accessor, self_, |key| Ok(key.public.export_spki())).await
2012 }
2013
2014 async fn export_key_jwk(
2015 accessor: &Accessor<T, Self>,
2016 self_: Resource<VerifyingKey>,
2017 ) -> Result<std::result::Result<String, Error>> {
2018 with_resource(accessor, self_, |key| Ok(key.public.export_jwk())).await
2019 }
2020
2021 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<VerifyingKey>) -> Result<()> {
2022 drop_resource(accessor, rep).await
2023 }
2024}
2025
2026impl signature_iface::HostSigningKey for WasiWebcryptoCtxView<'_> {
2027 fn algorithm_name(&mut self, self_: Resource<SigningKey>) -> Result<String> {
2028 Ok(self.table.get(&self_)?.material.name().to_string())
2029 }
2030
2031 fn algorithm_curve(&mut self, self_: Resource<SigningKey>) -> Result<Option<String>> {
2032 Ok(self.table.get(&self_)?.material.curve().map(str::to_string))
2033 }
2034
2035 fn algorithm_hash(&mut self, self_: Resource<SigningKey>) -> Result<Option<String>> {
2036 Ok(self.table.get(&self_)?.material.hash().map(str::to_string))
2037 }
2038
2039 fn algorithm_length(&mut self, self_: Resource<SigningKey>) -> Result<Option<u32>> {
2040 Ok(self.table.get(&self_)?.material.length())
2041 }
2042
2043 fn algorithm_public_exponent(
2044 &mut self,
2045 self_: Resource<SigningKey>,
2046 ) -> Result<Option<Vec<u8>>> {
2047 Ok(self.table.get(&self_)?.material.public_exponent())
2048 }
2049
2050 fn extractable(&mut self, self_: Resource<SigningKey>) -> Result<bool> {
2051 Ok(self.table.get(&self_)?.material.extractable())
2052 }
2053
2054 fn can_sign(&mut self, self_: Resource<SigningKey>) -> Result<bool> {
2055 Ok(self.table.get(&self_)?.material.can_sign())
2056 }
2057}
2058
2059host_options! {
2060 signature_iface::{HostSigningKeyOptions, HostSigningKeyOptionsWithStore}
2061 for crate::SigningKeyOptions {
2062 can_sign => sign,
2063 extractable => extractable,
2064 }
2065}
2066
2067impl<T: Send> signature_iface::HostSigningKeyWithStore<T> for WasiWebcrypto {
2068 async fn sign(
2069 accessor: &Accessor<T, Self>,
2070 self_: Resource<SigningKey>,
2071 data: StreamReader<u8>,
2072 ) -> Result<std::result::Result<Vec<u8>, Error>> {
2073 drain_then(accessor, self_, data, |key, bytes| {
2074 key.material.sign(bytes).map_err(Error::from)
2075 })
2076 .await
2077 }
2078
2079 async fn export_key_jwk(
2080 accessor: &Accessor<T, Self>,
2081 self_: Resource<SigningKey>,
2082 ) -> Result<std::result::Result<String, Error>> {
2083 with_resource(accessor, self_, |key| {
2084 key.material.export_jwk().map_err(Error::from)
2085 })
2086 .await
2087 }
2088
2089 async fn export_key_pkcs8(
2090 accessor: &Accessor<T, Self>,
2091 self_: Resource<SigningKey>,
2092 ) -> Result<std::result::Result<Vec<u8>, Error>> {
2093 with_resource(accessor, self_, |key| {
2094 key.material.export_pkcs8().map_err(Error::from)
2095 })
2096 .await
2097 }
2098
2099 async fn to_wrap_input_jwk(
2100 accessor: &Accessor<T, Self>,
2101 self_: Resource<SigningKey>,
2102 ) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
2103 to_wrap_input(accessor, self_, WrapFormat::Jwk, |key| {
2104 key.material.export_jwk().map(String::into_bytes)
2105 })
2106 .await
2107 }
2108
2109 async fn to_wrap_input_pkcs8(
2110 accessor: &Accessor<T, Self>,
2111 self_: Resource<SigningKey>,
2112 ) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
2113 to_wrap_input(accessor, self_, WrapFormat::Pkcs8, |key| {
2114 key.material.export_pkcs8()
2115 })
2116 .await
2117 }
2118
2119 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<SigningKey>) -> Result<()> {
2120 drop_resource(accessor, rep).await
2121 }
2122}
2123
2124impl ed25519_verify_iface::Host for WasiWebcryptoCtxView<'_> {}
2127impl ed25519_sign_iface::Host for WasiWebcryptoCtxView<'_> {}
2128
2129impl<T: Send> ed25519_verify_iface::HostWithStore<T> for WasiWebcrypto {
2130 async fn import_verifying_key_raw(
2131 accessor: &Accessor<T, Self>,
2132 raw: Vec<u8>,
2133 ) -> Result<std::result::Result<Resource<VerifyingKey>, Error>> {
2134 let public = SigPublic::import_ed25519(&raw);
2135 mint(accessor, public).await
2136 }
2137
2138 async fn import_verifying_key_spki(
2139 accessor: &Accessor<T, Self>,
2140 spki: Vec<u8>,
2141 ) -> Result<std::result::Result<Resource<VerifyingKey>, Error>> {
2142 let public = SigPublic::import_ed25519_spki(&spki);
2143 mint(accessor, public).await
2144 }
2145
2146 async fn import_verifying_key_jwk(
2147 accessor: &Accessor<T, Self>,
2148 jwk: String,
2149 ) -> Result<std::result::Result<Resource<VerifyingKey>, Error>> {
2150 let public = SigPublic::import_ed25519_jwk(&jwk);
2151 mint(accessor, public).await
2152 }
2153}
2154
2155impl<T: Send> ed25519_sign_iface::HostWithStore<T> for WasiWebcrypto {
2156 async fn generate_key(
2157 accessor: &Accessor<T, Self>,
2158 options: Resource<crate::SigningKeyOptions>,
2159 ) -> Result<std::result::Result<(Resource<SigningKey>, Resource<VerifyingKey>), Error>> {
2160 let policy = take_options(accessor, options).await?.policy;
2161 let material = match SigningKeyMaterial::generate_ed25519(policy)
2162 .map_err(rng_trap("random key generation"))?
2163 {
2164 Ok(material) => material,
2165 Err(err) => return Ok(Err(err.into())),
2166 };
2167 mint_signing_pair(accessor, material).await
2168 }
2169
2170 async fn import_signing_key_pkcs8(
2171 accessor: &Accessor<T, Self>,
2172 pkcs8: Vec<u8>,
2173 options: Resource<crate::SigningKeyOptions>,
2174 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2175 let policy = take_options(accessor, options).await?.policy;
2176 let material = SigningKeyMaterial::import_ed25519_pkcs8(&pkcs8, policy);
2177 mint(accessor, material).await
2178 }
2179
2180 async fn import_signing_key_jwk(
2181 accessor: &Accessor<T, Self>,
2182 jwk: String,
2183 options: Resource<crate::SigningKeyOptions>,
2184 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2185 let policy = take_options(accessor, options).await?.policy;
2186 let material = SigningKeyMaterial::import_ed25519_jwk(&jwk, policy);
2187 mint(accessor, material).await
2188 }
2189
2190 async fn unwrap_signing_key_pkcs8(
2191 accessor: &Accessor<T, Self>,
2192 input: Resource<UnwrapInput>,
2193 options: Resource<crate::SigningKeyOptions>,
2194 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2195 let policy = take_options(accessor, options).await?.policy;
2196 let input = take_options(accessor, input).await?.material;
2197 let material = polymorph_webcrypto_core::unwrap_ed25519_signing_key_pkcs8(input, policy);
2198 mint(accessor, material).await
2199 }
2200
2201 async fn unwrap_signing_key_jwk(
2202 accessor: &Accessor<T, Self>,
2203 input: Resource<UnwrapInput>,
2204 options: Resource<crate::SigningKeyOptions>,
2205 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2206 let policy = take_options(accessor, options).await?.policy;
2207 let input = take_options(accessor, input).await?.material;
2208 let material = polymorph_webcrypto_core::unwrap_ed25519_signing_key_jwk(input, policy);
2209 mint(accessor, material).await
2210 }
2211}
2212
2213async fn mint_signing_pair<T: Send>(
2215 accessor: &Accessor<T, WasiWebcrypto>,
2216 material: SigningKeyMaterial,
2217) -> Result<std::result::Result<(Resource<SigningKey>, Resource<VerifyingKey>), Error>> {
2218 let public = material.public();
2219 mint_key_pair(accessor, material, public).await
2220}
2221
2222impl ecdsa_verify_iface::Host for WasiWebcryptoCtxView<'_> {}
2225impl ecdsa_sign_iface::Host for WasiWebcryptoCtxView<'_> {}
2226
2227impl<T: Send> ecdsa_verify_iface::HostWithStore<T> for WasiWebcrypto {
2228 async fn import_verifying_key_raw(
2229 accessor: &Accessor<T, Self>,
2230 variant: ecdsa_verify_iface::EcdsaVariant,
2231 raw: Vec<u8>,
2232 ) -> Result<std::result::Result<Resource<VerifyingKey>, Error>> {
2233 let public = SigPublic::import_ecdsa(variant.into(), &raw);
2234 mint(accessor, public).await
2235 }
2236
2237 async fn import_verifying_key_spki(
2238 accessor: &Accessor<T, Self>,
2239 variant: ecdsa_verify_iface::EcdsaVariant,
2240 spki: Vec<u8>,
2241 ) -> Result<std::result::Result<Resource<VerifyingKey>, Error>> {
2242 let public = SigPublic::import_ecdsa_spki(variant.into(), &spki);
2243 mint(accessor, public).await
2244 }
2245
2246 async fn import_verifying_key_jwk(
2247 accessor: &Accessor<T, Self>,
2248 variant: ecdsa_verify_iface::EcdsaVariant,
2249 jwk: String,
2250 ) -> Result<std::result::Result<Resource<VerifyingKey>, Error>> {
2251 let public = SigPublic::import_ecdsa_jwk(variant.into(), &jwk);
2252 mint(accessor, public).await
2253 }
2254}
2255
2256impl<T: Send> ecdsa_sign_iface::HostWithStore<T> for WasiWebcrypto {
2257 async fn generate_key(
2258 accessor: &Accessor<T, Self>,
2259 variant: ecdsa_verify_iface::EcdsaVariant,
2260 options: Resource<crate::SigningKeyOptions>,
2261 ) -> Result<std::result::Result<(Resource<SigningKey>, Resource<VerifyingKey>), Error>> {
2262 let policy = take_options(accessor, options).await?.policy;
2263 let material = match SigningKeyMaterial::generate_ecdsa(variant.into(), policy)
2264 .map_err(rng_trap("random key generation"))?
2265 {
2266 Ok(material) => material,
2267 Err(err) => return Ok(Err(err.into())),
2268 };
2269 mint_signing_pair(accessor, material).await
2270 }
2271
2272 async fn import_signing_key_pkcs8(
2273 accessor: &Accessor<T, Self>,
2274 variant: ecdsa_verify_iface::EcdsaVariant,
2275 pkcs8: Vec<u8>,
2276 options: Resource<crate::SigningKeyOptions>,
2277 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2278 let policy = take_options(accessor, options).await?.policy;
2279 let material = SigningKeyMaterial::import_ecdsa_pkcs8(variant.into(), &pkcs8, policy);
2280 mint(accessor, material).await
2281 }
2282
2283 async fn import_signing_key_jwk(
2284 accessor: &Accessor<T, Self>,
2285 variant: ecdsa_verify_iface::EcdsaVariant,
2286 jwk: String,
2287 options: Resource<crate::SigningKeyOptions>,
2288 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2289 let policy = take_options(accessor, options).await?.policy;
2290 let material = SigningKeyMaterial::import_ecdsa_jwk(variant.into(), &jwk, policy);
2291 mint(accessor, material).await
2292 }
2293
2294 async fn unwrap_signing_key_pkcs8(
2295 accessor: &Accessor<T, Self>,
2296 variant: ecdsa_verify_iface::EcdsaVariant,
2297 input: Resource<UnwrapInput>,
2298 options: Resource<crate::SigningKeyOptions>,
2299 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2300 let policy = take_options(accessor, options).await?.policy;
2301 let input = take_options(accessor, input).await?.material;
2302 let material =
2303 polymorph_webcrypto_core::unwrap_ecdsa_signing_key_pkcs8(variant.into(), input, policy);
2304 mint(accessor, material).await
2305 }
2306
2307 async fn unwrap_signing_key_jwk(
2308 accessor: &Accessor<T, Self>,
2309 variant: ecdsa_verify_iface::EcdsaVariant,
2310 input: Resource<UnwrapInput>,
2311 options: Resource<crate::SigningKeyOptions>,
2312 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2313 let policy = take_options(accessor, options).await?.policy;
2314 let input = take_options(accessor, input).await?.material;
2315 let material =
2316 polymorph_webcrypto_core::unwrap_ecdsa_signing_key_jwk(variant.into(), input, policy);
2317 mint(accessor, material).await
2318 }
2319}
2320
2321impl rsa_iface::Host for WasiWebcryptoCtxView<'_> {}
2324impl rsassa_verify_iface::Host for WasiWebcryptoCtxView<'_> {}
2325impl rsa_pss_verify_iface::Host for WasiWebcryptoCtxView<'_> {}
2326impl rsassa_sign_iface::Host for WasiWebcryptoCtxView<'_> {}
2327impl rsa_pss_sign_iface::Host for WasiWebcryptoCtxView<'_> {}
2328
2329impl From<rsa_iface::RsaModulus> for polymorph_webcrypto_core::RsaModulus {
2333 fn from(modulus: rsa_iface::RsaModulus) -> Self {
2334 match modulus {
2335 rsa_iface::RsaModulus::M2048 => Self::M2048,
2336 rsa_iface::RsaModulus::M3072 => Self::M3072,
2337 rsa_iface::RsaModulus::M4096 => Self::M4096,
2338 rsa_iface::RsaModulus::M8192 => Self::M8192,
2339 }
2340 }
2341}
2342
2343impl<T: Send> rsassa_verify_iface::HostWithStore<T> for WasiWebcrypto {
2344 async fn import_verifying_key_spki(
2345 accessor: &Accessor<T, Self>,
2346 variant: rsa_iface::RsaVariant,
2347 spki: Vec<u8>,
2348 ) -> Result<std::result::Result<Resource<VerifyingKey>, Error>> {
2349 let public = SigPublic::import_rsassa_spki(variant.into(), &spki);
2350 mint(accessor, public).await
2351 }
2352
2353 async fn import_verifying_key_jwk(
2354 accessor: &Accessor<T, Self>,
2355 variant: rsa_iface::RsaVariant,
2356 jwk: String,
2357 ) -> Result<std::result::Result<Resource<VerifyingKey>, Error>> {
2358 let public = SigPublic::import_rsassa_jwk(variant.into(), &jwk);
2359 mint(accessor, public).await
2360 }
2361}
2362
2363impl<T: Send> rsa_pss_verify_iface::HostWithStore<T> for WasiWebcrypto {
2364 async fn import_verifying_key_spki(
2365 accessor: &Accessor<T, Self>,
2366 variant: rsa_iface::RsaVariant,
2367 salt_length: u32,
2368 spki: Vec<u8>,
2369 ) -> Result<std::result::Result<Resource<VerifyingKey>, Error>> {
2370 let public = SigPublic::import_pss_spki(variant.into(), salt_length, &spki);
2371 mint(accessor, public).await
2372 }
2373
2374 async fn import_verifying_key_jwk(
2375 accessor: &Accessor<T, Self>,
2376 variant: rsa_iface::RsaVariant,
2377 salt_length: u32,
2378 jwk: String,
2379 ) -> Result<std::result::Result<Resource<VerifyingKey>, Error>> {
2380 let public = SigPublic::import_pss_jwk(variant.into(), salt_length, &jwk);
2381 mint(accessor, public).await
2382 }
2383}
2384
2385impl<T: Send> rsassa_sign_iface::HostWithStore<T> for WasiWebcrypto {
2386 async fn generate_key(
2387 accessor: &Accessor<T, Self>,
2388 variant: rsa_iface::RsaVariant,
2389 modulus: rsa_iface::RsaModulus,
2390 options: Resource<crate::SigningKeyOptions>,
2391 ) -> Result<std::result::Result<(Resource<SigningKey>, Resource<VerifyingKey>), Error>> {
2392 let policy = take_options(accessor, options).await?.policy;
2393 let material =
2394 match SigningKeyMaterial::generate_rsassa(variant.into(), modulus.into(), policy)
2395 .map_err(rng_trap("random key generation"))?
2396 {
2397 Ok(material) => material,
2398 Err(err) => return Ok(Err(err.into())),
2399 };
2400 mint_signing_pair(accessor, material).await
2401 }
2402
2403 async fn import_signing_key_pkcs8(
2404 accessor: &Accessor<T, Self>,
2405 variant: rsa_iface::RsaVariant,
2406 pkcs8: Vec<u8>,
2407 options: Resource<crate::SigningKeyOptions>,
2408 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2409 let policy = take_options(accessor, options).await?.policy;
2410 let material = SigningKeyMaterial::import_rsassa_pkcs8(variant.into(), &pkcs8, policy);
2411 mint(accessor, material).await
2412 }
2413
2414 async fn import_signing_key_jwk(
2415 accessor: &Accessor<T, Self>,
2416 variant: rsa_iface::RsaVariant,
2417 jwk: String,
2418 options: Resource<crate::SigningKeyOptions>,
2419 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2420 let policy = take_options(accessor, options).await?.policy;
2421 let material = SigningKeyMaterial::import_rsassa_jwk(variant.into(), &jwk, policy);
2422 mint(accessor, material).await
2423 }
2424
2425 async fn unwrap_signing_key_pkcs8(
2426 accessor: &Accessor<T, Self>,
2427 variant: rsa_iface::RsaVariant,
2428 input: Resource<UnwrapInput>,
2429 options: Resource<crate::SigningKeyOptions>,
2430 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2431 let policy = take_options(accessor, options).await?.policy;
2432 let input = take_options(accessor, input).await?.material;
2433 let material = polymorph_webcrypto_core::unwrap_rsassa_signing_key_pkcs8(
2434 variant.into(),
2435 input,
2436 policy,
2437 );
2438 mint(accessor, material).await
2439 }
2440
2441 async fn unwrap_signing_key_jwk(
2442 accessor: &Accessor<T, Self>,
2443 variant: rsa_iface::RsaVariant,
2444 input: Resource<UnwrapInput>,
2445 options: Resource<crate::SigningKeyOptions>,
2446 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2447 let policy = take_options(accessor, options).await?.policy;
2448 let input = take_options(accessor, input).await?.material;
2449 let material =
2450 polymorph_webcrypto_core::unwrap_rsassa_signing_key_jwk(variant.into(), input, policy);
2451 mint(accessor, material).await
2452 }
2453}
2454
2455impl<T: Send> rsa_pss_sign_iface::HostWithStore<T> for WasiWebcrypto {
2456 async fn generate_key(
2457 accessor: &Accessor<T, Self>,
2458 variant: rsa_iface::RsaVariant,
2459 modulus: rsa_iface::RsaModulus,
2460 options: Resource<crate::SigningKeyOptions>,
2461 ) -> Result<std::result::Result<(Resource<SigningKey>, Resource<VerifyingKey>), Error>> {
2462 let policy = take_options(accessor, options).await?.policy;
2463 let material =
2464 match SigningKeyMaterial::generate_pss(variant.into(), modulus.into(), policy)
2465 .map_err(rng_trap("random key generation"))?
2466 {
2467 Ok(material) => material,
2468 Err(err) => return Ok(Err(err.into())),
2469 };
2470 mint_signing_pair(accessor, material).await
2471 }
2472
2473 async fn import_signing_key_pkcs8(
2474 accessor: &Accessor<T, Self>,
2475 variant: rsa_iface::RsaVariant,
2476 pkcs8: Vec<u8>,
2477 options: Resource<crate::SigningKeyOptions>,
2478 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2479 let policy = take_options(accessor, options).await?.policy;
2480 let material = SigningKeyMaterial::import_pss_pkcs8(variant.into(), &pkcs8, policy);
2481 mint(accessor, material).await
2482 }
2483
2484 async fn import_signing_key_jwk(
2485 accessor: &Accessor<T, Self>,
2486 variant: rsa_iface::RsaVariant,
2487 jwk: String,
2488 options: Resource<crate::SigningKeyOptions>,
2489 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2490 let policy = take_options(accessor, options).await?.policy;
2491 let material = SigningKeyMaterial::import_pss_jwk(variant.into(), &jwk, policy);
2492 mint(accessor, material).await
2493 }
2494
2495 async fn unwrap_signing_key_pkcs8(
2496 accessor: &Accessor<T, Self>,
2497 variant: rsa_iface::RsaVariant,
2498 input: Resource<UnwrapInput>,
2499 options: Resource<crate::SigningKeyOptions>,
2500 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2501 let policy = take_options(accessor, options).await?.policy;
2502 let input = take_options(accessor, input).await?.material;
2503 let material =
2504 polymorph_webcrypto_core::unwrap_pss_signing_key_pkcs8(variant.into(), input, policy);
2505 mint(accessor, material).await
2506 }
2507
2508 async fn unwrap_signing_key_jwk(
2509 accessor: &Accessor<T, Self>,
2510 variant: rsa_iface::RsaVariant,
2511 input: Resource<UnwrapInput>,
2512 options: Resource<crate::SigningKeyOptions>,
2513 ) -> Result<std::result::Result<Resource<SigningKey>, Error>> {
2514 let policy = take_options(accessor, options).await?.policy;
2515 let input = take_options(accessor, input).await?.material;
2516 let material =
2517 polymorph_webcrypto_core::unwrap_pss_signing_key_jwk(variant.into(), input, policy);
2518 mint(accessor, material).await
2519 }
2520}
2521
2522impl public_encryption_iface::Host for WasiWebcryptoCtxView<'_> {}
2525
2526host_options! {
2527 public_encryption_iface::{HostDecryptionKeyOptions, HostDecryptionKeyOptionsWithStore}
2528 for crate::DecryptionKeyOptions {
2529 can_decrypt => decrypt,
2530 can_unwrap => unwrap,
2531 extractable => extractable,
2532 }
2533}
2534
2535impl HostEncryptionKey for WasiWebcryptoCtxView<'_> {
2536 fn algorithm_name(&mut self, self_: Resource<EncryptionKey>) -> Result<String> {
2537 Ok(self.table.get(&self_)?.material.name().to_string())
2538 }
2539
2540 fn algorithm_hash(&mut self, self_: Resource<EncryptionKey>) -> Result<Option<String>> {
2541 Ok(self.table.get(&self_)?.material.hash().map(str::to_string))
2542 }
2543
2544 fn algorithm_length(&mut self, self_: Resource<EncryptionKey>) -> Result<Option<u32>> {
2545 Ok(self.table.get(&self_)?.material.length())
2546 }
2547
2548 fn algorithm_public_exponent(
2549 &mut self,
2550 self_: Resource<EncryptionKey>,
2551 ) -> Result<Option<Vec<u8>>> {
2552 Ok(self.table.get(&self_)?.material.public_exponent())
2553 }
2554}
2555
2556impl<T: Send> HostEncryptionKeyWithStore<T> for WasiWebcrypto {
2557 async fn encrypt(
2558 accessor: &Accessor<T, Self>,
2559 self_: Resource<EncryptionKey>,
2560 label: Option<Vec<u8>>,
2561 plaintext: Vec<u8>,
2562 ) -> Result<std::result::Result<Vec<u8>, Error>> {
2563 with_resource(accessor, self_, |key| {
2564 key.material
2565 .encrypt(label.as_deref(), &plaintext)
2566 .map_err(Error::from)
2567 })
2568 .await
2569 }
2570
2571 async fn wrap(
2572 accessor: &Accessor<T, Self>,
2573 self_: Resource<EncryptionKey>,
2574 label: Option<Vec<u8>>,
2575 input: Resource<WrapInput>,
2576 ) -> Result<std::result::Result<Vec<u8>, Error>> {
2577 let input = take_options(accessor, input).await?.material;
2578 with_resource(accessor, self_, |key| {
2579 key.material
2580 .wrap(label.as_deref(), input)
2581 .map_err(Error::from)
2582 })
2583 .await
2584 }
2585
2586 async fn export_key_raw(
2587 accessor: &Accessor<T, Self>,
2588 self_: Resource<EncryptionKey>,
2589 ) -> Result<std::result::Result<Vec<u8>, Error>> {
2590 with_resource(accessor, self_, |key| {
2591 key.material.export().map_err(Error::from)
2592 })
2593 .await
2594 }
2595
2596 async fn export_key_spki(
2597 accessor: &Accessor<T, Self>,
2598 self_: Resource<EncryptionKey>,
2599 ) -> Result<std::result::Result<Vec<u8>, Error>> {
2600 with_resource(accessor, self_, |key| Ok(key.material.export_spki())).await
2601 }
2602
2603 async fn export_key_jwk(
2604 accessor: &Accessor<T, Self>,
2605 self_: Resource<EncryptionKey>,
2606 ) -> Result<std::result::Result<String, Error>> {
2607 with_resource(accessor, self_, |key| Ok(key.material.export_jwk())).await
2608 }
2609
2610 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<EncryptionKey>) -> Result<()> {
2611 drop_resource(accessor, rep).await
2612 }
2613}
2614
2615impl HostDecryptionKey for WasiWebcryptoCtxView<'_> {
2616 fn algorithm_name(&mut self, self_: Resource<DecryptionKey>) -> Result<String> {
2617 Ok(self.table.get(&self_)?.material.name().to_string())
2618 }
2619
2620 fn algorithm_hash(&mut self, self_: Resource<DecryptionKey>) -> Result<Option<String>> {
2621 Ok(self.table.get(&self_)?.material.hash().map(str::to_string))
2622 }
2623
2624 fn algorithm_length(&mut self, self_: Resource<DecryptionKey>) -> Result<Option<u32>> {
2625 Ok(self.table.get(&self_)?.material.length())
2626 }
2627
2628 fn algorithm_public_exponent(
2629 &mut self,
2630 self_: Resource<DecryptionKey>,
2631 ) -> Result<Option<Vec<u8>>> {
2632 Ok(self.table.get(&self_)?.material.public_exponent())
2633 }
2634
2635 fn can_decrypt(&mut self, self_: Resource<DecryptionKey>) -> Result<bool> {
2636 Ok(self.table.get(&self_)?.material.can_decrypt())
2637 }
2638
2639 fn can_unwrap(&mut self, self_: Resource<DecryptionKey>) -> Result<bool> {
2640 Ok(self.table.get(&self_)?.material.can_unwrap())
2641 }
2642
2643 fn extractable(&mut self, self_: Resource<DecryptionKey>) -> Result<bool> {
2644 Ok(self.table.get(&self_)?.material.extractable())
2645 }
2646}
2647
2648impl<T: Send> HostDecryptionKeyWithStore<T> for WasiWebcrypto {
2649 async fn decrypt(
2650 accessor: &Accessor<T, Self>,
2651 self_: Resource<DecryptionKey>,
2652 label: Option<Vec<u8>>,
2653 ciphertext: Vec<u8>,
2654 ) -> Result<std::result::Result<Vec<u8>, Error>> {
2655 with_resource(accessor, self_, |key| {
2656 key.material
2657 .decrypt(label.as_deref(), &ciphertext)
2658 .map_err(Error::from)
2659 })
2660 .await
2661 }
2662
2663 async fn unwrap(
2664 accessor: &Accessor<T, Self>,
2665 self_: Resource<DecryptionKey>,
2666 label: Option<Vec<u8>>,
2667 ciphertext: Vec<u8>,
2668 ) -> Result<std::result::Result<Resource<UnwrapInput>, Error>> {
2669 let material = with_resource(accessor, self_, |key| {
2670 key.material.unwrap(label.as_deref(), &ciphertext)
2671 })
2672 .await?;
2673 mint(accessor, material).await
2674 }
2675
2676 async fn export_key_jwk(
2677 accessor: &Accessor<T, Self>,
2678 self_: Resource<DecryptionKey>,
2679 ) -> Result<std::result::Result<String, Error>> {
2680 with_resource(accessor, self_, |key| {
2681 key.material.export_jwk().map_err(Error::from)
2682 })
2683 .await
2684 }
2685
2686 async fn export_key_pkcs8(
2687 accessor: &Accessor<T, Self>,
2688 self_: Resource<DecryptionKey>,
2689 ) -> Result<std::result::Result<Vec<u8>, Error>> {
2690 with_resource(accessor, self_, |key| {
2691 key.material.export_pkcs8().map_err(Error::from)
2692 })
2693 .await
2694 }
2695
2696 async fn to_wrap_input_jwk(
2697 accessor: &Accessor<T, Self>,
2698 self_: Resource<DecryptionKey>,
2699 ) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
2700 to_wrap_input(accessor, self_, WrapFormat::Jwk, |key| {
2701 key.material.export_jwk().map(String::into_bytes)
2702 })
2703 .await
2704 }
2705
2706 async fn to_wrap_input_pkcs8(
2707 accessor: &Accessor<T, Self>,
2708 self_: Resource<DecryptionKey>,
2709 ) -> Result<std::result::Result<Resource<WrapInput>, Error>> {
2710 to_wrap_input(accessor, self_, WrapFormat::Pkcs8, |key| {
2711 key.material.export_pkcs8()
2712 })
2713 .await
2714 }
2715
2716 async fn drop(accessor: &Accessor<T, Self>, rep: Resource<DecryptionKey>) -> Result<()> {
2717 drop_resource(accessor, rep).await
2718 }
2719}
2720
2721impl rsa_oaep_encrypt_iface::Host for WasiWebcryptoCtxView<'_> {}
2724impl rsa_oaep_decrypt_iface::Host for WasiWebcryptoCtxView<'_> {}
2725
2726impl<T: Send> rsa_oaep_encrypt_iface::HostWithStore<T> for WasiWebcrypto {
2727 async fn import_encryption_key_spki(
2728 accessor: &Accessor<T, Self>,
2729 variant: rsa_iface::RsaVariant,
2730 spki: Vec<u8>,
2731 ) -> Result<std::result::Result<Resource<EncryptionKey>, Error>> {
2732 let material = EncryptionKeyMaterial::import_oaep_spki(variant.into(), &spki);
2733 mint(accessor, material).await
2734 }
2735
2736 async fn import_encryption_key_jwk(
2737 accessor: &Accessor<T, Self>,
2738 variant: rsa_iface::RsaVariant,
2739 jwk: String,
2740 ) -> Result<std::result::Result<Resource<EncryptionKey>, Error>> {
2741 let material = EncryptionKeyMaterial::import_oaep_jwk(variant.into(), &jwk);
2742 mint(accessor, material).await
2743 }
2744}
2745
2746impl<T: Send> rsa_oaep_decrypt_iface::HostWithStore<T> for WasiWebcrypto {
2747 async fn generate_key(
2748 accessor: &Accessor<T, Self>,
2749 variant: rsa_iface::RsaVariant,
2750 modulus: rsa_iface::RsaModulus,
2751 options: Resource<crate::DecryptionKeyOptions>,
2752 ) -> Result<std::result::Result<(Resource<DecryptionKey>, Resource<EncryptionKey>), Error>>
2753 {
2754 let policy = take_options(accessor, options).await?.policy;
2755 let material =
2756 match DecryptionKeyMaterial::generate_oaep(variant.into(), modulus.into(), policy)
2757 .map_err(rng_trap("random key generation"))?
2758 {
2759 Ok(material) => material,
2760 Err(err) => return Ok(Err(err.into())),
2761 };
2762 let public = material.public();
2763 mint_key_pair(accessor, material, public).await
2764 }
2765
2766 async fn import_decryption_key_pkcs8(
2767 accessor: &Accessor<T, Self>,
2768 variant: rsa_iface::RsaVariant,
2769 pkcs8: Vec<u8>,
2770 options: Resource<crate::DecryptionKeyOptions>,
2771 ) -> Result<std::result::Result<Resource<DecryptionKey>, Error>> {
2772 let policy = take_options(accessor, options).await?.policy;
2773 let material = DecryptionKeyMaterial::import_oaep_pkcs8(variant.into(), &pkcs8, policy);
2774 mint(accessor, material).await
2775 }
2776
2777 async fn import_decryption_key_jwk(
2778 accessor: &Accessor<T, Self>,
2779 variant: rsa_iface::RsaVariant,
2780 jwk: String,
2781 options: Resource<crate::DecryptionKeyOptions>,
2782 ) -> Result<std::result::Result<Resource<DecryptionKey>, Error>> {
2783 let policy = take_options(accessor, options).await?.policy;
2784 let material = DecryptionKeyMaterial::import_oaep_jwk(variant.into(), &jwk, policy);
2785 mint(accessor, material).await
2786 }
2787
2788 async fn unwrap_decryption_key_pkcs8(
2789 accessor: &Accessor<T, Self>,
2790 variant: rsa_iface::RsaVariant,
2791 input: Resource<UnwrapInput>,
2792 options: Resource<crate::DecryptionKeyOptions>,
2793 ) -> Result<std::result::Result<Resource<DecryptionKey>, Error>> {
2794 let policy = take_options(accessor, options).await?.policy;
2795 let input = take_options(accessor, input).await?.material;
2796 let material = polymorph_webcrypto_core::unwrap_oaep_decryption_key_pkcs8(
2797 variant.into(),
2798 input,
2799 policy,
2800 );
2801 mint(accessor, material).await
2802 }
2803
2804 async fn unwrap_decryption_key_jwk(
2805 accessor: &Accessor<T, Self>,
2806 variant: rsa_iface::RsaVariant,
2807 input: Resource<UnwrapInput>,
2808 options: Resource<crate::DecryptionKeyOptions>,
2809 ) -> Result<std::result::Result<Resource<DecryptionKey>, Error>> {
2810 let policy = take_options(accessor, options).await?.policy;
2811 let input = take_options(accessor, input).await?.material;
2812 let material =
2813 polymorph_webcrypto_core::unwrap_oaep_decryption_key_jwk(variant.into(), input, policy);
2814 mint(accessor, material).await
2815 }
2816}
2817
2818#[cfg(test)]
2819mod tests {
2820 use crate::bindings::webcrypto::sha1_checked::Host as _;
2821 use crate::bindings::webcrypto::sha2::{self as sha2_iface, Host as _};
2822 use crate::bindings::webcrypto::types::Error;
2823 use crate::{MacKey, Minted as _};
2824 use polymorph_webcrypto_core::{MacKeyMaterial, MacPolicy, Sha2Variant};
2825
2826 #[test]
2831 fn minting_charges_the_retention_budget() {
2832 let mut ctx = crate::WasiWebcryptoCtx::new();
2833 ctx.set_retention_limit(Some(crate::limits::RETENTION_FLOOR));
2834 let mut table = wasmtime::component::ResourceTable::new();
2835 let mut view = crate::WasiWebcryptoCtxView {
2836 ctx: &mut ctx,
2837 table: &mut table,
2838 };
2839
2840 let digest = view
2841 .make_digest(sha2_iface::Sha2Variant::Sha256)
2842 .unwrap()
2843 .expect("one floor-sized mint fits the budget");
2844
2845 match view.make_rejecting_digest().unwrap() {
2846 Err(Error::Other(msg)) => assert!(msg.contains("set_retention_limit"), "{msg}"),
2847 other => panic!("expected the retention error, got {other:?}"),
2848 }
2849 let trap = crate::bindings::webcrypto::mac::HostMacKeyOptions::new(&mut view)
2850 .expect_err("an options mint past the budget traps");
2851 assert!(trap.to_string().contains("set_retention_limit"), "{trap}");
2852
2853 view.table.delete(digest).unwrap();
2854 view.make_rejecting_digest()
2855 .unwrap()
2856 .expect("the dropped resource's charge readmits the mint");
2857 }
2858
2859 #[test]
2864 fn debug_redacts_key_material() {
2865 let policy = MacPolicy {
2866 sign: true,
2867 verify: true,
2868 extractable: true,
2869 };
2870 let pool = crate::limits::pool(1024);
2871 let key = MacKey::minted(
2872 MacKeyMaterial::import(Sha2Variant::Sha256, vec![0xAB; 32], policy).unwrap(),
2873 crate::limits::charge(&pool, 32).unwrap(),
2874 );
2875 let rendered = format!("{key:?}");
2876 assert!(rendered.contains("<redacted>"), "{rendered}");
2877 assert!(!rendered.contains("171"), "{rendered}"); assert!(!rendered.to_lowercase().contains("ab, ab"), "{rendered}");
2879 }
2880}