diff options
-rw-r--r-- | example/ndpiReader.c | 19 | ||||
-rw-r--r-- | src/include/ndpi_api.h | 1 | ||||
-rw-r--r-- | src/lib/ndpi_utils.c | 21 | ||||
-rw-r--r-- | src/lib/protocols/ssl.c | 80 |
4 files changed, 69 insertions, 52 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c index 6351ce034..dfc65072b 100644 --- a/example/ndpiReader.c +++ b/example/ndpiReader.c @@ -764,23 +764,6 @@ static char* print_cipher(ndpi_cipher_weakness c) { /* ********************************** */ -static char* ssl_version2str(u_int16_t version) { - static char v[8]; - - switch(version) { - case 0x300: return("SSLv3"); - case 0x301: return("TLSv1"); - case 0x302: return("TLSv1.1"); - case 0x303: return("TLSv1.2"); - case 0x304: return("TLSv1.3"); - } - - snprintf(v, sizeof(v), "%04X", version); - return(v); -} - -/* ********************************** */ - /** * @brief Print the flow */ @@ -835,7 +818,7 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa if(flow->info[0] != '\0') fprintf(out, "[%s]", flow->info); - if(flow->ssh_ssl.ssl_version != 0) fprintf(out, "[%s]", ssl_version2str(flow->ssh_ssl.ssl_version)); + if(flow->ssh_ssl.ssl_version != 0) fprintf(out, "[%s]", ndpi_ssl_version2str(flow->ssh_ssl.ssl_version)); if(flow->ssh_ssl.ja3_client[0] != '\0') fprintf(out, "[JA3C: %s%s]", flow->ssh_ssl.ja3_client, print_cipher(flow->ssh_ssl.client_unsafe_cipher)); if(flow->ssh_ssl.server_info[0] != '\0') fprintf(out, "[server: %s]", flow->ssh_ssl.server_info); diff --git a/src/include/ndpi_api.h b/src/include/ndpi_api.h index 7297f0038..466d51b48 100644 --- a/src/include/ndpi_api.h +++ b/src/include/ndpi_api.h @@ -813,6 +813,7 @@ extern "C" { struct ndpi_flow_struct *flow); int ndpi_has_human_readeable_string(struct ndpi_detection_module_struct *ndpi_struct, char *buffer, u_int buffer_size); + char* ndpi_ssl_version2str(u_int16_t version); #ifdef __cplusplus } #endif diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c index 9be5cb7cb..b2f2f4658 100644 --- a/src/lib/ndpi_utils.c +++ b/src/lib/ndpi_utils.c @@ -687,3 +687,24 @@ int ndpi_has_human_readeable_string(struct ndpi_detection_module_struct *ndpi_st return(ret); } + +/* ********************************** */ + +char* ndpi_ssl_version2str(u_int16_t version) { + static char v[8]; + + switch(version) { + case 0x300: return("SSLv3"); + case 0x301: return("TLSv1"); + case 0x302: return("TLSv1.1"); + case 0x303: return("TLSv1.2"); + case 0x304: return("TLSv1.3"); + } + + if((version >= 0x7f00) && (version <= 0x7fff)) + return("TLSv1.3 (draft)"); + + snprintf(v, sizeof(v), "%04X", version); + return(v); +} + diff --git a/src/lib/protocols/ssl.c b/src/lib/protocols/ssl.c index f7009a788..91ffee2e7 100644 --- a/src/lib/protocols/ssl.c +++ b/src/lib/protocols/ssl.c @@ -27,7 +27,7 @@ #include "ndpi_api.h" -/* #define CERTIFICATE_DEBUG 1 */ +#define CERTIFICATE_DEBUG 1 #define NDPI_MAX_SSL_REQUEST_SIZE 10000 @@ -238,9 +238,10 @@ static u_int32_t ndpi_ssl_refine_master_protocol(struct ndpi_detection_module_st { struct ndpi_packet_struct *packet = &flow->packet; - if(((flow->l4.tcp.ssl_seen_client_cert == 1) && (flow->protos.stun_ssl.ssl.client_certificate[0] != '\0')) - || ((flow->l4.tcp.ssl_seen_server_cert == 1) && (flow->protos.stun_ssl.ssl.server_certificate[0] != '\0')) - || (flow->host_server_name[0] != '\0')) + if(((flow->l4.tcp.ssl_seen_client_cert == 1) && (flow->protos.stun_ssl.ssl.ja3_client[0] != '\0')) + || ((flow->l4.tcp.ssl_seen_server_cert == 1) && (flow->protos.stun_ssl.ssl.ja3_server[0] != '\0')) + // || (flow->host_server_name[0] != '\0') + ) protocol = NDPI_PROTOCOL_SSL; else protocol = NDPI_PROTOCOL_SSL_NO_CERT; @@ -373,7 +374,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, u_char md5_hash[16]; flow->protos.stun_ssl.ssl.ssl_version = ssl_version; - + memset(&ja3, 0, sizeof(ja3)); #ifdef CERTIFICATE_DEBUG @@ -409,7 +410,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, if((handshake_protocol == 0x02) || (handshake_protocol == 0xb) /* Server Hello and Certificate message types are interesting for us */) { u_int num_found = 0; - u_int16_t ssl_version = ntohs(*((u_int16_t*)&packet->payload[9])); + u_int16_t ssl_version = ntohs(*((u_int16_t*)&packet->payload[9])); ja3.ssl_version = ssl_version; @@ -417,12 +418,23 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t offset = 43, extension_len, j; u_int8_t session_id_len = packet->payload[43]; - offset += session_id_len+1; +#ifdef CERTIFICATE_DEBUG + printf("SSL Server Hello [version: 0x%04X]\n", ssl_version); +#endif + + /* + The server hello decides about the SSL version of this flow + https://networkengineering.stackexchange.com/questions/55752/why-does-wireshark-show-version-tls-1-2-here-instead-of-tls-1-3 + */ + flow->protos.stun_ssl.ssl.ssl_version = ssl_version; + + if(ssl_version < 0x7F15 /* TLS 1.3 lacks of session id */) + offset += session_id_len+1; ja3.num_cipher = 1, ja3.cipher[0] = ntohs(*((u_int16_t*)&packet->payload[offset])); flow->protos.stun_ssl.ssl.server_unsafe_cipher = ndpi_is_safe_ssl_cipher(ja3.cipher[0]); flow->protos.stun_ssl.ssl.server_cipher = ja3.cipher[0]; - + #ifdef CERTIFICATE_DEBUG printf("SSL [server][session_id_len: %u][cipher: %04X]\n", session_id_len, ja3.cipher[0]); #endif @@ -468,23 +480,23 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, #ifdef CERTIFICATE_DEBUG printf("SSL [server] %s\n", ja3_str); #endif - + #ifdef CERTIFICATE_DEBUG printf("[JA3] Server: %s \n", ja3_str); #endif - + MD5Init(&ctx); MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str)); MD5Final(md5_hash, &ctx); - + for(i=0, j=0; i<16; i++) j += snprintf(&flow->protos.stun_ssl.ssl.ja3_server[j], sizeof(flow->protos.stun_ssl.ssl.ja3_server)-j, "%02x", md5_hash[i]); - + #ifdef CERTIFICATE_DEBUG printf("[JA3] Server: %s \n", flow->protos.stun_ssl.ssl.ja3_server); #endif - + flow->l4.tcp.ssl_seen_server_cert = 1; } else flow->l4.tcp.ssl_seen_certificate = 1; @@ -561,7 +573,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, if((cipher_offset+cipher_len) <= total_len) { for(i=0; i<cipher_len;) { u_int16_t *id = (u_int16_t*)&packet->payload[cipher_offset+i]; - + #ifdef CERTIFICATE_DEBUG printf("Client SSL [cipher suite: %u] [%u/%u]\n", ntohs(*id), i, cipher_len); #endif @@ -570,7 +582,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, Skip GREASE [https://tools.ietf.org/id/draft-ietf-tls-grease-01.html] https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967 */ - + if(ja3.num_cipher < MAX_NUM_JA3) ja3.cipher[ja3.num_cipher++] = ntohs(*id); else { @@ -580,16 +592,16 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, #endif } } - + i += 2; } } else { invalid_ja3 = 1; #ifdef CERTIFICATE_DEBUG printf("Client SSL Invalid len %u vs %u\n", (cipher_offset+cipher_len), total_len); -#endif +#endif } - + offset = base_offset + session_id_len + cipher_len + 2; flow->l4.tcp.ssl_seen_client_cert = 1; @@ -673,7 +685,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, if((s_offset+extension_len-2) <= total_len) { for(i=0; i<extension_len-2;) { u_int16_t s_group = ntohs(*((u_int16_t*)&packet->payload[s_offset+i])); - + #ifdef CERTIFICATE_DEBUG printf("Client SSL [EllipticCurve: %u]\n", s_group); #endif @@ -681,7 +693,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, /* Skip GREASE */ if(ja3.num_elliptic_curve < MAX_NUM_JA3) ja3.elliptic_curve[ja3.num_elliptic_curve++] = s_group; - else { + else { invalid_ja3 = 1; #ifdef CERTIFICATE_DEBUG printf("Client SSL Invalid num elliptic %u\n", ja3.num_elliptic_curve); @@ -696,7 +708,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, #ifdef CERTIFICATE_DEBUG printf("Client SSL Invalid len %u vs %u\n", (s_offset+extension_len-1), total_len); #endif - } + } } else if(extension_id == 11 /* ec_point_formats groups */) { u_int16_t i, s_offset = offset+extension_offset + 1; @@ -706,11 +718,11 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, if((s_offset+extension_len) < total_len) { for(i=0; i<extension_len-1;i++) { u_int8_t s_group = packet->payload[s_offset+i]; - + #ifdef CERTIFICATE_DEBUG printf("Client SSL [EllipticCurveFormat: %u]\n", s_group); #endif - + if(ja3.num_elliptic_curve_point_format < MAX_NUM_JA3) ja3.elliptic_curve_point_format[ja3.num_elliptic_curve_point_format++] = s_group; else { @@ -727,7 +739,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, #endif } } - + extension_offset += extension_len; #ifdef CERTIFICATE_DEBUG @@ -737,30 +749,30 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, if(!invalid_ja3) { ja3_str_len = snprintf(ja3_str, sizeof(ja3_str), "%u,", ja3.ssl_version); - + for(i=0; i<ja3.num_cipher; i++) { ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.cipher[i]); } - + ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ","); - + /* ********** */ - + for(i=0; i<ja3.num_ssl_extension; i++) ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.ssl_extension[i]); - + ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ","); - + /* ********** */ - + for(i=0; i<ja3.num_elliptic_curve; i++) ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.elliptic_curve[i]); - + ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ","); - + for(i=0; i<ja3.num_elliptic_curve_point_format; i++) ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.elliptic_curve_point_format[i]); @@ -781,7 +793,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, printf("[JA3] Client: %s \n", flow->protos.stun_ssl.ssl.ja3_client); #endif } - + return(2 /* Client Certificate */); } } |