Skip to main content

RootStore

Struct RootStore 

Source
pub struct RootStore { /* private fields */ }
Expand description

A set of trust anchors.

Implementations§

Source§

impl RootStore

Source

pub fn empty() -> RootStore

Examples found in repository?
examples/../tests/fuzzing/mod.rs (line 124)
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}
206
207/// ClientHello parsing (and everything the server does with it) without the record layer.
208pub fn quic_server_messages(rng: &mut Rng, c: &Corpus, iters: usize) {
209    for _ in 0..iters {
210        let m = mutate(rng, &c.ch_msg, &[]);
211        let mut s = QuicConnection::new_server(c.scfg.clone(), vec![9]);
212        if s.read_handshake(Level::Initial, &m).is_err() {
213            assert!(s.tls_alert().is_some());
214        }
215        let mut out = Vec::new();
216        while s.write_handshake(&mut out).is_some() {}
217    }
218}
219
220/// EncryptedExtensions, Certificate (X.509), CertificateVerify and Finished parsing on the
221/// client: a real ServerHello, then a mutated Handshake-level flight.
222pub fn quic_client_messages(rng: &mut Rng, c: &Corpus, iters: usize) {
223    for _ in 0..iters {
224        let mut qc = QuicConnection::new_client(c.ccfg.clone(), "localhost", vec![1]).unwrap();
225        let mut qs = QuicConnection::new_server(c.scfg.clone(), vec![2]);
226        let mut ch = Vec::new();
227        qc.write_handshake(&mut ch);
228        qs.read_handshake(Level::Initial, &ch).unwrap();
229        let mut sh = Vec::new();
230        qs.write_handshake(&mut sh);
231        let mut hs = Vec::new();
232        qs.write_handshake(&mut hs);
233        qc.read_handshake(Level::Initial, &sh).unwrap();
234        let mut ignore = Vec::new();
235        qc.write_handshake(&mut ignore);
236        let m = mutate(rng, &hs, &[c.cert_der.clone()]);
237        let _ = qc.read_handshake(Level::Handshake, &m);
238    }
239}
240
241pub fn x509_and_keys(rng: &mut Rng, c: &Corpus, iters: usize) {
242    let mut roots = RootStore::empty();
243    roots.add_der(&c.cert_der).unwrap();
244    for _ in 0..iters {
245        let d = mutate(rng, &c.cert_der, &[]);
246        if let Ok(cert) = Certificate::from_der(&d) {
247            let _ = cert.matches_hostname("localhost");
248        }
249        let _ = x509::verify_chain(&[d], Some("localhost"), &roots, 1_800_000_000, x509::OID_EKU_SERVER_AUTH);
250        let k = mutate(rng, &c.key_der, &[]);
251        let _ = PrivateKey::from_der(&k);
252        let pem = simoom_tls::pem::encode_pem("PRIVATE KEY", &k);
253        let p = mutate(rng, pem.as_bytes(), &[]);
254        let _ = PrivateKey::from_pem(&p);
255    }
256}
More examples
Hide additional examples
examples/bench_tls.rs (line 158)
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 system() -> RootStore

The system trust store (SSL_CERT_FILE, else the first existing bundle in SYSTEM_BUNDLE_PATHS, else the Windows ROOT certificate store; macOS is covered by /etc/ssl/cert.pem); loaded once per process. Certificates that fail to parse are skipped.

Source

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

Adds every certificate in PEM text; fails if any block is malformed or none found.

Source

pub fn add_pem_file(&mut self, path: impl AsRef<Path>) -> Result<usize, String>

Source

pub fn add_der(&mut self, der: &[u8]) -> Result<(), String>

Examples found in repository?
examples/../tests/fuzzing/mod.rs (line 125)
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}
206
207/// ClientHello parsing (and everything the server does with it) without the record layer.
208pub fn quic_server_messages(rng: &mut Rng, c: &Corpus, iters: usize) {
209    for _ in 0..iters {
210        let m = mutate(rng, &c.ch_msg, &[]);
211        let mut s = QuicConnection::new_server(c.scfg.clone(), vec![9]);
212        if s.read_handshake(Level::Initial, &m).is_err() {
213            assert!(s.tls_alert().is_some());
214        }
215        let mut out = Vec::new();
216        while s.write_handshake(&mut out).is_some() {}
217    }
218}
219
220/// EncryptedExtensions, Certificate (X.509), CertificateVerify and Finished parsing on the
221/// client: a real ServerHello, then a mutated Handshake-level flight.
222pub fn quic_client_messages(rng: &mut Rng, c: &Corpus, iters: usize) {
223    for _ in 0..iters {
224        let mut qc = QuicConnection::new_client(c.ccfg.clone(), "localhost", vec![1]).unwrap();
225        let mut qs = QuicConnection::new_server(c.scfg.clone(), vec![2]);
226        let mut ch = Vec::new();
227        qc.write_handshake(&mut ch);
228        qs.read_handshake(Level::Initial, &ch).unwrap();
229        let mut sh = Vec::new();
230        qs.write_handshake(&mut sh);
231        let mut hs = Vec::new();
232        qs.write_handshake(&mut hs);
233        qc.read_handshake(Level::Initial, &sh).unwrap();
234        let mut ignore = Vec::new();
235        qc.write_handshake(&mut ignore);
236        let m = mutate(rng, &hs, &[c.cert_der.clone()]);
237        let _ = qc.read_handshake(Level::Handshake, &m);
238    }
239}
240
241pub fn x509_and_keys(rng: &mut Rng, c: &Corpus, iters: usize) {
242    let mut roots = RootStore::empty();
243    roots.add_der(&c.cert_der).unwrap();
244    for _ in 0..iters {
245        let d = mutate(rng, &c.cert_der, &[]);
246        if let Ok(cert) = Certificate::from_der(&d) {
247            let _ = cert.matches_hostname("localhost");
248        }
249        let _ = x509::verify_chain(&[d], Some("localhost"), &roots, 1_800_000_000, x509::OID_EKU_SERVER_AUTH);
250        let k = mutate(rng, &c.key_der, &[]);
251        let _ = PrivateKey::from_der(&k);
252        let pem = simoom_tls::pem::encode_pem("PRIVATE KEY", &k);
253        let p = mutate(rng, pem.as_bytes(), &[]);
254        let _ = PrivateKey::from_pem(&p);
255    }
256}
More examples
Hide additional examples
examples/bench_tls.rs (line 159)
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 len(&self) -> usize

Source

pub fn is_empty(&self) -> bool

Source

pub fn extend(&mut self, other: &RootStore)

Source

pub fn certificates(&self) -> impl Iterator<Item = &Certificate>

The trust anchors.

Trait Implementations§

Source§

impl Clone for RootStore

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for RootStore

Source§

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

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

impl Default for RootStore

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.