Coverage Report

Created: 2026-09-28 07:39

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
263
{
69
263
    const SSLState *ssl_state = (SSLState *)txv;
70
263
    const SSLStateConnp *connp;
71
72
263
    if (flags & STREAM_TOSERVER) {
73
0
        connp = &ssl_state->client_connp;
74
263
    } else {
75
263
        connp = &ssl_state->server_connp;
76
263
    }
77
78
263
    if (TAILQ_EMPTY(&connp->certs)) {
79
32
        return false;
80
32
    }
81
82
231
    SSLCertsChain *cert;
83
231
    if (local_id == 0) {
84
79
        cert = TAILQ_FIRST(&connp->certs);
85
152
    } else {
86
        // TODO optimize ?
87
152
        cert = TAILQ_FIRST(&connp->certs);
88
380
        for (uint32_t i = 0; i < local_id; i++) {
89
228
            cert = TAILQ_NEXT(cert, next);
90
228
        }
91
152
    }
92
231
    if (cert == NULL) {
93
79
        return false;
94
79
    }
95
96
152
    *buf = cert->cert_data;
97
152
    *buf_len = cert->cert_len;
98
152
    return true;
99
231
}
100
101
/**
102
 * \brief Registration function for keyword: tls.certs
103
 */
104
void DetectTlsCertsRegister(void)
105
79
{
106
79
    sigmatch_table[DETECT_TLS_CERTS].name = "tls.certs";
107
79
    sigmatch_table[DETECT_TLS_CERTS].desc = "sticky buffer to match the TLS certificate buffer";
108
79
    sigmatch_table[DETECT_TLS_CERTS].url = "/rules/tls-keywords.html#tls-certs";
109
79
    sigmatch_table[DETECT_TLS_CERTS].Setup = DetectTlsCertsSetup;
110
#ifdef UNITTESTS
111
    sigmatch_table[DETECT_TLS_CERTS].RegisterTests = DetectTlsCertsRegisterTests;
112
#endif
113
79
    sigmatch_table[DETECT_TLS_CERTS].flags |= SIGMATCH_NOOPT;
114
79
    sigmatch_table[DETECT_TLS_CERTS].flags |= SIGMATCH_INFO_STICKY_BUFFER;
115
116
79
    DetectAppLayerMultiRegister("tls.certs", ALPROTO_TLS, SIG_FLAG_TOCLIENT,
117
79
            TLS_STATE_SERVER_CERT_DONE, TlsCertsGetData, 2);
118
79
    DetectAppLayerMultiRegister("tls.certs", ALPROTO_TLS, SIG_FLAG_TOSERVER,
119
79
            TLS_STATE_CLIENT_CERT_DONE, TlsCertsGetData, 2);
120
121
79
    DetectBufferTypeSetDescriptionByName("tls.certs", "TLS certificate");
122
123
79
    DetectBufferTypeSupportsMultiInstance("tls.certs");
124
125
79
    g_tls_certs_buffer_id = DetectBufferTypeGetByName("tls.certs");
126
79
}
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
876
{
141
876
    if (SCDetectBufferSetActiveList(de_ctx, s, g_tls_certs_buffer_id) < 0)
142
3
        return -1;
143
144
873
    if (SCDetectSignatureSetAppProto(s, ALPROTO_TLS) < 0)
145
189
        return -1;
146
147
684
    return 0;
148
873
}
149
150
static int g_tls_cert_buffer_id = 0;
151
79
#define BUFFER_NAME  "tls:server_cert_done:generic"
152
542
#define KEYWORD_ID   DETECT_TLS_CHAIN_LEN
153
79
#define KEYWORD_NAME "tls.cert_chain_len"
154
79
#define KEYWORD_DESC "match TLS certificate chain length"
155
79
#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
68
{
204
68
    SCDetectU32Free(ptr);
205
68
}
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
72
{
220
72
    if (SCDetectSignatureSetAppProto(s, ALPROTO_TLS) != 0)
221
2
        return -1;
222
223
70
    DetectU32Data *dd = DetectU32Parse(rawstr);
224
70
    if (dd == NULL) {
225
2
        SCLogError("Parsing \'%s\' failed for %s", rawstr, sigmatch_table[KEYWORD_ID].name);
226
2
        return -1;
227
2
    }
228
229
68
    if (SCSigMatchAppendSMToList(de_ctx, s, KEYWORD_ID, (SigMatchCtx *)dd, g_tls_cert_buffer_id) ==
230
68
            NULL) {
231
0
        SCDetectU32Free(dd);
232
0
        return -1;
233
0
    }
234
68
    return 0;
235
68
}
236
237
void DetectTlsCertChainLenRegister(void)
238
79
{
239
79
    sigmatch_table[KEYWORD_ID].name = KEYWORD_NAME;
240
79
    sigmatch_table[KEYWORD_ID].desc = KEYWORD_DESC;
241
79
    sigmatch_table[KEYWORD_ID].url = KEYWORD_URL;
242
79
    sigmatch_table[KEYWORD_ID].AppLayerTxMatch = DetectTLSCertChainLenMatch;
243
79
    sigmatch_table[KEYWORD_ID].Setup = DetectTLSCertChainLenSetup;
244
79
    sigmatch_table[KEYWORD_ID].Free = DetectTLSCertChainLenFree;
245
246
79
    g_tls_cert_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
247
79
}
248
249
#ifdef UNITTESTS
250
#include "tests/detect-tls-certs.c"
251
#endif