From 85d0e55759fe41f45bd1c322c0a5da515ec956ed Mon Sep 17 00:00:00 2001 From: kalindafab Date: Sun, 25 Jan 2026 15:54:19 +0200 Subject: [PATCH 1/4] adding tls certificate hash match to proto.txt --- src/include/ndpi_private.h | 1 + src/include/ndpi_typedefs.h | 6 ++++ src/lib/ndpi_main.c | 66 ++++++++++++++++++++++++++++++++++++- src/lib/protocols/tls.c | 21 ++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) diff --git a/src/include/ndpi_private.h b/src/include/ndpi_private.h index 039409bf6e0..2d0ff9a7f45 100644 --- a/src/include/ndpi_private.h +++ b/src/include/ndpi_private.h @@ -498,6 +498,7 @@ struct ndpi_detection_module_struct { u_int16_t max_payload_track_len; ndpi_str_hash *public_domain_suffixes, *ja4_custom_protos, *ndpifp_custom_protos; + ndpi_tls_cert_name_match_dynamic *dynamic_tls_cert_list; struct ndpi_address_cache *address_cache; struct { ndpi_filter *cache, *cache_shadow; diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index a56f92df25e..49f113db71e 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1634,6 +1634,12 @@ struct ndpi_ipsec_details { struct ndpi_ipsec_proposal proposal[2]; }; +typedef struct ndpi_tls_cert_name_match_dynamic { + char *cert_pattern; + u_int16_t protocol_id; + struct ndpi_tls_cert_name_match_dynamic *next; +} ndpi_tls_cert_name_match_dynamic; + struct ndpi_flow_struct { u_int16_t detected_protocol_stack[NDPI_PROTOCOL_SIZE]; struct ndpi_proto_stack protocol_stack; diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index 2a1a14e7998..b79cef345f2 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -3765,6 +3765,42 @@ static int ndpi_add_ndpifp_subprotocol(struct ndpi_detection_module_struct *ndpi return(ndpi_hash_add_entry(&ndpi_str->ndpifp_custom_protos, ndpifp, ndpifp_len, protocol_id, (void*)blocks)); } +static int ndpi_add_tls_cert_subprotocol(struct ndpi_detection_module_struct *ndpi_str, + char *cert_pattern, + u_int16_t protocol_id) { + ndpi_tls_cert_name_match_dynamic *new_rule; + + if(!cert_pattern || cert_pattern[0] == '\0') { + NDPI_LOG_ERR(ndpi_str, "Empty TLS certificate pattern\n"); + return(-1); + } + + + new_rule = (ndpi_tls_cert_name_match_dynamic *)ndpi_malloc(sizeof(*new_rule)); + if(new_rule == NULL) { + NDPI_LOG_ERR(ndpi_str, "Memory allocation failure for TLS cert rule\n"); + return(-2); + } + + /* Store the certificate pattern */ + new_rule->cert_pattern = ndpi_strdup(cert_pattern); + if(new_rule->cert_pattern == NULL) { + ndpi_free(new_rule); + NDPI_LOG_ERR(ndpi_str, "Memory allocation failure for TLS cert pattern\n"); + return(-2); + } + + new_rule->protocol_id = protocol_id; + + + new_rule->next = ndpi_str->dynamic_tls_cert_list; + ndpi_str->dynamic_tls_cert_list = new_rule; + + NDPI_LOG_DBG(ndpi_str, "Added TLS cert rule: [%s] -> protocol %u\n", + cert_pattern, protocol_id); + + return(0); +} /* ******************************************* */ @@ -4289,6 +4325,7 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(struct ndpi_glob ndpi_str->malicious_sha1_hashmap = NULL; /* Initialized on demand */ ndpi_str->ja4_custom_protos = NULL; /* Initialized on demand */ ndpi_str->ndpifp_custom_protos = NULL; /* Initialized on demand */ + ndpi_str->dynamic_tls_cert_list = NULL; /* Initialized on demand */ ndpi_str->http_url_hashmap = NULL; /* Initialized on demand */ ndpi_str->trusted_issuer_dn = NULL; /* Initialized on demand */ @@ -5340,6 +5377,17 @@ void ndpi_exit_detection_module(struct ndpi_detection_module_struct *ndpi_str) { if(ndpi_str->ndpifp_custom_protos) ndpi_hash_free(&ndpi_str->ndpifp_custom_protos); + if(ndpi_str->dynamic_tls_cert_list) { + ndpi_tls_cert_name_match_dynamic *rule = ndpi_str->dynamic_tls_cert_list; + + while(rule != NULL) { + ndpi_tls_cert_name_match_dynamic *next = rule->next; + if(rule->cert_pattern) + ndpi_free(rule->cert_pattern); + ndpi_free(rule); + rule = next; + } + } if(ndpi_str->http_url_hashmap) ndpi_hash_free(&ndpi_str->http_url_hashmap); @@ -5810,7 +5858,7 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str, while((elem = strsep(&rule, ",")) != NULL) { char *attr = elem, *value = NULL; ndpi_port_range range; - int is_tcp = 0, is_udp = 0, is_ip = 0, is_ja4 = 0, is_ndpifp = 0, is_httpurl = 0;; + int is_tcp = 0, is_udp = 0, is_ip = 0, is_ja4 = 0, is_ndpifp = 0, is_httpurl = 0, is_tls_cert = 0;; u_int8_t is_ipv6_ip = 0; if(strncmp(attr, "tcp:", 4) == 0) @@ -5873,7 +5921,17 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str, is_ndpifp = 1, value = &attr[7]; } else if(strncmp(attr, "url:", 4) == 0) { is_httpurl = 1, value = &attr[4]; + } else if(strncmp(attr, "tls_cert:", 9) == 0) { + is_tls_cert = 1, value = &attr[9]; + if (value[0] == '"') { + value++; + if (value[0] != '\0') { + size_t len=strlen(value); + if(len > 0 && value[len-1] == '"') + value[len-1] = '\0'; /* remove trailing " */ + } } + } if(is_tcp || is_udp) { u_int p_low, p_high; @@ -5924,6 +5982,11 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str, if(rc != 0) return(rc); + } else if(is_tls_cert) { + int rc = ndpi_add_tls_cert_subprotocol(ndpi_str, value, subprotocol_id); + + if(rc != 0) + return(rc); } else { int rc = ndpi_add_host_url_subprotocol(ndpi_str, value, subprotocol_id, category, breed, 0); @@ -5934,6 +5997,7 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str, return(ret); } + /* ******************************************************************** */ diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c index 4e8b16806c1..c747070eabf 100644 --- a/src/lib/protocols/tls.c +++ b/src/lib/protocols/tls.c @@ -1093,8 +1093,29 @@ void processCertificateElements(struct ndpi_detection_module_struct *ndpi_struct ndpi_lru_add_to_cache(ndpi_struct->tls_cert_cache, key, proto_id, ndpi_get_current_time(flow)); } } + /* Check dynamic TLS certificate rules from protos.txt */ + if(flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN && + ndpi_struct->dynamic_tls_cert_list != NULL) { + ndpi_tls_cert_name_match_dynamic *rule = ndpi_struct->dynamic_tls_cert_list; + while(rule != NULL) { + if(strstr(rdnSeqBuf, rule->cert_pattern) != NULL) { + ndpi_master_app_protocol proto; + ndpi_set_detected_protocol(ndpi_struct, flow, rule->protocol_id, + ndpi_get_master_proto(ndpi_struct, flow), + NDPI_CONFIDENCE_DPI); + proto.master_protocol = ndpi_get_master_proto(ndpi_struct, flow); + proto.app_protocol = rule->protocol_id; + flow->category = get_proto_category(ndpi_struct, proto); + flow->breed = get_proto_breed(ndpi_struct, proto); + ndpi_check_subprotocol_risk(ndpi_struct, flow, rule->protocol_id); + ndpi_unset_risk(ndpi_struct, flow, NDPI_NUMERIC_IP_HOST); + break; /* Match found, stop checking */ + } + rule = rule->next; + } } } + } if(flow->protos.tls_quic.subjectDN && flow->protos.tls_quic.issuerDN && (!strcmp(flow->protos.tls_quic.subjectDN, flow->protos.tls_quic.issuerDN))) { From 182ca998d614f1fe98b6632f0a59859652e468c9 Mon Sep 17 00:00:00 2001 From: kalindafab Date: Tue, 27 Jan 2026 13:05:16 +0200 Subject: [PATCH 2/4] Adding Unit test --- tls_test_cert/test_cert.pem | 20 ++++++++++++++++++++ tls_test_cert/test_key.pem | 28 ++++++++++++++++++++++++++++ tls_test_cert/test_protos.txt | 5 +++++ tls_test_cert/tls_cert_test.pcap | Bin 0 -> 3692 bytes 4 files changed, 53 insertions(+) create mode 100644 tls_test_cert/test_cert.pem create mode 100644 tls_test_cert/test_key.pem create mode 100644 tls_test_cert/test_protos.txt create mode 100644 tls_test_cert/tls_cert_test.pcap diff --git a/tls_test_cert/test_cert.pem b/tls_test_cert/test_cert.pem new file mode 100644 index 00000000000..5e6c6100e91 --- /dev/null +++ b/tls_test_cert/test_cert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDUTCCAjmgAwIBAgIULUbQtEBRJprhFCASbHdkq5NdZtAwDQYJKoZIhvcNAQEL +BQAwODELMAkGA1UEBhMCVVMxFjAUBgNVBAoMDW5EUElfVGVzdF9PcmcxETAPBgNV +BAMMCFRlc3RDZXJ0MB4XDTI2MDEyNzA5NTM1OVoXDTI3MDEyNzA5NTM1OVowODEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoMDW5EUElfVGVzdF9PcmcxETAPBgNVBAMMCFRl +c3RDZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkhvJ7MLWRiBU ++cMy1ShfLjiqpcAOMH7ujk03wc+hvg7M97TBNZI4CO90Ke94oqxW8jW4b1mGhxXu +usqbRqY//b911C/CHOjR02B+AHMEx21F8KnPynYJS8kiqE1n9wIc0VLH18vZy001 +emtW/MAJ1CO7SN3Wkj5FHf5WrTCfC0zLFxJpDPDHSI3E9nOhtxyADx6TcmYnbZko +04C2edLqlDS6OFhFqcrhBopvqf15uNBM4C06DEKaugkwjUnMovcBKVJ3PcZzjOJa +29FaNulZ2qmj32VYGulQQcrAOoSHWDVyA6kz3UfRPW84uN8sY6nNd9x5J7UO/e8Q +Hwj9eApIRQIDAQABo1MwUTAdBgNVHQ4EFgQUt5I+Hu9ONZFXfmWlIjp4HrNFSqYw +HwYDVR0jBBgwFoAUt5I+Hu9ONZFXfmWlIjp4HrNFSqYwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAQEAUAKCL//MAxbhawYgAchlHRhBv/q8V+ndrjOa +5tJh7sOGCJ4Fxp+2k3oAk6Yv0X0jikr5Ca40CWZdNU4ONaTHkl8QEvtDU/TgfFYw +ZVeyrzcP+GYyCx4o0l2Q9L/ldYn6nTicbfblPRbLhlBp71afjxmXE3EQK5pQum9n +ZNmeltzi2yAGNjTRfPSuEYCNhMFF6XocPfTKNHmhkwfAgeSjoKoDEHiticD/e1Op +6vsVIQhUyZurhIFhGitw83q1izeeNUKBk2zcn5KCZtXpq1Ior6z86z5pbBo7+ue1 +YYXASZ/b2vCvBXUaEEjSiN1g6tT4v9ggHu+8Zz06x784TkBV8Q== +-----END CERTIFICATE----- diff --git a/tls_test_cert/test_key.pem b/tls_test_cert/test_key.pem new file mode 100644 index 00000000000..4439b7d1e4c --- /dev/null +++ b/tls_test_cert/test_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCSG8nswtZGIFT5 +wzLVKF8uOKqlwA4wfu6OTTfBz6G+Dsz3tME1kjgI73Qp73iirFbyNbhvWYaHFe66 +yptGpj/9v3XUL8Ic6NHTYH4AcwTHbUXwqc/KdglLySKoTWf3AhzRUsfXy9nLTTV6 +a1b8wAnUI7tI3daSPkUd/latMJ8LTMsXEmkM8MdIjcT2c6G3HIAPHpNyZidtmSjT +gLZ50uqUNLo4WEWpyuEGim+p/Xm40EzgLToMQpq6CTCNScyi9wEpUnc9xnOM4lrb +0Vo26VnaqaPfZVga6VBBysA6hIdYNXIDqTPdR9E9bzi43yxjqc133HkntQ797xAf +CP14CkhFAgMBAAECggEAC7F3pqAtP+2Ef3y0y8RwYaWdWqiVOiJeezsI1FUGr8xF +cSmhMOVj4KsxU83bjMFYMAhGm3rBvnvt4Dso1C2n/2ncR0APO/sSF+WoD+ckocVI +DKu6eoyZz9voDyoqwOUFY2dJoSaqZo/mUMbYbl/8KWM2sO04J/od0/mv/CphACll +O1IKuaaifvIvBXrj6JfR1L/mwpkko4FPRhBoP76/0PYwf+TLWvV1jrfRYiYX8p7m +11gDAZ8cfv6/njpJXJk+xf5NAZj1oKLoyJn0s/K6aEd/7iWINQFO91n8c0t2qdqk +R7FYbaWvbK9DFZ1Dh63Ggyl5t8gvvI+OnCpGKcZZ4QKBgQDHHX0dP4ebCe8T1g+3 +mN6fWTlDjFCWsYa3irNwdxDUxN7cZOebtK767vqFTH2VWyuPatXAt3m39BqV2GhT +yUAehtTiz/0e4V/FFMH4XPoZFDH1XFARNfbcp48OGirO0YmFKnnHhwBOxIURlGny +U4Lyho985WBenLxiq2gYrV2oqQKBgQC72ZmvxubY5nzSCi/RJ0jWxk71Fz0vrARA +BLrPAiwqz8Y/7T7RgRm53OzK+6oOy1LEq4a0EMn0MUxu1Dhre4iMR/KGVARtPYTC +zYP4eoq9PH2gRvo4Rj7viydaNXCdLYhWWxUoiuOk6bnkhmY8T6L3NKgqUlg6CBu6 +sTr3PSdYPQKBgGdHI2MtVaAUOf629HYNg8NxWyNvP0m6kR7YgZRfHcrOxq3YZM29 +nVko5aaIc0cp/+Emz/Ji+G5y3etFUW/MHkb3NqriqO8AhVVLHAU/7LVfZT5YAGu8 +6uuuuaPd7MBTrRn2Wy4kFwPEKSViLsXzjSNQqlJlA2RvtcMUFy1dlwvpAoGAFbH2 +9v8g0DImfleg2CYSWoPCwLmzXlsejoo9TQUyNquSePWciLPBVd73FiZkqJrA72fk +Ac3ilSpQaohmD7vPtGvmza7MaBVvzNPRhxQYC+z9kVJBOdibEi1fGSMM44pLsbWJ +RwprajN4PbVr/1EvQB+7wE+MUv92vGQVrFJKxf0CgYB8tn1ugKAcO42y5JIXH3Dg +l0p6TGkIB3xko2HzpRVd5bERfJbwFrwofwq5Ze5V/eoffnR55RKuN4CcxQoKQ/Nk +tgMHR0uCH1CNgzdMoArH5hk0oP90I79exZ40nILCl98Q1amJiZudDilmHgXG+u+I +e7exMWDWby/uVPCiNW6L2Q== +-----END PRIVATE KEY----- diff --git a/tls_test_cert/test_protos.txt b/tls_test_cert/test_protos.txt new file mode 100644 index 00000000000..166a5d13623 --- /dev/null +++ b/tls_test_cert/test_protos.txt @@ -0,0 +1,5 @@ +# Match by Common Name +nDPI_TestApp@tls_cert:"CN=nDPI_TestCert" + +# Match by Organization +nDPI_TestOrg@tls_cert:"O=nDPI_Test_Org" diff --git a/tls_test_cert/tls_cert_test.pcap b/tls_test_cert/tls_cert_test.pcap new file mode 100644 index 0000000000000000000000000000000000000000..5e758fbbfa81ec103b7ac43f854cb757f6f312fa GIT binary patch literal 3692 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 dYAp*~KUI=L{2#N$s51Zn literal 0 HcmV?d00001 From 65e1d296893270baa37d11c1c0b1f06549e8cf37 Mon Sep 17 00:00:00 2001 From: kalindafab Date: Mon, 27 Jul 2026 10:01:21 +0200 Subject: [PATCH 3/4] implement TLS Cert hash matching --- src/include/ndpi_private.h | 2 +- src/include/ndpi_typedefs.h | 6 ++++ src/lib/ndpi_main.c | 57 +++++++++++++---------------- src/lib/protocols/tls.c | 60 +++++++++++++++++++------------ test_protos_hash.txt | 1 + tls_test_cert/test_cert.pem | 40 +++++++++++---------- tls_test_cert/test_key.pem | 52 +++++++++++++-------------- tls_test_cert/tls_cert_test.pcap | Bin 3692 -> 6231 bytes 8 files changed, 118 insertions(+), 100 deletions(-) create mode 100644 test_protos_hash.txt diff --git a/src/include/ndpi_private.h b/src/include/ndpi_private.h index 2d0ff9a7f45..18926b9ea12 100644 --- a/src/include/ndpi_private.h +++ b/src/include/ndpi_private.h @@ -498,7 +498,7 @@ struct ndpi_detection_module_struct { u_int16_t max_payload_track_len; ndpi_str_hash *public_domain_suffixes, *ja4_custom_protos, *ndpifp_custom_protos; - ndpi_tls_cert_name_match_dynamic *dynamic_tls_cert_list; + ndpi_tls_cert_hash_match_dynamic *dynamic_tls_cert_hash_list; struct ndpi_address_cache *address_cache; struct { ndpi_filter *cache, *cache_shadow; diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 49f113db71e..ec5145af228 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1640,6 +1640,12 @@ typedef struct ndpi_tls_cert_name_match_dynamic { struct ndpi_tls_cert_name_match_dynamic *next; } ndpi_tls_cert_name_match_dynamic; +typedef struct ndpi_tls_cert_hash_match_dynamic { + char *cert_hash; + u_int16_t protocol_id; + struct ndpi_tls_cert_hash_match_dynamic *next; +} ndpi_tls_cert_hash_match_dynamic; + struct ndpi_flow_struct { u_int16_t detected_protocol_stack[NDPI_PROTOCOL_SIZE]; struct ndpi_proto_stack protocol_stack; diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index b79cef345f2..e7a5760eb56 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -3765,43 +3765,34 @@ static int ndpi_add_ndpifp_subprotocol(struct ndpi_detection_module_struct *ndpi return(ndpi_hash_add_entry(&ndpi_str->ndpifp_custom_protos, ndpifp, ndpifp_len, protocol_id, (void*)blocks)); } -static int ndpi_add_tls_cert_subprotocol(struct ndpi_detection_module_struct *ndpi_str, - char *cert_pattern, - u_int16_t protocol_id) { - ndpi_tls_cert_name_match_dynamic *new_rule; +static int ndpi_add_tls_cert_hash_subprotocol(struct ndpi_detection_module_struct *ndpi_str, + char *cert_hash, + u_int16_t protocol_id) { + ndpi_tls_cert_hash_match_dynamic *new_rule; - if(!cert_pattern || cert_pattern[0] == '\0') { - NDPI_LOG_ERR(ndpi_str, "Empty TLS certificate pattern\n"); + if(!cert_hash || cert_hash[0] == '\0') { + NDPI_LOG_ERR(ndpi_str, "Empty TLS cert hash\n"); return(-1); } - - new_rule = (ndpi_tls_cert_name_match_dynamic *)ndpi_malloc(sizeof(*new_rule)); + new_rule = (ndpi_tls_cert_hash_match_dynamic *)ndpi_malloc(sizeof(*new_rule)); if(new_rule == NULL) { - NDPI_LOG_ERR(ndpi_str, "Memory allocation failure for TLS cert rule\n"); + NDPI_LOG_ERR(ndpi_str, "Memory allocation failure for TLS cert hash\n"); return(-2); } - /* Store the certificate pattern */ - new_rule->cert_pattern = ndpi_strdup(cert_pattern); - if(new_rule->cert_pattern == NULL) { + new_rule->cert_hash = ndpi_strdup(cert_hash); + if(new_rule->cert_hash == NULL) { ndpi_free(new_rule); - NDPI_LOG_ERR(ndpi_str, "Memory allocation failure for TLS cert pattern\n"); + NDPI_LOG_ERR(ndpi_str, "Memory allocation failure for TLS cert hash\n"); return(-2); } - new_rule->protocol_id = protocol_id; - - - new_rule->next = ndpi_str->dynamic_tls_cert_list; - ndpi_str->dynamic_tls_cert_list = new_rule; - - NDPI_LOG_DBG(ndpi_str, "Added TLS cert rule: [%s] -> protocol %u\n", - cert_pattern, protocol_id); + new_rule->next = ndpi_str->dynamic_tls_cert_hash_list; + ndpi_str->dynamic_tls_cert_hash_list = new_rule; return(0); } - /* ******************************************* */ static int ndpi_add_http_url_subprotocol(struct ndpi_detection_module_struct *ndpi_str, @@ -4325,7 +4316,7 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(struct ndpi_glob ndpi_str->malicious_sha1_hashmap = NULL; /* Initialized on demand */ ndpi_str->ja4_custom_protos = NULL; /* Initialized on demand */ ndpi_str->ndpifp_custom_protos = NULL; /* Initialized on demand */ - ndpi_str->dynamic_tls_cert_list = NULL; /* Initialized on demand */ + ndpi_str->dynamic_tls_cert_hash_list = NULL; /* Initialized on demand */ ndpi_str->http_url_hashmap = NULL; /* Initialized on demand */ ndpi_str->trusted_issuer_dn = NULL; /* Initialized on demand */ @@ -5377,13 +5368,13 @@ void ndpi_exit_detection_module(struct ndpi_detection_module_struct *ndpi_str) { if(ndpi_str->ndpifp_custom_protos) ndpi_hash_free(&ndpi_str->ndpifp_custom_protos); - if(ndpi_str->dynamic_tls_cert_list) { - ndpi_tls_cert_name_match_dynamic *rule = ndpi_str->dynamic_tls_cert_list; + if(ndpi_str->dynamic_tls_cert_hash_list) { + ndpi_tls_cert_hash_match_dynamic *rule = ndpi_str->dynamic_tls_cert_hash_list; while(rule != NULL) { - ndpi_tls_cert_name_match_dynamic *next = rule->next; - if(rule->cert_pattern) - ndpi_free(rule->cert_pattern); + ndpi_tls_cert_hash_match_dynamic *next = rule->next; + if(rule->cert_hash) + ndpi_free(rule->cert_hash); ndpi_free(rule); rule = next; } @@ -5858,7 +5849,7 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str, while((elem = strsep(&rule, ",")) != NULL) { char *attr = elem, *value = NULL; ndpi_port_range range; - int is_tcp = 0, is_udp = 0, is_ip = 0, is_ja4 = 0, is_ndpifp = 0, is_httpurl = 0, is_tls_cert = 0;; + int is_tcp = 0, is_udp = 0, is_ip = 0, is_ja4 = 0, is_ndpifp = 0, is_httpurl = 0, is_tls_cert_hash = 0;; u_int8_t is_ipv6_ip = 0; if(strncmp(attr, "tcp:", 4) == 0) @@ -5921,8 +5912,8 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str, is_ndpifp = 1, value = &attr[7]; } else if(strncmp(attr, "url:", 4) == 0) { is_httpurl = 1, value = &attr[4]; - } else if(strncmp(attr, "tls_cert:", 9) == 0) { - is_tls_cert = 1, value = &attr[9]; + } else if(strncmp(attr, "tls_cert_hash:", 14) == 0) { + is_tls_cert_hash = 1, value = &attr[14]; if (value[0] == '"') { value++; if (value[0] != '\0') { @@ -5982,8 +5973,8 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str, if(rc != 0) return(rc); - } else if(is_tls_cert) { - int rc = ndpi_add_tls_cert_subprotocol(ndpi_str, value, subprotocol_id); + } else if(is_tls_cert_hash) { + int rc = ndpi_add_tls_cert_hash_subprotocol(ndpi_str, value, subprotocol_id); if(rc != 0) return(rc); diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c index c747070eabf..310708f2725 100644 --- a/src/lib/protocols/tls.c +++ b/src/lib/protocols/tls.c @@ -1093,28 +1093,9 @@ void processCertificateElements(struct ndpi_detection_module_struct *ndpi_struct ndpi_lru_add_to_cache(ndpi_struct->tls_cert_cache, key, proto_id, ndpi_get_current_time(flow)); } } - /* Check dynamic TLS certificate rules from protos.txt */ - if(flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN && - ndpi_struct->dynamic_tls_cert_list != NULL) { - ndpi_tls_cert_name_match_dynamic *rule = ndpi_struct->dynamic_tls_cert_list; - while(rule != NULL) { - if(strstr(rdnSeqBuf, rule->cert_pattern) != NULL) { - ndpi_master_app_protocol proto; - ndpi_set_detected_protocol(ndpi_struct, flow, rule->protocol_id, - ndpi_get_master_proto(ndpi_struct, flow), - NDPI_CONFIDENCE_DPI); - proto.master_protocol = ndpi_get_master_proto(ndpi_struct, flow); - proto.app_protocol = rule->protocol_id; - flow->category = get_proto_category(ndpi_struct, proto); - flow->breed = get_proto_breed(ndpi_struct, proto); - ndpi_check_subprotocol_risk(ndpi_struct, flow, rule->protocol_id); - ndpi_unset_risk(ndpi_struct, flow, NDPI_NUMERIC_IP_HOST); - break; /* Match found, stop checking */ - } - rule = rule->next; - } } - } + + } if(flow->protos.tls_quic.subjectDN && flow->protos.tls_quic.issuerDN @@ -1276,10 +1257,45 @@ int processCertificate(struct ndpi_detection_module_struct *ndpi_struct, if(rc1 == 0) ndpi_set_risk(ndpi_struct, flow, NDPI_MALICIOUS_SHA1_CERTIFICATE, sha1_str); } + + if(flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN && + ndpi_struct->dynamic_tls_cert_hash_list != NULL) { + + ndpi_tls_cert_hash_match_dynamic *rule = ndpi_struct->dynamic_tls_cert_hash_list; + + while(rule != NULL) { + char rule_hash_no_colon[256]; + int j = 0; + for(int i = 0; rule->cert_hash[i] != '\0' && j < (int)sizeof(rule_hash_no_colon)-1; i++) { + if(rule->cert_hash[i] != ':') { + rule_hash_no_colon[j++] = toupper((unsigned char)rule->cert_hash[i]); + } + } + rule_hash_no_colon[j] = '\0'; + + + if(strcasecmp(sha1_str, rule_hash_no_colon) == 0) { + /* Hash match found */ + ndpi_master_app_protocol proto; + + ndpi_set_detected_protocol(ndpi_struct, flow, rule->protocol_id, + ndpi_get_master_proto(ndpi_struct, flow), + NDPI_CONFIDENCE_DPI); + proto.master_protocol = ndpi_get_master_proto(ndpi_struct, flow); + proto.app_protocol = rule->protocol_id; + flow->category = get_proto_category(ndpi_struct, proto); + flow->breed = get_proto_breed(ndpi_struct, proto); + ndpi_check_subprotocol_risk(ndpi_struct, flow, rule->protocol_id); + ndpi_unset_risk(ndpi_struct, flow, NDPI_NUMERIC_IP_HOST); + break; + } + rule = rule->next; + } + } } processCertificateElements(ndpi_struct, flow, certificates_offset, certificate_len); - } + } certificates_offset += certificate_len; } diff --git a/test_protos_hash.txt b/test_protos_hash.txt new file mode 100644 index 00000000000..b8080793b7d --- /dev/null +++ b/test_protos_hash.txt @@ -0,0 +1 @@ +nDPI_TestApp@tls_cert_hash:"da:39:a3:ee:5e:6b:4b:0d:32:55:bf:ef:95:60:18:90:af:d8:07:09" diff --git a/tls_test_cert/test_cert.pem b/tls_test_cert/test_cert.pem index 5e6c6100e91..2e6f9f3dcc5 100644 --- a/tls_test_cert/test_cert.pem +++ b/tls_test_cert/test_cert.pem @@ -1,20 +1,24 @@ -----BEGIN CERTIFICATE----- -MIIDUTCCAjmgAwIBAgIULUbQtEBRJprhFCASbHdkq5NdZtAwDQYJKoZIhvcNAQEL -BQAwODELMAkGA1UEBhMCVVMxFjAUBgNVBAoMDW5EUElfVGVzdF9PcmcxETAPBgNV -BAMMCFRlc3RDZXJ0MB4XDTI2MDEyNzA5NTM1OVoXDTI3MDEyNzA5NTM1OVowODEL -MAkGA1UEBhMCVVMxFjAUBgNVBAoMDW5EUElfVGVzdF9PcmcxETAPBgNVBAMMCFRl -c3RDZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkhvJ7MLWRiBU -+cMy1ShfLjiqpcAOMH7ujk03wc+hvg7M97TBNZI4CO90Ke94oqxW8jW4b1mGhxXu -usqbRqY//b911C/CHOjR02B+AHMEx21F8KnPynYJS8kiqE1n9wIc0VLH18vZy001 -emtW/MAJ1CO7SN3Wkj5FHf5WrTCfC0zLFxJpDPDHSI3E9nOhtxyADx6TcmYnbZko -04C2edLqlDS6OFhFqcrhBopvqf15uNBM4C06DEKaugkwjUnMovcBKVJ3PcZzjOJa -29FaNulZ2qmj32VYGulQQcrAOoSHWDVyA6kz3UfRPW84uN8sY6nNd9x5J7UO/e8Q -Hwj9eApIRQIDAQABo1MwUTAdBgNVHQ4EFgQUt5I+Hu9ONZFXfmWlIjp4HrNFSqYw -HwYDVR0jBBgwFoAUt5I+Hu9ONZFXfmWlIjp4HrNFSqYwDwYDVR0TAQH/BAUwAwEB -/zANBgkqhkiG9w0BAQsFAAOCAQEAUAKCL//MAxbhawYgAchlHRhBv/q8V+ndrjOa -5tJh7sOGCJ4Fxp+2k3oAk6Yv0X0jikr5Ca40CWZdNU4ONaTHkl8QEvtDU/TgfFYw -ZVeyrzcP+GYyCx4o0l2Q9L/ldYn6nTicbfblPRbLhlBp71afjxmXE3EQK5pQum9n -ZNmeltzi2yAGNjTRfPSuEYCNhMFF6XocPfTKNHmhkwfAgeSjoKoDEHiticD/e1Op -6vsVIQhUyZurhIFhGitw83q1izeeNUKBk2zcn5KCZtXpq1Ior6z86z5pbBo7+ue1 -YYXASZ/b2vCvBXUaEEjSiN1g6tT4v9ggHu+8Zz06x784TkBV8Q== +MIIEAzCCAuugAwIBAgIUGpLRiLOOApm+pLR7eUZBQmXwd/AwDQYJKoZIhvcNAQEL +BQAwgZAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH +DA1TYW4gRnJhbmNpc2NvMR8wHQYDVQQKDBZuRFBJX1Rlc3RfT3JnYW5pemF0aW9u +MRAwDgYDVQQLDAdUZXN0aW5nMSEwHwYDVQQDDBhuRFBJX1Rlc3RBcHBfQ2VydGlm +aWNhdGUwHhcNMjYwNzI1MTAwNjQ2WhcNMjcwNzI1MTAwNjQ2WjCBkDELMAkGA1UE +BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lz +Y28xHzAdBgNVBAoMFm5EUElfVGVzdF9Pcmdhbml6YXRpb24xEDAOBgNVBAsMB1Rl +c3RpbmcxITAfBgNVBAMMGG5EUElfVGVzdEFwcF9DZXJ0aWZpY2F0ZTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBANbsezILR6MkDuSWPRKlNhGfy0ItXbw7 +9S1F9NFevvckTwvyK7CtTNh4SeukgFqTnwIe5t0WMKg8I6DVUjSAP+BctMk7ZC0q +yfTSijMQ4DPjAFmj9DztZpMTwP/YfKaNIO4qTDknZ7LaOBVaIjdsL2++W9wFo6hq +zMAhfjcfvLp70oWGPz7i3dhvJ925ymbrrDXY2mpNmEhuAB5MtBIL6pxP389ygWyo +8QrnTzhErt3JDSq+N73bNeq1t/hwV7Ufg+SBNtURoT6vLpOgwbAi3w3zk3mgPoxO +iB6YoNhpi4Sqh0Dzbvf2UFVGClfzKsB40NsmGrjFs7XgFIoqIAv8H2sCAwEAAaNT +MFEwHQYDVR0OBBYEFOqbaHUFL/kbmDjQie14VJ7Uvf2hMB8GA1UdIwQYMBaAFOqb +aHUFL/kbmDjQie14VJ7Uvf2hMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAEctiMs+zoaQ7LCk00geSCJFnFoeNYL/LFetksJRiCJkDC1Hy9PVtn86 +axYNai2I+w1eEOdNjHR9E43Cl3bxwnQM064iekEdhGQmjfDYVXjdQtTt8Y0Gs/95 +O/cnDVotmcfQdRzkNAlc5KEviy0YepKMajmBYRFwbg9Up6UGKjeHreZA0ebUx/BE +plCkBANCSPnBGLnTJD8YOkPORqlutAJtxDB5IWrjrlfjnX5h++mmS5B263C/TR4m +3BRnXMEhft056NDPDMzZI+fxGAn4xpMejd4ZfZd6l+YeYpxZyMn/4WuuyglnEDhp +ptU731ISG3+QJKG8+LHIlz78xx3GDxw= -----END CERTIFICATE----- diff --git a/tls_test_cert/test_key.pem b/tls_test_cert/test_key.pem index 4439b7d1e4c..720020a7a06 100644 --- a/tls_test_cert/test_key.pem +++ b/tls_test_cert/test_key.pem @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCSG8nswtZGIFT5 -wzLVKF8uOKqlwA4wfu6OTTfBz6G+Dsz3tME1kjgI73Qp73iirFbyNbhvWYaHFe66 -yptGpj/9v3XUL8Ic6NHTYH4AcwTHbUXwqc/KdglLySKoTWf3AhzRUsfXy9nLTTV6 -a1b8wAnUI7tI3daSPkUd/latMJ8LTMsXEmkM8MdIjcT2c6G3HIAPHpNyZidtmSjT -gLZ50uqUNLo4WEWpyuEGim+p/Xm40EzgLToMQpq6CTCNScyi9wEpUnc9xnOM4lrb -0Vo26VnaqaPfZVga6VBBysA6hIdYNXIDqTPdR9E9bzi43yxjqc133HkntQ797xAf -CP14CkhFAgMBAAECggEAC7F3pqAtP+2Ef3y0y8RwYaWdWqiVOiJeezsI1FUGr8xF -cSmhMOVj4KsxU83bjMFYMAhGm3rBvnvt4Dso1C2n/2ncR0APO/sSF+WoD+ckocVI -DKu6eoyZz9voDyoqwOUFY2dJoSaqZo/mUMbYbl/8KWM2sO04J/od0/mv/CphACll -O1IKuaaifvIvBXrj6JfR1L/mwpkko4FPRhBoP76/0PYwf+TLWvV1jrfRYiYX8p7m -11gDAZ8cfv6/njpJXJk+xf5NAZj1oKLoyJn0s/K6aEd/7iWINQFO91n8c0t2qdqk -R7FYbaWvbK9DFZ1Dh63Ggyl5t8gvvI+OnCpGKcZZ4QKBgQDHHX0dP4ebCe8T1g+3 -mN6fWTlDjFCWsYa3irNwdxDUxN7cZOebtK767vqFTH2VWyuPatXAt3m39BqV2GhT -yUAehtTiz/0e4V/FFMH4XPoZFDH1XFARNfbcp48OGirO0YmFKnnHhwBOxIURlGny -U4Lyho985WBenLxiq2gYrV2oqQKBgQC72ZmvxubY5nzSCi/RJ0jWxk71Fz0vrARA -BLrPAiwqz8Y/7T7RgRm53OzK+6oOy1LEq4a0EMn0MUxu1Dhre4iMR/KGVARtPYTC -zYP4eoq9PH2gRvo4Rj7viydaNXCdLYhWWxUoiuOk6bnkhmY8T6L3NKgqUlg6CBu6 -sTr3PSdYPQKBgGdHI2MtVaAUOf629HYNg8NxWyNvP0m6kR7YgZRfHcrOxq3YZM29 -nVko5aaIc0cp/+Emz/Ji+G5y3etFUW/MHkb3NqriqO8AhVVLHAU/7LVfZT5YAGu8 -6uuuuaPd7MBTrRn2Wy4kFwPEKSViLsXzjSNQqlJlA2RvtcMUFy1dlwvpAoGAFbH2 -9v8g0DImfleg2CYSWoPCwLmzXlsejoo9TQUyNquSePWciLPBVd73FiZkqJrA72fk -Ac3ilSpQaohmD7vPtGvmza7MaBVvzNPRhxQYC+z9kVJBOdibEi1fGSMM44pLsbWJ -RwprajN4PbVr/1EvQB+7wE+MUv92vGQVrFJKxf0CgYB8tn1ugKAcO42y5JIXH3Dg -l0p6TGkIB3xko2HzpRVd5bERfJbwFrwofwq5Ze5V/eoffnR55RKuN4CcxQoKQ/Nk -tgMHR0uCH1CNgzdMoArH5hk0oP90I79exZ40nILCl98Q1amJiZudDilmHgXG+u+I -e7exMWDWby/uVPCiNW6L2Q== +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDW7HsyC0ejJA7k +lj0SpTYRn8tCLV28O/UtRfTRXr73JE8L8iuwrUzYeEnrpIBak58CHubdFjCoPCOg +1VI0gD/gXLTJO2QtKsn00oozEOAz4wBZo/Q87WaTE8D/2HymjSDuKkw5J2ey2jgV +WiI3bC9vvlvcBaOoaszAIX43H7y6e9KFhj8+4t3Ybyfducpm66w12NpqTZhIbgAe +TLQSC+qcT9/PcoFsqPEK5084RK7dyQ0qvje92zXqtbf4cFe1H4PkgTbVEaE+ry6T +oMGwIt8N85N5oD6MTogemKDYaYuEqodA82739lBVRgpX8yrAeNDbJhq4xbO14BSK +KiAL/B9rAgMBAAECggEAAnHfNuME9hifaL9Cw5cIhevM6pxMgCsob1Ln5YfP4UzS +715aW+CkyqOXp6wP37flK6eBVct+UzOX7ijvDfTVhS5Yyh84VQEzGetZMhqDimOP +KfXg/d5vd8XWQLLMPDLHyJ3HjzDhD5pG4AtN71Z2Na2zKs4PngdU++yFnIfqZC6m +EMCnaVy+vG/FH072IOD7g9avBv3y765crOZnskscbzjsh8GGqbNYAM8WzoHQLaxg +/JXNtMcg5E92vLhoIdk5oicsxGNbppl+SqBxp3M0R0qjpYNybaeZ9aBdFgn9lxii +aZSZJoL7o1eKtabg3hipZaUnZtxMN7X5Kw2jyDw0PQKBgQDrQfz2J/01Ji/EGn/M +npAXgFUO+MWetWKVGdScj2d0GO7DHekoN4+CkQUthyY8y/30nXIRGnY+Y4JugpOi +JP7htK4oDOzGYS6MMT+kUMv1FnWhmbFH1JjaGElVOXy3lct+QYYRCX6tZXEsXYdK +74dLtYwcxOjcOuCdWltRPOPjXQKBgQDp34iK2ACU44XD4so9BZ2Mh26M4rABQY7Q +vmOgdM0TrEq0aWeNU1DR1g2H/Xuc/5LlZg0Jw+biFkX8TiaW6c1d5K/jJjDcQN2P +SOMqHUjtkufnLVYsbH8KfbMmZWFdmqmia8OmsXgZo7VB1tmU9wzSeg8SuRLmPlLH +tBSSwgzpZwKBgGXygpxpV+DgW3KvyRHy5J5KjpGeXIUaNU5Hk0sFGd/FrjH/lDpJ +WXdLQOMp3fgarkKCuBuRTAxdMviQvUlWnt1QXugcMb8F/hXigaHDIZ9jzDXrVFe8 +WUCppZ24+8LStwxPeLmJU8vwWcrP/QEMK6UzVzRgYEiPeya1MT1TFa5BAoGBAJvR +Ypee8kRAko7AOx4M77sBQJZ9MeakVxKcxqPRLhE9aUhqMaPnLqGfi8RfDky7upM8 +OtOWwe1ACcDgELXbcAhupQEiIMueK/+bAD6+5CflCLztZ8yRPNMwjHu4b/Z9ZSfh +xKj69JmgiNMk4jJtpw1UZVaEGCNuwphrUom04AVhAoGAWINTXulnmcjN9qNlgeQK +gx6tOjkLXms0E+Qzc5DoQQs10tqV7OCoqCyaAB1jG5qTSH8S90pymZyrYVWbwYZu +UeejMmWyz2LHbXsLNJhNNyhHXryjngDTMHQZdPAe4D0JVpaQneR89zC0fgjjxJqs +F4XdupKVcAoySZ97HvAjbaw= -----END PRIVATE KEY----- diff --git a/tls_test_cert/tls_cert_test.pcap b/tls_test_cert/tls_cert_test.pcap index 5e758fbbfa81ec103b7ac43f854cb757f6f312fa..9cebdebc764558065486b4ff0e126d8cefa5ebc0 100644 GIT binary patch literal 6231 zcmai&1yodP*T>HUDUC36DnmCSB}2D_}0|QXtzY7Y0&>u{rt?#I55&^2{_Za(q z;Q|T(APHAP00?Xf*I)nuVXQ%zRNHNWc@A@BF8KWQPksOZL(gAB!MOMy5>};{??Dg< zK8B3^BN+fNWXaZFWK!)0VJYOAESf%_OLji|JGs5!9Ezd;B3q-$vS?2j`+Z$#7KW=| zX!ia^{*UH)G+i!)1VH>`M{5NAr58iSXg${=0?e_23;QP#TL-RzArc$>E0GF7K$ZR` zmSKpL5D+#s2*9R*Km^@y+B_cywcFyqq}LnIXl$ZneBJtR(8jCA-B5{`XOSt){%)7; zL_>Mdl8WBUos6u$vC?*DV92y4oNr;ryOIKsBnOj2$U!J>6hDwNQaVyHQikF}@c~a! zS5WMLBZ?IT2kcPzsLOyD3J*mN2m#qZ79a&k0wMq(2*64>2VHD7Ko8IY0F{fpmWr9K zji;B4o12-OjfaN^8tuyjt&EgRfl;e?M-^$(hNP6#*vR_hqi7#m=q$|YZq3iH5 zwF`Oem0DVRB9roprdmPRpp0Of6`LE|s09`NwUwY24?{JjJY~8+QN9LHH!kMP3f4uxNx|ppY57Uy4;S(my|+euQJ9MXa1pHti`lP|RtQJik@Go`VtPS?yD z+z?V0UAi^)6hr_WD)=VAIYkLdt|)pxAVVl&`FJD!YX05%q+ph5Z@*bV=cp@#pQ7Ge zzU0x%9_mS4{J^P&ilO38%#}#D&RvfO&&~KEO5FELVr`{-+nxkku@NP51dD=01|pOx zI>y-~4Ah4{%2fCD`=^L_pVp@WgyBzzao|Sd19BpQAQ3{{0Uy!qd=)LXC}>KUWxqw{ zp;*P$yANvQydCM-Gi-A77jAM41B$3#i`?esw^}ZSNU~Dyc)K#BP#_z7JD5^WuH21IB$??FlO+x&n-T6T>gQXd_HEOtMNHZHW@*@#~OP`pD8gDq#vqajVG%?h~%Nb zQu196&QJ<|h{Jvuf{i+iqYVH)!~VDc%4&qZUY1MLv8C@)VajdrToPE zKwHmE(G;pX>0qYj1jS`ROK`f5o)z*iHEf8FL%>*5*qKwABXyX?%}Cuh(T(>Zl3!VW zrzJ9ig44y&-3i_vt2dn7eb>uUk!`tWRt1Gr<+zu*g zEx`{t#~oJeLHjA(}sjw}S=$Vxm%9p#!OoQKwwFZJr>p8u{$&+Kq zBP{u=Vz7w(o6CQyUVgz!QLLZXFd%;PX3&`Q3XXlnL2G=H4=6}n?xb}+zgn6x=kc0* z_EgG{f&%vfdlT#4IJx_R)6|;2PNjxBr^wVtZ=IinVNXhgq-M803iaH7Eb|heizU-* zqNTYS@XBV9npin9-rDY%vYYmme~JR*^o>~tL1$KU^~J)pT?nS%;AsD;gKY(3`i-W- zuYU8N-YDlb0Y64}u$#X+7`oSBq5EPPhIq@D2x!CyF6^Hj48M3Q2t$;g{8u6sa1%G{ zuMUPL5@U#z5D2stJu);wApNYK85Hns7VAwy^J^mH#SF|s52Jg8wadca71#`p#r(e= zj2z8zL6?3o1d6Ws*64a~ZX6S0P`~J!4%Mo$*R!6BfU$r>*m?M(9e)4DSnD!=`hB@3Nz4GZ6vLH8{#p=_F~y zmF%8<7KWcjJPe-3sq$-Jvk1%4<_kSl5u&vTt;b4LT@j&N-$o4dPrq^sbdy>p-Cp(R zaa9E3)?w_G6Y#c`w8PFT0x}EzzF%BsZ$u%4?rIjyMKx@zCTg?5rPJlYLp~D*<09~# z*Uj|BjSAiK`oNC?rf7$ND+0!nPC;_33Ia3NfF()j^4e=$+s zIQ#B%+)F~Ed{V^5hjAgh=rETz_w6=B)Ta`}Elfxq%LokFeXu0SRjkuL?`(aE7@IYd zX}e>ftxMilc3kIcRGO#87~0E$;5ssJYqw>fYNGjZOEMfR9kV%*Q{vyKEN{GdrCEkUR6di~!{|YkI_nWHsu%^f} z1XJj@+PpaoQjE8hc3?DTdX!4Tk^SaKs8qpg<=pslAwKlmP`zv$g#6H2y^f;O_c-rP zYNifi9k#h{hqczeQ^W24SiUc@nv~Jq-Whb+({fsV(Q%vGd^7UyDwb*L%L>yMajVxy z1ne7IW?kWkyCCp$JkK&e8uA)KsXUVrR57_t@H>JOe!T3u_8^xEiXJUWGn z;U|=_mX6Ui&c(kKl@*b_!&xQwB{Z{BqTM)BYx-g5jihlIRA{Kh@s)J=_~D)__C8CM zQAY-ie^dMuQV9nTcqbiCSoZh3b-sCP#-)(vm=qO)8qpTm~ zbl2qFY@MBD^4cZ3MJmb;`#wGnPrDtgm<3oWF>ras=FC`ncL|BgGq%~7D<*`G7GL9@ z>FW__A7Wz&5c8^`q%i(lcKLwBal%*ys-pL>t2@Mhq!EH8s+ zEjL6{;_fXYzCoxsg@H$Pv6St4WblVO!_vMBcTZq|&*nFCRhqtHiHr=2F>W%QuX((u z{3lNKI)wy3j}boHW-9)lLuDA_vUwvXLyQ{4i=oa>U|Kwi`Ct7SL&yvyRQ5>P@l7wI zM@$e1hJJ;u81Q^4GcVMs@boxGu)T;Lr0CO7*_Q}i zy+-VqBrWADj9wLszEhngA8Ak*So!3);cI5BU06gAy7Gl#XM&uxo?2EIh!@<$AL31U zoBdAjKCidLC1(7BtS*;XP`4_v2CLW+1K-{k*tfYy@7odu^oq1i93oqUN1mOIwkN1* z%l=f@g0XD(q?>HyTibES=V_1r_@S;Fvx$}dt?Y*X>&FXEXutZlGE48&SGn57P0qUKwrb$%SjW;i->Qp@Dyc3k3KJ1(Cs4-c0N@7kAIa{p*c zKwpZd^!DBDy3MPDclkfh*y|u zvl^O0VC%gncZiqLBUtbQdMX6}iQw9Ic;MP#&m+7FiwGEv^7qxDLmCGE1v^FMFXANQ z4L2+zcvjm_T6gKQcoL9pn<^FN8E zV8#&1595T1=3?}%(Sj?UkQ(~jT)Eyv)7@w78ZuF~@&r!F2jqGK^@+I8@x3P%h-N;N ztQ2y}If-7g2+aH_$ESC|Ox%*FrqPt~@gB_HOc?qFA$t@&jELBk#ajd~C{K@~?KXuFRS)K2`>pQqL38p(dg@iV`L4W^~H zlnbw)kl|*qNhp){kcKY&3|=aUGO;%nt98l#c;=8Zz*?cJr_+X|@J5$XcOG}Q=PRm^ z*7SAiE0n^^3U=rE?2rX)5vlJS;oSdbK;=scP^B?}kRJW6=vw8YkKOu7~jY{&YrA5z_Tu zVVCM`lx=}^Jo(!#b?uifbIXmvKPwIe{7LM;3k61gv5<9 zGIG?(i_SvIO5g6?oq=hSN2v}DJO<%z5yE0u$JF>$Mkbc9@ZRmWuyucm6)S!Wm53u) zAM(UzjaJ_v6)}i3?LbwEkNBkHnA}f~qq66EP<{C5?p7M*yBlrQQsI~yt1!p?YMF{5 z$5gbR?vZSLB3`M-ln5Iuh)XREox62W(p9B47Y=nUNCndYZ_g+A{w zKZ#bK;^rkXH)tJZh&4qIv41$&xp{H0f(GbKLl zNur|a>gUO(rAL-8HL(R4Q&u^YBqzbaqSSK71&v2@UN4L^pWM%v3`6Q7C9BM<%s&NJ zYGM@5pcTrXPvbE5`@$#$32oiOD7-2EOW|LC1$LX1g5VN^==ADl*iqI`)K+vP4-sT2FO03-f!+ABAt^qur%1} z$Z)yNZEx-H6?&S#Xy@MoY$=566hIj=^vniJM3q{K8g>e*GuJ!8DALU?@*$xeQwpG8w_e9fN{x!>Mwen~@s@4776~`0z$>>J8rv_;cRP3vy?zKlJ(kiN+&B^S= z@eH_fO>Ma0fbV(SFAx(UJit8_Y%yN$P$GIde+fd7OI%d8=>GAU){4pkCZMo;e++2w zML^~LH=uise+;OPY+`djm{d_PPi0=%e!nL(x81m?F>#)SnGWw{wAF^ARx{;L$~3`1 zTA(HuU0AO`Bkk(qgBK3-b>-1l?4rbGEd}Btc|d)wlOKruB_m^aKbcjbq>UlM%>Q<49EB=lp} z@Ru?iwY?IuH`i0}#&_h_w{}cgIyqv_Af-ppci(9Dl_#$IvERp~KH zsl6PwFeCcj5apwcH71AC71TDZ!`VprUCw~=Zy*?bMW)w@#u+iY*=wDYI?eW=q1lZY z=oBWP;=zB+O0A0=^7s|dzp|2DMGCp!fX+(O-?Fj^okJuTB0~rffJ8s+82f!)WTiS> z`+{inuS6;|5%G6cUJxvHeG1Xrs+-4degEw4^39m zmVfGCq!oqH9{NY^TcH=85dZKra^Z>ee+~&QJYk4YeTh?|rAEqpnWhb6xjbvt7UY|Nigie(v|}X40>t00#WCFaUx-Jc{&l zyGz9bWB5H1OBW6p0iaFJ)Cc-p9m0VCKuDCo6EJ6G#U>;FOh>VM7d8NZ!mxWWC>-~} zuZgwD_YfMr3?X;@mJ9$w)~;S83z(O`Q)`*_gy~n(SFl@uCL{Dk@-R%^24_NI>EdYC zAZKwjOD>ZC)_et~Q-b(WU_lYq2z}FwP!X+%&*6a!YzY!e7ea&%kZ&Nwzh-_(6h#5{ zp6|pugeZ)LAQ=ci5@>XwT|JXn-;ZX-Rx8_0rJY!n)uAItYG>)NijQi_hw;epdyb&i z3Z!L3=Q0(B9`2Yg#JKqE?6OL<2<=JoZ*LI;x&#yfO@J8d7#qN~hj|ZkALcWZ8LA+S zv6`U>$P77#0&rn)GX%j_#&QM$sDo5M13Ew(Yyzr)4PVe@zymO70HFXk5C(!k5{LjP zuo8&E5+Mi$p&<;AgRfc`4iPx`fD%x|ps{E!G;SFVhg**0#_`}VI4q6}17RU9xD03r zjl!U?C@vIG23QOlgGK`tfPx@6{Ti?uP9Y=upgUJmqPNT0q}tV|{T^RPNz(RxKJWPq zPxBaEkc?16Y(E9t{_lnCvqfxoI=X24-&=&j%DPk+#1AbjDI{Wh9YSoR;Qb%C% zwbIs@+*|yV+zNBPF_+Q(U<@Bb zZd20}gwsQi2>dFt(68ZiH@Qk9IMcPj$sn9{z&?c^GwcBWhCbn8SX>%Bpi#vi$n+n7 z8XsGxxnDWhzLm*H3A}W88DvvulrZYb91fn@t0FQO*m=T4DCKq+>g2Ki&VL zZtB&y!II?3a_L4?=;h?GUUk{oy>d+cdqoB|_%;G?6?TCU7GAT@uy1j2a$K?08*v z;LIKc-D(|mw`9kWFP$=sHZL9`SM;V$UqWU=bZxcKtG=}3soPi`2GIVY&4qF6AXo_=AKRZ;)b zt@PBmJsv047Y_K$nKg`fsk^*-D@D;-M%-o^Es|zwDG)FdRxCCpw$Q;RIXXfcFQSA< z=@5>bb;ZlHGmX2(Kase5(zx7d841&ctb;kJx?9q34EW))#uFY>{&YIFHT_l$JupO6 zr@KS(NnKu?~4`)<{`xSa&LhXF;-= z7*R{T*_YyYkVQH4xpa?}a}?Fv`ILsG%I=c%j57b30DH*tVMFuSux*mdsOrh0K~ksawWO(?;^ z-OzqIVfRU1+AzNmCeLJOUT;n+@a8maa%cbL(*CqO+;D4C6uR{h&DKIjA8V){@${>} zQHnw4L?V^fpdmnH^YrjY{QdelO7yARc+ey#5Gk>bI{hlTCsaLmZ^Db5+R10x)Y+@q zk0!hl3&v9%rEX?0F+Lvny5s%_r#^Te$U3(=)`7S?M(Xtyus1IGZl~|p|G0H2mFmlf zB?UCh(-cPk@G_jEot+&T&#iN9tfEzz^+atI4})GqD@JyN>l2F(zbuYr-?lt48C46toa~%Z6PtB0`5C# zWuAz%czk)NzVxh5NzzyOi(_QXg5s6Fx`7sU$L8{15sRMJm|sYswvyHb*6wJYk?jq z(XzeaPlYF0bj6irpYMe>$g=3ZZ?Cv+mi1JaL(}wx-;XhJN8ELJj2a!f-e~iaUAg_s zESVd2ds2BD8cJq&p-yvwV;fvb*lfbA-H(Z<*hi zS{`LhRXHC-WXASNkuYbDZ7@x_w?A`TWi@hQ8M&DKH$?V&cW1JLqU+9kQ|BAX*lM>g zZWG#f%`(w_yL8zn+)$)u+BNhT_KwC}6H)#_&226W|CWoa_Nfeuc*;$B1S{?ta-EEXPr8>2i`3ZR1TP+z9$dS%Oi0gClAP$}mNGx5P`v)pH2O+k% z{E{dN6aBsqiAIF@&nazGwrvwG{ceH*R8^@&jph>_YY~2>kYGhq!V1M$4`d(OVfjFB zoiC(J>caBMX0FJaZ3s20P~MPfN%E7Y;D!&+3wd7s15tQ74-X9B(T&8?#kn6*@3Th~ zIyx^Z{5BZpCsB(zZxx31ru%9Pq z)B7sl)Lyp{&sQRy4H8{Zt&+grrjZ-{!2hW~DNkC!>=3JL))W_D}6~8^l`3p zhPdWd(+}L+;z}*{pi7Ugmo1=%?;{S z=UkS@Rc6eDc&uw1YV#HTZ@gFKlSeG3cayT@$F)u8Ol>mECHabL1~T2&E)T&RFc&*6 zKC$sd4Nr4`YF_n1-bQGoH6sjL&Goflv*amtL(EW^4_Si4|v*Y`=05gQ@fgNcP9b&iTX zEZH+14_sPs2E|(8?8rlv8Fr#;N}6oXnkrRJc1-*BvdM^{e-`|IN;Q!$+BHz!IyCzHrenbvT$3;bI9lizCZJA@FOj2DUD`t|ELyuB2V ze*H;%6Vk7QkFPdsY1pK)4R3VWjMt3E$?j`Gv`ZBKPJ5pNC)42{Gc8~_nFM}#_IUtr dYAp*~KUI=L{2#N$s51Zn From d4b882321021f3cdd0b9762d38ec05290455167b Mon Sep 17 00:00:00 2001 From: kalindafab Date: Mon, 31 Aug 2026 11:49:27 +0200 Subject: [PATCH 4/4] update TLS certificate protocol matching --- src/lib/ndpi_main.c | 74 +++++++++++++++++++++++++++-------- src/lib/protocols/tls.c | 15 +++++++ tls_test_cert/test_protos.txt | 7 +--- 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index e7a5760eb56..68b191e1723 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -5686,6 +5686,61 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str, ndpi_protocol_category_t category = NDPI_PROTOCOL_CATEGORY_UNSPECIFIED; ndpi_protocol_breed_t breed = NDPI_PROTOCOL_ACCEPTABLE; + if(strncmp(rule, "tls_cert_hash:", 14) == 0) { + + char *hash_start = &rule[14]; + char *at_sign = strchr(hash_start, '@'); + + if(at_sign != NULL) { + int hash_len = at_sign - hash_start; + char *cert_hash = (char *)ndpi_malloc(hash_len + 1); + if(cert_hash == NULL) { + NDPI_LOG_ERR(ndpi_str, "Memory allocation failure for TLS cert hash\n"); + return(-1); + } + strncpy(cert_hash, hash_start, hash_len); + cert_hash[hash_len] = '\0'; + char *proto_name = &at_sign[1]; + u_int16_t proto_id = ndpi_get_proto_by_name(ndpi_str, proto_name); + + if(proto_id == NDPI_PROTOCOL_UNKNOWN) { + if(ndpi_str->num_supported_protocols >= 65535) { + NDPI_LOG_ERR(ndpi_str, "Too many protocols defined\n"); + ndpi_free(cert_hash); + return(-2); + } + + proto_id = ndpi_str->num_supported_protocols; + ndpi_port_range ports_a[MAX_DEFAULT_PORTS], ports_b[MAX_DEFAULT_PORTS]; + + ret = ndpi_set_proto_defaults(ndpi_str, 1, 1, + NDPI_PROTOCOL_ACCEPTABLE, + proto_id, + proto_name, + NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, + NDPI_PROTOCOL_QOE_CATEGORY_UNSPECIFIED, + ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0), + ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0), + 1); + if(ret != 0) { + NDPI_LOG_ERR(ndpi_str, "Error creating protocol. Skip rule\n"); + ndpi_free(cert_hash); + return(-3); + } + } + + /*hash rule*/ + ret = ndpi_add_tls_cert_hash_subprotocol(ndpi_str, cert_hash, proto_id); + printf("[DEBUG] Added TLS cert hash rule: hash=%s, proto_id=%u, ret=%d\n", + cert_hash, proto_id, ret); + ndpi_free(cert_hash); + return(ret); + } else { + NDPI_LOG_ERR(ndpi_str, "Invalid TLS cert hash rule format: %s\n", rule); + return(-1); + } + } + at = strrchr(rule, '@'); if(at == NULL) { /* This looks like a mask rule or an invalid rule */ @@ -5849,7 +5904,7 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str, while((elem = strsep(&rule, ",")) != NULL) { char *attr = elem, *value = NULL; ndpi_port_range range; - int is_tcp = 0, is_udp = 0, is_ip = 0, is_ja4 = 0, is_ndpifp = 0, is_httpurl = 0, is_tls_cert_hash = 0;; + int is_tcp = 0, is_udp = 0, is_ip = 0, is_ja4 = 0, is_ndpifp = 0, is_httpurl = 0; u_int8_t is_ipv6_ip = 0; if(strncmp(attr, "tcp:", 4) == 0) @@ -5912,17 +5967,7 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str, is_ndpifp = 1, value = &attr[7]; } else if(strncmp(attr, "url:", 4) == 0) { is_httpurl = 1, value = &attr[4]; - } else if(strncmp(attr, "tls_cert_hash:", 14) == 0) { - is_tls_cert_hash = 1, value = &attr[14]; - if (value[0] == '"') { - value++; - if (value[0] != '\0') { - size_t len=strlen(value); - if(len > 0 && value[len-1] == '"') - value[len-1] = '\0'; /* remove trailing " */ - } } - } if(is_tcp || is_udp) { u_int p_low, p_high; @@ -5973,12 +6018,7 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str, if(rc != 0) return(rc); - } else if(is_tls_cert_hash) { - int rc = ndpi_add_tls_cert_hash_subprotocol(ndpi_str, value, subprotocol_id); - - if(rc != 0) - return(rc); - } else { + }else { int rc = ndpi_add_host_url_subprotocol(ndpi_str, value, subprotocol_id, category, breed, 0); if(rc != 0) diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c index 310708f2725..315b3bd3f65 100644 --- a/src/lib/protocols/tls.c +++ b/src/lib/protocols/tls.c @@ -675,6 +675,8 @@ static void checkTLSSubprotocol(struct ndpi_detection_module_struct *ndpi_struct void processCertificateElements(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, u_int16_t p_offset, u_int16_t certificate_len) { + printf("[DEBUG] processCertificateElements called! cert_len=%u\n", certificate_len); + fflush(stdout); struct ndpi_packet_struct *packet = &ndpi_struct->packet; u_int16_t num_found = 0; int32_t i; @@ -1220,6 +1222,7 @@ int processCertificate(struct ndpi_detection_module_struct *ndpi_struct, printf("\n"); } #endif +printf("[DEBUG] tls_sha1_fingerprint_enabled=%d\n", ndpi_struct->cfg.tls_sha1_fingerprint_enabled); /* For SHA-1 we take into account only the first certificate and not all of them */ if(ndpi_struct->cfg.tls_sha1_fingerprint_enabled) { @@ -1257,9 +1260,12 @@ int processCertificate(struct ndpi_detection_module_struct *ndpi_struct, if(rc1 == 0) ndpi_set_risk(ndpi_struct, flow, NDPI_MALICIOUS_SHA1_CERTIFICATE, sha1_str); } + printf("[DEBUG_CONDITIONS] detected_protocol_stack[1]=%u (should be 0), list_exists=%d\n", + flow->detected_protocol_stack[1], ndpi_struct->dynamic_tls_cert_hash_list != NULL); if(flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN && ndpi_struct->dynamic_tls_cert_hash_list != NULL) { + printf("[DEBUG] ✅ Both conditions met! Checking TLS cert hashes\n"); ndpi_tls_cert_hash_match_dynamic *rule = ndpi_struct->dynamic_tls_cert_hash_list; @@ -1275,6 +1281,8 @@ int processCertificate(struct ndpi_detection_module_struct *ndpi_struct, if(strcasecmp(sha1_str, rule_hash_no_colon) == 0) { + printf("[DEBUG] ✅ HASH MATCH! sha1_str=%s\n", sha1_str); + /* Hash match found */ ndpi_master_app_protocol proto; @@ -1288,11 +1296,18 @@ int processCertificate(struct ndpi_detection_module_struct *ndpi_struct, ndpi_check_subprotocol_risk(ndpi_struct, flow, rule->protocol_id); ndpi_unset_risk(ndpi_struct, flow, NDPI_NUMERIC_IP_HOST); break; + }else { + printf("[DEBUG] ❌ No match. sha1_str=%s vs rule=%s\n", sha1_str, rule_hash_no_colon); } rule = rule->next; } } + else { + printf("[DEBUG] ❌ Conditions NOT met: stack[1]=%u (need 0), list=%d (need 1)\n", + flow->detected_protocol_stack[1], + ndpi_struct->dynamic_tls_cert_hash_list != NULL); } + } processCertificateElements(ndpi_struct, flow, certificates_offset, certificate_len); } diff --git a/tls_test_cert/test_protos.txt b/tls_test_cert/test_protos.txt index 166a5d13623..d70f716459b 100644 --- a/tls_test_cert/test_protos.txt +++ b/tls_test_cert/test_protos.txt @@ -1,5 +1,2 @@ -# Match by Common Name -nDPI_TestApp@tls_cert:"CN=nDPI_TestCert" - -# Match by Organization -nDPI_TestOrg@tls_cert:"O=nDPI_Test_Org" +# Match by TLS certificate hash +tls_cert_hash:0a:a0:ed:1a:71:50:5d:37:c4:4f:8f:d0:9a:0f:3e:a0:17:6e:e9:58@nDPI_TestApp