Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/rust/src/tls_version.rs
Line
Count
Source
1
use std::borrow::Cow;
2
use std::ffi::c_char;
3
use std::ptr;
4
5
/* Max string length of the TLS version string */
6
pub const SSL_VERSION_MAX_STRLEN: usize = 20;
7
8
// Enum as constants for C ABI
9
pub const TLS_VERSION_UNKNOWN: u16 = 0x0000;
10
pub const SSL_VERSION_2: u16 = 0x0200;
11
pub const SSL_VERSION_3: u16 = 0x0300;
12
pub const TLS_VERSION_10: u16 = 0x0301;
13
pub const TLS_VERSION_11: u16 = 0x0302;
14
pub const TLS_VERSION_12: u16 = 0x0303;
15
pub const TLS_VERSION_13: u16 = 0x0304;
16
pub const TLS_VERSION_13_DRAFT28: u16 = 0x7f1c;
17
pub const TLS_VERSION_13_DRAFT27: u16 = 0x7f1b;
18
pub const TLS_VERSION_13_DRAFT26: u16 = 0x7f1a;
19
pub const TLS_VERSION_13_DRAFT25: u16 = 0x7f19;
20
pub const TLS_VERSION_13_DRAFT24: u16 = 0x7f18;
21
pub const TLS_VERSION_13_DRAFT23: u16 = 0x7f17;
22
pub const TLS_VERSION_13_DRAFT22: u16 = 0x7f16;
23
pub const TLS_VERSION_13_DRAFT21: u16 = 0x7f15;
24
pub const TLS_VERSION_13_DRAFT20: u16 = 0x7f14;
25
pub const TLS_VERSION_13_DRAFT19: u16 = 0x7f13;
26
pub const TLS_VERSION_13_DRAFT18: u16 = 0x7f12;
27
pub const TLS_VERSION_13_DRAFT17: u16 = 0x7f11;
28
pub const TLS_VERSION_13_DRAFT16: u16 = 0x7f10;
29
pub const TLS_VERSION_13_PRE_DRAFT16: u16 = 0x7f01;
30
pub const TLS_VERSION_13_DRAFT20_FB: u16 = 0xfb14;
31
pub const TLS_VERSION_13_DRAFT21_FB: u16 = 0xfb15;
32
pub const TLS_VERSION_13_DRAFT22_FB: u16 = 0xfb16;
33
pub const TLS_VERSION_13_DRAFT23_FB: u16 = 0xfb17;
34
pub const TLS_VERSION_13_DRAFT26_FB: u16 = 0xfb1a;
35
36
/* SSL versions.  We'll use a unified format for all, with the top byte
37
 * holding the major version and the lower byte the minor version */
38
#[repr(u16)]
39
#[derive(Default)]
40
pub enum SCTlsVersion {
41
    #[default]
42
    Unknown = TLS_VERSION_UNKNOWN,
43
    SslV2 = SSL_VERSION_2,
44
    SslV3 = SSL_VERSION_3,
45
    TlsV1_0 = TLS_VERSION_10,
46
    TlsV1_1 = TLS_VERSION_11,
47
    TlsV1_2 = TLS_VERSION_12,
48
    TlsV1_3 = TLS_VERSION_13,
49
    Tls13Draft28 = TLS_VERSION_13_DRAFT28,
50
    Tls13Draft27 = TLS_VERSION_13_DRAFT27,
51
    Tls13Draft26 = TLS_VERSION_13_DRAFT26,
52
    Tls13Draft25 = TLS_VERSION_13_DRAFT25,
53
    Tls13Draft24 = TLS_VERSION_13_DRAFT24,
54
    Tls13Draft23 = TLS_VERSION_13_DRAFT23,
55
    Tls13Draft22 = TLS_VERSION_13_DRAFT22,
56
    Tls13Draft21 = TLS_VERSION_13_DRAFT21,
57
    Tls13Draft20 = TLS_VERSION_13_DRAFT20,
58
    Tls13Draft19 = TLS_VERSION_13_DRAFT19,
59
    Tls13Draft18 = TLS_VERSION_13_DRAFT18,
60
    Tls13Draft17 = TLS_VERSION_13_DRAFT17,
61
    Tls13Draft16 = TLS_VERSION_13_DRAFT16,
62
    Tls13PreDraft16 = TLS_VERSION_13_PRE_DRAFT16,
63
    Tls13Draft20Fb = TLS_VERSION_13_DRAFT20_FB,
64
    Tls13Draft21Fb = TLS_VERSION_13_DRAFT21_FB,
65
    Tls13Draft22Fb = TLS_VERSION_13_DRAFT22_FB,
66
    Tls13Draft23Fb = TLS_VERSION_13_DRAFT23_FB,
67
    Tls13Draft26Fb = TLS_VERSION_13_DRAFT26_FB,
68
}
69
70
impl TryFrom<u16> for SCTlsVersion {
71
    type Error = ();
72
73
99.8k
    fn try_from(v: u16) -> Result<Self, Self::Error> {
74
99.8k
        match v {
75
1.42k
            0x0000 => Ok(Self::Unknown),
76
185
            0x0200 => Ok(Self::SslV2),
77
5.30k
            0x0300 => Ok(Self::SslV3),
78
27.9k
            0x0301 => Ok(Self::TlsV1_0),
79
13.6k
            0x0302 => Ok(Self::TlsV1_1),
80
498
            0x0303 => Ok(Self::TlsV1_2),
81
100
            0x0304 => Ok(Self::TlsV1_3),
82
221
            0x7f1c => Ok(Self::Tls13Draft28),
83
426
            0x7f1b => Ok(Self::Tls13Draft27),
84
258
            0x7f1a => Ok(Self::Tls13Draft26),
85
217
            0x7f19 => Ok(Self::Tls13Draft25),
86
1.26k
            0x7f18 => Ok(Self::Tls13Draft24),
87
391
            0x7f17 => Ok(Self::Tls13Draft23),
88
208
            0x7f16 => Ok(Self::Tls13Draft22),
89
194
            0x7f15 => Ok(Self::Tls13Draft21),
90
195
            0x7f14 => Ok(Self::Tls13Draft20),
91
512
            0x7f13 => Ok(Self::Tls13Draft19),
92
198
            0x7f12 => Ok(Self::Tls13Draft18),
93
244
            0x7f11 => Ok(Self::Tls13Draft17),
94
205
            0x7f10 => Ok(Self::Tls13Draft16),
95
579
            0x7f01 => Ok(Self::Tls13PreDraft16),
96
35.8k
            0xfb14 => Ok(Self::Tls13Draft20Fb),
97
251
            0xfb15 => Ok(Self::Tls13Draft21Fb),
98
368
            0xfb16 => Ok(Self::Tls13Draft22Fb),
99
280
            0xfb17 => Ok(Self::Tls13Draft23Fb),
100
246
            0xfb1a => Ok(Self::Tls13Draft26Fb),
101
8.58k
            _ => Err(()),
102
        }
103
99.8k
    }
104
}
105
106
impl SCTlsVersion {
107
236
    pub fn as_str(&self) -> &'static str {
108
236
        match self {
109
93
            Self::Unknown => "UNDETERMINED",
110
116
            Self::SslV2 => "SSLv2",
111
0
            Self::SslV3 => "SSLv3",
112
2
            Self::TlsV1_0 => "TLSv1",
113
0
            Self::TlsV1_1 => "TLS 1.1",
114
23
            Self::TlsV1_2 => "TLS 1.2",
115
1
            Self::TlsV1_3 => "TLS 1.3",
116
0
            Self::Tls13Draft28 => "TLS 1.3 draft-28",
117
0
            Self::Tls13Draft27 => "TLS 1.3 draft-27",
118
0
            Self::Tls13Draft26 => "TLS 1.3 draft-26",
119
0
            Self::Tls13Draft25 => "TLS 1.3 draft-25",
120
0
            Self::Tls13Draft24 => "TLS 1.3 draft-24",
121
0
            Self::Tls13Draft23 => "TLS 1.3 draft-23",
122
0
            Self::Tls13Draft22 => "TLS 1.3 draft-22",
123
0
            Self::Tls13Draft21 => "TLS 1.3 draft-21",
124
0
            Self::Tls13Draft20 => "TLS 1.3 draft-20",
125
0
            Self::Tls13Draft19 => "TLS 1.3 draft-19",
126
0
            Self::Tls13Draft18 => "TLS 1.3 draft-18",
127
0
            Self::Tls13Draft17 => "TLS 1.3 draft-17",
128
0
            Self::Tls13Draft16 => "TLS 1.3 draft-16",
129
1
            Self::Tls13PreDraft16 => "TLS 1.3 draft-<16",
130
0
            Self::Tls13Draft20Fb => "TLS 1.3 draft-20-fb",
131
0
            Self::Tls13Draft21Fb => "TLS 1.3 draft-21-fb",
132
0
            Self::Tls13Draft22Fb => "TLS 1.3 draft-22-fb",
133
0
            Self::Tls13Draft23Fb => "TLS 1.3 draft-23-fb",
134
0
            Self::Tls13Draft26Fb => "TLS 1.3 draft-26-fb",
135
        }
136
236
    }
137
138
99.4k
    fn is_valid(v: u16) -> bool {
139
99.4k
        match Self::try_from(v) {
140
1.33k
            Ok(SCTlsVersion::Unknown) => false,
141
69
            Ok(SCTlsVersion::SslV2) => false,
142
8.47k
            Err(_) => false,
143
89.5k
            _ => true,
144
        }
145
99.4k
    }
146
}
147
148
#[no_mangle]
149
99.4k
pub unsafe extern "C" fn TLSVersionValid(v: u16) -> bool {
150
99.4k
    SCTlsVersion::is_valid(v)
151
99.4k
}
152
153
#[no_mangle]
154
340
pub unsafe extern "C" fn SSLVersionToString(v: u16, buf: *mut c_char) -> bool {
155
340
    let vers = match SCTlsVersion::try_from(v) {
156
236
        Ok(val) => Cow::Borrowed(val.as_str()),
157
104
        Err(_) => Cow::Owned(v.to_string()),
158
    };
159
340
    let b = vers.as_bytes();
160
161
340
    if b.len() > SSL_VERSION_MAX_STRLEN {
162
0
        return false;
163
340
    }
164
165
340
    ptr::write_bytes(buf, 0, b.len());
166
340
    std::ptr::copy_nonoverlapping(b.as_ptr() as *const c_char, buf, b.len());
167
340
    *buf.add(b.len()) = 0;
168
340
    true
169
340
}
170
171
#[cfg(test)]
172
mod tests {
173
    use super::*;
174
175
    #[test]
176
    fn test_valid_versions() {
177
        assert!(SCTlsVersion::is_valid(SSL_VERSION_3));
178
        assert!(SCTlsVersion::is_valid(TLS_VERSION_10));
179
        assert!(SCTlsVersion::is_valid(TLS_VERSION_11));
180
        assert!(SCTlsVersion::is_valid(TLS_VERSION_12));
181
        assert!(SCTlsVersion::is_valid(TLS_VERSION_13_DRAFT16));
182
    }
183
184
    #[test]
185
    fn test_invalid_versions() {
186
        assert!(!SCTlsVersion::is_valid(TLS_VERSION_UNKNOWN));
187
        assert!(!SCTlsVersion::is_valid(SSL_VERSION_2));
188
    }
189
190
    // Out-of-range ie unknown currently
191
    #[test]
192
    fn test_oor_versions() {
193
        assert!(!SCTlsVersion::is_valid(0xffff));
194
        assert!(!SCTlsVersion::is_valid(0xfffe));
195
    }
196
}