aboutsummaryrefslogtreecommitdiff
path: root/src/lib/protocols
diff options
context:
space:
mode:
authorIvan Nardi <12729895+IvanNardi@users.noreply.github.com>2021-03-02 21:15:40 +0100
committerGitHub <noreply@github.com>2021-03-02 21:15:40 +0100
commit4c00ff89dfa64f1026c2f1d267dc081a86b45243 (patch)
tree42a219182bf7d40a7ab17fb9c856d4ab22432657 /src/lib/protocols
parent2b71a329c18026cb56d938db6f14014aaf682abd (diff)
DTLS: improve support (#1146)
* DTLS: add some pcap tests * DTLS: fix parsing of Client/Server Helllo message * DTLS: add parsing of server certificates
Diffstat (limited to 'src/lib/protocols')
-rw-r--r--src/lib/protocols/tls.c139
1 files changed, 101 insertions, 38 deletions
diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c
index 5e3ae65b1..f9d96f55c 100644
--- a/src/lib/protocols/tls.c
+++ b/src/lib/protocols/tls.c
@@ -546,8 +546,9 @@ static void processCertificateElements(struct ndpi_detection_module_struct *ndpi
int processCertificate(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &flow->packet;
+ int is_dtls = packet->udp ? 1 : 0;
u_int32_t certificates_length, length = (packet->payload[1] << 16) + (packet->payload[2] << 8) + packet->payload[3];
- u_int16_t certificates_offset = 7;
+ u_int32_t certificates_offset = 7 + (is_dtls ? 8 : 0);
u_int8_t num_certificates_found = 0;
SHA1_CTX srv_cert_fingerprint_ctx ;
@@ -559,14 +560,16 @@ int processCertificate(struct ndpi_detection_module_struct *ndpi_struct,
packet->payload[3], packet->payload[4], packet->payload[5]);
#endif
- if((packet->payload_packet_len != (length + 4)) || (packet->payload[1] != 0x0)) {
+ if((packet->payload_packet_len != (length + 4 + (is_dtls ? 8 : 0))) || (packet->payload[1] != 0x0)) {
NDPI_SET_BIT(flow->risk, NDPI_MALFORMED_PACKET);
return(-1); /* Invalid length */
}
- certificates_length = (packet->payload[4] << 16) + (packet->payload[5] << 8) + packet->payload[6];
+ certificates_length = (packet->payload[certificates_offset - 3] << 16) +
+ (packet->payload[certificates_offset - 2] << 8) +
+ packet->payload[certificates_offset - 1];
- if((packet->payload[4] != 0x0) || ((certificates_length+3) != length)) {
+ if((packet->payload[certificates_offset - 3] != 0x0) || ((certificates_length+3) != length)) {
NDPI_SET_BIT(flow->risk, NDPI_MALFORMED_PACKET);
return(-2); /* Invalid length */
}
@@ -578,7 +581,7 @@ int processCertificate(struct ndpi_detection_module_struct *ndpi_struct,
/* Invalid lenght */
if((certificate_len == 0)
|| (packet->payload[certificates_offset] != 0x0)
- || ((certificates_offset+certificate_len) > (4+certificates_length))) {
+ || ((certificates_offset+certificate_len) > (4+certificates_length+(is_dtls ? 8 : 0)))) {
#ifdef DEBUG_TLS
printf("[TLS] Invalid length [certificate_len: %u][certificates_offset: %u][%u vs %u]\n",
certificate_len, certificates_offset,
@@ -667,6 +670,7 @@ int processCertificate(struct ndpi_detection_module_struct *ndpi_struct,
static int processTLSBlock(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &flow->packet;
+ int ret;
switch(packet->payload[0] /* block type */) {
case 0x01: /* Client Hello */
@@ -691,7 +695,12 @@ static int processTLSBlock(struct ndpi_detection_module_struct *ndpi_struct,
/* Important: populate the tls union fields only after
* ndpi_int_tls_add_connection has been called */
if(flow->l4.tcp.tls.hello_processed) {
- processCertificate(ndpi_struct, flow);
+ ret = processCertificate(ndpi_struct, flow);
+ if (ret != 1) {
+#ifdef DEBUG_TLS
+ printf("[TLS] Error processing certificate: %d\n", ret);
+#endif
+ }
flow->l4.tcp.tls.certificate_processed = 1;
}
break;
@@ -861,50 +870,97 @@ static int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct,
static int ndpi_search_tls_udp(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &flow->packet;
- // u_int8_t handshake_type;
u_int32_t handshake_len;
- u_int16_t p_len;
+ u_int16_t p_len, processed;
const u_int8_t *p;
+ u_int8_t no_dtls = 0, change_cipher_found = 0;
#ifdef DEBUG_TLS
printf("[TLS] %s()\n", __FUNCTION__);
#endif
- /* Consider only specific SSL packets (handshake) */
- if((packet->payload_packet_len < 17)
- || (packet->payload[0] != 0x16)
- || (packet->payload[1] != 0xfe) /* We ignore old DTLS versions */
- || ((packet->payload[2] != 0xff) && (packet->payload[2] != 0xfd))
- || ((ntohs(*((u_int16_t*)&packet->payload[11]))+13) != packet->payload_packet_len)
- ) {
- no_dtls:
+ /* Overwriting packet payload */
+ p = packet->payload, p_len = packet->payload_packet_len; /* Backup */
+
+ /* Split the element in blocks */
+ processed = 0;
+ while(processed + 13 < p_len) {
+ u_int32_t block_len;
+ const u_int8_t *block = (const u_int8_t *)&p[processed];
+ if((block[0] != 0x16 && block[0] != 0x14) || /* Handshake, change-cipher-spec */
+ (block[1] != 0xfe) || /* We ignore old DTLS versions */
+ ((block[2] != 0xff) && (block[2] != 0xfd))) {
+#ifdef DEBUG_TLS
+ printf("[TLS] DTLS invalid block 0x%x or old version 0x%x-0x%x-0x%x\n",
+ block[0], block[1], block[2], block[3]);
+#endif
+ no_dtls = 1;
+ break;
+ }
+ block_len = ntohs(*((u_int16_t*)&block[11]));
+#ifdef DEBUG_TLS
+ printf("[TLS] DTLS block len: %d\n", block_len);
+#endif
+ if (block_len == 0 || (processed + block_len + 12 >= p_len)) {
+#ifdef DEBUG_TLS
+ printf("[TLS] DTLS invalid block len %d (processed %d, p_len %d)\n",
+ block_len, processed, p_len);
+#endif
+ no_dtls = 1;
+ break;
+ }
+ /* We process only handshake msgs */
+ if(block[0] == 0x16) {
+ if (processed + block_len + 13 > p_len) {
+#ifdef DEBUG_TLS
+ printf("[TLS] DTLS invalid len %d %d %d\n", processed, block_len, p_len);
+#endif
+ no_dtls = 1;
+ break;
+ }
+ /* TODO: handle (certificate) fragments */
+ handshake_len = (block[14] << 16) + (block[15] << 8) + block[16];
+ if((handshake_len + 12) != block_len) {
+#ifdef DEBUG_TLS
+ printf("[TLS] DTLS invalid handshake_len %d, %d)\n",
+ handshake_len, block_len);
+#endif
+ no_dtls = 1;
+ break;
+ }
+ packet->payload = &block[13];
+ packet->payload_packet_len = block_len;
+ processTLSBlock(ndpi_struct, flow);
+ } else {
+ /* Change-cipher-spec: any subsequent block might be encrypted */
#ifdef DEBUG_TLS
- printf("[TLS] No DTLS found\n");
+ printf("[TLS] Change-cipher-spec\n");
#endif
+ change_cipher_found = 1;
+ processed += block_len + 13;
+ break;
+ }
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
- return(0); /* Giveup */
+ processed += block_len + 13;
+ }
+ if(processed != p_len) {
+#ifdef DEBUG_TLS
+ printf("[TLS] DTLS invalid processed len %d/%d (%d)\n", processed, p_len, change_cipher_found);
+#endif
+ if(!change_cipher_found)
+ no_dtls = 1;
}
-
- // handshake_type = packet->payload[13];
- handshake_len = (packet->payload[14] << 16) + (packet->payload[15] << 8) + packet->payload[16];
-
- if((handshake_len+25) != packet->payload_packet_len)
- goto no_dtls;
-
- /* Overwriting packet payload */
- p = packet->payload, p_len = packet->payload_packet_len; /* Backup */
- packet->payload = &packet->payload[13], packet->payload_packet_len -= 13;
-
- processTLSBlock(ndpi_struct, flow);
packet->payload = p;
packet->payload_packet_len = p_len; /* Restore */
- ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_DTLS);
-
- return(1); /* Keep working */
+ if(no_dtls || change_cipher_found) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return(0); /* That's all */
+ } else {
+ return(1); /* Keep working */
+ }
}
/* **************************************** */
@@ -1023,7 +1079,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
https://networkengineering.stackexchange.com/questions/55752/why-does-wireshark-show-version-tls-1-2-here-instead-of-tls-1-3
*/
if(packet->udp)
- offset += 1;
+ offset += session_id_len + 1;
else {
if(tls_version < 0x7F15 /* TLS 1.3 lacks of session id */)
offset += session_id_len+1;
@@ -1127,6 +1183,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
#endif
} else if(handshake_type == 0x01 /* Client Hello */) {
u_int16_t cipher_len, cipher_offset;
+ u_int8_t cookie_len = 0;
if((session_id_len+base_offset+3) > packet->payload_packet_len)
return(0); /* Not found */
@@ -1135,8 +1192,14 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
cipher_len = packet->payload[session_id_len+base_offset+2] + (packet->payload[session_id_len+base_offset+1] << 8);
cipher_offset = base_offset + session_id_len + 3;
} else {
- cipher_len = ntohs(*((u_int16_t*)&packet->payload[base_offset+2]));
- cipher_offset = base_offset+4;
+ cookie_len = packet->payload[base_offset+session_id_len+1];
+#ifdef DEBUG_TLS
+ printf("[JA3] Client: DTLS cookie len %d\n", cookie_len);
+#endif
+ if((session_id_len+base_offset+cookie_len+4) > packet->payload_packet_len)
+ return(0); /* Not found */
+ cipher_len = ntohs(*((u_int16_t*)&packet->payload[base_offset+session_id_len+cookie_len+2]));
+ cipher_offset = base_offset + session_id_len + cookie_len + 4;
}
#ifdef DEBUG_TLS
@@ -1175,7 +1238,7 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
#endif
}
- offset = base_offset + session_id_len + cipher_len + 2;
+ offset = base_offset + session_id_len + cookie_len + cipher_len + 2;
if(offset < total_len) {
u_int16_t compression_len;