@point3/node-rdkafka 3.6.0-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +20 -0
- package/README.md +636 -0
- package/binding.gyp +154 -0
- package/deps/librdkafka/.clang-format +136 -0
- package/deps/librdkafka/.clang-format-cpp +103 -0
- package/deps/librdkafka/.dir-locals.el +10 -0
- package/deps/librdkafka/.formatignore +33 -0
- package/deps/librdkafka/.gdbmacros +19 -0
- package/deps/librdkafka/.github/CODEOWNERS +1 -0
- package/deps/librdkafka/.github/ISSUE_TEMPLATE +34 -0
- package/deps/librdkafka/.semaphore/run-all-tests.yml +77 -0
- package/deps/librdkafka/.semaphore/semaphore-integration.yml +250 -0
- package/deps/librdkafka/.semaphore/semaphore.yml +378 -0
- package/deps/librdkafka/.semaphore/verify-linux-packages.yml +41 -0
- package/deps/librdkafka/CHANGELOG.md +2208 -0
- package/deps/librdkafka/CMakeLists.txt +291 -0
- package/deps/librdkafka/CODE_OF_CONDUCT.md +46 -0
- package/deps/librdkafka/CONFIGURATION.md +209 -0
- package/deps/librdkafka/CONTRIBUTING.md +431 -0
- package/deps/librdkafka/Doxyfile +2375 -0
- package/deps/librdkafka/INTRODUCTION.md +2481 -0
- package/deps/librdkafka/LICENSE +26 -0
- package/deps/librdkafka/LICENSE.cjson +22 -0
- package/deps/librdkafka/LICENSE.crc32c +28 -0
- package/deps/librdkafka/LICENSE.fnv1a +18 -0
- package/deps/librdkafka/LICENSE.hdrhistogram +27 -0
- package/deps/librdkafka/LICENSE.lz4 +26 -0
- package/deps/librdkafka/LICENSE.murmur2 +25 -0
- package/deps/librdkafka/LICENSE.nanopb +22 -0
- package/deps/librdkafka/LICENSE.opentelemetry +203 -0
- package/deps/librdkafka/LICENSE.pycrc +23 -0
- package/deps/librdkafka/LICENSE.queue +31 -0
- package/deps/librdkafka/LICENSE.regexp +5 -0
- package/deps/librdkafka/LICENSE.snappy +36 -0
- package/deps/librdkafka/LICENSE.tinycthread +26 -0
- package/deps/librdkafka/LICENSE.wingetopt +49 -0
- package/deps/librdkafka/LICENSES.txt +625 -0
- package/deps/librdkafka/Makefile +125 -0
- package/deps/librdkafka/README.md +199 -0
- package/deps/librdkafka/README.win32 +26 -0
- package/deps/librdkafka/STATISTICS.md +624 -0
- package/deps/librdkafka/configure +214 -0
- package/deps/librdkafka/configure.self +331 -0
- package/deps/librdkafka/debian/changelog +111 -0
- package/deps/librdkafka/debian/compat +1 -0
- package/deps/librdkafka/debian/control +71 -0
- package/deps/librdkafka/debian/copyright +99 -0
- package/deps/librdkafka/debian/gbp.conf +9 -0
- package/deps/librdkafka/debian/librdkafka++1.install +1 -0
- package/deps/librdkafka/debian/librdkafka-dev.examples +2 -0
- package/deps/librdkafka/debian/librdkafka-dev.install +9 -0
- package/deps/librdkafka/debian/librdkafka1.docs +5 -0
- package/deps/librdkafka/debian/librdkafka1.install +1 -0
- package/deps/librdkafka/debian/librdkafka1.symbols +135 -0
- package/deps/librdkafka/debian/rules +19 -0
- package/deps/librdkafka/debian/source/format +1 -0
- package/deps/librdkafka/debian/watch +2 -0
- package/deps/librdkafka/dev-conf.sh +123 -0
- package/deps/librdkafka/examples/CMakeLists.txt +79 -0
- package/deps/librdkafka/examples/Makefile +167 -0
- package/deps/librdkafka/examples/README.md +42 -0
- package/deps/librdkafka/examples/alter_consumer_group_offsets.c +338 -0
- package/deps/librdkafka/examples/consumer.c +271 -0
- package/deps/librdkafka/examples/delete_records.c +233 -0
- package/deps/librdkafka/examples/describe_cluster.c +322 -0
- package/deps/librdkafka/examples/describe_consumer_groups.c +455 -0
- package/deps/librdkafka/examples/describe_topics.c +427 -0
- package/deps/librdkafka/examples/elect_leaders.c +317 -0
- package/deps/librdkafka/examples/globals.json +11 -0
- package/deps/librdkafka/examples/idempotent_producer.c +344 -0
- package/deps/librdkafka/examples/incremental_alter_configs.c +347 -0
- package/deps/librdkafka/examples/kafkatest_verifiable_client.cpp +945 -0
- package/deps/librdkafka/examples/list_consumer_group_offsets.c +359 -0
- package/deps/librdkafka/examples/list_consumer_groups.c +365 -0
- package/deps/librdkafka/examples/list_offsets.c +327 -0
- package/deps/librdkafka/examples/misc.c +287 -0
- package/deps/librdkafka/examples/openssl_engine_example.cpp +248 -0
- package/deps/librdkafka/examples/producer.c +251 -0
- package/deps/librdkafka/examples/producer.cpp +228 -0
- package/deps/librdkafka/examples/rdkafka_complex_consumer_example.c +617 -0
- package/deps/librdkafka/examples/rdkafka_complex_consumer_example.cpp +467 -0
- package/deps/librdkafka/examples/rdkafka_consume_batch.cpp +264 -0
- package/deps/librdkafka/examples/rdkafka_example.c +853 -0
- package/deps/librdkafka/examples/rdkafka_example.cpp +679 -0
- package/deps/librdkafka/examples/rdkafka_performance.c +1781 -0
- package/deps/librdkafka/examples/transactions-older-broker.c +668 -0
- package/deps/librdkafka/examples/transactions.c +665 -0
- package/deps/librdkafka/examples/user_scram.c +491 -0
- package/deps/librdkafka/examples/win_ssl_cert_store.cpp +396 -0
- package/deps/librdkafka/lds-gen.py +73 -0
- package/deps/librdkafka/mainpage.doxy +40 -0
- package/deps/librdkafka/mklove/Makefile.base +329 -0
- package/deps/librdkafka/mklove/modules/configure.atomics +144 -0
- package/deps/librdkafka/mklove/modules/configure.base +2484 -0
- package/deps/librdkafka/mklove/modules/configure.builtin +70 -0
- package/deps/librdkafka/mklove/modules/configure.cc +186 -0
- package/deps/librdkafka/mklove/modules/configure.cxx +8 -0
- package/deps/librdkafka/mklove/modules/configure.fileversion +65 -0
- package/deps/librdkafka/mklove/modules/configure.gitversion +29 -0
- package/deps/librdkafka/mklove/modules/configure.good_cflags +18 -0
- package/deps/librdkafka/mklove/modules/configure.host +132 -0
- package/deps/librdkafka/mklove/modules/configure.lib +49 -0
- package/deps/librdkafka/mklove/modules/configure.libcurl +99 -0
- package/deps/librdkafka/mklove/modules/configure.libsasl2 +36 -0
- package/deps/librdkafka/mklove/modules/configure.libssl +147 -0
- package/deps/librdkafka/mklove/modules/configure.libzstd +58 -0
- package/deps/librdkafka/mklove/modules/configure.parseversion +95 -0
- package/deps/librdkafka/mklove/modules/configure.pic +16 -0
- package/deps/librdkafka/mklove/modules/configure.socket +20 -0
- package/deps/librdkafka/mklove/modules/configure.zlib +61 -0
- package/deps/librdkafka/mklove/modules/patches/README.md +8 -0
- package/deps/librdkafka/mklove/modules/patches/libcurl.0000-no-runtime-linking-check.patch +11 -0
- package/deps/librdkafka/mklove/modules/patches/libssl.0000-osx-rand-include-fix-OpenSSL-PR16409.patch +56 -0
- package/deps/librdkafka/packaging/RELEASE.md +319 -0
- package/deps/librdkafka/packaging/alpine/build-alpine.sh +38 -0
- package/deps/librdkafka/packaging/archlinux/PKGBUILD +30 -0
- package/deps/librdkafka/packaging/cmake/Config.cmake.in +37 -0
- package/deps/librdkafka/packaging/cmake/Modules/FindLZ4.cmake +38 -0
- package/deps/librdkafka/packaging/cmake/Modules/FindZSTD.cmake +27 -0
- package/deps/librdkafka/packaging/cmake/Modules/LICENSE.FindZstd +178 -0
- package/deps/librdkafka/packaging/cmake/README.md +38 -0
- package/deps/librdkafka/packaging/cmake/config.h.in +52 -0
- package/deps/librdkafka/packaging/cmake/parseversion.cmake +60 -0
- package/deps/librdkafka/packaging/cmake/rdkafka.pc.in +12 -0
- package/deps/librdkafka/packaging/cmake/try_compile/atomic_32_test.c +8 -0
- package/deps/librdkafka/packaging/cmake/try_compile/atomic_64_test.c +8 -0
- package/deps/librdkafka/packaging/cmake/try_compile/c11threads_test.c +14 -0
- package/deps/librdkafka/packaging/cmake/try_compile/crc32c_hw_test.c +27 -0
- package/deps/librdkafka/packaging/cmake/try_compile/dlopen_test.c +11 -0
- package/deps/librdkafka/packaging/cmake/try_compile/libsasl2_test.c +7 -0
- package/deps/librdkafka/packaging/cmake/try_compile/pthread_setname_darwin_test.c +6 -0
- package/deps/librdkafka/packaging/cmake/try_compile/pthread_setname_freebsd_test.c +7 -0
- package/deps/librdkafka/packaging/cmake/try_compile/pthread_setname_gnu_test.c +5 -0
- package/deps/librdkafka/packaging/cmake/try_compile/rand_r_test.c +7 -0
- package/deps/librdkafka/packaging/cmake/try_compile/rdkafka_setup.cmake +122 -0
- package/deps/librdkafka/packaging/cmake/try_compile/regex_test.c +10 -0
- package/deps/librdkafka/packaging/cmake/try_compile/strndup_test.c +5 -0
- package/deps/librdkafka/packaging/cmake/try_compile/sync_32_test.c +8 -0
- package/deps/librdkafka/packaging/cmake/try_compile/sync_64_test.c +8 -0
- package/deps/librdkafka/packaging/cp/README.md +16 -0
- package/deps/librdkafka/packaging/cp/check_features.c +72 -0
- package/deps/librdkafka/packaging/cp/verify-deb.sh +33 -0
- package/deps/librdkafka/packaging/cp/verify-packages.sh +69 -0
- package/deps/librdkafka/packaging/cp/verify-rpm.sh +32 -0
- package/deps/librdkafka/packaging/debian/changelog +66 -0
- package/deps/librdkafka/packaging/debian/compat +1 -0
- package/deps/librdkafka/packaging/debian/control +49 -0
- package/deps/librdkafka/packaging/debian/copyright +84 -0
- package/deps/librdkafka/packaging/debian/docs +5 -0
- package/deps/librdkafka/packaging/debian/gbp.conf +9 -0
- package/deps/librdkafka/packaging/debian/librdkafka-dev.dirs +2 -0
- package/deps/librdkafka/packaging/debian/librdkafka-dev.examples +2 -0
- package/deps/librdkafka/packaging/debian/librdkafka-dev.install +6 -0
- package/deps/librdkafka/packaging/debian/librdkafka-dev.substvars +1 -0
- package/deps/librdkafka/packaging/debian/librdkafka.dsc +16 -0
- package/deps/librdkafka/packaging/debian/librdkafka1-dbg.substvars +1 -0
- package/deps/librdkafka/packaging/debian/librdkafka1.dirs +1 -0
- package/deps/librdkafka/packaging/debian/librdkafka1.install +2 -0
- package/deps/librdkafka/packaging/debian/librdkafka1.postinst.debhelper +5 -0
- package/deps/librdkafka/packaging/debian/librdkafka1.postrm.debhelper +5 -0
- package/deps/librdkafka/packaging/debian/librdkafka1.symbols +64 -0
- package/deps/librdkafka/packaging/debian/rules +19 -0
- package/deps/librdkafka/packaging/debian/source/format +1 -0
- package/deps/librdkafka/packaging/debian/watch +2 -0
- package/deps/librdkafka/packaging/get_version.py +21 -0
- package/deps/librdkafka/packaging/homebrew/README.md +15 -0
- package/deps/librdkafka/packaging/homebrew/brew-update-pr.sh +31 -0
- package/deps/librdkafka/packaging/mingw-w64/configure-build-msys2-mingw-static.sh +52 -0
- package/deps/librdkafka/packaging/mingw-w64/configure-build-msys2-mingw.sh +21 -0
- package/deps/librdkafka/packaging/mingw-w64/export-variables.sh +13 -0
- package/deps/librdkafka/packaging/mingw-w64/run-tests.sh +6 -0
- package/deps/librdkafka/packaging/mingw-w64/semaphoreci-build.sh +38 -0
- package/deps/librdkafka/packaging/nuget/README.md +84 -0
- package/deps/librdkafka/packaging/nuget/artifact.py +177 -0
- package/deps/librdkafka/packaging/nuget/cleanup-s3.py +143 -0
- package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-win32__bldtype-Release/msvcr120.zip +0 -0
- package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-win32__bldtype-Release/msvcr140.zip +0 -0
- package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-x64__bldtype-Release/msvcr120.zip +0 -0
- package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-x64__bldtype-Release/msvcr140.zip +0 -0
- package/deps/librdkafka/packaging/nuget/nuget.sh +21 -0
- package/deps/librdkafka/packaging/nuget/nugetpackage.py +278 -0
- package/deps/librdkafka/packaging/nuget/packaging.py +448 -0
- package/deps/librdkafka/packaging/nuget/push-to-nuget.sh +21 -0
- package/deps/librdkafka/packaging/nuget/release.py +167 -0
- package/deps/librdkafka/packaging/nuget/requirements.txt +3 -0
- package/deps/librdkafka/packaging/nuget/staticpackage.py +178 -0
- package/deps/librdkafka/packaging/nuget/templates/librdkafka.redist.nuspec +21 -0
- package/deps/librdkafka/packaging/nuget/templates/librdkafka.redist.props +18 -0
- package/deps/librdkafka/packaging/nuget/templates/librdkafka.redist.targets +19 -0
- package/deps/librdkafka/packaging/nuget/zfile/__init__.py +0 -0
- package/deps/librdkafka/packaging/nuget/zfile/zfile.py +98 -0
- package/deps/librdkafka/packaging/rpm/Makefile +92 -0
- package/deps/librdkafka/packaging/rpm/README.md +23 -0
- package/deps/librdkafka/packaging/rpm/el7-x86_64.cfg +40 -0
- package/deps/librdkafka/packaging/rpm/librdkafka.spec +118 -0
- package/deps/librdkafka/packaging/rpm/mock-on-docker.sh +96 -0
- package/deps/librdkafka/packaging/rpm/tests/Makefile +25 -0
- package/deps/librdkafka/packaging/rpm/tests/README.md +8 -0
- package/deps/librdkafka/packaging/rpm/tests/run-test.sh +42 -0
- package/deps/librdkafka/packaging/rpm/tests/test-on-docker.sh +56 -0
- package/deps/librdkafka/packaging/rpm/tests/test.c +77 -0
- package/deps/librdkafka/packaging/rpm/tests/test.cpp +34 -0
- package/deps/librdkafka/packaging/tools/Dockerfile +31 -0
- package/deps/librdkafka/packaging/tools/build-configurations-checks.sh +12 -0
- package/deps/librdkafka/packaging/tools/build-deb-package.sh +64 -0
- package/deps/librdkafka/packaging/tools/build-debian.sh +65 -0
- package/deps/librdkafka/packaging/tools/build-manylinux.sh +68 -0
- package/deps/librdkafka/packaging/tools/build-release-artifacts.sh +139 -0
- package/deps/librdkafka/packaging/tools/distro-build.sh +38 -0
- package/deps/librdkafka/packaging/tools/gh-release-checksums.py +39 -0
- package/deps/librdkafka/packaging/tools/rdutcoverage.sh +25 -0
- package/deps/librdkafka/packaging/tools/requirements.txt +2 -0
- package/deps/librdkafka/packaging/tools/run-in-docker.sh +28 -0
- package/deps/librdkafka/packaging/tools/run-integration-tests.sh +31 -0
- package/deps/librdkafka/packaging/tools/run-style-check.sh +4 -0
- package/deps/librdkafka/packaging/tools/style-format.sh +149 -0
- package/deps/librdkafka/packaging/tools/update_rpcs_max_versions.py +100 -0
- package/deps/librdkafka/service.yml +172 -0
- package/deps/librdkafka/src/CMakeLists.txt +374 -0
- package/deps/librdkafka/src/Makefile +103 -0
- package/deps/librdkafka/src/README.lz4.md +30 -0
- package/deps/librdkafka/src/cJSON.c +2834 -0
- package/deps/librdkafka/src/cJSON.h +398 -0
- package/deps/librdkafka/src/crc32c.c +430 -0
- package/deps/librdkafka/src/crc32c.h +38 -0
- package/deps/librdkafka/src/generate_proto.sh +66 -0
- package/deps/librdkafka/src/librdkafka_cgrp_synch.png +0 -0
- package/deps/librdkafka/src/lz4.c +2727 -0
- package/deps/librdkafka/src/lz4.h +842 -0
- package/deps/librdkafka/src/lz4frame.c +2078 -0
- package/deps/librdkafka/src/lz4frame.h +692 -0
- package/deps/librdkafka/src/lz4frame_static.h +47 -0
- package/deps/librdkafka/src/lz4hc.c +1631 -0
- package/deps/librdkafka/src/lz4hc.h +413 -0
- package/deps/librdkafka/src/nanopb/pb.h +917 -0
- package/deps/librdkafka/src/nanopb/pb_common.c +388 -0
- package/deps/librdkafka/src/nanopb/pb_common.h +49 -0
- package/deps/librdkafka/src/nanopb/pb_decode.c +1727 -0
- package/deps/librdkafka/src/nanopb/pb_decode.h +193 -0
- package/deps/librdkafka/src/nanopb/pb_encode.c +1000 -0
- package/deps/librdkafka/src/nanopb/pb_encode.h +185 -0
- package/deps/librdkafka/src/opentelemetry/common.pb.c +32 -0
- package/deps/librdkafka/src/opentelemetry/common.pb.h +170 -0
- package/deps/librdkafka/src/opentelemetry/metrics.options +2 -0
- package/deps/librdkafka/src/opentelemetry/metrics.pb.c +67 -0
- package/deps/librdkafka/src/opentelemetry/metrics.pb.h +966 -0
- package/deps/librdkafka/src/opentelemetry/resource.pb.c +12 -0
- package/deps/librdkafka/src/opentelemetry/resource.pb.h +58 -0
- package/deps/librdkafka/src/queue.h +850 -0
- package/deps/librdkafka/src/rd.h +584 -0
- package/deps/librdkafka/src/rdaddr.c +255 -0
- package/deps/librdkafka/src/rdaddr.h +202 -0
- package/deps/librdkafka/src/rdatomic.h +230 -0
- package/deps/librdkafka/src/rdavg.h +260 -0
- package/deps/librdkafka/src/rdavl.c +210 -0
- package/deps/librdkafka/src/rdavl.h +250 -0
- package/deps/librdkafka/src/rdbase64.c +200 -0
- package/deps/librdkafka/src/rdbase64.h +43 -0
- package/deps/librdkafka/src/rdbuf.c +1884 -0
- package/deps/librdkafka/src/rdbuf.h +375 -0
- package/deps/librdkafka/src/rdcrc32.c +114 -0
- package/deps/librdkafka/src/rdcrc32.h +170 -0
- package/deps/librdkafka/src/rddl.c +179 -0
- package/deps/librdkafka/src/rddl.h +43 -0
- package/deps/librdkafka/src/rdendian.h +175 -0
- package/deps/librdkafka/src/rdfloat.h +67 -0
- package/deps/librdkafka/src/rdfnv1a.c +113 -0
- package/deps/librdkafka/src/rdfnv1a.h +35 -0
- package/deps/librdkafka/src/rdgz.c +120 -0
- package/deps/librdkafka/src/rdgz.h +46 -0
- package/deps/librdkafka/src/rdhdrhistogram.c +721 -0
- package/deps/librdkafka/src/rdhdrhistogram.h +87 -0
- package/deps/librdkafka/src/rdhttp.c +830 -0
- package/deps/librdkafka/src/rdhttp.h +101 -0
- package/deps/librdkafka/src/rdinterval.h +177 -0
- package/deps/librdkafka/src/rdkafka.c +5505 -0
- package/deps/librdkafka/src/rdkafka.h +10686 -0
- package/deps/librdkafka/src/rdkafka_admin.c +9794 -0
- package/deps/librdkafka/src/rdkafka_admin.h +661 -0
- package/deps/librdkafka/src/rdkafka_assignment.c +1010 -0
- package/deps/librdkafka/src/rdkafka_assignment.h +73 -0
- package/deps/librdkafka/src/rdkafka_assignor.c +1786 -0
- package/deps/librdkafka/src/rdkafka_assignor.h +402 -0
- package/deps/librdkafka/src/rdkafka_aux.c +409 -0
- package/deps/librdkafka/src/rdkafka_aux.h +174 -0
- package/deps/librdkafka/src/rdkafka_background.c +221 -0
- package/deps/librdkafka/src/rdkafka_broker.c +6337 -0
- package/deps/librdkafka/src/rdkafka_broker.h +744 -0
- package/deps/librdkafka/src/rdkafka_buf.c +543 -0
- package/deps/librdkafka/src/rdkafka_buf.h +1525 -0
- package/deps/librdkafka/src/rdkafka_cert.c +576 -0
- package/deps/librdkafka/src/rdkafka_cert.h +62 -0
- package/deps/librdkafka/src/rdkafka_cgrp.c +7587 -0
- package/deps/librdkafka/src/rdkafka_cgrp.h +477 -0
- package/deps/librdkafka/src/rdkafka_conf.c +4880 -0
- package/deps/librdkafka/src/rdkafka_conf.h +732 -0
- package/deps/librdkafka/src/rdkafka_confval.h +97 -0
- package/deps/librdkafka/src/rdkafka_coord.c +623 -0
- package/deps/librdkafka/src/rdkafka_coord.h +132 -0
- package/deps/librdkafka/src/rdkafka_error.c +228 -0
- package/deps/librdkafka/src/rdkafka_error.h +80 -0
- package/deps/librdkafka/src/rdkafka_event.c +502 -0
- package/deps/librdkafka/src/rdkafka_event.h +126 -0
- package/deps/librdkafka/src/rdkafka_feature.c +898 -0
- package/deps/librdkafka/src/rdkafka_feature.h +104 -0
- package/deps/librdkafka/src/rdkafka_fetcher.c +1422 -0
- package/deps/librdkafka/src/rdkafka_fetcher.h +44 -0
- package/deps/librdkafka/src/rdkafka_header.c +220 -0
- package/deps/librdkafka/src/rdkafka_header.h +76 -0
- package/deps/librdkafka/src/rdkafka_idempotence.c +807 -0
- package/deps/librdkafka/src/rdkafka_idempotence.h +144 -0
- package/deps/librdkafka/src/rdkafka_int.h +1260 -0
- package/deps/librdkafka/src/rdkafka_interceptor.c +819 -0
- package/deps/librdkafka/src/rdkafka_interceptor.h +104 -0
- package/deps/librdkafka/src/rdkafka_lz4.c +450 -0
- package/deps/librdkafka/src/rdkafka_lz4.h +49 -0
- package/deps/librdkafka/src/rdkafka_metadata.c +2209 -0
- package/deps/librdkafka/src/rdkafka_metadata.h +345 -0
- package/deps/librdkafka/src/rdkafka_metadata_cache.c +1183 -0
- package/deps/librdkafka/src/rdkafka_mock.c +3661 -0
- package/deps/librdkafka/src/rdkafka_mock.h +610 -0
- package/deps/librdkafka/src/rdkafka_mock_cgrp.c +1876 -0
- package/deps/librdkafka/src/rdkafka_mock_handlers.c +3113 -0
- package/deps/librdkafka/src/rdkafka_mock_int.h +710 -0
- package/deps/librdkafka/src/rdkafka_msg.c +2589 -0
- package/deps/librdkafka/src/rdkafka_msg.h +614 -0
- package/deps/librdkafka/src/rdkafka_msgbatch.h +62 -0
- package/deps/librdkafka/src/rdkafka_msgset.h +98 -0
- package/deps/librdkafka/src/rdkafka_msgset_reader.c +1806 -0
- package/deps/librdkafka/src/rdkafka_msgset_writer.c +1474 -0
- package/deps/librdkafka/src/rdkafka_offset.c +1565 -0
- package/deps/librdkafka/src/rdkafka_offset.h +150 -0
- package/deps/librdkafka/src/rdkafka_op.c +997 -0
- package/deps/librdkafka/src/rdkafka_op.h +858 -0
- package/deps/librdkafka/src/rdkafka_partition.c +4896 -0
- package/deps/librdkafka/src/rdkafka_partition.h +1182 -0
- package/deps/librdkafka/src/rdkafka_pattern.c +228 -0
- package/deps/librdkafka/src/rdkafka_pattern.h +70 -0
- package/deps/librdkafka/src/rdkafka_plugin.c +213 -0
- package/deps/librdkafka/src/rdkafka_plugin.h +41 -0
- package/deps/librdkafka/src/rdkafka_proto.h +736 -0
- package/deps/librdkafka/src/rdkafka_protocol.h +128 -0
- package/deps/librdkafka/src/rdkafka_queue.c +1230 -0
- package/deps/librdkafka/src/rdkafka_queue.h +1220 -0
- package/deps/librdkafka/src/rdkafka_range_assignor.c +1748 -0
- package/deps/librdkafka/src/rdkafka_request.c +7089 -0
- package/deps/librdkafka/src/rdkafka_request.h +732 -0
- package/deps/librdkafka/src/rdkafka_roundrobin_assignor.c +123 -0
- package/deps/librdkafka/src/rdkafka_sasl.c +530 -0
- package/deps/librdkafka/src/rdkafka_sasl.h +63 -0
- package/deps/librdkafka/src/rdkafka_sasl_cyrus.c +722 -0
- package/deps/librdkafka/src/rdkafka_sasl_int.h +89 -0
- package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.c +1833 -0
- package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.h +52 -0
- package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.c +1666 -0
- package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.h +47 -0
- package/deps/librdkafka/src/rdkafka_sasl_plain.c +142 -0
- package/deps/librdkafka/src/rdkafka_sasl_scram.c +858 -0
- package/deps/librdkafka/src/rdkafka_sasl_win32.c +550 -0
- package/deps/librdkafka/src/rdkafka_ssl.c +2129 -0
- package/deps/librdkafka/src/rdkafka_ssl.h +86 -0
- package/deps/librdkafka/src/rdkafka_sticky_assignor.c +4785 -0
- package/deps/librdkafka/src/rdkafka_subscription.c +278 -0
- package/deps/librdkafka/src/rdkafka_telemetry.c +760 -0
- package/deps/librdkafka/src/rdkafka_telemetry.h +52 -0
- package/deps/librdkafka/src/rdkafka_telemetry_decode.c +1053 -0
- package/deps/librdkafka/src/rdkafka_telemetry_decode.h +59 -0
- package/deps/librdkafka/src/rdkafka_telemetry_encode.c +997 -0
- package/deps/librdkafka/src/rdkafka_telemetry_encode.h +301 -0
- package/deps/librdkafka/src/rdkafka_timer.c +402 -0
- package/deps/librdkafka/src/rdkafka_timer.h +117 -0
- package/deps/librdkafka/src/rdkafka_topic.c +2161 -0
- package/deps/librdkafka/src/rdkafka_topic.h +334 -0
- package/deps/librdkafka/src/rdkafka_transport.c +1309 -0
- package/deps/librdkafka/src/rdkafka_transport.h +99 -0
- package/deps/librdkafka/src/rdkafka_transport_int.h +100 -0
- package/deps/librdkafka/src/rdkafka_txnmgr.c +3256 -0
- package/deps/librdkafka/src/rdkafka_txnmgr.h +171 -0
- package/deps/librdkafka/src/rdkafka_zstd.c +226 -0
- package/deps/librdkafka/src/rdkafka_zstd.h +57 -0
- package/deps/librdkafka/src/rdlist.c +576 -0
- package/deps/librdkafka/src/rdlist.h +434 -0
- package/deps/librdkafka/src/rdlog.c +89 -0
- package/deps/librdkafka/src/rdlog.h +41 -0
- package/deps/librdkafka/src/rdmap.c +508 -0
- package/deps/librdkafka/src/rdmap.h +492 -0
- package/deps/librdkafka/src/rdmurmur2.c +167 -0
- package/deps/librdkafka/src/rdmurmur2.h +35 -0
- package/deps/librdkafka/src/rdports.c +61 -0
- package/deps/librdkafka/src/rdports.h +38 -0
- package/deps/librdkafka/src/rdposix.h +250 -0
- package/deps/librdkafka/src/rdrand.c +80 -0
- package/deps/librdkafka/src/rdrand.h +43 -0
- package/deps/librdkafka/src/rdregex.c +156 -0
- package/deps/librdkafka/src/rdregex.h +43 -0
- package/deps/librdkafka/src/rdsignal.h +57 -0
- package/deps/librdkafka/src/rdstring.c +645 -0
- package/deps/librdkafka/src/rdstring.h +98 -0
- package/deps/librdkafka/src/rdsysqueue.h +404 -0
- package/deps/librdkafka/src/rdtime.h +356 -0
- package/deps/librdkafka/src/rdtypes.h +86 -0
- package/deps/librdkafka/src/rdunittest.c +549 -0
- package/deps/librdkafka/src/rdunittest.h +232 -0
- package/deps/librdkafka/src/rdvarint.c +134 -0
- package/deps/librdkafka/src/rdvarint.h +165 -0
- package/deps/librdkafka/src/rdwin32.h +382 -0
- package/deps/librdkafka/src/rdxxhash.c +1030 -0
- package/deps/librdkafka/src/rdxxhash.h +328 -0
- package/deps/librdkafka/src/regexp.c +1352 -0
- package/deps/librdkafka/src/regexp.h +41 -0
- package/deps/librdkafka/src/snappy.c +1866 -0
- package/deps/librdkafka/src/snappy.h +62 -0
- package/deps/librdkafka/src/snappy_compat.h +138 -0
- package/deps/librdkafka/src/statistics_schema.json +444 -0
- package/deps/librdkafka/src/tinycthread.c +932 -0
- package/deps/librdkafka/src/tinycthread.h +503 -0
- package/deps/librdkafka/src/tinycthread_extra.c +199 -0
- package/deps/librdkafka/src/tinycthread_extra.h +212 -0
- package/deps/librdkafka/src/win32_config.h +58 -0
- package/deps/librdkafka/src-cpp/CMakeLists.txt +90 -0
- package/deps/librdkafka/src-cpp/ConfImpl.cpp +84 -0
- package/deps/librdkafka/src-cpp/ConsumerImpl.cpp +244 -0
- package/deps/librdkafka/src-cpp/HandleImpl.cpp +436 -0
- package/deps/librdkafka/src-cpp/HeadersImpl.cpp +48 -0
- package/deps/librdkafka/src-cpp/KafkaConsumerImpl.cpp +296 -0
- package/deps/librdkafka/src-cpp/Makefile +55 -0
- package/deps/librdkafka/src-cpp/MessageImpl.cpp +38 -0
- package/deps/librdkafka/src-cpp/MetadataImpl.cpp +170 -0
- package/deps/librdkafka/src-cpp/ProducerImpl.cpp +197 -0
- package/deps/librdkafka/src-cpp/QueueImpl.cpp +70 -0
- package/deps/librdkafka/src-cpp/README.md +16 -0
- package/deps/librdkafka/src-cpp/RdKafka.cpp +59 -0
- package/deps/librdkafka/src-cpp/TopicImpl.cpp +124 -0
- package/deps/librdkafka/src-cpp/TopicPartitionImpl.cpp +57 -0
- package/deps/librdkafka/src-cpp/rdkafkacpp.h +3797 -0
- package/deps/librdkafka/src-cpp/rdkafkacpp_int.h +1641 -0
- package/deps/librdkafka/tests/0000-unittests.c +72 -0
- package/deps/librdkafka/tests/0001-multiobj.c +102 -0
- package/deps/librdkafka/tests/0002-unkpart.c +244 -0
- package/deps/librdkafka/tests/0003-msgmaxsize.c +173 -0
- package/deps/librdkafka/tests/0004-conf.c +934 -0
- package/deps/librdkafka/tests/0005-order.c +133 -0
- package/deps/librdkafka/tests/0006-symbols.c +163 -0
- package/deps/librdkafka/tests/0007-autotopic.c +136 -0
- package/deps/librdkafka/tests/0008-reqacks.c +179 -0
- package/deps/librdkafka/tests/0009-mock_cluster.c +97 -0
- package/deps/librdkafka/tests/0011-produce_batch.c +753 -0
- package/deps/librdkafka/tests/0012-produce_consume.c +537 -0
- package/deps/librdkafka/tests/0013-null-msgs.c +473 -0
- package/deps/librdkafka/tests/0014-reconsume-191.c +512 -0
- package/deps/librdkafka/tests/0015-offset_seeks.c +172 -0
- package/deps/librdkafka/tests/0016-client_swname.c +181 -0
- package/deps/librdkafka/tests/0017-compression.c +140 -0
- package/deps/librdkafka/tests/0018-cgrp_term.c +338 -0
- package/deps/librdkafka/tests/0019-list_groups.c +289 -0
- package/deps/librdkafka/tests/0020-destroy_hang.c +162 -0
- package/deps/librdkafka/tests/0021-rkt_destroy.c +72 -0
- package/deps/librdkafka/tests/0022-consume_batch.c +279 -0
- package/deps/librdkafka/tests/0025-timers.c +147 -0
- package/deps/librdkafka/tests/0026-consume_pause.c +547 -0
- package/deps/librdkafka/tests/0028-long_topicnames.c +79 -0
- package/deps/librdkafka/tests/0029-assign_offset.c +202 -0
- package/deps/librdkafka/tests/0030-offset_commit.c +589 -0
- package/deps/librdkafka/tests/0031-get_offsets.c +235 -0
- package/deps/librdkafka/tests/0033-regex_subscribe.c +536 -0
- package/deps/librdkafka/tests/0034-offset_reset.c +398 -0
- package/deps/librdkafka/tests/0035-api_version.c +73 -0
- package/deps/librdkafka/tests/0036-partial_fetch.c +87 -0
- package/deps/librdkafka/tests/0037-destroy_hang_local.c +85 -0
- package/deps/librdkafka/tests/0038-performance.c +121 -0
- package/deps/librdkafka/tests/0039-event.c +284 -0
- package/deps/librdkafka/tests/0040-io_event.c +257 -0
- package/deps/librdkafka/tests/0041-fetch_max_bytes.c +97 -0
- package/deps/librdkafka/tests/0042-many_topics.c +252 -0
- package/deps/librdkafka/tests/0043-no_connection.c +77 -0
- package/deps/librdkafka/tests/0044-partition_cnt.c +94 -0
- package/deps/librdkafka/tests/0045-subscribe_update.c +1010 -0
- package/deps/librdkafka/tests/0046-rkt_cache.c +65 -0
- package/deps/librdkafka/tests/0047-partial_buf_tmout.c +98 -0
- package/deps/librdkafka/tests/0048-partitioner.c +283 -0
- package/deps/librdkafka/tests/0049-consume_conn_close.c +162 -0
- package/deps/librdkafka/tests/0050-subscribe_adds.c +145 -0
- package/deps/librdkafka/tests/0051-assign_adds.c +126 -0
- package/deps/librdkafka/tests/0052-msg_timestamps.c +238 -0
- package/deps/librdkafka/tests/0053-stats_cb.cpp +527 -0
- package/deps/librdkafka/tests/0054-offset_time.cpp +236 -0
- package/deps/librdkafka/tests/0055-producer_latency.c +539 -0
- package/deps/librdkafka/tests/0056-balanced_group_mt.c +315 -0
- package/deps/librdkafka/tests/0057-invalid_topic.cpp +112 -0
- package/deps/librdkafka/tests/0058-log.cpp +123 -0
- package/deps/librdkafka/tests/0059-bsearch.cpp +241 -0
- package/deps/librdkafka/tests/0060-op_prio.cpp +163 -0
- package/deps/librdkafka/tests/0061-consumer_lag.cpp +295 -0
- package/deps/librdkafka/tests/0062-stats_event.c +126 -0
- package/deps/librdkafka/tests/0063-clusterid.cpp +180 -0
- package/deps/librdkafka/tests/0064-interceptors.c +481 -0
- package/deps/librdkafka/tests/0065-yield.cpp +140 -0
- package/deps/librdkafka/tests/0066-plugins.cpp +129 -0
- package/deps/librdkafka/tests/0067-empty_topic.cpp +151 -0
- package/deps/librdkafka/tests/0068-produce_timeout.c +136 -0
- package/deps/librdkafka/tests/0069-consumer_add_parts.c +119 -0
- package/deps/librdkafka/tests/0070-null_empty.cpp +197 -0
- package/deps/librdkafka/tests/0072-headers_ut.c +448 -0
- package/deps/librdkafka/tests/0073-headers.c +381 -0
- package/deps/librdkafka/tests/0074-producev.c +87 -0
- package/deps/librdkafka/tests/0075-retry.c +290 -0
- package/deps/librdkafka/tests/0076-produce_retry.c +452 -0
- package/deps/librdkafka/tests/0077-compaction.c +363 -0
- package/deps/librdkafka/tests/0078-c_from_cpp.cpp +96 -0
- package/deps/librdkafka/tests/0079-fork.c +93 -0
- package/deps/librdkafka/tests/0080-admin_ut.c +3095 -0
- package/deps/librdkafka/tests/0081-admin.c +5633 -0
- package/deps/librdkafka/tests/0082-fetch_max_bytes.cpp +137 -0
- package/deps/librdkafka/tests/0083-cb_event.c +233 -0
- package/deps/librdkafka/tests/0084-destroy_flags.c +208 -0
- package/deps/librdkafka/tests/0085-headers.cpp +392 -0
- package/deps/librdkafka/tests/0086-purge.c +368 -0
- package/deps/librdkafka/tests/0088-produce_metadata_timeout.c +162 -0
- package/deps/librdkafka/tests/0089-max_poll_interval.c +511 -0
- package/deps/librdkafka/tests/0090-idempotence.c +171 -0
- package/deps/librdkafka/tests/0091-max_poll_interval_timeout.c +295 -0
- package/deps/librdkafka/tests/0092-mixed_msgver.c +103 -0
- package/deps/librdkafka/tests/0093-holb.c +200 -0
- package/deps/librdkafka/tests/0094-idempotence_msg_timeout.c +231 -0
- package/deps/librdkafka/tests/0095-all_brokers_down.cpp +122 -0
- package/deps/librdkafka/tests/0097-ssl_verify.cpp +658 -0
- package/deps/librdkafka/tests/0098-consumer-txn.cpp +1218 -0
- package/deps/librdkafka/tests/0099-commit_metadata.c +194 -0
- package/deps/librdkafka/tests/0100-thread_interceptors.cpp +195 -0
- package/deps/librdkafka/tests/0101-fetch-from-follower.cpp +446 -0
- package/deps/librdkafka/tests/0102-static_group_rebalance.c +836 -0
- package/deps/librdkafka/tests/0103-transactions.c +1383 -0
- package/deps/librdkafka/tests/0104-fetch_from_follower_mock.c +625 -0
- package/deps/librdkafka/tests/0105-transactions_mock.c +3930 -0
- package/deps/librdkafka/tests/0106-cgrp_sess_timeout.c +318 -0
- package/deps/librdkafka/tests/0107-topic_recreate.c +259 -0
- package/deps/librdkafka/tests/0109-auto_create_topics.cpp +278 -0
- package/deps/librdkafka/tests/0110-batch_size.cpp +182 -0
- package/deps/librdkafka/tests/0111-delay_create_topics.cpp +127 -0
- package/deps/librdkafka/tests/0112-assign_unknown_part.c +87 -0
- package/deps/librdkafka/tests/0113-cooperative_rebalance.cpp +3473 -0
- package/deps/librdkafka/tests/0114-sticky_partitioning.cpp +176 -0
- package/deps/librdkafka/tests/0115-producer_auth.cpp +182 -0
- package/deps/librdkafka/tests/0116-kafkaconsumer_close.cpp +216 -0
- package/deps/librdkafka/tests/0117-mock_errors.c +331 -0
- package/deps/librdkafka/tests/0118-commit_rebalance.c +154 -0
- package/deps/librdkafka/tests/0119-consumer_auth.cpp +167 -0
- package/deps/librdkafka/tests/0120-asymmetric_subscription.c +185 -0
- package/deps/librdkafka/tests/0121-clusterid.c +115 -0
- package/deps/librdkafka/tests/0122-buffer_cleaning_after_rebalance.c +227 -0
- package/deps/librdkafka/tests/0123-connections_max_idle.c +98 -0
- package/deps/librdkafka/tests/0124-openssl_invalid_engine.c +69 -0
- package/deps/librdkafka/tests/0125-immediate_flush.c +144 -0
- package/deps/librdkafka/tests/0126-oauthbearer_oidc.c +528 -0
- package/deps/librdkafka/tests/0127-fetch_queue_backoff.cpp +165 -0
- package/deps/librdkafka/tests/0128-sasl_callback_queue.cpp +125 -0
- package/deps/librdkafka/tests/0129-fetch_aborted_msgs.c +79 -0
- package/deps/librdkafka/tests/0130-store_offsets.c +178 -0
- package/deps/librdkafka/tests/0131-connect_timeout.c +81 -0
- package/deps/librdkafka/tests/0132-strategy_ordering.c +179 -0
- package/deps/librdkafka/tests/0133-ssl_keys.c +150 -0
- package/deps/librdkafka/tests/0134-ssl_provider.c +92 -0
- package/deps/librdkafka/tests/0135-sasl_credentials.cpp +143 -0
- package/deps/librdkafka/tests/0136-resolve_cb.c +181 -0
- package/deps/librdkafka/tests/0137-barrier_batch_consume.c +619 -0
- package/deps/librdkafka/tests/0138-admin_mock.c +281 -0
- package/deps/librdkafka/tests/0139-offset_validation_mock.c +950 -0
- package/deps/librdkafka/tests/0140-commit_metadata.cpp +108 -0
- package/deps/librdkafka/tests/0142-reauthentication.c +515 -0
- package/deps/librdkafka/tests/0143-exponential_backoff_mock.c +552 -0
- package/deps/librdkafka/tests/0144-idempotence_mock.c +373 -0
- package/deps/librdkafka/tests/0145-pause_resume_mock.c +119 -0
- package/deps/librdkafka/tests/0146-metadata_mock.c +505 -0
- package/deps/librdkafka/tests/0147-consumer_group_consumer_mock.c +952 -0
- package/deps/librdkafka/tests/0148-offset_fetch_commit_error_mock.c +563 -0
- package/deps/librdkafka/tests/0149-broker-same-host-port.c +140 -0
- package/deps/librdkafka/tests/0150-telemetry_mock.c +651 -0
- package/deps/librdkafka/tests/0151-purge-brokers.c +566 -0
- package/deps/librdkafka/tests/0152-rebootstrap.c +59 -0
- package/deps/librdkafka/tests/0153-memberid.c +128 -0
- package/deps/librdkafka/tests/1000-unktopic.c +164 -0
- package/deps/librdkafka/tests/8000-idle.cpp +60 -0
- package/deps/librdkafka/tests/8001-fetch_from_follower_mock_manual.c +113 -0
- package/deps/librdkafka/tests/CMakeLists.txt +170 -0
- package/deps/librdkafka/tests/LibrdkafkaTestApp.py +291 -0
- package/deps/librdkafka/tests/Makefile +182 -0
- package/deps/librdkafka/tests/README.md +509 -0
- package/deps/librdkafka/tests/autotest.sh +33 -0
- package/deps/librdkafka/tests/backtrace.gdb +30 -0
- package/deps/librdkafka/tests/broker_version_tests.py +315 -0
- package/deps/librdkafka/tests/buildbox.sh +17 -0
- package/deps/librdkafka/tests/cleanup-checker-tests.sh +20 -0
- package/deps/librdkafka/tests/cluster_testing.py +191 -0
- package/deps/librdkafka/tests/delete-test-topics.sh +56 -0
- package/deps/librdkafka/tests/fixtures/oauthbearer/jwt_assertion_template.json +10 -0
- package/deps/librdkafka/tests/fixtures/ssl/Makefile +8 -0
- package/deps/librdkafka/tests/fixtures/ssl/README.md +13 -0
- package/deps/librdkafka/tests/fixtures/ssl/client.keystore.intermediate.p12 +0 -0
- package/deps/librdkafka/tests/fixtures/ssl/client.keystore.p12 +0 -0
- package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.intermediate.pem +72 -0
- package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.pem +50 -0
- package/deps/librdkafka/tests/fixtures/ssl/client2.intermediate.key +46 -0
- package/deps/librdkafka/tests/fixtures/ssl/client2.key +46 -0
- package/deps/librdkafka/tests/fixtures/ssl/create_keys.sh +168 -0
- package/deps/librdkafka/tests/fuzzers/Makefile +12 -0
- package/deps/librdkafka/tests/fuzzers/README.md +31 -0
- package/deps/librdkafka/tests/fuzzers/fuzz_regex.c +74 -0
- package/deps/librdkafka/tests/fuzzers/helpers.h +90 -0
- package/deps/librdkafka/tests/gen-ssl-certs.sh +165 -0
- package/deps/librdkafka/tests/interactive_broker_version.py +170 -0
- package/deps/librdkafka/tests/interceptor_test/CMakeLists.txt +16 -0
- package/deps/librdkafka/tests/interceptor_test/Makefile +22 -0
- package/deps/librdkafka/tests/interceptor_test/interceptor_test.c +314 -0
- package/deps/librdkafka/tests/interceptor_test/interceptor_test.h +54 -0
- package/deps/librdkafka/tests/java/IncrementalRebalanceCli.java +97 -0
- package/deps/librdkafka/tests/java/Makefile +13 -0
- package/deps/librdkafka/tests/java/Murmur2Cli.java +46 -0
- package/deps/librdkafka/tests/java/README.md +14 -0
- package/deps/librdkafka/tests/java/TransactionProducerCli.java +162 -0
- package/deps/librdkafka/tests/java/run-class.sh +11 -0
- package/deps/librdkafka/tests/librdkafka.suppressions +483 -0
- package/deps/librdkafka/tests/lz4_manual_test.sh +59 -0
- package/deps/librdkafka/tests/multi-broker-version-test.sh +50 -0
- package/deps/librdkafka/tests/parse-refcnt.sh +43 -0
- package/deps/librdkafka/tests/performance_plot.py +115 -0
- package/deps/librdkafka/tests/plugin_test/Makefile +19 -0
- package/deps/librdkafka/tests/plugin_test/plugin_test.c +58 -0
- package/deps/librdkafka/tests/requirements.txt +2 -0
- package/deps/librdkafka/tests/run-all-tests.sh +79 -0
- package/deps/librdkafka/tests/run-consumer-tests.sh +16 -0
- package/deps/librdkafka/tests/run-producer-tests.sh +16 -0
- package/deps/librdkafka/tests/run-test-batches.py +157 -0
- package/deps/librdkafka/tests/run-test.sh +140 -0
- package/deps/librdkafka/tests/rusage.c +249 -0
- package/deps/librdkafka/tests/sasl_test.py +289 -0
- package/deps/librdkafka/tests/scenarios/README.md +6 -0
- package/deps/librdkafka/tests/scenarios/ak23.json +6 -0
- package/deps/librdkafka/tests/scenarios/default.json +5 -0
- package/deps/librdkafka/tests/scenarios/noautocreate.json +5 -0
- package/deps/librdkafka/tests/sockem.c +801 -0
- package/deps/librdkafka/tests/sockem.h +85 -0
- package/deps/librdkafka/tests/sockem_ctrl.c +145 -0
- package/deps/librdkafka/tests/sockem_ctrl.h +61 -0
- package/deps/librdkafka/tests/test.c +7778 -0
- package/deps/librdkafka/tests/test.conf.example +27 -0
- package/deps/librdkafka/tests/test.h +1028 -0
- package/deps/librdkafka/tests/testcpp.cpp +131 -0
- package/deps/librdkafka/tests/testcpp.h +388 -0
- package/deps/librdkafka/tests/testshared.h +416 -0
- package/deps/librdkafka/tests/tools/README.md +4 -0
- package/deps/librdkafka/tests/tools/stats/README.md +21 -0
- package/deps/librdkafka/tests/tools/stats/filter.jq +42 -0
- package/deps/librdkafka/tests/tools/stats/graph.py +150 -0
- package/deps/librdkafka/tests/tools/stats/requirements.txt +3 -0
- package/deps/librdkafka/tests/tools/stats/to_csv.py +124 -0
- package/deps/librdkafka/tests/trivup/trivup-0.14.0.tar.gz +0 -0
- package/deps/librdkafka/tests/until-fail.sh +87 -0
- package/deps/librdkafka/tests/xxxx-assign_partition.c +122 -0
- package/deps/librdkafka/tests/xxxx-metadata.cpp +159 -0
- package/deps/librdkafka/vcpkg.json +23 -0
- package/deps/librdkafka/win32/README.md +5 -0
- package/deps/librdkafka/win32/build-package.bat +3 -0
- package/deps/librdkafka/win32/build.bat +19 -0
- package/deps/librdkafka/win32/common.vcxproj +84 -0
- package/deps/librdkafka/win32/interceptor_test/interceptor_test.vcxproj +87 -0
- package/deps/librdkafka/win32/librdkafka.autopkg.template +54 -0
- package/deps/librdkafka/win32/librdkafka.master.testing.targets +13 -0
- package/deps/librdkafka/win32/librdkafka.sln +226 -0
- package/deps/librdkafka/win32/librdkafka.vcxproj +276 -0
- package/deps/librdkafka/win32/librdkafkacpp/librdkafkacpp.vcxproj +104 -0
- package/deps/librdkafka/win32/msbuild.ps1 +15 -0
- package/deps/librdkafka/win32/openssl_engine_example/openssl_engine_example.vcxproj +132 -0
- package/deps/librdkafka/win32/package-zip.ps1 +46 -0
- package/deps/librdkafka/win32/packages/repositories.config +4 -0
- package/deps/librdkafka/win32/push-package.bat +4 -0
- package/deps/librdkafka/win32/rdkafka_complex_consumer_example_cpp/rdkafka_complex_consumer_example_cpp.vcxproj +67 -0
- package/deps/librdkafka/win32/rdkafka_example/rdkafka_example.vcxproj +97 -0
- package/deps/librdkafka/win32/rdkafka_performance/rdkafka_performance.vcxproj +97 -0
- package/deps/librdkafka/win32/setup-msys2.ps1 +47 -0
- package/deps/librdkafka/win32/setup-vcpkg.ps1 +34 -0
- package/deps/librdkafka/win32/tests/test.conf.example +25 -0
- package/deps/librdkafka/win32/tests/tests.vcxproj +253 -0
- package/deps/librdkafka/win32/win_ssl_cert_store/win_ssl_cert_store.vcxproj +132 -0
- package/deps/librdkafka/win32/wingetopt.c +564 -0
- package/deps/librdkafka/win32/wingetopt.h +101 -0
- package/deps/librdkafka/win32/wintime.h +33 -0
- package/deps/librdkafka.gyp +62 -0
- package/lib/admin.js +233 -0
- package/lib/client.js +573 -0
- package/lib/error.js +500 -0
- package/lib/index.js +34 -0
- package/lib/kafka-consumer-stream.js +397 -0
- package/lib/kafka-consumer.js +698 -0
- package/lib/producer/high-level-producer.js +323 -0
- package/lib/producer-stream.js +307 -0
- package/lib/producer.js +375 -0
- package/lib/tools/ref-counter.js +52 -0
- package/lib/topic-partition.js +88 -0
- package/lib/topic.js +42 -0
- package/lib/util.js +29 -0
- package/package.json +61 -0
- package/prebuilds/darwin-arm64/@point3+node-rdkafka.node +0 -0
- package/prebuilds/linux-x64/@point3+node-rdkafka.node +0 -0
- package/util/configure.js +30 -0
- package/util/get-env.js +6 -0
- package/util/test-compile.js +11 -0
- package/util/test-producer-delivery.js +100 -0
|
@@ -0,0 +1,2129 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* librdkafka - The Apache Kafka C/C++ library
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2019-2022, Magnus Edenhill
|
|
5
|
+
* 2023, Confluent Inc.
|
|
6
|
+
* All rights reserved.
|
|
7
|
+
*
|
|
8
|
+
* Redistribution and use in source and binary forms, with or without
|
|
9
|
+
* modification, are permitted provided that the following conditions are met:
|
|
10
|
+
*
|
|
11
|
+
* 1. Redistributions of source code must retain the above copyright notice,
|
|
12
|
+
* this list of conditions and the following disclaimer.
|
|
13
|
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
14
|
+
* this list of conditions and the following disclaimer in the documentation
|
|
15
|
+
* and/or other materials provided with the distribution.
|
|
16
|
+
*
|
|
17
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
18
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
19
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
20
|
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
21
|
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
22
|
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
23
|
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
24
|
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
25
|
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
26
|
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
27
|
+
* POSSIBILITY OF SUCH DAMAGE.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @name OpenSSL integration
|
|
33
|
+
*
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
#include "rdkafka_int.h"
|
|
37
|
+
#include "rdkafka_transport_int.h"
|
|
38
|
+
#include "rdkafka_cert.h"
|
|
39
|
+
|
|
40
|
+
#ifdef _WIN32
|
|
41
|
+
#include <wincrypt.h>
|
|
42
|
+
#pragma comment(lib, "crypt32.lib")
|
|
43
|
+
#pragma comment(lib, "libcrypto.lib")
|
|
44
|
+
#pragma comment(lib, "libssl.lib")
|
|
45
|
+
#endif
|
|
46
|
+
|
|
47
|
+
#include <openssl/x509.h>
|
|
48
|
+
#include <openssl/x509_vfy.h>
|
|
49
|
+
|
|
50
|
+
#if OPENSSL_VERSION_NUMBER >= 0x30000000
|
|
51
|
+
#include <openssl/provider.h>
|
|
52
|
+
#endif
|
|
53
|
+
|
|
54
|
+
#include <ctype.h>
|
|
55
|
+
|
|
56
|
+
#if !_WIN32
|
|
57
|
+
#include <sys/types.h>
|
|
58
|
+
#include <sys/stat.h>
|
|
59
|
+
#include <unistd.h>
|
|
60
|
+
#endif
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
#if WITH_VALGRIND
|
|
64
|
+
/* OpenSSL relies on uninitialized memory, which Valgrind will whine about.
|
|
65
|
+
* We use in-code Valgrind macros to suppress those warnings. */
|
|
66
|
+
#include <valgrind/memcheck.h>
|
|
67
|
+
#else
|
|
68
|
+
#define VALGRIND_MAKE_MEM_DEFINED(A, B)
|
|
69
|
+
#endif
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
73
|
+
static mtx_t *rd_kafka_ssl_locks;
|
|
74
|
+
static int rd_kafka_ssl_locks_cnt;
|
|
75
|
+
#endif
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @brief Close and destroy SSL session
|
|
80
|
+
*/
|
|
81
|
+
void rd_kafka_transport_ssl_close(rd_kafka_transport_t *rktrans) {
|
|
82
|
+
SSL_shutdown(rktrans->rktrans_ssl);
|
|
83
|
+
SSL_free(rktrans->rktrans_ssl);
|
|
84
|
+
rktrans->rktrans_ssl = NULL;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @brief Clear OpenSSL error queue to get a proper error reporting in case
|
|
90
|
+
* the next SSL_*() operation fails.
|
|
91
|
+
*/
|
|
92
|
+
static RD_INLINE void
|
|
93
|
+
rd_kafka_transport_ssl_clear_error(rd_kafka_transport_t *rktrans) {
|
|
94
|
+
ERR_clear_error();
|
|
95
|
+
#ifdef _WIN32
|
|
96
|
+
WSASetLastError(0);
|
|
97
|
+
#else
|
|
98
|
+
rd_set_errno(0);
|
|
99
|
+
#endif
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @returns a thread-local single-invocation-use error string for
|
|
104
|
+
* the last thread-local error in OpenSSL, or an empty string
|
|
105
|
+
* if no error.
|
|
106
|
+
*/
|
|
107
|
+
const char *rd_kafka_ssl_last_error_str(void) {
|
|
108
|
+
static RD_TLS char errstr[256];
|
|
109
|
+
unsigned long l;
|
|
110
|
+
const char *file, *data, *func;
|
|
111
|
+
int line, flags;
|
|
112
|
+
|
|
113
|
+
#if OPENSSL_VERSION_NUMBER >= 0x30000000
|
|
114
|
+
l = ERR_peek_last_error_all(&file, &line, &func, &data, &flags);
|
|
115
|
+
#else
|
|
116
|
+
l = ERR_peek_last_error_line_data(&file, &line, &data, &flags);
|
|
117
|
+
func = ERR_func_error_string(l);
|
|
118
|
+
#endif
|
|
119
|
+
|
|
120
|
+
if (!l)
|
|
121
|
+
return "";
|
|
122
|
+
|
|
123
|
+
rd_snprintf(errstr, sizeof(errstr), "%lu:%s:%s:%s:%d: %s", l,
|
|
124
|
+
ERR_lib_error_string(l), func, file, line,
|
|
125
|
+
((flags & ERR_TXT_STRING) && data && *data)
|
|
126
|
+
? data
|
|
127
|
+
: ERR_reason_error_string(l));
|
|
128
|
+
|
|
129
|
+
return errstr;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Serves the entire OpenSSL error queue and logs each error.
|
|
134
|
+
* The last error is not logged but returned in 'errstr'.
|
|
135
|
+
*
|
|
136
|
+
* If 'rkb' is non-NULL broker-specific logging will be used,
|
|
137
|
+
* else it will fall back on global 'rk' debugging.
|
|
138
|
+
*
|
|
139
|
+
* `ctx_identifier` is a string used to customize the log message.
|
|
140
|
+
*/
|
|
141
|
+
char *rd_kafka_ssl_error0(rd_kafka_t *rk,
|
|
142
|
+
rd_kafka_broker_t *rkb,
|
|
143
|
+
const char *ctx_identifier,
|
|
144
|
+
char *errstr,
|
|
145
|
+
size_t errstr_size) {
|
|
146
|
+
unsigned long l;
|
|
147
|
+
const char *file, *data, *func;
|
|
148
|
+
int line, flags;
|
|
149
|
+
int cnt = 0;
|
|
150
|
+
|
|
151
|
+
if (!rk) {
|
|
152
|
+
rd_assert(rkb);
|
|
153
|
+
rk = rkb->rkb_rk;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
while (
|
|
157
|
+
#if OPENSSL_VERSION_NUMBER >= 0x30000000
|
|
158
|
+
(l = ERR_get_error_all(&file, &line, &func, &data, &flags))
|
|
159
|
+
#else
|
|
160
|
+
(l = ERR_get_error_line_data(&file, &line, &data, &flags))
|
|
161
|
+
#endif
|
|
162
|
+
) {
|
|
163
|
+
char buf[256];
|
|
164
|
+
|
|
165
|
+
#if OPENSSL_VERSION_NUMBER < 0x30000000
|
|
166
|
+
func = ERR_func_error_string(l);
|
|
167
|
+
#endif
|
|
168
|
+
|
|
169
|
+
if (cnt++ > 0) {
|
|
170
|
+
/* Log last message */
|
|
171
|
+
if (rkb)
|
|
172
|
+
rd_rkb_log(rkb, LOG_ERR, "SSL", "%s: %s",
|
|
173
|
+
ctx_identifier, errstr);
|
|
174
|
+
else
|
|
175
|
+
rd_kafka_log(rk, LOG_ERR, "SSL", "%s: %s",
|
|
176
|
+
ctx_identifier, errstr);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
ERR_error_string_n(l, buf, sizeof(buf));
|
|
180
|
+
|
|
181
|
+
if (!(flags & ERR_TXT_STRING) || !data || !*data)
|
|
182
|
+
data = NULL;
|
|
183
|
+
|
|
184
|
+
/* Include openssl file:line:func if debugging is enabled */
|
|
185
|
+
if (rk->rk_conf.log_level >= LOG_DEBUG)
|
|
186
|
+
rd_snprintf(errstr, errstr_size, "%s:%d:%s %s%s%s",
|
|
187
|
+
file, line, func, buf, data ? ": " : "",
|
|
188
|
+
data ? data : "");
|
|
189
|
+
else
|
|
190
|
+
rd_snprintf(errstr, errstr_size, "%s%s%s", buf,
|
|
191
|
+
data ? ": " : "", data ? data : "");
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (cnt == 0)
|
|
195
|
+
rd_snprintf(errstr, errstr_size,
|
|
196
|
+
"%s: No further error information available",
|
|
197
|
+
ctx_identifier);
|
|
198
|
+
|
|
199
|
+
return errstr;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
static char *rd_kafka_ssl_error(rd_kafka_t *rk,
|
|
203
|
+
rd_kafka_broker_t *rkb,
|
|
204
|
+
char *errstr,
|
|
205
|
+
size_t errstr_size) {
|
|
206
|
+
return rd_kafka_ssl_error0(rk, rkb, "kafka", errstr, errstr_size);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Set transport IO event polling based on SSL error.
|
|
211
|
+
*
|
|
212
|
+
* Returns -1 on permanent errors.
|
|
213
|
+
*
|
|
214
|
+
* Locality: broker thread
|
|
215
|
+
*/
|
|
216
|
+
static RD_INLINE int
|
|
217
|
+
rd_kafka_transport_ssl_io_update(rd_kafka_transport_t *rktrans,
|
|
218
|
+
int ret,
|
|
219
|
+
char *errstr,
|
|
220
|
+
size_t errstr_size) {
|
|
221
|
+
int serr = SSL_get_error(rktrans->rktrans_ssl, ret);
|
|
222
|
+
int serr2;
|
|
223
|
+
|
|
224
|
+
switch (serr) {
|
|
225
|
+
case SSL_ERROR_WANT_READ:
|
|
226
|
+
rd_kafka_transport_poll_set(rktrans, POLLIN);
|
|
227
|
+
break;
|
|
228
|
+
|
|
229
|
+
case SSL_ERROR_WANT_WRITE:
|
|
230
|
+
rd_kafka_transport_set_blocked(rktrans, rd_true);
|
|
231
|
+
rd_kafka_transport_poll_set(rktrans, POLLOUT);
|
|
232
|
+
break;
|
|
233
|
+
|
|
234
|
+
case SSL_ERROR_SYSCALL:
|
|
235
|
+
serr2 = ERR_peek_error();
|
|
236
|
+
if (serr2)
|
|
237
|
+
rd_kafka_ssl_error(NULL, rktrans->rktrans_rkb, errstr,
|
|
238
|
+
errstr_size);
|
|
239
|
+
else if (!rd_socket_errno) {
|
|
240
|
+
rd_snprintf(errstr, errstr_size,
|
|
241
|
+
"Disconnected: connection closed by "
|
|
242
|
+
"peer");
|
|
243
|
+
} else if (rd_socket_errno == ECONNRESET) {
|
|
244
|
+
rd_snprintf(errstr, errstr_size,
|
|
245
|
+
"Disconnected: connection reset by peer");
|
|
246
|
+
} else
|
|
247
|
+
rd_snprintf(errstr, errstr_size,
|
|
248
|
+
"SSL transport error: %s",
|
|
249
|
+
rd_strerror(rd_socket_errno));
|
|
250
|
+
return -1;
|
|
251
|
+
|
|
252
|
+
case SSL_ERROR_ZERO_RETURN:
|
|
253
|
+
rd_snprintf(errstr, errstr_size,
|
|
254
|
+
"Disconnected: SSL connection closed by peer");
|
|
255
|
+
return -1;
|
|
256
|
+
|
|
257
|
+
default:
|
|
258
|
+
rd_kafka_ssl_error(NULL, rktrans->rktrans_rkb, errstr,
|
|
259
|
+
errstr_size);
|
|
260
|
+
return -1;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return 0;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
ssize_t rd_kafka_transport_ssl_send(rd_kafka_transport_t *rktrans,
|
|
267
|
+
rd_slice_t *slice,
|
|
268
|
+
char *errstr,
|
|
269
|
+
size_t errstr_size) {
|
|
270
|
+
ssize_t sum = 0;
|
|
271
|
+
const void *p;
|
|
272
|
+
size_t rlen;
|
|
273
|
+
|
|
274
|
+
rd_kafka_transport_ssl_clear_error(rktrans);
|
|
275
|
+
|
|
276
|
+
while ((rlen = rd_slice_peeker(slice, &p))) {
|
|
277
|
+
int r;
|
|
278
|
+
size_t r2;
|
|
279
|
+
|
|
280
|
+
r = SSL_write(rktrans->rktrans_ssl, p, (int)rlen);
|
|
281
|
+
|
|
282
|
+
if (unlikely(r <= 0)) {
|
|
283
|
+
if (rd_kafka_transport_ssl_io_update(rktrans, r, errstr,
|
|
284
|
+
errstr_size) == -1)
|
|
285
|
+
return -1;
|
|
286
|
+
else
|
|
287
|
+
return sum;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/* Update buffer read position */
|
|
291
|
+
r2 = rd_slice_read(slice, NULL, (size_t)r);
|
|
292
|
+
rd_assert((size_t)r == r2 &&
|
|
293
|
+
*"BUG: wrote more bytes than available in slice");
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
sum += r;
|
|
297
|
+
/* FIXME: remove this and try again immediately and let
|
|
298
|
+
* the next SSL_write() call fail instead? */
|
|
299
|
+
if ((size_t)r < rlen)
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
return sum;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
ssize_t rd_kafka_transport_ssl_recv(rd_kafka_transport_t *rktrans,
|
|
306
|
+
rd_buf_t *rbuf,
|
|
307
|
+
char *errstr,
|
|
308
|
+
size_t errstr_size) {
|
|
309
|
+
ssize_t sum = 0;
|
|
310
|
+
void *p;
|
|
311
|
+
size_t len;
|
|
312
|
+
|
|
313
|
+
while ((len = rd_buf_get_writable(rbuf, &p))) {
|
|
314
|
+
int r;
|
|
315
|
+
|
|
316
|
+
rd_kafka_transport_ssl_clear_error(rktrans);
|
|
317
|
+
|
|
318
|
+
r = SSL_read(rktrans->rktrans_ssl, p, (int)len);
|
|
319
|
+
|
|
320
|
+
if (unlikely(r <= 0)) {
|
|
321
|
+
if (rd_kafka_transport_ssl_io_update(rktrans, r, errstr,
|
|
322
|
+
errstr_size) == -1)
|
|
323
|
+
return -1;
|
|
324
|
+
else
|
|
325
|
+
return sum;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
VALGRIND_MAKE_MEM_DEFINED(p, r);
|
|
329
|
+
|
|
330
|
+
/* Update buffer write position */
|
|
331
|
+
rd_buf_write(rbuf, NULL, (size_t)r);
|
|
332
|
+
|
|
333
|
+
sum += r;
|
|
334
|
+
|
|
335
|
+
/* FIXME: remove this and try again immediately and let
|
|
336
|
+
* the next SSL_read() call fail instead? */
|
|
337
|
+
if ((size_t)r < len)
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
return sum;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* OpenSSL password query callback
|
|
346
|
+
*
|
|
347
|
+
* Locality: application thread
|
|
348
|
+
*/
|
|
349
|
+
static int rd_kafka_transport_ssl_passwd_cb(char *buf,
|
|
350
|
+
int size,
|
|
351
|
+
int rwflag,
|
|
352
|
+
void *userdata) {
|
|
353
|
+
rd_kafka_t *rk = userdata;
|
|
354
|
+
int pwlen;
|
|
355
|
+
|
|
356
|
+
rd_kafka_dbg(rk, SECURITY, "SSLPASSWD",
|
|
357
|
+
"Private key requires password");
|
|
358
|
+
|
|
359
|
+
if (!rk->rk_conf.ssl.key_password) {
|
|
360
|
+
rd_kafka_log(rk, LOG_WARNING, "SSLPASSWD",
|
|
361
|
+
"Private key requires password but "
|
|
362
|
+
"no password configured (ssl.key.password)");
|
|
363
|
+
return -1;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
pwlen = (int)strlen(rk->rk_conf.ssl.key_password);
|
|
368
|
+
memcpy(buf, rk->rk_conf.ssl.key_password, RD_MIN(pwlen, size));
|
|
369
|
+
|
|
370
|
+
return pwlen;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* @brief OpenSSL callback to perform additional broker certificate
|
|
376
|
+
* verification and validation.
|
|
377
|
+
*
|
|
378
|
+
* @return 1 on success when the broker certificate
|
|
379
|
+
* is valid and 0 when the certificate is not valid.
|
|
380
|
+
*
|
|
381
|
+
* @sa SSL_CTX_set_verify()
|
|
382
|
+
*/
|
|
383
|
+
static int rd_kafka_transport_ssl_cert_verify_cb(int preverify_ok,
|
|
384
|
+
X509_STORE_CTX *x509_ctx) {
|
|
385
|
+
rd_kafka_transport_t *rktrans = rd_kafka_curr_transport;
|
|
386
|
+
rd_kafka_broker_t *rkb;
|
|
387
|
+
rd_kafka_t *rk;
|
|
388
|
+
X509 *cert;
|
|
389
|
+
char *buf = NULL;
|
|
390
|
+
int buf_size;
|
|
391
|
+
int depth;
|
|
392
|
+
int x509_orig_error, x509_error;
|
|
393
|
+
char errstr[512];
|
|
394
|
+
int ok;
|
|
395
|
+
|
|
396
|
+
rd_assert(rktrans != NULL);
|
|
397
|
+
rkb = rktrans->rktrans_rkb;
|
|
398
|
+
rk = rkb->rkb_rk;
|
|
399
|
+
|
|
400
|
+
cert = X509_STORE_CTX_get_current_cert(x509_ctx);
|
|
401
|
+
if (!cert) {
|
|
402
|
+
rd_rkb_log(rkb, LOG_ERR, "SSLCERTVRFY",
|
|
403
|
+
"Failed to get current certificate to verify");
|
|
404
|
+
return 0;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
depth = X509_STORE_CTX_get_error_depth(x509_ctx);
|
|
408
|
+
|
|
409
|
+
x509_orig_error = x509_error = X509_STORE_CTX_get_error(x509_ctx);
|
|
410
|
+
|
|
411
|
+
buf_size = i2d_X509(cert, (unsigned char **)&buf);
|
|
412
|
+
if (buf_size < 0 || !buf) {
|
|
413
|
+
rd_rkb_log(rkb, LOG_ERR, "SSLCERTVRFY",
|
|
414
|
+
"Unable to convert certificate to X509 format");
|
|
415
|
+
return 0;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
*errstr = '\0';
|
|
419
|
+
|
|
420
|
+
/* Call application's verification callback. */
|
|
421
|
+
ok = rk->rk_conf.ssl.cert_verify_cb(
|
|
422
|
+
rk, rkb->rkb_nodename, rkb->rkb_nodeid, &x509_error, depth, buf,
|
|
423
|
+
(size_t)buf_size, errstr, sizeof(errstr), rk->rk_conf.opaque);
|
|
424
|
+
|
|
425
|
+
OPENSSL_free(buf);
|
|
426
|
+
|
|
427
|
+
if (!ok) {
|
|
428
|
+
char subject[128];
|
|
429
|
+
char issuer[128];
|
|
430
|
+
|
|
431
|
+
X509_NAME_oneline(X509_get_subject_name(cert), subject,
|
|
432
|
+
sizeof(subject));
|
|
433
|
+
X509_NAME_oneline(X509_get_issuer_name(cert), issuer,
|
|
434
|
+
sizeof(issuer));
|
|
435
|
+
rd_rkb_log(rkb, LOG_ERR, "SSLCERTVRFY",
|
|
436
|
+
"Certificate (subject=%s, issuer=%s) verification "
|
|
437
|
+
"callback failed: %s",
|
|
438
|
+
subject, issuer, errstr);
|
|
439
|
+
|
|
440
|
+
X509_STORE_CTX_set_error(x509_ctx, x509_error);
|
|
441
|
+
|
|
442
|
+
return 0; /* verification failed */
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/* Clear error */
|
|
446
|
+
if (x509_orig_error != 0 && x509_error == 0)
|
|
447
|
+
X509_STORE_CTX_set_error(x509_ctx, 0);
|
|
448
|
+
|
|
449
|
+
return 1; /* verification successful */
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* @brief Set TLSEXT hostname for SNI and optionally enable
|
|
454
|
+
* SSL endpoint identification verification.
|
|
455
|
+
*
|
|
456
|
+
* @returns 0 on success or -1 on error.
|
|
457
|
+
*/
|
|
458
|
+
static int rd_kafka_transport_ssl_set_endpoint_id(rd_kafka_transport_t *rktrans,
|
|
459
|
+
char *errstr,
|
|
460
|
+
size_t errstr_size) {
|
|
461
|
+
char name[RD_KAFKA_NODENAME_SIZE];
|
|
462
|
+
char *t;
|
|
463
|
+
|
|
464
|
+
rd_kafka_broker_lock(rktrans->rktrans_rkb);
|
|
465
|
+
rd_snprintf(name, sizeof(name), "%s",
|
|
466
|
+
rktrans->rktrans_rkb->rkb_nodename);
|
|
467
|
+
rd_kafka_broker_unlock(rktrans->rktrans_rkb);
|
|
468
|
+
|
|
469
|
+
/* Remove ":9092" port suffix from nodename */
|
|
470
|
+
if ((t = strrchr(name, ':')))
|
|
471
|
+
*t = '\0';
|
|
472
|
+
|
|
473
|
+
#if (OPENSSL_VERSION_NUMBER >= 0x0090806fL) && !defined(OPENSSL_NO_TLSEXT)
|
|
474
|
+
/* If non-numerical hostname, send it for SNI */
|
|
475
|
+
if (!(/*ipv6*/ (strchr(name, ':') &&
|
|
476
|
+
strspn(name, "0123456789abcdefABCDEF:.[]%") ==
|
|
477
|
+
strlen(name)) ||
|
|
478
|
+
/*ipv4*/ strspn(name, "0123456789.") == strlen(name)) &&
|
|
479
|
+
!SSL_set_tlsext_host_name(rktrans->rktrans_ssl, name))
|
|
480
|
+
goto fail;
|
|
481
|
+
#endif
|
|
482
|
+
|
|
483
|
+
if (rktrans->rktrans_rkb->rkb_rk->rk_conf.ssl.endpoint_identification ==
|
|
484
|
+
RD_KAFKA_SSL_ENDPOINT_ID_NONE)
|
|
485
|
+
return 0;
|
|
486
|
+
|
|
487
|
+
#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(OPENSSL_IS_BORINGSSL)
|
|
488
|
+
if (!SSL_set1_host(rktrans->rktrans_ssl, name))
|
|
489
|
+
goto fail;
|
|
490
|
+
#elif OPENSSL_VERSION_NUMBER >= 0x1000200fL /* 1.0.2 */
|
|
491
|
+
{
|
|
492
|
+
X509_VERIFY_PARAM *param;
|
|
493
|
+
|
|
494
|
+
param = SSL_get0_param(rktrans->rktrans_ssl);
|
|
495
|
+
|
|
496
|
+
if (!X509_VERIFY_PARAM_set1_host(param, name,
|
|
497
|
+
strnlen(name, sizeof(name))))
|
|
498
|
+
goto fail;
|
|
499
|
+
}
|
|
500
|
+
#else
|
|
501
|
+
rd_snprintf(errstr, errstr_size,
|
|
502
|
+
"Endpoint identification not supported on this "
|
|
503
|
+
"OpenSSL version (0x%lx)",
|
|
504
|
+
OPENSSL_VERSION_NUMBER);
|
|
505
|
+
return -1;
|
|
506
|
+
#endif
|
|
507
|
+
|
|
508
|
+
rd_rkb_dbg(rktrans->rktrans_rkb, SECURITY, "ENDPOINT",
|
|
509
|
+
"Enabled endpoint identification using hostname %s", name);
|
|
510
|
+
|
|
511
|
+
return 0;
|
|
512
|
+
|
|
513
|
+
fail:
|
|
514
|
+
rd_kafka_ssl_error(NULL, rktrans->rktrans_rkb, errstr, errstr_size);
|
|
515
|
+
return -1;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* @brief Set up SSL for a newly connected connection
|
|
521
|
+
*
|
|
522
|
+
* @returns -1 on failure, else 0.
|
|
523
|
+
*/
|
|
524
|
+
int rd_kafka_transport_ssl_connect(rd_kafka_broker_t *rkb,
|
|
525
|
+
rd_kafka_transport_t *rktrans,
|
|
526
|
+
char *errstr,
|
|
527
|
+
size_t errstr_size) {
|
|
528
|
+
int r;
|
|
529
|
+
|
|
530
|
+
rktrans->rktrans_ssl = SSL_new(rkb->rkb_rk->rk_conf.ssl.ctx);
|
|
531
|
+
if (!rktrans->rktrans_ssl)
|
|
532
|
+
goto fail;
|
|
533
|
+
|
|
534
|
+
if (!SSL_set_fd(rktrans->rktrans_ssl, (int)rktrans->rktrans_s))
|
|
535
|
+
goto fail;
|
|
536
|
+
|
|
537
|
+
if (rd_kafka_transport_ssl_set_endpoint_id(rktrans, errstr,
|
|
538
|
+
errstr_size) == -1)
|
|
539
|
+
return -1;
|
|
540
|
+
|
|
541
|
+
rd_kafka_transport_ssl_clear_error(rktrans);
|
|
542
|
+
|
|
543
|
+
r = SSL_connect(rktrans->rktrans_ssl);
|
|
544
|
+
if (r == 1) {
|
|
545
|
+
/* Connected, highly unlikely since this is a
|
|
546
|
+
* non-blocking operation. */
|
|
547
|
+
rd_kafka_transport_connect_done(rktrans, NULL);
|
|
548
|
+
return 0;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (rd_kafka_transport_ssl_io_update(rktrans, r, errstr, errstr_size) ==
|
|
552
|
+
-1)
|
|
553
|
+
return -1;
|
|
554
|
+
|
|
555
|
+
return 0;
|
|
556
|
+
|
|
557
|
+
fail:
|
|
558
|
+
rd_kafka_ssl_error(NULL, rkb, errstr, errstr_size);
|
|
559
|
+
return -1;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
static RD_UNUSED int
|
|
564
|
+
rd_kafka_transport_ssl_io_event(rd_kafka_transport_t *rktrans, int events) {
|
|
565
|
+
int r;
|
|
566
|
+
char errstr[512];
|
|
567
|
+
|
|
568
|
+
if (events & POLLOUT) {
|
|
569
|
+
rd_kafka_transport_ssl_clear_error(rktrans);
|
|
570
|
+
|
|
571
|
+
r = SSL_write(rktrans->rktrans_ssl, NULL, 0);
|
|
572
|
+
if (rd_kafka_transport_ssl_io_update(rktrans, r, errstr,
|
|
573
|
+
sizeof(errstr)) == -1)
|
|
574
|
+
goto fail;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
return 0;
|
|
578
|
+
|
|
579
|
+
fail:
|
|
580
|
+
/* Permanent error */
|
|
581
|
+
rd_kafka_broker_fail(rktrans->rktrans_rkb, LOG_ERR,
|
|
582
|
+
RD_KAFKA_RESP_ERR__TRANSPORT, "%s", errstr);
|
|
583
|
+
return -1;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* @brief Verify SSL handshake was valid.
|
|
589
|
+
*/
|
|
590
|
+
static int rd_kafka_transport_ssl_verify(rd_kafka_transport_t *rktrans) {
|
|
591
|
+
long int rl;
|
|
592
|
+
X509 *cert;
|
|
593
|
+
|
|
594
|
+
if (!rktrans->rktrans_rkb->rkb_rk->rk_conf.ssl.enable_verify)
|
|
595
|
+
return 0;
|
|
596
|
+
|
|
597
|
+
#if OPENSSL_VERSION_NUMBER >= 0x30000000
|
|
598
|
+
cert = SSL_get1_peer_certificate(rktrans->rktrans_ssl);
|
|
599
|
+
#else
|
|
600
|
+
cert = SSL_get_peer_certificate(rktrans->rktrans_ssl);
|
|
601
|
+
#endif
|
|
602
|
+
X509_free(cert);
|
|
603
|
+
if (!cert) {
|
|
604
|
+
rd_kafka_broker_fail(rktrans->rktrans_rkb, LOG_ERR,
|
|
605
|
+
RD_KAFKA_RESP_ERR__SSL,
|
|
606
|
+
"Broker did not provide a certificate");
|
|
607
|
+
return -1;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
if ((rl = SSL_get_verify_result(rktrans->rktrans_ssl)) != X509_V_OK) {
|
|
611
|
+
rd_kafka_broker_fail(rktrans->rktrans_rkb, LOG_ERR,
|
|
612
|
+
RD_KAFKA_RESP_ERR__SSL,
|
|
613
|
+
"Failed to verify broker certificate: %s",
|
|
614
|
+
X509_verify_cert_error_string(rl));
|
|
615
|
+
return -1;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
rd_rkb_dbg(rktrans->rktrans_rkb, SECURITY, "SSLVERIFY",
|
|
619
|
+
"Broker SSL certificate verified");
|
|
620
|
+
return 0;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* @brief SSL handshake handling.
|
|
625
|
+
* Call repeatedly (based on IO events) until handshake is done.
|
|
626
|
+
*
|
|
627
|
+
* @returns -1 on error, 0 if handshake is still in progress,
|
|
628
|
+
* or 1 on completion.
|
|
629
|
+
*/
|
|
630
|
+
int rd_kafka_transport_ssl_handshake(rd_kafka_transport_t *rktrans) {
|
|
631
|
+
rd_kafka_broker_t *rkb = rktrans->rktrans_rkb;
|
|
632
|
+
char errstr[512];
|
|
633
|
+
int r;
|
|
634
|
+
|
|
635
|
+
r = SSL_do_handshake(rktrans->rktrans_ssl);
|
|
636
|
+
if (r == 1) {
|
|
637
|
+
/* SSL handshake done. Verify. */
|
|
638
|
+
if (rd_kafka_transport_ssl_verify(rktrans) == -1)
|
|
639
|
+
return -1;
|
|
640
|
+
|
|
641
|
+
rd_kafka_transport_connect_done(rktrans, NULL);
|
|
642
|
+
return 1;
|
|
643
|
+
|
|
644
|
+
} else if (rd_kafka_transport_ssl_io_update(rktrans, r, errstr,
|
|
645
|
+
sizeof(errstr)) == -1) {
|
|
646
|
+
const char *extra = "";
|
|
647
|
+
rd_kafka_resp_err_t err = RD_KAFKA_RESP_ERR__SSL;
|
|
648
|
+
|
|
649
|
+
if (strstr(errstr, "unexpected message"))
|
|
650
|
+
extra =
|
|
651
|
+
": client SSL authentication might be "
|
|
652
|
+
"required (see ssl.key.location and "
|
|
653
|
+
"ssl.certificate.location and consult the "
|
|
654
|
+
"broker logs for more information)";
|
|
655
|
+
else if (strstr(errstr,
|
|
656
|
+
"tls_process_server_certificate:"
|
|
657
|
+
"certificate verify failed") ||
|
|
658
|
+
strstr(errstr, "error:0A000086") /*openssl3*/ ||
|
|
659
|
+
strstr(errstr,
|
|
660
|
+
"get_server_certificate:"
|
|
661
|
+
"certificate verify failed"))
|
|
662
|
+
extra =
|
|
663
|
+
": broker certificate could not be verified, "
|
|
664
|
+
"verify that ssl.ca.location is correctly "
|
|
665
|
+
"configured or root CA certificates are "
|
|
666
|
+
"installed"
|
|
667
|
+
#ifdef __APPLE__
|
|
668
|
+
" (brew install openssl)"
|
|
669
|
+
#elif defined(_WIN32)
|
|
670
|
+
" (add broker's CA certificate to the Windows "
|
|
671
|
+
"Root certificate store)"
|
|
672
|
+
#else
|
|
673
|
+
" (install ca-certificates package)"
|
|
674
|
+
#endif
|
|
675
|
+
;
|
|
676
|
+
else if (rd_kafka_transport_error_disconnected(errstr)) {
|
|
677
|
+
extra = ": connecting to a PLAINTEXT broker listener?";
|
|
678
|
+
/* Disconnects during handshake are most likely
|
|
679
|
+
* not due to SSL, but rather at the transport level */
|
|
680
|
+
err = RD_KAFKA_RESP_ERR__TRANSPORT;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
rd_kafka_broker_fail(rkb, LOG_ERR, err,
|
|
684
|
+
"SSL handshake failed: %s%s", errstr,
|
|
685
|
+
extra);
|
|
686
|
+
return -1;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
return 0;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* @brief Parse a PEM-formatted string into an EVP_PKEY (PrivateKey) object.
|
|
696
|
+
*
|
|
697
|
+
* @param str Input PEM string, nul-terminated
|
|
698
|
+
*
|
|
699
|
+
* @remark This method does not provide automatic addition of PEM
|
|
700
|
+
* headers and footers.
|
|
701
|
+
*
|
|
702
|
+
* @returns a new EVP_PKEY on success or NULL on error.
|
|
703
|
+
*/
|
|
704
|
+
static EVP_PKEY *rd_kafka_ssl_PKEY_from_string(rd_kafka_t *rk,
|
|
705
|
+
const char *str) {
|
|
706
|
+
BIO *bio = BIO_new_mem_buf((void *)str, -1);
|
|
707
|
+
EVP_PKEY *pkey;
|
|
708
|
+
|
|
709
|
+
pkey = PEM_read_bio_PrivateKey(bio, NULL,
|
|
710
|
+
rd_kafka_transport_ssl_passwd_cb, rk);
|
|
711
|
+
|
|
712
|
+
BIO_free(bio);
|
|
713
|
+
|
|
714
|
+
return pkey;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* Read a PEM formatted cert chain from BIO \p in into \p chainp .
|
|
719
|
+
*
|
|
720
|
+
* @param rk rdkafka instance.
|
|
721
|
+
* @param in BIO to read from.
|
|
722
|
+
* @param chainp Stack to push the certificates to.
|
|
723
|
+
*
|
|
724
|
+
* @return 0 on success, -1 on error.
|
|
725
|
+
*/
|
|
726
|
+
int rd_kafka_ssl_read_cert_chain_from_BIO(BIO *in,
|
|
727
|
+
STACK_OF(X509) * chainp,
|
|
728
|
+
pem_password_cb *password_cb,
|
|
729
|
+
void *password_cb_opaque) {
|
|
730
|
+
X509 *ca;
|
|
731
|
+
int r, ret = 0;
|
|
732
|
+
unsigned long err;
|
|
733
|
+
while (1) {
|
|
734
|
+
ca = X509_new();
|
|
735
|
+
if (ca == NULL) {
|
|
736
|
+
rd_assert(!*"X509_new() allocation failed");
|
|
737
|
+
}
|
|
738
|
+
if (PEM_read_bio_X509(in, &ca, password_cb,
|
|
739
|
+
password_cb_opaque) != NULL) {
|
|
740
|
+
r = sk_X509_push(chainp, ca);
|
|
741
|
+
if (!r) {
|
|
742
|
+
X509_free(ca);
|
|
743
|
+
ret = -1;
|
|
744
|
+
goto end;
|
|
745
|
+
}
|
|
746
|
+
} else {
|
|
747
|
+
X509_free(ca);
|
|
748
|
+
break;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
/* When the while loop ends, it's usually just EOF. */
|
|
752
|
+
err = ERR_peek_last_error();
|
|
753
|
+
if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
|
|
754
|
+
ERR_GET_REASON(err) == PEM_R_NO_START_LINE)
|
|
755
|
+
ret = 0;
|
|
756
|
+
else
|
|
757
|
+
ret = -1; /* some real error */
|
|
758
|
+
ERR_clear_error();
|
|
759
|
+
end:
|
|
760
|
+
return ret;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* @brief Parse a PEM-formatted string into an X509 object.
|
|
765
|
+
* Rest of CA chain is pushed to the \p chainp stack.
|
|
766
|
+
*
|
|
767
|
+
* @param str Input PEM string, nul-terminated.
|
|
768
|
+
* @param chainp Stack to push the certificates to.
|
|
769
|
+
*
|
|
770
|
+
* @returns a new X509 on success or NULL on error.
|
|
771
|
+
*
|
|
772
|
+
* @remark When NULL is returned the chainp stack is not modified.
|
|
773
|
+
*/
|
|
774
|
+
static X509 *rd_kafka_ssl_X509_from_string(rd_kafka_t *rk,
|
|
775
|
+
const char *str,
|
|
776
|
+
STACK_OF(X509) * chainp) {
|
|
777
|
+
BIO *bio = BIO_new_mem_buf((void *)str, -1);
|
|
778
|
+
X509 *x509;
|
|
779
|
+
|
|
780
|
+
x509 =
|
|
781
|
+
PEM_read_bio_X509(bio, NULL, rd_kafka_transport_ssl_passwd_cb, rk);
|
|
782
|
+
|
|
783
|
+
if (!x509) {
|
|
784
|
+
BIO_free(bio);
|
|
785
|
+
return NULL;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
if (rd_kafka_ssl_read_cert_chain_from_BIO(
|
|
789
|
+
bio, chainp, rd_kafka_transport_ssl_passwd_cb, rk) != 0) {
|
|
790
|
+
/* Rest of the certificate is present,
|
|
791
|
+
* but couldn't be read,
|
|
792
|
+
* returning NULL as certificate cannot be verified
|
|
793
|
+
* without its chain. */
|
|
794
|
+
rd_kafka_log(rk, LOG_WARNING, "SSL",
|
|
795
|
+
"Failed to read certificate chain from PEM. "
|
|
796
|
+
"Returning NULL certificate too.");
|
|
797
|
+
X509_free(x509);
|
|
798
|
+
BIO_free(bio);
|
|
799
|
+
return NULL;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
BIO_free(bio);
|
|
803
|
+
return x509;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
#ifdef _WIN32
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* @brief Attempt load CA certificates from a Windows Certificate store.
|
|
811
|
+
*/
|
|
812
|
+
static int rd_kafka_ssl_win_load_cert_store(rd_kafka_t *rk,
|
|
813
|
+
const char *ctx_identifier,
|
|
814
|
+
SSL_CTX *ctx,
|
|
815
|
+
const char *store_name) {
|
|
816
|
+
HCERTSTORE w_store;
|
|
817
|
+
PCCERT_CONTEXT w_cctx = NULL;
|
|
818
|
+
X509_STORE *store;
|
|
819
|
+
int fail_cnt = 0, cnt = 0;
|
|
820
|
+
char errstr[256];
|
|
821
|
+
wchar_t *wstore_name;
|
|
822
|
+
size_t wsize = 0;
|
|
823
|
+
errno_t werr;
|
|
824
|
+
|
|
825
|
+
/* Convert store_name to wide-char */
|
|
826
|
+
werr = mbstowcs_s(&wsize, NULL, 0, store_name, strlen(store_name));
|
|
827
|
+
if (werr || wsize < 2 || wsize > 1000) {
|
|
828
|
+
rd_kafka_log(
|
|
829
|
+
rk, LOG_ERR, "CERTSTORE",
|
|
830
|
+
"%s: Invalid Windows certificate store name: %.*s%s",
|
|
831
|
+
ctx_identifier, 30, store_name,
|
|
832
|
+
wsize < 2 ? " (empty)" : " (truncated)");
|
|
833
|
+
return -1;
|
|
834
|
+
}
|
|
835
|
+
wstore_name = rd_alloca(sizeof(*wstore_name) * wsize);
|
|
836
|
+
werr = mbstowcs_s(NULL, wstore_name, wsize, store_name,
|
|
837
|
+
strlen(store_name));
|
|
838
|
+
rd_assert(!werr);
|
|
839
|
+
|
|
840
|
+
w_store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
|
|
841
|
+
CERT_SYSTEM_STORE_CURRENT_USER |
|
|
842
|
+
CERT_STORE_READONLY_FLAG |
|
|
843
|
+
CERT_STORE_OPEN_EXISTING_FLAG,
|
|
844
|
+
wstore_name);
|
|
845
|
+
if (!w_store) {
|
|
846
|
+
rd_kafka_log(
|
|
847
|
+
rk, LOG_ERR, "CERTSTORE",
|
|
848
|
+
"%s: Failed to open Windows certificate "
|
|
849
|
+
"%s store: %s",
|
|
850
|
+
ctx_identifier, store_name,
|
|
851
|
+
rd_strerror_w32(GetLastError(), errstr, sizeof(errstr)));
|
|
852
|
+
return -1;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
/* Get the OpenSSL trust store */
|
|
856
|
+
store = SSL_CTX_get_cert_store(ctx);
|
|
857
|
+
|
|
858
|
+
/* Enumerate the Windows certs */
|
|
859
|
+
while ((w_cctx = CertEnumCertificatesInStore(w_store, w_cctx))) {
|
|
860
|
+
X509 *x509;
|
|
861
|
+
|
|
862
|
+
/* Parse Windows cert: DER -> X.509 */
|
|
863
|
+
x509 = d2i_X509(NULL,
|
|
864
|
+
(const unsigned char **)&w_cctx->pbCertEncoded,
|
|
865
|
+
(long)w_cctx->cbCertEncoded);
|
|
866
|
+
if (!x509) {
|
|
867
|
+
fail_cnt++;
|
|
868
|
+
continue;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
/* Add cert to OpenSSL's trust store */
|
|
872
|
+
if (!X509_STORE_add_cert(store, x509))
|
|
873
|
+
fail_cnt++;
|
|
874
|
+
else
|
|
875
|
+
cnt++;
|
|
876
|
+
|
|
877
|
+
X509_free(x509);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
if (w_cctx)
|
|
881
|
+
CertFreeCertificateContext(w_cctx);
|
|
882
|
+
|
|
883
|
+
CertCloseStore(w_store, 0);
|
|
884
|
+
|
|
885
|
+
rd_kafka_dbg(rk, SECURITY, "CERTSTORE",
|
|
886
|
+
"%s: %d certificate(s) successfully added from "
|
|
887
|
+
"Windows Certificate %s store, %d failed",
|
|
888
|
+
ctx_identifier, cnt, store_name, fail_cnt);
|
|
889
|
+
|
|
890
|
+
if (cnt == 0 && fail_cnt > 0)
|
|
891
|
+
return -1;
|
|
892
|
+
|
|
893
|
+
return cnt;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
/**
|
|
897
|
+
* @brief Load certs from the configured CSV list of Windows Cert stores.
|
|
898
|
+
*
|
|
899
|
+
* @returns the number of successfully loaded certificates, or -1 on error.
|
|
900
|
+
*/
|
|
901
|
+
int rd_kafka_ssl_win_load_cert_stores(rd_kafka_t *rk,
|
|
902
|
+
const char *ctx_identifier,
|
|
903
|
+
SSL_CTX *ctx,
|
|
904
|
+
const char *store_names) {
|
|
905
|
+
char *s;
|
|
906
|
+
int cert_cnt = 0, fail_cnt = 0;
|
|
907
|
+
|
|
908
|
+
if (!store_names || !*store_names)
|
|
909
|
+
return 0;
|
|
910
|
+
|
|
911
|
+
rd_strdupa(&s, store_names);
|
|
912
|
+
|
|
913
|
+
/* Parse CSV list ("Root,CA, , ,Something") and load
|
|
914
|
+
* each store in order. */
|
|
915
|
+
while (*s) {
|
|
916
|
+
char *t;
|
|
917
|
+
const char *store_name;
|
|
918
|
+
int r;
|
|
919
|
+
|
|
920
|
+
while (isspace((int)*s) || *s == ',')
|
|
921
|
+
s++;
|
|
922
|
+
|
|
923
|
+
if (!*s)
|
|
924
|
+
break;
|
|
925
|
+
|
|
926
|
+
store_name = s;
|
|
927
|
+
|
|
928
|
+
t = strchr(s, (int)',');
|
|
929
|
+
if (t) {
|
|
930
|
+
*t = '\0';
|
|
931
|
+
s = t + 1;
|
|
932
|
+
for (; t >= store_name && isspace((int)*t); t--)
|
|
933
|
+
*t = '\0';
|
|
934
|
+
} else {
|
|
935
|
+
s = "";
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
r = rd_kafka_ssl_win_load_cert_store(rk, ctx_identifier, ctx,
|
|
939
|
+
store_name);
|
|
940
|
+
if (r != -1)
|
|
941
|
+
cert_cnt += r;
|
|
942
|
+
else
|
|
943
|
+
fail_cnt++;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
if (cert_cnt == 0 && fail_cnt > 0)
|
|
947
|
+
return -1;
|
|
948
|
+
|
|
949
|
+
return cert_cnt;
|
|
950
|
+
}
|
|
951
|
+
#endif /* MSC_VER */
|
|
952
|
+
|
|
953
|
+
/**
|
|
954
|
+
* @brief Probe for a single \p path and if found and not an empty directory,
|
|
955
|
+
* set it on the \p ctx.
|
|
956
|
+
*
|
|
957
|
+
* @returns 0 if CA location was set with an error, 1 if it was set correctly,
|
|
958
|
+
* -1 if path should be skipped.
|
|
959
|
+
*/
|
|
960
|
+
static int rd_kafka_ssl_set_ca_path(rd_kafka_t *rk,
|
|
961
|
+
const char *ctx_identifier,
|
|
962
|
+
const char *path,
|
|
963
|
+
SSL_CTX *ctx,
|
|
964
|
+
rd_bool_t *is_dir) {
|
|
965
|
+
if (!rd_file_stat(path, is_dir))
|
|
966
|
+
return -1;
|
|
967
|
+
|
|
968
|
+
if (*is_dir && rd_kafka_dir_is_empty(path))
|
|
969
|
+
return -1;
|
|
970
|
+
|
|
971
|
+
rd_kafka_dbg(rk, SECURITY, "CACERTS",
|
|
972
|
+
"Setting default CA certificate location for %s "
|
|
973
|
+
"to \"%s\"",
|
|
974
|
+
ctx_identifier, path);
|
|
975
|
+
|
|
976
|
+
return SSL_CTX_load_verify_locations(ctx, *is_dir ? NULL : path,
|
|
977
|
+
*is_dir ? path : NULL);
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
* @brief Probe for the system's CA certificate location and if found set it
|
|
982
|
+
* on the \p CTX.
|
|
983
|
+
*
|
|
984
|
+
* @returns 0 if CA location was set, else -1.
|
|
985
|
+
*/
|
|
986
|
+
int rd_kafka_ssl_probe_and_set_default_ca_location(rd_kafka_t *rk,
|
|
987
|
+
const char *ctx_identifier,
|
|
988
|
+
SSL_CTX *ctx) {
|
|
989
|
+
#if _WIN32
|
|
990
|
+
/* No standard location on Windows, CA certs are in the ROOT store. */
|
|
991
|
+
return -1;
|
|
992
|
+
#else
|
|
993
|
+
/* The probe paths are based on:
|
|
994
|
+
* https://www.happyassassin.net/posts/2015/01/12/a-note-about-ssltls-trusted-certificate-stores-and-platforms/
|
|
995
|
+
* Golang's crypto probing paths:
|
|
996
|
+
* https://golang.org/search?q=certFiles and certDirectories
|
|
997
|
+
*/
|
|
998
|
+
static const char *paths[] = {
|
|
999
|
+
"/etc/pki/tls/certs/ca-bundle.crt",
|
|
1000
|
+
"/etc/ssl/certs/ca-bundle.crt",
|
|
1001
|
+
"/etc/pki/tls/certs/ca-bundle.trust.crt",
|
|
1002
|
+
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
|
|
1003
|
+
|
|
1004
|
+
"/etc/ssl/ca-bundle.pem",
|
|
1005
|
+
"/etc/pki/tls/cacert.pem",
|
|
1006
|
+
"/etc/ssl/cert.pem",
|
|
1007
|
+
"/etc/ssl/cacert.pem",
|
|
1008
|
+
|
|
1009
|
+
"/etc/certs/ca-certificates.crt",
|
|
1010
|
+
"/etc/ssl/certs/ca-certificates.crt",
|
|
1011
|
+
|
|
1012
|
+
"/etc/ssl/certs",
|
|
1013
|
+
|
|
1014
|
+
"/usr/local/etc/ssl/cert.pem",
|
|
1015
|
+
"/usr/local/etc/ssl/cacert.pem",
|
|
1016
|
+
|
|
1017
|
+
"/usr/local/etc/ssl/certs/cert.pem",
|
|
1018
|
+
"/usr/local/etc/ssl/certs/cacert.pem",
|
|
1019
|
+
|
|
1020
|
+
/* BSD */
|
|
1021
|
+
"/usr/local/share/certs/ca-root-nss.crt",
|
|
1022
|
+
"/etc/openssl/certs/ca-certificates.crt",
|
|
1023
|
+
#ifdef __APPLE__
|
|
1024
|
+
"/private/etc/ssl/cert.pem",
|
|
1025
|
+
"/private/etc/ssl/certs",
|
|
1026
|
+
"/usr/local/etc/openssl@1.1/cert.pem",
|
|
1027
|
+
"/usr/local/etc/openssl@1.0/cert.pem",
|
|
1028
|
+
"/usr/local/etc/openssl/certs",
|
|
1029
|
+
"/System/Library/OpenSSL",
|
|
1030
|
+
#endif
|
|
1031
|
+
#ifdef _AIX
|
|
1032
|
+
"/var/ssl/certs/ca-bundle.crt",
|
|
1033
|
+
#endif
|
|
1034
|
+
NULL,
|
|
1035
|
+
};
|
|
1036
|
+
const char *path = NULL;
|
|
1037
|
+
int i;
|
|
1038
|
+
|
|
1039
|
+
for (i = 0; (path = paths[i]); i++) {
|
|
1040
|
+
rd_bool_t is_dir;
|
|
1041
|
+
int r = rd_kafka_ssl_set_ca_path(rk, ctx_identifier, path, ctx,
|
|
1042
|
+
&is_dir);
|
|
1043
|
+
if (r == -1)
|
|
1044
|
+
continue;
|
|
1045
|
+
|
|
1046
|
+
if (r != 1) {
|
|
1047
|
+
char errstr[512];
|
|
1048
|
+
/* Read error and clear the error stack */
|
|
1049
|
+
rd_kafka_ssl_error(rk, NULL, errstr, sizeof(errstr));
|
|
1050
|
+
rd_kafka_dbg(rk, SECURITY, "CACERTS",
|
|
1051
|
+
"Failed to set default CA certificate "
|
|
1052
|
+
"location to %s %s for %s: %s: skipping",
|
|
1053
|
+
is_dir ? "directory" : "file", path,
|
|
1054
|
+
ctx_identifier, errstr);
|
|
1055
|
+
continue;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
return 0;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
rd_kafka_dbg(rk, SECURITY, "CACERTS",
|
|
1062
|
+
"Unable to find any standard CA certificate"
|
|
1063
|
+
"paths for %s: is the ca-certificates package installed?",
|
|
1064
|
+
ctx_identifier);
|
|
1065
|
+
return -1;
|
|
1066
|
+
#endif
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/**
|
|
1070
|
+
* @brief Simple utility function to check if \p ca DN is matching
|
|
1071
|
+
* any of the DNs in the \p ca_dns stack.
|
|
1072
|
+
*/
|
|
1073
|
+
static int rd_kafka_ssl_cert_issuer_match(STACK_OF(X509_NAME) * ca_dns,
|
|
1074
|
+
X509 *ca) {
|
|
1075
|
+
X509_NAME *issuer_dn = X509_get_issuer_name(ca);
|
|
1076
|
+
X509_NAME *dn;
|
|
1077
|
+
int i;
|
|
1078
|
+
|
|
1079
|
+
for (i = 0; i < sk_X509_NAME_num(ca_dns); i++) {
|
|
1080
|
+
dn = sk_X509_NAME_value(ca_dns, i);
|
|
1081
|
+
if (0 == X509_NAME_cmp(dn, issuer_dn)) {
|
|
1082
|
+
/* match found */
|
|
1083
|
+
return 1;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
return 0;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
/**
|
|
1090
|
+
* @brief callback function for SSL_CTX_set_cert_cb, see
|
|
1091
|
+
* https://docs.openssl.org/master/man3/SSL_CTX_set_cert_cb for details
|
|
1092
|
+
* of the callback function requirements.
|
|
1093
|
+
*
|
|
1094
|
+
* According to section 4.2.4 of RFC 8446:
|
|
1095
|
+
* The "certificate_authorities" extension is used to indicate the
|
|
1096
|
+
* certificate authorities (CAs) which an endpoint supports and which
|
|
1097
|
+
* SHOULD be used by the receiving endpoint to guide certificate
|
|
1098
|
+
* selection.
|
|
1099
|
+
*
|
|
1100
|
+
* We avoid sending a client certificate if the issuer doesn't match any DN
|
|
1101
|
+
* of server trusted certificate authorities (SSL_get_client_CA_list).
|
|
1102
|
+
* This is done to avoid sending a client certificate that would almost
|
|
1103
|
+
* certainly be rejected by the peer and would avoid successful
|
|
1104
|
+
* SASL_SSL authentication on the same connection in case
|
|
1105
|
+
* `ssl.client.auth=requested`.
|
|
1106
|
+
*/
|
|
1107
|
+
static int rd_kafka_ssl_cert_callback(SSL *ssl, void *arg) {
|
|
1108
|
+
rd_kafka_t *rk = arg;
|
|
1109
|
+
STACK_OF(X509_NAME) * ca_list;
|
|
1110
|
+
STACK_OF(X509) *certs = NULL;
|
|
1111
|
+
X509 *cert;
|
|
1112
|
+
int i;
|
|
1113
|
+
|
|
1114
|
+
/* Get client cert from SSL connection */
|
|
1115
|
+
cert = SSL_get_certificate(ssl);
|
|
1116
|
+
if (cert == NULL) {
|
|
1117
|
+
/* If there's no client certificate,
|
|
1118
|
+
* skip certificate issuer verification and
|
|
1119
|
+
* avoid logging a warning. */
|
|
1120
|
+
return 1;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
/* Get the accepted client CA list from the SSL connection, this
|
|
1124
|
+
* comes from the `certificate_authorities` field. */
|
|
1125
|
+
ca_list = SSL_get_client_CA_list(ssl);
|
|
1126
|
+
if (sk_X509_NAME_num(ca_list) < 1) {
|
|
1127
|
+
/* `certificate_authorities` is supported either
|
|
1128
|
+
* in CertificateRequest (SSL <= 3, TLS <= 1.2)
|
|
1129
|
+
* or as an extension (TLS >= 1.3). This should be always
|
|
1130
|
+
* available, but in case it isn't, just send the certificate
|
|
1131
|
+
* and let the server validate it. */
|
|
1132
|
+
return 1;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
if (rd_kafka_ssl_cert_issuer_match(ca_list, cert)) {
|
|
1136
|
+
/* A match is found, use the certificate. */
|
|
1137
|
+
return 1;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
/* Get client cert chain from SSL connection */
|
|
1141
|
+
SSL_get0_chain_certs(ssl, &certs);
|
|
1142
|
+
|
|
1143
|
+
if (certs) {
|
|
1144
|
+
/* Check if there's a match in the CA list for
|
|
1145
|
+
* each cert in the chain. */
|
|
1146
|
+
for (i = 0; i < sk_X509_num(certs); i++) {
|
|
1147
|
+
cert = sk_X509_value(certs, i);
|
|
1148
|
+
if (rd_kafka_ssl_cert_issuer_match(ca_list, cert)) {
|
|
1149
|
+
/* A match is found, use the certificate. */
|
|
1150
|
+
return 1;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
/* No match is found, which means they would almost certainly be
|
|
1156
|
+
* rejected by the peer.
|
|
1157
|
+
* We decide to send no certificates. */
|
|
1158
|
+
rd_kafka_log(rk, LOG_WARNING, "SSL",
|
|
1159
|
+
"No matching issuer found in "
|
|
1160
|
+
"server trusted certificate authorities, "
|
|
1161
|
+
"not sending any client certificates");
|
|
1162
|
+
SSL_certs_clear(ssl);
|
|
1163
|
+
return 1;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
/**
|
|
1167
|
+
* @brief Registers certificates, keys, etc, on the SSL_CTX
|
|
1168
|
+
*
|
|
1169
|
+
* @returns -1 on error, or 0 on success.
|
|
1170
|
+
*/
|
|
1171
|
+
static int rd_kafka_ssl_set_certs(rd_kafka_t *rk,
|
|
1172
|
+
SSL_CTX *ctx,
|
|
1173
|
+
char *errstr,
|
|
1174
|
+
size_t errstr_size) {
|
|
1175
|
+
rd_bool_t ca_probe = rd_true;
|
|
1176
|
+
rd_bool_t check_pkey = rd_false;
|
|
1177
|
+
int r;
|
|
1178
|
+
|
|
1179
|
+
/*
|
|
1180
|
+
* ssl_ca, ssl.ca.location, or Windows cert root store,
|
|
1181
|
+
* or default paths.
|
|
1182
|
+
*/
|
|
1183
|
+
if (rk->rk_conf.ssl.ca) {
|
|
1184
|
+
/* CA certificate chain set with conf_set_ssl_cert() */
|
|
1185
|
+
rd_kafka_dbg(rk, SECURITY, "SSL",
|
|
1186
|
+
"Loading CA certificate(s) from memory");
|
|
1187
|
+
|
|
1188
|
+
SSL_CTX_set_cert_store(ctx, rk->rk_conf.ssl.ca->store);
|
|
1189
|
+
|
|
1190
|
+
/* OpenSSL takes ownership of the store */
|
|
1191
|
+
rk->rk_conf.ssl.ca->store = NULL;
|
|
1192
|
+
|
|
1193
|
+
ca_probe = rd_false;
|
|
1194
|
+
|
|
1195
|
+
} else {
|
|
1196
|
+
|
|
1197
|
+
if (rk->rk_conf.ssl.ca_location &&
|
|
1198
|
+
strcmp(rk->rk_conf.ssl.ca_location, "probe")) {
|
|
1199
|
+
/* CA certificate location, either file or directory. */
|
|
1200
|
+
int is_dir =
|
|
1201
|
+
rd_kafka_path_is_dir(rk->rk_conf.ssl.ca_location);
|
|
1202
|
+
|
|
1203
|
+
rd_kafka_dbg(rk, SECURITY, "SSL",
|
|
1204
|
+
"Loading CA certificate(s) from %s %s",
|
|
1205
|
+
is_dir ? "directory" : "file",
|
|
1206
|
+
rk->rk_conf.ssl.ca_location);
|
|
1207
|
+
|
|
1208
|
+
r = SSL_CTX_load_verify_locations(
|
|
1209
|
+
ctx, !is_dir ? rk->rk_conf.ssl.ca_location : NULL,
|
|
1210
|
+
is_dir ? rk->rk_conf.ssl.ca_location : NULL);
|
|
1211
|
+
|
|
1212
|
+
if (r != 1) {
|
|
1213
|
+
rd_snprintf(errstr, errstr_size,
|
|
1214
|
+
"ssl.ca.location failed: ");
|
|
1215
|
+
return -1;
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
ca_probe = rd_false;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
if (rk->rk_conf.ssl.ca_pem) {
|
|
1222
|
+
/* CA as PEM string */
|
|
1223
|
+
X509 *x509;
|
|
1224
|
+
X509_STORE *store;
|
|
1225
|
+
BIO *bio;
|
|
1226
|
+
int cnt = 0;
|
|
1227
|
+
|
|
1228
|
+
/* Get the OpenSSL trust store */
|
|
1229
|
+
store = SSL_CTX_get_cert_store(ctx);
|
|
1230
|
+
rd_assert(store != NULL);
|
|
1231
|
+
|
|
1232
|
+
rd_kafka_dbg(rk, SECURITY, "SSL",
|
|
1233
|
+
"Loading CA certificate(s) from string");
|
|
1234
|
+
|
|
1235
|
+
bio =
|
|
1236
|
+
BIO_new_mem_buf((void *)rk->rk_conf.ssl.ca_pem, -1);
|
|
1237
|
+
rd_assert(bio != NULL);
|
|
1238
|
+
|
|
1239
|
+
/* Add all certificates to cert store */
|
|
1240
|
+
while ((x509 = PEM_read_bio_X509(
|
|
1241
|
+
bio, NULL, rd_kafka_transport_ssl_passwd_cb,
|
|
1242
|
+
rk))) {
|
|
1243
|
+
if (!X509_STORE_add_cert(store, x509)) {
|
|
1244
|
+
rd_snprintf(errstr, errstr_size,
|
|
1245
|
+
"failed to add ssl.ca.pem "
|
|
1246
|
+
"certificate "
|
|
1247
|
+
"#%d to CA cert store: ",
|
|
1248
|
+
cnt);
|
|
1249
|
+
X509_free(x509);
|
|
1250
|
+
BIO_free(bio);
|
|
1251
|
+
return -1;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
X509_free(x509);
|
|
1255
|
+
cnt++;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
if (!BIO_eof(bio) || !cnt) {
|
|
1259
|
+
rd_snprintf(errstr, errstr_size,
|
|
1260
|
+
"failed to read certificate #%d "
|
|
1261
|
+
"from ssl.ca.pem: "
|
|
1262
|
+
"not in PEM format?: ",
|
|
1263
|
+
cnt);
|
|
1264
|
+
BIO_free(bio);
|
|
1265
|
+
return -1;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
BIO_free(bio);
|
|
1269
|
+
|
|
1270
|
+
rd_kafka_dbg(rk, SECURITY, "SSL",
|
|
1271
|
+
"Loaded %d CA certificate(s) from string",
|
|
1272
|
+
cnt);
|
|
1273
|
+
|
|
1274
|
+
|
|
1275
|
+
ca_probe = rd_false;
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
if (ca_probe) {
|
|
1280
|
+
#ifdef _WIN32
|
|
1281
|
+
/* Attempt to load CA root certificates from the
|
|
1282
|
+
* configured Windows certificate stores. */
|
|
1283
|
+
r = rd_kafka_ssl_win_load_cert_stores(
|
|
1284
|
+
rk, "kafka", ctx, rk->rk_conf.ssl.ca_cert_stores);
|
|
1285
|
+
if (r == 0) {
|
|
1286
|
+
rd_kafka_log(
|
|
1287
|
+
rk, LOG_NOTICE, "CERTSTORE",
|
|
1288
|
+
"No CA certificates loaded from "
|
|
1289
|
+
"Windows certificate stores: "
|
|
1290
|
+
"falling back to default OpenSSL CA paths");
|
|
1291
|
+
r = -1;
|
|
1292
|
+
} else if (r == -1)
|
|
1293
|
+
rd_kafka_log(
|
|
1294
|
+
rk, LOG_NOTICE, "CERTSTORE",
|
|
1295
|
+
"Failed to load CA certificates from "
|
|
1296
|
+
"Windows certificate stores: "
|
|
1297
|
+
"falling back to default OpenSSL CA paths");
|
|
1298
|
+
#else
|
|
1299
|
+
r = -1;
|
|
1300
|
+
#endif
|
|
1301
|
+
|
|
1302
|
+
if ((rk->rk_conf.ssl.ca_location &&
|
|
1303
|
+
!strcmp(rk->rk_conf.ssl.ca_location, "probe"))
|
|
1304
|
+
#if WITH_STATIC_LIB_libcrypto
|
|
1305
|
+
|| r == -1
|
|
1306
|
+
#endif
|
|
1307
|
+
) {
|
|
1308
|
+
/* If OpenSSL was linked statically there is a risk
|
|
1309
|
+
* that the system installed CA certificate path
|
|
1310
|
+
* doesn't match the cert path of OpenSSL.
|
|
1311
|
+
* To circumvent this we check for the existence
|
|
1312
|
+
* of standard CA certificate paths and use the
|
|
1313
|
+
* first one that is found.
|
|
1314
|
+
* Ignore failures. */
|
|
1315
|
+
r = rd_kafka_ssl_probe_and_set_default_ca_location(
|
|
1316
|
+
rk, "kafka", ctx);
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
if (r == -1) {
|
|
1320
|
+
/* Use default CA certificate paths from linked OpenSSL:
|
|
1321
|
+
* ignore failures */
|
|
1322
|
+
|
|
1323
|
+
r = SSL_CTX_set_default_verify_paths(ctx);
|
|
1324
|
+
if (r != 1) {
|
|
1325
|
+
char errstr2[512];
|
|
1326
|
+
/* Read error and clear the error stack. */
|
|
1327
|
+
rd_kafka_ssl_error(rk, NULL, errstr2,
|
|
1328
|
+
sizeof(errstr2));
|
|
1329
|
+
rd_kafka_dbg(
|
|
1330
|
+
rk, SECURITY, "SSL",
|
|
1331
|
+
"SSL_CTX_set_default_verify_paths() "
|
|
1332
|
+
"failed: %s: ignoring",
|
|
1333
|
+
errstr2);
|
|
1334
|
+
}
|
|
1335
|
+
r = 0;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
if (rk->rk_conf.ssl.crl_location) {
|
|
1340
|
+
rd_kafka_dbg(rk, SECURITY, "SSL", "Loading CRL from file %s",
|
|
1341
|
+
rk->rk_conf.ssl.crl_location);
|
|
1342
|
+
|
|
1343
|
+
r = SSL_CTX_load_verify_locations(
|
|
1344
|
+
ctx, rk->rk_conf.ssl.crl_location, NULL);
|
|
1345
|
+
|
|
1346
|
+
if (r != 1) {
|
|
1347
|
+
rd_snprintf(errstr, errstr_size,
|
|
1348
|
+
"ssl.crl.location failed: ");
|
|
1349
|
+
return -1;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
rd_kafka_dbg(rk, SECURITY, "SSL", "Enabling CRL checks");
|
|
1354
|
+
|
|
1355
|
+
X509_STORE_set_flags(SSL_CTX_get_cert_store(ctx),
|
|
1356
|
+
X509_V_FLAG_CRL_CHECK);
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
|
|
1360
|
+
/*
|
|
1361
|
+
* ssl_cert, ssl.certificate.location and ssl.certificate.pem
|
|
1362
|
+
*/
|
|
1363
|
+
if (rk->rk_conf.ssl.cert) {
|
|
1364
|
+
rd_kafka_dbg(rk, SECURITY, "SSL",
|
|
1365
|
+
"Loading public key from memory");
|
|
1366
|
+
|
|
1367
|
+
rd_assert(rk->rk_conf.ssl.cert->x509);
|
|
1368
|
+
r = SSL_CTX_use_certificate(ctx, rk->rk_conf.ssl.cert->x509);
|
|
1369
|
+
if (r != 1) {
|
|
1370
|
+
rd_snprintf(errstr, errstr_size, "ssl_cert failed: ");
|
|
1371
|
+
return -1;
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
if (rk->rk_conf.ssl.cert->chain) {
|
|
1375
|
+
r = SSL_CTX_set0_chain(ctx,
|
|
1376
|
+
rk->rk_conf.ssl.cert->chain);
|
|
1377
|
+
if (r != 1) {
|
|
1378
|
+
rd_snprintf(errstr, errstr_size,
|
|
1379
|
+
"ssl_cert failed: "
|
|
1380
|
+
"setting certificate chain: ");
|
|
1381
|
+
return -1;
|
|
1382
|
+
} else {
|
|
1383
|
+
/* The chain is now owned by the CTX */
|
|
1384
|
+
rk->rk_conf.ssl.cert->chain = NULL;
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
if (rk->rk_conf.ssl.cert_location) {
|
|
1390
|
+
rd_kafka_dbg(rk, SECURITY, "SSL",
|
|
1391
|
+
"Loading public key from file %s",
|
|
1392
|
+
rk->rk_conf.ssl.cert_location);
|
|
1393
|
+
|
|
1394
|
+
r = SSL_CTX_use_certificate_chain_file(
|
|
1395
|
+
ctx, rk->rk_conf.ssl.cert_location);
|
|
1396
|
+
|
|
1397
|
+
if (r != 1) {
|
|
1398
|
+
rd_snprintf(errstr, errstr_size,
|
|
1399
|
+
"ssl.certificate.location failed: ");
|
|
1400
|
+
return -1;
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
if (rk->rk_conf.ssl.cert_pem) {
|
|
1405
|
+
X509 *x509;
|
|
1406
|
+
STACK_OF(X509) *ca = sk_X509_new_null();
|
|
1407
|
+
if (!ca) {
|
|
1408
|
+
rd_assert(!*"sk_X509_new_null() allocation failed");
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
rd_kafka_dbg(rk, SECURITY, "SSL",
|
|
1412
|
+
"Loading public key from string");
|
|
1413
|
+
|
|
1414
|
+
x509 = rd_kafka_ssl_X509_from_string(
|
|
1415
|
+
rk, rk->rk_conf.ssl.cert_pem, ca);
|
|
1416
|
+
if (!x509) {
|
|
1417
|
+
rd_snprintf(errstr, errstr_size,
|
|
1418
|
+
"ssl.certificate.pem failed: "
|
|
1419
|
+
"not in PEM format?: ");
|
|
1420
|
+
sk_X509_pop_free(ca, X509_free);
|
|
1421
|
+
return -1;
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
r = SSL_CTX_use_certificate(ctx, x509);
|
|
1425
|
+
|
|
1426
|
+
X509_free(x509);
|
|
1427
|
+
|
|
1428
|
+
if (r != 1) {
|
|
1429
|
+
rd_snprintf(errstr, errstr_size,
|
|
1430
|
+
"ssl.certificate.pem failed: "
|
|
1431
|
+
"setting main certificate: ");
|
|
1432
|
+
sk_X509_pop_free(ca, X509_free);
|
|
1433
|
+
return -1;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
if (sk_X509_num(ca) == 0) {
|
|
1437
|
+
sk_X509_pop_free(ca, X509_free);
|
|
1438
|
+
} else {
|
|
1439
|
+
r = SSL_CTX_set0_chain(ctx, ca);
|
|
1440
|
+
if (r != 1) {
|
|
1441
|
+
rd_snprintf(errstr, errstr_size,
|
|
1442
|
+
"ssl.certificate.pem failed: "
|
|
1443
|
+
"setting certificate chain: ");
|
|
1444
|
+
sk_X509_pop_free(ca, X509_free);
|
|
1445
|
+
return -1;
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
/*
|
|
1451
|
+
* ssl_key, ssl.key.location and ssl.key.pem
|
|
1452
|
+
*/
|
|
1453
|
+
if (rk->rk_conf.ssl.key) {
|
|
1454
|
+
rd_kafka_dbg(rk, SECURITY, "SSL",
|
|
1455
|
+
"Loading private key file from memory");
|
|
1456
|
+
|
|
1457
|
+
rd_assert(rk->rk_conf.ssl.key->pkey);
|
|
1458
|
+
r = SSL_CTX_use_PrivateKey(ctx, rk->rk_conf.ssl.key->pkey);
|
|
1459
|
+
if (r != 1) {
|
|
1460
|
+
rd_snprintf(errstr, errstr_size,
|
|
1461
|
+
"ssl_key (in-memory) failed: ");
|
|
1462
|
+
return -1;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
check_pkey = rd_true;
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
if (rk->rk_conf.ssl.key_location) {
|
|
1469
|
+
rd_kafka_dbg(rk, SECURITY, "SSL",
|
|
1470
|
+
"Loading private key file from %s",
|
|
1471
|
+
rk->rk_conf.ssl.key_location);
|
|
1472
|
+
|
|
1473
|
+
r = SSL_CTX_use_PrivateKey_file(
|
|
1474
|
+
ctx, rk->rk_conf.ssl.key_location, SSL_FILETYPE_PEM);
|
|
1475
|
+
if (r != 1) {
|
|
1476
|
+
rd_snprintf(errstr, errstr_size,
|
|
1477
|
+
"ssl.key.location failed: ");
|
|
1478
|
+
return -1;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
check_pkey = rd_true;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
if (rk->rk_conf.ssl.key_pem) {
|
|
1485
|
+
EVP_PKEY *pkey;
|
|
1486
|
+
|
|
1487
|
+
rd_kafka_dbg(rk, SECURITY, "SSL",
|
|
1488
|
+
"Loading private key from string");
|
|
1489
|
+
|
|
1490
|
+
pkey =
|
|
1491
|
+
rd_kafka_ssl_PKEY_from_string(rk, rk->rk_conf.ssl.key_pem);
|
|
1492
|
+
if (!pkey) {
|
|
1493
|
+
rd_snprintf(errstr, errstr_size,
|
|
1494
|
+
"ssl.key.pem failed: "
|
|
1495
|
+
"not in PEM format?: ");
|
|
1496
|
+
return -1;
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
r = SSL_CTX_use_PrivateKey(ctx, pkey);
|
|
1500
|
+
|
|
1501
|
+
EVP_PKEY_free(pkey);
|
|
1502
|
+
|
|
1503
|
+
if (r != 1) {
|
|
1504
|
+
rd_snprintf(errstr, errstr_size,
|
|
1505
|
+
"ssl.key.pem failed: ");
|
|
1506
|
+
return -1;
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
/* We no longer need the PEM key (it is cached in the CTX),
|
|
1510
|
+
* clear its memory. */
|
|
1511
|
+
rd_kafka_desensitize_str(rk->rk_conf.ssl.key_pem);
|
|
1512
|
+
|
|
1513
|
+
check_pkey = rd_true;
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
|
|
1517
|
+
/*
|
|
1518
|
+
* ssl.keystore.location
|
|
1519
|
+
*/
|
|
1520
|
+
if (rk->rk_conf.ssl.keystore_location) {
|
|
1521
|
+
EVP_PKEY *pkey = NULL;
|
|
1522
|
+
X509 *cert = NULL;
|
|
1523
|
+
STACK_OF(X509) *ca = NULL;
|
|
1524
|
+
BIO *bio;
|
|
1525
|
+
PKCS12 *p12;
|
|
1526
|
+
|
|
1527
|
+
rd_kafka_dbg(rk, SECURITY, "SSL",
|
|
1528
|
+
"Loading client's keystore file from %s",
|
|
1529
|
+
rk->rk_conf.ssl.keystore_location);
|
|
1530
|
+
|
|
1531
|
+
bio = BIO_new_file(rk->rk_conf.ssl.keystore_location, "rb");
|
|
1532
|
+
if (!bio) {
|
|
1533
|
+
rd_snprintf(errstr, errstr_size,
|
|
1534
|
+
"Failed to open ssl.keystore.location: "
|
|
1535
|
+
"%s: ",
|
|
1536
|
+
rk->rk_conf.ssl.keystore_location);
|
|
1537
|
+
return -1;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
p12 = d2i_PKCS12_bio(bio, NULL);
|
|
1541
|
+
if (!p12) {
|
|
1542
|
+
BIO_free(bio);
|
|
1543
|
+
rd_snprintf(errstr, errstr_size,
|
|
1544
|
+
"Error reading ssl.keystore.location "
|
|
1545
|
+
"PKCS#12 file: %s: ",
|
|
1546
|
+
rk->rk_conf.ssl.keystore_location);
|
|
1547
|
+
return -1;
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
if (!PKCS12_parse(p12, rk->rk_conf.ssl.keystore_password, &pkey,
|
|
1551
|
+
&cert, &ca)) {
|
|
1552
|
+
EVP_PKEY_free(pkey);
|
|
1553
|
+
X509_free(cert);
|
|
1554
|
+
PKCS12_free(p12);
|
|
1555
|
+
BIO_free(bio);
|
|
1556
|
+
if (ca != NULL)
|
|
1557
|
+
sk_X509_pop_free(ca, X509_free);
|
|
1558
|
+
rd_snprintf(errstr, errstr_size,
|
|
1559
|
+
"Failed to parse ssl.keystore.location "
|
|
1560
|
+
"PKCS#12 file: %s: ",
|
|
1561
|
+
rk->rk_conf.ssl.keystore_location);
|
|
1562
|
+
return -1;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
PKCS12_free(p12);
|
|
1566
|
+
BIO_free(bio);
|
|
1567
|
+
|
|
1568
|
+
r = SSL_CTX_use_cert_and_key(ctx, cert, pkey, ca, 1);
|
|
1569
|
+
RD_IF_FREE(cert, X509_free);
|
|
1570
|
+
RD_IF_FREE(pkey, EVP_PKEY_free);
|
|
1571
|
+
if (ca != NULL)
|
|
1572
|
+
sk_X509_pop_free(ca, X509_free);
|
|
1573
|
+
if (r != 1) {
|
|
1574
|
+
rd_snprintf(errstr, errstr_size,
|
|
1575
|
+
"Failed to use ssl.keystore.location: ");
|
|
1576
|
+
return -1;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
check_pkey = rd_true;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
#if WITH_SSL_ENGINE
|
|
1583
|
+
/*
|
|
1584
|
+
* If applicable, use OpenSSL engine to fetch SSL certificate.
|
|
1585
|
+
*/
|
|
1586
|
+
if (rk->rk_conf.ssl.engine) {
|
|
1587
|
+
STACK_OF(X509_NAME) *cert_names = sk_X509_NAME_new_null();
|
|
1588
|
+
STACK_OF(X509_OBJECT) *roots =
|
|
1589
|
+
X509_STORE_get0_objects(SSL_CTX_get_cert_store(ctx));
|
|
1590
|
+
X509 *x509 = NULL;
|
|
1591
|
+
EVP_PKEY *pkey = NULL;
|
|
1592
|
+
int i = 0;
|
|
1593
|
+
for (i = 0; i < sk_X509_OBJECT_num(roots); i++) {
|
|
1594
|
+
x509 = X509_OBJECT_get0_X509(
|
|
1595
|
+
sk_X509_OBJECT_value(roots, i));
|
|
1596
|
+
|
|
1597
|
+
if (x509)
|
|
1598
|
+
sk_X509_NAME_push(cert_names,
|
|
1599
|
+
X509_get_subject_name(x509));
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
if (cert_names)
|
|
1603
|
+
sk_X509_NAME_free(cert_names);
|
|
1604
|
+
|
|
1605
|
+
x509 = NULL;
|
|
1606
|
+
r = ENGINE_load_ssl_client_cert(
|
|
1607
|
+
rk->rk_conf.ssl.engine, NULL, cert_names, &x509, &pkey,
|
|
1608
|
+
NULL, NULL, rk->rk_conf.ssl.engine_callback_data);
|
|
1609
|
+
|
|
1610
|
+
sk_X509_NAME_free(cert_names);
|
|
1611
|
+
if (r == -1 || !x509 || !pkey) {
|
|
1612
|
+
X509_free(x509);
|
|
1613
|
+
EVP_PKEY_free(pkey);
|
|
1614
|
+
if (r == -1)
|
|
1615
|
+
rd_snprintf(errstr, errstr_size,
|
|
1616
|
+
"OpenSSL "
|
|
1617
|
+
"ENGINE_load_ssl_client_cert "
|
|
1618
|
+
"failed: ");
|
|
1619
|
+
else if (!x509)
|
|
1620
|
+
rd_snprintf(errstr, errstr_size,
|
|
1621
|
+
"OpenSSL engine failed to "
|
|
1622
|
+
"load certificate: ");
|
|
1623
|
+
else
|
|
1624
|
+
rd_snprintf(errstr, errstr_size,
|
|
1625
|
+
"OpenSSL engine failed to "
|
|
1626
|
+
"load private key: ");
|
|
1627
|
+
|
|
1628
|
+
return -1;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
r = SSL_CTX_use_certificate(ctx, x509);
|
|
1632
|
+
X509_free(x509);
|
|
1633
|
+
if (r != 1) {
|
|
1634
|
+
rd_snprintf(errstr, errstr_size,
|
|
1635
|
+
"Failed to use SSL_CTX_use_certificate "
|
|
1636
|
+
"with engine: ");
|
|
1637
|
+
EVP_PKEY_free(pkey);
|
|
1638
|
+
return -1;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
r = SSL_CTX_use_PrivateKey(ctx, pkey);
|
|
1642
|
+
EVP_PKEY_free(pkey);
|
|
1643
|
+
if (r != 1) {
|
|
1644
|
+
rd_snprintf(errstr, errstr_size,
|
|
1645
|
+
"Failed to use SSL_CTX_use_PrivateKey "
|
|
1646
|
+
"with engine: ");
|
|
1647
|
+
return -1;
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
check_pkey = rd_true;
|
|
1651
|
+
}
|
|
1652
|
+
#endif /*WITH_SSL_ENGINE*/
|
|
1653
|
+
|
|
1654
|
+
/* Check that a valid private/public key combo was set. */
|
|
1655
|
+
if (check_pkey && SSL_CTX_check_private_key(ctx) != 1) {
|
|
1656
|
+
rd_snprintf(errstr, errstr_size, "Private key check failed: ");
|
|
1657
|
+
return -1;
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
/* Set client certificate callback to control the behaviour
|
|
1661
|
+
* of client certificate selection TLS handshake. */
|
|
1662
|
+
SSL_CTX_set_cert_cb(ctx, rd_kafka_ssl_cert_callback, rk);
|
|
1663
|
+
|
|
1664
|
+
return 0;
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
|
|
1668
|
+
/**
|
|
1669
|
+
* @brief Once per rd_kafka_t handle cleanup of OpenSSL
|
|
1670
|
+
*
|
|
1671
|
+
* @locality any thread
|
|
1672
|
+
*
|
|
1673
|
+
* @locks rd_kafka_wrlock() MUST be held
|
|
1674
|
+
*/
|
|
1675
|
+
void rd_kafka_ssl_ctx_term(rd_kafka_t *rk) {
|
|
1676
|
+
SSL_CTX_free(rk->rk_conf.ssl.ctx);
|
|
1677
|
+
rk->rk_conf.ssl.ctx = NULL;
|
|
1678
|
+
|
|
1679
|
+
#if WITH_SSL_ENGINE
|
|
1680
|
+
RD_IF_FREE(rk->rk_conf.ssl.engine, ENGINE_free);
|
|
1681
|
+
#endif
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
|
|
1685
|
+
#if WITH_SSL_ENGINE
|
|
1686
|
+
/**
|
|
1687
|
+
* @brief Initialize and load OpenSSL engine, if configured.
|
|
1688
|
+
*
|
|
1689
|
+
* @returns true on success, false on error.
|
|
1690
|
+
*/
|
|
1691
|
+
static rd_bool_t
|
|
1692
|
+
rd_kafka_ssl_ctx_init_engine(rd_kafka_t *rk, char *errstr, size_t errstr_size) {
|
|
1693
|
+
ENGINE *engine;
|
|
1694
|
+
|
|
1695
|
+
/* OpenSSL loads an engine as dynamic id and stores it in
|
|
1696
|
+
* internal list, as per LIST_ADD command below. If engine
|
|
1697
|
+
* already exists in internal list, it is supposed to be
|
|
1698
|
+
* fetched using engine id.
|
|
1699
|
+
*/
|
|
1700
|
+
engine = ENGINE_by_id(rk->rk_conf.ssl.engine_id);
|
|
1701
|
+
if (!engine) {
|
|
1702
|
+
engine = ENGINE_by_id("dynamic");
|
|
1703
|
+
if (!engine) {
|
|
1704
|
+
rd_snprintf(errstr, errstr_size,
|
|
1705
|
+
"OpenSSL engine initialization failed in"
|
|
1706
|
+
" ENGINE_by_id: ");
|
|
1707
|
+
return rd_false;
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
if (!ENGINE_ctrl_cmd_string(engine, "SO_PATH",
|
|
1712
|
+
rk->rk_conf.ssl.engine_location, 0)) {
|
|
1713
|
+
ENGINE_free(engine);
|
|
1714
|
+
rd_snprintf(errstr, errstr_size,
|
|
1715
|
+
"OpenSSL engine initialization failed in"
|
|
1716
|
+
" ENGINE_ctrl_cmd_string SO_PATH: ");
|
|
1717
|
+
return rd_false;
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
if (!ENGINE_ctrl_cmd_string(engine, "LIST_ADD", "1", 0)) {
|
|
1721
|
+
ENGINE_free(engine);
|
|
1722
|
+
rd_snprintf(errstr, errstr_size,
|
|
1723
|
+
"OpenSSL engine initialization failed in"
|
|
1724
|
+
" ENGINE_ctrl_cmd_string LIST_ADD: ");
|
|
1725
|
+
return rd_false;
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
if (!ENGINE_ctrl_cmd_string(engine, "LOAD", NULL, 0)) {
|
|
1729
|
+
ENGINE_free(engine);
|
|
1730
|
+
rd_snprintf(errstr, errstr_size,
|
|
1731
|
+
"OpenSSL engine initialization failed in"
|
|
1732
|
+
" ENGINE_ctrl_cmd_string LOAD: ");
|
|
1733
|
+
return rd_false;
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
if (!ENGINE_init(engine)) {
|
|
1737
|
+
ENGINE_free(engine);
|
|
1738
|
+
rd_snprintf(errstr, errstr_size,
|
|
1739
|
+
"OpenSSL engine initialization failed in"
|
|
1740
|
+
" ENGINE_init: ");
|
|
1741
|
+
return rd_false;
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
rk->rk_conf.ssl.engine = engine;
|
|
1745
|
+
|
|
1746
|
+
return rd_true;
|
|
1747
|
+
}
|
|
1748
|
+
#endif
|
|
1749
|
+
|
|
1750
|
+
|
|
1751
|
+
#if OPENSSL_VERSION_NUMBER >= 0x30000000
|
|
1752
|
+
/**
|
|
1753
|
+
* @brief Wrapper around OSSL_PROVIDER_unload() to expose a free(void*) API
|
|
1754
|
+
* suitable for rd_list_t's free_cb.
|
|
1755
|
+
*/
|
|
1756
|
+
static void rd_kafka_ssl_OSSL_PROVIDER_free(void *ptr) {
|
|
1757
|
+
OSSL_PROVIDER *prov = ptr;
|
|
1758
|
+
(void)OSSL_PROVIDER_unload(prov);
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
|
|
1762
|
+
/**
|
|
1763
|
+
* @brief Load OpenSSL 3.0.x providers specified in comma-separated string.
|
|
1764
|
+
*
|
|
1765
|
+
* @remark Only the error preamble/prefix is written here, the actual
|
|
1766
|
+
* OpenSSL error is retrieved from the OpenSSL error stack by
|
|
1767
|
+
* the caller.
|
|
1768
|
+
*
|
|
1769
|
+
* @returns rd_false on failure (errstr will be written to), or rd_true
|
|
1770
|
+
* on successs.
|
|
1771
|
+
*/
|
|
1772
|
+
static rd_bool_t rd_kafka_ssl_ctx_load_providers(rd_kafka_t *rk,
|
|
1773
|
+
const char *providers_csv,
|
|
1774
|
+
char *errstr,
|
|
1775
|
+
size_t errstr_size) {
|
|
1776
|
+
size_t provider_cnt, i;
|
|
1777
|
+
char **providers = rd_string_split(
|
|
1778
|
+
providers_csv, ',', rd_true /*skip empty*/, &provider_cnt);
|
|
1779
|
+
|
|
1780
|
+
|
|
1781
|
+
if (!providers || !provider_cnt) {
|
|
1782
|
+
rd_snprintf(errstr, errstr_size,
|
|
1783
|
+
"ssl.providers expects a comma-separated "
|
|
1784
|
+
"list of OpenSSL 3.0.x providers");
|
|
1785
|
+
if (providers)
|
|
1786
|
+
rd_free(providers);
|
|
1787
|
+
return rd_false;
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
rd_list_init(&rk->rk_conf.ssl.loaded_providers, (int)provider_cnt,
|
|
1791
|
+
rd_kafka_ssl_OSSL_PROVIDER_free);
|
|
1792
|
+
|
|
1793
|
+
for (i = 0; i < provider_cnt; i++) {
|
|
1794
|
+
const char *provider = providers[i];
|
|
1795
|
+
OSSL_PROVIDER *prov;
|
|
1796
|
+
const char *buildinfo = NULL;
|
|
1797
|
+
OSSL_PARAM request[] = {{"buildinfo", OSSL_PARAM_UTF8_PTR,
|
|
1798
|
+
(void *)&buildinfo, 0, 0},
|
|
1799
|
+
{NULL, 0, NULL, 0, 0}};
|
|
1800
|
+
|
|
1801
|
+
prov = OSSL_PROVIDER_load(NULL, provider);
|
|
1802
|
+
if (!prov) {
|
|
1803
|
+
rd_snprintf(errstr, errstr_size,
|
|
1804
|
+
"Failed to load OpenSSL provider \"%s\": ",
|
|
1805
|
+
provider);
|
|
1806
|
+
rd_free(providers);
|
|
1807
|
+
return rd_false;
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
if (!OSSL_PROVIDER_get_params(prov, request))
|
|
1811
|
+
buildinfo = "no buildinfo";
|
|
1812
|
+
|
|
1813
|
+
rd_kafka_dbg(rk, SECURITY, "SSL",
|
|
1814
|
+
"OpenSSL provider \"%s\" loaded (%s)", provider,
|
|
1815
|
+
buildinfo);
|
|
1816
|
+
|
|
1817
|
+
rd_list_add(&rk->rk_conf.ssl.loaded_providers, prov);
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
rd_free(providers);
|
|
1821
|
+
|
|
1822
|
+
return rd_true;
|
|
1823
|
+
}
|
|
1824
|
+
#endif
|
|
1825
|
+
|
|
1826
|
+
|
|
1827
|
+
|
|
1828
|
+
/**
|
|
1829
|
+
* @brief Once per rd_kafka_t handle initialization of OpenSSL
|
|
1830
|
+
*
|
|
1831
|
+
* @locality application thread
|
|
1832
|
+
*
|
|
1833
|
+
* @locks rd_kafka_wrlock() MUST be held
|
|
1834
|
+
*/
|
|
1835
|
+
int rd_kafka_ssl_ctx_init(rd_kafka_t *rk, char *errstr, size_t errstr_size) {
|
|
1836
|
+
int r;
|
|
1837
|
+
SSL_CTX *ctx = NULL;
|
|
1838
|
+
const char *linking =
|
|
1839
|
+
#if WITH_STATIC_LIB_libcrypto
|
|
1840
|
+
"statically linked "
|
|
1841
|
+
#else
|
|
1842
|
+
""
|
|
1843
|
+
#endif
|
|
1844
|
+
;
|
|
1845
|
+
|
|
1846
|
+
#if OPENSSL_VERSION_NUMBER >= 0x10100000
|
|
1847
|
+
rd_kafka_dbg(rk, SECURITY, "OPENSSL",
|
|
1848
|
+
"Using %sOpenSSL version %s "
|
|
1849
|
+
"(0x%lx, librdkafka built with 0x%lx)",
|
|
1850
|
+
linking, OpenSSL_version(OPENSSL_VERSION),
|
|
1851
|
+
OpenSSL_version_num(), OPENSSL_VERSION_NUMBER);
|
|
1852
|
+
#else
|
|
1853
|
+
rd_kafka_dbg(rk, SECURITY, "OPENSSL",
|
|
1854
|
+
"librdkafka built with %sOpenSSL version 0x%lx", linking,
|
|
1855
|
+
OPENSSL_VERSION_NUMBER);
|
|
1856
|
+
#endif
|
|
1857
|
+
|
|
1858
|
+
if (errstr_size > 0)
|
|
1859
|
+
errstr[0] = '\0';
|
|
1860
|
+
|
|
1861
|
+
#if OPENSSL_VERSION_NUMBER >= 0x30000000
|
|
1862
|
+
if (rk->rk_conf.ssl.providers &&
|
|
1863
|
+
!rd_kafka_ssl_ctx_load_providers(rk, rk->rk_conf.ssl.providers,
|
|
1864
|
+
errstr, errstr_size))
|
|
1865
|
+
goto fail;
|
|
1866
|
+
#endif
|
|
1867
|
+
|
|
1868
|
+
#if WITH_SSL_ENGINE
|
|
1869
|
+
if (rk->rk_conf.ssl.engine_location && !rk->rk_conf.ssl.engine) {
|
|
1870
|
+
rd_kafka_dbg(rk, SECURITY, "SSL",
|
|
1871
|
+
"Loading OpenSSL engine from \"%s\"",
|
|
1872
|
+
rk->rk_conf.ssl.engine_location);
|
|
1873
|
+
if (!rd_kafka_ssl_ctx_init_engine(rk, errstr, errstr_size))
|
|
1874
|
+
goto fail;
|
|
1875
|
+
}
|
|
1876
|
+
#endif
|
|
1877
|
+
|
|
1878
|
+
#if OPENSSL_VERSION_NUMBER >= 0x10100000
|
|
1879
|
+
ctx = SSL_CTX_new(TLS_client_method());
|
|
1880
|
+
#else
|
|
1881
|
+
ctx = SSL_CTX_new(SSLv23_client_method());
|
|
1882
|
+
#endif
|
|
1883
|
+
if (!ctx) {
|
|
1884
|
+
rd_snprintf(errstr, errstr_size, "SSL_CTX_new() failed: ");
|
|
1885
|
+
goto fail;
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
#ifdef SSL_OP_NO_SSLv3
|
|
1889
|
+
/* Disable SSLv3 (unsafe) */
|
|
1890
|
+
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
|
|
1891
|
+
#endif
|
|
1892
|
+
|
|
1893
|
+
/* Key file password callback */
|
|
1894
|
+
SSL_CTX_set_default_passwd_cb(ctx, rd_kafka_transport_ssl_passwd_cb);
|
|
1895
|
+
SSL_CTX_set_default_passwd_cb_userdata(ctx, rk);
|
|
1896
|
+
|
|
1897
|
+
/* Ciphers */
|
|
1898
|
+
if (rk->rk_conf.ssl.cipher_suites) {
|
|
1899
|
+
rd_kafka_dbg(rk, SECURITY, "SSL", "Setting cipher list: %s",
|
|
1900
|
+
rk->rk_conf.ssl.cipher_suites);
|
|
1901
|
+
if (!SSL_CTX_set_cipher_list(ctx,
|
|
1902
|
+
rk->rk_conf.ssl.cipher_suites)) {
|
|
1903
|
+
/* Set a string that will prefix the
|
|
1904
|
+
* the OpenSSL error message (which is lousy)
|
|
1905
|
+
* to make it more meaningful. */
|
|
1906
|
+
rd_snprintf(errstr, errstr_size,
|
|
1907
|
+
"ssl.cipher.suites failed: ");
|
|
1908
|
+
goto fail;
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
/* Set up broker certificate verification. */
|
|
1913
|
+
SSL_CTX_set_verify(ctx,
|
|
1914
|
+
rk->rk_conf.ssl.enable_verify ? SSL_VERIFY_PEER
|
|
1915
|
+
: SSL_VERIFY_NONE,
|
|
1916
|
+
rk->rk_conf.ssl.cert_verify_cb
|
|
1917
|
+
? rd_kafka_transport_ssl_cert_verify_cb
|
|
1918
|
+
: NULL);
|
|
1919
|
+
|
|
1920
|
+
#if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(LIBRESSL_VERSION_NUMBER)
|
|
1921
|
+
/* Curves */
|
|
1922
|
+
if (rk->rk_conf.ssl.curves_list) {
|
|
1923
|
+
rd_kafka_dbg(rk, SECURITY, "SSL", "Setting curves list: %s",
|
|
1924
|
+
rk->rk_conf.ssl.curves_list);
|
|
1925
|
+
if (!SSL_CTX_set1_curves_list(ctx,
|
|
1926
|
+
rk->rk_conf.ssl.curves_list)) {
|
|
1927
|
+
rd_snprintf(errstr, errstr_size,
|
|
1928
|
+
"ssl.curves.list failed: ");
|
|
1929
|
+
goto fail;
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
/* Certificate signature algorithms */
|
|
1934
|
+
if (rk->rk_conf.ssl.sigalgs_list) {
|
|
1935
|
+
rd_kafka_dbg(rk, SECURITY, "SSL",
|
|
1936
|
+
"Setting signature algorithms list: %s",
|
|
1937
|
+
rk->rk_conf.ssl.sigalgs_list);
|
|
1938
|
+
if (!SSL_CTX_set1_sigalgs_list(ctx,
|
|
1939
|
+
rk->rk_conf.ssl.sigalgs_list)) {
|
|
1940
|
+
rd_snprintf(errstr, errstr_size,
|
|
1941
|
+
"ssl.sigalgs.list failed: ");
|
|
1942
|
+
goto fail;
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
#endif
|
|
1946
|
+
|
|
1947
|
+
/* Register certificates, keys, etc. */
|
|
1948
|
+
if (rd_kafka_ssl_set_certs(rk, ctx, errstr, errstr_size) == -1)
|
|
1949
|
+
goto fail;
|
|
1950
|
+
|
|
1951
|
+
|
|
1952
|
+
#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
|
|
1953
|
+
/* Ignore unexpected EOF error in OpenSSL 3.x, treating
|
|
1954
|
+
* it like a normal connection close even if
|
|
1955
|
+
* close_notify wasn't received.
|
|
1956
|
+
* see issue #4293 */
|
|
1957
|
+
SSL_CTX_set_options(ctx, SSL_OP_IGNORE_UNEXPECTED_EOF);
|
|
1958
|
+
#endif
|
|
1959
|
+
|
|
1960
|
+
SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
|
1961
|
+
|
|
1962
|
+
rk->rk_conf.ssl.ctx = ctx;
|
|
1963
|
+
|
|
1964
|
+
return 0;
|
|
1965
|
+
|
|
1966
|
+
fail:
|
|
1967
|
+
r = (int)strlen(errstr);
|
|
1968
|
+
/* If only the error preamble is provided in errstr and ending with
|
|
1969
|
+
* "....: ", then retrieve the last error from the OpenSSL error stack,
|
|
1970
|
+
* else treat the errstr as complete. */
|
|
1971
|
+
if (r > 2 && !strcmp(&errstr[r - 2], ": "))
|
|
1972
|
+
rd_kafka_ssl_error(rk, NULL, errstr + r,
|
|
1973
|
+
(int)errstr_size > r ? (int)errstr_size - r
|
|
1974
|
+
: 0);
|
|
1975
|
+
RD_IF_FREE(ctx, SSL_CTX_free);
|
|
1976
|
+
#if WITH_SSL_ENGINE
|
|
1977
|
+
RD_IF_FREE(rk->rk_conf.ssl.engine, ENGINE_free);
|
|
1978
|
+
#endif
|
|
1979
|
+
rd_list_destroy(&rk->rk_conf.ssl.loaded_providers);
|
|
1980
|
+
|
|
1981
|
+
return -1;
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
|
|
1985
|
+
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
1986
|
+
static RD_UNUSED void
|
|
1987
|
+
rd_kafka_transport_ssl_lock_cb(int mode, int i, const char *file, int line) {
|
|
1988
|
+
if (mode & CRYPTO_LOCK)
|
|
1989
|
+
mtx_lock(&rd_kafka_ssl_locks[i]);
|
|
1990
|
+
else
|
|
1991
|
+
mtx_unlock(&rd_kafka_ssl_locks[i]);
|
|
1992
|
+
}
|
|
1993
|
+
#endif
|
|
1994
|
+
|
|
1995
|
+
static RD_UNUSED unsigned long rd_kafka_transport_ssl_threadid_cb(void) {
|
|
1996
|
+
#ifdef _WIN32
|
|
1997
|
+
/* Windows makes a distinction between thread handle
|
|
1998
|
+
* and thread id, which means we can't use the
|
|
1999
|
+
* thrd_current() API that returns the handle. */
|
|
2000
|
+
return (unsigned long)GetCurrentThreadId();
|
|
2001
|
+
#else
|
|
2002
|
+
return (unsigned long)(intptr_t)thrd_current();
|
|
2003
|
+
#endif
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
#ifdef HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK
|
|
2007
|
+
static void
|
|
2008
|
+
rd_kafka_transport_libcrypto_THREADID_callback(CRYPTO_THREADID *id) {
|
|
2009
|
+
unsigned long thread_id = rd_kafka_transport_ssl_threadid_cb();
|
|
2010
|
+
|
|
2011
|
+
CRYPTO_THREADID_set_numeric(id, thread_id);
|
|
2012
|
+
}
|
|
2013
|
+
#endif
|
|
2014
|
+
|
|
2015
|
+
/**
|
|
2016
|
+
* @brief Global OpenSSL cleanup.
|
|
2017
|
+
*/
|
|
2018
|
+
void rd_kafka_ssl_term(void) {
|
|
2019
|
+
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
2020
|
+
int i;
|
|
2021
|
+
|
|
2022
|
+
if (CRYPTO_get_locking_callback() == &rd_kafka_transport_ssl_lock_cb) {
|
|
2023
|
+
CRYPTO_set_locking_callback(NULL);
|
|
2024
|
+
#ifdef HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK
|
|
2025
|
+
CRYPTO_THREADID_set_callback(NULL);
|
|
2026
|
+
#else
|
|
2027
|
+
CRYPTO_set_id_callback(NULL);
|
|
2028
|
+
#endif
|
|
2029
|
+
|
|
2030
|
+
for (i = 0; i < rd_kafka_ssl_locks_cnt; i++)
|
|
2031
|
+
mtx_destroy(&rd_kafka_ssl_locks[i]);
|
|
2032
|
+
|
|
2033
|
+
rd_free(rd_kafka_ssl_locks);
|
|
2034
|
+
}
|
|
2035
|
+
#endif
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
|
|
2039
|
+
/**
|
|
2040
|
+
* @brief Global (once per process) OpenSSL init.
|
|
2041
|
+
*/
|
|
2042
|
+
void rd_kafka_ssl_init(void) {
|
|
2043
|
+
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
2044
|
+
int i;
|
|
2045
|
+
|
|
2046
|
+
if (!CRYPTO_get_locking_callback()) {
|
|
2047
|
+
rd_kafka_ssl_locks_cnt = CRYPTO_num_locks();
|
|
2048
|
+
rd_kafka_ssl_locks = rd_malloc(rd_kafka_ssl_locks_cnt *
|
|
2049
|
+
sizeof(*rd_kafka_ssl_locks));
|
|
2050
|
+
for (i = 0; i < rd_kafka_ssl_locks_cnt; i++)
|
|
2051
|
+
mtx_init(&rd_kafka_ssl_locks[i], mtx_plain);
|
|
2052
|
+
|
|
2053
|
+
CRYPTO_set_locking_callback(rd_kafka_transport_ssl_lock_cb);
|
|
2054
|
+
|
|
2055
|
+
#ifdef HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK
|
|
2056
|
+
CRYPTO_THREADID_set_callback(
|
|
2057
|
+
rd_kafka_transport_libcrypto_THREADID_callback);
|
|
2058
|
+
#else
|
|
2059
|
+
CRYPTO_set_id_callback(rd_kafka_transport_ssl_threadid_cb);
|
|
2060
|
+
#endif
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
/* OPENSSL_init_ssl(3) and OPENSSL_init_crypto(3) say:
|
|
2064
|
+
* "As of version 1.1.0 OpenSSL will automatically allocate
|
|
2065
|
+
* all resources that it needs so no explicit initialisation
|
|
2066
|
+
* is required. Similarly it will also automatically
|
|
2067
|
+
* deinitialise as required."
|
|
2068
|
+
*/
|
|
2069
|
+
SSL_load_error_strings();
|
|
2070
|
+
SSL_library_init();
|
|
2071
|
+
|
|
2072
|
+
ERR_load_BIO_strings();
|
|
2073
|
+
ERR_load_crypto_strings();
|
|
2074
|
+
OpenSSL_add_all_algorithms();
|
|
2075
|
+
#endif
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
int rd_kafka_ssl_hmac(rd_kafka_broker_t *rkb,
|
|
2079
|
+
const EVP_MD *evp,
|
|
2080
|
+
const rd_chariov_t *in,
|
|
2081
|
+
const rd_chariov_t *salt,
|
|
2082
|
+
int itcnt,
|
|
2083
|
+
rd_chariov_t *out) {
|
|
2084
|
+
unsigned int ressize = 0;
|
|
2085
|
+
unsigned char tempres[EVP_MAX_MD_SIZE];
|
|
2086
|
+
unsigned char *saltplus;
|
|
2087
|
+
int i;
|
|
2088
|
+
|
|
2089
|
+
/* U1 := HMAC(str, salt + INT(1)) */
|
|
2090
|
+
saltplus = rd_alloca(salt->size + 4);
|
|
2091
|
+
memcpy(saltplus, salt->ptr, salt->size);
|
|
2092
|
+
saltplus[salt->size] = 0;
|
|
2093
|
+
saltplus[salt->size + 1] = 0;
|
|
2094
|
+
saltplus[salt->size + 2] = 0;
|
|
2095
|
+
saltplus[salt->size + 3] = 1;
|
|
2096
|
+
|
|
2097
|
+
/* U1 := HMAC(str, salt + INT(1)) */
|
|
2098
|
+
if (!HMAC(evp, (const unsigned char *)in->ptr, (int)in->size, saltplus,
|
|
2099
|
+
salt->size + 4, tempres, &ressize)) {
|
|
2100
|
+
rd_rkb_dbg(rkb, SECURITY, "SSLHMAC", "HMAC priming failed");
|
|
2101
|
+
return -1;
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
memcpy(out->ptr, tempres, ressize);
|
|
2105
|
+
|
|
2106
|
+
/* Ui-1 := HMAC(str, Ui-2) .. */
|
|
2107
|
+
for (i = 1; i < itcnt; i++) {
|
|
2108
|
+
unsigned char tempdest[EVP_MAX_MD_SIZE];
|
|
2109
|
+
int j;
|
|
2110
|
+
|
|
2111
|
+
if (unlikely(!HMAC(evp, (const unsigned char *)in->ptr,
|
|
2112
|
+
(int)in->size, tempres, ressize, tempdest,
|
|
2113
|
+
NULL))) {
|
|
2114
|
+
rd_rkb_dbg(rkb, SECURITY, "SSLHMAC",
|
|
2115
|
+
"Hi() HMAC #%d/%d failed", i, itcnt);
|
|
2116
|
+
return -1;
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
/* U1 XOR U2 .. */
|
|
2120
|
+
for (j = 0; j < (int)ressize; j++) {
|
|
2121
|
+
out->ptr[j] ^= tempdest[j];
|
|
2122
|
+
tempres[j] = tempdest[j];
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
out->size = ressize;
|
|
2127
|
+
|
|
2128
|
+
return 0;
|
|
2129
|
+
}
|