File: benchmark.rs

package info (click to toggle)
rust-rustls-webpki 0.103.4-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental, sid
  • size: 10,632 kB
  • sloc: python: 2,278; sh: 61; makefile: 12
file content (241 lines) | stat: -rw-r--r-- 9,664 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#![allow(clippy::incompatible_msrv)]

use bencher::{Bencher, benchmark_group, benchmark_main};
use once_cell::sync::Lazy;
use rcgen::{
    BasicConstraints, CertificateParams, CertificateRevocationListParams, CertifiedKey, IsCa,
    KeyIdMethod, KeyPair, KeyUsagePurpose, PKCS_ECDSA_P256_SHA256, RevocationReason,
    RevokedCertParams, SerialNumber, date_time_ymd,
};

use pki_types::CertificateRevocationListDer;
use std::fs::File;
use std::hint::black_box;
use std::io::{ErrorKind, Read, Write};
use std::path::Path;
use std::sync::Mutex;

use webpki::{BorrowedCertRevocationList, CertRevocationList, OwnedCertRevocationList};

/// Lazy initialized CRL issuer to be used when generating CRL data. Includes
/// `KeyUsagePurpose::CrlSign` key usage bit.
static CRL_ISSUER: Lazy<Mutex<CertifiedKey>> = Lazy::new(|| {
    let mut issuer_params =
        CertificateParams::new(vec!["crl.issuer.example.com".to_string()]).unwrap();
    issuer_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
    issuer_params.key_usages = vec![
        KeyUsagePurpose::KeyCertSign,
        KeyUsagePurpose::DigitalSignature,
        KeyUsagePurpose::CrlSign,
    ];
    let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap();
    let cert = issuer_params.self_signed(&key_pair).unwrap();
    Mutex::new(CertifiedKey { cert, key_pair })
});

/// Number of revoked certificates to include in the small benchmark CRL. Produces a CRL roughly
/// ~72kb in size when serialized to disk.
const SMALL_CRL_CERT_COUNT: usize = 2_000;
/// Number of revoked certificates to include in the medium benchmark CRL. Produces a CRL roughly
/// ~22mb in size when serialized to disk.
const MEDIUM_CRL_CERT_COUNT: usize = 600_000;
/// Number of revoked certificates to include in the large benchmark CRL. Produces a CRL roughly
/// ~50mb in size when serialized to disk.
const LARGE_CRL_CERT_COUNT: usize = 1_500_000;

/// A fake serial number to use in the search tests. In order to provoke a full scan of the CRL
/// contents this serial should **not** appear in the revoked certificates.
const FAKE_SERIAL: &[u8] = &[0xC0, 0xFF, 0xEE];

/// Try to load a DER bytes from `crl_path`. If that file path does not exist, generate a CRL
/// with `revoked_count` revoked certificates, write the DER encoding to `crl_path` and return the
/// newly created DER bytes.
fn load_or_generate(
    crl_path: impl AsRef<Path> + Copy,
    revoked_count: usize,
) -> CertificateRevocationListDer<'static> {
    match File::open(crl_path) {
        Ok(mut crl_file) => {
            let mut crl_der = Vec::new();
            crl_file.read_to_end(&mut crl_der).unwrap();
            crl_der.into()
        }
        Err(e) => match e.kind() {
            ErrorKind::NotFound => match File::create(crl_path) {
                Err(e) => panic!("unexpected err creating CRL file: {e:?}"),
                Ok(mut crl_file) => {
                    let new_crl = generate_crl(revoked_count);
                    crl_file.write_all(&new_crl).unwrap();
                    new_crl
                }
            },
            e => {
                panic!("unexpected err opening CRL file: {e:?}");
            }
        },
    }
}

/// Create a new benchmark CRL with `revoked_count` revoked certificates.
fn generate_crl(revoked_count: usize) -> CertificateRevocationListDer<'static> {
    let mut revoked_certs = Vec::with_capacity(revoked_count);
    (0..revoked_count).for_each(|i| {
        revoked_certs.push(RevokedCertParams {
            serial_number: SerialNumber::from((i + 1) as u64),
            revocation_time: date_time_ymd(2024, 6, 17),
            reason_code: Some(RevocationReason::KeyCompromise),
            invalidity_date: None,
        });
    });

    let crl = CertificateRevocationListParams {
        this_update: date_time_ymd(2023, 6, 17),
        next_update: date_time_ymd(2024, 6, 17),
        crl_number: SerialNumber::from(1234),
        key_identifier_method: KeyIdMethod::Sha256,
        issuing_distribution_point: None,
        revoked_certs,
    };
    let issuer = CRL_ISSUER.lock().unwrap();
    crl.signed_by(&issuer.cert, &issuer.key_pair)
        .unwrap()
        .into()
}

/// Benchmark parsing a small CRL file into a borrowed representation.
fn bench_parse_borrowed_crl_small(c: &mut Bencher) {
    let crl_bytes = load_or_generate("./benches/small.crl.der", SMALL_CRL_CERT_COUNT);

    c.iter(|| BorrowedCertRevocationList::from_der(&crl_bytes).unwrap());
}

/// Benchmark parsing a small CRL file into an owned representation.
fn bench_parse_owned_crl_small(c: &mut Bencher) {
    let crl_bytes = load_or_generate("./benches/small.crl.der", SMALL_CRL_CERT_COUNT);

    c.iter(|| OwnedCertRevocationList::from_der(&crl_bytes).unwrap());
}

/// Benchmark parsing a medium CRL file into a borrowed representation..
fn bench_parse_borrowed_crl_medium(c: &mut Bencher) {
    let crl_bytes = load_or_generate("./benches/medium.crl.der", MEDIUM_CRL_CERT_COUNT);

    c.iter(|| BorrowedCertRevocationList::from_der(&crl_bytes).unwrap());
}

/// Benchmark parsing a medium CRL file into an owned representation..
fn bench_parse_owned_crl_medium(c: &mut Bencher) {
    let crl_bytes = load_or_generate("./benches/medium.crl.der", MEDIUM_CRL_CERT_COUNT);

    c.iter(|| OwnedCertRevocationList::from_der(&crl_bytes).unwrap());
}

/// Benchmark parsing a large CRL file into a borrowed representation..
fn bench_parse_borrowed_crl_large(c: &mut Bencher) {
    let crl_bytes = load_or_generate("./benches/large.crl.der", LARGE_CRL_CERT_COUNT);

    c.iter(|| BorrowedCertRevocationList::from_der(&crl_bytes).unwrap());
}

/// Benchmark parsing a large CRL file into an owned representation..
fn bench_parse_owned_crl_large(c: &mut Bencher) {
    let crl_bytes = load_or_generate("./benches/large.crl.der", LARGE_CRL_CERT_COUNT);

    c.iter(|| BorrowedCertRevocationList::from_der(&crl_bytes).unwrap());
}

/// Benchmark searching a small CRL file in borrowed representation for a serial that does not
/// appear. Doesn't include the time it takes to parse the CRL in the benchmark task.
fn bench_search_borrowed_crl_small(c: &mut Bencher) {
    let crl_bytes = load_or_generate("./benches/small.crl.der", SMALL_CRL_CERT_COUNT);
    let crl: CertRevocationList = BorrowedCertRevocationList::from_der(&crl_bytes)
        .unwrap()
        .into();

    c.iter(|| {
        assert!(matches!(black_box(crl.find_serial(FAKE_SERIAL)), Ok(None)));
    });
}

/// Benchmark searching a small CRL file in owned representation for a serial that does not
/// appear. Doesn't include the time it takes to parse the CRL in the benchmark task.
fn bench_search_owned_crl_small(c: &mut Bencher) {
    let crl_bytes = load_or_generate("./benches/small.crl.der", SMALL_CRL_CERT_COUNT);
    let crl: CertRevocationList = OwnedCertRevocationList::from_der(&crl_bytes)
        .unwrap()
        .into();

    c.iter(|| {
        assert!(matches!(black_box(crl.find_serial(FAKE_SERIAL)), Ok(None)));
    });
}

/// Benchmark searching a medium CRL file in borrowed representation for a serial that does not
/// appear. Doesn't include the time it takes to parse the CRL in the benchmark task.
fn bench_search_borrowed_crl_medium(c: &mut Bencher) {
    let crl_bytes = load_or_generate("./benches/medium.crl.der", MEDIUM_CRL_CERT_COUNT);
    let crl: CertRevocationList = BorrowedCertRevocationList::from_der(&crl_bytes)
        .unwrap()
        .into();

    c.iter(|| {
        assert!(matches!(black_box(crl.find_serial(FAKE_SERIAL)), Ok(None)));
    });
}

/// Benchmark searching a medium CRL file in owned representation for a serial that does not
/// appear. Doesn't include the time it takes to parse the CRL in the benchmark task.
fn bench_search_owned_crl_medium(c: &mut Bencher) {
    let crl_bytes = load_or_generate("./benches/medium.crl.der", MEDIUM_CRL_CERT_COUNT);
    let crl: CertRevocationList = OwnedCertRevocationList::from_der(&crl_bytes)
        .unwrap()
        .into();

    c.iter(|| {
        assert!(matches!(black_box(crl.find_serial(FAKE_SERIAL)), Ok(None)));
    });
}

/// Benchmark searching a large CRL file in borrowed representation for a serial that does not
/// appear. Doesn't include the time it takes to parse the CRL in the benchmark task.
fn bench_search_borrowed_crl_large(c: &mut Bencher) {
    let crl_bytes = load_or_generate("./benches/large.crl.der", LARGE_CRL_CERT_COUNT);
    let crl: CertRevocationList = BorrowedCertRevocationList::from_der(&crl_bytes)
        .unwrap()
        .into();

    c.iter(|| {
        assert!(matches!(black_box(crl.find_serial(FAKE_SERIAL)), Ok(None)));
    });
}

/// Benchmark searching a large CRL file in owned representation for a serial that does not
/// appear. Doesn't include the time it takes to parse the CRL in the benchmark task.
fn bench_search_owned_crl_large(c: &mut Bencher) {
    let crl_bytes = load_or_generate("./benches/large.crl.der", LARGE_CRL_CERT_COUNT);
    let crl: CertRevocationList = OwnedCertRevocationList::from_der(&crl_bytes)
        .unwrap()
        .into();

    c.iter(|| {
        assert!(matches!(black_box(crl.find_serial(FAKE_SERIAL)), Ok(None)));
    });
}

benchmark_group!(
    crl_benches,
    bench_parse_borrowed_crl_small,
    bench_parse_owned_crl_small,
    bench_parse_borrowed_crl_medium,
    bench_parse_owned_crl_medium,
    bench_parse_borrowed_crl_large,
    bench_parse_owned_crl_large,
    bench_search_borrowed_crl_small,
    bench_search_owned_crl_small,
    bench_search_borrowed_crl_medium,
    bench_search_owned_crl_medium,
    bench_search_borrowed_crl_large,
    bench_search_owned_crl_large,
);

benchmark_main!(crl_benches);