/src/suricata8/src/detect-tls.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2011-2012 ANSSI |
3 | | * Copyright (C) 2022-2025 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 | 158 | #define PARSE_REGEX "^([A-z0-9\\s\\-\\.=,\\*@]+|\"[A-z0-9\\s\\-\\.=,\\*@]+\")\\s*$" |
70 | 79 | #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 | 79 | { |
103 | 79 | sigmatch_table[DETECT_TLS_SUBJECT].name = "tls.subject"; |
104 | 79 | sigmatch_table[DETECT_TLS_SUBJECT].desc = "match TLS/SSL certificate Subject field"; |
105 | 79 | sigmatch_table[DETECT_TLS_SUBJECT].url = "/rules/tls-keywords.html#tls-subject"; |
106 | 79 | sigmatch_table[DETECT_TLS_SUBJECT].AppLayerTxMatch = DetectTlsSubjectMatch; |
107 | 79 | sigmatch_table[DETECT_TLS_SUBJECT].Setup = DetectTlsSubjectSetup; |
108 | 79 | sigmatch_table[DETECT_TLS_SUBJECT].Free = DetectTlsSubjectFree; |
109 | 79 | sigmatch_table[DETECT_TLS_SUBJECT].flags = SIGMATCH_QUOTES_MANDATORY | SIGMATCH_HANDLE_NEGATION; |
110 | 79 | sigmatch_table[DETECT_TLS_SUBJECT].alternative = DETECT_TLS_CERT_SUBJECT; |
111 | | |
112 | 79 | sigmatch_table[DETECT_TLS_ISSUERDN].name = "tls.issuerdn"; |
113 | 79 | sigmatch_table[DETECT_TLS_ISSUERDN].desc = "match TLS/SSL certificate IssuerDN field"; |
114 | 79 | sigmatch_table[DETECT_TLS_ISSUERDN].url = "/rules/tls-keywords.html#tls-issuerdn"; |
115 | 79 | sigmatch_table[DETECT_TLS_ISSUERDN].AppLayerTxMatch = DetectTlsIssuerDNMatch; |
116 | 79 | sigmatch_table[DETECT_TLS_ISSUERDN].Setup = DetectTlsIssuerDNSetup; |
117 | 79 | sigmatch_table[DETECT_TLS_ISSUERDN].Free = DetectTlsIssuerDNFree; |
118 | 79 | sigmatch_table[DETECT_TLS_ISSUERDN].flags = |
119 | 79 | SIGMATCH_QUOTES_MANDATORY | SIGMATCH_HANDLE_NEGATION; |
120 | 79 | sigmatch_table[DETECT_TLS_ISSUERDN].alternative = DETECT_TLS_CERT_ISSUER; |
121 | | |
122 | 79 | sigmatch_table[DETECT_TLS_FINGERPRINT].name = "tls.fingerprint"; |
123 | 79 | sigmatch_table[DETECT_TLS_FINGERPRINT].desc = "match TLS/SSL certificate SHA1 fingerprint"; |
124 | 79 | sigmatch_table[DETECT_TLS_FINGERPRINT].url = "/rules/tls-keywords.html#tls-fingerprint"; |
125 | 79 | sigmatch_table[DETECT_TLS_FINGERPRINT].Setup = DetectTlsFingerprintSetup; |
126 | 79 | sigmatch_table[DETECT_TLS_FINGERPRINT].Free = DetectTlsFingerprintFree; |
127 | 79 | sigmatch_table[DETECT_TLS_FINGERPRINT].flags = |
128 | 79 | SIGMATCH_QUOTES_MANDATORY | SIGMATCH_HANDLE_NEGATION; |
129 | 79 | sigmatch_table[DETECT_TLS_FINGERPRINT].alternative = DETECT_TLS_CERT_FINGERPRINT; |
130 | | |
131 | 79 | sigmatch_table[DETECT_TLS_STORE].name = "tls_store"; |
132 | 79 | sigmatch_table[DETECT_TLS_STORE].alias = "tls.store"; |
133 | 79 | sigmatch_table[DETECT_TLS_STORE].desc = "store TLS/SSL certificate on disk"; |
134 | 79 | sigmatch_table[DETECT_TLS_STORE].url = "/rules/tls-keywords.html#tls-store"; |
135 | 79 | sigmatch_table[DETECT_TLS_STORE].Match = DetectTlsStorePostMatch; |
136 | 79 | sigmatch_table[DETECT_TLS_STORE].Setup = DetectTlsStoreSetup; |
137 | 79 | sigmatch_table[DETECT_TLS_STORE].flags |= SIGMATCH_NOOPT; |
138 | | |
139 | 79 | DetectSetupParseRegexes(PARSE_REGEX, &subject_parse_regex); |
140 | 79 | DetectSetupParseRegexes(PARSE_REGEX, &issuerdn_parse_regex); |
141 | 79 | DetectSetupParseRegexes(PARSE_REGEX_FINGERPRINT, &fingerprint_parse_regex); |
142 | | |
143 | 79 | g_tls_cert_list_id = DetectBufferTypeRegister("tls_cert"); |
144 | 79 | g_tls_cert_fingerprint_list_id = DetectBufferTypeRegister("tls.cert_fingerprint"); |
145 | | |
146 | 79 | DetectAppLayerInspectEngineRegister("tls_cert", ALPROTO_TLS, SIG_FLAG_TOCLIENT, |
147 | 79 | TLS_STATE_SERVER_CERT_DONE, DetectEngineInspectGenericList, NULL); |
148 | | |
149 | 79 | DetectAppLayerInspectEngineRegister("tls_cert", ALPROTO_TLS, SIG_FLAG_TOSERVER, |
150 | 79 | TLS_STATE_CLIENT_CERT_DONE, DetectEngineInspectGenericList, NULL); |
151 | 79 | } |
152 | | |
153 | | /** |
154 | | * \brief match the specified Subject on a tls session |
155 | | * |
156 | | * \param t pointer to thread vars |
157 | | * \param det_ctx pointer to the pattern matcher thread |
158 | | * \param p pointer to the current packet |
159 | | * \param m pointer to the sigmatch that we will cast into DetectTlsData |
160 | | * |
161 | | * \retval 0 no match |
162 | | * \retval 1 match |
163 | | */ |
164 | | static int DetectTlsSubjectMatch (DetectEngineThreadCtx *det_ctx, |
165 | | Flow *f, uint8_t flags, void *state, void *txv, |
166 | | const Signature *s, const SigMatchCtx *m) |
167 | 0 | { |
168 | 0 | SCEnter(); |
169 | |
|
170 | 0 | const DetectTlsData *tls_data = (const DetectTlsData *)m; |
171 | 0 | SSLState *ssl_state = (SSLState *)state; |
172 | 0 | if (ssl_state == NULL) { |
173 | 0 | SCLogDebug("no tls state, no match"); |
174 | 0 | SCReturnInt(0); |
175 | 0 | } |
176 | | |
177 | 0 | int ret = 0; |
178 | |
|
179 | 0 | SSLStateConnp *connp = NULL; |
180 | 0 | if (flags & STREAM_TOSERVER) { |
181 | 0 | connp = &ssl_state->client_connp; |
182 | 0 | } else { |
183 | 0 | connp = &ssl_state->server_connp; |
184 | 0 | } |
185 | |
|
186 | 0 | if (connp->cert0_subject != NULL) { |
187 | 0 | SCLogDebug("TLS: Subject is [%s], looking for [%s]\n", |
188 | 0 | connp->cert0_subject, tls_data->subject); |
189 | |
|
190 | 0 | if (SpmSearch(connp->cert0_subject, connp->cert0_subject_len, |
191 | 0 | (const uint8_t *)tls_data->subject, |
192 | 0 | (uint16_t)strlen(tls_data->subject)) != NULL) { |
193 | 0 | if (tls_data->flags & DETECT_CONTENT_NEGATED) { |
194 | 0 | ret = 0; |
195 | 0 | } else { |
196 | 0 | ret = 1; |
197 | 0 | } |
198 | 0 | } else { |
199 | 0 | if (tls_data->flags & DETECT_CONTENT_NEGATED) { |
200 | 0 | ret = 1; |
201 | 0 | } else { |
202 | 0 | ret = 0; |
203 | 0 | } |
204 | 0 | } |
205 | 0 | } else { |
206 | 0 | ret = 0; |
207 | 0 | } |
208 | |
|
209 | 0 | SCReturnInt(ret); |
210 | 0 | } |
211 | | |
212 | | /** |
213 | | * \brief This function is used to parse IPV4 ip_id passed via keyword: "id" |
214 | | * |
215 | | * \param de_ctx Pointer to the detection engine context |
216 | | * \param str Pointer to the user provided id option |
217 | | * |
218 | | * \retval id_d pointer to DetectTlsData on success |
219 | | * \retval NULL on failure |
220 | | */ |
221 | | static DetectTlsData *DetectTlsSubjectParse (DetectEngineCtx *de_ctx, const char *str, bool negate) |
222 | 93 | { |
223 | 93 | DetectTlsData *tls = NULL; |
224 | 93 | size_t pcre2_len; |
225 | 93 | const char *str_ptr; |
226 | 93 | char *orig = NULL; |
227 | 93 | char *tmp_str; |
228 | 93 | uint32_t flag = 0; |
229 | | |
230 | 93 | pcre2_match_data *match = NULL; |
231 | 93 | int ret = DetectParsePcreExec(&subject_parse_regex, &match, str, 0, 0); |
232 | 93 | if (ret != 2) { |
233 | 2 | SCLogError("invalid tls.subject option"); |
234 | 2 | goto error; |
235 | 2 | } |
236 | | |
237 | 91 | if (negate) |
238 | 1 | flag = DETECT_CONTENT_NEGATED; |
239 | | |
240 | 91 | int res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); |
241 | 91 | if (res < 0) { |
242 | 0 | SCLogError("pcre2_substring_get_bynumber failed"); |
243 | 0 | goto error; |
244 | 0 | } |
245 | | |
246 | | /* We have a correct id option */ |
247 | 91 | tls = SCMalloc(sizeof(DetectTlsData)); |
248 | 91 | if (unlikely(tls == NULL)) |
249 | 0 | goto error; |
250 | 91 | tls->subject = NULL; |
251 | 91 | tls->flags = flag; |
252 | | |
253 | 91 | orig = SCStrdup((char*)str_ptr); |
254 | 91 | if (unlikely(orig == NULL)) { |
255 | 0 | goto error; |
256 | 0 | } |
257 | 91 | pcre2_substring_free((PCRE2_UCHAR *)str_ptr); |
258 | | |
259 | 91 | tmp_str=orig; |
260 | | |
261 | | /* Let's see if we need to escape "'s */ |
262 | 91 | if (tmp_str[0] == '"') { |
263 | 0 | tmp_str[strlen(tmp_str) - 1] = '\0'; |
264 | 0 | tmp_str += 1; |
265 | 0 | } |
266 | | |
267 | 91 | tls->subject = SCStrdup(tmp_str); |
268 | 91 | if (unlikely(tls->subject == NULL)) { |
269 | 0 | goto error; |
270 | 0 | } |
271 | | |
272 | 91 | pcre2_match_data_free(match); |
273 | 91 | SCFree(orig); |
274 | | |
275 | 91 | SCLogDebug("will look for TLS subject %s", tls->subject); |
276 | | |
277 | 91 | return tls; |
278 | | |
279 | 2 | error: |
280 | 2 | if (match) { |
281 | 2 | pcre2_match_data_free(match); |
282 | 2 | } |
283 | 2 | if (orig != NULL) |
284 | 0 | SCFree(orig); |
285 | 2 | if (tls != NULL) |
286 | 0 | DetectTlsSubjectFree(de_ctx, tls); |
287 | 2 | return NULL; |
288 | | |
289 | 91 | } |
290 | | |
291 | | /** |
292 | | * \brief this function is used to add the parsed "id" option |
293 | | * \brief into the current signature |
294 | | * |
295 | | * \param de_ctx pointer to the Detection Engine Context |
296 | | * \param s pointer to the Current Signature |
297 | | * \param idstr pointer to the user provided "id" option |
298 | | * |
299 | | * \retval 0 on Success |
300 | | * \retval -1 on Failure |
301 | | */ |
302 | | static int DetectTlsSubjectSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) |
303 | 95 | { |
304 | 95 | DetectTlsData *tls = NULL; |
305 | | |
306 | 95 | if (SCDetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) |
307 | 2 | return -1; |
308 | | |
309 | 93 | tls = DetectTlsSubjectParse(de_ctx, str, s->init_data->negated); |
310 | 93 | if (tls == NULL) |
311 | 2 | goto error; |
312 | | |
313 | | /* Okay so far so good, lets get this into a SigMatch |
314 | | * and put it in the Signature. */ |
315 | | |
316 | 91 | if (SCSigMatchAppendSMToList( |
317 | 91 | de_ctx, s, DETECT_TLS_SUBJECT, (SigMatchCtx *)tls, g_tls_cert_list_id) == NULL) { |
318 | 0 | goto error; |
319 | 0 | } |
320 | 91 | return 0; |
321 | | |
322 | 2 | error: |
323 | 2 | if (tls != NULL) |
324 | 0 | DetectTlsSubjectFree(de_ctx, tls); |
325 | 2 | return -1; |
326 | | |
327 | 91 | } |
328 | | |
329 | | /** |
330 | | * \brief this function will free memory associated with DetectTlsData |
331 | | * |
332 | | * \param id_d pointer to DetectTlsData |
333 | | */ |
334 | | static void DetectTlsSubjectFree(DetectEngineCtx *de_ctx, void *ptr) |
335 | 91 | { |
336 | 91 | DetectTlsData *id_d = (DetectTlsData *)ptr; |
337 | 91 | if (ptr == NULL) |
338 | 0 | return; |
339 | 91 | if (id_d->subject != NULL) |
340 | 91 | SCFree(id_d->subject); |
341 | 91 | SCFree(id_d); |
342 | 91 | } |
343 | | |
344 | | /** |
345 | | * \brief match the specified IssuerDN on a tls session |
346 | | * |
347 | | * \param t pointer to thread vars |
348 | | * \param det_ctx pointer to the pattern matcher thread |
349 | | * \param p pointer to the current packet |
350 | | * \param m pointer to the sigmatch that we will cast into DetectTlsData |
351 | | * |
352 | | * \retval 0 no match |
353 | | * \retval 1 match |
354 | | */ |
355 | | static int DetectTlsIssuerDNMatch (DetectEngineThreadCtx *det_ctx, |
356 | | Flow *f, uint8_t flags, void *state, void *txv, |
357 | | const Signature *s, const SigMatchCtx *m) |
358 | 0 | { |
359 | 0 | SCEnter(); |
360 | |
|
361 | 0 | const DetectTlsData *tls_data = (const DetectTlsData *)m; |
362 | 0 | SSLState *ssl_state = (SSLState *)state; |
363 | 0 | if (ssl_state == NULL) { |
364 | 0 | SCLogDebug("no tls state, no match"); |
365 | 0 | SCReturnInt(0); |
366 | 0 | } |
367 | | |
368 | 0 | int ret = 0; |
369 | |
|
370 | 0 | SSLStateConnp *connp = NULL; |
371 | 0 | if (flags & STREAM_TOSERVER) { |
372 | 0 | connp = &ssl_state->client_connp; |
373 | 0 | } else { |
374 | 0 | connp = &ssl_state->server_connp; |
375 | 0 | } |
376 | |
|
377 | 0 | if (connp->cert0_issuerdn != NULL) { |
378 | 0 | SCLogDebug("TLS: IssuerDN is [%s], looking for [%s]\n", |
379 | 0 | connp->cert0_issuerdn, tls_data->issuerdn); |
380 | |
|
381 | 0 | if (SpmSearch(connp->cert0_issuerdn, connp->cert0_issuerdn_len, |
382 | 0 | (const uint8_t *)tls_data->issuerdn, |
383 | 0 | (uint16_t)strlen(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 | 4.21k | { |
414 | 4.21k | DetectTlsData *tls = NULL; |
415 | 4.21k | size_t pcre2_len; |
416 | 4.21k | const char *str_ptr; |
417 | 4.21k | char *orig = NULL; |
418 | 4.21k | char *tmp_str; |
419 | 4.21k | uint32_t flag = 0; |
420 | | |
421 | 4.21k | pcre2_match_data *match = NULL; |
422 | 4.21k | int ret = DetectParsePcreExec(&issuerdn_parse_regex, &match, str, 0, 0); |
423 | 4.21k | if (ret != 2) { |
424 | 249 | SCLogError("invalid tls.issuerdn option"); |
425 | 249 | goto error; |
426 | 249 | } |
427 | | |
428 | 3.96k | if (negate) |
429 | 0 | flag = DETECT_CONTENT_NEGATED; |
430 | | |
431 | 3.96k | int res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); |
432 | 3.96k | 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 | 3.96k | tls = SCMalloc(sizeof(DetectTlsData)); |
439 | 3.96k | if (unlikely(tls == NULL)) |
440 | 0 | goto error; |
441 | 3.96k | tls->issuerdn = NULL; |
442 | 3.96k | tls->flags = flag; |
443 | | |
444 | 3.96k | orig = SCStrdup((char*)str_ptr); |
445 | 3.96k | if (unlikely(orig == NULL)) { |
446 | 0 | goto error; |
447 | 0 | } |
448 | 3.96k | pcre2_substring_free((PCRE2_UCHAR *)str_ptr); |
449 | | |
450 | 3.96k | tmp_str=orig; |
451 | | |
452 | | /* Let's see if we need to escape "'s */ |
453 | 3.96k | if (tmp_str[0] == '"') |
454 | 351 | { |
455 | 351 | tmp_str[strlen(tmp_str) - 1] = '\0'; |
456 | 351 | tmp_str += 1; |
457 | 351 | } |
458 | | |
459 | 3.96k | tls->issuerdn = SCStrdup(tmp_str); |
460 | 3.96k | if (unlikely(tls->issuerdn == NULL)) { |
461 | 0 | goto error; |
462 | 0 | } |
463 | | |
464 | 3.96k | SCFree(orig); |
465 | | |
466 | 3.96k | pcre2_match_data_free(match); |
467 | 3.96k | SCLogDebug("Will look for TLS issuerdn %s", tls->issuerdn); |
468 | | |
469 | 3.96k | return tls; |
470 | | |
471 | 249 | error: |
472 | 249 | if (match) { |
473 | 249 | pcre2_match_data_free(match); |
474 | 249 | } |
475 | 249 | if (orig != NULL) |
476 | 0 | SCFree(orig); |
477 | 249 | if (tls != NULL) |
478 | 0 | DetectTlsIssuerDNFree(de_ctx, tls); |
479 | 249 | return NULL; |
480 | | |
481 | 3.96k | } |
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 | 4.21k | { |
496 | 4.21k | DetectTlsData *tls = NULL; |
497 | | |
498 | 4.21k | if (SCDetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) |
499 | 4 | return -1; |
500 | | |
501 | 4.21k | tls = DetectTlsIssuerDNParse(de_ctx, str, s->init_data->negated); |
502 | 4.21k | if (tls == NULL) |
503 | 249 | goto error; |
504 | | |
505 | | /* Okay so far so good, lets get this into a SigMatch |
506 | | * and put it in the Signature. */ |
507 | | |
508 | 3.96k | if (SCSigMatchAppendSMToList( |
509 | 3.96k | de_ctx, s, DETECT_TLS_ISSUERDN, (SigMatchCtx *)tls, g_tls_cert_list_id) == NULL) { |
510 | 0 | goto error; |
511 | 0 | } |
512 | 3.96k | return 0; |
513 | | |
514 | 249 | error: |
515 | 249 | if (tls != NULL) |
516 | 0 | DetectTlsIssuerDNFree(de_ctx, tls); |
517 | 249 | return -1; |
518 | | |
519 | 3.96k | } |
520 | | |
521 | | /** |
522 | | * \brief this function will free memory associated with DetectTlsData |
523 | | * |
524 | | * \param id_d pointer to DetectTlsData |
525 | | */ |
526 | | static void DetectTlsIssuerDNFree(DetectEngineCtx *de_ctx, void *ptr) |
527 | 3.96k | { |
528 | 3.96k | DetectTlsData *id_d = (DetectTlsData *)ptr; |
529 | 3.96k | SCFree(id_d->issuerdn); |
530 | 3.96k | SCFree(id_d); |
531 | 3.96k | } |
532 | | |
533 | | /** |
534 | | * \brief This function is used to parse fingerprint passed via keyword: "fingerprint" |
535 | | * |
536 | | * \param de_ctx Pointer to the detection engine context |
537 | | * \param str Pointer to the user provided fingerprint option |
538 | | * |
539 | | * \retval pointer to DetectTlsData on success |
540 | | * \retval NULL on failure |
541 | | */ |
542 | | |
543 | | /** |
544 | | * \brief this function is used to add the parsed "fingerprint" option |
545 | | * \brief into the current signature |
546 | | * |
547 | | * \param de_ctx pointer to the Detection Engine Context |
548 | | * \param s pointer to the Current Signature |
549 | | * \param id pointer to the user provided "fingerprint" option |
550 | | * |
551 | | * \retval 0 on Success |
552 | | * \retval -1 on Failure |
553 | | */ |
554 | | static int DetectTlsFingerprintSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) |
555 | 393 | { |
556 | 393 | if (DetectContentSetup(de_ctx, s, str) < 0) { |
557 | 34 | return -1; |
558 | 34 | } |
559 | | |
560 | 359 | if (DetectEngineContentModifierBufferSetup(de_ctx, s, NULL, DETECT_TLS_CERT_FINGERPRINT, |
561 | 359 | g_tls_cert_fingerprint_list_id, ALPROTO_TLS) < 0) |
562 | 22 | return -1; |
563 | | |
564 | 337 | return 0; |
565 | 359 | } |
566 | | |
567 | | /** |
568 | | * \brief this function will free memory associated with DetectTlsData |
569 | | * |
570 | | * \param pointer to DetectTlsData |
571 | | */ |
572 | | static void DetectTlsFingerprintFree(DetectEngineCtx *de_ctx, void *ptr) |
573 | 0 | { |
574 | 0 | DetectTlsData *id_d = (DetectTlsData *)ptr; |
575 | 0 | SCFree(id_d); |
576 | 0 | } |
577 | | |
578 | | /** |
579 | | * \brief this function is used to add the parsed "store" option |
580 | | * \brief into the current signature |
581 | | * |
582 | | * \param de_ctx pointer to the Detection Engine Context |
583 | | * \param s pointer to the Current Signature |
584 | | * \param idstr pointer to the user provided "store" option |
585 | | * |
586 | | * \retval 0 on Success |
587 | | * \retval -1 on Failure |
588 | | */ |
589 | | static int DetectTlsStoreSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) |
590 | 550 | { |
591 | | |
592 | 550 | if (SCDetectSignatureSetAppProto(s, ALPROTO_TLS) != 0) |
593 | 148 | return -1; |
594 | | |
595 | 402 | s->flags |= SIG_FLAG_TLSSTORE; |
596 | | |
597 | 402 | if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_TLS_STORE, NULL, DETECT_SM_LIST_POSTMATCH) == |
598 | 402 | NULL) { |
599 | 0 | return -1; |
600 | 0 | } |
601 | 402 | return 0; |
602 | 402 | } |
603 | | |
604 | | /** \warning modifies Flow::alstate */ |
605 | | static int DetectTlsStorePostMatch (DetectEngineThreadCtx *det_ctx, |
606 | | Packet *p, const Signature *s, const SigMatchCtx *unused) |
607 | 14 | { |
608 | 14 | SCEnter(); |
609 | | |
610 | 14 | if (p->flow == NULL) |
611 | 0 | return 0; |
612 | | |
613 | 14 | SSLState *ssl_state = FlowGetAppState(p->flow); |
614 | 14 | if (ssl_state == NULL) { |
615 | 0 | SCLogDebug("no tls state, no match"); |
616 | 0 | SCReturnInt(0); |
617 | 0 | } |
618 | | |
619 | 14 | SSLStateConnp *connp; |
620 | | |
621 | 14 | if (PKT_IS_TOSERVER(p)) { |
622 | 2 | connp = &ssl_state->client_connp; |
623 | 12 | } else { |
624 | 12 | connp = &ssl_state->server_connp; |
625 | 12 | } |
626 | | |
627 | 14 | connp->cert_log_flag |= SSL_TLS_LOG_PEM; |
628 | 14 | SCReturnInt(1); |
629 | 14 | } |