]> git.ipfire.org Git - people/ms/suricata.git/blame - src/detect-tls-ja3-hash.c
core: Remove unneeded consts
[people/ms/suricata.git] / src / detect-tls-ja3-hash.c
CommitLineData
6c7aacce
MK
1/* Copyright (C) 2017 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 Mats Klepsland <mats.klepsland@gmail.com>
22 *
7f102d95 23 * Implements support for ja3.hash keyword.
6c7aacce
MK
24 */
25
26#include "suricata-common.h"
27#include "threads.h"
28#include "debug.h"
29#include "decode.h"
30#include "detect.h"
31
32#include "detect-parse.h"
33#include "detect-engine.h"
34#include "detect-engine-mpm.h"
35#include "detect-engine-prefilter.h"
36#include "detect-content.h"
37#include "detect-pcre.h"
38#include "detect-tls-ja3-hash.h"
39
40#include "flow.h"
41#include "flow-util.h"
42#include "flow-var.h"
43
44#include "conf.h"
45#include "conf-yaml-loader.h"
46
47#include "util-debug.h"
48#include "util-unittest.h"
49#include "util-spm.h"
50#include "util-print.h"
51#include "util-ja3.h"
52
53#include "stream-tcp.h"
54
55#include "app-layer.h"
56#include "app-layer-ssl.h"
57
58#include "util-unittest.h"
59#include "util-unittest-helper.h"
60
61static int DetectTlsJa3HashSetup(DetectEngineCtx *, Signature *, const char *);
74a7b7e3 62#ifdef UNITTESTS
6c7aacce 63static void DetectTlsJa3HashRegisterTests(void);
74a7b7e3 64#endif
6c7aacce
MK
65static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
66 const DetectEngineTransforms *transforms,
1c04d7cd 67 Flow *f, const uint8_t flow_flags,
6c7aacce 68 void *txv, const int list_id);
f36d578e
MK
69static void DetectTlsJa3HashSetupCallback(const DetectEngineCtx *de_ctx,
70 Signature *s);
be4c6b85 71static bool DetectTlsJa3HashValidateCallback(const Signature *s,
4c9d448f 72 const char **sigerror);
6c7aacce
MK
73static int g_tls_ja3_hash_buffer_id = 0;
74
75/**
76 * \brief Registration function for keyword: ja3_hash
77 */
78void DetectTlsJa3HashRegister(void)
79{
7f102d95
JL
80 sigmatch_table[DETECT_AL_TLS_JA3_HASH].name = "ja3.hash";
81 sigmatch_table[DETECT_AL_TLS_JA3_HASH].alias = "ja3_hash";
6c7aacce 82 sigmatch_table[DETECT_AL_TLS_JA3_HASH].desc = "content modifier to match the JA3 hash buffer";
26bcc975 83 sigmatch_table[DETECT_AL_TLS_JA3_HASH].url = "/rules/ja3-keywords.html#ja3-hash";
6c7aacce 84 sigmatch_table[DETECT_AL_TLS_JA3_HASH].Setup = DetectTlsJa3HashSetup;
74a7b7e3 85#ifdef UNITTESTS
6c7aacce 86 sigmatch_table[DETECT_AL_TLS_JA3_HASH].RegisterTests = DetectTlsJa3HashRegisterTests;
74a7b7e3 87#endif
6c7aacce 88 sigmatch_table[DETECT_AL_TLS_JA3_HASH].flags |= SIGMATCH_NOOPT;
7f102d95 89 sigmatch_table[DETECT_AL_TLS_JA3_HASH].flags |= SIGMATCH_INFO_STICKY_BUFFER;
6c7aacce 90
7f102d95 91 DetectAppLayerInspectEngineRegister2("ja3.hash", ALPROTO_TLS, SIG_FLAG_TOSERVER, 0,
6c7aacce
MK
92 DetectEngineInspectBufferGeneric, GetData);
93
7f102d95 94 DetectAppLayerMpmRegister2("ja3.hash", SIG_FLAG_TOSERVER, 2,
6c7aacce
MK
95 PrefilterGenericMpmRegister, GetData, ALPROTO_TLS, 0);
96
7f102d95 97 DetectBufferTypeSetDescriptionByName("ja3.hash", "TLS JA3 hash");
6c7aacce 98
7f102d95 99 DetectBufferTypeRegisterSetupCallback("ja3.hash",
f36d578e
MK
100 DetectTlsJa3HashSetupCallback);
101
7f102d95 102 DetectBufferTypeRegisterValidateCallback("ja3.hash",
4c9d448f
MK
103 DetectTlsJa3HashValidateCallback);
104
7f102d95 105 g_tls_ja3_hash_buffer_id = DetectBufferTypeGetByName("ja3.hash");
6c7aacce
MK
106}
107
108/**
7f102d95 109 * \brief this function setup the ja3.hash modifier keyword used in the rule
6c7aacce
MK
110 *
111 * \param de_ctx Pointer to the Detection Engine Context
112 * \param s Pointer to the Signature to which the current keyword belongs
113 * \param str Should hold an empty string always
114 *
0f7f35bd
MK
115 * \retval 0 On success
116 * \retval -1 On failure
0771eb1e 117 * \retval -2 on failure that should be silent after the first
6c7aacce
MK
118 */
119static int DetectTlsJa3HashSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
120{
0f7f35bd
MK
121 if (DetectBufferSetActiveList(s, g_tls_ja3_hash_buffer_id) < 0)
122 return -1;
123
124 if (DetectSignatureSetAppProto(s, ALPROTO_TLS) < 0)
125 return -1;
6c7aacce 126
ca5226f0
VJ
127 /* try to enable JA3 */
128 SSLEnableJA3();
129
6c7aacce 130 /* Check if JA3 is disabled */
0771eb1e
VJ
131 if (!RunmodeIsUnittests() && Ja3IsDisabled("rule")) {
132 if (!SigMatchSilentErrorEnabled(de_ctx, DETECT_AL_TLS_JA3_HASH)) {
133 SCLogError(SC_WARN_JA3_DISABLED, "ja3 support is not enabled");
134 }
135 return -2;
136 }
6c7aacce
MK
137
138 return 0;
139}
140
141static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
1c04d7cd
MK
142 const DetectEngineTransforms *transforms, Flow *f,
143 const uint8_t flow_flags, void *txv, const int list_id)
6c7aacce 144{
0b3220a0 145 InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
6c7aacce 146 if (buffer->inspect == NULL) {
008f08c1 147 const SSLState *ssl_state = (SSLState *)f->alstate;
6c7aacce 148
a4471987 149 if (ssl_state->client_connp.ja3_hash == NULL) {
6c7aacce
MK
150 return NULL;
151 }
152
a4471987
MK
153 const uint32_t data_len = strlen(ssl_state->client_connp.ja3_hash);
154 const uint8_t *data = (uint8_t *)ssl_state->client_connp.ja3_hash;
6c7aacce 155
13cebb18 156 InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len);
6c7aacce
MK
157 InspectionBufferApplyTransforms(buffer, transforms);
158 }
159
160 return buffer;
161}
162
be4c6b85 163static bool DetectTlsJa3HashValidateCallback(const Signature *s,
4c9d448f
MK
164 const char **sigerror)
165{
166 const SigMatch *sm = s->init_data->smlists[g_tls_ja3_hash_buffer_id];
167 for ( ; sm != NULL; sm = sm->next)
168 {
169 if (sm->type != DETECT_CONTENT)
170 continue;
171
5b954212
MK
172 const DetectContentData *cd = (DetectContentData *)sm->ctx;
173
174 if (cd->flags & DETECT_CONTENT_NOCASE) {
7f102d95 175 *sigerror = "ja3.hash should not be used together with "
5b954212
MK
176 "nocase, since the rule is automatically "
177 "lowercased anyway which makes nocase redundant.";
178 SCLogWarning(SC_WARN_POOR_RULE, "rule %u: %s", s->id, *sigerror);
179 }
4c9d448f
MK
180
181 if (cd->content_len == 32)
1eeb9669 182 return true;
4c9d448f
MK
183
184 *sigerror = "Invalid length of the specified JA3 hash (should "
185 "be 32 characters long). This rule will therefore "
186 "never match.";
187 SCLogWarning(SC_WARN_POOR_RULE, "rule %u: %s", s->id, *sigerror);
1eeb9669 188 return false;
4c9d448f
MK
189 }
190
1eeb9669 191 return true;
4c9d448f
MK
192}
193
f36d578e
MK
194static void DetectTlsJa3HashSetupCallback(const DetectEngineCtx *de_ctx,
195 Signature *s)
196{
197 SigMatch *sm = s->init_data->smlists[g_tls_ja3_hash_buffer_id];
198 for ( ; sm != NULL; sm = sm->next)
199 {
200 if (sm->type != DETECT_CONTENT)
201 continue;
202
203 DetectContentData *cd = (DetectContentData *)sm->ctx;
204
1eeb9669 205 bool changed = false;
f36d578e
MK
206 uint32_t u;
207 for (u = 0; u < cd->content_len; u++)
208 {
209 if (isupper(cd->content[u])) {
210 cd->content[u] = tolower(cd->content[u]);
1eeb9669 211 changed = true;
f36d578e
MK
212 }
213 }
214
215 /* recreate the context if changes were made */
216 if (changed) {
217 SpmDestroyCtx(cd->spm_ctx);
218 cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1,
219 de_ctx->spm_global_thread_ctx);
220 }
221 }
222}
223
6c7aacce 224#ifdef UNITTESTS
74a7b7e3
MK
225#include "tests/detect-tls-ja3-hash.c"
226#endif