aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuca Deri <deri@ntop.org>2019-08-22 19:25:58 +0200
committerLuca Deri <deri@ntop.org>2019-08-22 19:25:58 +0200
commite7c0ac37d87958c80115e7553ea39b26668ce360 (patch)
treea3d6adb3b5379fc9ac67916cda6dbd8f5a09ae29 /src
parent385e848a0f61b9e517f096b010070a6dd61d1f62 (diff)
Implemented HASSH (https://github.com/salesforce/hassh)
Diffstat (limited to 'src')
-rw-r--r--src/include/ndpi_typedefs.h1
-rw-r--r--src/lib/protocols/ssh.c240
-rw-r--r--src/lib/protocols/tls.c216
-rw-r--r--src/lib/third_party/include/ndpi_md5.h18
-rw-r--r--src/lib/third_party/src/ndpi_md5.c204
5 files changed, 458 insertions, 221 deletions
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index 089547570..c206da93c 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -1171,6 +1171,7 @@ struct ndpi_flow_struct {
struct {
char client_signature[48], server_signature[48];
+ char hassh_client[33], hassh_server[33];
} ssh;
struct {
diff --git a/src/lib/protocols/ssh.c b/src/lib/protocols/ssh.c
index 1a20078c3..7e5ca5e62 100644
--- a/src/lib/protocols/ssh.c
+++ b/src/lib/protocols/ssh.c
@@ -2,7 +2,7 @@
* ssh.c
*
* Copyright (C) 2009-2011 by ipoque GmbH
- * Copyright (C) 2011-18 - ntop.org
+ * Copyright (C) 2011-19 - ntop.org
*
* This file is part of nDPI, an open source deep packet inspection
* library based on the OpenDPI and PACE technology by ipoque GmbH
@@ -19,7 +19,7 @@
*
* You should have received a copy of the GNU Lesser General Public License
* along with nDPI. If not, see <http://www.gnu.org/licenses/>.
- *
+ *
*/
#include "ndpi_protocol_ids.h"
@@ -27,12 +27,134 @@
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_SSH
#include "ndpi_api.h"
+#include "ndpi_md5.h"
+
+/*
+ HASSH - https://github.com/salesforce/hassh
+
+ https://github.com/salesforce/hassh/blob/master/python/hassh.py
+
+ [server]
+ skex = packet.ssh.kex_algorithms
+ seastc = packet.ssh.encryption_algorithms_server_to_client
+ smastc = packet.ssh.mac_algorithms_server_to_client
+ scastc = packet.ssh.compression_algorithms_server_to_client
+ hasshs_str = ';'.join([skex, seastc, smastc, scastc])
+
+ [client]
+ ckex = packet.ssh.kex_algorithms
+ ceacts = packet.ssh.encryption_algorithms_client_to_server
+ cmacts = packet.ssh.mac_algorithms_client_to_server
+ ccacts = packet.ssh.compression_algorithms_client_to_server
+ hassh_str = ';'.join([ckex, ceacts, cmacts, ccacts])
+*/
+
+/* #define SSH_DEBUG 1 */
+
+/* ************************************************************************ */
static void ndpi_int_ssh_add_connection(struct ndpi_detection_module_struct
- *ndpi_struct, struct ndpi_flow_struct *flow){
+ *ndpi_struct, struct ndpi_flow_struct *flow) {
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SSH, NDPI_PROTOCOL_UNKNOWN);
}
+/* ************************************************************************ */
+
+static u_int16_t concat_hash_string(struct ndpi_packet_struct *packet,
+ char *buf, u_int8_t client_hash) {
+ u_int16_t offset = 22, buf_out_len = 0;
+ u_int32_t len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+
+ if(len < (packet->payload_packet_len-offset)) {
+ /* ssh.kex_algorithms [C/S] */
+ offset += 4;
+ strncpy(buf, (const char *)&packet->payload[offset], buf_out_len = len);
+ buf[buf_out_len++] = ';';
+ offset += len;
+
+ /* ssh.server_host_key_algorithms [None] */
+ len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+ offset += 4 + len;
+
+ /* ssh.encryption_algorithms_client_to_server [C] */
+ len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+
+ if(client_hash) {
+ offset += 4;
+ strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len);
+ buf_out_len += len;
+ buf[buf_out_len++] = ';';
+ offset += len;
+ } else
+ offset += 4 + len;
+
+ /* ssh.encryption_algorithms_server_to_client [S] */
+ len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+ if(!client_hash) {
+ offset += 4;
+ strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len);
+ buf_out_len += len;
+ buf[buf_out_len++] = ';';
+ offset += len;
+ } else
+ offset += 4 + len;
+
+ /* ssh.mac_algorithms_client_to_server [C] */
+ len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+ if(client_hash) {
+ offset += 4;
+ strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len);
+ buf_out_len += len;
+ buf[buf_out_len++] = ';';
+ offset += len;
+ } else
+ offset += 4 + len;
+
+ /* ssh.mac_algorithms_server_to_client [S] */
+ len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+ if(!client_hash) {
+ offset += 4;
+ strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len);
+ buf_out_len += len;
+ buf[buf_out_len++] = ';';
+ offset += len;
+ } else
+ offset += 4 + len;
+
+ /* ssh.compression_algorithms_client_to_server [C] */
+ len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+ if(client_hash) {
+ offset += 4;
+ strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len);
+ buf_out_len += len;
+ offset += len;
+ } else
+ offset += 4 + len;
+
+ /* ssh.compression_algorithms_server_to_client [S] */
+ len = ntohl(*(u_int32_t*)&packet->payload[offset]);
+ if(!client_hash) {
+ offset += 4;
+ strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len);
+ buf_out_len += len;
+ offset += len;
+ } else
+ offset += 4 + len;
+
+ /* ssh.languages_client_to_server [None] */
+
+ /* ssh.languages_server_to_client [None] */
+ }
+
+#ifdef SSH_DEBUG
+ printf("\n[SSH] %s\n", buf);
+#endif
+
+ return(buf_out_len);
+}
+
+/* ************************************************************************ */
+
static void ndpi_ssh_zap_cr(char *str, int len) {
len--;
@@ -45,46 +167,132 @@ static void ndpi_ssh_zap_cr(char *str, int len) {
}
}
-void ndpi_search_ssh_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
-{
- struct ndpi_packet_struct *packet = &flow->packet;
+/* ************************************************************************ */
+
+void ndpi_search_ssh_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) {
+ struct ndpi_packet_struct *packet = &flow->packet;
+
+#ifdef SSH_DEBUG
+ printf("\n[SSH] [stage: %u]\n", flow->l4.tcp.ssh_stage);
+#endif
- if (flow->l4.tcp.ssh_stage == 0) {
- if (packet->payload_packet_len > 7 && packet->payload_packet_len < 100
+ if(flow->l4.tcp.ssh_stage == 0) {
+ if(packet->payload_packet_len > 7 && packet->payload_packet_len < 100
&& memcmp(packet->payload, "SSH-", 4) == 0) {
if(!ndpi_struct->disable_metadata_export) {
- int len = ndpi_min(sizeof(flow->protos.ssh.client_signature)-1, packet->payload_packet_len);
+ int len = ndpi_min(sizeof(flow->protos.ssh.client_signature)-1, packet->payload_packet_len);
+
strncpy(flow->protos.ssh.client_signature, (const char *)packet->payload, len);
flow->protos.ssh.client_signature[len] = '\0';
ndpi_ssh_zap_cr(flow->protos.ssh.client_signature, len);
+
+#ifdef SSH_DEBUG
+ printf("\n[SSH] [client_signature: %s]\n", flow->protos.ssh.client_signature);
+#endif
}
-
+
NDPI_LOG_DBG2(ndpi_struct, "ssh stage 0 passed\n");
flow->l4.tcp.ssh_stage = 1 + packet->packet_direction;
+ flow->guessed_host_protocol_id = flow->guessed_protocol_id = NDPI_PROTOCOL_SSH;
return;
}
- } else if (flow->l4.tcp.ssh_stage == (2 - packet->packet_direction)) {
- if (packet->payload_packet_len > 7 && packet->payload_packet_len < 500
+ } else if(flow->l4.tcp.ssh_stage == (2 - packet->packet_direction)) {
+ if(packet->payload_packet_len > 7 && packet->payload_packet_len < 500
&& memcmp(packet->payload, "SSH-", 4) == 0) {
if(!ndpi_struct->disable_metadata_export) {
int len = ndpi_min(sizeof(flow->protos.ssh.server_signature)-1, packet->payload_packet_len);
+
strncpy(flow->protos.ssh.server_signature, (const char *)packet->payload, len);
flow->protos.ssh.server_signature[len] = '\0';
ndpi_ssh_zap_cr(flow->protos.ssh.server_signature, len);
+
+#ifdef SSH_DEBUG
+ printf("\n[SSH] [server_signature: %s]\n", flow->protos.ssh.server_signature);
+#endif
+
+ NDPI_LOG_DBG2(ndpi_struct, "ssh stage 1 passed\n");
+ flow->l4.tcp.ssh_stage++;;
+ flow->guessed_host_protocol_id = flow->guessed_protocol_id = NDPI_PROTOCOL_SSH;
+ } else {
+ NDPI_LOG_INFO(ndpi_struct, "found ssh\n");
+ ndpi_int_ssh_add_connection(ndpi_struct, flow);
}
-
- NDPI_LOG_INFO(ndpi_struct, "found ssh\n");
-
- ndpi_int_ssh_add_connection(ndpi_struct, flow);
+
+#ifdef SSH_DEBUG
+ printf("\n[SSH] [completed stage: %u]\n", flow->l4.tcp.ssh_stage);
+#endif
+
return;
+ }
+ } else {
+ u_int8_t msgcode = *(packet->payload + 5);
+ ndpi_MD5_CTX ctx;
+
+#ifdef SSH_DEBUG
+ printf("\n[SSH] [stage: %u][msg: %u]\n", flow->l4.tcp.ssh_stage, msgcode);
+#endif
+ if(msgcode == 20 /* key exchange init */) {
+ char *hassh_buf = calloc(packet->payload_packet_len, sizeof(char));
+ u_int i, len;
+
+ if(hassh_buf) {
+ if(flow->l4.tcp.ssh_stage == 3) {
+ u_char fingerprint_client[16];
+
+ len = concat_hash_string(packet, hassh_buf, 1 /* client */);
+
+ ndpi_MD5Init(&ctx);
+ ndpi_MD5Update(&ctx, (const unsigned char *)hassh_buf, len);
+ ndpi_MD5Final(fingerprint_client, &ctx);
+
+#ifdef SSH_DEBUG
+ {
+ printf("\n[SSH] [client][%s][", hassh_buf);
+ for(i=0; i<16; i++) printf("%02X", fingerprint_client[i]);
+ printf("]\n");
+ }
+#endif
+ for(i=0; i<16; i++) sprintf(&flow->protos.ssh.hassh_client[i*2], "%02X", fingerprint_client[i] & 0xFF);
+ flow->protos.ssh.hassh_client[32] = '\0';
+ } else {
+ u_char fingerprint_server[16];
+
+ len = concat_hash_string(packet, hassh_buf, 0 /* server */);
+
+ ndpi_MD5Init(&ctx);
+ ndpi_MD5Update(&ctx, (const unsigned char *)hassh_buf, len);
+ ndpi_MD5Final(fingerprint_server, &ctx);
+
+#ifdef SSH_DEBUG
+ {
+ printf("\n[SSH] [server][%s][", hassh_buf);
+ for(i=0; i<16; i++) printf("%02X", fingerprint_server[i]);
+ printf("]\n");
+ }
+#endif
+
+ for(i=0; i<16; i++) sprintf(&flow->protos.ssh.hassh_server[i*2], "%02X", fingerprint_server[i] & 0xFF);
+ flow->protos.ssh.hassh_server[32] = '\0';
+ }
+
+ free(hassh_buf);
+ }
}
+
+ if(flow->l4.tcp.ssh_stage++ == 4) {
+ NDPI_LOG_INFO(ndpi_struct, "found ssh\n");
+ ndpi_int_ssh_add_connection(ndpi_struct, flow);
+ }
+
+ return;
}
NDPI_LOG_DBG(ndpi_struct, "excluding ssh at stage %d\n", flow->l4.tcp.ssh_stage);
NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_SSH);
}
+/* ************************************************************************ */
void init_ssh_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask)
{
diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c
index d2aa5f1a9..d9b7b0962 100644
--- a/src/lib/protocols/tls.c
+++ b/src/lib/protocols/tls.c
@@ -26,6 +26,7 @@
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_TLS
#include "ndpi_api.h"
+#include "ndpi_md5.h"
// #define DEBUG_TLS 1
@@ -37,202 +38,6 @@ extern u_int8_t is_skype_flow(struct ndpi_detection_module_struct *ndpi_struct,
/* **************************************** */
-typedef struct MD5Context {
- uint32_t buf[4];
- uint32_t bits[2];
- unsigned char in[64];
-} MD5_CTX;
-
-/* **************************************** */
-
-static int is_big_endian(void) {
- static const int n = 1;
- return ((char *) &n)[0] == 0;
-}
-
-static void byteReverse(unsigned char *buf, unsigned longs) {
- // Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN
- if (is_big_endian()) {
- do {
- uint32_t t;
-
- t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
- ((unsigned) buf[1] << 8 | buf[0]);
- * (uint32_t *) buf = t;
- buf += 4;
- } while (--longs);
- }
-}
-
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-#define MD5STEP(f, w, x, y, z, data, s) \
- ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
-
-// Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
-// initialization constants.
-static void MD5Init(MD5_CTX *ctx) {
- ctx->buf[0] = 0x67452301;
- ctx->buf[1] = 0xefcdab89;
- ctx->buf[2] = 0x98badcfe;
- ctx->buf[3] = 0x10325476;
-
- ctx->bits[0] = 0;
- ctx->bits[1] = 0;
-}
-
-static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
- uint32_t a, b, c, d;
-
- a = buf[0];
- b = buf[1];
- c = buf[2];
- d = buf[3];
-
- MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
- MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
- MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
- MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
- MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
- MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
- MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
- MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
- MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
- MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
- MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
- MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
- MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
- MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
- MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
- MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
- MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
- MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
- MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
- MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
- MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
- MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
- MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
- MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
- MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
- MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
- MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
- MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
- MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
- MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
- MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
- MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
- MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
- MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
- MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
- MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
- MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
- MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
- MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
- MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
- MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
- MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
- MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
- MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
- MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
- MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
- MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
- MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-
- MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
- MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
- MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
- MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
- MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
- MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
- MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
- MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
- MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
- MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
- MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
- MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
- MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
- MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
- MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
- MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
- buf[0] += a;
- buf[1] += b;
- buf[2] += c;
- buf[3] += d;
-}
-
-static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
- uint32_t t;
-
- t = ctx->bits[0];
- if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
- ctx->bits[1]++;
- ctx->bits[1] += len >> 29;
-
- t = (t >> 3) & 0x3f;
-
- if (t) {
- unsigned char *p = (unsigned char *) ctx->in + t;
-
- t = 64 - t;
- if (len < t) {
- memcpy(p, buf, len);
- return;
- }
- memcpy(p, buf, t);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
- buf += t;
- len -= t;
- }
-
- while (len >= 64) {
- memcpy(ctx->in, buf, 64);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
- buf += 64;
- len -= 64;
- }
-
- memcpy(ctx->in, buf, len);
-}
-
-static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) {
- unsigned count;
- unsigned char *p;
- uint32_t *c = (uint32_t*)ctx->in;
-
- count = (ctx->bits[0] >> 3) & 0x3F;
-
- p = ctx->in + count;
- *p++ = 0x80;
- count = 64 - 1 - count;
- if (count < 8) {
- memset(p, 0, count);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
- memset(ctx->in, 0, 56);
- } else {
- memset(p, 0, count - 8);
- }
- byteReverse(ctx->in, 14);
-
- c[14] = ctx->bits[0];
- c[15] = ctx->bits[1];
-
- MD5Transform(ctx->buf, (uint32_t *) ctx->in);
- byteReverse((unsigned char *) ctx->buf, 4);
- memcpy(digest, ctx->buf, 16);
- memset((char *) ctx, 0, sizeof(*ctx));
-}
-
-/* **************************************** */
-
static u_int32_t ndpi_tls_refine_master_protocol(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow, u_int32_t protocol) {
struct ndpi_packet_struct *packet = &flow->packet;
@@ -375,7 +180,7 @@ int getTLScertificate(struct ndpi_detection_module_struct *ndpi_struct,
u_int8_t invalid_ja3 = 0;
u_int16_t pkt_tls_version = (packet->payload[1] << 8) + packet->payload[2], ja3_str_len;
char ja3_str[JA3_STR_LEN];
- MD5_CTX ctx;
+ ndpi_MD5_CTX ctx;
u_char md5_hash[16];
if(packet->udp) {
@@ -521,9 +326,9 @@ int getTLScertificate(struct ndpi_detection_module_struct *ndpi_struct,
printf("[JA3] Server: %s \n", ja3_str);
#endif
- MD5Init(&ctx);
- MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str));
- MD5Final(md5_hash, &ctx);
+ ndpi_MD5Init(&ctx);
+ ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str));
+ ndpi_MD5Final(md5_hash, &ctx);
for(i=0, j=0; i<16; i++)
j += snprintf(&flow->protos.stun_ssl.ssl.ja3_server[j],
@@ -834,14 +639,15 @@ int getTLScertificate(struct ndpi_detection_module_struct *ndpi_struct,
#ifdef DEBUG_TLS
printf("[JA3] Client: %s \n", ja3_str);
#endif
-
- MD5Init(&ctx);
- MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str));
- MD5Final(md5_hash, &ctx);
+
+ ndpi_MD5Init(&ctx);
+ ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str));
+ ndpi_MD5Final(md5_hash, &ctx);
for(i=0, j=0; i<16; i++)
j += snprintf(&flow->protos.stun_ssl.ssl.ja3_client[j],
- sizeof(flow->protos.stun_ssl.ssl.ja3_client)-j, "%02x", md5_hash[i]);
+ sizeof(flow->protos.stun_ssl.ssl.ja3_client)-j, "%02x",
+ md5_hash[i]);
#ifdef DEBUG_TLS
printf("[JA3] Client: %s \n", flow->protos.stun_ssl.ssl.ja3_client);
diff --git a/src/lib/third_party/include/ndpi_md5.h b/src/lib/third_party/include/ndpi_md5.h
new file mode 100644
index 000000000..f7dd9b946
--- /dev/null
+++ b/src/lib/third_party/include/ndpi_md5.h
@@ -0,0 +1,18 @@
+/*
+ Contributed code pasted here to make nDPI self-contained with no
+ external dependencies
+*/
+
+/* **************************************** */
+
+typedef struct ndpi_MD5Context {
+ uint32_t buf[4];
+ uint32_t bits[2];
+ unsigned char in[64];
+} ndpi_MD5_CTX;
+
+/* **************************************** */
+
+extern void ndpi_MD5Init(ndpi_MD5_CTX *ctx);
+extern void ndpi_MD5Update(ndpi_MD5_CTX *ctx, unsigned char const *buf, unsigned len);
+extern void ndpi_MD5Final(unsigned char digest[16], ndpi_MD5_CTX *ctx);
diff --git a/src/lib/third_party/src/ndpi_md5.c b/src/lib/third_party/src/ndpi_md5.c
new file mode 100644
index 000000000..fefe9d65f
--- /dev/null
+++ b/src/lib/third_party/src/ndpi_md5.c
@@ -0,0 +1,204 @@
+/*
+ Contributed code pasted here to make nDPI self-contained with no
+ external dependencies
+*/
+
+#include "ndpi_api.h"
+#include "ndpi_md5.h"
+
+/* **************************************** */
+
+static int is_big_endian(void) {
+ static const int n = 1;
+ return ((char *) &n)[0] == 0;
+}
+
+static void byte_reverse(unsigned char *buf, unsigned longs) {
+ // Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN
+ if (is_big_endian()) {
+ do {
+ u_int32_t t;
+
+ t = (u_int32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ * (u_int32_t *) buf = t;
+ buf += 4;
+ } while (--longs);
+ }
+}
+
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/* **************************************** */
+
+// Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+// initialization constants.
+void ndpi_MD5Init(ndpi_MD5_CTX *ctx) {
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/* **************************************** */
+
+static void MD5Transform(u_int32_t buf[4], u_int32_t const in[16]) {
+ u_int32_t a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/* **************************************** */
+
+void ndpi_MD5Update(ndpi_MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
+ u_int32_t t;
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((u_int32_t) len << 3)) < t)
+ ctx->bits[1]++;
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f;
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byte_reverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (u_int32_t *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byte_reverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (u_int32_t *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ memcpy(ctx->in, buf, len);
+}
+
+/* **************************************** */
+
+void ndpi_MD5Final(unsigned char digest[16], ndpi_MD5_CTX *ctx) {
+ unsigned count;
+ unsigned char *p;
+ u_int32_t *c = (u_int32_t*)ctx->in;
+
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ p = ctx->in + count;
+ *p++ = 0x80;
+ count = 64 - 1 - count;
+ if (count < 8) {
+ memset(p, 0, count);
+ byte_reverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (u_int32_t *) ctx->in);
+ memset(ctx->in, 0, 56);
+ } else {
+ memset(p, 0, count - 8);
+ }
+ byte_reverse(ctx->in, 14);
+
+ c[14] = ctx->bits[0];
+ c[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (u_int32_t *) ctx->in);
+ byte_reverse((unsigned char *) ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset((char *) ctx, 0, sizeof(*ctx));
+}
+