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/lib | |
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/lib')
-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 |
4 files changed, 43 insertions, 25 deletions
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"); } |