Skip to content

Commit

Permalink
Drop support for non-gcrypt builds.
Browse files Browse the repository at this point in the history
 * As there is now a builtin, lightweight libgcrypt
   there is no need to disable tls-clho decryption.
 * It is still possible to use a host libgcrypt
   with `--with-local-libgcrypt'.

Signed-off-by: Toni Uhlig <[email protected]>
  • Loading branch information
utoni committed Mar 2, 2022
1 parent e8559a4 commit 5ae637a
Show file tree
Hide file tree
Showing 11 changed files with 48 additions and 83 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ A clear and concise description of what happening.
* OS version: [e.g. 18.04]
* Architecture: [e.g. arm64]
* nDPI version or commit hash: [e.g. 4.0-stable or 937357e4bc55610f116f66d15a8e0fc1e260c02c].
* nDPI compilation flags used: if you are building from source [e.g. --with-pcre --disable-gcrypt].
* nDPI compilation flags used: if you are building from source [e.g. --with-pcre --with-local-libgcrypt].
* Attach the `config.log` file generated after `./configure` ran (if you are building from source).

## How to reproduce the reported bug
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
sudo apt-get update
sudo apt-get install autoconf automake libtool pkg-config gettext libjson-c-dev flex bison libpcap-dev
sudo apt-get install rrdtool librrd-dev
sudo apt-get install libgcrypt20-dev libpcre3-dev libmaxminddb-dev lcov
sudo apt-get install libpcre3-dev libmaxminddb-dev lcov
- name: Configure
run: env CC=gcc CFLAGS='-Werror' ./autogen.sh --enable-debug-messages --enable-code-coverage --with-pcre --with-maxminddb
- name: Build
Expand Down Expand Up @@ -51,7 +51,7 @@ jobs:
matrix:
os: ["ubuntu-latest", "ubuntu-18.04", "macOS-latest", "macos-11"]
arch: ["x86_64"]
gcrypt: ["--disable-gcrypt", ""]
gcrypt: ["--with-local-libgcrypt", ""]
compiler: ["default-cc"]
pcre: [""]
maxminddb: [""]
Expand Down Expand Up @@ -151,7 +151,7 @@ jobs:
sudo apt-get install doxygen python3-sphinx python3-sphinx-rtd-theme python3-breathe python3-pip
sudo apt-get install rrdtool librrd-dev
- name: Install Ubuntu Prerequisites (libgcrypt)
if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.arch, 'x86_64') && !startsWith(matrix.gcrypt, '--disable-gcrypt')
if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.arch, 'x86_64') && startsWith(matrix.gcrypt, '--with-local-libgcrypt')
run: |
sudo apt-get install libgcrypt20-dev
- name: Install Ubuntu Prerequisites (libpcre)
Expand All @@ -177,7 +177,7 @@ jobs:
brew install coreutils
brew install rrdtool
- name: Install MacOS Prerequisites (libgcrypt)
if: startsWith(matrix.os, 'macOS') && startsWith(matrix.arch, 'x86_64') && !startsWith(matrix.gcrypt, '--disable-gcrypt')
if: startsWith(matrix.os, 'macOS') && startsWith(matrix.arch, 'x86_64') && startsWith(matrix.gcrypt, '--with-local-libgcrypt')
run: |
brew install libgcrypt
- name: Install MacOS Prerequisites (libpcre)
Expand Down Expand Up @@ -241,7 +241,7 @@ jobs:
- name: Configure nDPI [Mingw-w64] (runs only on ubuntu jobs)
if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.arch, 'x86_64')
run: |
make distclean && ./autogen.sh --host=x86_64-w64-mingw32 ${{ matrix.gcrypt }} ${{ matrix.pcre }} ${{ matrix.maxminddb }}
make distclean && ./autogen.sh --host=x86_64-w64-mingw32 ${{ matrix.pcre }} ${{ matrix.maxminddb }}
- name: Build nDPI [Mingw-w64] (runs only on ubuntu jobs)
if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.arch, 'x86_64')
run: |
Expand Down
29 changes: 11 additions & 18 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ AS_IF([test "${with_only_libndpi+set}" = set],[
AC_ARG_WITH(sanitizer, AS_HELP_STRING([--with-sanitizer], [Build with support for address, undefined and leak sanitizer]))
AC_ARG_ENABLE(fuzztargets, AS_HELP_STRING([--enable-fuzztargets], [Enable fuzz targets]),[enable_fuzztargets=$enableval],[enable_fuzztargets=no])
AC_ARG_ENABLE(code-coverage, AS_HELP_STRING([--enable-code-coverage], [Generate Code Coverage report]))
AC_ARG_WITH(libgcrypt, AS_HELP_STRING([--with-libgcrypt], [Build with libgcrypt (if present) instead of the enclosed gcrypt light]))
AC_ARG_WITH(local-libgcrypt, AS_HELP_STRING([--with-local-libgcrypt], [Build with libgcrypt (if present) instead of the enclosed gcrypt light]))

AS_IF([test "x$enable_fuzztargets" = "xyes"], [BUILD_FUZZTARGETS=1], [BUILD_FUZZTARGETS=0])
AM_CONDITIONAL([BUILD_FUZZTARGETS], [test "x$enable_fuzztargets" = "xyes"])
Expand Down Expand Up @@ -238,27 +238,20 @@ AM_CONDITIONAL([HAS_FUZZLDFLAGS], [test "x$has_sanitizefuzzer" = "xyes"])

AC_CHECK_LIB(pthread, pthread_setaffinity_np, AC_DEFINE_UNQUOTED(HAVE_PTHREAD_SETAFFINITY_NP, 1, [libc has pthread_setaffinity_np]))

AS_IF([test "${with_libgcrypt+set}" = set],[
dnl> GCRYPT
GCRYPT_ENABLED=1
AC_ARG_ENABLE([gcrypt],
[AS_HELP_STRING([--disable-gcrypt], [Avoid compiling with libgcrypt/libgpg-error, even if they are present. QUIC sub-classification may be missing])],
[GCRYPT_ENABLED=0],
[AC_CHECK_LIB(gcrypt, gcry_cipher_checktag)])
AS_IF([test ${GCRYPT_ENABLED} -eq 1], [
dnl> libgcrypt (external)
USE_HOST_LIBGCRYPT=0
AS_IF([test "${with_local_libgcrypt+set}" = set],[
USE_HOST_LIBGCRYPT=1
AC_CHECK_LIB(gcrypt, gcry_cipher_checktag)
if test "x$ac_cv_lib_gcrypt_gcry_cipher_checktag" = xyes; then :
ADDITIONAL_LIBS="${ADDITIONAL_LIBS} -lgcrypt"
else
$as_unset ac_cv_lib_gcrypt_gcry_cipher_checktag
AC_CHECK_LIB(gpg-error, gpg_strerror_r)
AC_CHECK_LIB(gcrypt, gcry_cipher_checktag)
if test "x$ac_cv_lib_gcrypt_gcry_cipher_checktag" = xyes -a "x$ac_cv_lib_gpg_error_gpg_strerror_r" = xyes; then :
ADDITIONAL_LIBS="${ADDITIONAL_LIBS} -lgcrypt -lgpg-error"
else
GCRYPT_ENABLED=0
fi
AC_CHECK_LIB(gpg-error, gpg_strerror_r, [], AC_MSG_ERROR([libgpg-error required (because of --with-local-libgcrypt) but not found or too old.]))
AC_CHECK_LIB(gcrypt, gcry_cipher_checktag, [], AC_MSG_ERROR([libgcrypt required (because of --with-local-libgcrypt) but not found or too old.]))
ADDITIONAL_LIBS="${ADDITIONAL_LIBS} -lgcrypt -lgpg-error"
fi
])
AC_DEFINE_UNQUOTED(USE_HOST_LIBGCRYPT, 1, [Use locally installed libgcrypt instead of builtin gcrypt-light])
])

dnl> PCRE
Expand Down Expand Up @@ -314,6 +307,6 @@ AC_SUBST(BUILD_MINGW_X64)
AC_SUBST(BUILD_FUZZTARGETS)
AC_SUBST(JSONC_CFLAGS)
AC_SUBST(JSONC_LIBS)
AC_SUBST(GCRYPT_ENABLED)
AC_SUBST(USE_HOST_LIBGCRYPT)
AC_SUBST(PCRE_ENABLED)
AC_OUTPUT
9 changes: 5 additions & 4 deletions packages/openwrt/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/uclibc++.mk
include $(INCLUDE_DIR)/package.mk

ifeq ($(CONFIG_LIBNDPI_GCRYPT),)
CONFIGURE_ARGS += --disable-gcrypt
ifneq ($(CONFIG_LIBNDPI_GCRYPT),)
CONFIGURE_ARGS += --with-local-libgcrypt
endif

define Package/libndpi
Expand All @@ -47,11 +47,12 @@ endef

define Package/libndpi/config
config LIBNDPI_GCRYPT
bool "GCrypt support"
bool "Use external libgcrypt"
depends on PACKAGE_libndpi
default n
help
This option enables QUIC client hello decryption.
This option enables QUIC client hello decryption through
an external libgcrypt instead of a lightweight builtin version.
Disabled by default.
endef

Expand Down
9 changes: 5 additions & 4 deletions packages/openwrt/Makefile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/uclibc++.mk
include $(INCLUDE_DIR)/package.mk

ifeq ($(CONFIG_LIBNDPI_GCRYPT),)
CONFIGURE_ARGS += --disable-gcrypt
ifneq ($(CONFIG_LIBNDPI_GCRYPT),)
CONFIGURE_ARGS += --with-local-libgcrypt
endif

define Package/libndpi
Expand All @@ -46,11 +46,12 @@ endef

define Package/libndpi/config
config LIBNDPI_GCRYPT
bool "GCrypt support"
bool "Use external libgcrypt"
depends on PACKAGE_libndpi
default n
help
This option enables QUIC client hello decryption.
This option enables QUIC client hello decryption through
an external libgcrypt instead of a lightweight builtin version.
Disabled by default.
endef

Expand Down
6 changes: 6 additions & 0 deletions src/lib/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ NDPI_LIB_STATIC = libndpi.a
NDPI_LIB_SHARED_BASE = libndpi.so
NDPI_LIB_SHARED = $(NDPI_LIB_SHARED_BASE).@NDPI_VERSION_SHORT@
NDPI_LIBS = $(NDPI_LIB_STATIC) $(NDPI_LIB_SHARED)
USE_HOST_LIBGCRYPT = @USE_HOST_LIBGCRYPT@

ifneq ($(USE_HOST_LIBGCRYPT),0)
TMP_OBJS := $(OBJECTS)
OBJECTS = $(filter-out third_party/src/gcrypt_light.o,$(TMP_OBJS))
endif

ifneq ($(OS),Windows_NT)
OS := $(shell uname)
Expand Down
8 changes: 1 addition & 7 deletions src/lib/ndpi_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,10 @@
#include "ahocorasick.h"
#include "libcache.h"

#ifdef HAVE_LIBGCRYPT
#ifdef USE_HOST_LIBGCRYPT
#include <gcrypt.h>
#else
#include <gcrypt_light.h>
#define HAVE_LIBGCRYPT 1
#endif

#include <time.h>
Expand Down Expand Up @@ -2420,7 +2419,6 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs
if(prefs & ndpi_enable_ja3_plus)
ndpi_str->enable_ja3_plus = 1;

#ifdef HAVE_LIBGCRYPT
if(!(prefs & ndpi_dont_init_libgcrypt)) {
if(!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) {
const char *gcrypt_ver = gcry_check_version(NULL);
Expand All @@ -2436,7 +2434,6 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs
} else {
NDPI_LOG_DBG(ndpi_str, "Libgcrypt initialization skipped\n");
}
#endif

if((ndpi_str->protocols_ptree = ndpi_patricia_new(32 /* IPv4 */)) != NULL) {
ndpi_init_ptree_ipv4(ndpi_str, ndpi_str->protocols_ptree, host_protocol_list);
Expand Down Expand Up @@ -7554,10 +7551,7 @@ u_int16_t ndpi_get_api_version() {
}

const char *ndpi_get_gcrypt_version(void) {
#ifdef HAVE_LIBGCRYPT
return gcry_check_version(NULL);
#endif
return NULL;
}

ndpi_proto_defaults_t *ndpi_get_proto_defaults(struct ndpi_detection_module_struct *ndpi_str) {
Expand Down
43 changes: 14 additions & 29 deletions src/lib/protocols/quic.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_QUIC
#include "ndpi_api.h"

#ifdef HAVE_LIBGCRYPT
#ifdef USE_HOST_LIBGCRYPT
#include <gcrypt.h>
#else
#define HAVE_LIBGCRYPT 1
#include <gcrypt_light.h>
#endif

Expand Down Expand Up @@ -124,13 +123,13 @@ static uint8_t get_u8_quic_ver(uint32_t version)

return 0;
}
#ifdef HAVE_LIBGCRYPT

static int is_quic_ver_less_than(uint32_t version, uint8_t max_version)
{
uint8_t u8_ver = get_u8_quic_ver(version);
return u8_ver && u8_ver <= max_version;
}
#endif

static int is_quic_ver_greater_than(uint32_t version, uint8_t min_version)
{
return get_u8_quic_ver(version) >= min_version;
Expand Down Expand Up @@ -191,15 +190,13 @@ int is_version_with_ietf_long_header(uint32_t version)
((version & 0xFFFFFF00) == 0x51303500) /* Q05X */ ||
((version & 0xFFFFFF00) == 0x54303500) /* T05X */;
}
#ifdef HAVE_LIBGCRYPT
int is_version_with_v1_labels(uint32_t version)
{
if(((version & 0xFFFFFF00) == 0x51303500) /* Q05X */ ||
((version & 0xFFFFFF00) == 0x54303500)) /* T05X */
return 1;
return is_quic_ver_less_than(version, 33);
}
#endif

int quic_len(const uint8_t *buf, uint64_t *value)
{
Expand Down Expand Up @@ -246,12 +243,10 @@ static uint16_t gquic_get_u16(const uint8_t *buf, uint32_t version)
}


#if defined(HAVE_LIBGCRYPT)

#ifdef DEBUG_CRYPT
char *__gcry_err(gpg_error_t err, char *buf, size_t buflen)
{
#if defined(HAVE_LIBGPG_ERROR) || defined(LIBGCRYPT_INTERNAL)
#if defined(HAVE_LIBGPG_ERROR) || !defined(USE_HOST_LIBGCRYPT)
gpg_strerror_r(err, buf, buflen);
/* I am not sure if the string will be always null-terminated...
Better safe than sorry */
Expand Down Expand Up @@ -555,7 +550,7 @@ static int quic_hp_cipher_init(quic_hp_cipher *hp_cipher, int hash_algo,
{
uint8_t hp_key[256/8]; /* Maximum key size is for AES256 cipher. */
uint32_t hash_len = gcry_md_get_algo_dlen(hash_algo);
char *label = is_version_with_v1_labels(version) ? "quic hp" : "quicv2 hp";
char const * const label = is_version_with_v1_labels(version) ? "quic hp" : "quicv2 hp";

if(!quic_hkdf_expand_label(hash_algo, secret, hash_len, label, hp_key, key_length)) {
return 0;
Expand All @@ -569,8 +564,8 @@ static int quic_pp_cipher_init(quic_pp_cipher *pp_cipher, int hash_algo,
{
uint8_t write_key[256/8]; /* Maximum key size is for AES256 cipher. */
uint32_t hash_len = gcry_md_get_algo_dlen(hash_algo);
char *key_label = is_version_with_v1_labels(version) ? "quic key" : "quicv2 key";
char *iv_label = is_version_with_v1_labels(version) ? "quic iv" : "quicv2 iv";
char const * const key_label = is_version_with_v1_labels(version) ? "quic key" : "quicv2 key";
char const * const iv_label = is_version_with_v1_labels(version) ? "quic iv" : "quicv2 iv";

if(key_length > sizeof(write_key)) {
return 0;
Expand Down Expand Up @@ -955,7 +950,6 @@ static int quic_derive_initial_secrets(uint32_t version,


static uint8_t *decrypt_initial_packet(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
const uint8_t *dest_conn_id, uint8_t dest_conn_id_len,
uint8_t source_conn_id_len, uint32_t version,
uint32_t *clear_payload_len)
Expand Down Expand Up @@ -1036,8 +1030,6 @@ static uint8_t *decrypt_initial_packet(struct ndpi_detection_module_struct *ndpi
return NULL;
}

#endif /* HAVE_LIBGCRYPT */


static int __reassemble(struct ndpi_flow_struct *flow, const u_int8_t *frag,
uint64_t frag_len, uint64_t frag_offset,
Expand All @@ -1053,7 +1045,7 @@ static int __reassemble(struct ndpi_flow_struct *flow, const u_int8_t *frag,
*/

if(!flow->l4.udp.quic_reasm_buf) {
flow->l4.udp.quic_reasm_buf = ndpi_malloc(max_quic_reasm_buffer_len);
flow->l4.udp.quic_reasm_buf = (uint8_t *)ndpi_malloc(max_quic_reasm_buffer_len);
if(!flow->l4.udp.quic_reasm_buf)
return -1; /* Memory error */
flow->l4.udp.quic_reasm_buf_len = 0;
Expand Down Expand Up @@ -1090,7 +1082,7 @@ static int is_ch_reassembler_pending(struct ndpi_flow_struct *flow)
flow->l4.udp.quic_reasm_buf_len);
}
static const uint8_t *get_reassembled_crypto_data(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
struct ndpi_flow_struct *flow,
const u_int8_t *frag,
uint64_t frag_offset, uint64_t frag_len,
uint64_t *crypto_data_len)
Expand Down Expand Up @@ -1265,15 +1257,12 @@ static const uint8_t *get_crypto_data(struct ndpi_detection_module_struct *ndpi_
}

static uint8_t *get_clear_payload(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
uint32_t version, uint32_t *clear_payload_len)
{
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
u_int8_t *clear_payload;
u_int8_t dest_conn_id_len;
#ifdef HAVE_LIBGCRYPT
u_int8_t source_conn_id_len;
#endif

if(is_gquic_ver_less_than(version, 43)) {
clear_payload = (uint8_t *)&packet->payload[26];
Expand All @@ -1300,16 +1289,13 @@ static uint8_t *get_clear_payload(struct ndpi_detection_module_struct *ndpi_stru
version, dest_conn_id_len);
return NULL;
}
#ifdef HAVE_LIBGCRYPT

source_conn_id_len = packet->payload[6 + dest_conn_id_len];
const u_int8_t *dest_conn_id = &packet->payload[6];
clear_payload = decrypt_initial_packet(ndpi_struct, flow,
clear_payload = decrypt_initial_packet(ndpi_struct,
dest_conn_id, dest_conn_id_len,
source_conn_id_len, version,
clear_payload_len);
#else
clear_payload = NULL;
#endif
}

return clear_payload;
Expand Down Expand Up @@ -1435,7 +1421,6 @@ static void process_chlo(struct ndpi_detection_module_struct *ndpi_struct,


static int may_be_initial_pkt(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
uint32_t *version)
{
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
Expand Down Expand Up @@ -1529,7 +1514,7 @@ static int may_be_initial_pkt(struct ndpi_detection_module_struct *ndpi_struct,
/* ***************************************************************** */

static int eval_extra_processing(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow, u_int32_t version)
struct ndpi_flow_struct *flow, u_int32_t version)
{
/* For the time being we need extra processing in two cases only:
1) to detect Snapchat calls, i.e. RTP/RTCP multiplxed with QUIC.
Expand Down Expand Up @@ -1631,7 +1616,7 @@ static void ndpi_search_quic(struct ndpi_detection_module_struct *ndpi_struct,
* anyone complains...
*/

is_quic = may_be_initial_pkt(ndpi_struct, flow, &version);
is_quic = may_be_initial_pkt(ndpi_struct, &version);
if(!is_quic) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return;
Expand Down Expand Up @@ -1659,7 +1644,7 @@ static void ndpi_search_quic(struct ndpi_detection_module_struct *ndpi_struct,
/*
* 4) Extract the Payload from Initial Packets
*/
clear_payload = get_clear_payload(ndpi_struct, flow, version, &clear_payload_len);
clear_payload = get_clear_payload(ndpi_struct, version, &clear_payload_len);
if(!clear_payload) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return;
Expand Down
Loading

0 comments on commit 5ae637a

Please sign in to comment.