Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/detect-tls-certs.c
Line
Count
Source
1
/* Copyright (C) 2019-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
20
 *
21
 * \author Mats Klepsland <mats.klepsland@gmail.com>
22
 *
23
 * Implements support for tls.certs keyword.
24
 */
25
26
#include "suricata-common.h"
27
#include "threads.h"
28
#include "decode.h"
29
#include "detect.h"
30
31
#include "detect-parse.h"
32
#include "detect-engine.h"
33
#include "detect-engine-buffer.h"
34
#include "detect-engine-mpm.h"
35
#include "detect-engine-prefilter.h"
36
#include "detect-engine-content-inspection.h"
37
#include "detect-content.h"
38
#include "detect-pcre.h"
39
#include "detect-tls-certs.h"
40
#include "detect-engine-uint.h"
41
42
#include "flow.h"
43
#include "flow-util.h"
44
#include "flow-var.h"
45
46
#include "util-debug.h"
47
#include "util-spm.h"
48
#include "util-print.h"
49
50
#include "stream-tcp.h"
51
52
#include "app-layer.h"
53
#include "app-layer-ssl.h"
54
55
#include "util-profiling.h"
56
#include "util-unittest.h"
57
#include "util-unittest-helper.h"
58
59
static int DetectTlsCertsSetup(DetectEngineCtx *, Signature *, const char *);
60
#ifdef UNITTESTS
61
static void DetectTlsCertsRegisterTests(void);
62
#endif
63
64
static int g_tls_certs_buffer_id = 0;
65
66
static bool TlsCertsGetData(DetectEngineThreadCtx *det_ctx, const void *txv, const uint8_t flags,
67
        uint32_t local_id, const uint8_t **buf, uint32_t *buf_len)
68
180
{
69
180
    const SSLState *ssl_state = (SSLState *)txv;
70
180
    const SSLStateConnp *connp;
71
72
180
    if (flags & STREAM_TOSERVER) {
73
0
        connp = &ssl_state->client_connp;
74
180
    } else {
75
180
        connp = &ssl_state->server_connp;
76
180
    }
77
78
180
    if (TAILQ_EMPTY(&connp->certs)) {
79
63
        return false;
80
63
    }
81
82
117
    SSLCertsChain *cert;
83
117
    if (local_id == 0) {
84
40
        cert = TAILQ_FIRST(&connp->certs);
85
77
    } else {
86
        // TODO optimize ?
87
77
        cert = TAILQ_FIRST(&connp->certs);
88
191
        for (uint32_t i = 0; i < local_id; i++) {
89
114
            cert = TAILQ_NEXT(cert, next);
90
114
        }
91
77
    }
92
117
    if (cert == NULL) {
93
40
        return false;
94
40
    }
95
96
77
    *buf = cert->cert_data;
97
77
    *buf_len = cert->cert_len;
98
77
    return true;
99
117
}
100
101
/**
102
 * \brief Registration function for keyword: tls.certs
103
 */
104
void DetectTlsCertsRegister(void)
105
12
{
106
12
    sigmatch_table[DETECT_TLS_CERTS].name = "tls.certs";
107
12
    sigmatch_table[DETECT_TLS_CERTS].desc = "sticky buffer to match the TLS certificate buffer";
108
12
    sigmatch_table[DETECT_TLS_CERTS].url = "/rules/tls-keywords.html#tls-certs";
109
12
    sigmatch_table[DETECT_TLS_CERTS].Setup = DetectTlsCertsSetup;
110
#ifdef UNITTESTS
111
    sigmatch_table[DETECT_TLS_CERTS].RegisterTests = DetectTlsCertsRegisterTests;
112
#endif
113
12
    sigmatch_table[DETECT_TLS_CERTS].flags |= SIGMATCH_NOOPT;
114
12
    sigmatch_table[DETECT_TLS_CERTS].flags |= SIGMATCH_INFO_STICKY_BUFFER;
115
116
12
    DetectAppLayerMultiRegister("tls.certs", ALPROTO_TLS, SIG_FLAG_TOCLIENT,
117
12
            TLS_STATE_SERVER_CERT_DONE, TlsCertsGetData, 2);
118
12
    DetectAppLayerMultiRegister("tls.certs", ALPROTO_TLS, SIG_FLAG_TOSERVER,
119
12
            TLS_STATE_CLIENT_CERT_DONE, TlsCertsGetData, 2);
120
121
12
    DetectBufferTypeSetDescriptionByName("tls.certs", "TLS certificate");
122
123
12
    DetectBufferTypeSupportsMultiInstance("tls.certs");
124
125
12
    g_tls_certs_buffer_id = DetectBufferTypeGetByName("tls.certs");
126
12
}
127
128
/**
129
 * \brief This function setup the tls.certs modifier keyword
130
 *
131
 * \param de_ctx Pointer to the Detect Engine Context
132
 * \param s      Pointer to the Signature to which the keyword belongs
133
 * \param str    Should hold an empty string always
134
 *
135
 * \retval  0 On success
136
 * \retval -1 On failure
137
 */
138
static int DetectTlsCertsSetup(DetectEngineCtx *de_ctx, Signature *s,
139
                               const char *str)
140
1.90k
{
141
1.90k
    if (SCDetectBufferSetActiveList(de_ctx, s, g_tls_certs_buffer_id) < 0)
142
3
        return -1;
143
144
1.89k
    if (SCDetectSignatureSetAppProto(s, ALPROTO_TLS) < 0)
145
441
        return -1;
146
147
1.45k
    return 0;
148
1.89k
}
149
150
static int g_tls_cert_buffer_id = 0;
151
12
#define BUFFER_NAME  "tls:server_cert_done:generic"
152
147
#define KEYWORD_ID   DETECT_TLS_CHAIN_LEN
153
12
#define KEYWORD_NAME "tls.cert_chain_len"
154
12
#define KEYWORD_DESC "match TLS certificate chain length"
155
12
#define KEYWORD_URL  "/rules/tls-keywords.html#tls-cert-chain-len"
156
157
/**
158
 * \internal
159
 * \brief Function to match cert chain length in TLS
160
 *
161
 * \param t       Pointer to thread vars.
162
 * \param det_ctx Pointer to the pattern matcher thread.
163
 * \param f       Pointer to the current flow.
164
 * \param flags   Flags.
165
 * \param state   App layer state.
166
 * \param s       Pointer to the Signature.
167
 * \param m       Pointer to the sigmatch that we will cast into
168
 *                DetectU64Data.
169
 *
170
 * \retval 0 no match.
171
 * \retval 1 match.
172
 */
173
static int DetectTLSCertChainLenMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags,
174
        void *state, void *txv, const Signature *s, const SigMatchCtx *ctx)
175
0
{
176
0
    SCEnter();
177
178
0
    SSLState *ssl_state = state;
179
0
    if (flags & STREAM_TOCLIENT) {
180
0
        SSLStateConnp *connp = &ssl_state->server_connp;
181
0
        uint32_t cnt = 0;
182
0
        SSLCertsChain *cert;
183
0
        TAILQ_FOREACH (cert, &connp->certs, next) {
184
0
            cnt++;
185
0
        }
186
0
        SCLogDebug("%u certs in chain", cnt);
187
188
0
        const DetectU32Data *dd = (const DetectU32Data *)ctx;
189
0
        if (DetectU32Match(cnt, dd)) {
190
0
            SCReturnInt(1);
191
0
        }
192
0
    }
193
0
    SCReturnInt(0);
194
0
}
195
196
/**
197
 * \internal
198
 * \brief Function to free memory associated with DetectU64Data.
199
 *
200
 * \param de_ptr Pointer to DetectU64Data.
201
 */
202
static void DetectTLSCertChainLenFree(DetectEngineCtx *de_ctx, void *ptr)
203
75
{
204
75
    SCDetectU32Free(ptr);
205
75
}
206
207
/**
208
 * \brief Function to add the parsed tls cert chain len field into the current signature.
209
 *
210
 * \param de_ctx Pointer to the Detection Engine Context.
211
 * \param s      Pointer to the Current Signature.
212
 * \param rawstr Pointer to the user provided flags options.
213
 * \param type   Defines if this is notBefore or notAfter.
214
 *
215
 * \retval 0 on Success.
216
 * \retval -1 on Failure.
217
 */
218
static int DetectTLSCertChainLenSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
219
81
{
220
81
    if (SCDetectSignatureSetAppProto(s, ALPROTO_TLS) != 0)
221
2
        return -1;
222
223
79
    DetectU32Data *dd = DetectU32Parse(rawstr);
224
79
    if (dd == NULL) {
225
4
        SCLogError("Parsing \'%s\' failed for %s", rawstr, sigmatch_table[KEYWORD_ID].name);
226
4
        return -1;
227
4
    }
228
229
75
    if (SCSigMatchAppendSMToList(de_ctx, s, KEYWORD_ID, (SigMatchCtx *)dd, g_tls_cert_buffer_id) ==
230
75
            NULL) {
231
0
        SCDetectU32Free(dd);
232
0
        return -1;
233
0
    }
234
75
    return 0;
235
75
}
236
237
void DetectTlsCertChainLenRegister(void)
238
12
{
239
12
    sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME;
240
12
    sigmatch_table[KEYWORD_ID].desc = KEYWORD_DESC;
241
12
    sigmatch_table[KEYWORD_ID].url = KEYWORD_URL;
242
12
    sigmatch_table[KEYWORD_ID].AppLayerTxMatch = DetectTLSCertChainLenMatch;
243
12
    sigmatch_table[KEYWORD_ID].Setup = DetectTLSCertChainLenSetup;
244
12
    sigmatch_table[KEYWORD_ID].Free = DetectTLSCertChainLenFree;
245
246
12
    g_tls_cert_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
247
12
}
248
249
#ifdef UNITTESTS
250
#include "tests/detect-tls-certs.c"
251
#endif