suricata
detect-ssl-version.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2020 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 detect-ssl-version.c
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 
54 static int DetectSslVersionMatch(DetectEngineThreadCtx *,
55  Flow *, uint8_t, void *, void *,
56  const Signature *, const SigMatchCtx *);
57 static int DetectSslVersionSetup(DetectEngineCtx *, Signature *, const char *);
58 #ifdef UNITTESTS
59 static void DetectSslVersionRegisterTests(void);
60 #endif
61 static void DetectSslVersionFree(DetectEngineCtx *, void *);
62 static int g_tls_generic_list_id = 0;
63 
64 /**
65  * \brief Registration function for keyword: ssl_version
66  */
68 {
69  sigmatch_table[DETECT_SSL_VERSION].name = "ssl_version";
70  sigmatch_table[DETECT_SSL_VERSION].desc = "match version of SSL/TLS record";
71  sigmatch_table[DETECT_SSL_VERSION].url = "/rules/tls-keywords.html#ssl-version";
72  sigmatch_table[DETECT_SSL_VERSION].AppLayerTxMatch = DetectSslVersionMatch;
73  sigmatch_table[DETECT_SSL_VERSION].Setup = DetectSslVersionSetup;
74  sigmatch_table[DETECT_SSL_VERSION].Free = DetectSslVersionFree;
75 #ifdef UNITTESTS
76  sigmatch_table[DETECT_SSL_VERSION].RegisterTests = DetectSslVersionRegisterTests;
77 #endif
78 
79  g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic");
80 }
81 
82 /**
83  * \brief match the specified version on a ssl session
84  *
85  * \param t pointer to thread vars
86  * \param det_ctx pointer to the pattern matcher thread
87  * \param p pointer to the current packet
88  * \param m pointer to the sigmatch that we will cast into DetectSslVersionData
89  *
90  * \retval 0 no match
91  * \retval 1 match
92  */
93 static int DetectSslVersionMatch(DetectEngineThreadCtx *det_ctx,
94  Flow *f, uint8_t flags, void *state, void *txv,
95  const Signature *s, const SigMatchCtx *m)
96 {
97  SCEnter();
98 
99  int ret = 0;
100  uint16_t ver = 0;
101  bool sig_ver = false;
102 
103  const DetectSslVersionData *ssl = (const DetectSslVersionData *)m;
104  SSLState *app_state = (SSLState *)state;
105  if (app_state == NULL) {
106  SCLogDebug("no app state, no match");
107  SCReturnInt(0);
108  }
109 
110  if (flags & STREAM_TOCLIENT) {
111  SCLogDebug("server (toclient) version is 0x%02X",
112  app_state->server_connp.version);
113  ver = app_state->server_connp.version;
114  } else if (flags & STREAM_TOSERVER) {
115  SCLogDebug("client (toserver) version is 0x%02X",
116  app_state->client_connp.version);
117  ver = app_state->client_connp.version;
118  }
119 
120  switch (ver) {
121  case SSL_VERSION_2:
122  if (ssl->data[SSLv2])
123  ret = 1;
124  sig_ver = true;
125  break;
126  case SSL_VERSION_3:
127  if (ssl->data[SSLv3])
128  ret = 1;
129  sig_ver = true;
130  break;
131  case TLS_VERSION_10:
132  if (ssl->data[TLS10])
133  ret = 1;
134  sig_ver = true;
135  break;
136  case TLS_VERSION_11:
137  if (ssl->data[TLS11])
138  ret = 1;
139  sig_ver = true;
140  break;
141  case TLS_VERSION_12:
142  if (ssl->data[TLS12])
143  ret = 1;
144  sig_ver = true;
145  break;
146  case TLS_VERSION_13_DRAFT28:
147  case TLS_VERSION_13_DRAFT27:
148  case TLS_VERSION_13_DRAFT26:
149  case TLS_VERSION_13_DRAFT25:
150  case TLS_VERSION_13_DRAFT24:
151  case TLS_VERSION_13_DRAFT23:
152  case TLS_VERSION_13_DRAFT22:
153  case TLS_VERSION_13_DRAFT21:
154  case TLS_VERSION_13_DRAFT20:
155  case TLS_VERSION_13_DRAFT19:
156  case TLS_VERSION_13_DRAFT18:
157  case TLS_VERSION_13_DRAFT17:
158  case TLS_VERSION_13_DRAFT16:
159  case TLS_VERSION_13_PRE_DRAFT16:
160  case TLS_VERSION_13:
161  if (ssl->data[TLS13])
162  ret = 1;
163  sig_ver = true;
164  break;
165  }
166 
167  if (!sig_ver)
168  SCReturnInt(0);
169 
170  // matches if ret == 1 and negate is false
171  // or if ret == 0 and negate is true
172  SCReturnInt(ret ^ (ssl->negate ? 1 : 0));
173 }
174 
176  const char *word;
177  int index;
178 };
179 
181  { "sslv2", SSLv2 },
182  { "sslv3", SSLv3 },
183  { "tls1.0", TLS10 },
184  { "tls1.1", TLS11 },
185  { "tls1.2", TLS12 },
186  { "tls1.3", TLS13 },
187 };
188 
189 /**
190  * \brief This function is used to parse ssl_version data passed via
191  * keyword: "ssl_version"
192  *
193  * \param de_ctx Pointer to the detection engine context
194  * \param str Pointer to the user provided options
195  *
196  * \retval ssl pointer to DetectSslVersionData on success
197  * \retval NULL on failure
198  */
199 static DetectSslVersionData *DetectSslVersionParse(DetectEngineCtx *de_ctx, const char *str)
200 {
201  DetectSslVersionData *ssl = NULL;
202  const char *tmp_str = str;
203  size_t tmp_len = 0;
204 
205  /* We have a correct ssl_version options */
206  ssl = SCCalloc(1, sizeof(DetectSslVersionData));
207  if (unlikely(ssl == NULL))
208  goto error;
209 
210  // skip leading space
211  while (tmp_str[0] != 0 && isspace(tmp_str[0])) {
212  tmp_str++;
213  }
214  if (tmp_str[0] == 0) {
215  SCLogError("Invalid empty value");
216  goto error;
217  }
218  if (tmp_str[0] == '!') {
219  ssl->negate = true;
220  tmp_str++;
221  }
222  // iterate every version separated by comma
223  while (tmp_str[0] != 0) {
224  // counts word length
225  tmp_len = 0;
226  while (tmp_str[tmp_len] != 0 && !isspace(tmp_str[tmp_len]) && tmp_str[tmp_len] != ',') {
227  tmp_len++;
228  }
229 
230  bool is_keyword = false;
231  for (size_t i = 0; i < TLS_SIZE; i++) {
232  if (tmp_len == strlen(ssl_version_keywords[i].word) &&
233  strncasecmp(ssl_version_keywords[i].word, tmp_str, tmp_len) == 0) {
234  if (ssl->data[ssl_version_keywords[i].index]) {
235  SCLogError("Invalid duplicate value");
236  goto error;
237  }
238  ssl->data[ssl_version_keywords[i].index] = true;
239  is_keyword = true;
240  break;
241  }
242  }
243  if (!is_keyword) {
244  SCLogError("Invalid unknown value");
245  goto error;
246  }
247 
248  tmp_str += tmp_len;
249  while (isspace(tmp_str[0]) || tmp_str[0] == ',') {
250  tmp_str++;
251  }
252  }
253 
254  return ssl;
255 
256 error:
257  if (ssl != NULL)
258  DetectSslVersionFree(de_ctx, ssl);
259  return NULL;
260 
261 }
262 
263 /**
264  * \brief this function is used to add the parsed "id" option
265  * \brief into the current signature
266  *
267  * \param de_ctx pointer to the Detection Engine Context
268  * \param s pointer to the Current Signature
269  * \param idstr pointer to the user provided "id" option
270  *
271  * \retval 0 on Success
272  * \retval -1 on Failure
273  */
274 static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
275 {
276  DetectSslVersionData *ssl = NULL;
277 
279  return -1;
280 
281  ssl = DetectSslVersionParse(de_ctx, str);
282  if (ssl == NULL)
283  goto error;
284 
285  /* Okay so far so good, lets get this into a SigMatch
286  * and put it in the Signature. */
287 
289  de_ctx, s, DETECT_SSL_VERSION, (SigMatchCtx *)ssl, g_tls_generic_list_id) == NULL) {
290  goto error;
291  }
292  return 0;
293 
294 error:
295  if (ssl != NULL)
296  DetectSslVersionFree(de_ctx, ssl);
297  return -1;
298 }
299 
300 /**
301  * \brief this function will free memory associated with DetectSslVersionData
302  *
303  * \param id_d pointer to DetectSslVersionData
304  */
305 void DetectSslVersionFree(DetectEngineCtx *de_ctx, void *ptr)
306 {
307  if (ptr != NULL)
308  SCFree(ptr);
309 }
310 
311 #ifdef UNITTESTS
313 #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:227
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:248
ALPROTO_TLS
@ ALPROTO_TLS
Definition: app-layer-protos.h:39
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:279
SSLState_::server_connp
SSLStateConnp server_connp
Definition: app-layer-ssl.h:249
threads.h
Flow_
Flow data structure.
Definition: flow.h:348
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:176
SSLVersionKeywords
Definition: detect-ssl-version.c:175
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:177
decode.h
util-debug.h
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
TLS10
@ TLS10
Definition: detect-ssl-version.h:31
DetectEngineThreadCtx_
Definition: detect.h:1245
SCEnter
#define SCEnter(...)
Definition: util-debug.h:281
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:180
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:199
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:271
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:67
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:285
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:176