suricata
detect-asn1.c
Go to the documentation of this file.
1/* Copyright (C) 2020-2022 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-asn1.c
20 *
21 * Implements "asn1" keyword
22 */
23
24#include "suricata-common.h"
25#include "decode.h"
26#include "rust.h"
27
28#include "detect.h"
29#include "detect-parse.h"
30
31#include "flow.h"
32#include "detect-asn1.h"
33
34#include "util-unittest.h"
36#include "util-byte.h"
37#include "util-debug.h"
38
39static int DetectAsn1Setup (DetectEngineCtx *, Signature *, const char *);
40#ifdef UNITTESTS
41static void DetectAsn1RegisterTests(void);
42#endif
43static void DetectAsn1Free(DetectEngineCtx *, void *);
44
45/**
46 * \brief Registration function for asn1
47 */
49{
51 sigmatch_table[DETECT_ASN1].Setup = DetectAsn1Setup;
52 sigmatch_table[DETECT_ASN1].Free = DetectAsn1Free;
53#ifdef UNITTESTS
54 sigmatch_table[DETECT_ASN1].RegisterTests = DetectAsn1RegisterTests;
55#endif
56}
57
58bool DetectAsn1Match(const SigMatchData *smd, const uint8_t *buffer, const uint32_t buffer_len,
59 const uint32_t offset)
60{
61 const DetectAsn1Data *ad = (const DetectAsn1Data *)smd->ctx;
62 Asn1 *asn1 = SCAsn1Decode(buffer, buffer_len, offset, ad);
63 uint8_t ret = SCAsn1Checks(asn1, ad);
64 SCAsn1Free(asn1);
65 return ret == 1;
66}
67
68/**
69 * \brief This function is used to parse asn1 options passed via asn1: keyword
70 *
71 * \param asn1str pointer to the user provided asn1 options
72 *
73 * \retval pointer to `DetectAsn1Data` on success
74 * \retval NULL on failure
75 */
76static DetectAsn1Data *DetectAsn1Parse(const char *asn1str)
77{
78 DetectAsn1Data *ad = SCAsn1DetectParse(asn1str);
79
80 if (ad == NULL) {
81 SCLogError("Malformed asn1 argument: %s", asn1str);
82 }
83
84 return ad;
85}
86
87/**
88 * \brief this function is used to add the parsed asn1 data into
89 * the current signature
90 *
91 * \param de_ctx pointer to the detection engine context
92 * \param s pointer to the current signature
93 * \param asn1str pointer to the user provided asn1 options
94 *
95 * \retval 0 on success
96 * \retval -1 on failure
97 */
98static int DetectAsn1Setup(DetectEngineCtx *de_ctx, Signature *s, const char *asn1str)
99{
100 DetectAsn1Data *ad = DetectAsn1Parse(asn1str);
101 if (ad == NULL)
102 return -1;
103
106 DetectAsn1Free(de_ctx, ad);
107 return -1;
108 }
109
111 return 0;
112}
113
114/**
115 * \brief this function will free memory associated with `DetectAsn1Data`
116 *
117 * \param de_ctx pointer to the detection engine context
118 * \param ptr point to `DetectAsn1Data`
119 */
120static void DetectAsn1Free(DetectEngineCtx *de_ctx, void *ptr)
121{
122 DetectAsn1Data *ad = (DetectAsn1Data *)ptr;
123 SCAsn1DetectFree(ad);
124}
125
126#ifdef UNITTESTS
127
128/**
129 * \test DetectAsn1TestReal01 Ensure that all works together
130 */
131static int DetectAsn1TestReal01(void)
132{
133 uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01"
134 "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director"
135 "\x42\x01\x33\xA1\x0A\x43\x08""19710917"
136 "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05"
137 "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01"
138 "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111"
139 "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05"
140 "Jones""\xA0\x0A\x43\x08""19590717"
141 "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P"
142 "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director"
143 "\x42\x01\x33\xA1\x0A\x43\x08""19710917"
144 "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05"
145 "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01"
146 "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F"
147 "\x61\x11\x1A\x05""Pablo""\x1A\x01""B""\x1A\x05""Jones"
148 "\xA0\x0A\x43\x08""19590717";
149
150 uint16_t buflen = strlen((char *)buf) - 1;
151
152 /* Check the start with AA (this is to test the relative_offset keyword) */
153 uint8_t *buf2 = (uint8_t *) "AA\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01"
154 "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director"
155 "\x42\x01\x33\xA1\x0A\x43\x08""19710917"
156 "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05"
157 "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01"
158 "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111"
159 "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05"
160 "Jones""\xA0\x0A\x43\x08""19590717"
161 "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P"
162 "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director"
163 "\x42\x01\x33\xA1\x0A\x43\x08""19710917"
164 "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05"
165 "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01"
166 "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F"
167 "\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05""Jones"
168 "\xA0\x0A\x43\x08""19590717";
169
170 uint16_t buflen2 = strlen((char *)buf2) - 1;
171
172 Packet *p[2];
173
174 p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
175 FAIL_IF_NULL(p[0]);
176 p[1] = UTHBuildPacket((uint8_t *)buf2, buflen2, IPPROTO_TCP);
177 FAIL_IF_NULL(p[1]);
178
179 const char *sigs[3];
180 sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; "
181 "content:\"Pablo\"; asn1:absolute_offset 0, "
182 "oversize_length 130; sid:1;)";
183 sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; "
184 "content:\"AA\"; asn1:relative_offset 0, "
185 "oversize_length 130; sid:2;)";
186 sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; "
187 "content:\"lalala\"; asn1: oversize_length 2000; sid:3;)";
188
189 uint32_t sid[3] = {1, 2, 3};
190 uint32_t results[2][3] = {
191 /* packet 0 match sid 1 */
192 {1, 0, 0},
193 /* packet 1 match sid 2 */
194 {0, 1, 0}};
195 /* None of the packets should match sid 3 */
196 FAIL_IF_NOT(UTHGenericTest(p, 2, sigs, sid, (uint32_t *)results, 3) == 1);
197
198 UTHFreePackets(p, 2);
199 PASS;
200}
201
202/**
203 * \test DetectAsn1TestReal02 Ensure that all works together
204 */
205static int DetectAsn1TestReal02(void)
206{
207 int result = 0;
208 uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01"
209 "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director"
210 "\x42\x01\x33\xA1\x0A\x43\x08""19710917"
211 "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05"
212 "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01"
213 "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111"
214 "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05"
215 "Jones""\xA0\x0A\x43\x08""19590717"
216 "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P"
217 "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director"
218 "\x42\x01\x33\xA1\x0A\x43\x08""19710917"
219 "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05"
220 "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01"
221 "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F"
222 "\x61\x11\x1A\x05""Pablo""\x1A\x01""B""\x1A\x05""Jones"
223 "\xA0\x0A\x43\x08""19590717";
224
225 uint16_t buflen = strlen((char *)buf) - 1;
226
227 /* Check the start with AA (this is to test the relative_offset keyword) */
228 uint8_t *buf2 = (uint8_t *) "AA\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01"
229 "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director"
230 "\x42\x01\x33\xA1\x0A\x43\x08""19710917"
231 "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05"
232 "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01"
233 "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111"
234 "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05"
235 "Jones""\xA0\x0A\x43\x08""19590717"
236 "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P"
237 "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director"
238 "\x42\x01\x33\xA1\x0A\x43\x08""19710917"
239 "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05"
240 "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01"
241 "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F"
242 "\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05""Jones"
243 "\xA0\x0A\x43\x08""19590717";
244
245 uint16_t buflen2 = strlen((char *)buf2) - 1;
246
247 Packet *p[2];
248
249 p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
250 p[1] = UTHBuildPacket((uint8_t *)buf2, buflen2, IPPROTO_TCP);
251
252 if (p[0] == NULL || p[1] == NULL)
253 goto end;
254
255 const char *sigs[3];
256 sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; "
257 "content:\"Pablo\"; asn1:absolute_offset 0, "
258 "oversize_length 140; sid:1;)";
259 sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; "
260 "content:\"AA\"; asn1:relative_offset 0, "
261 "oversize_length 140; sid:2;)";
262 sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; "
263 "content:\"lalala\"; asn1: oversize_length 2000; sid:3;)";
264
265 uint32_t sid[3] = {1, 2, 3};
266
267 uint32_t results[2][3] = {
268 {0, 0, 0},
269 {0, 0, 0}};
270 /* None of the packets should match */
271
272 result = UTHGenericTest(p, 2, sigs, sid, (uint32_t *) results, 3);
273
274 UTHFreePackets(p, 2);
275end:
276 return result;
277}
278
279/**
280 * \test DetectAsn1TestReal03 Ensure that all works together
281 */
282static int DetectAsn1TestReal03(void)
283{
284 int result = 0;
285 uint8_t buf[261] = "";
286 /* universal class, primitive type, tag_num = 9 (Data type Real) */
287 buf[0] = '\x09';
288 /* length, definite form, 2 octets */
289 buf[1] = '\x82';
290 /* length is the sum of the following octets (257): */
291 buf[2] = '\x01';
292 buf[3] = '\x01';
293
294 /* Fill the content of the number */
295 uint16_t i = 4;
296 for (; i < 257;i++)
297 buf[i] = '\x05';
298
299 uint16_t buflen = 261;
300
301 /* Check the start with AA (this is to test the relative_offset keyword) */
302 uint8_t *buf2 = (uint8_t *) "AA\x03\x01\xFF";
303
304 uint16_t buflen2 = 5;
305
306 Packet *p[2] = { NULL, NULL };
307
308 p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
309 p[1] = UTHBuildPacket((uint8_t *)buf2, buflen2, IPPROTO_TCP);
310
311 if (p[0] == NULL || p[1] == NULL)
312 goto end;
313
314 const char *sigs[3];
315 /* This should match the first packet */
316 sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; "
317 "asn1:absolute_offset 0, double_overflow; sid:1;)";
318 /* This should match the second packet */
319 sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; "
320 "asn1:relative_offset 2, bitstring_overflow,"
321 "oversize_length 140; sid:2;)";
322 /* This should match no packet */
323 sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; "
324 "asn1: oversize_length 2000; sid:3;)";
325
326 uint32_t sid[3] = {1, 2, 3};
327
328 uint32_t results[2][3] = {{1, 0, 0},
329 {0, 1, 0}};
330
331 result = UTHGenericTest(p, 2, sigs, sid, (uint32_t *) results, 3);
332
333 UTHFreePackets(p, 2);
334end:
335 return result;
336}
337
338/**
339 * \test DetectAsn1TestReal04 like the real test 02, but modified the
340 * relative offset to check negative offset values, in this case
341 * start decoding from -7 bytes respect the content match "John"
342 */
343static int DetectAsn1TestReal04(void)
344{
345 int result = 0;
346 uint8_t *buf = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01"
347 "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director"
348 "\x42\x01\x33\xA1\x0A\x43\x08""19710917"
349 "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05"
350 "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01"
351 "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111"
352 "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05"
353 "Jones""\xA0\x0A\x43\x08""19590717"
354 "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P"
355 "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director"
356 "\x42\x01\x33\xA1\x0A\x43\x08""19710917"
357 "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05"
358 "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01"
359 "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F"
360 "\x61\x11\x1A\x05""Pablo""\x1A\x01""B""\x1A\x05""Jones"
361 "\xA0\x0A\x43\x08""19590717";
362
363 uint16_t buflen = strlen((char *)buf) - 1;
364
365 /* Check the start with AA (this is to test the relative_offset keyword) */
366 uint8_t *buf2 = (uint8_t *) "AA\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01"
367 "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director"
368 "\x42\x01\x33\xA1\x0A\x43\x08""19710917"
369 "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05"
370 "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01"
371 "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111"
372 "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05"
373 "Jones""\xA0\x0A\x43\x08""19590717"
374 "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P"
375 "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director"
376 "\x42\x01\x33\xA1\x0A\x43\x08""19710917"
377 "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05"
378 "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01"
379 "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F"
380 "\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05""Jones"
381 "\xA0\x0A\x43\x08""19590717";
382
383 uint16_t buflen2 = strlen((char *)buf2) - 1;
384
385 Packet *p[2];
386
387 p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
388 p[1] = UTHBuildPacket((uint8_t *)buf2, buflen2, IPPROTO_TCP);
389
390 if (p[0] == NULL || p[1] == NULL)
391 goto end;
392
393 const char *sigs[3];
394 sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; "
395 "content:\"Pablo\"; asn1:absolute_offset 0, "
396 "oversize_length 140; sid:1;)";
397 sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; "
398 "content:\"John\"; asn1:relative_offset -11, "
399 "oversize_length 140; sid:2;)";
400 sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; "
401 "content:\"lalala\"; asn1: oversize_length 2000; sid:3;)";
402
403 uint32_t sid[3] = {1, 2, 3};
404
405 uint32_t results[2][3] = {
406 {0, 0, 0},
407 {0, 0, 0}};
408 /* None of the packets should match */
409
410 result = UTHGenericTest(p, 2, sigs, sid, (uint32_t *) results, 3);
411
412 UTHFreePackets(p, 2);
413end:
414 return result;
415}
416
417/**
418 * \brief this function registers unit tests for DetectAsn1
419 */
420static void DetectAsn1RegisterTests(void)
421{
422 UtRegisterTest("DetectAsn1TestReal01", DetectAsn1TestReal01);
423 UtRegisterTest("DetectAsn1TestReal02", DetectAsn1TestReal02);
424 UtRegisterTest("DetectAsn1TestReal03", DetectAsn1TestReal03);
425 UtRegisterTest("DetectAsn1TestReal04", DetectAsn1TestReal04);
426}
427#endif /* UNITTESTS */
void DetectAsn1Register(void)
Registration function for asn1.
Definition detect-asn1.c:48
bool DetectAsn1Match(const SigMatchData *smd, const uint8_t *buffer, const uint32_t buffer_len, const uint32_t offset)
Definition detect-asn1.c:58
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
#define SIG_FLAG_REQUIRE_PACKET
Definition detect.h:254
@ DETECT_SM_LIST_PMATCH
Definition detect.h:119
DetectEngineCtx * de_ctx
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
main detection engine ctx
Definition detect.h:932
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition detect.h:351
Data needed for Match()
Definition detect.h:365
SigMatchCtx * ctx
Definition detect.h:368
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
void(* Free)(DetectEngineCtx *, void *)
Definition detect.h:1446
void(* RegisterTests)(void)
Definition detect.h:1448
const char * name
Definition detect.h:1459
Signature container.
Definition detect.h:668
uint32_t flags
Definition detect.h:669
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
uint64_t offset
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
int UTHGenericTest(Packet **pkt, int numpkts, const char *sigs[], uint32_t sids[], uint32_t *results, int numsigs)
UTHGenericTest: function that perform a generic check taking care of as maximum common unittest eleme...