suricata
detect-tls-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
20 *
21 * \author Victor Julien <victor@inliniac.net>
22 *
23 * Implements the tls.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"
44
45#include "app-layer.h"
46#include "app-layer-parser.h"
47
48#include "app-layer-ssl.h"
49#include "detect-tls-version.h"
50
51#include "stream-tcp.h"
52
53/**
54 * \brief Regex for parsing "id" option, matching number or "number"
55 */
56#define PARSE_REGEX "^\\s*([A-z0-9\\.]+|\"[A-z0-9\\.]+\")\\s*$"
57
58static DetectParseRegex parse_regex;
59
60static int DetectTlsVersionMatch (DetectEngineThreadCtx *,
61 Flow *, uint8_t, void *, void *,
62 const Signature *, const SigMatchCtx *);
63static int DetectTlsVersionSetup (DetectEngineCtx *, Signature *, const char *);
64#ifdef UNITTESTS
65static void DetectTlsVersionRegisterTests(void);
66#endif
67static void DetectTlsVersionFree(DetectEngineCtx *, void *);
68static int g_tls_generic_list_id = 0;
69
70/**
71 * \brief Registration function for keyword: tls.version
72 */
74{
75 sigmatch_table[DETECT_TLS_VERSION].name = "tls.version";
76 sigmatch_table[DETECT_TLS_VERSION].desc = "match on TLS/SSL version";
77 sigmatch_table[DETECT_TLS_VERSION].url = "/rules/tls-keywords.html#tls-version";
78 sigmatch_table[DETECT_TLS_VERSION].AppLayerTxMatch = DetectTlsVersionMatch;
79 sigmatch_table[DETECT_TLS_VERSION].Setup = DetectTlsVersionSetup;
80 sigmatch_table[DETECT_TLS_VERSION].Free = DetectTlsVersionFree;
82#ifdef UNITTESTS
83 sigmatch_table[DETECT_TLS_VERSION].RegisterTests = DetectTlsVersionRegisterTests;
84#endif
85
87
88 g_tls_generic_list_id = DetectBufferTypeRegister("tls_generic");
89}
90
91/**
92 * \brief match the specified version on a tls session
93 *
94 * \param t pointer to thread vars
95 * \param det_ctx pointer to the pattern matcher thread
96 * \param p pointer to the current packet
97 * \param m pointer to the sigmatch that we will cast into DetectTlsVersionData
98 *
99 * \retval 0 no match
100 * \retval 1 match
101 */
102static int DetectTlsVersionMatch (DetectEngineThreadCtx *det_ctx,
103 Flow *f, uint8_t flags, void *state, void *txv,
104 const Signature *s, const SigMatchCtx *m)
105{
106 SCEnter();
107
108 const DetectTlsVersionData *tls_data = (const DetectTlsVersionData *)m;
109 SSLState *ssl_state = (SSLState *)state;
110 if (ssl_state == NULL) {
111 SCLogDebug("no tls state, no match");
112 SCReturnInt(0);
113 }
114
115 int ret = 0;
116 uint16_t version = 0;
117 SCLogDebug("looking for tls_data->ver 0x%02X (flags 0x%02X)", tls_data->ver, flags);
118
119 if (flags & STREAM_TOCLIENT) {
120 version = ssl_state->server_connp.version;
121 SCLogDebug("server (toclient) version is 0x%02X", version);
122 } else if (flags & STREAM_TOSERVER) {
123 version = ssl_state->client_connp.version;
124 SCLogDebug("client (toserver) version is 0x%02X", version);
125 }
126
127 if ((tls_data->flags & DETECT_TLS_VERSION_FLAG_RAW) == 0) {
128 /* Match all TLSv1.3 drafts as TLSv1.3 */
129 if (((version >> 8) & 0xff) == 0x7f) {
130 version = TLS_VERSION_13;
131 }
132 }
133
134 if (tls_data->ver == version) {
135 ret = 1;
136 }
137
138 SCReturnInt(ret);
139}
140
141/**
142 * \brief This function is used to parse IPV4 ip_id passed via keyword: "id"
143 *
144 * \param de_ctx Pointer to the detection engine context
145 * \param idstr Pointer to the user provided id option
146 *
147 * \retval id_d pointer to DetectTlsVersionData on success
148 * \retval NULL on failure
149 */
150static DetectTlsVersionData *DetectTlsVersionParse (DetectEngineCtx *de_ctx, const char *str)
151{
152 uint16_t temp;
153 DetectTlsVersionData *tls = NULL;
154 int res = 0;
155 size_t pcre2len;
156
157 pcre2_match_data *match = NULL;
158 int ret = DetectParsePcreExec(&parse_regex, &match, str, 0, 0);
159 if (ret < 1 || ret > 3) {
160 SCLogError("invalid tls.version option");
161 goto error;
162 }
163
164 if (ret > 1) {
165 char ver_ptr[64];
166 char *tmp_str;
167 pcre2len = sizeof(ver_ptr);
168 res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)ver_ptr, &pcre2len);
169 if (res < 0) {
170 SCLogError("pcre2_substring_copy_bynumber failed");
171 goto error;
172 }
173
174 /* We have a correct id option */
175 tls = SCCalloc(1, sizeof(DetectTlsVersionData));
176 if (unlikely(tls == NULL))
177 goto error;
178
179 tmp_str = ver_ptr;
180
181 /* Let's see if we need to scape "'s */
182 if (tmp_str[0] == '"')
183 {
184 tmp_str[strlen(tmp_str) - 1] = '\0';
185 tmp_str += 1;
186 }
187
188 if (strncmp("1.0", tmp_str, 3) == 0) {
189 temp = TLS_VERSION_10;
190 } else if (strncmp("1.1", tmp_str, 3) == 0) {
191 temp = TLS_VERSION_11;
192 } else if (strncmp("1.2", tmp_str, 3) == 0) {
193 temp = TLS_VERSION_12;
194 } else if (strncmp("1.3", tmp_str, 3) == 0) {
195 temp = TLS_VERSION_13;
196 } else if ((strncmp("0x", tmp_str, 2) == 0) && (strlen(str) == 6)) {
197 temp = (uint16_t)strtol(tmp_str, NULL, 0);
199 } else {
200 SCLogError("Invalid value");
201 goto error;
202 }
203
204 tls->ver = temp;
205
206 SCLogDebug("will look for tls %"PRIu16"", tls->ver);
207 }
208
209 pcre2_match_data_free(match);
210 return tls;
211
212error:
213 if (match) {
214 pcre2_match_data_free(match);
215 }
216 if (tls != NULL)
217 DetectTlsVersionFree(de_ctx, tls);
218 return NULL;
219
220}
221
222/**
223 * \brief this function is used to add the parsed "id" option
224 * \brief into the current signature
225 *
226 * \param de_ctx pointer to the Detection Engine Context
227 * \param s pointer to the Current Signature
228 * \param idstr pointer to the user provided "id" option
229 *
230 * \retval 0 on Success
231 * \retval -1 on Failure
232 */
233static int DetectTlsVersionSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
234{
235 DetectTlsVersionData *tls = NULL;
236
238 return -1;
239
240 tls = DetectTlsVersionParse(de_ctx, str);
241 if (tls == NULL)
242 goto error;
243
244 /* keyword supports multiple hooks, so attach to the hook specified in the rule. */
245 int list = g_tls_generic_list_id;
246 /* Okay so far so good, lets get this into a SigMatch
247 * and put it in the Signature. */
249 list = s->init_data->hook.sm_list;
250 }
251
252 if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_TLS_VERSION, (SigMatchCtx *)tls, list) == NULL) {
253 goto error;
254 }
255
256 return 0;
257
258error:
259 if (tls != NULL)
260 DetectTlsVersionFree(de_ctx, tls);
261 return -1;
262
263}
264
265/**
266 * \brief this function will free memory associated with DetectTlsVersionData
267 *
268 * \param id_d pointer to DetectTlsVersionData
269 */
270static void DetectTlsVersionFree(DetectEngineCtx *de_ctx, void *ptr)
271{
273 SCFree(id_d);
274}
275
276#ifdef UNITTESTS
278#endif
@ ALPROTO_TLS
uint8_t flags
Definition decode-gre.h:0
uint8_t version
Definition decode-gre.h:1
@ DETECT_TLS_VERSION
Data structures and function prototypes for keeping state for the detection engine.
int DetectBufferTypeRegister(const char *name)
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
int SCDetectSignatureSetAppProto(Signature *s, AppProto alproto)
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
SigTableElmt * sigmatch_table
void DetectTlsVersionRegister(void)
Registration function for keyword: tls.version.
#define PARSE_REGEX
Regex for parsing "id" option, matching number or "number".
#define DETECT_TLS_VERSION_FLAG_RAW
#define SIGMATCH_SUPPORT_FIREWALL
Definition detect.h:1682
@ SIGNATURE_HOOK_TYPE_APP
Definition detect.h:549
SCMutex m
Definition flow-hash.h:6
DetectEngineCtx * de_ctx
main detection engine ctx
Definition detect.h:932
Flow data structure.
Definition flow.h:356
SSLv[2.0|3.[0|1|2|3]] state structure.
SSLStateConnp server_connp
SSLStateConnp client_connp
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition detect.h:351
const char * url
Definition detect.h:1462
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
void(* Free)(DetectEngineCtx *, void *)
Definition detect.h:1446
uint16_t flags
Definition detect.h:1450
const char * desc
Definition detect.h:1461
int(* AppLayerTxMatch)(DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, void *txv, const Signature *, const SigMatchCtx *)
Definition detect.h:1424
void(* RegisterTests)(void)
Definition detect.h:1448
const char * name
Definition detect.h:1459
enum SignatureHookType type
Definition detect.h:572
SignatureHook hook
Definition detect.h:590
Signature container.
Definition detect.h:668
SignatureInitData * init_data
Definition detect.h:747
#define str(s)
#define SCEnter(...)
Definition util-debug.h:277
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define unlikely(expr)