suricata
detect-ssl-state.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
20  *
21  * \author Anoop Saldanha <anoopsaldanha@gmail.com>
22  *
23  * Implements support for ssl_state 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-state.h"
50 
51 #include "stream-tcp.h"
52 #include "app-layer-ssl.h"
53 
54 #define PARSE_REGEX1 "^(!?)([_a-zA-Z0-9]+)(.*)$"
55 static DetectParseRegex parse_regex1;
56 
57 #define PARSE_REGEX2 "^(?:\\s*[|,]\\s*(!?)([_a-zA-Z0-9]+))(.*)$"
58 static DetectParseRegex parse_regex2;
59 
60 static int DetectSslStateMatch(DetectEngineThreadCtx *,
61  Flow *, uint8_t, void *, void *,
62  const Signature *, const SigMatchCtx *);
63 static int DetectSslStateSetup(DetectEngineCtx *, Signature *, const char *);
64 #ifdef UNITTESTS
65 static void DetectSslStateRegisterTests(void);
66 #endif
67 static void DetectSslStateFree(DetectEngineCtx *, void *);
68 
69 static int InspectTlsGeneric(ThreadVars *tv,
71  const Signature *s, const SigMatchData *smd,
72  Flow *f, uint8_t flags, void *alstate,
73  void *txv, uint64_t tx_id);
74 
75 static int g_tls_generic_list_id = 0;
76 
77 /**
78  * \brief Registers the keyword handlers for the "ssl_state" keyword.
79  */
81 {
83  sigmatch_table[DETECT_AL_SSL_STATE].desc = "match the state of the SSL connection";
84  sigmatch_table[DETECT_AL_SSL_STATE].url = "/rules/tls-keywords.html#ssl-state";
85  sigmatch_table[DETECT_AL_SSL_STATE].AppLayerTxMatch = DetectSslStateMatch;
86  sigmatch_table[DETECT_AL_SSL_STATE].Setup = DetectSslStateSetup;
87  sigmatch_table[DETECT_AL_SSL_STATE].Free = DetectSslStateFree;
88 #ifdef UNITTESTS
89  sigmatch_table[DETECT_AL_SSL_STATE].RegisterTests = DetectSslStateRegisterTests;
90 #endif
91  DetectSetupParseRegexes(PARSE_REGEX1, &parse_regex1);
92  DetectSetupParseRegexes(PARSE_REGEX2, &parse_regex2);
93 
94  g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic");
95 
97  "generic ssl/tls inspection");
98 
101  InspectTlsGeneric);
104  InspectTlsGeneric);
105 }
106 
107 static int InspectTlsGeneric(ThreadVars *tv,
109  const Signature *s, const SigMatchData *smd,
110  Flow *f, uint8_t flags, void *alstate,
111  void *txv, uint64_t tx_id)
112 {
113  return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd,
114  f, flags, alstate, txv, tx_id);
115 }
116 
117 /**
118  * \brief App layer match function ssl_state keyword.
119  *
120  * \param tv Pointer to threadvars.
121  * \param det_ctx Pointer to the thread's detection context.
122  * \param f Pointer to the flow.
123  * \param flags Flags.
124  * \param state App layer state.
125  * \param s Sig we are currently inspecting.
126  * \param m SigMatch we are currently inspecting.
127  *
128  * \retval 1 Match.
129  * \retval 0 No match.
130  */
131 static int DetectSslStateMatch(DetectEngineThreadCtx *det_ctx,
132  Flow *f, uint8_t flags, void *alstate, void *txv,
133  const Signature *s, const SigMatchCtx *m)
134 {
135  const DetectSslStateData *ssd = (const DetectSslStateData *)m;
136  SSLState *ssl_state = (SSLState *)alstate;
137  if (ssl_state == NULL) {
138  SCLogDebug("no app state, no match");
139  return 0;
140  }
141 
142  uint32_t ssl_flags = ssl_state->current_flags;
143 
144  if ((ssd->flags & ssl_flags) ^ ssd->mask) {
145  return 1;
146  }
147 
148  return 0;
149 }
150 
151 /**
152  * \brief Parse the arg supplied with ssl_state and return it in a
153  * DetectSslStateData instance.
154  *
155  * \param arg Pointer to the string to be parsed.
156  *
157  * \retval ssd Pointer to DetectSslStateData on success.
158  * \retval NULL On failure.
159  */
160 static DetectSslStateData *DetectSslStateParse(const char *arg)
161 {
162  int ret = 0, res = 0;
163  int ov1[MAX_SUBSTRINGS];
164  int ov2[MAX_SUBSTRINGS];
165  char str1[64];
166  char str2[64];
167  int negate = 0;
168  uint32_t flags = 0, mask = 0;
169  DetectSslStateData *ssd = NULL;
170 
171  ret = DetectParsePcreExec(&parse_regex1, arg, 0, 0, ov1, MAX_SUBSTRINGS);
172  if (ret < 1) {
173  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid arg \"%s\" supplied to "
174  "ssl_state keyword.", arg);
175  goto error;
176  }
177 
178  res = pcre_copy_substring((char *)arg, ov1, MAX_SUBSTRINGS, 1, str1, sizeof(str1));
179  if (res < 0) {
180  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
181  goto error;
182  }
183  negate = !strcmp("!", str1);
184 
185  res = pcre_copy_substring((char *)arg, ov1, MAX_SUBSTRINGS, 2, str1, sizeof(str1));
186  if (res < 0) {
187  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
188  goto error;
189  }
190 
191  if (strcmp("client_hello", str1) == 0) {
193  if (negate)
195  } else if (strcmp("server_hello", str1) == 0) {
197  if (negate)
199  } else if (strcmp("client_keyx", str1) == 0) {
201  if (negate)
203  } else if (strcmp("server_keyx", str1) == 0) {
205  if (negate)
207  } else if (strcmp("unknown", str1) == 0) {
209  if (negate)
210  mask |= DETECT_SSL_STATE_UNKNOWN;
211  } else {
212  SCLogError(SC_ERR_INVALID_SIGNATURE, "Found invalid option \"%s\" "
213  "in ssl_state keyword.", str1);
214  goto error;
215  }
216 
217  res = pcre_copy_substring((char *)arg, ov1, MAX_SUBSTRINGS, 3, str1, sizeof(str1));
218  if (res < 0) {
219  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
220  goto error;
221  }
222  while (res > 0) {
223  ret = DetectParsePcreExec(&parse_regex2, str1, 0, 0, ov2, MAX_SUBSTRINGS);
224  if (ret < 1) {
225  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid arg \"%s\" supplied to "
226  "ssl_state keyword.", arg);
227  goto error;
228  }
229 
230  res = pcre_copy_substring((char *)str1, ov2, MAX_SUBSTRINGS, 1, str2, sizeof(str2));
231  if (res < 0) {
232  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
233  goto error;
234  }
235  negate = !strcmp("!", str2);
236 
237  res = pcre_copy_substring((char *)str1, ov2, MAX_SUBSTRINGS, 2, str2, sizeof(str2));
238  if (res <= 0) {
239  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
240  goto error;
241  }
242  if (strcmp("client_hello", str2) == 0) {
244  if (negate)
246  } else if (strcmp("server_hello", str2) == 0) {
248  if (negate)
250  } else if (strcmp("client_keyx", str2) == 0) {
252  if (negate)
254  } else if (strcmp("server_keyx", str2) == 0) {
256  if (negate)
258  } else if (strcmp("unknown", str2) == 0) {
260  if (negate)
261  mask |= DETECT_SSL_STATE_UNKNOWN;
262  } else {
263  SCLogError(SC_ERR_INVALID_SIGNATURE, "Found invalid option \"%s\" "
264  "in ssl_state keyword.", str2);
265  goto error;
266  }
267 
268  res = pcre_copy_substring((char *)str1, ov2, MAX_SUBSTRINGS, 3, str2, sizeof(str2));
269  if (res < 0) {
270  SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed");
271  goto error;
272  }
273 
274  memcpy(str1, str2, sizeof(str1));
275  }
276 
277  if ( (ssd = SCMalloc(sizeof(DetectSslStateData))) == NULL) {
278  goto error;
279  }
280  ssd->flags = flags;
281  ssd->mask = mask;
282 
283  return ssd;
284 
285 error:
286  return NULL;
287 }
288 
289  /**
290  * \internal
291  * \brief Setup function for ssl_state keyword.
292  *
293  * \param de_ctx Pointer to the Detection Engine Context.
294  * \param s Pointer to the Current Signature
295  * \param arg String holding the arg.
296  *
297  * \retval 0 On success.
298  * \retval -1 On failure.
299  */
300 static int DetectSslStateSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
301 {
302  DetectSslStateData *ssd = NULL;
303  SigMatch *sm = NULL;
304 
306  return -1;
307 
308  ssd = DetectSslStateParse(arg);
309  if (ssd == NULL)
310  goto error;
311 
312  sm = SigMatchAlloc();
313  if (sm == NULL)
314  goto error;
315 
317  sm->ctx = (SigMatchCtx*)ssd;
318 
319  SigMatchAppendSMToList(s, sm, g_tls_generic_list_id);
320  return 0;
321 
322 error:
323  if (ssd != NULL)
324  DetectSslStateFree(de_ctx, ssd);
325  if (sm != NULL)
326  SCFree(sm);
327  return -1;
328 }
329 
330 /**
331  * \brief Free memory associated with DetectSslStateData.
332  *
333  * \param ptr pointer to the data to be freed.
334  */
335 static void DetectSslStateFree(DetectEngineCtx *de_ctx, void *ptr)
336 {
337  if (ptr != NULL)
338  SCFree(ptr);
339 
340  return;
341 }
342 
343 #ifdef UNITTESTS
344 #include "tests/detect-ssl-state.c"
345 #endif
SigTableElmt_::url
const char * url
Definition: detect.h:1214
DetectSignatureSetAppProto
int DetectSignatureSetAppProto(Signature *s, AppProto alproto)
Definition: detect-parse.c:1480
SSLState_
SSLv[2.0|3.[0|1|2|3]] state structure.
Definition: app-layer-ssl.h:233
detect-engine.h
SigTableElmt_::desc
const char * desc
Definition: detect.h:1213
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1201
flow-util.h
SigTableElmt_::name
const char * name
Definition: detect.h:1211
stream-tcp.h
MAX_SUBSTRINGS
#define MAX_SUBSTRINGS
ALPROTO_TLS
@ ALPROTO_TLS
Definition: app-layer-protos.h:33
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
threads.h
Flow_
Flow data structure.
Definition: flow.h:347
DETECT_SSL_STATE_CLIENT_HELLO
#define DETECT_SSL_STATE_CLIENT_HELLO
Definition: detect-ssl-state.h:30
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:767
SC_ERR_INVALID_SIGNATURE
@ SC_ERR_INVALID_SIGNATURE
Definition: util-error.h:69
DETECT_SSL_STATE_UNKNOWN
#define DETECT_SSL_STATE_UNKNOWN
Definition: detect-ssl-state.h:34
SigTableElmt_::AppLayerTxMatch
int(* AppLayerTxMatch)(DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, void *txv, const Signature *, const SigMatchCtx *)
Definition: detect.h:1182
m
SCMutex m
Definition: flow-hash.h:6
DetectSslStateData_::mask
uint32_t mask
Definition: detect-ssl-state.h:38
SIG_FLAG_TOCLIENT
#define SIG_FLAG_TOCLIENT
Definition: detect.h:237
SigMatchData_
Data needed for Match()
Definition: detect.h:329
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1196
util-unittest.h
util-unittest-helper.h
DetectEngineInspectGenericList
int DetectEngineInspectGenericList(ThreadVars *tv, const DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Flow *f, const uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
Do the content inspection & validation for a signature.
Definition: detect-engine.c:1596
SSLState_::current_flags
uint32_t current_flags
Definition: app-layer-ssl.h:246
SIG_FLAG_TOSERVER
#define SIG_FLAG_TOSERVER
Definition: detect.h:236
decode.h
util-debug.h
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
DetectEngineThreadCtx_
Definition: detect.h:1010
res
PoolThreadReserved res
Definition: stream-tcp-private.h:0
detect-ssl-state.c
DetectSetupParseRegexes
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
Definition: detect-parse.c:2493
SC_ERR_PCRE_COPY_SUBSTRING
@ SC_ERR_PCRE_COPY_SUBSTRING
Definition: util-error.h:358
detect-engine-mpm.h
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
DetectSslStateRegister
void DetectSslStateRegister(void)
Registers the keyword handlers for the "ssl_state" keyword.
Definition: detect-ssl-state.c:80
app-layer-parser.h
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:323
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, const char *str, int start_offset, int options, int *ovector, int ovector_size)
Definition: detect-parse.c:2423
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:235
DetectSslStateData_::flags
uint32_t flags
Definition: detect-ssl-state.h:37
SigMatch_::type
uint8_t type
Definition: detect.h:321
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:315
DETECT_AL_SSL_STATE
@ DETECT_AL_SSL_STATE
Definition: detect-engine-register.h:169
DetectBufferTypeRegister
int DetectBufferTypeRegister(const char *name)
Definition: detect-engine.c:836
flags
uint8_t flags
Definition: decode-gre.h:0
suricata-common.h
sigmatch_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:73
DetectParseRegex_
Definition: detect-parse.h:42
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:257
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:29
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
DETECT_SSL_STATE_SERVER_KEYX
#define DETECT_SSL_STATE_SERVER_KEYX
Definition: detect-ssl-state.h:33
SCFree
#define SCFree(p)
Definition: util-mem.h:61
detect-parse.h
Signature_
Signature container.
Definition: detect.h:528
SigMatch_
a single match condition for a signature
Definition: detect.h:320
PARSE_REGEX2
#define PARSE_REGEX2
Definition: detect-ssl-state.c:57
PARSE_REGEX1
#define PARSE_REGEX1
Definition: detect-ssl-state.c:54
detect-ssl-state.h
DetectBufferTypeSetDescriptionByName
void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc)
Definition: detect-engine.c:908
DetectSslStateData_
Definition: detect-ssl-state.h:36
flow.h
DetectAppLayerInspectEngineRegister
void DetectAppLayerInspectEngineRegister(const char *name, AppProto alproto, uint32_t dir, int progress, InspectEngineFuncPtr Callback)
register inspect engine at start up time
Definition: detect-engine.c:171
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
debug.h
DETECT_SSL_STATE_CLIENT_KEYX
#define DETECT_SSL_STATE_CLIENT_KEYX
Definition: detect-ssl-state.h:32
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1203
app-layer.h
DETECT_SSL_STATE_SERVER_HELLO
#define DETECT_SSL_STATE_SERVER_HELLO
Definition: detect-ssl-state.h:31