Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/detect-asn1.c
Line
Count
Source
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"
35
#include "util-unittest-helper.h"
36
#include "util-byte.h"
37
#include "util-debug.h"
38
39
static int DetectAsn1Setup (DetectEngineCtx *, Signature *, const char *);
40
#ifdef UNITTESTS
41
static void DetectAsn1RegisterTests(void);
42
#endif
43
static void DetectAsn1Free(DetectEngineCtx *, void *);
44
45
/**
46
 * \brief Registration function for asn1
47
 */
48
void DetectAsn1Register(void)
49
79
{
50
79
    sigmatch_table[DETECT_ASN1].name = "asn1";
51
79
    sigmatch_table[DETECT_ASN1].Setup = DetectAsn1Setup;
52
79
    sigmatch_table[DETECT_ASN1].Free  = DetectAsn1Free;
53
#ifdef UNITTESTS
54
    sigmatch_table[DETECT_ASN1].RegisterTests = DetectAsn1RegisterTests;
55
#endif
56
79
}
57
58
bool DetectAsn1Match(const SigMatchData *smd, const uint8_t *buffer, const uint32_t buffer_len,
59
        const uint32_t offset)
60
0
{
61
0
    const DetectAsn1Data *ad = (const DetectAsn1Data *)smd->ctx;
62
0
    Asn1 *asn1 = SCAsn1Decode(buffer, buffer_len, offset, ad);
63
0
    uint8_t ret = SCAsn1Checks(asn1, ad);
64
0
    SCAsn1Free(asn1);
65
0
    return ret == 1;
66
0
}
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
 */
76
static DetectAsn1Data *DetectAsn1Parse(const char *asn1str)
77
1.21k
{
78
1.21k
    DetectAsn1Data *ad = SCAsn1DetectParse(asn1str);
79
80
1.21k
    if (ad == NULL) {
81
775
        SCLogError("Malformed asn1 argument: %s", asn1str);
82
775
    }
83
84
1.21k
    return ad;
85
1.21k
}
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
 */
98
static int DetectAsn1Setup(DetectEngineCtx *de_ctx, Signature *s, const char *asn1str)
99
1.21k
{
100
1.21k
    DetectAsn1Data *ad = DetectAsn1Parse(asn1str);
101
1.21k
    if (ad == NULL)
102
775
        return -1;
103
104
444
    if (SCSigMatchAppendSMToList(
105
444
                de_ctx, s, DETECT_ASN1, (SigMatchCtx *)ad, DETECT_SM_LIST_PMATCH) == NULL) {
106
0
        DetectAsn1Free(de_ctx, ad);
107
0
        return -1;
108
0
    }
109
110
444
    s->flags |= SIG_FLAG_REQUIRE_PACKET;
111
444
    return 0;
112
444
}
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
 */
120
static void DetectAsn1Free(DetectEngineCtx *de_ctx, void *ptr)
121
444
{
122
444
    DetectAsn1Data *ad = (DetectAsn1Data *)ptr;
123
444
    SCAsn1DetectFree(ad);
124
444
}
125
126
#ifdef UNITTESTS
127
128
/**
129
 * \test DetectAsn1TestReal01 Ensure that all works together
130
 */
131
static 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
 */
205
static 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);
275
end:
276
    return result;
277
}
278
279
/**
280
 * \test DetectAsn1TestReal03 Ensure that all works together
281
 */
282
static 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);
334
end:
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
 */
343
static 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);
413
end:
414
    return result;
415
}
416
417
/**
418
 * \brief this function registers unit tests for DetectAsn1
419
 */
420
static void DetectAsn1RegisterTests(void)
421
{
422
    UtRegisterTest("DetectAsn1TestReal01", DetectAsn1TestReal01);
423
    UtRegisterTest("DetectAsn1TestReal02", DetectAsn1TestReal02);
424
    UtRegisterTest("DetectAsn1TestReal03", DetectAsn1TestReal03);
425
    UtRegisterTest("DetectAsn1TestReal04", DetectAsn1TestReal04);
426
}
427
#endif /* UNITTESTS */