Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: Certificate Compression with boringssl #2056

Merged
merged 1 commit into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ jobs:
libjemalloc-dev \
libc-ares-dev \
libelf-dev \
libbrotli-dev \
cmake \
cmake-data
echo 'CPPFLAGS=-fsanitize=address,undefined -fno-sanitize-recover=undefined -g' >> $GITHUB_ENV
Expand All @@ -262,6 +263,7 @@ jobs:
c-ares \
cunit \
libressl \
brotli \
autoconf \
automake \
pkg-config \
Expand Down Expand Up @@ -433,12 +435,12 @@ jobs:
if: matrix.buildtool == 'autotools' && runner.os == 'Linux'
run: |
make -j"$(nproc)" distcheck \
DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --with-libev --enable-werror $EXTRA_AUTOTOOLS_OPTS CPPFLAGS=\"$CPPFLAGS\" LDFLAGS=\"$LDFLAGS\""
DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --with-libev --with-librotlienc --with-libbrotlidec --enable-werror $EXTRA_AUTOTOOLS_OPTS CPPFLAGS=\"$CPPFLAGS\" LDFLAGS=\"$LDFLAGS\""
- name: Build nghttp2 with autotools (MacOS)
if: matrix.buildtool == 'autotools' && runner.os == 'macOS'
run: |
make -j"$(sysctl -n hw.ncpu)" distcheck \
DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-libev --enable-werror $EXTRA_AUTOTOOLS_OPTS CPPFLAGS=\"$CPPFLAGS\" LDFLAGS=\"$LDFLAGS\""
DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-libev --with-librotlienc --with-libbrotlidec --enable-werror $EXTRA_AUTOTOOLS_OPTS CPPFLAGS=\"$CPPFLAGS\" LDFLAGS=\"$LDFLAGS\""
- name: Build nghttp2 with cmake
if: matrix.buildtool == 'cmake'
run: |
Expand Down
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ if(NOT ENABLE_LIB_ONLY)
find_package(Libev 4.11)
find_package(Libcares 1.7.5)
find_package(ZLIB 1.2.3)
find_package(Libbrotlienc 1.0.9)
find_package(Libbrotlidec 1.0.9)
endif()

find_package(OpenSSL 1.1.1)
Expand Down Expand Up @@ -474,6 +476,8 @@ message(STATUS "summary of build options:
Jemalloc: ${HAVE_JEMALLOC} (LIBS='${JEMALLOC_LIBRARIES}')
Zlib: ${HAVE_ZLIB} (LIBS='${ZLIB_LIBRARIES}')
Systemd: ${HAVE_SYSTEMD} (LIBS='${SYSTEMD_LIBRARIES}')
Libbrotlienc: ${HAVE_LIBBROTLIENC} (LIBS='${LIBBROTLIENC_LIBRARIES}')
Libbrotlidec: ${HAVE_LIBBROTLIDEC} (LIBS='${LIBBROTLIDEC_LIBRARIES}')
Third-party:
http-parser: ${ENABLE_THIRD_PARTY}
MRuby: ${HAVE_MRUBY}
Expand Down
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-env \
cmake/FindLibnghttp3.cmake \
cmake/FindLibngtcp2.cmake \
cmake/FindLibngtcp2_crypto_quictls.cmake \
cmake/FindLibbrotlienc.cmake \
cmake/FindLibbrotlidec.cmake \
cmake/PickyWarningsC.cmake \
cmake/PickyWarningsCXX.cmake

Expand Down
5 changes: 5 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ To mitigate heap fragmentation in long running server programs
Alpine Linux currently does not support malloc replacement
due to musl limitations. See details in issue `#762 <https://github.com/nghttp2/nghttp2/issues/762>`_.

For BoringSSL or aws-lc build, to enable :rfc:`8879` TLS Certificate
Compression in applications, the following library is required:

* libbrotli-dev >= 1.0.9

To enable mruby support for nghttpx, `mruby
<https://github.com/mruby/mruby>`_ is required. We need to build
mruby with C++ ABI explicitly turned on, and probably need other
Expand Down
36 changes: 36 additions & 0 deletions cmake/FindLibbrotlidec.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# - Try to find libbrotlidec
# Once done this will define
# LIBBROTLIDEC_FOUND - System has libbrotlidec
# LIBBROTLIDEC_INCLUDE_DIRS - The libbrotlidec include directories
# LIBBROTLIDEC_LIBRARIES - The libraries needed to use libbrotlidec

find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBBROTLIDEC QUIET libbrotlidec)

find_path(LIBBROTLIDEC_INCLUDE_DIR
NAMES brotli/decode.h
HINTS ${PC_LIBBROTLIDEC_INCLUDE_DIRS}
)
find_library(LIBBROTLIDEC_LIBRARY
NAMES brotlidec
HINTS ${PC_LIBBROTLIDEC_LIBRARY_DIRS}
)

if(PC_LIBBROTLIDEC_FOUND)
set(LIBBROTLIDEC_VERSION ${PC_LIBBROTLIDEC_VERSION})
endif()

include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBBROTLIDEC_FOUND
# to TRUE if all listed variables are TRUE and the requested version
# matches.
find_package_handle_standard_args(Libbrotlidec REQUIRED_VARS
LIBBROTLIDEC_LIBRARY LIBBROTLIDEC_INCLUDE_DIR
VERSION_VAR LIBBROTLIDEC_VERSION)

if(LIBBROTLIDEC_FOUND)
set(LIBBROTLIDEC_LIBRARIES ${LIBBROTLIDEC_LIBRARY})
set(LIBBROTLIDEC_INCLUDE_DIRS ${LIBBROTLIDEC_INCLUDE_DIR})
endif()

mark_as_advanced(LIBBROTLIDEC_INCLUDE_DIR LIBBROTLIDEC_LIBRARY)
36 changes: 36 additions & 0 deletions cmake/FindLibbrotlienc.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# - Try to find libbrotlienc
# Once done this will define
# LIBBROTLIENC_FOUND - System has libbrotlienc
# LIBBROTLIENC_INCLUDE_DIRS - The libbrotlienc include directories
# LIBBROTLIENC_LIBRARIES - The libraries needed to use libbrotlienc

find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBBROTLIENC QUIET libbrotlienc)

find_path(LIBBROTLIENC_INCLUDE_DIR
NAMES brotli/encode.h
HINTS ${PC_LIBBROTLIENC_INCLUDE_DIRS}
)
find_library(LIBBROTLIENC_LIBRARY
NAMES brotlienc
HINTS ${PC_LIBBROTLIENC_LIBRARY_DIRS}
)

if(PC_LIBBROTLIENC_FOUND)
set(LIBBROTLIENC_VERSION ${PC_LIBBROTLIENC_VERSION})
endif()

include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBBROTLIENC_FOUND
# to TRUE if all listed variables are TRUE and the requested version
# matches.
find_package_handle_standard_args(Libbrotlienc REQUIRED_VARS
LIBBROTLIENC_LIBRARY LIBBROTLIENC_INCLUDE_DIR
VERSION_VAR LIBBROTLIENC_VERSION)

if(LIBBROTLIENC_FOUND)
set(LIBBROTLIENC_LIBRARIES ${LIBBROTLIENC_LIBRARY})
set(LIBBROTLIENC_INCLUDE_DIRS ${LIBBROTLIENC_INCLUDE_DIR})
endif()

mark_as_advanced(LIBBROTLIENC_INCLUDE_DIR LIBBROTLIENC_LIBRARY)
53 changes: 53 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,16 @@ AC_ARG_WITH([libbpf],
[Use libbpf [default=no]])],
[request_libbpf=$withval], [request_libbpf=no])

AC_ARG_WITH([libbrotlienc],
[AS_HELP_STRING([--with-libbrotlienc],
[Use libbrotlienc [default=check]])],
[request_libbrotlienc=$withval], [request_libbrotlienc=check])

AC_ARG_WITH([libbrotlidec],
[AS_HELP_STRING([--with-libbrotlidec],
[Use libbrotlidec [default=check]])],
[request_libbrotlidec=$withval], [request_libbrotlidec=check])

dnl Define variables
AC_ARG_VAR([LIBEV_CFLAGS], [C compiler flags for libev, skipping any checks])
AC_ARG_VAR([LIBEV_LIBS], [linker flags for libev, skipping any checks])
Expand Down Expand Up @@ -626,6 +636,47 @@ fi

AM_CONDITIONAL([HAVE_LIBBPF], [ test "x${have_libbpf}" = "xyes" ])

# libbrotlienc (for src)
have_libbrotlienc=no
if test "x${request_libbrotlienc}" != "xno"; then
PKG_CHECK_MODULES([LIBBROTLIENC], [libbrotlienc >= 1.0.9],
[have_libbrotlienc=yes],
[have_libbrotlienc=no])
if test "x${have_libbrotlienc}" = "xno"; then
AC_MSG_NOTICE($LIBBROTLIENC_PKG_ERRORS)
fi
fi

if test "x${request_libbrotlienc}" = "xyes" &&
test "x${have_libbrotlienc}" != "xyes"; then
AC_MSG_ERROR([libbrotlienc was requested (--with-libbrotlienc) but not found])
fi

# libbrotlidec (for src)
have_libbrotlidec=no
if test "x${request_libbrotlidec}" != "xno"; then
PKG_CHECK_MODULES([LIBBROTLIDEC], [libbrotlidec >= 1.0.9],
[have_libbrotlidec=yes],
[have_libbrotlidec=no])
if test "x${have_libbrotlidec}" = "xno"; then
AC_MSG_NOTICE($LIBBROTLIDEC_PKG_ERRORS)
fi
fi

if test "x${request_libbrotlidec}" = "xyes" &&
test "x${have_libbrotlidec}" != "xyes"; then
AC_MSG_ERROR([libbrotlidec was requested (--with-libbrotlidec) but not found])
fi

have_libbrotli=no
if test "x${have_libbrotlienc}" = "xyes" &&
test "x${have_libbrotlidec}" = "xyes"; then
have_libbrotli=yes

AC_DEFINE([HAVE_LIBBROTLI], [1],
[Define to 1 if you have `libbrotlienc` and libbrotlidec` libraries.])
fi

# libevent_openssl (for examples)
# 2.0.8 is required because we use evconnlistener_set_error_cb()
have_libevent_openssl=no
Expand Down Expand Up @@ -1172,6 +1223,8 @@ AC_MSG_NOTICE([summary of build options:
Jemalloc: ${have_jemalloc} (CFLAGS='${JEMALLOC_CFLAGS}' LIBS='${JEMALLOC_LIBS}')
Zlib: ${have_zlib} (CFLAGS='${ZLIB_CFLAGS}' LIBS='${ZLIB_LIBS}')
Systemd: ${have_libsystemd} (CFLAGS='${SYSTEMD_CFLAGS}' LIBS='${SYSTEMD_LIBS}')
Libbrotlienc ${have_libbrotlienc} (CFLAGS="${LIBBROTLIENC_CFLAGS}' LIBS='${LIBBROTLIENC_LIBS}')
Libbrotlidec ${have_libbrotlidec} (CFLAGS="${LIBBROTLIDEC_CFLAGS}' LIBS='${LIBBROTLIDEC_LIBS}')
Third-party:
http-parser: ${enable_third_party}
MRuby: ${have_mruby} (CFLAGS='${LIBMRUBY_CFLAGS}' LIBS='${LIBMRUBY_LIBS}')
Expand Down
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ include_directories(
${JANSSON_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS}
${LIBBPF_INCLUDE_DIRS}
${LIBBROTLIENC_INCLUDE_DIRS}
${LIBBROTLIDEC_INCLUDE_DIRS}
)

# XXX per-target?
Expand All @@ -38,6 +40,8 @@ link_libraries(
${ZLIB_LIBRARIES}
${APP_LIBRARIES}
${LIBBPF_LIBRARIES}
${LIBBROTLIENC_LIBRARIES}
${LIBBROTLIDEC_LIBRARIES}
)

if(ENABLE_APP)
Expand Down
9 changes: 9 additions & 0 deletions src/HttpServer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2205,6 +2205,15 @@ int HttpServer::run() {

// ALPN selection callback
SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, this);

#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI)
if (!SSL_CTX_add_cert_compression_alg(
ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI,
nghttp2::tls::cert_compress, nghttp2::tls::cert_decompress)) {
std::cerr << "SSL_CTX_add_cert_compression_alg failed." << std::endl;
return -1;
}
#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI
}

auto loop = EV_DEFAULT;
Expand Down
4 changes: 4 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ AM_CPPFLAGS = \
@JANSSON_CFLAGS@ \
@LIBBPF_CFLAGS@ \
@ZLIB_CFLAGS@ \
@LIBBROTLIENC_CFLAGS@ \
@LIBBROTLIDEC_CFLAGS@ \
@EXTRA_DEFS@ \
@DEFS@
AM_LDFLAGS = @LIBTOOL_LDFLAGS@
Expand All @@ -73,6 +75,8 @@ LDADD = $(top_builddir)/lib/libnghttp2.la \
@JANSSON_LIBS@ \
@LIBBPF_LIBS@ \
@ZLIB_LIBS@ \
@LIBBROTLIENC_LIBS@ \
@LIBBROTLIDEC_LIBS@ \
@APPLDFLAGS@

if ENABLE_APP
Expand Down
9 changes: 9 additions & 0 deletions src/h2load.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2973,6 +2973,15 @@ int main(int argc, char **argv) {
}
}

#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI)
if (!SSL_CTX_add_cert_compression_alg(
ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI,
nghttp2::tls::cert_compress, nghttp2::tls::cert_decompress)) {
std::cerr << "SSL_CTX_add_cert_compression_alg failed" << std::endl;
exit(EXIT_FAILURE);
}
#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI

std::string user_agent = "h2load nghttp2/" NGHTTP2_VERSION;
Headers shared_nva;
shared_nva.emplace_back(":scheme", config.scheme);
Expand Down
11 changes: 11 additions & 0 deletions src/nghttp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2311,6 +2311,17 @@ int communicate(
auto proto_list = util::get_default_alpn();

SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size());

#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI)
if (!SSL_CTX_add_cert_compression_alg(
ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI,
nghttp2::tls::cert_compress, nghttp2::tls::cert_decompress)) {
std::cerr << "[ERROR] SSL_CTX_add_cert_compression_alg failed."
<< std::endl;
result = -1;
goto fin;
}
#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI
}
{
HttpClient client{callbacks, loop, ssl_ctx};
Expand Down