Skip to main content

ClientConnection

Struct ClientConnection 

Source
pub struct ClientConnection(/* private fields */);
Expand description

A TLS 1.3 client connection. The ClientHello is queued at construction.

Implementations§

Source§

impl ClientConnection

Source

pub fn new( cfg: Arc<ClientConfig>, server_name: &str, ) -> Result<ClientConnection>

server_name is verified against the certificate and sent as SNI (unless it is an IP address).

Examples found in repository?
examples/../tests/fuzzing/mod.rs (line 131)
122pub fn corpus() -> Corpus {
123    let ss = certgen::issue(&CertParams::server(&["localhost"]), PrivateKey::generate_ec(EcCurve::P256), None);
124    let mut roots = RootStore::empty();
125    roots.add_der(&ss.cert_der).unwrap();
126    let scfg = Arc::new(ServerConfig::new(CertifiedKey::new(vec![ss.cert_der.clone()], ss.key.clone()).unwrap()).with_alpn(&[b"h3", b"http/1.1"]));
127    let mut cc = ClientConfig::new(roots).with_alpn(&[b"h3", b"http/1.1"]);
128    cc.sessions = None;
129    let ccfg = Arc::new(cc);
130    // a TLS handshake transcript
131    let mut c = ClientConnection::new(ccfg.clone(), "localhost").unwrap();
132    let mut s = ServerConnection::new(scfg.clone());
133    let ch = c.tls_output().to_vec();
134    c.consume_tls_output(ch.len());
135    s.read_tls(&ch);
136    s.process_new_packets().unwrap();
137    let flight = s.tls_output().to_vec();
138    let mut ch_plus = ch.clone();
139    ch_plus.extend_from_slice(&[20, 3, 3, 0, 1, 1, 23, 3, 3, 0, 20]);
140    ch_plus.extend(std::iter::repeat_n(0xaa, 20));
141    // a QUIC handshake: the ClientHello message and the server's Handshake-level flight
142    let mut qc = QuicConnection::new_client(ccfg.clone(), "localhost", vec![1, 2, 3]).unwrap();
143    let mut qs = QuicConnection::new_server(scfg.clone(), vec![4, 5, 6]);
144    let mut ch_msg = Vec::new();
145    qc.write_handshake(&mut ch_msg);
146    qs.read_handshake(Level::Initial, &ch_msg).unwrap();
147    let mut sh = Vec::new();
148    qs.write_handshake(&mut sh);
149    let mut hs = Vec::new();
150    qs.write_handshake(&mut hs);
151    Corpus {
152        scfg,
153        ccfg,
154        to_server: vec![ch, ch_plus],
155        to_client: vec![flight],
156        ch_msg,
157        server_hs_flight: hs,
158        key_der: ss.key_der.clone(),
159        cert_der: ss.cert_der,
160    }
161}
162
163/// Feeds `data` in random-sized pieces and processes after each; checks that errors stick.
164fn feed(rng: &mut Rng, conn: &mut simoom_tls::Connection, data: &[u8]) {
165    let mut off = 0;
166    while off < data.len() {
167        let k = 1 + rng.below(data.len() - off);
168        let taken = conn.read_tls(&data[off..off + k]);
169        off += taken;
170        let r = conn.process_new_packets();
171        if let Err(e) = r {
172            assert_eq!(conn.process_new_packets().unwrap_err(), e, "errors must stick");
173            assert!(conn.tls_output().len() < 64 * 1024, "output stays bounded");
174            assert!(conn.write_plaintext(b"x").is_err(), "a failed connection refuses writes");
175            return;
176        }
177        if taken == 0 {
178            // buffer full: the application reads plaintext
179            let n = conn.plaintext().len();
180            if n == 0 {
181                return;
182            }
183            conn.consume_plaintext(n);
184        }
185    }
186}
187
188pub fn server_records(rng: &mut Rng, c: &Corpus, iters: usize) {
189    for _ in 0..iters {
190        let seed = &c.to_server[rng.below(c.to_server.len())];
191        let data = mutate(rng, seed, &c.to_client);
192        let mut s = ServerConnection::new(c.scfg.clone());
193        feed(rng, &mut s, &data);
194    }
195}
196
197pub fn client_records(rng: &mut Rng, c: &Corpus, iters: usize) {
198    for _ in 0..iters {
199        let data = mutate(rng, &c.to_client[0], &c.to_server);
200        let mut cl = ClientConnection::new(c.ccfg.clone(), "localhost").unwrap();
201        let n = cl.tls_output().len();
202        cl.consume_tls_output(n);
203        feed(rng, &mut cl, &data);
204    }
205}
More examples
Hide additional examples
examples/bench_tls.rs (line 174)
63fn main() {
64    let openssl = std::env::args().any(|a| a == "--openssl");
65    let d = Duration::from_millis(if std::env::args().any(|a| a == "--quick") { 300 } else { 1500 });
66    println!("simoom-tls benchmarks (single thread), hardware AES: {}, CLMUL: {}, SHA-NI: {}", simoom_sys::arch::has_aes(), simoom_sys::arch::has_clmul(), simoom_sys::arch::has_sha256());
67    println!();
68    println!("{:<34} {:>12} {:>12}", "AEAD seal (encrypt + tag)", "16384 B", "1400 B");
69    let aad = [0u8; 13];
70    let mut buf = vec![0x5au8; 16384];
71    let gcm128 = AesGcm::new(&[1u8; 16]);
72    let gcm256 = AesGcm::new(&[1u8; 32]);
73    let gcm128s = AesGcm::new_soft(&[1u8; 16]);
74    let chacha = ChaCha20Poly1305::new(&[2u8; 32]);
75    let mut seq = 0u64;
76    let mut nonce = || {
77        seq += 1;
78        let mut n = [0u8; 12];
79        n[4..].copy_from_slice(&seq.to_be_bytes());
80        n
81    };
82    let f1 = |n: &[u8; 12], b: &mut [u8]| gcm128.seal(n, &aad, b);
83    let f2 = |n: &[u8; 12], b: &mut [u8]| gcm256.seal(n, &aad, b);
84    let f3 = |n: &[u8; 12], b: &mut [u8]| gcm128s.seal(n, &aad, b);
85    let f4 = |n: &[u8; 12], b: &mut [u8]| chacha.seal(n, &aad, b);
86    let algs: [(&str, &dyn Fn(&[u8; 12], &mut [u8]) -> [u8; 16]); 4] =
87        [("AES-128-GCM", &f1), ("AES-256-GCM", &f2), ("AES-128-GCM (portable, bitsliced)", &f3), ("ChaCha20-Poly1305", &f4)];
88    for (name, f) in algs {
89        let size_d = if name.contains("portable") { d / 3 } else { d };
90        let a = rate(size_d, || {
91            black_box(f(&nonce(), &mut buf));
92        });
93        let b = rate(size_d, || {
94            black_box(f(&nonce(), &mut buf[..1400]));
95        });
96        println!("{:<34} {:>9.2} GB/s {:>7.2} GB/s", name, gbps(a, 16384), gbps(b, 1400));
97    }
98    let mut tag = [0u8; 16];
99    let n12 = [0u8; 12];
100    tag.copy_from_slice(&gcm128.seal(&n12, &aad, &mut buf));
101    let o = rate(d, || {
102        // open fails (buffer changed) but does the full work: GHASH, CTR, tag compare
103        black_box(gcm128.open(&n12, &aad, &mut buf, &tag));
104    });
105    println!("{:<34} {:>9.2} GB/s", "AES-128-GCM open", gbps(o, 16384));
106
107    println!();
108    println!("{:<34} {:>12}", "Primitive", "ops/s");
109    let sk = [7u8; 32];
110    let pk = x25519::x25519_base(&[9u8; 32]);
111    println!("{:<34} {:>12.0}", "X25519 key generation (table)", rate(d, || {
112        black_box(x25519::x25519_base(black_box(&sk)));
113    }));
114    println!("{:<34} {:>12.0}", "X25519 shared secret (ladder)", rate(d, || {
115        black_box(x25519::x25519(black_box(&sk), &pk));
116    }));
117    let d256 = p256::generate_private();
118    let q256 = p256::public_key(&p256::generate_private()).unwrap();
119    let h = [3u8; 32];
120    println!("{:<34} {:>12.0}", "P-256 key generation", rate(d, || {
121        black_box(p256::public_key(black_box(&d256)));
122    }));
123    println!("{:<34} {:>12.0}", "P-256 ECDH", rate(d, || {
124        black_box(p256::ecdh(black_box(&d256), &q256));
125    }));
126    let (r, s) = p256::sign(&d256, &h, simoom_tls::crypto::sha2::HashAlg::Sha256).unwrap();
127    let pub256 = p256::public_key(&d256).unwrap();
128    println!("{:<34} {:>12.0}", "ECDSA P-256 sign", rate(d, || {
129        black_box(p256::sign(black_box(&d256), &h, simoom_tls::crypto::sha2::HashAlg::Sha256));
130    }));
131    println!("{:<34} {:>12.0}", "ECDSA P-256 verify", rate(d, || {
132        black_box(p256::verify(&pub256, &h, &r, &s));
133    }));
134    let seed = [5u8; 32];
135    let edpub = simoom_tls::crypto::ed25519::public_key(&seed);
136    // as the server signs: the key's public half is known (OpenSSL keeps it in the key too)
137    println!("{:<34} {:>12.0}", "Ed25519 sign", rate(d, || {
138        black_box(simoom_tls::crypto::ed25519::sign_with_public(&seed, &edpub, b"message"));
139    }));
140    let edsig = simoom_tls::crypto::ed25519::sign(&seed, b"message");
141    println!("{:<34} {:>12.0}", "Ed25519 verify", rate(d, || {
142        black_box(simoom_tls::crypto::ed25519::verify(&edpub, b"message", &edsig));
143    }));
144    let rsa = PrivateKey::from_pem(include_bytes!("../testdata/rsa2048.pkcs1.pem")).unwrap();
145    if let PrivateKey::Rsa(k) = &rsa {
146        let dg = [1u8; 32];
147        println!("{:<34} {:>12.0}", "RSA-2048 PSS sign", rate(d, || {
148            black_box(k.sign_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg));
149        }));
150        let sig = k.sign_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg).unwrap();
151        println!("{:<34} {:>12.0}", "RSA-2048 PSS verify", rate(d, || {
152            black_box(k.public.verify_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg, &sig, Some(32)));
153        }));
154    }
155
156    // handshakes
157    let ss = certgen::issue(&CertParams::server(&["localhost"]), PrivateKey::generate_ec(EcCurve::P256), None);
158    let mut roots = RootStore::empty();
159    roots.add_der(&ss.cert_der).unwrap();
160    let mut scfg = ServerConfig::new(CertifiedKey::new(vec![ss.cert_der.clone()], ss.key.clone()).unwrap());
161    scfg.groups = vec![NamedGroup::X25519];
162    let scfg = Arc::new(scfg);
163    let mut cfull = ClientConfig::new(roots.clone());
164    cfull.sessions = None;
165    cfull.groups = vec![NamedGroup::X25519];
166    let cfull = Arc::new(cfull);
167    let mut cres = ClientConfig::new(roots);
168    cres.groups = vec![NamedGroup::X25519];
169    let cres = Arc::new(cres);
170
171    println!();
172    println!("{:<44} {:>12}", "TLS 1.3 handshake (X25519, ECDSA P-256 cert)", "per second");
173    let full = rate(d, || {
174        let mut c = ClientConnection::new(cfull.clone(), "localhost").unwrap();
175        let mut s = ServerConnection::new(scfg.clone());
176        pump(&mut c, &mut s);
177        assert!(!s.is_handshaking());
178    });
179    println!("{:<44} {:>12.0}", "full, client + server", full);
180    // server side only: replay a fresh ClientHello per iteration and time the server's work
181    let mut server_time = Duration::ZERO;
182    let mut n = 0u32;
183    let t0 = Instant::now();
184    while t0.elapsed() < d {
185        let mut c = ClientConnection::new(cfull.clone(), "localhost").unwrap();
186        let mut s = ServerConnection::new(scfg.clone());
187        let ch = c.tls_output().to_vec();
188        c.consume_tls_output(ch.len());
189        let t = Instant::now();
190        s.read_tls(&ch);
191        s.process_new_packets().unwrap();
192        server_time += t.elapsed();
193        let flight = s.tls_output().to_vec();
194        s.consume_tls_output(flight.len());
195        c.read_tls(&flight);
196        c.process_new_packets().unwrap();
197        let fin = c.tls_output().to_vec();
198        let t = Instant::now();
199        s.read_tls(&fin);
200        s.process_new_packets().unwrap();
201        server_time += t.elapsed();
202        n += 1;
203    }
204    println!("{:<44} {:>12.0}", "full, server side only", n as f64 / server_time.as_secs_f64());
205    // resumption: prime the cache, then each connection uses one ticket and stores a new one
206    let mut c = ClientConnection::new(cres.clone(), "localhost").unwrap();
207    let mut s = ServerConnection::new(scfg.clone());
208    pump(&mut c, &mut s);
209    let resumed = rate(d, || {
210        let mut c = ClientConnection::new(cres.clone(), "localhost").unwrap();
211        let mut s = ServerConnection::new(scfg.clone());
212        pump(&mut c, &mut s);
213        assert!(c.is_resumed());
214    });
215    println!("{:<44} {:>12.0}", "PSK-DHE resumption, client + server", resumed);
216
217    if openssl {
218        println!();
219        println!("openssl speed (same machine, single thread):");
220        for args in [
221            &["speed", "-seconds", "2", "-bytes", "16384", "-evp", "aes-128-gcm"][..],
222            &["speed", "-seconds", "2", "-bytes", "1400", "-evp", "aes-128-gcm"][..],
223            &["speed", "-seconds", "2", "-bytes", "16384", "-evp", "chacha20-poly1305"][..],
224            &["speed", "-seconds", "2", "-bytes", "1400", "-evp", "chacha20-poly1305"][..],
225            &["speed", "-seconds", "2", "ecdhx25519", "ecdhp256", "ecdsap256", "ed25519", "rsa2048"][..],
226        ] {
227            match std::process::Command::new("openssl").args(args).output() {
228                Ok(o) => {
229                    let out = String::from_utf8_lossy(&o.stdout);
230                    for line in out.lines().filter(|l| {
231                        l.starts_with("AES-128-GCM") || l.starts_with("ChaCha20-Poly1305") || l.contains(" sign ") || l.contains("op/s") || l.starts_with("rsa") || l.contains("ecdh") || l.contains("ecdsa") || l.contains("Ed25519") || l.contains("type")
232                    }) {
233                        println!("  {line}");
234                    }
235                }
236                Err(e) => println!("  openssl not available: {e}"),
237            }
238        }
239    }
240}
Source

pub fn into_inner(self) -> Connection

The underlying connection (for example to call Connection::export_traffic_secrets).

Methods from Deref<Target = Connection>§

Source

pub fn read_tls(&mut self, data: &[u8]) -> usize

Buffers received TLS bytes and returns how many were taken (fewer than offered, possibly zero, while earlier input waits to be processed or read).

Examples found in repository?
examples/bench_tls.rs (line 46)
42fn pump(c: &mut Connection, s: &mut Connection) {
43    loop {
44        let mut moved = false;
45        if c.wants_write() {
46            let n = s.read_tls(c.tls_output());
47            c.consume_tls_output(n);
48            s.process_new_packets().unwrap();
49            moved = true;
50        }
51        if s.wants_write() {
52            let n = c.read_tls(s.tls_output());
53            s.consume_tls_output(n);
54            c.process_new_packets().unwrap();
55            moved = true;
56        }
57        if !moved {
58            return;
59        }
60    }
61}
62
63fn main() {
64    let openssl = std::env::args().any(|a| a == "--openssl");
65    let d = Duration::from_millis(if std::env::args().any(|a| a == "--quick") { 300 } else { 1500 });
66    println!("simoom-tls benchmarks (single thread), hardware AES: {}, CLMUL: {}, SHA-NI: {}", simoom_sys::arch::has_aes(), simoom_sys::arch::has_clmul(), simoom_sys::arch::has_sha256());
67    println!();
68    println!("{:<34} {:>12} {:>12}", "AEAD seal (encrypt + tag)", "16384 B", "1400 B");
69    let aad = [0u8; 13];
70    let mut buf = vec![0x5au8; 16384];
71    let gcm128 = AesGcm::new(&[1u8; 16]);
72    let gcm256 = AesGcm::new(&[1u8; 32]);
73    let gcm128s = AesGcm::new_soft(&[1u8; 16]);
74    let chacha = ChaCha20Poly1305::new(&[2u8; 32]);
75    let mut seq = 0u64;
76    let mut nonce = || {
77        seq += 1;
78        let mut n = [0u8; 12];
79        n[4..].copy_from_slice(&seq.to_be_bytes());
80        n
81    };
82    let f1 = |n: &[u8; 12], b: &mut [u8]| gcm128.seal(n, &aad, b);
83    let f2 = |n: &[u8; 12], b: &mut [u8]| gcm256.seal(n, &aad, b);
84    let f3 = |n: &[u8; 12], b: &mut [u8]| gcm128s.seal(n, &aad, b);
85    let f4 = |n: &[u8; 12], b: &mut [u8]| chacha.seal(n, &aad, b);
86    let algs: [(&str, &dyn Fn(&[u8; 12], &mut [u8]) -> [u8; 16]); 4] =
87        [("AES-128-GCM", &f1), ("AES-256-GCM", &f2), ("AES-128-GCM (portable, bitsliced)", &f3), ("ChaCha20-Poly1305", &f4)];
88    for (name, f) in algs {
89        let size_d = if name.contains("portable") { d / 3 } else { d };
90        let a = rate(size_d, || {
91            black_box(f(&nonce(), &mut buf));
92        });
93        let b = rate(size_d, || {
94            black_box(f(&nonce(), &mut buf[..1400]));
95        });
96        println!("{:<34} {:>9.2} GB/s {:>7.2} GB/s", name, gbps(a, 16384), gbps(b, 1400));
97    }
98    let mut tag = [0u8; 16];
99    let n12 = [0u8; 12];
100    tag.copy_from_slice(&gcm128.seal(&n12, &aad, &mut buf));
101    let o = rate(d, || {
102        // open fails (buffer changed) but does the full work: GHASH, CTR, tag compare
103        black_box(gcm128.open(&n12, &aad, &mut buf, &tag));
104    });
105    println!("{:<34} {:>9.2} GB/s", "AES-128-GCM open", gbps(o, 16384));
106
107    println!();
108    println!("{:<34} {:>12}", "Primitive", "ops/s");
109    let sk = [7u8; 32];
110    let pk = x25519::x25519_base(&[9u8; 32]);
111    println!("{:<34} {:>12.0}", "X25519 key generation (table)", rate(d, || {
112        black_box(x25519::x25519_base(black_box(&sk)));
113    }));
114    println!("{:<34} {:>12.0}", "X25519 shared secret (ladder)", rate(d, || {
115        black_box(x25519::x25519(black_box(&sk), &pk));
116    }));
117    let d256 = p256::generate_private();
118    let q256 = p256::public_key(&p256::generate_private()).unwrap();
119    let h = [3u8; 32];
120    println!("{:<34} {:>12.0}", "P-256 key generation", rate(d, || {
121        black_box(p256::public_key(black_box(&d256)));
122    }));
123    println!("{:<34} {:>12.0}", "P-256 ECDH", rate(d, || {
124        black_box(p256::ecdh(black_box(&d256), &q256));
125    }));
126    let (r, s) = p256::sign(&d256, &h, simoom_tls::crypto::sha2::HashAlg::Sha256).unwrap();
127    let pub256 = p256::public_key(&d256).unwrap();
128    println!("{:<34} {:>12.0}", "ECDSA P-256 sign", rate(d, || {
129        black_box(p256::sign(black_box(&d256), &h, simoom_tls::crypto::sha2::HashAlg::Sha256));
130    }));
131    println!("{:<34} {:>12.0}", "ECDSA P-256 verify", rate(d, || {
132        black_box(p256::verify(&pub256, &h, &r, &s));
133    }));
134    let seed = [5u8; 32];
135    let edpub = simoom_tls::crypto::ed25519::public_key(&seed);
136    // as the server signs: the key's public half is known (OpenSSL keeps it in the key too)
137    println!("{:<34} {:>12.0}", "Ed25519 sign", rate(d, || {
138        black_box(simoom_tls::crypto::ed25519::sign_with_public(&seed, &edpub, b"message"));
139    }));
140    let edsig = simoom_tls::crypto::ed25519::sign(&seed, b"message");
141    println!("{:<34} {:>12.0}", "Ed25519 verify", rate(d, || {
142        black_box(simoom_tls::crypto::ed25519::verify(&edpub, b"message", &edsig));
143    }));
144    let rsa = PrivateKey::from_pem(include_bytes!("../testdata/rsa2048.pkcs1.pem")).unwrap();
145    if let PrivateKey::Rsa(k) = &rsa {
146        let dg = [1u8; 32];
147        println!("{:<34} {:>12.0}", "RSA-2048 PSS sign", rate(d, || {
148            black_box(k.sign_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg));
149        }));
150        let sig = k.sign_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg).unwrap();
151        println!("{:<34} {:>12.0}", "RSA-2048 PSS verify", rate(d, || {
152            black_box(k.public.verify_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg, &sig, Some(32)));
153        }));
154    }
155
156    // handshakes
157    let ss = certgen::issue(&CertParams::server(&["localhost"]), PrivateKey::generate_ec(EcCurve::P256), None);
158    let mut roots = RootStore::empty();
159    roots.add_der(&ss.cert_der).unwrap();
160    let mut scfg = ServerConfig::new(CertifiedKey::new(vec![ss.cert_der.clone()], ss.key.clone()).unwrap());
161    scfg.groups = vec![NamedGroup::X25519];
162    let scfg = Arc::new(scfg);
163    let mut cfull = ClientConfig::new(roots.clone());
164    cfull.sessions = None;
165    cfull.groups = vec![NamedGroup::X25519];
166    let cfull = Arc::new(cfull);
167    let mut cres = ClientConfig::new(roots);
168    cres.groups = vec![NamedGroup::X25519];
169    let cres = Arc::new(cres);
170
171    println!();
172    println!("{:<44} {:>12}", "TLS 1.3 handshake (X25519, ECDSA P-256 cert)", "per second");
173    let full = rate(d, || {
174        let mut c = ClientConnection::new(cfull.clone(), "localhost").unwrap();
175        let mut s = ServerConnection::new(scfg.clone());
176        pump(&mut c, &mut s);
177        assert!(!s.is_handshaking());
178    });
179    println!("{:<44} {:>12.0}", "full, client + server", full);
180    // server side only: replay a fresh ClientHello per iteration and time the server's work
181    let mut server_time = Duration::ZERO;
182    let mut n = 0u32;
183    let t0 = Instant::now();
184    while t0.elapsed() < d {
185        let mut c = ClientConnection::new(cfull.clone(), "localhost").unwrap();
186        let mut s = ServerConnection::new(scfg.clone());
187        let ch = c.tls_output().to_vec();
188        c.consume_tls_output(ch.len());
189        let t = Instant::now();
190        s.read_tls(&ch);
191        s.process_new_packets().unwrap();
192        server_time += t.elapsed();
193        let flight = s.tls_output().to_vec();
194        s.consume_tls_output(flight.len());
195        c.read_tls(&flight);
196        c.process_new_packets().unwrap();
197        let fin = c.tls_output().to_vec();
198        let t = Instant::now();
199        s.read_tls(&fin);
200        s.process_new_packets().unwrap();
201        server_time += t.elapsed();
202        n += 1;
203    }
204    println!("{:<44} {:>12.0}", "full, server side only", n as f64 / server_time.as_secs_f64());
205    // resumption: prime the cache, then each connection uses one ticket and stores a new one
206    let mut c = ClientConnection::new(cres.clone(), "localhost").unwrap();
207    let mut s = ServerConnection::new(scfg.clone());
208    pump(&mut c, &mut s);
209    let resumed = rate(d, || {
210        let mut c = ClientConnection::new(cres.clone(), "localhost").unwrap();
211        let mut s = ServerConnection::new(scfg.clone());
212        pump(&mut c, &mut s);
213        assert!(c.is_resumed());
214    });
215    println!("{:<44} {:>12.0}", "PSK-DHE resumption, client + server", resumed);
216
217    if openssl {
218        println!();
219        println!("openssl speed (same machine, single thread):");
220        for args in [
221            &["speed", "-seconds", "2", "-bytes", "16384", "-evp", "aes-128-gcm"][..],
222            &["speed", "-seconds", "2", "-bytes", "1400", "-evp", "aes-128-gcm"][..],
223            &["speed", "-seconds", "2", "-bytes", "16384", "-evp", "chacha20-poly1305"][..],
224            &["speed", "-seconds", "2", "-bytes", "1400", "-evp", "chacha20-poly1305"][..],
225            &["speed", "-seconds", "2", "ecdhx25519", "ecdhp256", "ecdsap256", "ed25519", "rsa2048"][..],
226        ] {
227            match std::process::Command::new("openssl").args(args).output() {
228                Ok(o) => {
229                    let out = String::from_utf8_lossy(&o.stdout);
230                    for line in out.lines().filter(|l| {
231                        l.starts_with("AES-128-GCM") || l.starts_with("ChaCha20-Poly1305") || l.contains(" sign ") || l.contains("op/s") || l.starts_with("rsa") || l.contains("ecdh") || l.contains("ecdsa") || l.contains("Ed25519") || l.contains("type")
232                    }) {
233                        println!("  {line}");
234                    }
235                }
236                Err(e) => println!("  openssl not available: {e}"),
237            }
238        }
239    }
240}
More examples
Hide additional examples
examples/size_server.rs (line 24)
12fn main() {
13    let args: Vec<String> = std::env::args().collect();
14    if args.len() < 3 {
15        eprintln!("usage: size_server CERT.pem KEY.pem < client_flight");
16        std::process::exit(2);
17    }
18    let cert = std::fs::read(&args[1]).expect("certificate");
19    let key = std::fs::read(&args[2]).expect("key");
20    let cfg = Arc::new(ServerConfig::from_pem(&cert, &key).expect("server config").with_alpn(&[b"h2", b"http/1.1"]));
21    let mut conn = ServerConnection::new(cfg);
22    let mut input = Vec::new();
23    std::io::stdin().read_to_end(&mut input).expect("stdin");
24    conn.read_tls(&input);
25    if let Err(e) = conn.process_new_packets() {
26        eprintln!("{e:?}");
27    }
28    let out = conn.tls_output().to_vec();
29    conn.consume_tls_output(out.len());
30    std::io::stdout().write_all(&out).expect("stdout");
31    let mut buf = [0u8; 1024];
32    let n = conn.read_plaintext(&mut buf);
33    std::io::stdout().write_all(&buf[..n]).expect("stdout");
34}
examples/size_features.rs (line 68)
48fn main() {
49    let args: Vec<String> = std::env::args().collect();
50    if args.len() < 3 {
51        eprintln!("usage: size_features CERT.pem KEY.pem [PASSWORD [KEYSTORE [OCSP.der [CRL]]]] < client_flight");
52        std::process::exit(2);
53    }
54    let cfg = Arc::new(config(&args));
55    #[cfg(feature = "blocking")]
56    if std::env::var("SIZE_FEATURES_LISTEN").is_ok() {
57        let l = std::net::TcpListener::bind("127.0.0.1:0").expect("bind");
58        let (tcp, _) = l.accept().expect("accept");
59        let mut s = simoom_tls::blocking::accept(tcp, cfg).expect("handshake");
60        let mut buf = [0u8; 1024];
61        let n = s.read(&mut buf).expect("read");
62        s.write_all(&buf[..n]).expect("write");
63        return;
64    }
65    let mut conn = ServerConnection::new(cfg);
66    let mut input = Vec::new();
67    std::io::stdin().read_to_end(&mut input).expect("stdin");
68    conn.read_tls(&input);
69    if let Err(e) = conn.process_new_packets() {
70        eprintln!("{e:?}");
71    }
72    let out = conn.tls_output().to_vec();
73    conn.consume_tls_output(out.len());
74    std::io::stdout().write_all(&out).expect("stdout");
75    let mut buf = [0u8; 1024];
76    let n = conn.read_plaintext(&mut buf);
77    std::io::stdout().write_all(&buf[..n]).expect("stdout");
78}
examples/../tests/fuzzing/mod.rs (line 135)
122pub fn corpus() -> Corpus {
123    let ss = certgen::issue(&CertParams::server(&["localhost"]), PrivateKey::generate_ec(EcCurve::P256), None);
124    let mut roots = RootStore::empty();
125    roots.add_der(&ss.cert_der).unwrap();
126    let scfg = Arc::new(ServerConfig::new(CertifiedKey::new(vec![ss.cert_der.clone()], ss.key.clone()).unwrap()).with_alpn(&[b"h3", b"http/1.1"]));
127    let mut cc = ClientConfig::new(roots).with_alpn(&[b"h3", b"http/1.1"]);
128    cc.sessions = None;
129    let ccfg = Arc::new(cc);
130    // a TLS handshake transcript
131    let mut c = ClientConnection::new(ccfg.clone(), "localhost").unwrap();
132    let mut s = ServerConnection::new(scfg.clone());
133    let ch = c.tls_output().to_vec();
134    c.consume_tls_output(ch.len());
135    s.read_tls(&ch);
136    s.process_new_packets().unwrap();
137    let flight = s.tls_output().to_vec();
138    let mut ch_plus = ch.clone();
139    ch_plus.extend_from_slice(&[20, 3, 3, 0, 1, 1, 23, 3, 3, 0, 20]);
140    ch_plus.extend(std::iter::repeat_n(0xaa, 20));
141    // a QUIC handshake: the ClientHello message and the server's Handshake-level flight
142    let mut qc = QuicConnection::new_client(ccfg.clone(), "localhost", vec![1, 2, 3]).unwrap();
143    let mut qs = QuicConnection::new_server(scfg.clone(), vec![4, 5, 6]);
144    let mut ch_msg = Vec::new();
145    qc.write_handshake(&mut ch_msg);
146    qs.read_handshake(Level::Initial, &ch_msg).unwrap();
147    let mut sh = Vec::new();
148    qs.write_handshake(&mut sh);
149    let mut hs = Vec::new();
150    qs.write_handshake(&mut hs);
151    Corpus {
152        scfg,
153        ccfg,
154        to_server: vec![ch, ch_plus],
155        to_client: vec![flight],
156        ch_msg,
157        server_hs_flight: hs,
158        key_der: ss.key_der.clone(),
159        cert_der: ss.cert_der,
160    }
161}
162
163/// Feeds `data` in random-sized pieces and processes after each; checks that errors stick.
164fn feed(rng: &mut Rng, conn: &mut simoom_tls::Connection, data: &[u8]) {
165    let mut off = 0;
166    while off < data.len() {
167        let k = 1 + rng.below(data.len() - off);
168        let taken = conn.read_tls(&data[off..off + k]);
169        off += taken;
170        let r = conn.process_new_packets();
171        if let Err(e) = r {
172            assert_eq!(conn.process_new_packets().unwrap_err(), e, "errors must stick");
173            assert!(conn.tls_output().len() < 64 * 1024, "output stays bounded");
174            assert!(conn.write_plaintext(b"x").is_err(), "a failed connection refuses writes");
175            return;
176        }
177        if taken == 0 {
178            // buffer full: the application reads plaintext
179            let n = conn.plaintext().len();
180            if n == 0 {
181                return;
182            }
183            conn.consume_plaintext(n);
184        }
185    }
186}
Source

pub fn process_new_packets(&mut self) -> Result<IoState>

Processes buffered records. After an error every call returns the same error; the alert for it (if any) is already queued in the TLS output.

Examples found in repository?
examples/bench_tls.rs (line 48)
42fn pump(c: &mut Connection, s: &mut Connection) {
43    loop {
44        let mut moved = false;
45        if c.wants_write() {
46            let n = s.read_tls(c.tls_output());
47            c.consume_tls_output(n);
48            s.process_new_packets().unwrap();
49            moved = true;
50        }
51        if s.wants_write() {
52            let n = c.read_tls(s.tls_output());
53            s.consume_tls_output(n);
54            c.process_new_packets().unwrap();
55            moved = true;
56        }
57        if !moved {
58            return;
59        }
60    }
61}
62
63fn main() {
64    let openssl = std::env::args().any(|a| a == "--openssl");
65    let d = Duration::from_millis(if std::env::args().any(|a| a == "--quick") { 300 } else { 1500 });
66    println!("simoom-tls benchmarks (single thread), hardware AES: {}, CLMUL: {}, SHA-NI: {}", simoom_sys::arch::has_aes(), simoom_sys::arch::has_clmul(), simoom_sys::arch::has_sha256());
67    println!();
68    println!("{:<34} {:>12} {:>12}", "AEAD seal (encrypt + tag)", "16384 B", "1400 B");
69    let aad = [0u8; 13];
70    let mut buf = vec![0x5au8; 16384];
71    let gcm128 = AesGcm::new(&[1u8; 16]);
72    let gcm256 = AesGcm::new(&[1u8; 32]);
73    let gcm128s = AesGcm::new_soft(&[1u8; 16]);
74    let chacha = ChaCha20Poly1305::new(&[2u8; 32]);
75    let mut seq = 0u64;
76    let mut nonce = || {
77        seq += 1;
78        let mut n = [0u8; 12];
79        n[4..].copy_from_slice(&seq.to_be_bytes());
80        n
81    };
82    let f1 = |n: &[u8; 12], b: &mut [u8]| gcm128.seal(n, &aad, b);
83    let f2 = |n: &[u8; 12], b: &mut [u8]| gcm256.seal(n, &aad, b);
84    let f3 = |n: &[u8; 12], b: &mut [u8]| gcm128s.seal(n, &aad, b);
85    let f4 = |n: &[u8; 12], b: &mut [u8]| chacha.seal(n, &aad, b);
86    let algs: [(&str, &dyn Fn(&[u8; 12], &mut [u8]) -> [u8; 16]); 4] =
87        [("AES-128-GCM", &f1), ("AES-256-GCM", &f2), ("AES-128-GCM (portable, bitsliced)", &f3), ("ChaCha20-Poly1305", &f4)];
88    for (name, f) in algs {
89        let size_d = if name.contains("portable") { d / 3 } else { d };
90        let a = rate(size_d, || {
91            black_box(f(&nonce(), &mut buf));
92        });
93        let b = rate(size_d, || {
94            black_box(f(&nonce(), &mut buf[..1400]));
95        });
96        println!("{:<34} {:>9.2} GB/s {:>7.2} GB/s", name, gbps(a, 16384), gbps(b, 1400));
97    }
98    let mut tag = [0u8; 16];
99    let n12 = [0u8; 12];
100    tag.copy_from_slice(&gcm128.seal(&n12, &aad, &mut buf));
101    let o = rate(d, || {
102        // open fails (buffer changed) but does the full work: GHASH, CTR, tag compare
103        black_box(gcm128.open(&n12, &aad, &mut buf, &tag));
104    });
105    println!("{:<34} {:>9.2} GB/s", "AES-128-GCM open", gbps(o, 16384));
106
107    println!();
108    println!("{:<34} {:>12}", "Primitive", "ops/s");
109    let sk = [7u8; 32];
110    let pk = x25519::x25519_base(&[9u8; 32]);
111    println!("{:<34} {:>12.0}", "X25519 key generation (table)", rate(d, || {
112        black_box(x25519::x25519_base(black_box(&sk)));
113    }));
114    println!("{:<34} {:>12.0}", "X25519 shared secret (ladder)", rate(d, || {
115        black_box(x25519::x25519(black_box(&sk), &pk));
116    }));
117    let d256 = p256::generate_private();
118    let q256 = p256::public_key(&p256::generate_private()).unwrap();
119    let h = [3u8; 32];
120    println!("{:<34} {:>12.0}", "P-256 key generation", rate(d, || {
121        black_box(p256::public_key(black_box(&d256)));
122    }));
123    println!("{:<34} {:>12.0}", "P-256 ECDH", rate(d, || {
124        black_box(p256::ecdh(black_box(&d256), &q256));
125    }));
126    let (r, s) = p256::sign(&d256, &h, simoom_tls::crypto::sha2::HashAlg::Sha256).unwrap();
127    let pub256 = p256::public_key(&d256).unwrap();
128    println!("{:<34} {:>12.0}", "ECDSA P-256 sign", rate(d, || {
129        black_box(p256::sign(black_box(&d256), &h, simoom_tls::crypto::sha2::HashAlg::Sha256));
130    }));
131    println!("{:<34} {:>12.0}", "ECDSA P-256 verify", rate(d, || {
132        black_box(p256::verify(&pub256, &h, &r, &s));
133    }));
134    let seed = [5u8; 32];
135    let edpub = simoom_tls::crypto::ed25519::public_key(&seed);
136    // as the server signs: the key's public half is known (OpenSSL keeps it in the key too)
137    println!("{:<34} {:>12.0}", "Ed25519 sign", rate(d, || {
138        black_box(simoom_tls::crypto::ed25519::sign_with_public(&seed, &edpub, b"message"));
139    }));
140    let edsig = simoom_tls::crypto::ed25519::sign(&seed, b"message");
141    println!("{:<34} {:>12.0}", "Ed25519 verify", rate(d, || {
142        black_box(simoom_tls::crypto::ed25519::verify(&edpub, b"message", &edsig));
143    }));
144    let rsa = PrivateKey::from_pem(include_bytes!("../testdata/rsa2048.pkcs1.pem")).unwrap();
145    if let PrivateKey::Rsa(k) = &rsa {
146        let dg = [1u8; 32];
147        println!("{:<34} {:>12.0}", "RSA-2048 PSS sign", rate(d, || {
148            black_box(k.sign_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg));
149        }));
150        let sig = k.sign_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg).unwrap();
151        println!("{:<34} {:>12.0}", "RSA-2048 PSS verify", rate(d, || {
152            black_box(k.public.verify_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg, &sig, Some(32)));
153        }));
154    }
155
156    // handshakes
157    let ss = certgen::issue(&CertParams::server(&["localhost"]), PrivateKey::generate_ec(EcCurve::P256), None);
158    let mut roots = RootStore::empty();
159    roots.add_der(&ss.cert_der).unwrap();
160    let mut scfg = ServerConfig::new(CertifiedKey::new(vec![ss.cert_der.clone()], ss.key.clone()).unwrap());
161    scfg.groups = vec![NamedGroup::X25519];
162    let scfg = Arc::new(scfg);
163    let mut cfull = ClientConfig::new(roots.clone());
164    cfull.sessions = None;
165    cfull.groups = vec![NamedGroup::X25519];
166    let cfull = Arc::new(cfull);
167    let mut cres = ClientConfig::new(roots);
168    cres.groups = vec![NamedGroup::X25519];
169    let cres = Arc::new(cres);
170
171    println!();
172    println!("{:<44} {:>12}", "TLS 1.3 handshake (X25519, ECDSA P-256 cert)", "per second");
173    let full = rate(d, || {
174        let mut c = ClientConnection::new(cfull.clone(), "localhost").unwrap();
175        let mut s = ServerConnection::new(scfg.clone());
176        pump(&mut c, &mut s);
177        assert!(!s.is_handshaking());
178    });
179    println!("{:<44} {:>12.0}", "full, client + server", full);
180    // server side only: replay a fresh ClientHello per iteration and time the server's work
181    let mut server_time = Duration::ZERO;
182    let mut n = 0u32;
183    let t0 = Instant::now();
184    while t0.elapsed() < d {
185        let mut c = ClientConnection::new(cfull.clone(), "localhost").unwrap();
186        let mut s = ServerConnection::new(scfg.clone());
187        let ch = c.tls_output().to_vec();
188        c.consume_tls_output(ch.len());
189        let t = Instant::now();
190        s.read_tls(&ch);
191        s.process_new_packets().unwrap();
192        server_time += t.elapsed();
193        let flight = s.tls_output().to_vec();
194        s.consume_tls_output(flight.len());
195        c.read_tls(&flight);
196        c.process_new_packets().unwrap();
197        let fin = c.tls_output().to_vec();
198        let t = Instant::now();
199        s.read_tls(&fin);
200        s.process_new_packets().unwrap();
201        server_time += t.elapsed();
202        n += 1;
203    }
204    println!("{:<44} {:>12.0}", "full, server side only", n as f64 / server_time.as_secs_f64());
205    // resumption: prime the cache, then each connection uses one ticket and stores a new one
206    let mut c = ClientConnection::new(cres.clone(), "localhost").unwrap();
207    let mut s = ServerConnection::new(scfg.clone());
208    pump(&mut c, &mut s);
209    let resumed = rate(d, || {
210        let mut c = ClientConnection::new(cres.clone(), "localhost").unwrap();
211        let mut s = ServerConnection::new(scfg.clone());
212        pump(&mut c, &mut s);
213        assert!(c.is_resumed());
214    });
215    println!("{:<44} {:>12.0}", "PSK-DHE resumption, client + server", resumed);
216
217    if openssl {
218        println!();
219        println!("openssl speed (same machine, single thread):");
220        for args in [
221            &["speed", "-seconds", "2", "-bytes", "16384", "-evp", "aes-128-gcm"][..],
222            &["speed", "-seconds", "2", "-bytes", "1400", "-evp", "aes-128-gcm"][..],
223            &["speed", "-seconds", "2", "-bytes", "16384", "-evp", "chacha20-poly1305"][..],
224            &["speed", "-seconds", "2", "-bytes", "1400", "-evp", "chacha20-poly1305"][..],
225            &["speed", "-seconds", "2", "ecdhx25519", "ecdhp256", "ecdsap256", "ed25519", "rsa2048"][..],
226        ] {
227            match std::process::Command::new("openssl").args(args).output() {
228                Ok(o) => {
229                    let out = String::from_utf8_lossy(&o.stdout);
230                    for line in out.lines().filter(|l| {
231                        l.starts_with("AES-128-GCM") || l.starts_with("ChaCha20-Poly1305") || l.contains(" sign ") || l.contains("op/s") || l.starts_with("rsa") || l.contains("ecdh") || l.contains("ecdsa") || l.contains("Ed25519") || l.contains("type")
232                    }) {
233                        println!("  {line}");
234                    }
235                }
236                Err(e) => println!("  openssl not available: {e}"),
237            }
238        }
239    }
240}
More examples
Hide additional examples
examples/size_server.rs (line 25)
12fn main() {
13    let args: Vec<String> = std::env::args().collect();
14    if args.len() < 3 {
15        eprintln!("usage: size_server CERT.pem KEY.pem < client_flight");
16        std::process::exit(2);
17    }
18    let cert = std::fs::read(&args[1]).expect("certificate");
19    let key = std::fs::read(&args[2]).expect("key");
20    let cfg = Arc::new(ServerConfig::from_pem(&cert, &key).expect("server config").with_alpn(&[b"h2", b"http/1.1"]));
21    let mut conn = ServerConnection::new(cfg);
22    let mut input = Vec::new();
23    std::io::stdin().read_to_end(&mut input).expect("stdin");
24    conn.read_tls(&input);
25    if let Err(e) = conn.process_new_packets() {
26        eprintln!("{e:?}");
27    }
28    let out = conn.tls_output().to_vec();
29    conn.consume_tls_output(out.len());
30    std::io::stdout().write_all(&out).expect("stdout");
31    let mut buf = [0u8; 1024];
32    let n = conn.read_plaintext(&mut buf);
33    std::io::stdout().write_all(&buf[..n]).expect("stdout");
34}
examples/size_features.rs (line 69)
48fn main() {
49    let args: Vec<String> = std::env::args().collect();
50    if args.len() < 3 {
51        eprintln!("usage: size_features CERT.pem KEY.pem [PASSWORD [KEYSTORE [OCSP.der [CRL]]]] < client_flight");
52        std::process::exit(2);
53    }
54    let cfg = Arc::new(config(&args));
55    #[cfg(feature = "blocking")]
56    if std::env::var("SIZE_FEATURES_LISTEN").is_ok() {
57        let l = std::net::TcpListener::bind("127.0.0.1:0").expect("bind");
58        let (tcp, _) = l.accept().expect("accept");
59        let mut s = simoom_tls::blocking::accept(tcp, cfg).expect("handshake");
60        let mut buf = [0u8; 1024];
61        let n = s.read(&mut buf).expect("read");
62        s.write_all(&buf[..n]).expect("write");
63        return;
64    }
65    let mut conn = ServerConnection::new(cfg);
66    let mut input = Vec::new();
67    std::io::stdin().read_to_end(&mut input).expect("stdin");
68    conn.read_tls(&input);
69    if let Err(e) = conn.process_new_packets() {
70        eprintln!("{e:?}");
71    }
72    let out = conn.tls_output().to_vec();
73    conn.consume_tls_output(out.len());
74    std::io::stdout().write_all(&out).expect("stdout");
75    let mut buf = [0u8; 1024];
76    let n = conn.read_plaintext(&mut buf);
77    std::io::stdout().write_all(&buf[..n]).expect("stdout");
78}
examples/../tests/fuzzing/mod.rs (line 136)
122pub fn corpus() -> Corpus {
123    let ss = certgen::issue(&CertParams::server(&["localhost"]), PrivateKey::generate_ec(EcCurve::P256), None);
124    let mut roots = RootStore::empty();
125    roots.add_der(&ss.cert_der).unwrap();
126    let scfg = Arc::new(ServerConfig::new(CertifiedKey::new(vec![ss.cert_der.clone()], ss.key.clone()).unwrap()).with_alpn(&[b"h3", b"http/1.1"]));
127    let mut cc = ClientConfig::new(roots).with_alpn(&[b"h3", b"http/1.1"]);
128    cc.sessions = None;
129    let ccfg = Arc::new(cc);
130    // a TLS handshake transcript
131    let mut c = ClientConnection::new(ccfg.clone(), "localhost").unwrap();
132    let mut s = ServerConnection::new(scfg.clone());
133    let ch = c.tls_output().to_vec();
134    c.consume_tls_output(ch.len());
135    s.read_tls(&ch);
136    s.process_new_packets().unwrap();
137    let flight = s.tls_output().to_vec();
138    let mut ch_plus = ch.clone();
139    ch_plus.extend_from_slice(&[20, 3, 3, 0, 1, 1, 23, 3, 3, 0, 20]);
140    ch_plus.extend(std::iter::repeat_n(0xaa, 20));
141    // a QUIC handshake: the ClientHello message and the server's Handshake-level flight
142    let mut qc = QuicConnection::new_client(ccfg.clone(), "localhost", vec![1, 2, 3]).unwrap();
143    let mut qs = QuicConnection::new_server(scfg.clone(), vec![4, 5, 6]);
144    let mut ch_msg = Vec::new();
145    qc.write_handshake(&mut ch_msg);
146    qs.read_handshake(Level::Initial, &ch_msg).unwrap();
147    let mut sh = Vec::new();
148    qs.write_handshake(&mut sh);
149    let mut hs = Vec::new();
150    qs.write_handshake(&mut hs);
151    Corpus {
152        scfg,
153        ccfg,
154        to_server: vec![ch, ch_plus],
155        to_client: vec![flight],
156        ch_msg,
157        server_hs_flight: hs,
158        key_der: ss.key_der.clone(),
159        cert_der: ss.cert_der,
160    }
161}
162
163/// Feeds `data` in random-sized pieces and processes after each; checks that errors stick.
164fn feed(rng: &mut Rng, conn: &mut simoom_tls::Connection, data: &[u8]) {
165    let mut off = 0;
166    while off < data.len() {
167        let k = 1 + rng.below(data.len() - off);
168        let taken = conn.read_tls(&data[off..off + k]);
169        off += taken;
170        let r = conn.process_new_packets();
171        if let Err(e) = r {
172            assert_eq!(conn.process_new_packets().unwrap_err(), e, "errors must stick");
173            assert!(conn.tls_output().len() < 64 * 1024, "output stays bounded");
174            assert!(conn.write_plaintext(b"x").is_err(), "a failed connection refuses writes");
175            return;
176        }
177        if taken == 0 {
178            // buffer full: the application reads plaintext
179            let n = conn.plaintext().len();
180            if n == 0 {
181                return;
182            }
183            conn.consume_plaintext(n);
184        }
185    }
186}
Source

pub fn wants_write(&self) -> bool

True if TLS bytes are waiting to be sent.

Examples found in repository?
examples/bench_tls.rs (line 45)
42fn pump(c: &mut Connection, s: &mut Connection) {
43    loop {
44        let mut moved = false;
45        if c.wants_write() {
46            let n = s.read_tls(c.tls_output());
47            c.consume_tls_output(n);
48            s.process_new_packets().unwrap();
49            moved = true;
50        }
51        if s.wants_write() {
52            let n = c.read_tls(s.tls_output());
53            s.consume_tls_output(n);
54            c.process_new_packets().unwrap();
55            moved = true;
56        }
57        if !moved {
58            return;
59        }
60    }
61}
Source

pub fn tls_output(&self) -> &[u8] ⓘ

The TLS bytes waiting to be sent.

Examples found in repository?
examples/bench_tls.rs (line 46)
42fn pump(c: &mut Connection, s: &mut Connection) {
43    loop {
44        let mut moved = false;
45        if c.wants_write() {
46            let n = s.read_tls(c.tls_output());
47            c.consume_tls_output(n);
48            s.process_new_packets().unwrap();
49            moved = true;
50        }
51        if s.wants_write() {
52            let n = c.read_tls(s.tls_output());
53            s.consume_tls_output(n);
54            c.process_new_packets().unwrap();
55            moved = true;
56        }
57        if !moved {
58            return;
59        }
60    }
61}
62
63fn main() {
64    let openssl = std::env::args().any(|a| a == "--openssl");
65    let d = Duration::from_millis(if std::env::args().any(|a| a == "--quick") { 300 } else { 1500 });
66    println!("simoom-tls benchmarks (single thread), hardware AES: {}, CLMUL: {}, SHA-NI: {}", simoom_sys::arch::has_aes(), simoom_sys::arch::has_clmul(), simoom_sys::arch::has_sha256());
67    println!();
68    println!("{:<34} {:>12} {:>12}", "AEAD seal (encrypt + tag)", "16384 B", "1400 B");
69    let aad = [0u8; 13];
70    let mut buf = vec![0x5au8; 16384];
71    let gcm128 = AesGcm::new(&[1u8; 16]);
72    let gcm256 = AesGcm::new(&[1u8; 32]);
73    let gcm128s = AesGcm::new_soft(&[1u8; 16]);
74    let chacha = ChaCha20Poly1305::new(&[2u8; 32]);
75    let mut seq = 0u64;
76    let mut nonce = || {
77        seq += 1;
78        let mut n = [0u8; 12];
79        n[4..].copy_from_slice(&seq.to_be_bytes());
80        n
81    };
82    let f1 = |n: &[u8; 12], b: &mut [u8]| gcm128.seal(n, &aad, b);
83    let f2 = |n: &[u8; 12], b: &mut [u8]| gcm256.seal(n, &aad, b);
84    let f3 = |n: &[u8; 12], b: &mut [u8]| gcm128s.seal(n, &aad, b);
85    let f4 = |n: &[u8; 12], b: &mut [u8]| chacha.seal(n, &aad, b);
86    let algs: [(&str, &dyn Fn(&[u8; 12], &mut [u8]) -> [u8; 16]); 4] =
87        [("AES-128-GCM", &f1), ("AES-256-GCM", &f2), ("AES-128-GCM (portable, bitsliced)", &f3), ("ChaCha20-Poly1305", &f4)];
88    for (name, f) in algs {
89        let size_d = if name.contains("portable") { d / 3 } else { d };
90        let a = rate(size_d, || {
91            black_box(f(&nonce(), &mut buf));
92        });
93        let b = rate(size_d, || {
94            black_box(f(&nonce(), &mut buf[..1400]));
95        });
96        println!("{:<34} {:>9.2} GB/s {:>7.2} GB/s", name, gbps(a, 16384), gbps(b, 1400));
97    }
98    let mut tag = [0u8; 16];
99    let n12 = [0u8; 12];
100    tag.copy_from_slice(&gcm128.seal(&n12, &aad, &mut buf));
101    let o = rate(d, || {
102        // open fails (buffer changed) but does the full work: GHASH, CTR, tag compare
103        black_box(gcm128.open(&n12, &aad, &mut buf, &tag));
104    });
105    println!("{:<34} {:>9.2} GB/s", "AES-128-GCM open", gbps(o, 16384));
106
107    println!();
108    println!("{:<34} {:>12}", "Primitive", "ops/s");
109    let sk = [7u8; 32];
110    let pk = x25519::x25519_base(&[9u8; 32]);
111    println!("{:<34} {:>12.0}", "X25519 key generation (table)", rate(d, || {
112        black_box(x25519::x25519_base(black_box(&sk)));
113    }));
114    println!("{:<34} {:>12.0}", "X25519 shared secret (ladder)", rate(d, || {
115        black_box(x25519::x25519(black_box(&sk), &pk));
116    }));
117    let d256 = p256::generate_private();
118    let q256 = p256::public_key(&p256::generate_private()).unwrap();
119    let h = [3u8; 32];
120    println!("{:<34} {:>12.0}", "P-256 key generation", rate(d, || {
121        black_box(p256::public_key(black_box(&d256)));
122    }));
123    println!("{:<34} {:>12.0}", "P-256 ECDH", rate(d, || {
124        black_box(p256::ecdh(black_box(&d256), &q256));
125    }));
126    let (r, s) = p256::sign(&d256, &h, simoom_tls::crypto::sha2::HashAlg::Sha256).unwrap();
127    let pub256 = p256::public_key(&d256).unwrap();
128    println!("{:<34} {:>12.0}", "ECDSA P-256 sign", rate(d, || {
129        black_box(p256::sign(black_box(&d256), &h, simoom_tls::crypto::sha2::HashAlg::Sha256));
130    }));
131    println!("{:<34} {:>12.0}", "ECDSA P-256 verify", rate(d, || {
132        black_box(p256::verify(&pub256, &h, &r, &s));
133    }));
134    let seed = [5u8; 32];
135    let edpub = simoom_tls::crypto::ed25519::public_key(&seed);
136    // as the server signs: the key's public half is known (OpenSSL keeps it in the key too)
137    println!("{:<34} {:>12.0}", "Ed25519 sign", rate(d, || {
138        black_box(simoom_tls::crypto::ed25519::sign_with_public(&seed, &edpub, b"message"));
139    }));
140    let edsig = simoom_tls::crypto::ed25519::sign(&seed, b"message");
141    println!("{:<34} {:>12.0}", "Ed25519 verify", rate(d, || {
142        black_box(simoom_tls::crypto::ed25519::verify(&edpub, b"message", &edsig));
143    }));
144    let rsa = PrivateKey::from_pem(include_bytes!("../testdata/rsa2048.pkcs1.pem")).unwrap();
145    if let PrivateKey::Rsa(k) = &rsa {
146        let dg = [1u8; 32];
147        println!("{:<34} {:>12.0}", "RSA-2048 PSS sign", rate(d, || {
148            black_box(k.sign_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg));
149        }));
150        let sig = k.sign_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg).unwrap();
151        println!("{:<34} {:>12.0}", "RSA-2048 PSS verify", rate(d, || {
152            black_box(k.public.verify_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg, &sig, Some(32)));
153        }));
154    }
155
156    // handshakes
157    let ss = certgen::issue(&CertParams::server(&["localhost"]), PrivateKey::generate_ec(EcCurve::P256), None);
158    let mut roots = RootStore::empty();
159    roots.add_der(&ss.cert_der).unwrap();
160    let mut scfg = ServerConfig::new(CertifiedKey::new(vec![ss.cert_der.clone()], ss.key.clone()).unwrap());
161    scfg.groups = vec![NamedGroup::X25519];
162    let scfg = Arc::new(scfg);
163    let mut cfull = ClientConfig::new(roots.clone());
164    cfull.sessions = None;
165    cfull.groups = vec![NamedGroup::X25519];
166    let cfull = Arc::new(cfull);
167    let mut cres = ClientConfig::new(roots);
168    cres.groups = vec![NamedGroup::X25519];
169    let cres = Arc::new(cres);
170
171    println!();
172    println!("{:<44} {:>12}", "TLS 1.3 handshake (X25519, ECDSA P-256 cert)", "per second");
173    let full = rate(d, || {
174        let mut c = ClientConnection::new(cfull.clone(), "localhost").unwrap();
175        let mut s = ServerConnection::new(scfg.clone());
176        pump(&mut c, &mut s);
177        assert!(!s.is_handshaking());
178    });
179    println!("{:<44} {:>12.0}", "full, client + server", full);
180    // server side only: replay a fresh ClientHello per iteration and time the server's work
181    let mut server_time = Duration::ZERO;
182    let mut n = 0u32;
183    let t0 = Instant::now();
184    while t0.elapsed() < d {
185        let mut c = ClientConnection::new(cfull.clone(), "localhost").unwrap();
186        let mut s = ServerConnection::new(scfg.clone());
187        let ch = c.tls_output().to_vec();
188        c.consume_tls_output(ch.len());
189        let t = Instant::now();
190        s.read_tls(&ch);
191        s.process_new_packets().unwrap();
192        server_time += t.elapsed();
193        let flight = s.tls_output().to_vec();
194        s.consume_tls_output(flight.len());
195        c.read_tls(&flight);
196        c.process_new_packets().unwrap();
197        let fin = c.tls_output().to_vec();
198        let t = Instant::now();
199        s.read_tls(&fin);
200        s.process_new_packets().unwrap();
201        server_time += t.elapsed();
202        n += 1;
203    }
204    println!("{:<44} {:>12.0}", "full, server side only", n as f64 / server_time.as_secs_f64());
205    // resumption: prime the cache, then each connection uses one ticket and stores a new one
206    let mut c = ClientConnection::new(cres.clone(), "localhost").unwrap();
207    let mut s = ServerConnection::new(scfg.clone());
208    pump(&mut c, &mut s);
209    let resumed = rate(d, || {
210        let mut c = ClientConnection::new(cres.clone(), "localhost").unwrap();
211        let mut s = ServerConnection::new(scfg.clone());
212        pump(&mut c, &mut s);
213        assert!(c.is_resumed());
214    });
215    println!("{:<44} {:>12.0}", "PSK-DHE resumption, client + server", resumed);
216
217    if openssl {
218        println!();
219        println!("openssl speed (same machine, single thread):");
220        for args in [
221            &["speed", "-seconds", "2", "-bytes", "16384", "-evp", "aes-128-gcm"][..],
222            &["speed", "-seconds", "2", "-bytes", "1400", "-evp", "aes-128-gcm"][..],
223            &["speed", "-seconds", "2", "-bytes", "16384", "-evp", "chacha20-poly1305"][..],
224            &["speed", "-seconds", "2", "-bytes", "1400", "-evp", "chacha20-poly1305"][..],
225            &["speed", "-seconds", "2", "ecdhx25519", "ecdhp256", "ecdsap256", "ed25519", "rsa2048"][..],
226        ] {
227            match std::process::Command::new("openssl").args(args).output() {
228                Ok(o) => {
229                    let out = String::from_utf8_lossy(&o.stdout);
230                    for line in out.lines().filter(|l| {
231                        l.starts_with("AES-128-GCM") || l.starts_with("ChaCha20-Poly1305") || l.contains(" sign ") || l.contains("op/s") || l.starts_with("rsa") || l.contains("ecdh") || l.contains("ecdsa") || l.contains("Ed25519") || l.contains("type")
232                    }) {
233                        println!("  {line}");
234                    }
235                }
236                Err(e) => println!("  openssl not available: {e}"),
237            }
238        }
239    }
240}
More examples
Hide additional examples
examples/size_server.rs (line 28)
12fn main() {
13    let args: Vec<String> = std::env::args().collect();
14    if args.len() < 3 {
15        eprintln!("usage: size_server CERT.pem KEY.pem < client_flight");
16        std::process::exit(2);
17    }
18    let cert = std::fs::read(&args[1]).expect("certificate");
19    let key = std::fs::read(&args[2]).expect("key");
20    let cfg = Arc::new(ServerConfig::from_pem(&cert, &key).expect("server config").with_alpn(&[b"h2", b"http/1.1"]));
21    let mut conn = ServerConnection::new(cfg);
22    let mut input = Vec::new();
23    std::io::stdin().read_to_end(&mut input).expect("stdin");
24    conn.read_tls(&input);
25    if let Err(e) = conn.process_new_packets() {
26        eprintln!("{e:?}");
27    }
28    let out = conn.tls_output().to_vec();
29    conn.consume_tls_output(out.len());
30    std::io::stdout().write_all(&out).expect("stdout");
31    let mut buf = [0u8; 1024];
32    let n = conn.read_plaintext(&mut buf);
33    std::io::stdout().write_all(&buf[..n]).expect("stdout");
34}
examples/size_features.rs (line 72)
48fn main() {
49    let args: Vec<String> = std::env::args().collect();
50    if args.len() < 3 {
51        eprintln!("usage: size_features CERT.pem KEY.pem [PASSWORD [KEYSTORE [OCSP.der [CRL]]]] < client_flight");
52        std::process::exit(2);
53    }
54    let cfg = Arc::new(config(&args));
55    #[cfg(feature = "blocking")]
56    if std::env::var("SIZE_FEATURES_LISTEN").is_ok() {
57        let l = std::net::TcpListener::bind("127.0.0.1:0").expect("bind");
58        let (tcp, _) = l.accept().expect("accept");
59        let mut s = simoom_tls::blocking::accept(tcp, cfg).expect("handshake");
60        let mut buf = [0u8; 1024];
61        let n = s.read(&mut buf).expect("read");
62        s.write_all(&buf[..n]).expect("write");
63        return;
64    }
65    let mut conn = ServerConnection::new(cfg);
66    let mut input = Vec::new();
67    std::io::stdin().read_to_end(&mut input).expect("stdin");
68    conn.read_tls(&input);
69    if let Err(e) = conn.process_new_packets() {
70        eprintln!("{e:?}");
71    }
72    let out = conn.tls_output().to_vec();
73    conn.consume_tls_output(out.len());
74    std::io::stdout().write_all(&out).expect("stdout");
75    let mut buf = [0u8; 1024];
76    let n = conn.read_plaintext(&mut buf);
77    std::io::stdout().write_all(&buf[..n]).expect("stdout");
78}
examples/../tests/fuzzing/mod.rs (line 133)
122pub fn corpus() -> Corpus {
123    let ss = certgen::issue(&CertParams::server(&["localhost"]), PrivateKey::generate_ec(EcCurve::P256), None);
124    let mut roots = RootStore::empty();
125    roots.add_der(&ss.cert_der).unwrap();
126    let scfg = Arc::new(ServerConfig::new(CertifiedKey::new(vec![ss.cert_der.clone()], ss.key.clone()).unwrap()).with_alpn(&[b"h3", b"http/1.1"]));
127    let mut cc = ClientConfig::new(roots).with_alpn(&[b"h3", b"http/1.1"]);
128    cc.sessions = None;
129    let ccfg = Arc::new(cc);
130    // a TLS handshake transcript
131    let mut c = ClientConnection::new(ccfg.clone(), "localhost").unwrap();
132    let mut s = ServerConnection::new(scfg.clone());
133    let ch = c.tls_output().to_vec();
134    c.consume_tls_output(ch.len());
135    s.read_tls(&ch);
136    s.process_new_packets().unwrap();
137    let flight = s.tls_output().to_vec();
138    let mut ch_plus = ch.clone();
139    ch_plus.extend_from_slice(&[20, 3, 3, 0, 1, 1, 23, 3, 3, 0, 20]);
140    ch_plus.extend(std::iter::repeat_n(0xaa, 20));
141    // a QUIC handshake: the ClientHello message and the server's Handshake-level flight
142    let mut qc = QuicConnection::new_client(ccfg.clone(), "localhost", vec![1, 2, 3]).unwrap();
143    let mut qs = QuicConnection::new_server(scfg.clone(), vec![4, 5, 6]);
144    let mut ch_msg = Vec::new();
145    qc.write_handshake(&mut ch_msg);
146    qs.read_handshake(Level::Initial, &ch_msg).unwrap();
147    let mut sh = Vec::new();
148    qs.write_handshake(&mut sh);
149    let mut hs = Vec::new();
150    qs.write_handshake(&mut hs);
151    Corpus {
152        scfg,
153        ccfg,
154        to_server: vec![ch, ch_plus],
155        to_client: vec![flight],
156        ch_msg,
157        server_hs_flight: hs,
158        key_der: ss.key_der.clone(),
159        cert_der: ss.cert_der,
160    }
161}
162
163/// Feeds `data` in random-sized pieces and processes after each; checks that errors stick.
164fn feed(rng: &mut Rng, conn: &mut simoom_tls::Connection, data: &[u8]) {
165    let mut off = 0;
166    while off < data.len() {
167        let k = 1 + rng.below(data.len() - off);
168        let taken = conn.read_tls(&data[off..off + k]);
169        off += taken;
170        let r = conn.process_new_packets();
171        if let Err(e) = r {
172            assert_eq!(conn.process_new_packets().unwrap_err(), e, "errors must stick");
173            assert!(conn.tls_output().len() < 64 * 1024, "output stays bounded");
174            assert!(conn.write_plaintext(b"x").is_err(), "a failed connection refuses writes");
175            return;
176        }
177        if taken == 0 {
178            // buffer full: the application reads plaintext
179            let n = conn.plaintext().len();
180            if n == 0 {
181                return;
182            }
183            conn.consume_plaintext(n);
184        }
185    }
186}
187
188pub fn server_records(rng: &mut Rng, c: &Corpus, iters: usize) {
189    for _ in 0..iters {
190        let seed = &c.to_server[rng.below(c.to_server.len())];
191        let data = mutate(rng, seed, &c.to_client);
192        let mut s = ServerConnection::new(c.scfg.clone());
193        feed(rng, &mut s, &data);
194    }
195}
196
197pub fn client_records(rng: &mut Rng, c: &Corpus, iters: usize) {
198    for _ in 0..iters {
199        let data = mutate(rng, &c.to_client[0], &c.to_server);
200        let mut cl = ClientConnection::new(c.ccfg.clone(), "localhost").unwrap();
201        let n = cl.tls_output().len();
202        cl.consume_tls_output(n);
203        feed(rng, &mut cl, &data);
204    }
205}
Source

pub fn consume_tls_output(&mut self, n: usize)

Marks n bytes of tls_output as sent.

Examples found in repository?
examples/bench_tls.rs (line 47)
42fn pump(c: &mut Connection, s: &mut Connection) {
43    loop {
44        let mut moved = false;
45        if c.wants_write() {
46            let n = s.read_tls(c.tls_output());
47            c.consume_tls_output(n);
48            s.process_new_packets().unwrap();
49            moved = true;
50        }
51        if s.wants_write() {
52            let n = c.read_tls(s.tls_output());
53            s.consume_tls_output(n);
54            c.process_new_packets().unwrap();
55            moved = true;
56        }
57        if !moved {
58            return;
59        }
60    }
61}
62
63fn main() {
64    let openssl = std::env::args().any(|a| a == "--openssl");
65    let d = Duration::from_millis(if std::env::args().any(|a| a == "--quick") { 300 } else { 1500 });
66    println!("simoom-tls benchmarks (single thread), hardware AES: {}, CLMUL: {}, SHA-NI: {}", simoom_sys::arch::has_aes(), simoom_sys::arch::has_clmul(), simoom_sys::arch::has_sha256());
67    println!();
68    println!("{:<34} {:>12} {:>12}", "AEAD seal (encrypt + tag)", "16384 B", "1400 B");
69    let aad = [0u8; 13];
70    let mut buf = vec![0x5au8; 16384];
71    let gcm128 = AesGcm::new(&[1u8; 16]);
72    let gcm256 = AesGcm::new(&[1u8; 32]);
73    let gcm128s = AesGcm::new_soft(&[1u8; 16]);
74    let chacha = ChaCha20Poly1305::new(&[2u8; 32]);
75    let mut seq = 0u64;
76    let mut nonce = || {
77        seq += 1;
78        let mut n = [0u8; 12];
79        n[4..].copy_from_slice(&seq.to_be_bytes());
80        n
81    };
82    let f1 = |n: &[u8; 12], b: &mut [u8]| gcm128.seal(n, &aad, b);
83    let f2 = |n: &[u8; 12], b: &mut [u8]| gcm256.seal(n, &aad, b);
84    let f3 = |n: &[u8; 12], b: &mut [u8]| gcm128s.seal(n, &aad, b);
85    let f4 = |n: &[u8; 12], b: &mut [u8]| chacha.seal(n, &aad, b);
86    let algs: [(&str, &dyn Fn(&[u8; 12], &mut [u8]) -> [u8; 16]); 4] =
87        [("AES-128-GCM", &f1), ("AES-256-GCM", &f2), ("AES-128-GCM (portable, bitsliced)", &f3), ("ChaCha20-Poly1305", &f4)];
88    for (name, f) in algs {
89        let size_d = if name.contains("portable") { d / 3 } else { d };
90        let a = rate(size_d, || {
91            black_box(f(&nonce(), &mut buf));
92        });
93        let b = rate(size_d, || {
94            black_box(f(&nonce(), &mut buf[..1400]));
95        });
96        println!("{:<34} {:>9.2} GB/s {:>7.2} GB/s", name, gbps(a, 16384), gbps(b, 1400));
97    }
98    let mut tag = [0u8; 16];
99    let n12 = [0u8; 12];
100    tag.copy_from_slice(&gcm128.seal(&n12, &aad, &mut buf));
101    let o = rate(d, || {
102        // open fails (buffer changed) but does the full work: GHASH, CTR, tag compare
103        black_box(gcm128.open(&n12, &aad, &mut buf, &tag));
104    });
105    println!("{:<34} {:>9.2} GB/s", "AES-128-GCM open", gbps(o, 16384));
106
107    println!();
108    println!("{:<34} {:>12}", "Primitive", "ops/s");
109    let sk = [7u8; 32];
110    let pk = x25519::x25519_base(&[9u8; 32]);
111    println!("{:<34} {:>12.0}", "X25519 key generation (table)", rate(d, || {
112        black_box(x25519::x25519_base(black_box(&sk)));
113    }));
114    println!("{:<34} {:>12.0}", "X25519 shared secret (ladder)", rate(d, || {
115        black_box(x25519::x25519(black_box(&sk), &pk));
116    }));
117    let d256 = p256::generate_private();
118    let q256 = p256::public_key(&p256::generate_private()).unwrap();
119    let h = [3u8; 32];
120    println!("{:<34} {:>12.0}", "P-256 key generation", rate(d, || {
121        black_box(p256::public_key(black_box(&d256)));
122    }));
123    println!("{:<34} {:>12.0}", "P-256 ECDH", rate(d, || {
124        black_box(p256::ecdh(black_box(&d256), &q256));
125    }));
126    let (r, s) = p256::sign(&d256, &h, simoom_tls::crypto::sha2::HashAlg::Sha256).unwrap();
127    let pub256 = p256::public_key(&d256).unwrap();
128    println!("{:<34} {:>12.0}", "ECDSA P-256 sign", rate(d, || {
129        black_box(p256::sign(black_box(&d256), &h, simoom_tls::crypto::sha2::HashAlg::Sha256));
130    }));
131    println!("{:<34} {:>12.0}", "ECDSA P-256 verify", rate(d, || {
132        black_box(p256::verify(&pub256, &h, &r, &s));
133    }));
134    let seed = [5u8; 32];
135    let edpub = simoom_tls::crypto::ed25519::public_key(&seed);
136    // as the server signs: the key's public half is known (OpenSSL keeps it in the key too)
137    println!("{:<34} {:>12.0}", "Ed25519 sign", rate(d, || {
138        black_box(simoom_tls::crypto::ed25519::sign_with_public(&seed, &edpub, b"message"));
139    }));
140    let edsig = simoom_tls::crypto::ed25519::sign(&seed, b"message");
141    println!("{:<34} {:>12.0}", "Ed25519 verify", rate(d, || {
142        black_box(simoom_tls::crypto::ed25519::verify(&edpub, b"message", &edsig));
143    }));
144    let rsa = PrivateKey::from_pem(include_bytes!("../testdata/rsa2048.pkcs1.pem")).unwrap();
145    if let PrivateKey::Rsa(k) = &rsa {
146        let dg = [1u8; 32];
147        println!("{:<34} {:>12.0}", "RSA-2048 PSS sign", rate(d, || {
148            black_box(k.sign_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg));
149        }));
150        let sig = k.sign_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg).unwrap();
151        println!("{:<34} {:>12.0}", "RSA-2048 PSS verify", rate(d, || {
152            black_box(k.public.verify_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg, &sig, Some(32)));
153        }));
154    }
155
156    // handshakes
157    let ss = certgen::issue(&CertParams::server(&["localhost"]), PrivateKey::generate_ec(EcCurve::P256), None);
158    let mut roots = RootStore::empty();
159    roots.add_der(&ss.cert_der).unwrap();
160    let mut scfg = ServerConfig::new(CertifiedKey::new(vec![ss.cert_der.clone()], ss.key.clone()).unwrap());
161    scfg.groups = vec![NamedGroup::X25519];
162    let scfg = Arc::new(scfg);
163    let mut cfull = ClientConfig::new(roots.clone());
164    cfull.sessions = None;
165    cfull.groups = vec![NamedGroup::X25519];
166    let cfull = Arc::new(cfull);
167    let mut cres = ClientConfig::new(roots);
168    cres.groups = vec![NamedGroup::X25519];
169    let cres = Arc::new(cres);
170
171    println!();
172    println!("{:<44} {:>12}", "TLS 1.3 handshake (X25519, ECDSA P-256 cert)", "per second");
173    let full = rate(d, || {
174        let mut c = ClientConnection::new(cfull.clone(), "localhost").unwrap();
175        let mut s = ServerConnection::new(scfg.clone());
176        pump(&mut c, &mut s);
177        assert!(!s.is_handshaking());
178    });
179    println!("{:<44} {:>12.0}", "full, client + server", full);
180    // server side only: replay a fresh ClientHello per iteration and time the server's work
181    let mut server_time = Duration::ZERO;
182    let mut n = 0u32;
183    let t0 = Instant::now();
184    while t0.elapsed() < d {
185        let mut c = ClientConnection::new(cfull.clone(), "localhost").unwrap();
186        let mut s = ServerConnection::new(scfg.clone());
187        let ch = c.tls_output().to_vec();
188        c.consume_tls_output(ch.len());
189        let t = Instant::now();
190        s.read_tls(&ch);
191        s.process_new_packets().unwrap();
192        server_time += t.elapsed();
193        let flight = s.tls_output().to_vec();
194        s.consume_tls_output(flight.len());
195        c.read_tls(&flight);
196        c.process_new_packets().unwrap();
197        let fin = c.tls_output().to_vec();
198        let t = Instant::now();
199        s.read_tls(&fin);
200        s.process_new_packets().unwrap();
201        server_time += t.elapsed();
202        n += 1;
203    }
204    println!("{:<44} {:>12.0}", "full, server side only", n as f64 / server_time.as_secs_f64());
205    // resumption: prime the cache, then each connection uses one ticket and stores a new one
206    let mut c = ClientConnection::new(cres.clone(), "localhost").unwrap();
207    let mut s = ServerConnection::new(scfg.clone());
208    pump(&mut c, &mut s);
209    let resumed = rate(d, || {
210        let mut c = ClientConnection::new(cres.clone(), "localhost").unwrap();
211        let mut s = ServerConnection::new(scfg.clone());
212        pump(&mut c, &mut s);
213        assert!(c.is_resumed());
214    });
215    println!("{:<44} {:>12.0}", "PSK-DHE resumption, client + server", resumed);
216
217    if openssl {
218        println!();
219        println!("openssl speed (same machine, single thread):");
220        for args in [
221            &["speed", "-seconds", "2", "-bytes", "16384", "-evp", "aes-128-gcm"][..],
222            &["speed", "-seconds", "2", "-bytes", "1400", "-evp", "aes-128-gcm"][..],
223            &["speed", "-seconds", "2", "-bytes", "16384", "-evp", "chacha20-poly1305"][..],
224            &["speed", "-seconds", "2", "-bytes", "1400", "-evp", "chacha20-poly1305"][..],
225            &["speed", "-seconds", "2", "ecdhx25519", "ecdhp256", "ecdsap256", "ed25519", "rsa2048"][..],
226        ] {
227            match std::process::Command::new("openssl").args(args).output() {
228                Ok(o) => {
229                    let out = String::from_utf8_lossy(&o.stdout);
230                    for line in out.lines().filter(|l| {
231                        l.starts_with("AES-128-GCM") || l.starts_with("ChaCha20-Poly1305") || l.contains(" sign ") || l.contains("op/s") || l.starts_with("rsa") || l.contains("ecdh") || l.contains("ecdsa") || l.contains("Ed25519") || l.contains("type")
232                    }) {
233                        println!("  {line}");
234                    }
235                }
236                Err(e) => println!("  openssl not available: {e}"),
237            }
238        }
239    }
240}
More examples
Hide additional examples
examples/size_server.rs (line 29)
12fn main() {
13    let args: Vec<String> = std::env::args().collect();
14    if args.len() < 3 {
15        eprintln!("usage: size_server CERT.pem KEY.pem < client_flight");
16        std::process::exit(2);
17    }
18    let cert = std::fs::read(&args[1]).expect("certificate");
19    let key = std::fs::read(&args[2]).expect("key");
20    let cfg = Arc::new(ServerConfig::from_pem(&cert, &key).expect("server config").with_alpn(&[b"h2", b"http/1.1"]));
21    let mut conn = ServerConnection::new(cfg);
22    let mut input = Vec::new();
23    std::io::stdin().read_to_end(&mut input).expect("stdin");
24    conn.read_tls(&input);
25    if let Err(e) = conn.process_new_packets() {
26        eprintln!("{e:?}");
27    }
28    let out = conn.tls_output().to_vec();
29    conn.consume_tls_output(out.len());
30    std::io::stdout().write_all(&out).expect("stdout");
31    let mut buf = [0u8; 1024];
32    let n = conn.read_plaintext(&mut buf);
33    std::io::stdout().write_all(&buf[..n]).expect("stdout");
34}
examples/size_features.rs (line 73)
48fn main() {
49    let args: Vec<String> = std::env::args().collect();
50    if args.len() < 3 {
51        eprintln!("usage: size_features CERT.pem KEY.pem [PASSWORD [KEYSTORE [OCSP.der [CRL]]]] < client_flight");
52        std::process::exit(2);
53    }
54    let cfg = Arc::new(config(&args));
55    #[cfg(feature = "blocking")]
56    if std::env::var("SIZE_FEATURES_LISTEN").is_ok() {
57        let l = std::net::TcpListener::bind("127.0.0.1:0").expect("bind");
58        let (tcp, _) = l.accept().expect("accept");
59        let mut s = simoom_tls::blocking::accept(tcp, cfg).expect("handshake");
60        let mut buf = [0u8; 1024];
61        let n = s.read(&mut buf).expect("read");
62        s.write_all(&buf[..n]).expect("write");
63        return;
64    }
65    let mut conn = ServerConnection::new(cfg);
66    let mut input = Vec::new();
67    std::io::stdin().read_to_end(&mut input).expect("stdin");
68    conn.read_tls(&input);
69    if let Err(e) = conn.process_new_packets() {
70        eprintln!("{e:?}");
71    }
72    let out = conn.tls_output().to_vec();
73    conn.consume_tls_output(out.len());
74    std::io::stdout().write_all(&out).expect("stdout");
75    let mut buf = [0u8; 1024];
76    let n = conn.read_plaintext(&mut buf);
77    std::io::stdout().write_all(&buf[..n]).expect("stdout");
78}
examples/../tests/fuzzing/mod.rs (line 134)
122pub fn corpus() -> Corpus {
123    let ss = certgen::issue(&CertParams::server(&["localhost"]), PrivateKey::generate_ec(EcCurve::P256), None);
124    let mut roots = RootStore::empty();
125    roots.add_der(&ss.cert_der).unwrap();
126    let scfg = Arc::new(ServerConfig::new(CertifiedKey::new(vec![ss.cert_der.clone()], ss.key.clone()).unwrap()).with_alpn(&[b"h3", b"http/1.1"]));
127    let mut cc = ClientConfig::new(roots).with_alpn(&[b"h3", b"http/1.1"]);
128    cc.sessions = None;
129    let ccfg = Arc::new(cc);
130    // a TLS handshake transcript
131    let mut c = ClientConnection::new(ccfg.clone(), "localhost").unwrap();
132    let mut s = ServerConnection::new(scfg.clone());
133    let ch = c.tls_output().to_vec();
134    c.consume_tls_output(ch.len());
135    s.read_tls(&ch);
136    s.process_new_packets().unwrap();
137    let flight = s.tls_output().to_vec();
138    let mut ch_plus = ch.clone();
139    ch_plus.extend_from_slice(&[20, 3, 3, 0, 1, 1, 23, 3, 3, 0, 20]);
140    ch_plus.extend(std::iter::repeat_n(0xaa, 20));
141    // a QUIC handshake: the ClientHello message and the server's Handshake-level flight
142    let mut qc = QuicConnection::new_client(ccfg.clone(), "localhost", vec![1, 2, 3]).unwrap();
143    let mut qs = QuicConnection::new_server(scfg.clone(), vec![4, 5, 6]);
144    let mut ch_msg = Vec::new();
145    qc.write_handshake(&mut ch_msg);
146    qs.read_handshake(Level::Initial, &ch_msg).unwrap();
147    let mut sh = Vec::new();
148    qs.write_handshake(&mut sh);
149    let mut hs = Vec::new();
150    qs.write_handshake(&mut hs);
151    Corpus {
152        scfg,
153        ccfg,
154        to_server: vec![ch, ch_plus],
155        to_client: vec![flight],
156        ch_msg,
157        server_hs_flight: hs,
158        key_der: ss.key_der.clone(),
159        cert_der: ss.cert_der,
160    }
161}
162
163/// Feeds `data` in random-sized pieces and processes after each; checks that errors stick.
164fn feed(rng: &mut Rng, conn: &mut simoom_tls::Connection, data: &[u8]) {
165    let mut off = 0;
166    while off < data.len() {
167        let k = 1 + rng.below(data.len() - off);
168        let taken = conn.read_tls(&data[off..off + k]);
169        off += taken;
170        let r = conn.process_new_packets();
171        if let Err(e) = r {
172            assert_eq!(conn.process_new_packets().unwrap_err(), e, "errors must stick");
173            assert!(conn.tls_output().len() < 64 * 1024, "output stays bounded");
174            assert!(conn.write_plaintext(b"x").is_err(), "a failed connection refuses writes");
175            return;
176        }
177        if taken == 0 {
178            // buffer full: the application reads plaintext
179            let n = conn.plaintext().len();
180            if n == 0 {
181                return;
182            }
183            conn.consume_plaintext(n);
184        }
185    }
186}
187
188pub fn server_records(rng: &mut Rng, c: &Corpus, iters: usize) {
189    for _ in 0..iters {
190        let seed = &c.to_server[rng.below(c.to_server.len())];
191        let data = mutate(rng, seed, &c.to_client);
192        let mut s = ServerConnection::new(c.scfg.clone());
193        feed(rng, &mut s, &data);
194    }
195}
196
197pub fn client_records(rng: &mut Rng, c: &Corpus, iters: usize) {
198    for _ in 0..iters {
199        let data = mutate(rng, &c.to_client[0], &c.to_server);
200        let mut cl = ClientConnection::new(c.ccfg.clone(), "localhost").unwrap();
201        let n = cl.tls_output().len();
202        cl.consume_tls_output(n);
203        feed(rng, &mut cl, &data);
204    }
205}
Source

pub fn write_tls_into(&mut self, out: &mut Vec<u8>) -> usize

Moves all pending TLS output to out.

Source

pub fn write_plaintext(&mut self, data: &[u8]) -> Result<usize>

Encrypts application data. Before the handshake completes the data is buffered (up to 1 MiB) and sent right after it.

Examples found in repository?
examples/../tests/fuzzing/mod.rs (line 174)
164fn feed(rng: &mut Rng, conn: &mut simoom_tls::Connection, data: &[u8]) {
165    let mut off = 0;
166    while off < data.len() {
167        let k = 1 + rng.below(data.len() - off);
168        let taken = conn.read_tls(&data[off..off + k]);
169        off += taken;
170        let r = conn.process_new_packets();
171        if let Err(e) = r {
172            assert_eq!(conn.process_new_packets().unwrap_err(), e, "errors must stick");
173            assert!(conn.tls_output().len() < 64 * 1024, "output stays bounded");
174            assert!(conn.write_plaintext(b"x").is_err(), "a failed connection refuses writes");
175            return;
176        }
177        if taken == 0 {
178            // buffer full: the application reads plaintext
179            let n = conn.plaintext().len();
180            if n == 0 {
181                return;
182            }
183            conn.consume_plaintext(n);
184        }
185    }
186}
Source

pub fn read_plaintext(&mut self, buf: &mut [u8]) -> usize

Copies decrypted application data into buf.

Examples found in repository?
examples/size_server.rs (line 32)
12fn main() {
13    let args: Vec<String> = std::env::args().collect();
14    if args.len() < 3 {
15        eprintln!("usage: size_server CERT.pem KEY.pem < client_flight");
16        std::process::exit(2);
17    }
18    let cert = std::fs::read(&args[1]).expect("certificate");
19    let key = std::fs::read(&args[2]).expect("key");
20    let cfg = Arc::new(ServerConfig::from_pem(&cert, &key).expect("server config").with_alpn(&[b"h2", b"http/1.1"]));
21    let mut conn = ServerConnection::new(cfg);
22    let mut input = Vec::new();
23    std::io::stdin().read_to_end(&mut input).expect("stdin");
24    conn.read_tls(&input);
25    if let Err(e) = conn.process_new_packets() {
26        eprintln!("{e:?}");
27    }
28    let out = conn.tls_output().to_vec();
29    conn.consume_tls_output(out.len());
30    std::io::stdout().write_all(&out).expect("stdout");
31    let mut buf = [0u8; 1024];
32    let n = conn.read_plaintext(&mut buf);
33    std::io::stdout().write_all(&buf[..n]).expect("stdout");
34}
More examples
Hide additional examples
examples/size_features.rs (line 76)
48fn main() {
49    let args: Vec<String> = std::env::args().collect();
50    if args.len() < 3 {
51        eprintln!("usage: size_features CERT.pem KEY.pem [PASSWORD [KEYSTORE [OCSP.der [CRL]]]] < client_flight");
52        std::process::exit(2);
53    }
54    let cfg = Arc::new(config(&args));
55    #[cfg(feature = "blocking")]
56    if std::env::var("SIZE_FEATURES_LISTEN").is_ok() {
57        let l = std::net::TcpListener::bind("127.0.0.1:0").expect("bind");
58        let (tcp, _) = l.accept().expect("accept");
59        let mut s = simoom_tls::blocking::accept(tcp, cfg).expect("handshake");
60        let mut buf = [0u8; 1024];
61        let n = s.read(&mut buf).expect("read");
62        s.write_all(&buf[..n]).expect("write");
63        return;
64    }
65    let mut conn = ServerConnection::new(cfg);
66    let mut input = Vec::new();
67    std::io::stdin().read_to_end(&mut input).expect("stdin");
68    conn.read_tls(&input);
69    if let Err(e) = conn.process_new_packets() {
70        eprintln!("{e:?}");
71    }
72    let out = conn.tls_output().to_vec();
73    conn.consume_tls_output(out.len());
74    std::io::stdout().write_all(&out).expect("stdout");
75    let mut buf = [0u8; 1024];
76    let n = conn.read_plaintext(&mut buf);
77    std::io::stdout().write_all(&buf[..n]).expect("stdout");
78}
Source

pub fn plaintext(&self) -> &[u8] ⓘ

The decrypted application data not yet consumed.

Examples found in repository?
examples/../tests/fuzzing/mod.rs (line 179)
164fn feed(rng: &mut Rng, conn: &mut simoom_tls::Connection, data: &[u8]) {
165    let mut off = 0;
166    while off < data.len() {
167        let k = 1 + rng.below(data.len() - off);
168        let taken = conn.read_tls(&data[off..off + k]);
169        off += taken;
170        let r = conn.process_new_packets();
171        if let Err(e) = r {
172            assert_eq!(conn.process_new_packets().unwrap_err(), e, "errors must stick");
173            assert!(conn.tls_output().len() < 64 * 1024, "output stays bounded");
174            assert!(conn.write_plaintext(b"x").is_err(), "a failed connection refuses writes");
175            return;
176        }
177        if taken == 0 {
178            // buffer full: the application reads plaintext
179            let n = conn.plaintext().len();
180            if n == 0 {
181                return;
182            }
183            conn.consume_plaintext(n);
184        }
185    }
186}
Source

pub fn consume_plaintext(&mut self, n: usize)

Examples found in repository?
examples/../tests/fuzzing/mod.rs (line 183)
164fn feed(rng: &mut Rng, conn: &mut simoom_tls::Connection, data: &[u8]) {
165    let mut off = 0;
166    while off < data.len() {
167        let k = 1 + rng.below(data.len() - off);
168        let taken = conn.read_tls(&data[off..off + k]);
169        off += taken;
170        let r = conn.process_new_packets();
171        if let Err(e) = r {
172            assert_eq!(conn.process_new_packets().unwrap_err(), e, "errors must stick");
173            assert!(conn.tls_output().len() < 64 * 1024, "output stays bounded");
174            assert!(conn.write_plaintext(b"x").is_err(), "a failed connection refuses writes");
175            return;
176        }
177        if taken == 0 {
178            // buffer full: the application reads plaintext
179            let n = conn.plaintext().len();
180            if n == 0 {
181                return;
182            }
183            conn.consume_plaintext(n);
184        }
185    }
186}
Source

pub fn release_buffers(&mut self) -> usize

Frees the capacity of empty buffers (call on idle keep-alive connections). Returns the bytes still held by buffers with pending data.

Source

pub fn send_close_notify(&mut self)

Queues close_notify. Further writes fail with Error::Closed.

Source

pub fn send_key_update(&mut self, request_peer: bool) -> Result<()>

Sends a KeyUpdate and switches to the next write key; request_peer asks the peer to update its keys too.

Source

pub fn is_handshaking(&self) -> bool

Examples found in repository?
examples/bench_tls.rs (line 177)
63fn main() {
64    let openssl = std::env::args().any(|a| a == "--openssl");
65    let d = Duration::from_millis(if std::env::args().any(|a| a == "--quick") { 300 } else { 1500 });
66    println!("simoom-tls benchmarks (single thread), hardware AES: {}, CLMUL: {}, SHA-NI: {}", simoom_sys::arch::has_aes(), simoom_sys::arch::has_clmul(), simoom_sys::arch::has_sha256());
67    println!();
68    println!("{:<34} {:>12} {:>12}", "AEAD seal (encrypt + tag)", "16384 B", "1400 B");
69    let aad = [0u8; 13];
70    let mut buf = vec![0x5au8; 16384];
71    let gcm128 = AesGcm::new(&[1u8; 16]);
72    let gcm256 = AesGcm::new(&[1u8; 32]);
73    let gcm128s = AesGcm::new_soft(&[1u8; 16]);
74    let chacha = ChaCha20Poly1305::new(&[2u8; 32]);
75    let mut seq = 0u64;
76    let mut nonce = || {
77        seq += 1;
78        let mut n = [0u8; 12];
79        n[4..].copy_from_slice(&seq.to_be_bytes());
80        n
81    };
82    let f1 = |n: &[u8; 12], b: &mut [u8]| gcm128.seal(n, &aad, b);
83    let f2 = |n: &[u8; 12], b: &mut [u8]| gcm256.seal(n, &aad, b);
84    let f3 = |n: &[u8; 12], b: &mut [u8]| gcm128s.seal(n, &aad, b);
85    let f4 = |n: &[u8; 12], b: &mut [u8]| chacha.seal(n, &aad, b);
86    let algs: [(&str, &dyn Fn(&[u8; 12], &mut [u8]) -> [u8; 16]); 4] =
87        [("AES-128-GCM", &f1), ("AES-256-GCM", &f2), ("AES-128-GCM (portable, bitsliced)", &f3), ("ChaCha20-Poly1305", &f4)];
88    for (name, f) in algs {
89        let size_d = if name.contains("portable") { d / 3 } else { d };
90        let a = rate(size_d, || {
91            black_box(f(&nonce(), &mut buf));
92        });
93        let b = rate(size_d, || {
94            black_box(f(&nonce(), &mut buf[..1400]));
95        });
96        println!("{:<34} {:>9.2} GB/s {:>7.2} GB/s", name, gbps(a, 16384), gbps(b, 1400));
97    }
98    let mut tag = [0u8; 16];
99    let n12 = [0u8; 12];
100    tag.copy_from_slice(&gcm128.seal(&n12, &aad, &mut buf));
101    let o = rate(d, || {
102        // open fails (buffer changed) but does the full work: GHASH, CTR, tag compare
103        black_box(gcm128.open(&n12, &aad, &mut buf, &tag));
104    });
105    println!("{:<34} {:>9.2} GB/s", "AES-128-GCM open", gbps(o, 16384));
106
107    println!();
108    println!("{:<34} {:>12}", "Primitive", "ops/s");
109    let sk = [7u8; 32];
110    let pk = x25519::x25519_base(&[9u8; 32]);
111    println!("{:<34} {:>12.0}", "X25519 key generation (table)", rate(d, || {
112        black_box(x25519::x25519_base(black_box(&sk)));
113    }));
114    println!("{:<34} {:>12.0}", "X25519 shared secret (ladder)", rate(d, || {
115        black_box(x25519::x25519(black_box(&sk), &pk));
116    }));
117    let d256 = p256::generate_private();
118    let q256 = p256::public_key(&p256::generate_private()).unwrap();
119    let h = [3u8; 32];
120    println!("{:<34} {:>12.0}", "P-256 key generation", rate(d, || {
121        black_box(p256::public_key(black_box(&d256)));
122    }));
123    println!("{:<34} {:>12.0}", "P-256 ECDH", rate(d, || {
124        black_box(p256::ecdh(black_box(&d256), &q256));
125    }));
126    let (r, s) = p256::sign(&d256, &h, simoom_tls::crypto::sha2::HashAlg::Sha256).unwrap();
127    let pub256 = p256::public_key(&d256).unwrap();
128    println!("{:<34} {:>12.0}", "ECDSA P-256 sign", rate(d, || {
129        black_box(p256::sign(black_box(&d256), &h, simoom_tls::crypto::sha2::HashAlg::Sha256));
130    }));
131    println!("{:<34} {:>12.0}", "ECDSA P-256 verify", rate(d, || {
132        black_box(p256::verify(&pub256, &h, &r, &s));
133    }));
134    let seed = [5u8; 32];
135    let edpub = simoom_tls::crypto::ed25519::public_key(&seed);
136    // as the server signs: the key's public half is known (OpenSSL keeps it in the key too)
137    println!("{:<34} {:>12.0}", "Ed25519 sign", rate(d, || {
138        black_box(simoom_tls::crypto::ed25519::sign_with_public(&seed, &edpub, b"message"));
139    }));
140    let edsig = simoom_tls::crypto::ed25519::sign(&seed, b"message");
141    println!("{:<34} {:>12.0}", "Ed25519 verify", rate(d, || {
142        black_box(simoom_tls::crypto::ed25519::verify(&edpub, b"message", &edsig));
143    }));
144    let rsa = PrivateKey::from_pem(include_bytes!("../testdata/rsa2048.pkcs1.pem")).unwrap();
145    if let PrivateKey::Rsa(k) = &rsa {
146        let dg = [1u8; 32];
147        println!("{:<34} {:>12.0}", "RSA-2048 PSS sign", rate(d, || {
148            black_box(k.sign_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg));
149        }));
150        let sig = k.sign_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg).unwrap();
151        println!("{:<34} {:>12.0}", "RSA-2048 PSS verify", rate(d, || {
152            black_box(k.public.verify_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg, &sig, Some(32)));
153        }));
154    }
155
156    // handshakes
157    let ss = certgen::issue(&CertParams::server(&["localhost"]), PrivateKey::generate_ec(EcCurve::P256), None);
158    let mut roots = RootStore::empty();
159    roots.add_der(&ss.cert_der).unwrap();
160    let mut scfg = ServerConfig::new(CertifiedKey::new(vec![ss.cert_der.clone()], ss.key.clone()).unwrap());
161    scfg.groups = vec![NamedGroup::X25519];
162    let scfg = Arc::new(scfg);
163    let mut cfull = ClientConfig::new(roots.clone());
164    cfull.sessions = None;
165    cfull.groups = vec![NamedGroup::X25519];
166    let cfull = Arc::new(cfull);
167    let mut cres = ClientConfig::new(roots);
168    cres.groups = vec![NamedGroup::X25519];
169    let cres = Arc::new(cres);
170
171    println!();
172    println!("{:<44} {:>12}", "TLS 1.3 handshake (X25519, ECDSA P-256 cert)", "per second");
173    let full = rate(d, || {
174        let mut c = ClientConnection::new(cfull.clone(), "localhost").unwrap();
175        let mut s = ServerConnection::new(scfg.clone());
176        pump(&mut c, &mut s);
177        assert!(!s.is_handshaking());
178    });
179    println!("{:<44} {:>12.0}", "full, client + server", full);
180    // server side only: replay a fresh ClientHello per iteration and time the server's work
181    let mut server_time = Duration::ZERO;
182    let mut n = 0u32;
183    let t0 = Instant::now();
184    while t0.elapsed() < d {
185        let mut c = ClientConnection::new(cfull.clone(), "localhost").unwrap();
186        let mut s = ServerConnection::new(scfg.clone());
187        let ch = c.tls_output().to_vec();
188        c.consume_tls_output(ch.len());
189        let t = Instant::now();
190        s.read_tls(&ch);
191        s.process_new_packets().unwrap();
192        server_time += t.elapsed();
193        let flight = s.tls_output().to_vec();
194        s.consume_tls_output(flight.len());
195        c.read_tls(&flight);
196        c.process_new_packets().unwrap();
197        let fin = c.tls_output().to_vec();
198        let t = Instant::now();
199        s.read_tls(&fin);
200        s.process_new_packets().unwrap();
201        server_time += t.elapsed();
202        n += 1;
203    }
204    println!("{:<44} {:>12.0}", "full, server side only", n as f64 / server_time.as_secs_f64());
205    // resumption: prime the cache, then each connection uses one ticket and stores a new one
206    let mut c = ClientConnection::new(cres.clone(), "localhost").unwrap();
207    let mut s = ServerConnection::new(scfg.clone());
208    pump(&mut c, &mut s);
209    let resumed = rate(d, || {
210        let mut c = ClientConnection::new(cres.clone(), "localhost").unwrap();
211        let mut s = ServerConnection::new(scfg.clone());
212        pump(&mut c, &mut s);
213        assert!(c.is_resumed());
214    });
215    println!("{:<44} {:>12.0}", "PSK-DHE resumption, client + server", resumed);
216
217    if openssl {
218        println!();
219        println!("openssl speed (same machine, single thread):");
220        for args in [
221            &["speed", "-seconds", "2", "-bytes", "16384", "-evp", "aes-128-gcm"][..],
222            &["speed", "-seconds", "2", "-bytes", "1400", "-evp", "aes-128-gcm"][..],
223            &["speed", "-seconds", "2", "-bytes", "16384", "-evp", "chacha20-poly1305"][..],
224            &["speed", "-seconds", "2", "-bytes", "1400", "-evp", "chacha20-poly1305"][..],
225            &["speed", "-seconds", "2", "ecdhx25519", "ecdhp256", "ecdsap256", "ed25519", "rsa2048"][..],
226        ] {
227            match std::process::Command::new("openssl").args(args).output() {
228                Ok(o) => {
229                    let out = String::from_utf8_lossy(&o.stdout);
230                    for line in out.lines().filter(|l| {
231                        l.starts_with("AES-128-GCM") || l.starts_with("ChaCha20-Poly1305") || l.contains(" sign ") || l.contains("op/s") || l.starts_with("rsa") || l.contains("ecdh") || l.contains("ecdsa") || l.contains("Ed25519") || l.contains("type")
232                    }) {
233                        println!("  {line}");
234                    }
235                }
236                Err(e) => println!("  openssl not available: {e}"),
237            }
238        }
239    }
240}
Source

pub fn alpn_protocol(&self) -> Option<&[u8]>

Source

pub fn negotiated_cipher_suite(&self) -> Option<CipherSuite>

The TLS 1.3 cipher suite (None for TLS 1.2: see negotiated_tls12_suite and Connection::cipher_suite_name).

Source

pub fn cipher_suite_name(&self) -> Option<&'static str>

The IANA name of the negotiated cipher suite, for either version.

Source

pub fn protocol_version(&self) -> Option<ProtocolVersion>

The negotiated protocol version (None during the handshake).

Source

pub fn negotiated_group(&self) -> Option<NamedGroup>

Source

pub fn server_name(&self) -> Option<&str>

Server: the SNI name sent by the client. Client: the name, if the server acknowledged it.

Source

pub fn peer_certificates(&self) -> &[Vec<u8>]

The peer’s certificate chain, leaf first (restored from the ticket on resumption).

Source

pub fn is_resumed(&self) -> bool

Examples found in repository?
examples/bench_tls.rs (line 213)
63fn main() {
64    let openssl = std::env::args().any(|a| a == "--openssl");
65    let d = Duration::from_millis(if std::env::args().any(|a| a == "--quick") { 300 } else { 1500 });
66    println!("simoom-tls benchmarks (single thread), hardware AES: {}, CLMUL: {}, SHA-NI: {}", simoom_sys::arch::has_aes(), simoom_sys::arch::has_clmul(), simoom_sys::arch::has_sha256());
67    println!();
68    println!("{:<34} {:>12} {:>12}", "AEAD seal (encrypt + tag)", "16384 B", "1400 B");
69    let aad = [0u8; 13];
70    let mut buf = vec![0x5au8; 16384];
71    let gcm128 = AesGcm::new(&[1u8; 16]);
72    let gcm256 = AesGcm::new(&[1u8; 32]);
73    let gcm128s = AesGcm::new_soft(&[1u8; 16]);
74    let chacha = ChaCha20Poly1305::new(&[2u8; 32]);
75    let mut seq = 0u64;
76    let mut nonce = || {
77        seq += 1;
78        let mut n = [0u8; 12];
79        n[4..].copy_from_slice(&seq.to_be_bytes());
80        n
81    };
82    let f1 = |n: &[u8; 12], b: &mut [u8]| gcm128.seal(n, &aad, b);
83    let f2 = |n: &[u8; 12], b: &mut [u8]| gcm256.seal(n, &aad, b);
84    let f3 = |n: &[u8; 12], b: &mut [u8]| gcm128s.seal(n, &aad, b);
85    let f4 = |n: &[u8; 12], b: &mut [u8]| chacha.seal(n, &aad, b);
86    let algs: [(&str, &dyn Fn(&[u8; 12], &mut [u8]) -> [u8; 16]); 4] =
87        [("AES-128-GCM", &f1), ("AES-256-GCM", &f2), ("AES-128-GCM (portable, bitsliced)", &f3), ("ChaCha20-Poly1305", &f4)];
88    for (name, f) in algs {
89        let size_d = if name.contains("portable") { d / 3 } else { d };
90        let a = rate(size_d, || {
91            black_box(f(&nonce(), &mut buf));
92        });
93        let b = rate(size_d, || {
94            black_box(f(&nonce(), &mut buf[..1400]));
95        });
96        println!("{:<34} {:>9.2} GB/s {:>7.2} GB/s", name, gbps(a, 16384), gbps(b, 1400));
97    }
98    let mut tag = [0u8; 16];
99    let n12 = [0u8; 12];
100    tag.copy_from_slice(&gcm128.seal(&n12, &aad, &mut buf));
101    let o = rate(d, || {
102        // open fails (buffer changed) but does the full work: GHASH, CTR, tag compare
103        black_box(gcm128.open(&n12, &aad, &mut buf, &tag));
104    });
105    println!("{:<34} {:>9.2} GB/s", "AES-128-GCM open", gbps(o, 16384));
106
107    println!();
108    println!("{:<34} {:>12}", "Primitive", "ops/s");
109    let sk = [7u8; 32];
110    let pk = x25519::x25519_base(&[9u8; 32]);
111    println!("{:<34} {:>12.0}", "X25519 key generation (table)", rate(d, || {
112        black_box(x25519::x25519_base(black_box(&sk)));
113    }));
114    println!("{:<34} {:>12.0}", "X25519 shared secret (ladder)", rate(d, || {
115        black_box(x25519::x25519(black_box(&sk), &pk));
116    }));
117    let d256 = p256::generate_private();
118    let q256 = p256::public_key(&p256::generate_private()).unwrap();
119    let h = [3u8; 32];
120    println!("{:<34} {:>12.0}", "P-256 key generation", rate(d, || {
121        black_box(p256::public_key(black_box(&d256)));
122    }));
123    println!("{:<34} {:>12.0}", "P-256 ECDH", rate(d, || {
124        black_box(p256::ecdh(black_box(&d256), &q256));
125    }));
126    let (r, s) = p256::sign(&d256, &h, simoom_tls::crypto::sha2::HashAlg::Sha256).unwrap();
127    let pub256 = p256::public_key(&d256).unwrap();
128    println!("{:<34} {:>12.0}", "ECDSA P-256 sign", rate(d, || {
129        black_box(p256::sign(black_box(&d256), &h, simoom_tls::crypto::sha2::HashAlg::Sha256));
130    }));
131    println!("{:<34} {:>12.0}", "ECDSA P-256 verify", rate(d, || {
132        black_box(p256::verify(&pub256, &h, &r, &s));
133    }));
134    let seed = [5u8; 32];
135    let edpub = simoom_tls::crypto::ed25519::public_key(&seed);
136    // as the server signs: the key's public half is known (OpenSSL keeps it in the key too)
137    println!("{:<34} {:>12.0}", "Ed25519 sign", rate(d, || {
138        black_box(simoom_tls::crypto::ed25519::sign_with_public(&seed, &edpub, b"message"));
139    }));
140    let edsig = simoom_tls::crypto::ed25519::sign(&seed, b"message");
141    println!("{:<34} {:>12.0}", "Ed25519 verify", rate(d, || {
142        black_box(simoom_tls::crypto::ed25519::verify(&edpub, b"message", &edsig));
143    }));
144    let rsa = PrivateKey::from_pem(include_bytes!("../testdata/rsa2048.pkcs1.pem")).unwrap();
145    if let PrivateKey::Rsa(k) = &rsa {
146        let dg = [1u8; 32];
147        println!("{:<34} {:>12.0}", "RSA-2048 PSS sign", rate(d, || {
148            black_box(k.sign_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg));
149        }));
150        let sig = k.sign_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg).unwrap();
151        println!("{:<34} {:>12.0}", "RSA-2048 PSS verify", rate(d, || {
152            black_box(k.public.verify_pss(simoom_tls::crypto::sha2::HashAlg::Sha256, &dg, &sig, Some(32)));
153        }));
154    }
155
156    // handshakes
157    let ss = certgen::issue(&CertParams::server(&["localhost"]), PrivateKey::generate_ec(EcCurve::P256), None);
158    let mut roots = RootStore::empty();
159    roots.add_der(&ss.cert_der).unwrap();
160    let mut scfg = ServerConfig::new(CertifiedKey::new(vec![ss.cert_der.clone()], ss.key.clone()).unwrap());
161    scfg.groups = vec![NamedGroup::X25519];
162    let scfg = Arc::new(scfg);
163    let mut cfull = ClientConfig::new(roots.clone());
164    cfull.sessions = None;
165    cfull.groups = vec![NamedGroup::X25519];
166    let cfull = Arc::new(cfull);
167    let mut cres = ClientConfig::new(roots);
168    cres.groups = vec![NamedGroup::X25519];
169    let cres = Arc::new(cres);
170
171    println!();
172    println!("{:<44} {:>12}", "TLS 1.3 handshake (X25519, ECDSA P-256 cert)", "per second");
173    let full = rate(d, || {
174        let mut c = ClientConnection::new(cfull.clone(), "localhost").unwrap();
175        let mut s = ServerConnection::new(scfg.clone());
176        pump(&mut c, &mut s);
177        assert!(!s.is_handshaking());
178    });
179    println!("{:<44} {:>12.0}", "full, client + server", full);
180    // server side only: replay a fresh ClientHello per iteration and time the server's work
181    let mut server_time = Duration::ZERO;
182    let mut n = 0u32;
183    let t0 = Instant::now();
184    while t0.elapsed() < d {
185        let mut c = ClientConnection::new(cfull.clone(), "localhost").unwrap();
186        let mut s = ServerConnection::new(scfg.clone());
187        let ch = c.tls_output().to_vec();
188        c.consume_tls_output(ch.len());
189        let t = Instant::now();
190        s.read_tls(&ch);
191        s.process_new_packets().unwrap();
192        server_time += t.elapsed();
193        let flight = s.tls_output().to_vec();
194        s.consume_tls_output(flight.len());
195        c.read_tls(&flight);
196        c.process_new_packets().unwrap();
197        let fin = c.tls_output().to_vec();
198        let t = Instant::now();
199        s.read_tls(&fin);
200        s.process_new_packets().unwrap();
201        server_time += t.elapsed();
202        n += 1;
203    }
204    println!("{:<44} {:>12.0}", "full, server side only", n as f64 / server_time.as_secs_f64());
205    // resumption: prime the cache, then each connection uses one ticket and stores a new one
206    let mut c = ClientConnection::new(cres.clone(), "localhost").unwrap();
207    let mut s = ServerConnection::new(scfg.clone());
208    pump(&mut c, &mut s);
209    let resumed = rate(d, || {
210        let mut c = ClientConnection::new(cres.clone(), "localhost").unwrap();
211        let mut s = ServerConnection::new(scfg.clone());
212        pump(&mut c, &mut s);
213        assert!(c.is_resumed());
214    });
215    println!("{:<44} {:>12.0}", "PSK-DHE resumption, client + server", resumed);
216
217    if openssl {
218        println!();
219        println!("openssl speed (same machine, single thread):");
220        for args in [
221            &["speed", "-seconds", "2", "-bytes", "16384", "-evp", "aes-128-gcm"][..],
222            &["speed", "-seconds", "2", "-bytes", "1400", "-evp", "aes-128-gcm"][..],
223            &["speed", "-seconds", "2", "-bytes", "16384", "-evp", "chacha20-poly1305"][..],
224            &["speed", "-seconds", "2", "-bytes", "1400", "-evp", "chacha20-poly1305"][..],
225            &["speed", "-seconds", "2", "ecdhx25519", "ecdhp256", "ecdsap256", "ed25519", "rsa2048"][..],
226        ] {
227            match std::process::Command::new("openssl").args(args).output() {
228                Ok(o) => {
229                    let out = String::from_utf8_lossy(&o.stdout);
230                    for line in out.lines().filter(|l| {
231                        l.starts_with("AES-128-GCM") || l.starts_with("ChaCha20-Poly1305") || l.contains(" sign ") || l.contains("op/s") || l.starts_with("rsa") || l.contains("ecdh") || l.contains("ecdsa") || l.contains("Ed25519") || l.contains("type")
232                    }) {
233                        println!("  {line}");
234                    }
235                }
236                Err(e) => println!("  openssl not available: {e}"),
237            }
238        }
239    }
240}
Source

pub fn peer_has_closed(&self) -> bool

Source

pub fn error(&self) -> Option<&Error>

The error that ended the connection, if any.

Source

pub fn export_keying_material( &self, label: &[u8], context: &[u8], len: usize, ) -> Result<Vec<u8>>

RFC 8446 section 7.5 keying material exporter. With TLS 1.2 this is RFC 5705, where an empty context means no context.

Trait Implementations§

Source§

impl Debug for ClientConnection

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Deref for ClientConnection

Available on crate feature client only.
Source§

type Target = Connection

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Connection

Dereferences the value.
Source§

impl DerefMut for ClientConnection

Available on crate feature client only.
Source§

fn deref_mut(&mut self) -> &mut Connection

Mutably dereferences the value.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.