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