suricata
detect-ssl-version.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2025 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Gurvinder Singh <gurvindersinghdahiya@gmail.com>
22  *
23  * Implements the ssl_version keyword
24  */
25 
26 #include "suricata-common.h"
27 #include "threads.h"
28 #include "decode.h"
29 
30 #include "detect.h"
31 #include "detect-parse.h"
32 
33 #include "detect-engine.h"
34 #include "detect-engine-mpm.h"
35 #include "detect-engine-state.h"
36 
37 #include "flow.h"
38 #include "flow-var.h"
39 #include "flow-util.h"
40 
41 #include "util-debug.h"
42 #include "util-unittest.h"
43 #include "util-unittest-helper.h"
44 
45 #include "app-layer.h"
46 #include "app-layer-parser.h"
47 
48 #include "detect-ssl-version.h"
49 
50 #include "stream-tcp.h"
51 #include "app-layer-ssl.h"
52 
53 static int DetectSslVersionMatch(DetectEngineThreadCtx *,
54  Flow *, uint8_t, void *, void *,
55  const Signature *, const SigMatchCtx *);
56 static int DetectSslVersionSetup(DetectEngineCtx *, Signature *, const char *);
57 #ifdef UNITTESTS
58 static void DetectSslVersionRegisterTests(void);
59 #endif
60 static void DetectSslVersionFree(DetectEngineCtx *, void *);
61 static int g_tls_generic_list_id = 0;
62 
63 /**
64  * \brief Registration function for keyword: ssl_version
65  */
67 {
68  sigmatch_table[DETECT_SSL_VERSION].name = "ssl_version";
69  sigmatch_table[DETECT_SSL_VERSION].desc = "match version of SSL/TLS record";
70  sigmatch_table[DETECT_SSL_VERSION].url = "/rules/tls-keywords.html#ssl-version";
71  sigmatch_table[DETECT_SSL_VERSION].AppLayerTxMatch = DetectSslVersionMatch;
72  sigmatch_table[DETECT_SSL_VERSION].Setup = DetectSslVersionSetup;
73  sigmatch_table[DETECT_SSL_VERSION].Free = DetectSslVersionFree;
74 #ifdef UNITTESTS
75  sigmatch_table[DETECT_SSL_VERSION].RegisterTests = DetectSslVersionRegisterTests;
76 #endif
77 
78  g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic");
79 }
80 
81 /**
82  * \brief match the specified version on a ssl session
83  *
84  * \param t pointer to thread vars
85  * \param det_ctx pointer to the pattern matcher thread
86  * \param p pointer to the current packet
87  * \param m pointer to the sigmatch that we will cast into DetectSslVersionData
88  *
89  * \retval 0 no match
90  * \retval 1 match
91  */
92 static int DetectSslVersionMatch(DetectEngineThreadCtx *det_ctx,
93  Flow *f, uint8_t flags, void *state, void *txv,
94  const Signature *s, const SigMatchCtx *m)
95 {
96  SCEnter();
97 
98  int ret = 0;
99  uint16_t ver = 0;
100  bool sig_ver = false;
101 
102  const DetectSslVersionData *ssl = (const DetectSslVersionData *)m;
103  const SSLState *app_state = (SSLState *)state;
104  if (app_state == NULL) {
105  SCLogDebug("no app state, no match");
106  SCReturnInt(0);
107  }
108 
109  if (flags & STREAM_TOCLIENT) {
110  SCLogDebug("server (toclient) version is 0x%02X",
111  app_state->server_connp.version);
112  ver = app_state->server_connp.version;
113  } else if (flags & STREAM_TOSERVER) {
114  SCLogDebug("client (toserver) version is 0x%02X",
115  app_state->client_connp.version);
116  ver = app_state->client_connp.version;
117  }
118 
119  switch (ver) {
120  case SSL_VERSION_2:
121  if (ssl->data[SSLv2])
122  ret = 1;
123  sig_ver = true;
124  break;
125  case SSL_VERSION_3:
126  if (ssl->data[SSLv3])
127  ret = 1;
128  sig_ver = true;
129  break;
130  case TLS_VERSION_10:
131  if (ssl->data[TLS10])
132  ret = 1;
133  sig_ver = true;
134  break;
135  case TLS_VERSION_11:
136  if (ssl->data[TLS11])
137  ret = 1;
138  sig_ver = true;
139  break;
140  case TLS_VERSION_12:
141  if (ssl->data[TLS12])
142  ret = 1;
143  sig_ver = true;
144  break;
145  case TLS_VERSION_13_DRAFT28:
146  case TLS_VERSION_13_DRAFT27:
147  case TLS_VERSION_13_DRAFT26:
148  case TLS_VERSION_13_DRAFT25:
149  case TLS_VERSION_13_DRAFT24:
150  case TLS_VERSION_13_DRAFT23:
151  case TLS_VERSION_13_DRAFT22:
152  case TLS_VERSION_13_DRAFT21:
153  case TLS_VERSION_13_DRAFT20:
154  case TLS_VERSION_13_DRAFT19:
155  case TLS_VERSION_13_DRAFT18:
156  case TLS_VERSION_13_DRAFT17:
157  case TLS_VERSION_13_DRAFT16:
158  case TLS_VERSION_13_PRE_DRAFT16:
159  case TLS_VERSION_13:
160  if (ssl->data[TLS13])
161  ret = 1;
162  sig_ver = true;
163  break;
164  }
165 
166  if (!sig_ver)
167  SCReturnInt(0);
168 
169  // matches if ret == 1 and negate is false
170  // or if ret == 0 and negate is true
171  SCReturnInt(ret ^ (ssl->negate ? 1 : 0));
172 }
173 
175  const char *word;
176  int index;
177 };
178 
180  { "sslv2", SSLv2 },
181  { "sslv3", SSLv3 },
182  { "tls1.0", TLS10 },
183  { "tls1.1", TLS11 },
184  { "tls1.2", TLS12 },
185  { "tls1.3", TLS13 },
186 };
187 
188 /**
189  * \brief This function is used to parse ssl_version data passed via
190  * keyword: "ssl_version"
191  *
192  * \param de_ctx Pointer to the detection engine context
193  * \param str Pointer to the user provided options
194  *
195  * \retval ssl pointer to DetectSslVersionData on success
196  * \retval NULL on failure
197  */
198 static DetectSslVersionData *DetectSslVersionParse(DetectEngineCtx *de_ctx, const char *str)
199 {
200  const char *tmp_str = str;
201  size_t tmp_len = 0;
202 
203  /* We have a correct ssl_version options */
205  if (unlikely(ssl == NULL))
206  goto error;
207 
208  // skip leading space
209  while (tmp_str[0] != 0 && isspace(tmp_str[0])) {
210  tmp_str++;
211  }
212  if (tmp_str[0] == 0) {
213  SCLogError("Invalid empty value");
214  goto error;
215  }
216  if (tmp_str[0] == '!') {
217  ssl->negate = true;
218  tmp_str++;
219  }
220  // iterate every version separated by comma
221  while (tmp_str[0] != 0) {
222  // counts word length
223  tmp_len = 0;
224  while (tmp_str[tmp_len] != 0 && !isspace(tmp_str[tmp_len]) && tmp_str[tmp_len] != ',') {
225  tmp_len++;
226  }
227 
228  bool is_keyword = false;
229  for (size_t i = 0; i < TLS_SIZE; i++) {
230  if (tmp_len == strlen(ssl_version_keywords[i].word) &&
231  strncasecmp(ssl_version_keywords[i].word, tmp_str, tmp_len) == 0) {
232  if (ssl->data[ssl_version_keywords[i].index]) {
233  SCLogError("Invalid duplicate value");
234  goto error;
235  }
236  ssl->data[ssl_version_keywords[i].index] = true;
237  is_keyword = true;
238  break;
239  }
240  }
241  if (!is_keyword) {
242  SCLogError("Invalid unknown value");
243  goto error;
244  }
245 
246  tmp_str += tmp_len;
247  while (isspace(tmp_str[0]) || tmp_str[0] == ',') {
248  tmp_str++;
249  }
250  }
251 
252  return ssl;
253 
254 error:
255  if (ssl != NULL)
256  DetectSslVersionFree(de_ctx, ssl);
257  return NULL;
258 }
259 
260 /**
261  * \brief this function is used to add the parsed "id" option
262  * \brief into the current signature
263  *
264  * \param de_ctx pointer to the Detection Engine Context
265  * \param s pointer to the Current Signature
266  * \param idstr pointer to the user provided "id" option
267  *
268  * \retval 0 on Success
269  * \retval -1 on Failure
270  */
271 static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
272 {
274  return -1;
275 
276  DetectSslVersionData *ssl = DetectSslVersionParse(de_ctx, str);
277  if (ssl == NULL)
278  return -1;
279 
280  /* Okay so far so good, lets get this into a SigMatch
281  * and put it in the Signature. */
282 
284  de_ctx, s, DETECT_SSL_VERSION, (SigMatchCtx *)ssl, g_tls_generic_list_id) == NULL) {
285  DetectSslVersionFree(de_ctx, ssl);
286  return -1;
287  }
288 
289  return 0;
290 }
291 
292 /**
293  * \brief this function will free memory associated with DetectSslVersionData
294  *
295  * \param id_d pointer to DetectSslVersionData
296  */
297 void DetectSslVersionFree(DetectEngineCtx *de_ctx, void *ptr)
298 {
299  if (ptr != NULL)
300  SCFree(ptr);
301 }
302 
303 #ifdef UNITTESTS
305 #endif
SigTableElmt_::url
const char * url
Definition: detect.h:1461
SSLState_
SSLv[2.0|3.[0|1|2|3]] state structure.
Definition: app-layer-ssl.h:236
detect-engine.h
TLS11
@ TLS11
Definition: detect-ssl-version.h:32
SigTableElmt_::desc
const char * desc
Definition: detect.h:1460
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
SSLv3
@ SSLv3
Definition: detect-ssl-version.h:30
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1445
flow-util.h
SigTableElmt_::name
const char * name
Definition: detect.h:1458
stream-tcp.h
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SSLState_::client_connp
SSLStateConnp client_connp
Definition: app-layer-ssl.h:257
ALPROTO_TLS
@ ALPROTO_TLS
Definition: app-layer-protos.h:39
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
SSLState_::server_connp
SSLStateConnp server_connp
Definition: app-layer-ssl.h:258
threads.h
Flow_
Flow data structure.
Definition: flow.h:347
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:933
SigTableElmt_::AppLayerTxMatch
int(* AppLayerTxMatch)(DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, void *txv, const Signature *, const SigMatchCtx *)
Definition: detect.h:1423
DetectSslVersionData_::negate
bool negate
Definition: detect-ssl-version.h:41
SSLVersionKeywords::word
const char * word
Definition: detect-ssl-version.c:175
SSLVersionKeywords
Definition: detect-ssl-version.c:174
m
SCMutex m
Definition: flow-hash.h:6
detect-ssl-version.c
SCDetectSignatureSetAppProto
int SCDetectSignatureSetAppProto(Signature *s, AppProto alproto)
Definition: detect-parse.c:2236
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1440
util-unittest.h
util-unittest-helper.h
SSLVersionKeywords::index
int index
Definition: detect-ssl-version.c:176
decode.h
util-debug.h
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:19
TLS10
@ TLS10
Definition: detect-ssl-version.h:31
DetectEngineThreadCtx_
Definition: detect.h:1245
SCEnter
#define SCEnter(...)
Definition: util-debug.h:284
detect-engine-mpm.h
SSLv2
@ SSLv2
Definition: detect-ssl-version.h:29
SCSigMatchAppendSMToList
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:388
detect.h
DetectSslVersionData_
Definition: detect-ssl-version.h:39
app-layer-parser.h
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
ssl_version_keywords
struct SSLVersionKeywords ssl_version_keywords[TLS_SIZE]
Definition: detect-ssl-version.c:179
detect-ssl-version.h
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:351
DetectBufferTypeRegister
int DetectBufferTypeRegister(const char *name)
Definition: detect-engine.c:1214
flags
uint8_t flags
Definition: decode-gre.h:0
suricata-common.h
DETECT_SSL_VERSION
@ DETECT_SSL_VERSION
Definition: detect-engine-register.h:200
TLS13
@ TLS13
Definition: detect-ssl-version.h:34
str
#define str(s)
Definition: suricata-common.h:308
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
SCFree
#define SCFree(p)
Definition: util-mem.h:61
detect-parse.h
Signature_
Signature container.
Definition: detect.h:668
TLS12
@ TLS12
Definition: detect-ssl-version.h:33
DetectSslVersionRegister
void DetectSslVersionRegister(void)
Registration function for keyword: ssl_version.
Definition: detect-ssl-version.c:66
flow.h
DetectSslVersionData_::data
bool data[TLS_SIZE]
Definition: detect-ssl-version.h:43
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:288
flow-var.h
app-layer-ssl.h
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1447
app-layer.h
TLS_SIZE
@ TLS_SIZE
Definition: detect-ssl-version.h:36
SSLStateConnp_::version
uint16_t version
Definition: app-layer-ssl.h:181