Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/detect-tls.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2011-2012 ANSSI
3
 * Copyright (C) 2022 Open Information Security Foundation
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. The name of the author may not be used to endorse or promote products
15
 *    derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
20
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
29
/**
30
 * \file
31
 *
32
 * \author Pierre Chifflier <pierre.chifflier@ssi.gouv.fr>
33
 *
34
 * Implements the tls.* keywords
35
 */
36
37
#include "suricata-common.h"
38
#include "threads.h"
39
#include "decode.h"
40
41
#include "detect.h"
42
#include "detect-parse.h"
43
#include "detect-content.h"
44
45
#include "detect-engine.h"
46
#include "detect-engine-mpm.h"
47
#include "detect-engine-state.h"
48
49
#include "flow.h"
50
#include "flow-var.h"
51
#include "flow-util.h"
52
53
#include "util-debug.h"
54
#include "util-unittest.h"
55
#include "util-unittest-helper.h"
56
57
#include "app-layer.h"
58
59
#include "app-layer-ssl.h"
60
#include "detect-tls.h"
61
#include "detect-tls-cert-fingerprint.h"
62
63
#include "stream-tcp.h"
64
65
/**
66
 * \brief Regex for parsing "id" option, matching number or "number"
67
 */
68
69
146
#define PARSE_REGEX  "^([A-z0-9\\s\\-\\.=,\\*@]+|\"[A-z0-9\\s\\-\\.=,\\*@]+\")\\s*$"
70
73
#define PARSE_REGEX_FINGERPRINT  "^([A-z0-9\\:\\*]+|\"[A-z0-9\\:\\* ]+\")\\s*$"
71
72
static DetectParseRegex subject_parse_regex;
73
static DetectParseRegex issuerdn_parse_regex;
74
static DetectParseRegex fingerprint_parse_regex;
75
76
static int DetectTlsSubjectMatch (DetectEngineThreadCtx *,
77
        Flow *, uint8_t, void *, void *,
78
        const Signature *, const SigMatchCtx *);
79
static int DetectTlsSubjectSetup (DetectEngineCtx *, Signature *, const char *);
80
static void DetectTlsSubjectFree(DetectEngineCtx *, void *);
81
82
static int DetectTlsIssuerDNMatch (DetectEngineThreadCtx *,
83
        Flow *, uint8_t, void *, void *,
84
        const Signature *, const SigMatchCtx *);
85
static int DetectTlsIssuerDNSetup (DetectEngineCtx *, Signature *, const char *);
86
static void DetectTlsIssuerDNFree(DetectEngineCtx *, void *);
87
88
static int DetectTlsFingerprintSetup (DetectEngineCtx *, Signature *, const char *);
89
static void DetectTlsFingerprintFree(DetectEngineCtx *, void *);
90
91
static int DetectTlsStoreSetup (DetectEngineCtx *, Signature *, const char *);
92
static int DetectTlsStorePostMatch (DetectEngineThreadCtx *det_ctx,
93
        Packet *, const Signature *s, const SigMatchCtx *unused);
94
95
static int g_tls_cert_list_id = 0;
96
static int g_tls_cert_fingerprint_list_id = 0;
97
98
/**
99
 * \brief Registration function for keyword: tls.version
100
 */
101
void DetectTlsRegister (void)
102
73
{
103
73
    sigmatch_table[DETECT_AL_TLS_SUBJECT].name = "tls.subject";
104
73
    sigmatch_table[DETECT_AL_TLS_SUBJECT].desc = "match TLS/SSL certificate Subject field";
105
73
    sigmatch_table[DETECT_AL_TLS_SUBJECT].url = "/rules/tls-keywords.html#tls-subject";
106
73
    sigmatch_table[DETECT_AL_TLS_SUBJECT].AppLayerTxMatch = DetectTlsSubjectMatch;
107
73
    sigmatch_table[DETECT_AL_TLS_SUBJECT].Setup = DetectTlsSubjectSetup;
108
73
    sigmatch_table[DETECT_AL_TLS_SUBJECT].Free  = DetectTlsSubjectFree;
109
73
    sigmatch_table[DETECT_AL_TLS_SUBJECT].flags = SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION;
110
73
    sigmatch_table[DETECT_AL_TLS_SUBJECT].alternative = DETECT_AL_TLS_CERT_SUBJECT;
111
112
73
    sigmatch_table[DETECT_AL_TLS_ISSUERDN].name = "tls.issuerdn";
113
73
    sigmatch_table[DETECT_AL_TLS_ISSUERDN].desc = "match TLS/SSL certificate IssuerDN field";
114
73
    sigmatch_table[DETECT_AL_TLS_ISSUERDN].url = "/rules/tls-keywords.html#tls-issuerdn";
115
73
    sigmatch_table[DETECT_AL_TLS_ISSUERDN].AppLayerTxMatch = DetectTlsIssuerDNMatch;
116
73
    sigmatch_table[DETECT_AL_TLS_ISSUERDN].Setup = DetectTlsIssuerDNSetup;
117
73
    sigmatch_table[DETECT_AL_TLS_ISSUERDN].Free  = DetectTlsIssuerDNFree;
118
73
    sigmatch_table[DETECT_AL_TLS_ISSUERDN].flags = SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION;
119
73
    sigmatch_table[DETECT_AL_TLS_ISSUERDN].alternative = DETECT_AL_TLS_CERT_ISSUER;
120
121
73
    sigmatch_table[DETECT_AL_TLS_FINGERPRINT].name = "tls.fingerprint";
122
73
    sigmatch_table[DETECT_AL_TLS_FINGERPRINT].desc = "match TLS/SSL certificate SHA1 fingerprint";
123
73
    sigmatch_table[DETECT_AL_TLS_FINGERPRINT].url = "/rules/tls-keywords.html#tls-fingerprint";
124
73
    sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Setup = DetectTlsFingerprintSetup;
125
73
    sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Free  = DetectTlsFingerprintFree;
126
73
    sigmatch_table[DETECT_AL_TLS_FINGERPRINT].flags = SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION;
127
73
    sigmatch_table[DETECT_AL_TLS_FINGERPRINT].alternative = DETECT_AL_TLS_CERT_FINGERPRINT;
128
129
73
    sigmatch_table[DETECT_AL_TLS_STORE].name = "tls_store";
130
73
    sigmatch_table[DETECT_AL_TLS_STORE].alias = "tls.store";
131
73
    sigmatch_table[DETECT_AL_TLS_STORE].desc = "store TLS/SSL certificate on disk";
132
73
    sigmatch_table[DETECT_AL_TLS_STORE].url = "/rules/tls-keywords.html#tls-store";
133
73
    sigmatch_table[DETECT_AL_TLS_STORE].Match = DetectTlsStorePostMatch;
134
73
    sigmatch_table[DETECT_AL_TLS_STORE].Setup = DetectTlsStoreSetup;
135
73
    sigmatch_table[DETECT_AL_TLS_STORE].flags |= SIGMATCH_NOOPT;
136
137
73
    DetectSetupParseRegexes(PARSE_REGEX, &subject_parse_regex);
138
73
    DetectSetupParseRegexes(PARSE_REGEX, &issuerdn_parse_regex);
139
73
    DetectSetupParseRegexes(PARSE_REGEX_FINGERPRINT, &fingerprint_parse_regex);
140
141
73
    g_tls_cert_list_id = DetectBufferTypeRegister("tls_cert");
142
73
    g_tls_cert_fingerprint_list_id = DetectBufferTypeRegister("tls.cert_fingerprint");
143
144
73
    DetectAppLayerInspectEngineRegister2("tls_cert", ALPROTO_TLS, SIG_FLAG_TOCLIENT,
145
73
            TLS_STATE_CERT_READY, DetectEngineInspectGenericList, NULL);
146
147
73
    DetectAppLayerInspectEngineRegister2("tls_cert", ALPROTO_TLS, SIG_FLAG_TOSERVER,
148
73
            TLS_STATE_CERT_READY, DetectEngineInspectGenericList, NULL);
149
73
}
150
151
/**
152
 * \brief match the specified Subject on a tls session
153
 *
154
 * \param t pointer to thread vars
155
 * \param det_ctx pointer to the pattern matcher thread
156
 * \param p pointer to the current packet
157
 * \param m pointer to the sigmatch that we will cast into DetectTlsData
158
 *
159
 * \retval 0 no match
160
 * \retval 1 match
161
 */
162
static int DetectTlsSubjectMatch (DetectEngineThreadCtx *det_ctx,
163
        Flow *f, uint8_t flags, void *state, void *txv,
164
        const Signature *s, const SigMatchCtx *m)
165
0
{
166
0
    SCEnter();
167
168
0
    const DetectTlsData *tls_data = (const DetectTlsData *)m;
169
0
    SSLState *ssl_state = (SSLState *)state;
170
0
    if (ssl_state == NULL) {
171
0
        SCLogDebug("no tls state, no match");
172
0
        SCReturnInt(0);
173
0
    }
174
175
0
    int ret = 0;
176
177
0
    SSLStateConnp *connp = NULL;
178
0
    if (flags & STREAM_TOSERVER) {
179
0
        connp = &ssl_state->client_connp;
180
0
    } else {
181
0
        connp = &ssl_state->server_connp;
182
0
    }
183
184
0
    if (connp->cert0_subject != NULL) {
185
0
        SCLogDebug("TLS: Subject is [%s], looking for [%s]\n",
186
0
                   connp->cert0_subject, tls_data->subject);
187
188
0
        if (strstr(connp->cert0_subject, tls_data->subject) != NULL) {
189
0
            if (tls_data->flags & DETECT_CONTENT_NEGATED) {
190
0
                ret = 0;
191
0
            } else {
192
0
                ret = 1;
193
0
            }
194
0
        } else {
195
0
            if (tls_data->flags & DETECT_CONTENT_NEGATED) {
196
0
                ret = 1;
197
0
            } else {
198
0
                ret = 0;
199
0
            }
200
0
        }
201
0
    } else {
202
0
        ret = 0;
203
0
    }
204
205
0
    SCReturnInt(ret);
206
0
}
207
208
/**
209
 * \brief This function is used to parse IPV4 ip_id passed via keyword: "id"
210
 *
211
 * \param de_ctx Pointer to the detection engine context
212
 * \param str Pointer to the user provided id option
213
 *
214
 * \retval id_d pointer to DetectTlsData on success
215
 * \retval NULL on failure
216
 */
217
static DetectTlsData *DetectTlsSubjectParse (DetectEngineCtx *de_ctx, const char *str, bool negate)
218
74
{
219
74
    DetectTlsData *tls = NULL;
220
74
    size_t pcre2_len;
221
74
    const char *str_ptr;
222
74
    char *orig = NULL;
223
74
    char *tmp_str;
224
74
    uint32_t flag = 0;
225
226
74
    pcre2_match_data *match = NULL;
227
74
    int ret = DetectParsePcreExec(&subject_parse_regex, &match, str, 0, 0);
228
74
    if (ret != 2) {
229
1
        SCLogError("invalid tls.subject option");
230
1
        goto error;
231
1
    }
232
233
73
    if (negate)
234
1
        flag = DETECT_CONTENT_NEGATED;
235
236
73
    int res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len);
237
73
    if (res < 0) {
238
0
        SCLogError("pcre2_substring_get_bynumber failed");
239
0
        goto error;
240
0
    }
241
242
    /* We have a correct id option */
243
73
    tls = SCMalloc(sizeof(DetectTlsData));
244
73
    if (unlikely(tls == NULL))
245
0
        goto error;
246
73
    tls->subject = NULL;
247
73
    tls->flags = flag;
248
249
73
    orig = SCStrdup((char*)str_ptr);
250
73
    if (unlikely(orig == NULL)) {
251
0
        goto error;
252
0
    }
253
73
    pcre2_substring_free((PCRE2_UCHAR *)str_ptr);
254
255
73
    tmp_str=orig;
256
257
    /* Let's see if we need to escape "'s */
258
73
    if (tmp_str[0] == '"') {
259
0
        tmp_str[strlen(tmp_str) - 1] = '\0';
260
0
        tmp_str += 1;
261
0
    }
262
263
73
    tls->subject = SCStrdup(tmp_str);
264
73
    if (unlikely(tls->subject == NULL)) {
265
0
        goto error;
266
0
    }
267
268
73
    pcre2_match_data_free(match);
269
73
    SCFree(orig);
270
271
73
    SCLogDebug("will look for TLS subject %s", tls->subject);
272
273
73
    return tls;
274
275
1
error:
276
1
    if (match) {
277
1
        pcre2_match_data_free(match);
278
1
    }
279
1
    if (orig != NULL)
280
0
        SCFree(orig);
281
1
    if (tls != NULL)
282
0
        DetectTlsSubjectFree(de_ctx, tls);
283
1
    return NULL;
284
285
73
}
286
287
/**
288
 * \brief this function is used to add the parsed "id" option
289
 * \brief into the current signature
290
 *
291
 * \param de_ctx pointer to the Detection Engine Context
292
 * \param s pointer to the Current Signature
293
 * \param idstr pointer to the user provided "id" option
294
 *
295
 * \retval 0 on Success
296
 * \retval -1 on Failure
297
 */
298
static int DetectTlsSubjectSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
299
3
{
300
3
    DetectTlsData *tls = NULL;
301
3
    SigMatch *sm = NULL;
302
303
3
    if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0)
304
1
        return -1;
305
306
2
    tls = DetectTlsSubjectParse(de_ctx, str, s->init_data->negated);
307
2
    if (tls == NULL)
308
0
        goto error;
309
310
    /* Okay so far so good, lets get this into a SigMatch
311
     * and put it in the Signature. */
312
2
    sm = SigMatchAlloc();
313
2
    if (sm == NULL)
314
0
        goto error;
315
316
2
    sm->type = DETECT_AL_TLS_SUBJECT;
317
2
    sm->ctx = (void *)tls;
318
319
2
    SigMatchAppendSMToList(s, sm, g_tls_cert_list_id);
320
2
    return 0;
321
322
0
error:
323
0
    if (tls != NULL)
324
0
        DetectTlsSubjectFree(de_ctx, tls);
325
0
    if (sm != NULL)
326
0
        SCFree(sm);
327
0
    return -1;
328
329
2
}
330
331
/**
332
 * \brief this function will free memory associated with DetectTlsData
333
 *
334
 * \param id_d pointer to DetectTlsData
335
 */
336
static void DetectTlsSubjectFree(DetectEngineCtx *de_ctx, void *ptr)
337
73
{
338
73
    DetectTlsData *id_d = (DetectTlsData *)ptr;
339
73
    if (ptr == NULL)
340
0
        return;
341
73
    if (id_d->subject != NULL)
342
73
        SCFree(id_d->subject);
343
73
    SCFree(id_d);
344
73
}
345
346
/**
347
 * \brief match the specified IssuerDN on a tls session
348
 *
349
 * \param t pointer to thread vars
350
 * \param det_ctx pointer to the pattern matcher thread
351
 * \param p pointer to the current packet
352
 * \param m pointer to the sigmatch that we will cast into DetectTlsData
353
 *
354
 * \retval 0 no match
355
 * \retval 1 match
356
 */
357
static int DetectTlsIssuerDNMatch (DetectEngineThreadCtx *det_ctx,
358
        Flow *f, uint8_t flags, void *state, void *txv,
359
        const Signature *s, const SigMatchCtx *m)
360
0
{
361
0
    SCEnter();
362
363
0
    const DetectTlsData *tls_data = (const DetectTlsData *)m;
364
0
    SSLState *ssl_state = (SSLState *)state;
365
0
    if (ssl_state == NULL) {
366
0
        SCLogDebug("no tls state, no match");
367
0
        SCReturnInt(0);
368
0
    }
369
370
0
    int ret = 0;
371
372
0
    SSLStateConnp *connp = NULL;
373
0
    if (flags & STREAM_TOSERVER) {
374
0
        connp = &ssl_state->client_connp;
375
0
    } else {
376
0
        connp = &ssl_state->server_connp;
377
0
    }
378
379
0
    if (connp->cert0_issuerdn != NULL) {
380
0
        SCLogDebug("TLS: IssuerDN is [%s], looking for [%s]\n",
381
0
                   connp->cert0_issuerdn, tls_data->issuerdn);
382
383
0
        if (strstr(connp->cert0_issuerdn, tls_data->issuerdn) != NULL) {
384
0
            if (tls_data->flags & DETECT_CONTENT_NEGATED) {
385
0
                ret = 0;
386
0
            } else {
387
0
                ret = 1;
388
0
            }
389
0
        } else {
390
0
            if (tls_data->flags & DETECT_CONTENT_NEGATED) {
391
0
                ret = 1;
392
0
            } else {
393
0
                ret = 0;
394
0
            }
395
0
        }
396
0
    } else {
397
0
        ret = 0;
398
0
    }
399
400
0
    SCReturnInt(ret);
401
0
}
402
403
/**
404
 * \brief This function is used to parse IPV4 ip_id passed via keyword: "id"
405
 *
406
 * \param de_ctx Pointer to the detection engine context
407
 * \param str Pointer to the user provided id option
408
 *
409
 * \retval id_d pointer to DetectTlsData on success
410
 * \retval NULL on failure
411
 */
412
static DetectTlsData *DetectTlsIssuerDNParse(DetectEngineCtx *de_ctx, const char *str, bool negate)
413
7.13k
{
414
7.13k
    DetectTlsData *tls = NULL;
415
7.13k
    size_t pcre2_len;
416
7.13k
    const char *str_ptr;
417
7.13k
    char *orig = NULL;
418
7.13k
    char *tmp_str;
419
7.13k
    uint32_t flag = 0;
420
421
7.13k
    pcre2_match_data *match = NULL;
422
7.13k
    int ret = DetectParsePcreExec(&issuerdn_parse_regex, &match, str, 0, 0);
423
7.13k
    if (ret != 2) {
424
264
        SCLogError("invalid tls.issuerdn option");
425
264
        goto error;
426
264
    }
427
428
6.87k
    if (negate)
429
0
        flag = DETECT_CONTENT_NEGATED;
430
431
6.87k
    int res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len);
432
6.87k
    if (res < 0) {
433
0
        SCLogError("pcre2_substring_get_bynumber failed");
434
0
        goto error;
435
0
    }
436
437
    /* We have a correct id option */
438
6.87k
    tls = SCMalloc(sizeof(DetectTlsData));
439
6.87k
    if (unlikely(tls == NULL))
440
0
        goto error;
441
6.87k
    tls->issuerdn = NULL;
442
6.87k
    tls->flags = flag;
443
444
6.87k
    orig = SCStrdup((char*)str_ptr);
445
6.87k
    if (unlikely(orig == NULL)) {
446
0
        goto error;
447
0
    }
448
6.87k
    pcre2_substring_free((PCRE2_UCHAR *)str_ptr);
449
450
6.87k
    tmp_str=orig;
451
452
    /* Let's see if we need to escape "'s */
453
6.87k
    if (tmp_str[0] == '"')
454
475
    {
455
475
        tmp_str[strlen(tmp_str) - 1] = '\0';
456
475
        tmp_str += 1;
457
475
    }
458
459
6.87k
    tls->issuerdn = SCStrdup(tmp_str);
460
6.87k
    if (unlikely(tls->issuerdn == NULL)) {
461
0
        goto error;
462
0
    }
463
464
6.87k
    SCFree(orig);
465
466
6.87k
    pcre2_match_data_free(match);
467
6.87k
    SCLogDebug("Will look for TLS issuerdn %s", tls->issuerdn);
468
469
6.87k
    return tls;
470
471
264
error:
472
264
    if (match) {
473
264
        pcre2_match_data_free(match);
474
264
    }
475
264
    if (orig != NULL)
476
0
        SCFree(orig);
477
264
    if (tls != NULL)
478
0
        DetectTlsIssuerDNFree(de_ctx, tls);
479
264
    return NULL;
480
481
6.87k
}
482
483
/**
484
 * \brief this function is used to add the parsed "id" option
485
 * \brief into the current signature
486
 *
487
 * \param de_ctx pointer to the Detection Engine Context
488
 * \param s pointer to the Current Signature
489
 * \param idstr pointer to the user provided "id" option
490
 *
491
 * \retval 0 on Success
492
 * \retval -1 on Failure
493
 */
494
static int DetectTlsIssuerDNSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
495
3.09k
{
496
3.09k
    DetectTlsData *tls = NULL;
497
3.09k
    SigMatch *sm = NULL;
498
499
3.09k
    if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0)
500
1
        return -1;
501
502
3.09k
    tls = DetectTlsIssuerDNParse(de_ctx, str, s->init_data->negated);
503
3.09k
    if (tls == NULL)
504
79
        goto error;
505
506
    /* Okay so far so good, lets get this into a SigMatch
507
     * and put it in the Signature. */
508
3.01k
    sm = SigMatchAlloc();
509
3.01k
    if (sm == NULL)
510
0
        goto error;
511
512
3.01k
    sm->type = DETECT_AL_TLS_ISSUERDN;
513
3.01k
    sm->ctx = (void *)tls;
514
515
3.01k
    SigMatchAppendSMToList(s, sm, g_tls_cert_list_id);
516
3.01k
    return 0;
517
518
79
error:
519
79
    if (tls != NULL)
520
0
        DetectTlsIssuerDNFree(de_ctx, tls);
521
79
    if (sm != NULL)
522
0
        SCFree(sm);
523
79
    return -1;
524
525
3.01k
}
526
527
/**
528
 * \brief this function will free memory associated with DetectTlsData
529
 *
530
 * \param id_d pointer to DetectTlsData
531
 */
532
static void DetectTlsIssuerDNFree(DetectEngineCtx *de_ctx, void *ptr)
533
6.87k
{
534
6.87k
    DetectTlsData *id_d = (DetectTlsData *)ptr;
535
6.87k
    SCFree(id_d->issuerdn);
536
6.87k
    SCFree(id_d);
537
6.87k
}
538
539
/**
540
 * \brief This function is used to parse fingerprint passed via keyword: "fingerprint"
541
 *
542
 * \param de_ctx Pointer to the detection engine context
543
 * \param str Pointer to the user provided fingerprint option
544
 *
545
 * \retval pointer to DetectTlsData on success
546
 * \retval NULL on failure
547
 */
548
549
/**
550
 * \brief this function is used to add the parsed "fingerprint" option
551
 * \brief into the current signature
552
 *
553
 * \param de_ctx pointer to the Detection Engine Context
554
 * \param s pointer to the Current Signature
555
 * \param id pointer to the user provided "fingerprint" option
556
 *
557
 * \retval 0 on Success
558
 * \retval -1 on Failure
559
 */
560
static int DetectTlsFingerprintSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
561
1.43k
{
562
1.43k
    if (DetectContentSetup(de_ctx, s, str) < 0) {
563
74
        return -1;
564
74
    }
565
566
1.35k
    if (DetectEngineContentModifierBufferSetup(de_ctx, s, NULL, DETECT_AL_TLS_CERT_FINGERPRINT,
567
1.35k
                g_tls_cert_fingerprint_list_id, ALPROTO_TLS) < 0)
568
6
        return -1;
569
570
1.35k
    return 0;
571
1.35k
}
572
573
/**
574
 * \brief this function will free memory associated with DetectTlsData
575
 *
576
 * \param pointer to DetectTlsData
577
 */
578
static void DetectTlsFingerprintFree(DetectEngineCtx *de_ctx, void *ptr)
579
0
{
580
0
    DetectTlsData *id_d = (DetectTlsData *)ptr;
581
0
    SCFree(id_d);
582
0
}
583
584
/**
585
 * \brief this function is used to add the parsed "store" option
586
 * \brief into the current signature
587
 *
588
 * \param de_ctx pointer to the Detection Engine Context
589
 * \param s pointer to the Current Signature
590
 * \param idstr pointer to the user provided "store" option
591
 *
592
 * \retval 0 on Success
593
 * \retval -1 on Failure
594
 */
595
static int DetectTlsStoreSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
596
498
{
597
498
    SigMatch *sm = NULL;
598
599
498
    if (DetectSignatureSetAppProto(s, ALPROTO_TLS) != 0)
600
181
        return -1;
601
602
317
    sm = SigMatchAlloc();
603
317
    if (sm == NULL)
604
0
        return -1;
605
606
317
    sm->type = DETECT_AL_TLS_STORE;
607
317
    s->flags |= SIG_FLAG_TLSSTORE;
608
609
317
    SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH);
610
317
    return 0;
611
317
}
612
613
/** \warning modifies Flow::alstate */
614
static int DetectTlsStorePostMatch (DetectEngineThreadCtx *det_ctx,
615
        Packet *p, const Signature *s, const SigMatchCtx *unused)
616
2
{
617
2
    SCEnter();
618
619
2
    if (p->flow == NULL)
620
0
        return 0;
621
622
2
    SSLState *ssl_state = FlowGetAppState(p->flow);
623
2
    if (ssl_state == NULL) {
624
0
        SCLogDebug("no tls state, no match");
625
0
        SCReturnInt(0);
626
0
    }
627
628
2
    SSLStateConnp *connp;
629
630
2
    if (PKT_IS_TOSERVER(p)) {
631
1
        connp = &ssl_state->client_connp;
632
1
    } else {
633
1
        connp = &ssl_state->server_connp;
634
1
    }
635
636
2
    connp->cert_log_flag |= SSL_TLS_LOG_PEM;
637
2
    SCReturnInt(1);
638
2
}