aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Nardi <12729895+IvanNardi@users.noreply.github.com>2022-10-25 17:06:29 +0200
committerGitHub <noreply@github.com>2022-10-25 17:06:29 +0200
commitca5ffc498873805c07a29c6d8af3e995963c055d (patch)
treeefbc859babc7668069c9576b54439ffe10cc9859 /src
parent2ed2e5dc7e072d41065a7c04da5db598150c71fa (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.h10
-rw-r--r--src/lib/ndpi_main.c7
-rw-r--r--src/lib/ndpi_utils.c12
-rw-r--r--src/lib/protocols/quic.c6
-rw-r--r--src/lib/protocols/tls.c43
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");
}