rustls_openssl_post_quantum/
lib.rs

1//! Experimental post-quantum key exchange algorithms for rustls using OpenSSL and liboqs.
2#![deny(missing_docs)]
3mod ffi;
4mod kem;
5#[cfg(swapx25519hybrid)]
6mod swap;
7
8pub use kem::MLKEM768;
9#[cfg(not(swapx25519hybrid))]
10pub use kem::X25519MLKEM768;
11#[cfg(swapx25519hybrid)]
12pub use swap::X25519MLKEM768;
13
14#[cfg(test)]
15mod tests {
16    use once_cell::sync::OnceCell;
17    use openssl::provider::Provider;
18    use rustls::crypto::SupportedKxGroup;
19
20    use crate::{MLKEM768, X25519MLKEM768};
21
22    fn load_providers() {
23        static INSTANCE: OnceCell<Vec<Provider>> = OnceCell::new();
24        INSTANCE.get_or_init(|| {
25            let default_provider = openssl::provider::Provider::load(None, "default").unwrap();
26            let oqs_provider = openssl::provider::Provider::load(None, "oqsprovider").unwrap();
27            let _ = openssl::error::ErrorStack::get();
28            vec![default_provider, oqs_provider]
29        });
30    }
31
32    pub(crate) fn roundtrip(ours: &dyn SupportedKxGroup, theirs: &dyn SupportedKxGroup) {
33        load_providers();
34
35        let our_kx = ours.start().unwrap();
36        let their_kx = theirs.start().unwrap();
37
38        let our_completed = ours.start_and_complete(their_kx.pub_key()).unwrap();
39        let their_secret = their_kx.complete(&our_completed.pub_key).unwrap();
40
41        assert_eq!(
42            our_completed.secret.secret_bytes(),
43            their_secret.secret_bytes()
44        );
45
46        let their_completed = theirs.start_and_complete(our_kx.pub_key()).unwrap();
47        let our_secret = our_kx.complete(&their_completed.pub_key).unwrap();
48
49        assert_eq!(
50            our_secret.secret_bytes(),
51            their_completed.secret.secret_bytes()
52        );
53    }
54
55    pub(crate) fn roundtrip_classical(ours: &dyn SupportedKxGroup, theirs: &dyn SupportedKxGroup) {
56        load_providers();
57
58        let our_kx = ours.start().unwrap();
59        let their_kx = theirs.start().unwrap();
60
61        let (_group, our_key) = our_kx.hybrid_component().unwrap();
62        let our_key = our_key.to_vec();
63
64        let peer_pub_key = their_kx.pub_key();
65        let our_secret = our_kx.complete_hybrid_component(peer_pub_key).unwrap();
66        let their_secret = their_kx.complete(&our_key).unwrap();
67
68        assert_eq!(our_secret.secret_bytes(), their_secret.secret_bytes());
69    }
70
71    #[test]
72    fn mlkem768() {
73        roundtrip(MLKEM768, rustls_post_quantum::MLKEM768);
74    }
75
76    #[test]
77    fn x25519_mlkem768() {
78        roundtrip(X25519MLKEM768, rustls_post_quantum::X25519MLKEM768);
79    }
80
81    #[test]
82    fn x25519_mlkem768_classical() {
83        roundtrip_classical(X25519MLKEM768, rustls_openssl::kx_group::X25519);
84    }
85}