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_AL_SSL_VERSION].name = "ssl_version";
70  sigmatch_table[DETECT_AL_SSL_VERSION].desc = "match version of SSL/TLS record";
71  sigmatch_table[DETECT_AL_SSL_VERSION].url = "/rules/tls-keywords.html#ssl-version";
72  sigmatch_table[DETECT_AL_SSL_VERSION].AppLayerTxMatch = DetectSslVersionMatch;
73  sigmatch_table[DETECT_AL_SSL_VERSION].Setup = DetectSslVersionSetup;
74  sigmatch_table[DETECT_AL_SSL_VERSION].Free = DetectSslVersionFree;
75 #ifdef UNITTESTS
76  sigmatch_table[DETECT_AL_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  uint8_t sig_ver = TLS_UNKNOWN;
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 (ver == ssl->data[SSLv2].ver)
123  ret = 1;
124  sig_ver = SSLv2;
125  break;
126  case SSL_VERSION_3:
127  if (ver == ssl->data[SSLv3].ver)
128  ret = 1;
129  sig_ver = SSLv3;
130  break;
131  case TLS_VERSION_10:
132  if (ver == ssl->data[TLS10].ver)
133  ret = 1;
134  sig_ver = TLS10;
135  break;
136  case TLS_VERSION_11:
137  if (ver == ssl->data[TLS11].ver)
138  ret = 1;
139  sig_ver = TLS11;
140  break;
141  case TLS_VERSION_12:
142  if (ver == ssl->data[TLS12].ver)
143  ret = 1;
144  sig_ver = TLS12;
145  break;
160  if (((ver >> 8) & 0xff) == 0x7f)
161  ver = TLS_VERSION_13;
162  /* fall through */
163  case TLS_VERSION_13:
164  if (ver == ssl->data[TLS13].ver)
165  ret = 1;
166  sig_ver = TLS13;
167  break;
168  }
169 
170  if (sig_ver == TLS_UNKNOWN)
171  SCReturnInt(0);
172 
173  SCReturnInt(ret ^ ((ssl->data[sig_ver].flags & DETECT_SSL_VERSION_NEGATED) ? 1 : 0));
174 }
175 
177  const char *word;
178  int index;
179  uint16_t value;
180 };
181 
183  { "sslv2", SSLv2, SSL_VERSION_2 },
184  { "sslv3", SSLv3, SSL_VERSION_3 },
185  { "tls1.0", TLS10, TLS_VERSION_10 },
186  { "tls1.1", TLS11, TLS_VERSION_11 },
187  { "tls1.2", TLS12, TLS_VERSION_12 },
188  { "tls1.3", TLS13, TLS_VERSION_13 },
189 };
190 
191 /**
192  * \brief This function is used to parse ssl_version data passed via
193  * keyword: "ssl_version"
194  *
195  * \param de_ctx Pointer to the detection engine context
196  * \param str Pointer to the user provided options
197  *
198  * \retval ssl pointer to DetectSslVersionData on success
199  * \retval NULL on failure
200  */
201 static DetectSslVersionData *DetectSslVersionParse(DetectEngineCtx *de_ctx, const char *str)
202 {
203  DetectSslVersionData *ssl = NULL;
204  const char *tmp_str = str;
205  size_t tmp_len = 0;
206  uint8_t found = 0;
207 
208  /* We have a correct ssl_version options */
209  ssl = SCCalloc(1, sizeof(DetectSslVersionData));
210  if (unlikely(ssl == NULL))
211  goto error;
212 
213  // skip leading space
214  while (tmp_str[0] != 0 && isspace(tmp_str[0])) {
215  tmp_str++;
216  }
217  if (tmp_str[0] == 0) {
218  SCLogError("Invalid empty value");
219  goto error;
220  }
221  // iterate every version separated by comma
222  while (tmp_str[0] != 0) {
223  uint8_t neg = 0;
224  if (tmp_str[0] == '!') {
225  neg = 1;
226  tmp_str++;
227  }
228  // counts word length
229  tmp_len = 0;
230  while (tmp_str[tmp_len] != 0 && !isspace(tmp_str[tmp_len]) && tmp_str[tmp_len] != ',') {
231  tmp_len++;
232  }
233 
234  bool is_keyword = false;
235  for (size_t i = 0; i < TLS_SIZE; i++) {
236  if (tmp_len == strlen(ssl_version_keywords[i].word) &&
237  strncasecmp(ssl_version_keywords[i].word, tmp_str, tmp_len) == 0) {
238  if (ssl->data[ssl_version_keywords[i].index].ver != 0) {
239  SCLogError("Invalid duplicate value");
240  goto error;
241  }
243  if (neg == 1)
245  is_keyword = true;
246  break;
247  }
248  }
249  if (!is_keyword) {
250  SCLogError("Invalid unknown value");
251  goto error;
252  }
253 
254  /* check consistency between negative and positive values :
255  * if there is a negative value, it overrides positive values
256  */
257  if (found == 0) {
258  found |= 1 << neg;
259  } else if (found != 1 << neg) {
260  SCLogError("Invalid value mixing negative and positive forms");
261  goto error;
262  }
263 
264  tmp_str += tmp_len;
265  while (isspace(tmp_str[0]) || tmp_str[0] == ',') {
266  tmp_str++;
267  }
268  }
269 
270  return ssl;
271 
272 error:
273  if (ssl != NULL)
274  DetectSslVersionFree(de_ctx, ssl);
275  return NULL;
276 
277 }
278 
279 /**
280  * \brief this function is used to add the parsed "id" option
281  * \brief into the current signature
282  *
283  * \param de_ctx pointer to the Detection Engine Context
284  * \param s pointer to the Current Signature
285  * \param idstr pointer to the user provided "id" option
286  *
287  * \retval 0 on Success
288  * \retval -1 on Failure
289  */
290 static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
291 {
292  DetectSslVersionData *ssl = NULL;
293  SigMatch *sm = NULL;
294 
296  return -1;
297 
298  ssl = DetectSslVersionParse(de_ctx, str);
299  if (ssl == NULL)
300  goto error;
301 
302  /* Okay so far so good, lets get this into a SigMatch
303  * and put it in the Signature. */
304  sm = SigMatchAlloc();
305  if (sm == NULL)
306  goto error;
307 
309  sm->ctx = (void *)ssl;
310 
311  SigMatchAppendSMToList(s, sm, g_tls_generic_list_id);
312  return 0;
313 
314 error:
315  if (ssl != NULL)
316  DetectSslVersionFree(de_ctx, ssl);
317  if (sm != NULL)
318  SCFree(sm);
319  return -1;
320 }
321 
322 /**
323  * \brief this function will free memory associated with DetectSslVersionData
324  *
325  * \param id_d pointer to DetectSslVersionData
326  */
327 void DetectSslVersionFree(DetectEngineCtx *de_ctx, void *ptr)
328 {
329  if (ptr != NULL)
330  SCFree(ptr);
331 }
332 
333 #ifdef UNITTESTS
335 #endif
SigTableElmt_::url
const char * url
Definition: detect.h:1241
DetectSignatureSetAppProto
int DetectSignatureSetAppProto(Signature *s, AppProto alproto)
Definition: detect-parse.c:1498
SSLVersionKeywords::value
uint16_t value
Definition: detect-ssl-version.c:179
SSLState_
SSLv[2.0|3.[0|1|2|3]] state structure.
Definition: app-layer-ssl.h:288
TLS_VERSION_11
@ TLS_VERSION_11
Definition: app-layer-ssl.h:167
detect-engine.h
SigTableElmt_::desc
const char * desc
Definition: detect.h:1240
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1228
TLS_VERSION_12
@ TLS_VERSION_12
Definition: app-layer-ssl.h:168
flow-util.h
SigTableElmt_::name
const char * name
Definition: detect.h:1238
stream-tcp.h
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SSLState_::client_connp
SSLStateConnp client_connp
Definition: app-layer-ssl.h:306
TLS_VERSION_13_DRAFT21
@ TLS_VERSION_13_DRAFT21
Definition: app-layer-ssl.h:177
ALPROTO_TLS
@ ALPROTO_TLS
Definition: app-layer-protos.h:33
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
SSLState_::server_connp
SSLStateConnp server_connp
Definition: app-layer-ssl.h:307
TLS_UNKNOWN
@ TLS_UNKNOWN
Definition: detect-ssl-version.h:39
threads.h
Flow_
Flow data structure.
Definition: flow.h:357
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:785
SigTableElmt_::AppLayerTxMatch
int(* AppLayerTxMatch)(DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, void *txv, const Signature *, const SigMatchCtx *)
Definition: detect.h:1209
TLS_VERSION_13_DRAFT18
@ TLS_VERSION_13_DRAFT18
Definition: app-layer-ssl.h:180
SSLVersionKeywords::word
const char * word
Definition: detect-ssl-version.c:177
SSLVersionKeywords
Definition: detect-ssl-version.c:176
m
SCMutex m
Definition: flow-hash.h:6
detect-ssl-version.c
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1223
SSLVersionData_::flags
uint8_t flags
Definition: detect-ssl-version.h:44
TLS_VERSION_13_DRAFT26
@ TLS_VERSION_13_DRAFT26
Definition: app-layer-ssl.h:172
TLS12
@ TLS12
Definition: detect-ssl-version.h:35
util-unittest.h
util-unittest-helper.h
SSLVersionKeywords::index
int index
Definition: detect-ssl-version.c:178
TLS13
@ TLS13
Definition: detect-ssl-version.h:36
decode.h
util-debug.h
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
TLS_VERSION_13_DRAFT28
@ TLS_VERSION_13_DRAFT28
Definition: app-layer-ssl.h:170
TLS_VERSION_10
@ TLS_VERSION_10
Definition: app-layer-ssl.h:166
DetectEngineThreadCtx_
Definition: detect.h:1025
TLS_VERSION_13_DRAFT20
@ TLS_VERSION_13_DRAFT20
Definition: app-layer-ssl.h:178
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
detect-engine-mpm.h
detect.h
SSLv2
@ SSLv2
Definition: detect-ssl-version.h:31
DetectSslVersionData_
Definition: detect-ssl-version.h:47
TLS_VERSION_13_DRAFT22
@ TLS_VERSION_13_DRAFT22
Definition: app-layer-ssl.h:176
TLS_VERSION_13_DRAFT23
@ TLS_VERSION_13_DRAFT23
Definition: app-layer-ssl.h:175
app-layer-parser.h
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:316
TLS11
@ TLS11
Definition: detect-ssl-version.h:34
TLS_VERSION_13_DRAFT27
@ TLS_VERSION_13_DRAFT27
Definition: app-layer-ssl.h:171
TLS_VERSION_13
@ TLS_VERSION_13
Definition: app-layer-ssl.h:169
TLS_VERSION_13_DRAFT25
@ TLS_VERSION_13_DRAFT25
Definition: app-layer-ssl.h:173
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
TLS_VERSION_13_DRAFT17
@ TLS_VERSION_13_DRAFT17
Definition: app-layer-ssl.h:181
ssl_version_keywords
struct SSLVersionKeywords ssl_version_keywords[TLS_SIZE]
Definition: detect-ssl-version.c:182
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:239
detect-ssl-version.h
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:308
SSLv3
@ SSLv3
Definition: detect-ssl-version.h:32
TLS_SIZE
@ TLS_SIZE
Definition: detect-ssl-version.h:38
DetectBufferTypeRegister
int DetectBufferTypeRegister(const char *name)
Definition: detect-engine.c:1025
flags
uint8_t flags
Definition: decode-gre.h:0
suricata-common.h
DetectSslVersionData_::data
SSLVersionData data[TLS_SIZE]
Definition: detect-ssl-version.h:48
SigMatch_::type
uint16_t type
Definition: detect.h:314
sigmatch_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:76
TLS_VERSION_13_DRAFT16
@ TLS_VERSION_13_DRAFT16
Definition: app-layer-ssl.h:182
TLS_VERSION_13_DRAFT19
@ TLS_VERSION_13_DRAFT19
Definition: app-layer-ssl.h:179
SSL_VERSION_2
@ SSL_VERSION_2
Definition: app-layer-ssl.h:164
DETECT_AL_SSL_VERSION
@ DETECT_AL_SSL_VERSION
Definition: detect-engine-register.h:176
str
#define str(s)
Definition: suricata-common.h:280
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
detect-parse.h
Signature_
Signature container.
Definition: detect.h:540
SigMatch_
a single match condition for a signature
Definition: detect.h:313
TLS10
@ TLS10
Definition: detect-ssl-version.h:33
DetectSslVersionRegister
void DetectSslVersionRegister(void)
Registration function for keyword: ssl_version.
Definition: detect-ssl-version.c:67
SSLVersionData_::ver
uint16_t ver
Definition: detect-ssl-version.h:43
TLS_VERSION_13_DRAFT24
@ TLS_VERSION_13_DRAFT24
Definition: app-layer-ssl.h:174
flow.h
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SSL_VERSION_3
@ SSL_VERSION_3
Definition: app-layer-ssl.h:165
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
DETECT_SSL_VERSION_NEGATED
#define DETECT_SSL_VERSION_NEGATED
Definition: detect-ssl-version.h:28
flow-var.h
app-layer-ssl.h
SigMatchAppendSMToList
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:354
TLS_VERSION_13_PRE_DRAFT16
@ TLS_VERSION_13_PRE_DRAFT16
Definition: app-layer-ssl.h:183
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1230
app-layer.h
SSLStateConnp_::version
uint16_t version
Definition: app-layer-ssl.h:240