diff options
author | Ivan Nardi <12729895+IvanNardi@users.noreply.github.com> | 2022-10-25 17:06:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-25 17:06:29 +0200 |
commit | ca5ffc498873805c07a29c6d8af3e995963c055d (patch) | |
tree | efbc859babc7668069c9576b54439ffe10cc9859 /src | |
parent | 2ed2e5dc7e072d41065a7c04da5db598150c71fa (diff) |
TLS: improve handling of ALPN(s) (#1784)
Tell "Advertised" ALPN list from "Negotiated" ALPN; the former is
extracted from the CH, the latter from the SH.
Add some entries to the known ALPN list.
Fix printing of "TLS Supported Versions" field.
Diffstat (limited to 'src')
-rw-r--r-- | src/include/ndpi_typedefs.h | 10 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 7 | ||||
-rw-r--r-- | src/lib/ndpi_utils.c | 12 | ||||
-rw-r--r-- | src/lib/protocols/quic.c | 6 | ||||
-rw-r--r-- | src/lib/protocols/tls.c | 43 |
5 files changed, 48 insertions, 30 deletions
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 5b8a9c52b..33ccd93ec 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1404,7 +1404,7 @@ struct ndpi_flow_struct { } softether; struct { - char *server_names, *alpn, *tls_supported_versions, *issuerDN, *subjectDN; + char *server_names, *advertised_alpns, *negotiated_alpn, *tls_supported_versions, *issuerDN, *subjectDN; u_int32_t notBefore, notAfter; char ja3_client[33], ja3_server[33]; u_int16_t server_cipher; @@ -1578,11 +1578,11 @@ struct ndpi_flow_struct { #if !defined(NDPI_CFFI_PREPROCESSING) && defined(__linux__) #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L -_Static_assert(sizeof(((struct ndpi_flow_struct *)0)->protos) <= 200, - "Size of the struct member protocols increased to more than 200 bytes, " +_Static_assert(sizeof(((struct ndpi_flow_struct *)0)->protos) <= 208, + "Size of the struct member protocols increased to more than 208 bytes, " "please check if this change is necessary."); -_Static_assert(sizeof(struct ndpi_flow_struct) <= 920, - "Size of the flow struct increased to more than 920 bytes, " +_Static_assert(sizeof(struct ndpi_flow_struct) <= 928, + "Size of the flow struct increased to more than 928 bytes, " "please check if this change is necessary."); #endif #endif diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index 2c4116745..285f43d2a 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -5070,8 +5070,11 @@ void ndpi_free_flow_data(struct ndpi_flow_struct* flow) { if(flow->protos.tls_quic.server_names) ndpi_free(flow->protos.tls_quic.server_names); - if(flow->protos.tls_quic.alpn) - ndpi_free(flow->protos.tls_quic.alpn); + if(flow->protos.tls_quic.advertised_alpns) + ndpi_free(flow->protos.tls_quic.advertised_alpns); + + if(flow->protos.tls_quic.negotiated_alpn) + ndpi_free(flow->protos.tls_quic.negotiated_alpn); if(flow->protos.tls_quic.tls_supported_versions) ndpi_free(flow->protos.tls_quic.tls_supported_versions); diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c index 255a1fa8e..b7c687033 100644 --- a/src/lib/ndpi_utils.c +++ b/src/lib/ndpi_utils.c @@ -1202,9 +1202,13 @@ static void ndpi_tls2json(ndpi_serializer *serializer, struct ndpi_flow_struct * { ndpi_serialize_string_string(serializer, "subjectDN", flow->protos.tls_quic.subjectDN); } - if(flow->protos.tls_quic.alpn) + if(flow->protos.tls_quic.advertised_alpns) { - ndpi_serialize_string_string(serializer, "alpn", flow->protos.tls_quic.alpn); + ndpi_serialize_string_string(serializer, "advertised_alpns", flow->protos.tls_quic.advertised_alpns); + } + if(flow->protos.tls_quic.negotiated_alpn) + { + ndpi_serialize_string_string(serializer, "negotiated_alpn", flow->protos.tls_quic.negotiated_alpn); } if(flow->protos.tls_quic.tls_supported_versions) { @@ -2559,8 +2563,8 @@ void load_common_alpns(struct ndpi_detection_module_struct *ndpi_str) { /* QUIC ALPNs */ "h3-T051", "h3-T050", - "h3-32", "h3-30", "h3-29", "h3-28", "h3-27", "h3-24", "h3-22", - "hq-30", "hq-29", "hq-28", "hq-27", + "h3-34", "h3-33", "h3-32", "h3-31", "h3-30", "h3-29", "h3-28", "h3-27", "h3-24", "h3-22", + "hq-34", "hq-33", "hq-32", "hq-31", "hq-30", "hq-29", "hq-28", "hq-27", "hq-interop", "h3-fb-05", "h1q-fb", "doq-i00", diff --git a/src/lib/protocols/quic.c b/src/lib/protocols/quic.c index cbfaa9fd1..433bc0261 100644 --- a/src/lib/protocols/quic.c +++ b/src/lib/protocols/quic.c @@ -1335,9 +1335,9 @@ static void process_tls(struct ndpi_detection_module_struct *ndpi_struct, flow->protos.tls_quic.ssl_version = 0x0304; /* DNS-over-QUIC: ALPN is "doq" or "doq-XXX" (for drafts versions) */ - if(flow->protos.tls_quic.alpn && - strncmp(flow->protos.tls_quic.alpn, "doq", 3) == 0) { - NDPI_LOG_DBG(ndpi_struct, "Found DOQ (ALPN: [%s])\n", flow->protos.tls_quic.alpn); + if(flow->protos.tls_quic.advertised_alpns && + strncmp(flow->protos.tls_quic.advertised_alpns, "doq", 3) == 0) { + NDPI_LOG_DBG(ndpi_struct, "Found DOQ (ALPN: [%s])\n", flow->protos.tls_quic.advertised_alpns); ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_DOH_DOT, NDPI_PROTOCOL_QUIC, NDPI_CONFIDENCE_DPI); } } diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c index 869fe504b..fa40070f6 100644 --- a/src/lib/protocols/tls.c +++ b/src/lib/protocols/tls.c @@ -1261,11 +1261,11 @@ static void tls_subclassify_by_alpn(struct ndpi_detection_module_struct *ndpi_st struct ndpi_flow_struct *flow) { /* Right now we have only one rule so we can keep it trivial */ - if (!flow->protos.tls_quic.alpn) + if (!flow->protos.tls_quic.advertised_alpns) return; - if(strlen(flow->protos.tls_quic.alpn) > NDPI_STATICSTRING_LEN("anydesk/") && - strncmp(flow->protos.tls_quic.alpn, "anydesk/", NDPI_STATICSTRING_LEN("anydesk/")) == 0) { + if(strlen(flow->protos.tls_quic.advertised_alpns) > NDPI_STATICSTRING_LEN("anydesk/") && + strncmp(flow->protos.tls_quic.advertised_alpns, "anydesk/", NDPI_STATICSTRING_LEN("anydesk/")) == 0) { #ifdef DEBUG_TLS printf("Matching ANYDESK via alpn\n"); #endif @@ -1278,9 +1278,10 @@ static void tls_subclassify_by_alpn(struct ndpi_detection_module_struct *ndpi_st /* **************************************** */ static void tlsCheckUncommonALPN(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow) { - char * alpn_start = flow->protos.tls_quic.alpn; + struct ndpi_flow_struct *flow, + char *alpn_start) { char * comma_or_nul = alpn_start; + do { size_t alpn_len; @@ -1555,7 +1556,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t s_offset = offset+4; u_int16_t tot_alpn_len = ntohs(*((u_int16_t*)&packet->payload[s_offset])); char alpn_str[256]; - u_int8_t alpn_str_len = 0, i; + u_int16_t alpn_str_len = 0, i; #ifdef DEBUG_TLS printf("Server TLS [ALPN: block_len=%u/len=%u]\n", extension_len, tot_alpn_len); @@ -1605,13 +1606,18 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, if(ndpi_normalize_printable_string(alpn_str, alpn_str_len) == 0) ndpi_set_risk(ndpi_struct, flow, NDPI_INVALID_CHARACTERS, alpn_str); - if(flow->protos.tls_quic.alpn == NULL) - flow->protos.tls_quic.alpn = ndpi_strdup(alpn_str); + if(flow->protos.tls_quic.negotiated_alpn == NULL) + flow->protos.tls_quic.negotiated_alpn = ndpi_strdup(alpn_str); - if(flow->protos.tls_quic.alpn != NULL) - tlsCheckUncommonALPN(ndpi_struct, flow); + /* Check ALPN only if not already checked (client-side) */ + if(flow->protos.tls_quic.negotiated_alpn != NULL && + flow->protos.tls_quic.advertised_alpns == NULL) + tlsCheckUncommonALPN(ndpi_struct, flow, flow->protos.tls_quic.negotiated_alpn); - ndpi_snprintf(ja3.server.alpn, sizeof(ja3.server.alpn), "%s", alpn_str); + alpn_str_len = ndpi_min(sizeof(ja3.server.alpn), (size_t)alpn_str_len); + memcpy(ja3.server.alpn, alpn_str, alpn_str_len); + if(alpn_str_len > 0) + ja3.server.alpn[alpn_str_len - 1] = '\0'; /* Replace , with - as in JA3 */ for(i=0; ja3.server.alpn[i] != '\0'; i++) @@ -2164,7 +2170,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t s_offset = offset+extension_offset; u_int16_t tot_alpn_len = ntohs(*((u_int16_t*)&packet->payload[s_offset])); char alpn_str[256]; - u_int8_t alpn_str_len = 0, i; + u_int16_t alpn_str_len = 0, i; #ifdef DEBUG_TLS printf("Client TLS [ALPN: block_len=%u/len=%u]\n", extension_len, tot_alpn_len); @@ -2202,8 +2208,10 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, #ifdef DEBUG_TLS printf("Client TLS [ALPN: %s][len: %u]\n", alpn_str, alpn_str_len); #endif - if(flow->protos.tls_quic.alpn == NULL) { - flow->protos.tls_quic.alpn = ndpi_strdup(alpn_str); + if(flow->protos.tls_quic.advertised_alpns == NULL) { + flow->protos.tls_quic.advertised_alpns = ndpi_strdup(alpn_str); + + tlsCheckUncommonALPN(ndpi_struct, flow, flow->protos.tls_quic.advertised_alpns); /* Without SNI matching we can try to sub-classify the flow via ALPN. Note that this happens only on very rare cases, not the common ones @@ -2212,7 +2220,10 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, tls_subclassify_by_alpn(ndpi_struct, flow); } - ndpi_snprintf(ja3.client.alpn, sizeof(ja3.client.alpn), "%s", alpn_str); + alpn_str_len = ndpi_min(sizeof(ja3.client.alpn), (size_t)alpn_str_len); + memcpy(ja3.client.alpn, alpn_str, alpn_str_len); + if(alpn_str_len > 0) + ja3.client.alpn[alpn_str_len - 1] = '\0'; /* Replace , with - as in JA3 */ for(i=0; ja3.client.alpn[i] != '\0'; i++) @@ -2473,7 +2484,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, /* Before returning to the caller we need to make a final check */ if((flow->protos.tls_quic.ssl_version >= 0x0303) /* >= TLSv1.2 */ - && (flow->protos.tls_quic.alpn == NULL) /* No ALPN */) { + && (flow->protos.tls_quic.advertised_alpns == NULL) /* No ALPN */) { ndpi_set_risk(ndpi_struct, flow, NDPI_TLS_NOT_CARRYING_HTTPS, "No ALPN"); } |