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 "debug.h"
29 #include "decode.h"
30 
31 #include "detect.h"
32 #include "detect-parse.h"
33 
34 #include "detect-engine.h"
35 #include "detect-engine-mpm.h"
36 #include "detect-engine-state.h"
37 
38 #include "flow.h"
39 #include "flow-var.h"
40 #include "flow-util.h"
41 
42 #include "util-debug.h"
43 #include "util-unittest.h"
44 #include "util-unittest-helper.h"
45 
46 #include "app-layer.h"
47 #include "app-layer-parser.h"
48 
49 #include "detect-ssl-version.h"
50 
51 #include "stream-tcp.h"
52 #include "app-layer-ssl.h"
53 
54 
55 static int DetectSslVersionMatch(DetectEngineThreadCtx *,
56  Flow *, uint8_t, void *, void *,
57  const Signature *, const SigMatchCtx *);
58 static int DetectSslVersionSetup(DetectEngineCtx *, Signature *, const char *);
59 #ifdef UNITTESTS
60 static void DetectSslVersionRegisterTests(void);
61 #endif
62 static void DetectSslVersionFree(DetectEngineCtx *, void *);
63 static int g_tls_generic_list_id = 0;
64 
65 /**
66  * \brief Registration function for keyword: ssl_version
67  */
69 {
70  sigmatch_table[DETECT_AL_SSL_VERSION].name = "ssl_version";
71  sigmatch_table[DETECT_AL_SSL_VERSION].desc = "match version of SSL/TLS record";
72  sigmatch_table[DETECT_AL_SSL_VERSION].url = "/rules/tls-keywords.html#ssl-version";
73  sigmatch_table[DETECT_AL_SSL_VERSION].AppLayerTxMatch = DetectSslVersionMatch;
74  sigmatch_table[DETECT_AL_SSL_VERSION].Setup = DetectSslVersionSetup;
75  sigmatch_table[DETECT_AL_SSL_VERSION].Free = DetectSslVersionFree;
76 #ifdef UNITTESTS
77  sigmatch_table[DETECT_AL_SSL_VERSION].RegisterTests = DetectSslVersionRegisterTests;
78 #endif
79 
80  g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic");
81 }
82 
83 /**
84  * \brief match the specified version on a ssl session
85  *
86  * \param t pointer to thread vars
87  * \param det_ctx pointer to the pattern matcher thread
88  * \param p pointer to the current packet
89  * \param m pointer to the sigmatch that we will cast into DetectSslVersionData
90  *
91  * \retval 0 no match
92  * \retval 1 match
93  */
94 static int DetectSslVersionMatch(DetectEngineThreadCtx *det_ctx,
95  Flow *f, uint8_t flags, void *state, void *txv,
96  const Signature *s, const SigMatchCtx *m)
97 {
98  SCEnter();
99 
100  int ret = 0;
101  uint16_t ver = 0;
102  uint8_t sig_ver = TLS_UNKNOWN;
103 
104  const DetectSslVersionData *ssl = (const DetectSslVersionData *)m;
105  SSLState *app_state = (SSLState *)state;
106  if (app_state == NULL) {
107  SCLogDebug("no app state, no match");
108  SCReturnInt(0);
109  }
110 
111  if (flags & STREAM_TOCLIENT) {
112  SCLogDebug("server (toclient) version is 0x%02X",
113  app_state->server_connp.version);
114  ver = app_state->server_connp.version;
115  } else if (flags & STREAM_TOSERVER) {
116  SCLogDebug("client (toserver) version is 0x%02X",
117  app_state->client_connp.version);
118  ver = app_state->client_connp.version;
119  }
120 
121  switch (ver) {
122  case SSL_VERSION_2:
123  if (ver == ssl->data[SSLv2].ver)
124  ret = 1;
125  sig_ver = SSLv2;
126  break;
127  case SSL_VERSION_3:
128  if (ver == ssl->data[SSLv3].ver)
129  ret = 1;
130  sig_ver = SSLv3;
131  break;
132  case TLS_VERSION_10:
133  if (ver == ssl->data[TLS10].ver)
134  ret = 1;
135  sig_ver = TLS10;
136  break;
137  case TLS_VERSION_11:
138  if (ver == ssl->data[TLS11].ver)
139  ret = 1;
140  sig_ver = TLS11;
141  break;
142  case TLS_VERSION_12:
143  if (ver == ssl->data[TLS12].ver)
144  ret = 1;
145  sig_ver = TLS12;
146  break;
161  if (((ver >> 8) & 0xff) == 0x7f)
162  ver = TLS_VERSION_13;
163  /* fall through */
164  case TLS_VERSION_13:
165  if (ver == ssl->data[TLS13].ver)
166  ret = 1;
167  sig_ver = TLS13;
168  break;
169  }
170 
171  if (sig_ver == TLS_UNKNOWN)
172  SCReturnInt(0);
173 
174  SCReturnInt(ret ^ ((ssl->data[sig_ver].flags & DETECT_SSL_VERSION_NEGATED) ? 1 : 0));
175 }
176 
178  const char *word;
179  int index;
180  int value;
181 };
182 
184  { "sslv2", SSLv2, SSL_VERSION_2 },
185  { "sslv3", SSLv3, SSL_VERSION_3 },
186  { "tls1.0", TLS10, TLS_VERSION_10 },
187  { "tls1.1", TLS11, TLS_VERSION_11 },
188  { "tls1.2", TLS12, TLS_VERSION_12 },
189  { "tls1.3", TLS13, TLS_VERSION_13 },
190 };
191 
192 /**
193  * \brief This function is used to parse ssl_version data passed via
194  * keyword: "ssl_version"
195  *
196  * \param de_ctx Pointer to the detection engine context
197  * \param str Pointer to the user provided options
198  *
199  * \retval ssl pointer to DetectSslVersionData on success
200  * \retval NULL on failure
201  */
202 static DetectSslVersionData *DetectSslVersionParse(DetectEngineCtx *de_ctx, const char *str)
203 {
204  DetectSslVersionData *ssl = NULL;
205  const char *tmp_str = str;
206  size_t tmp_len = 0;
207  uint8_t found = 0;
208 
209  /* We have a correct ssl_version options */
210  ssl = SCCalloc(1, sizeof(DetectSslVersionData));
211  if (unlikely(ssl == NULL))
212  goto error;
213 
214  // skip leading space
215  while (tmp_str[0] != 0 && isspace(tmp_str[0])) {
216  tmp_str++;
217  }
218  if (tmp_str[0] == 0) {
219  SCLogError(SC_ERR_INVALID_VALUE, "Invalid empty value");
220  goto error;
221  }
222  // iterate every version separated by comma
223  while (tmp_str[0] != 0) {
224  uint8_t neg = 0;
225  if (tmp_str[0] == '!') {
226  neg = 1;
227  tmp_str++;
228  }
229  // counts word length
230  tmp_len = 0;
231  while (tmp_str[tmp_len] != 0 && !isspace(tmp_str[tmp_len]) && tmp_str[tmp_len] != ',') {
232  tmp_len++;
233  }
234 
235  bool is_keyword = false;
236  for (size_t i = 0; i < TLS_SIZE; i++) {
237  if (tmp_len == strlen(ssl_version_keywords[i].word) &&
238  strncasecmp(ssl_version_keywords[i].word, tmp_str, tmp_len) == 0) {
239  if (ssl->data[ssl_version_keywords[i].index].ver != 0) {
240  SCLogError(SC_ERR_INVALID_VALUE, "Invalid duplicate value");
241  goto error;
242  }
244  if (neg == 1)
246  is_keyword = true;
247  break;
248  }
249  }
250  if (!is_keyword) {
251  SCLogError(SC_ERR_INVALID_VALUE, "Invalid unknown value");
252  goto error;
253  }
254 
255  /* check consistency between negative and positive values :
256  * if there is a negative value, it overrides positive values
257  */
258  if (found == 0) {
259  found |= 1 << neg;
260  } else if (found != 1 << neg) {
261  SCLogError(SC_ERR_INVALID_VALUE, "Invalid value mixing negative and positive forms");
262  goto error;
263  }
264 
265  tmp_str += tmp_len;
266  while (isspace(tmp_str[0]) || tmp_str[0] == ',') {
267  tmp_str++;
268  }
269  }
270 
271  return ssl;
272 
273 error:
274  if (ssl != NULL)
275  DetectSslVersionFree(de_ctx, ssl);
276  return NULL;
277 
278 }
279 
280 /**
281  * \brief this function is used to add the parsed "id" option
282  * \brief into the current signature
283  *
284  * \param de_ctx pointer to the Detection Engine Context
285  * \param s pointer to the Current Signature
286  * \param idstr pointer to the user provided "id" option
287  *
288  * \retval 0 on Success
289  * \retval -1 on Failure
290  */
291 static int DetectSslVersionSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
292 {
293  DetectSslVersionData *ssl = NULL;
294  SigMatch *sm = NULL;
295 
297  return -1;
298 
299  ssl = DetectSslVersionParse(de_ctx, str);
300  if (ssl == NULL)
301  goto error;
302 
303  /* Okay so far so good, lets get this into a SigMatch
304  * and put it in the Signature. */
305  sm = SigMatchAlloc();
306  if (sm == NULL)
307  goto error;
308 
310  sm->ctx = (void *)ssl;
311 
312  SigMatchAppendSMToList(s, sm, g_tls_generic_list_id);
313  return 0;
314 
315 error:
316  if (ssl != NULL)
317  DetectSslVersionFree(de_ctx, ssl);
318  if (sm != NULL)
319  SCFree(sm);
320  return -1;
321 }
322 
323 /**
324  * \brief this function will free memory associated with DetectSslVersionData
325  *
326  * \param id_d pointer to DetectSslVersionData
327  */
328 void DetectSslVersionFree(DetectEngineCtx *de_ctx, void *ptr)
329 {
330  if (ptr != NULL)
331  SCFree(ptr);
332 }
333 
334 #ifdef UNITTESTS
336 #endif
SigTableElmt_::url
const char * url
Definition: detect.h:1270
DetectSignatureSetAppProto
int DetectSignatureSetAppProto(Signature *s, AppProto alproto)
Definition: detect-parse.c:1490
SSLState_
SSLv[2.0|3.[0|1|2|3]] state structure.
Definition: app-layer-ssl.h:243
TLS_VERSION_11
@ TLS_VERSION_11
Definition: app-layer-ssl.h:158
detect-engine.h
SigTableElmt_::desc
const char * desc
Definition: detect.h:1269
SC_ERR_INVALID_VALUE
@ SC_ERR_INVALID_VALUE
Definition: util-error.h:160
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1257
TLS_VERSION_12
@ TLS_VERSION_12
Definition: app-layer-ssl.h:159
flow-util.h
SigTableElmt_::name
const char * name
Definition: detect.h:1267
stream-tcp.h
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SSLState_::client_connp
SSLStateConnp client_connp
Definition: app-layer-ssl.h:260
TLS_VERSION_13_DRAFT21
@ TLS_VERSION_13_DRAFT21
Definition: app-layer-ssl.h:168
ALPROTO_TLS
@ ALPROTO_TLS
Definition: app-layer-protos.h:33
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
SSLState_::server_connp
SSLStateConnp server_connp
Definition: app-layer-ssl.h:261
TLS_UNKNOWN
@ TLS_UNKNOWN
Definition: detect-ssl-version.h:39
threads.h
Flow_
Flow data structure.
Definition: flow.h:353
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:811
SSLVersionKeywords::value
int value
Definition: detect-ssl-version.c:180
SigTableElmt_::AppLayerTxMatch
int(* AppLayerTxMatch)(DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, void *txv, const Signature *, const SigMatchCtx *)
Definition: detect.h:1238
TLS_VERSION_13_DRAFT18
@ TLS_VERSION_13_DRAFT18
Definition: app-layer-ssl.h:171
SSLVersionKeywords::word
const char * word
Definition: detect-ssl-version.c:178
SSLVersionKeywords
Definition: detect-ssl-version.c:177
m
SCMutex m
Definition: flow-hash.h:6
detect-ssl-version.c
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1252
SSLVersionData_::flags
uint8_t flags
Definition: detect-ssl-version.h:44
TLS_VERSION_13_DRAFT26
@ TLS_VERSION_13_DRAFT26
Definition: app-layer-ssl.h:163
TLS12
@ TLS12
Definition: detect-ssl-version.h:35
util-unittest.h
util-unittest-helper.h
SSLVersionKeywords::index
int index
Definition: detect-ssl-version.c:179
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:161
TLS_VERSION_10
@ TLS_VERSION_10
Definition: app-layer-ssl.h:157
DetectEngineThreadCtx_
Definition: detect.h:1060
TLS_VERSION_13_DRAFT20
@ TLS_VERSION_13_DRAFT20
Definition: app-layer-ssl.h:169
SCEnter
#define SCEnter(...)
Definition: util-debug.h:300
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:167
TLS_VERSION_13_DRAFT23
@ TLS_VERSION_13_DRAFT23
Definition: app-layer-ssl.h:166
app-layer-parser.h
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:324
TLS11
@ TLS11
Definition: detect-ssl-version.h:34
TLS_VERSION_13_DRAFT27
@ TLS_VERSION_13_DRAFT27
Definition: app-layer-ssl.h:162
TLS_VERSION_13
@ TLS_VERSION_13
Definition: app-layer-ssl.h:160
TLS_VERSION_13_DRAFT25
@ TLS_VERSION_13_DRAFT25
Definition: app-layer-ssl.h:164
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:172
ssl_version_keywords
struct SSLVersionKeywords ssl_version_keywords[TLS_SIZE]
Definition: detect-ssl-version.c:183
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:235
detect-ssl-version.h
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:316
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:1023
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:322
sigmatch_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:73
TLS_VERSION_13_DRAFT16
@ TLS_VERSION_13_DRAFT16
Definition: app-layer-ssl.h:173
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:257
TLS_VERSION_13_DRAFT19
@ TLS_VERSION_13_DRAFT19
Definition: app-layer-ssl.h:170
SSL_VERSION_2
@ SSL_VERSION_2
Definition: app-layer-ssl.h:155
DETECT_AL_SSL_VERSION
@ DETECT_AL_SSL_VERSION
Definition: detect-engine-register.h:171
str
#define str(s)
Definition: suricata-common.h:272
SCFree
#define SCFree(p)
Definition: util-mem.h:61
detect-parse.h
Signature_
Signature container.
Definition: detect.h:548
SigMatch_
a single match condition for a signature
Definition: detect.h:321
TLS10
@ TLS10
Definition: detect-ssl-version.h:33
DetectSslVersionRegister
void DetectSslVersionRegister(void)
Registration function for keyword: ssl_version.
Definition: detect-ssl-version.c:68
SSLVersionData_::ver
uint16_t ver
Definition: detect-ssl-version.h:43
TLS_VERSION_13_DRAFT24
@ TLS_VERSION_13_DRAFT24
Definition: app-layer-ssl.h:165
flow.h
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SSL_VERSION_3
@ SSL_VERSION_3
Definition: app-layer-ssl.h:156
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:304
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:349
TLS_VERSION_13_PRE_DRAFT16
@ TLS_VERSION_13_PRE_DRAFT16
Definition: app-layer-ssl.h:174
debug.h
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1259
app-layer.h
SSLStateConnp_::version
uint16_t version
Definition: app-layer-ssl.h:199