pub struct ClientConnection(/* private fields */);Expand description
A TLS 1.3 client connection. The ClientHello is queued at construction.
Implementations§
Source§impl ClientConnection
impl ClientConnection
Sourcepub fn new(
cfg: Arc<ClientConfig>,
server_name: &str,
) -> Result<ClientConnection>
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?
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
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}Sourcepub fn into_inner(self) -> Connection
pub fn into_inner(self) -> Connection
The underlying connection (for example to call Connection::export_traffic_secrets).
Methods from Deref<Target = Connection>§
Sourcepub fn read_tls(&mut self, data: &[u8]) -> usize
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?
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
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}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}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}Sourcepub fn process_new_packets(&mut self) -> Result<IoState>
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?
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
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}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}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}Sourcepub fn wants_write(&self) -> bool
pub fn wants_write(&self) -> bool
True if TLS bytes are waiting to be sent.
Examples found in repository?
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}Sourcepub fn tls_output(&self) -> &[u8] ⓘ
pub fn tls_output(&self) -> &[u8] ⓘ
The TLS bytes waiting to be sent.
Examples found in repository?
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
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}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}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}Sourcepub fn consume_tls_output(&mut self, n: usize)
pub fn consume_tls_output(&mut self, n: usize)
Marks n bytes of tls_output as sent.
Examples found in repository?
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
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}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}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}Sourcepub fn write_tls_into(&mut self, out: &mut Vec<u8>) -> usize
pub fn write_tls_into(&mut self, out: &mut Vec<u8>) -> usize
Moves all pending TLS output to out.
Sourcepub fn write_plaintext(&mut self, data: &[u8]) -> Result<usize>
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?
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}Sourcepub fn read_plaintext(&mut self, buf: &mut [u8]) -> usize
pub fn read_plaintext(&mut self, buf: &mut [u8]) -> usize
Copies decrypted application data into buf.
Examples found in repository?
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
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}Sourcepub fn plaintext(&self) -> &[u8] ⓘ
pub fn plaintext(&self) -> &[u8] ⓘ
The decrypted application data not yet consumed.
Examples found in repository?
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}Sourcepub fn consume_plaintext(&mut self, n: usize)
pub fn consume_plaintext(&mut self, n: usize)
Examples found in repository?
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}Sourcepub fn release_buffers(&mut self) -> usize
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.
Sourcepub fn send_close_notify(&mut self)
pub fn send_close_notify(&mut self)
Queues close_notify. Further writes fail with Error::Closed.
Sourcepub fn send_key_update(&mut self, request_peer: bool) -> Result<()>
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.
Sourcepub fn is_handshaking(&self) -> bool
pub fn is_handshaking(&self) -> bool
Examples found in repository?
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}pub fn alpn_protocol(&self) -> Option<&[u8]>
Sourcepub fn negotiated_cipher_suite(&self) -> Option<CipherSuite>
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).
Sourcepub fn cipher_suite_name(&self) -> Option<&'static str>
pub fn cipher_suite_name(&self) -> Option<&'static str>
The IANA name of the negotiated cipher suite, for either version.
Sourcepub fn protocol_version(&self) -> Option<ProtocolVersion>
pub fn protocol_version(&self) -> Option<ProtocolVersion>
The negotiated protocol version (None during the handshake).
pub fn negotiated_group(&self) -> Option<NamedGroup>
Sourcepub fn server_name(&self) -> Option<&str>
pub fn server_name(&self) -> Option<&str>
Server: the SNI name sent by the client. Client: the name, if the server acknowledged it.
Sourcepub fn peer_certificates(&self) -> &[Vec<u8>]
pub fn peer_certificates(&self) -> &[Vec<u8>]
The peer’s certificate chain, leaf first (restored from the ticket on resumption).
Sourcepub fn is_resumed(&self) -> bool
pub fn is_resumed(&self) -> bool
Examples found in repository?
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}pub fn peer_has_closed(&self) -> bool
Trait Implementations§
Source§impl Debug for ClientConnection
impl Debug for ClientConnection
Source§impl Deref for ClientConnection
Available on crate feature client only.
impl Deref for ClientConnection
client only.Source§type Target = Connection
type Target = Connection
Source§fn deref(&self) -> &Connection
fn deref(&self) -> &Connection
Source§impl DerefMut for ClientConnection
Available on crate feature client only.
impl DerefMut for ClientConnection
client only.