1mod aead;
6mod ec;
7mod ecdsa;
8mod hmac;
9mod kdf;
10mod kem;
11
12pub mod x509;
13
14#[cfg(feature = "fips")]
15use aws_lc_fips_sys as aws_lc_sys_impl;
16
17#[cfg(not(feature = "fips"))]
18use aws_lc_sys as aws_lc_sys_impl;
19pub use hmac::AwsLcHmac;
20
21use std::{ffi::c_int, mem::MaybeUninit, num::TryFromIntError};
22
23pub use aead::AwsLcAead;
24use aws_lc_rs::error::{KeyRejected, Unspecified};
25
26use crate::aws_lc_sys_impl::SHA256;
27use mls_rs_core::{
28 crypto::{
29 CipherSuite, CipherSuiteProvider, CryptoProvider, HpkeCiphertext, HpkePublicKey,
30 HpkeSecretKey, SignaturePublicKey, SignatureSecretKey,
31 },
32 error::{AnyError, IntoAnyError},
33};
34
35pub use ecdsa::AwsLcEcdsa;
36pub use kdf::AwsLcHkdf;
37pub use kem::ecdh::Ecdh;
38use mls_rs_crypto_hpke::{
39 context::{ContextR, ContextS},
40 dhkem::DhKem,
41 hpke::{Hpke, HpkeError},
42};
43use mls_rs_crypto_traits::{AeadId, AeadType, Curve, Hash, KdfId, KdfType, KemId};
44use thiserror::Error;
45use zeroize::Zeroizing;
46
47#[cfg(feature = "post-quantum")]
48use self::kdf::shake::AwsLcShake128;
49
50#[cfg(feature = "post-quantum")]
51use mls_rs_crypto_hpke::kem_combiner::xwing::{CombinedKem, XWingSharedSecretHashInput};
52
53#[cfg(feature = "post-quantum")]
54pub use self::kem::ml_kem::{MlKem, MlKemKem};
55
56#[cfg(feature = "post-quantum")]
57pub use self::kdf::Sha3;
58
59pub use self::kdf::AwsLcHash;
60
61#[derive(Clone)]
62pub struct AwsLcCipherSuite {
63 cipher_suite: CipherSuite,
64 signing: AwsLcEcdsa,
65 aead: AwsLcAead,
66 kdf: AwsLcHkdf,
67 hpke: AwsLcHpke,
68 hmac: AwsLcHmac,
69 hash: AwsLcHash,
70}
71
72pub type EcdhKem = DhKem<Ecdh, AwsLcHkdf>;
73
74#[cfg(feature = "post-quantum")]
75pub type CombinedEcdhMlKemKem =
76 CombinedKem<MlKemKem, EcdhKem, AwsLcHash, AwsLcShake128, XWingSharedSecretHashInput>;
77
78#[derive(Clone)]
79#[non_exhaustive]
80enum AwsLcHpke {
81 Classical(Hpke<EcdhKem, AwsLcHkdf, AwsLcAead>),
82 #[cfg(feature = "post-quantum")]
83 PostQuantum(Hpke<MlKemKem, AwsLcHkdf, AwsLcAead>),
84 #[cfg(feature = "post-quantum")]
85 Combined(Hpke<CombinedEcdhMlKemKem, AwsLcHkdf, AwsLcAead>),
86}
87
88impl AwsLcCipherSuite {
89 pub fn import_ec_der_private_key(
90 &self,
91 bytes: &[u8],
92 ) -> Result<SignatureSecretKey, AwsLcCryptoError> {
93 self.signing.import_ec_der_private_key(bytes)
94 }
95
96 pub fn import_ec_der_public_key(
97 &self,
98 bytes: &[u8],
99 ) -> Result<SignaturePublicKey, AwsLcCryptoError> {
100 self.signing.import_ec_der_public_key(bytes)
101 }
102}
103
104#[derive(Clone, Debug)]
105pub struct AwsLcCryptoProvider {
106 pub enabled_cipher_suites: Vec<CipherSuite>,
107}
108
109impl Default for AwsLcCryptoProvider {
110 fn default() -> Self {
111 Self::new()
112 }
113}
114
115impl AwsLcCryptoProvider {
116 pub fn new() -> Self {
117 Self {
118 enabled_cipher_suites: Self::all_supported_cipher_suites(),
119 }
120 }
121
122 pub fn all_supported_cipher_suites() -> Vec<CipherSuite> {
123 [
124 Self::supported_classical_cipher_suites(),
125 #[cfg(feature = "post-quantum")]
126 Self::supported_pq_cipher_suites(),
127 ]
128 .concat()
129 }
130
131 pub fn supported_classical_cipher_suites() -> Vec<CipherSuite> {
132 vec![
133 CipherSuite::CURVE25519_AES128,
134 CipherSuite::CURVE25519_CHACHA,
135 CipherSuite::P256_AES128,
136 CipherSuite::P384_AES256,
137 CipherSuite::P521_AES256,
138 ]
139 }
140
141 #[cfg(feature = "post-quantum")]
142 pub fn supported_pq_cipher_suites() -> Vec<CipherSuite> {
143 vec![
144 CipherSuite::ML_KEM_512,
145 CipherSuite::ML_KEM_768,
146 CipherSuite::ML_KEM_1024,
147 CipherSuite::ML_KEM_768_X25519,
148 ]
149 }
150}
151
152impl AwsLcCryptoProvider {
153 pub fn with_enabled_cipher_suites(enabled_cipher_suites: Vec<CipherSuite>) -> Self {
154 Self {
155 enabled_cipher_suites,
156 }
157 }
158}
159
160#[derive(Clone, Default)]
161pub struct AwsLcCipherSuiteBuilder {
162 signing: Option<AwsLcEcdsa>,
163 aead: Option<AwsLcAead>,
164 kdf: Option<AwsLcHkdf>,
165 hpke: Option<AwsLcHpke>,
166 hmac: Option<AwsLcHmac>,
167 hash: Option<AwsLcHash>,
168 fallback_cipher_suite: Option<CipherSuite>,
169}
170
171impl AwsLcCipherSuiteBuilder {
172 pub fn new() -> Self {
173 Self::default()
174 }
175
176 pub fn signing(self, signing: Curve) -> Self {
177 Self {
178 signing: Some(AwsLcEcdsa(signing)),
179 ..self
180 }
181 }
182
183 pub fn aead(self, aead: AeadId) -> Self {
184 Self {
185 aead: Some(AwsLcAead(aead)),
186 ..self
187 }
188 }
189
190 pub fn kdf(self, kdf: KdfId) -> Self {
191 Self {
192 kdf: Some(AwsLcHkdf(kdf)),
193 ..self
194 }
195 }
196
197 pub fn hmac(self, hmac: AwsLcHmac) -> Self {
198 Self {
199 hmac: Some(hmac),
200 ..self
201 }
202 }
203
204 pub fn hash(self, hash: AwsLcHash) -> Self {
205 Self {
206 hash: Some(hash),
207 ..self
208 }
209 }
210
211 pub fn hpke(self, cipher_suite: CipherSuite) -> Self {
212 Self {
213 hpke: classical_hpke(cipher_suite),
214 ..self
215 }
216 }
217
218 pub fn fallback_cipher_suite(self, cipher_suite: CipherSuite) -> Self {
219 Self {
220 fallback_cipher_suite: Some(cipher_suite),
221 ..self
222 }
223 }
224
225 #[cfg(feature = "post-quantum")]
226 pub fn pq_hpke(self, ml_kem: MlKem, kdf: KdfId, aead: AeadId) -> Self {
227 let ml_kem = MlKemKem {
228 ml_kem,
229 kdf: AwsLcHkdf(kdf),
230 };
231
232 Self {
233 hpke: Some(AwsLcHpke::PostQuantum(Hpke::new(
234 ml_kem,
235 AwsLcHkdf(kdf),
236 Some(AwsLcAead(aead)),
237 ))),
238 ..self
239 }
240 }
241
242 #[cfg(feature = "post-quantum")]
243 pub fn combined_hpke(
244 self,
245 classical_cipher_suite: CipherSuite,
246 ml_kem: MlKem,
247 kdf: KdfId,
248 aead: AeadId,
249 hash: AwsLcHash,
250 ) -> Self {
251 let ml_kem = MlKemKem {
252 ml_kem,
253 kdf: AwsLcHkdf(kdf),
254 };
255
256 let ecdh = dhkem(classical_cipher_suite);
257
258 let hpke = ecdh.map(|ecdh| {
259 let kem = CombinedKem::new_xwing(ml_kem, ecdh, hash, AwsLcShake128);
260
261 AwsLcHpke::Combined(Hpke::new(kem, AwsLcHkdf(kdf), Some(AwsLcAead(aead))))
262 });
263
264 Self { hpke, ..self }
265 }
266
267 #[cfg(feature = "post-quantum")]
268 pub fn ghp_combined_hpke(
269 self,
270 classical_cipher_suite: CipherSuite,
271 ml_kem: MlKem,
272 kdf: KdfId,
273 aead: AeadId,
274 hash: AwsLcHash,
275 ) -> Self {
276 let ml_kem = MlKemKem {
277 ml_kem,
278 kdf: AwsLcHkdf(kdf),
279 };
280
281 let ecdh = dhkem(classical_cipher_suite);
282
283 let hpke = ecdh.map(|ecdh| {
284 let kem = CombinedKem::new_xwing(ml_kem, ecdh, hash, AwsLcShake128);
285
286 AwsLcHpke::Combined(Hpke::new(kem, AwsLcHkdf(kdf), Some(AwsLcAead(aead))))
287 });
288
289 Self { hpke, ..self }
290 }
291
292 pub fn build(self, cipher_suite: CipherSuite) -> Option<AwsLcCipherSuite> {
293 let fallback_cs = self.fallback_cipher_suite.unwrap_or(cipher_suite);
294 let hpke = self.hpke.or_else(|| classical_hpke(fallback_cs))?;
295 let kdf = self.kdf.or_else(|| AwsLcHkdf::new(fallback_cs))?;
296 let aead = self.aead.or_else(|| AwsLcAead::new(fallback_cs))?;
297 let signing = self.signing.or_else(|| AwsLcEcdsa::new(fallback_cs))?;
298 let hmac = self.hmac.or_else(|| AwsLcHmac::new(fallback_cs))?;
299 let hash = self.hash.or_else(|| AwsLcHash::new(fallback_cs))?;
300
301 Some(AwsLcCipherSuite {
302 cipher_suite,
303 hpke,
304 aead,
305 kdf,
306 signing,
307 hmac,
308 hash,
309 })
310 }
311}
312
313fn classical_hpke(cipher_suite: CipherSuite) -> Option<AwsLcHpke> {
314 Some(AwsLcHpke::Classical(Hpke::new(
315 dhkem(cipher_suite)?,
316 AwsLcHkdf::new(cipher_suite)?,
317 Some(AwsLcAead::new(cipher_suite)?),
318 )))
319}
320
321impl CryptoProvider for AwsLcCryptoProvider {
322 type CipherSuiteProvider = AwsLcCipherSuite;
323
324 fn supported_cipher_suites(&self) -> Vec<CipherSuite> {
325 self.enabled_cipher_suites.clone()
326 }
327
328 fn cipher_suite_provider(
329 &self,
330 cipher_suite: CipherSuite,
331 ) -> Option<Self::CipherSuiteProvider> {
332 let classical_cs = match cipher_suite {
333 #[cfg(feature = "post-quantum")]
334 CipherSuite::ML_KEM_1024 => CipherSuite::P384_AES256,
335 #[cfg(feature = "post-quantum")]
336 CipherSuite::ML_KEM_512 | CipherSuite::ML_KEM_768 | CipherSuite::ML_KEM_768_X25519 => {
337 CipherSuite::CURVE25519_AES128
338 }
339 _ => cipher_suite,
340 };
341
342 let kdf = AwsLcHkdf::new(classical_cs)?;
343 let aead = AwsLcAead::new(classical_cs)?;
344 let hmac = AwsLcHmac::new(classical_cs)?;
345
346 let hpke = match cipher_suite {
347 #[cfg(feature = "post-quantum")]
348 CipherSuite::ML_KEM_512 | CipherSuite::ML_KEM_768 | CipherSuite::ML_KEM_1024 => {
349 AwsLcHpke::PostQuantum(Hpke::new(MlKemKem::new(cipher_suite)?, kdf, Some(aead)))
350 }
351 #[cfg(feature = "post-quantum")]
352 CipherSuite::ML_KEM_768_X25519 => {
353 let kem = CombinedKem::new_xwing(
354 MlKemKem::new(CipherSuite::ML_KEM_768)?,
355 dhkem(classical_cs)?,
356 AwsLcHash::new_sha3(Sha3::SHA3_256)?,
357 AwsLcShake128,
358 );
359
360 AwsLcHpke::Combined(Hpke::new(kem, kdf, Some(aead)))
361 }
362 _ => AwsLcHpke::Classical(Hpke::new(dhkem(cipher_suite)?, kdf, Some(aead))),
363 };
364
365 Some(AwsLcCipherSuite {
366 cipher_suite,
367 hpke,
368 aead,
369 kdf,
370 signing: AwsLcEcdsa::new(classical_cs)?,
371 hmac,
372 hash: AwsLcHash::new(classical_cs)?,
373 })
374 }
375}
376
377pub fn dhkem(cipher_suite: CipherSuite) -> Option<DhKem<Ecdh, AwsLcHkdf>> {
378 let kem_id = KemId::new(cipher_suite)?;
379 let dh = Ecdh::new(cipher_suite)?;
380 let kdf = AwsLcHkdf::new(cipher_suite)?;
381
382 Some(DhKem::new(dh, kdf, kem_id as u16, kem_id.n_secret()))
383}
384
385#[derive(Debug, Error)]
386pub enum AwsLcCryptoError {
387 #[error("Invalid key data")]
388 InvalidKeyData,
389 #[error("Underlying crypto error")]
390 CryptoError,
391 #[error("Invalid signature")]
392 InvalidSignature,
393 #[error(transparent)]
394 HpkeError(#[from] HpkeError),
395 #[error("Unsupported ciphersuite")]
396 UnsupportedCipherSuite,
397 #[error("Cert validation error: {0}")]
398 CertValidationFailure(String),
399 #[error(transparent)]
400 TryFromIntError(#[from] TryFromIntError),
401 #[error(transparent)]
402 KeyRejected(#[from] KeyRejected),
403 #[error(transparent)]
404 CombinedKemError(AnyError),
405 #[error(transparent)]
406 MlsCodecError(#[from] mls_rs_core::mls_rs_codec::Error),
407}
408
409impl From<Unspecified> for AwsLcCryptoError {
410 fn from(_value: Unspecified) -> Self {
411 AwsLcCryptoError::CryptoError
412 }
413}
414
415impl IntoAnyError for AwsLcCryptoError {}
416
417#[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
418#[cfg_attr(all(target_arch = "wasm32", mls_build_async), maybe_async::must_be_async(?Send))]
419#[cfg_attr(
420 all(not(target_arch = "wasm32"), mls_build_async),
421 maybe_async::must_be_async
422)]
423impl CipherSuiteProvider for AwsLcCipherSuite {
424 type Error = AwsLcCryptoError;
425
426 type HpkeContextS = ContextS<AwsLcHkdf, AwsLcAead>;
427 type HpkeContextR = ContextR<AwsLcHkdf, AwsLcAead>;
428
429 fn cipher_suite(&self) -> mls_rs_core::crypto::CipherSuite {
430 self.cipher_suite
431 }
432
433 async fn hash(&self, data: &[u8]) -> Result<Vec<u8>, Self::Error> {
434 self.hash.hash(data)
435 }
436
437 async fn mac(&self, key: &[u8], data: &[u8]) -> Result<Vec<u8>, Self::Error> {
438 self.hmac.hmac(key, data)
439 }
440
441 async fn aead_seal(
442 &self,
443 key: &[u8],
444 data: &[u8],
445 aad: Option<&[u8]>,
446 nonce: &[u8],
447 ) -> Result<Vec<u8>, Self::Error> {
448 self.aead.seal(key, data, aad, nonce).await
449 }
450
451 async fn aead_open(
452 &self,
453 key: &[u8],
454 ciphertext: &[u8],
455 aad: Option<&[u8]>,
456 nonce: &[u8],
457 ) -> Result<Zeroizing<Vec<u8>>, Self::Error> {
458 self.aead
459 .open(key, ciphertext, aad, nonce)
460 .await
461 .map(Into::into)
462 }
463
464 fn aead_key_size(&self) -> usize {
465 self.aead.key_size()
466 }
467
468 fn aead_nonce_size(&self) -> usize {
469 self.aead.nonce_size()
470 }
471
472 async fn kdf_extract(
473 &self,
474 salt: &[u8],
475 ikm: &[u8],
476 ) -> Result<Zeroizing<Vec<u8>>, Self::Error> {
477 self.kdf.extract(salt, ikm).await.map(Into::into)
478 }
479
480 async fn kdf_expand(
481 &self,
482 prk: &[u8],
483 info: &[u8],
484 len: usize,
485 ) -> Result<Zeroizing<Vec<u8>>, Self::Error> {
486 self.kdf.expand(prk, info, len).await.map(Into::into)
487 }
488
489 fn kdf_extract_size(&self) -> usize {
490 self.kdf.extract_size()
491 }
492
493 async fn hpke_seal(
494 &self,
495 remote_key: &HpkePublicKey,
496 info: &[u8],
497 aad: Option<&[u8]>,
498 pt: &[u8],
499 ) -> Result<HpkeCiphertext, Self::Error> {
500 match &self.hpke {
501 AwsLcHpke::Classical(hpke) => hpke.seal(remote_key, info, None, aad, pt),
502 #[cfg(feature = "post-quantum")]
503 AwsLcHpke::PostQuantum(hpke) => hpke.seal(remote_key, info, None, aad, pt),
504 #[cfg(feature = "post-quantum")]
505 AwsLcHpke::Combined(hpke) => hpke.seal(remote_key, info, None, aad, pt),
506 }
507 .await
508 .map_err(Into::into)
509 }
510
511 async fn hpke_open(
512 &self,
513 ciphertext: &HpkeCiphertext,
514 local_secret: &HpkeSecretKey,
515 local_public: &HpkePublicKey,
516 info: &[u8],
517 aad: Option<&[u8]>,
518 ) -> Result<Vec<u8>, Self::Error> {
519 match &self.hpke {
520 AwsLcHpke::Classical(hpke) => {
521 hpke.open(ciphertext, local_secret, local_public, info, None, aad)
522 }
523 #[cfg(feature = "post-quantum")]
524 AwsLcHpke::PostQuantum(hpke) => {
525 hpke.open(ciphertext, local_secret, local_public, info, None, aad)
526 }
527 #[cfg(feature = "post-quantum")]
528 AwsLcHpke::Combined(hpke) => {
529 hpke.open(ciphertext, local_secret, local_public, info, None, aad)
530 }
531 }
532 .await
533 .map_err(Into::into)
534 }
535
536 async fn hpke_setup_s(
537 &self,
538 remote_key: &HpkePublicKey,
539 info: &[u8],
540 ) -> Result<(Vec<u8>, Self::HpkeContextS), Self::Error> {
541 match &self.hpke {
542 AwsLcHpke::Classical(hpke) => hpke.setup_sender(remote_key, info, None),
543 #[cfg(feature = "post-quantum")]
544 AwsLcHpke::PostQuantum(hpke) => hpke.setup_sender(remote_key, info, None),
545 #[cfg(feature = "post-quantum")]
546 AwsLcHpke::Combined(hpke) => hpke.setup_sender(remote_key, info, None),
547 }
548 .await
549 .map_err(Into::into)
550 }
551
552 async fn hpke_setup_r(
553 &self,
554 kem_output: &[u8],
555 local_secret: &HpkeSecretKey,
556 local_public: &HpkePublicKey,
557 info: &[u8],
558 ) -> Result<Self::HpkeContextR, Self::Error> {
559 match &self.hpke {
560 AwsLcHpke::Classical(hpke) => {
561 hpke.setup_receiver(kem_output, local_secret, local_public, info, None)
562 }
563 #[cfg(feature = "post-quantum")]
564 AwsLcHpke::PostQuantum(hpke) => {
565 hpke.setup_receiver(kem_output, local_secret, local_public, info, None)
566 }
567 #[cfg(feature = "post-quantum")]
568 AwsLcHpke::Combined(hpke) => {
569 hpke.setup_receiver(kem_output, local_secret, local_public, info, None)
570 }
571 }
572 .await
573 .map_err(Into::into)
574 }
575
576 async fn kem_derive(&self, ikm: &[u8]) -> Result<(HpkeSecretKey, HpkePublicKey), Self::Error> {
577 match &self.hpke {
578 AwsLcHpke::Classical(hpke) => hpke.derive(ikm),
579 #[cfg(feature = "post-quantum")]
580 AwsLcHpke::PostQuantum(hpke) => hpke.derive(ikm),
581 #[cfg(feature = "post-quantum")]
582 AwsLcHpke::Combined(hpke) => hpke.derive(ikm),
583 }
584 .await
585 .map_err(Into::into)
586 }
587
588 async fn kem_generate(&self) -> Result<(HpkeSecretKey, HpkePublicKey), Self::Error> {
589 match &self.hpke {
590 AwsLcHpke::Classical(hpke) => hpke.generate(),
591 #[cfg(feature = "post-quantum")]
592 AwsLcHpke::PostQuantum(hpke) => hpke.generate(),
593 #[cfg(feature = "post-quantum")]
594 AwsLcHpke::Combined(hpke) => hpke.generate(),
595 }
596 .await
597 .map_err(Into::into)
598 }
599
600 fn kem_public_key_validate(&self, key: &HpkePublicKey) -> Result<(), Self::Error> {
601 match &self.hpke {
602 AwsLcHpke::Classical(hpke) => hpke.public_key_validate(key),
603 #[cfg(feature = "post-quantum")]
604 AwsLcHpke::PostQuantum(hpke) => hpke.public_key_validate(key),
605 #[cfg(feature = "post-quantum")]
606 AwsLcHpke::Combined(hpke) => hpke.public_key_validate(key),
607 }
608 .map_err(Into::into)
609 }
610
611 fn random_bytes(&self, out: &mut [u8]) -> Result<(), Self::Error> {
612 Ok(aws_lc_rs::rand::fill(out)?)
613 }
614
615 async fn signature_key_generate(
616 &self,
617 ) -> Result<(SignatureSecretKey, SignaturePublicKey), Self::Error> {
618 self.signing.signature_key_generate()
619 }
620
621 async fn signature_key_derive_public(
622 &self,
623 secret_key: &SignatureSecretKey,
624 ) -> Result<SignaturePublicKey, Self::Error> {
625 self.signing.signature_key_derive_public(secret_key)
626 }
627
628 async fn sign(
629 &self,
630 secret_key: &SignatureSecretKey,
631 data: &[u8],
632 ) -> Result<Vec<u8>, Self::Error> {
633 self.signing.sign(secret_key, data)
634 }
635
636 async fn verify(
637 &self,
638 public_key: &SignaturePublicKey,
639 signature: &[u8],
640 data: &[u8],
641 ) -> Result<(), Self::Error> {
642 self.signing.verify(public_key, signature, data)
643 }
644}
645
646pub fn sha256(data: &[u8]) -> [u8; 32] {
647 unsafe {
648 let mut out = MaybeUninit::<[u8; 32]>::uninit();
649 SHA256(data.as_ptr(), data.len(), out.as_mut_ptr() as *mut u8);
650 out.assume_init()
651 }
652}
653
654fn check_res(r: c_int) -> Result<(), AwsLcCryptoError> {
655 check_int_return(r).map(|_| ())
656}
657
658fn check_int_return(r: c_int) -> Result<c_int, AwsLcCryptoError> {
659 if r <= 0 {
660 Err(AwsLcCryptoError::CryptoError)
661 } else {
662 Ok(r)
663 }
664}
665
666fn check_non_null<T>(r: *mut T) -> Result<*mut T, AwsLcCryptoError> {
667 if r.is_null() {
668 return Err(AwsLcCryptoError::CryptoError);
669 }
670
671 Ok(r)
672}
673
674fn check_non_null_const<T>(r: *const T) -> Result<*const T, AwsLcCryptoError> {
675 if r.is_null() {
676 return Err(AwsLcCryptoError::CryptoError);
677 }
678
679 Ok(r)
680}
681
682#[cfg(not(mls_build_async))]
683#[test]
684fn mls_core_tests() {
685 mls_rs_core::crypto::test_suite::verify_tests(&AwsLcCryptoProvider::new(), true);
686
687 for cs in AwsLcCryptoProvider::supported_classical_cipher_suites() {
688 let mut hpke = Hpke::new(
689 dhkem(cs).unwrap(),
690 AwsLcHkdf::new(cs).unwrap(),
691 AwsLcAead::new(cs),
692 );
693
694 mls_rs_core::crypto::test_suite::verify_hpke_context_tests(&hpke, cs);
695 mls_rs_core::crypto::test_suite::verify_hpke_encap_tests(&mut hpke, cs);
696 }
697}
698
699#[cfg(all(not(mls_build_async), feature = "post-quantum", not(feature = "fips")))]
700#[test]
701fn pq_cipher_suite_test() {
702 for cs in AwsLcCryptoProvider::supported_pq_cipher_suites() {
703 let cs = AwsLcCryptoProvider::new()
704 .cipher_suite_provider(cs)
705 .unwrap();
706
707 let (sk, pk) = cs.kem_derive(&[0u8; 64]).unwrap();
708 let ct = cs.hpke_seal(&pk, b"info", None, b"very secret").unwrap();
709 let pt = cs.hpke_open(&ct, &sk, &pk, b"info", None).unwrap();
710 assert_eq!(pt, b"very secret");
711 }
712}