Coverage Report

Created: 2026-05-18 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/git/checkouts/nss-rs-71e20fe79ef91440/9b94ca3/src/replay.rs
Line
Count
Source
1
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4
// option. This file may not be copied, modified, or distributed
5
// except according to those terms.
6
7
use std::{
8
    os::raw::c_uint,
9
    ptr::null_mut,
10
    time::{Duration, Instant},
11
};
12
13
use crate::{
14
    err::Res,
15
    prio::PRFileDesc,
16
    time::{Interval, PRTime, Time},
17
};
18
19
// This is an opaque struct in NSS.
20
pub enum SSLAntiReplayContext {}
21
22
experimental_api!(SSL_CreateAntiReplayContext(
23
    now: PRTime,
24
    window: PRTime,
25
    k: c_uint,
26
    bits: c_uint,
27
    ctx: *mut *mut SSLAntiReplayContext,
28
));
29
experimental_api!(SSL_ReleaseAntiReplayContext(ctx: *mut SSLAntiReplayContext));
30
experimental_api!(SSL_SetAntiReplayContext(
31
    fd: *mut PRFileDesc,
32
    ctx: *mut SSLAntiReplayContext,
33
));
34
35
scoped_ptr!(
36
    AntiReplayContext,
37
    SSLAntiReplayContext,
38
    SSL_ReleaseAntiReplayContext
39
);
40
41
/// `AntiReplay` is used by servers when processing 0-RTT handshakes.
42
///
43
/// It limits the exposure of servers to replay attack by rejecting 0-RTT
44
/// if it appears to be a replay.  There is a false-positive rate that can be
45
/// managed by tuning the parameters used to create the context.
46
pub struct AntiReplay {
47
    ctx: AntiReplayContext,
48
}
49
50
impl AntiReplay {
51
    /// Make a new anti-replay context.
52
    /// See the documentation in NSS for advice on how to set these values.
53
    ///
54
    /// # Errors
55
    ///
56
    /// Returns an error if `now` is in the past relative to our baseline or
57
    /// NSS is unable to generate an anti-replay context.
58
1.28k
    pub fn new(now: Instant, window: Duration, k: usize, bits: usize) -> Res<Self> {
59
1.28k
        let mut ctx: *mut SSLAntiReplayContext = null_mut();
60
        unsafe {
61
1.28k
            SSL_CreateAntiReplayContext(
62
1.28k
                Time::from(now).try_into()?,
63
1.28k
                Interval::from(window).try_into()?,
64
1.28k
                c_uint::try_from(k)?,
65
1.28k
                c_uint::try_from(bits)?,
66
1.28k
                &raw mut ctx,
67
            )
68
0
        }?;
69
70
        Ok(Self {
71
1.28k
            ctx: AntiReplayContext::from_ptr(ctx)?,
72
        })
73
1.28k
    }
74
75
    /// Configure the provided socket with this anti-replay context.
76
1.28k
    pub(crate) fn config_socket(&self, fd: *mut PRFileDesc) -> Res<()> {
77
1.28k
        unsafe { SSL_SetAntiReplayContext(fd, *self.ctx) }
78
1.28k
    }
79
}
80
81
#[cfg(test)]
82
#[cfg_attr(coverage_nightly, coverage(off))]
83
mod tests {
84
    use std::time::Duration;
85
86
    #[test]
87
    fn creation() {
88
        test_fixture::fixture_init();
89
        for (k, bits, expected) in [(7, 8, true), (usize::MAX, 3, false), (1, usize::MAX, false)] {
90
            let res = crate::AntiReplay::new(test_fixture::now(), Duration::from_secs(10), k, bits);
91
            assert_eq!(res.is_ok(), expected);
92
        }
93
    }
94
}