diff options
| -rw-r--r-- | .gitlab-ci.yml | 26 | ||||
| -rw-r--r-- | CMakeLists.txt | 8 | ||||
| -rw-r--r-- | include/ssl.h | 8 | ||||
| -rw-r--r-- | src/SSL_Analyze.h | 3 | ||||
| -rw-r--r-- | src/SSL_Message.c | 168 | ||||
| -rw-r--r-- | src/utstring.h | 407 | ||||
| -rw-r--r-- | test/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | test/pcap/client_hello_fragment/1-ssl.client.hello.fragment.192.168.56.31.53868.74.118.186.107.443.pcap | bin | 0 -> 9609 bytes | |||
| -rw-r--r-- | test/pcap/client_hello_fragment/2-sni.client.hello.fragment.192.168.58.17.49218-23.216.55.29.443.pcap | bin | 0 -> 1412721 bytes | |||
| -rw-r--r-- | test/pcap/client_hello_fragment/ssl_client_hello_fragment_result.json | 50 | ||||
| -rw-r--r-- | test/ssl_test_plug.cpp | 7 |
11 files changed, 655 insertions, 25 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f7348e5..656ab5f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,7 +20,18 @@ run_cppcheck_for_centos7: - mkdir build || true - cd build - cmake3 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. - - cppcheck --project=compile_commands.json --enable=all --error-exitcode=1 --suppress=unusedFunction --suppress=missingInclude --suppress=uselessAssignmentPtrArg --suppress=unreachableCode --suppress=unreadVariable --suppress=unmatchedSuppression + - cppcheck --project=compile_commands.json + --enable=all + --error-exitcode=1 + --suppress=unusedFunction + --suppress=missingInclude + --suppress=uselessAssignmentPtrArg + --suppress=unreachableCode + --suppress=unreadVariable + --suppress=unmatchedSuppression + --suppress=variableScope + --suppress=constParameter + --suppress=*:${PROJECT_SOURCE_DIR}/src/utstring.h tags: - share @@ -31,7 +42,18 @@ run_cppcheck_for_centos8: - mkdir build || true - cd build - cmake3 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. - - cppcheck --project=compile_commands.json --enable=all --error-exitcode=1 --suppress=unusedFunction --suppress=missingInclude --suppress=uselessAssignmentPtrArg --suppress=unreachableCode --suppress=unreadVariable --suppress=unmatchedSuppression + - cppcheck --project=compile_commands.json + --enable=all + --error-exitcode=1 + --suppress=unusedFunction + --suppress=missingInclude + --suppress=uselessAssignmentPtrArg + --suppress=unreachableCode + --suppress=unreadVariable + --suppress=unmatchedSuppression + --suppress=variableScope + --suppress=constParameter + --suppress=*:${PROJECT_SOURCE_DIR}/src/utstring.h tags: - share diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ce3a56..8bb0cd6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 2.8) +cmake_minimum_required (VERSION 3.0) set(lib_name ssl) @@ -39,8 +39,10 @@ if (CMAKE_CXX_CPPCHECK) "--suppress=uselessAssignmentPtrArg" "--suppress=unmatchedSuppression" "--suppress=unreadVariable" - "--suppress=unreachableCode" - "--suppress=constParameter" + "--suppress=unreachableCode" + "--suppress=constParameter" + "--suppress=variableScope" + "--suppress=*:${PROJECT_SOURCE_DIR}/src/utstring.h" ) message("cppcheck start...") else() diff --git a/include/ssl.h b/include/ssl.h index 96d2835..16a7300 100644 --- a/include/ssl.h +++ b/include/ssl.h @@ -82,6 +82,13 @@ struct ssl_extenstions struct ssl_l2tv extension[MAX_EXTENSION_NUM]; }; +#define MAX_JA_MD5_STR_LEN 128 +struct ssl_ja_fingerprint +{ + int md5_len; + char md5[MAX_JA_MD5_STR_LEN]; +}; + #define MAX_SERVER_NAME_LEN 512 struct ssl_client_hello { @@ -97,6 +104,7 @@ struct ssl_client_hello struct ssl_extenstions extensions; struct ssl_encrypt_server_name esni; char server_name[MAX_SERVER_NAME_LEN]; + struct ssl_ja_fingerprint ja3; }; #define MAX_JA3S_FINGERPRINT_LEN 128 diff --git a/src/SSL_Analyze.h b/src/SSL_Analyze.h index b8dabac..a58f024 100644 --- a/src/SSL_Analyze.h +++ b/src/SSL_Analyze.h @@ -3,6 +3,7 @@ #include <MESA/stream.h> #include "ssl.h" +#include "SSL_Message.h" #if(__GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__ >= 410) #define atomic_inc(x) __sync_add_and_fetch((x),1) @@ -62,6 +63,8 @@ struct ssl_business_info struct ssl_record_trunk { + unsigned char is_offset_header; + struct ssl_record_header header; int cache_len; char* cache_buff; }; diff --git a/src/SSL_Message.c b/src/SSL_Message.c index d3bff89..bbc9033 100644 --- a/src/SSL_Message.c +++ b/src/SSL_Message.c @@ -2,6 +2,8 @@ #include <string.h> #include <stdlib.h> +#include "utstring.h" + #include "SSL_Analyze.h" #include "ssl.h" #include "SSL_Message.h" @@ -25,6 +27,12 @@ #define ENCRPTED_SERVER_NAME_EXT_TYPE 0xFFCE #define ENCRPTED_CLIENT_HELLO_EXT_TYPE 0xFE0D +#define EC_POINT_FORMATS_EXT_TYPE 0x000B + +// https://datatracker.ietf.org/doc/html/rfc7919 +// Supported Groups +#define SUPPORTED_GROUPS_EXT_TYPE 0x000A + #define CERTIFICATE_HDRLEN 7 #define SSL_CERTIFICATE_HDRLEN 3 @@ -48,6 +56,22 @@ const struct ssl_value2string ssl_version_list[] = { UNKNOWN_VERSION, NULL } }; +// https://tools.ietf.org/html/draft-davidben-tls-grease-00 +static int ssl_is_grease_value(unsigned short val) +{ + if ((val & 0x0f)!=0x0a) + { + return 0; + } + + if((val & 0xff) != ((val >> 8) & 0xff)) + { + return 0; + } + + return 1; +} + const char *ssl_get_suite(struct ssl_l2v *ciphersuites) { if (ciphersuites == NULL) @@ -127,7 +151,7 @@ void ssl_trunk_free(struct ssl_runtime_context *ssl_context, int thread_seq) ssl_context->record.cache_buff=NULL; } - ssl_context->record.cache_len=0; + memset(&(ssl_context->record), 0, sizeof(struct ssl_record_trunk)); } } @@ -310,6 +334,17 @@ int ssl_parse_encrypt_server_name(struct ssl_client_hello *chello, struct ssl_l2 int ssl_parse_client_hello(struct ssl_client_hello *chello, unsigned char *payload, int payload_len) { int offset=0,one_ltv=0; + unsigned int ec_point_format=0; + + UT_string *ja3_string,*cipher_suite_string,*ec_string,*ex_string; + utstring_new(ja3_string); + utstring_new(cipher_suite_string); + utstring_printf(cipher_suite_string, ","); + utstring_new(ec_string); + utstring_printf(ec_string, ","); + utstring_new(ex_string); + utstring_printf(ex_string, ","); + chello->total_len=BtoL3BytesNum((const char *)(payload+1)); if(chello->total_len<0) /*CLIENT_HELLO_HDRLEN: 4 means client_type+len*/ { @@ -318,7 +353,7 @@ int ssl_parse_client_hello(struct ssl_client_hello *chello, unsigned char *paylo if((chello->total_len+CLIENT_HELLO_HDRLEN > payload_len) || (chello->total_len-(int)sizeof(chello->version)<0)) { - return SSL_FLASE; + return SSL_CONTINUE; } chello->version=ssl_get_hello_version((unsigned char *)payload, payload_len); @@ -327,6 +362,7 @@ int ssl_parse_client_hello(struct ssl_client_hello *chello, unsigned char *paylo return SSL_FLASE; } + utstring_printf(ja3_string, "%u", chello->version); offset+=(CLIENT_HELLO_HDRLEN+sizeof(chello->version)); /*get client hello random*/ @@ -356,6 +392,19 @@ int ssl_parse_client_hello(struct ssl_client_hello *chello, unsigned char *paylo { return SSL_FLASE; } + + if(chello->ciphersuites.len>0) + { + for(unsigned short i=0; i<chello->ciphersuites.len; i+=2) + { + unsigned short cipher_suite=BtoL2BytesNum((const char *)(chello->ciphersuites.value+i)); + if(ssl_is_grease_value(cipher_suite)==0) + { + utstring_printf(cipher_suite_string, "%u-", cipher_suite); + } + } + } + offset+=one_ltv; /*get client hello compress*/ @@ -380,6 +429,12 @@ int ssl_parse_client_hello(struct ssl_client_hello *chello, unsigned char *paylo { return SSL_FLASE; } + + if(ssl_is_grease_value(chello->extensions.extension[ex_offset].type)==0) + { + utstring_printf(ex_string, "%u-", chello->extensions.extension[ex_offset].type); + } + offset+=one_ltv; switch(chello->extensions.extension[ex_offset].type) @@ -399,6 +454,44 @@ int ssl_parse_client_hello(struct ssl_client_hello *chello, unsigned char *paylo case ALPN_EXT_TYPE: chello->alpn=&(chello->extensions.extension[ex_offset++]); break; + case EC_POINT_FORMATS_EXT_TYPE: + // parse ec point formats + { + char length=BtoL1BytesNum((const char*)(chello->extensions.extension[ex_offset].value)); + switch(length) + { + case 1: + ec_point_format=BtoL1BytesNum((const char*)(chello->extensions.extension[ex_offset].value+1)); + break; + case 2: + ec_point_format=BtoL2BytesNum((const char*)(chello->extensions.extension[ex_offset].value+1)); + break; + case 3: + ec_point_format=BtoL3BytesNum((const char*)(chello->extensions.extension[ex_offset].value+1)); + break; + case 4: + ec_point_format=BtoL4BytesNum((const char*)(chello->extensions.extension[ex_offset].value+1)); + break; + default: + ec_point_format=0; + break; + } + } + break; + case SUPPORTED_GROUPS_EXT_TYPE: + // parse supported groups + { + unsigned short length=BtoL2BytesNum((const char*)(chello->extensions.extension[ex_offset].value)); + for(unsigned short j=0; j<length; j+=2) + { + unsigned short group=BtoL2BytesNum((const char*)(chello->extensions.extension[ex_offset].value+j+2)); + if(ssl_is_grease_value(group)==0) + { + utstring_printf(ec_string, "%u-", group); + } + } + } + break; default: break; } @@ -406,6 +499,20 @@ int ssl_parse_client_hello(struct ssl_client_hello *chello, unsigned char *paylo chello->extensions.num=ex_offset; } + + utstring_bincpy(ja3_string, utstring_body(cipher_suite_string), (utstring_len(cipher_suite_string)==1 ? utstring_len(cipher_suite_string) : utstring_len(cipher_suite_string)-1)); + utstring_bincpy(ja3_string, utstring_body(ex_string), (utstring_len(ex_string)==1 ? utstring_len(ex_string) : utstring_len(ex_string)-1)); + utstring_bincpy(ja3_string, utstring_body(ec_string), (utstring_len(ec_string)==1 ? utstring_len(ec_string) : utstring_len(ec_string)-1)); + utstring_printf(ja3_string, ",%u", ec_point_format); + + chello->ja3.md5_len=ja3_md5sum(utstring_body(ja3_string), utstring_len(ja3_string), chello->ja3.md5, sizeof(chello->ja3.md5)); + chello->ja3.md5[chello->ja3.md5_len]='\0'; + + utstring_free(ja3_string); + utstring_free(cipher_suite_string); + utstring_free(ec_string); + utstring_free(ex_string); + return SSL_TRUE; } @@ -731,7 +838,7 @@ int ssl_parse_handshake(const struct streaminfo *a_tcp, struct ssl_runtime_conte } } - return SSL_TRUE;; + return SSL_TRUE; } int ssl_parse_application_data(const struct streaminfo *a_tcp, struct ssl_runtime_context *ssl_context, char *payload, int payload_len, int thread_seq, const void *a_packet) @@ -864,18 +971,28 @@ int ssl_parse_message(const struct streaminfo *a_tcp, struct ssl_runtime_context while(payload_len-offset > SSL_RECORD_HDRLEN) { - struct ssl_record_header *ssl_record=(struct ssl_record_header *)(payload+offset); + int one_record_len=0; + struct ssl_record_header *ssl_record=NULL; - int one_record_len=htons(ssl_record->total_len); - ssl_context->is_ssl_stream=SSL_TRUE; - - if((payload_len-offset) < one_record_len) + if(ssl_context->record.is_offset_header==1) { - ssl_trunk_cache(ssl_context, payload+offset, payload_len-offset, thread_seq); - break; //cache + ssl_record=&(ssl_context->record.header); + one_record_len=payload_len; + } + else + { + ssl_record=(struct ssl_record_header *)(payload+offset); + one_record_len=htons(ssl_record->total_len); + ssl_context->is_ssl_stream=SSL_TRUE; + + if((payload_len-offset) < one_record_len) + { + ssl_trunk_cache(ssl_context, payload+offset, payload_len-offset, thread_seq); + break; //cache + } + + offset+=SSL_RECORD_HDRLEN; } - - offset+=SSL_RECORD_HDRLEN; switch (ssl_record->content_type) { @@ -907,6 +1024,14 @@ int ssl_parse_message(const struct streaminfo *a_tcp, struct ssl_runtime_context break; } + if(state==SSL_CONTINUE) + { + ssl_context->record.is_offset_header=1; + ssl_context->record.header=*ssl_record; + ssl_trunk_cache(ssl_context, payload+offset, payload_len-offset, thread_seq); + break; + } + offset+=one_record_len; } @@ -941,8 +1066,23 @@ int ssl_parse_stream(const struct streaminfo *a_tcp, struct ssl_runtime_context if(ssl_context->record.cache_len>0) { payload_len=MIN((int)tcp_detail->datalen, (g_ssl_runtime_para.max_cache_len - ssl_context->record.cache_len)); - memcpy(ssl_context->record.cache_buff + ssl_context->record.cache_len, tcp_detail->pdata, payload_len); - ssl_context->record.cache_len += payload_len; + if(ssl_context->record.is_offset_header==1) + { + if(payload_len<=SSL_RECORD_HDRLEN) + { + ssl_trunk_free(ssl_context, thread_seq); + return SSL_TRUE; + } + + memcpy(ssl_context->record.cache_buff + ssl_context->record.cache_len, ((char *)(tcp_detail->pdata))+SSL_RECORD_HDRLEN, payload_len-SSL_RECORD_HDRLEN); + ssl_context->record.cache_len += payload_len-SSL_RECORD_HDRLEN; + } + else + { + memcpy(ssl_context->record.cache_buff + ssl_context->record.cache_len, tcp_detail->pdata, payload_len); + ssl_context->record.cache_len += payload_len; + } + payload_len=ssl_context->record.cache_len; payload=ssl_context->record.cache_buff; } diff --git a/src/utstring.h b/src/utstring.h new file mode 100644 index 0000000..4cf5ffd --- /dev/null +++ b/src/utstring.h @@ -0,0 +1,407 @@ +/* +Copyright (c) 2008-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* a dynamic string implementation using macros + */ +#ifndef UTSTRING_H +#define UTSTRING_H + +#define UTSTRING_VERSION 2.1.0 + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <stdarg.h> + +#ifdef __GNUC__ +#define UTSTRING_UNUSED __attribute__((__unused__)) +#else +#define UTSTRING_UNUSED +#endif + +#ifdef oom +#error "The name of macro 'oom' has been changed to 'utstring_oom'. Please update your code." +#define utstring_oom() oom() +#endif + +#ifndef utstring_oom +#define utstring_oom() exit(-1) +#endif + +typedef struct { + char *d; /* pointer to allocated buffer */ + size_t n; /* allocated capacity */ + size_t i; /* index of first unused byte */ +} UT_string; + +#define utstring_reserve(s,amt) \ +do { \ + if (((s)->n - (s)->i) < (size_t)(amt)) { \ + char *utstring_tmp = (char*)realloc( \ + (s)->d, (s)->n + (amt)); \ + if (!utstring_tmp) { \ + utstring_oom(); \ + } \ + (s)->d = utstring_tmp; \ + (s)->n += (amt); \ + } \ +} while(0) + +#define utstring_init(s) \ +do { \ + (s)->n = 0; (s)->i = 0; (s)->d = NULL; \ + utstring_reserve(s,100); \ + (s)->d[0] = '\0'; \ +} while(0) + +#define utstring_done(s) \ +do { \ + if ((s)->d != NULL) free((s)->d); \ + (s)->n = 0; \ +} while(0) + +#define utstring_free(s) \ +do { \ + utstring_done(s); \ + free(s); \ +} while(0) + +#define utstring_new(s) \ +do { \ + (s) = (UT_string*)malloc(sizeof(UT_string)); \ + if (!(s)) { \ + utstring_oom(); \ + } \ + utstring_init(s); \ +} while(0) + +#define utstring_renew(s) \ +do { \ + if (s) { \ + utstring_clear(s); \ + } else { \ + utstring_new(s); \ + } \ +} while(0) + +#define utstring_clear(s) \ +do { \ + (s)->i = 0; \ + (s)->d[0] = '\0'; \ +} while(0) + +#define utstring_bincpy(s,b,l) \ +do { \ + utstring_reserve((s),(l)+1); \ + if (l) memcpy(&(s)->d[(s)->i], b, l); \ + (s)->i += (l); \ + (s)->d[(s)->i]='\0'; \ +} while(0) + +#define utstring_concat(dst,src) \ +do { \ + utstring_reserve((dst),((src)->i)+1); \ + if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \ + (dst)->i += (src)->i; \ + (dst)->d[(dst)->i]='\0'; \ +} while(0) + +#define utstring_len(s) ((s)->i) + +#define utstring_body(s) ((s)->d) + +UTSTRING_UNUSED static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) { + int n; + va_list cp; + for (;;) { +#ifdef _WIN32 + cp = ap; +#else + va_copy(cp, ap); +#endif + n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp); + va_end(cp); + + if ((n > -1) && ((size_t) n < (s->n-s->i))) { + s->i += n; + return; + } + + /* Else try again with more space. */ + if (n > -1) utstring_reserve(s,n+1); /* exact */ + else utstring_reserve(s,(s->n)*2); /* 2x */ + } +} +#ifdef __GNUC__ +/* support printf format checking (2=the format string, 3=start of varargs) */ +static void utstring_printf(UT_string *s, const char *fmt, ...) + __attribute__ (( format( printf, 2, 3) )); +#endif +UTSTRING_UNUSED static void utstring_printf(UT_string *s, const char *fmt, ...) { + va_list ap; + va_start(ap,fmt); + utstring_printf_va(s,fmt,ap); + va_end(ap); +} + +/******************************************************************************* + * begin substring search functions * + ******************************************************************************/ +/* Build KMP table from left to right. */ +UTSTRING_UNUSED static void _utstring_BuildTable( + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + + i = 0; + j = i - 1; + P_KMP_Table[i] = j; + while (i < (long) P_NeedleLen) + { + while ( (j > -1) && (P_Needle[i] != P_Needle[j]) ) + { + j = P_KMP_Table[j]; + } + i++; + j++; + if (i < (long) P_NeedleLen) + { + if (P_Needle[i] == P_Needle[j]) + { + P_KMP_Table[i] = P_KMP_Table[j]; + } + else + { + P_KMP_Table[i] = j; + } + } + else + { + P_KMP_Table[i] = j; + } + } + + return; +} + + +/* Build KMP table from right to left. */ +UTSTRING_UNUSED static void _utstring_BuildTableR( + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + + i = P_NeedleLen - 1; + j = i + 1; + P_KMP_Table[i + 1] = j; + while (i >= 0) + { + while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) ) + { + j = P_KMP_Table[j + 1]; + } + i--; + j--; + if (i >= 0) + { + if (P_Needle[i] == P_Needle[j]) + { + P_KMP_Table[i + 1] = P_KMP_Table[j + 1]; + } + else + { + P_KMP_Table[i + 1] = j; + } + } + else + { + P_KMP_Table[i + 1] = j; + } + } + + return; +} + + +/* Search data from left to right. ( Multiple search mode. ) */ +UTSTRING_UNUSED static long _utstring_find( + const char *P_Haystack, + size_t P_HaystackLen, + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + long V_FindPosition = -1; + + /* Search from left to right. */ + i = j = 0; + while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) ) + { + while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) ) + { + i = P_KMP_Table[i]; + } + i++; + j++; + if (i >= (int)P_NeedleLen) + { + /* Found. */ + V_FindPosition = j - i; + break; + } + } + + return V_FindPosition; +} + + +/* Search data from right to left. ( Multiple search mode. ) */ +UTSTRING_UNUSED static long _utstring_findR( + const char *P_Haystack, + size_t P_HaystackLen, + const char *P_Needle, + size_t P_NeedleLen, + long *P_KMP_Table) +{ + long i, j; + long V_FindPosition = -1; + + /* Search from right to left. */ + j = (P_HaystackLen - 1); + i = (P_NeedleLen - 1); + while ( (j >= 0) && (j >= i) ) + { + while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) ) + { + i = P_KMP_Table[i + 1]; + } + i--; + j--; + if (i < 0) + { + /* Found. */ + V_FindPosition = j + 1; + break; + } + } + + return V_FindPosition; +} + + +/* Search data from left to right. ( One time search mode. ) */ +UTSTRING_UNUSED static long utstring_find( + UT_string *s, + long P_StartPosition, /* Start from 0. -1 means last position. */ + const char *P_Needle, + size_t P_NeedleLen) +{ + long V_StartPosition; + long V_HaystackLen; + long *V_KMP_Table; + long V_FindPosition = -1; + + if (P_StartPosition < 0) + { + V_StartPosition = s->i + P_StartPosition; + } + else + { + V_StartPosition = P_StartPosition; + } + V_HaystackLen = s->i - V_StartPosition; + if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) + { + V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); + if (V_KMP_Table != NULL) + { + _utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table); + + V_FindPosition = _utstring_find(s->d + V_StartPosition, + V_HaystackLen, + P_Needle, + P_NeedleLen, + V_KMP_Table); + if (V_FindPosition >= 0) + { + V_FindPosition += V_StartPosition; + } + + free(V_KMP_Table); + } + } + + return V_FindPosition; +} + + +/* Search data from right to left. ( One time search mode. ) */ +UTSTRING_UNUSED static long utstring_findR( + UT_string *s, + long P_StartPosition, /* Start from 0. -1 means last position. */ + const char *P_Needle, + size_t P_NeedleLen) +{ + long V_StartPosition; + long V_HaystackLen; + long *V_KMP_Table; + long V_FindPosition = -1; + + if (P_StartPosition < 0) + { + V_StartPosition = s->i + P_StartPosition; + } + else + { + V_StartPosition = P_StartPosition; + } + V_HaystackLen = V_StartPosition + 1; + if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) + { + V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); + if (V_KMP_Table != NULL) + { + _utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table); + + V_FindPosition = _utstring_findR(s->d, + V_HaystackLen, + P_Needle, + P_NeedleLen, + V_KMP_Table); + + free(V_KMP_Table); + } + } + + return V_FindPosition; +} +/******************************************************************************* + * end substring search functions * + ******************************************************************************/ + +#endif /* UTSTRING_H */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6959e78..f7d79de 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 2.8) +cmake_minimum_required (VERSION 3.0) project(${lib_name}_test) @@ -44,3 +44,4 @@ add_test(NAME RUN_BUG_TEST COMMAND proto_test_main ${CMAKE_CURRENT_SOURCE_DIR}/p add_test(NAME RUN_MULTIPLE_HANDSHAKE_TEST COMMAND proto_test_main ${CMAKE_CURRENT_SOURCE_DIR}/pcap/multiple_handshake/ssl_multiple_handshake_result.json -f "find ${CMAKE_CURRENT_SOURCE_DIR}/pcap/multiple_handshake/ -name *.pcap|sort -V" WORKING_DIRECTORY ${PROTO_TEST_RUN_DIR}) add_test(NAME RUN_CLOSE_CONTAINS_PAYLOAD_TEST COMMAND proto_test_main ${CMAKE_CURRENT_SOURCE_DIR}/pcap/close_contains_payload/ssl_close_contains_payload_result.json -f "find ${CMAKE_CURRENT_SOURCE_DIR}/pcap/close_contains_payload/ -name *.pcap|sort -V" WORKING_DIRECTORY ${PROTO_TEST_RUN_DIR}) add_test(NAME RUN_EXTENSION_EXCEED_16 COMMAND proto_test_main ${CMAKE_CURRENT_SOURCE_DIR}/pcap/extensions_exceed_16/extensions_exceed_16_result.json -f "find ${CMAKE_CURRENT_SOURCE_DIR}/pcap/extensions_exceed_16/ -name *.pcap|sort -V" WORKING_DIRECTORY ${PROTO_TEST_RUN_DIR}) +add_test(NAME RUN_CLIENT_HELLO_FRAGMENT COMMAND proto_test_main ${CMAKE_CURRENT_SOURCE_DIR}/pcap/client_hello_fragment/ssl_client_hello_fragment_result.json -f "find ${CMAKE_CURRENT_SOURCE_DIR}/pcap/client_hello_fragment/ -name *.pcap|sort -V" WORKING_DIRECTORY ${PROTO_TEST_RUN_DIR}) diff --git a/test/pcap/client_hello_fragment/1-ssl.client.hello.fragment.192.168.56.31.53868.74.118.186.107.443.pcap b/test/pcap/client_hello_fragment/1-ssl.client.hello.fragment.192.168.56.31.53868.74.118.186.107.443.pcap Binary files differnew file mode 100644 index 0000000..8e0001c --- /dev/null +++ b/test/pcap/client_hello_fragment/1-ssl.client.hello.fragment.192.168.56.31.53868.74.118.186.107.443.pcap diff --git a/test/pcap/client_hello_fragment/2-sni.client.hello.fragment.192.168.58.17.49218-23.216.55.29.443.pcap b/test/pcap/client_hello_fragment/2-sni.client.hello.fragment.192.168.58.17.49218-23.216.55.29.443.pcap Binary files differnew file mode 100644 index 0000000..6782478 --- /dev/null +++ b/test/pcap/client_hello_fragment/2-sni.client.hello.fragment.192.168.58.17.49218-23.216.55.29.443.pcap diff --git a/test/pcap/client_hello_fragment/ssl_client_hello_fragment_result.json b/test/pcap/client_hello_fragment/ssl_client_hello_fragment_result.json new file mode 100644 index 0000000..dfbad1a --- /dev/null +++ b/test/pcap/client_hello_fragment/ssl_client_hello_fragment_result.json @@ -0,0 +1,50 @@ +[ + { + "Tuple4": "192.168.56.31.53868>74.118.186.107.443", + "ssl_sni": "sync.targeting.unrulymedia.com", + "ssl_client_version": "TLS1.2", + "ssl_ja3_hash": "bc93a67ef4492974195865dc0262e65e", + "ssl_ja3s_hash": "b898351eb5e266aefd3723d466935494", + "ssl_cert_version": "v3", + "ssl_cert_Issuer": "Sectigo RSA Domain Validation Secure Server CA;Sectigo Limited;;Salford;;Greater Manchester;GB", + "ssl_cert_IssuerCN": "Sectigo RSA Domain Validation Secure Server CA", + "ssl_cert_IssuerO": "Sectigo Limited", + "ssl_cert_IssuerC": "GB", + "ssl_cert_IssuerP": "Greater Manchester", + "ssl_cert_IssuerL": "Salford", + "ssl_cert_Sub": "*.targeting.unrulymedia.com;;;;;;", + "ssl_cert_SubCN": "*.targeting.unrulymedia.com", + "ssl_cert_SubAltName": "*.targeting.unrulymedia.com;targeting.unrulymedia.com", + "ssl_cert_SerialNum": "0x888d5e51787e0f1f485dc542465d2034", + "ssl_cert_AgID": "1.2.840.113549.1.1.11", + "ssl_cert_From": "230510000000Z", + "ssl_cert_To": "240510235959Z", + "ssl_cert_SSLFPAg": "1.2.840.113549.1.1.11", + "name": "SSL_RESULT_1" + }, + { + "Tuple4": "192.168.58.17.49218>23.216.55.29.443", + "ssl_sni": "www.missionsports.org", + "ssl_client_version": "TLS1.2", + "ssl_ja3_hash": "a69708a64f853c3bcc214c2c5faf84f3", + "ssl_ja3s_hash": "10a2ad147a870ef37af153dea9fe4dd3", + "ssl_cert_version": "v3", + "ssl_cert_Issuer": "DigiCert TLS RSA SHA256 2020 CA1;DigiCert Inc;;;;;US", + "ssl_cert_IssuerCN": "DigiCert TLS RSA SHA256 2020 CA1", + "ssl_cert_IssuerO": "DigiCert Inc", + "ssl_cert_IssuerC": "US", + "ssl_cert_Sub": "a248.e.akamai.net;Akamai Technologies, Inc.;;Cambridge;;Massachusetts;US", + "ssl_cert_SubCN": "a248.e.akamai.net", + "ssl_cert_SubO": "Akamai Technologies, Inc.", + "ssl_cert_SubC": "US", + "ssl_cert_SubP": "Massachusetts", + "ssl_cert_SubL": "Cambridge", + "ssl_cert_SubAltName": "a248.e.akamai.net;*.akamaized.net;*.akamaized-staging.net;*.akamaihd.net;*.akamaihd-staging.net", + "ssl_cert_SerialNum": "0x0d61f7742d583251a2b8d5a26a1dda0b", + "ssl_cert_AgID": "1.2.840.113549.1.1.11", + "ssl_cert_From": "230516000000Z", + "ssl_cert_To": "240515235959Z", + "ssl_cert_SSLFPAg": "1.2.840.113549.1.1.11", + "name": "SSL_RESULT_2" + } +]
\ No newline at end of file diff --git a/test/ssl_test_plug.cpp b/test/ssl_test_plug.cpp index c43ea72..9a1d27a 100644 --- a/test/ssl_test_plug.cpp +++ b/test/ssl_test_plug.cpp @@ -62,7 +62,6 @@ extern "C" unsigned char SSL_TEST_PLUG_ENTRY(stSessionInfo *session_info, void * cJSON *ctx = (cJSON *)*pme; struct ssl_stream *a_ssl = (struct ssl_stream *)(session_info->app_info); - struct ssl_ja3_info *ja3_info = NULL; if (session_info->session_state & SESSION_STATE_PENDING) { @@ -101,12 +100,10 @@ extern "C" unsigned char SSL_TEST_PLUG_ENTRY(stSessionInfo *session_info, void * cJSON_AddStringToObject(ctx, "ssl_client_version", ssl_get_version_name(a_ssl->chello->version)); } - ja3_info = ssl_get_ja3_fingerprint(a_tcp, (unsigned char *)a_tcp->ptcpdetail->pdata, (unsigned int)a_tcp->ptcpdetail->datalen, a_tcp->threadnum); - if (ja3_info != NULL && ja3_info->fp != NULL && ja3_info->fp_len > 0) + if(strlen(a_ssl->chello->ja3.md5) >0) { - cJSON_AddStringToObject(ctx, "ssl_ja3_hash", ja3_info->fp); + cJSON_AddStringToObject(ctx, "ssl_ja3_hash", a_ssl->chello->ja3.md5); } - break; case SSL_SERVER_HELLO: if (a_ssl->shello->ja3s.fingerprint_md5 != NULL && a_ssl->shello->ja3s.fingerprint_md5_len > 0) |
