/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 | } |