@platformatic/rdkafka 4.0.1 → 4.1.0

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.
Files changed (294) hide show
  1. package/README.md +5 -5
  2. package/bench/seed.sh +0 -0
  3. package/binding.gyp +8 -1
  4. package/ci/prepublish.js +0 -1
  5. package/config.d.ts +126 -10
  6. package/configure +0 -0
  7. package/deps/librdkafka/.semaphore/run-all-tests.yml +77 -0
  8. package/deps/librdkafka/.semaphore/semaphore-integration.yml +250 -0
  9. package/deps/librdkafka/.semaphore/semaphore.yml +67 -44
  10. package/deps/librdkafka/.semaphore/verify-linux-packages.yml +41 -0
  11. package/deps/librdkafka/CHANGELOG.md +471 -1
  12. package/deps/librdkafka/CONFIGURATION.md +29 -9
  13. package/deps/librdkafka/INTRODUCTION.md +909 -601
  14. package/deps/librdkafka/LICENSES.txt +592 -1
  15. package/deps/librdkafka/Makefile +2 -1
  16. package/deps/librdkafka/_mkltmpuuWEwa.c +13 -0
  17. package/deps/librdkafka/configure +0 -0
  18. package/deps/librdkafka/debian/rules +0 -0
  19. package/deps/librdkafka/dev-conf.sh +0 -0
  20. package/deps/librdkafka/examples/consumer.c +18 -8
  21. package/deps/librdkafka/examples/describe_consumer_groups.c +25 -6
  22. package/deps/librdkafka/examples/incremental_alter_configs.c +4 -5
  23. package/deps/librdkafka/examples/kafkatest_verifiable_client.cpp +26 -42
  24. package/deps/librdkafka/examples/openssl_engine_example.cpp +3 -4
  25. package/deps/librdkafka/examples/producer.cpp +2 -2
  26. package/deps/librdkafka/examples/user_scram.c +4 -5
  27. package/deps/librdkafka/examples/win_ssl_cert_store.cpp +4 -3
  28. package/deps/librdkafka/lds-gen.py +0 -0
  29. package/deps/librdkafka/mklove/Makefile.base +0 -0
  30. package/deps/librdkafka/packaging/RELEASE.md +8 -0
  31. package/deps/librdkafka/packaging/alpine/build-alpine.sh +0 -0
  32. package/deps/librdkafka/packaging/cp/README.md +4 -1
  33. package/deps/librdkafka/packaging/cp/check_features.c +12 -4
  34. package/deps/librdkafka/packaging/cp/verify-deb.sh +6 -6
  35. package/deps/librdkafka/packaging/cp/verify-packages.sh +52 -31
  36. package/deps/librdkafka/packaging/cp/verify-rpm.sh +6 -13
  37. package/deps/librdkafka/packaging/debian/rules +0 -0
  38. package/deps/librdkafka/packaging/get_version.py +0 -0
  39. package/deps/librdkafka/packaging/homebrew/brew-update-pr.sh +0 -0
  40. package/deps/librdkafka/packaging/mingw-w64/{travis-before-install.sh → export-variables.sh} +0 -7
  41. package/deps/librdkafka/packaging/mingw-w64/semaphoreci-build.sh +1 -1
  42. package/deps/librdkafka/packaging/nuget/artifact.py +0 -0
  43. package/deps/librdkafka/packaging/nuget/cleanup-s3.py +0 -0
  44. package/deps/librdkafka/packaging/nuget/nuget.sh +0 -0
  45. package/deps/librdkafka/packaging/nuget/packaging.py +0 -0
  46. package/deps/librdkafka/packaging/nuget/push-to-nuget.sh +0 -0
  47. package/deps/librdkafka/packaging/nuget/release.py +0 -0
  48. package/deps/librdkafka/packaging/nuget/requirements.txt +3 -3
  49. package/deps/librdkafka/packaging/rpm/mock-on-docker.sh +0 -0
  50. package/deps/librdkafka/packaging/rpm/tests/run-test.sh +0 -0
  51. package/deps/librdkafka/packaging/rpm/tests/test-on-docker.sh +0 -0
  52. package/deps/librdkafka/packaging/tools/build-configurations-checks.sh +3 -1
  53. package/deps/librdkafka/packaging/tools/build-deb-package.sh +0 -0
  54. package/deps/librdkafka/packaging/tools/build-debian.sh +0 -0
  55. package/deps/librdkafka/packaging/tools/build-manylinux.sh +0 -0
  56. package/deps/librdkafka/packaging/tools/build-release-artifacts.sh +0 -0
  57. package/deps/librdkafka/packaging/tools/distro-build.sh +0 -0
  58. package/deps/librdkafka/packaging/tools/gh-release-checksums.py +0 -0
  59. package/deps/librdkafka/packaging/tools/rdutcoverage.sh +0 -0
  60. package/deps/librdkafka/packaging/tools/run-in-docker.sh +28 -0
  61. package/deps/librdkafka/packaging/tools/run-integration-tests.sh +31 -0
  62. package/deps/librdkafka/packaging/tools/run-style-check.sh +4 -0
  63. package/deps/librdkafka/packaging/tools/style-format.sh +6 -5
  64. package/deps/librdkafka/packaging/tools/update_rpcs_max_versions.py +100 -0
  65. package/deps/librdkafka/service.yml +154 -0
  66. package/deps/librdkafka/src/generate_proto.sh +0 -0
  67. package/deps/librdkafka/src/rd.h +145 -2
  68. package/deps/librdkafka/src/rdaddr.h +6 -7
  69. package/deps/librdkafka/src/rdatomic.h +15 -11
  70. package/deps/librdkafka/src/rdavg.h +3 -2
  71. package/deps/librdkafka/src/rdbase64.c +33 -2
  72. package/deps/librdkafka/src/rdbase64.h +2 -0
  73. package/deps/librdkafka/src/rdendian.h +10 -9
  74. package/deps/librdkafka/src/rdhttp.c +418 -100
  75. package/deps/librdkafka/src/rdhttp.h +23 -5
  76. package/deps/librdkafka/src/rdkafka.c +299 -145
  77. package/deps/librdkafka/src/rdkafka.h +89 -6
  78. package/deps/librdkafka/src/rdkafka_admin.c +482 -105
  79. package/deps/librdkafka/src/rdkafka_admin.h +42 -0
  80. package/deps/librdkafka/src/rdkafka_broker.c +463 -312
  81. package/deps/librdkafka/src/rdkafka_broker.h +68 -10
  82. package/deps/librdkafka/src/rdkafka_buf.c +8 -5
  83. package/deps/librdkafka/src/rdkafka_buf.h +4 -3
  84. package/deps/librdkafka/src/rdkafka_cert.c +25 -1
  85. package/deps/librdkafka/src/rdkafka_cert.h +4 -3
  86. package/deps/librdkafka/src/rdkafka_cgrp.c +468 -143
  87. package/deps/librdkafka/src/rdkafka_cgrp.h +36 -2
  88. package/deps/librdkafka/src/rdkafka_conf.c +526 -102
  89. package/deps/librdkafka/src/rdkafka_conf.h +68 -4
  90. package/deps/librdkafka/src/rdkafka_feature.c +472 -35
  91. package/deps/librdkafka/src/rdkafka_feature.h +2 -0
  92. package/deps/librdkafka/src/rdkafka_fetcher.c +22 -2
  93. package/deps/librdkafka/src/rdkafka_fetcher.h +2 -2
  94. package/deps/librdkafka/src/rdkafka_int.h +84 -46
  95. package/deps/librdkafka/src/rdkafka_metadata.c +221 -136
  96. package/deps/librdkafka/src/rdkafka_metadata.h +15 -11
  97. package/deps/librdkafka/src/rdkafka_metadata_cache.c +279 -73
  98. package/deps/librdkafka/src/rdkafka_mock.c +795 -19
  99. package/deps/librdkafka/src/rdkafka_mock.h +119 -0
  100. package/deps/librdkafka/src/rdkafka_mock_cgrp.c +1298 -132
  101. package/deps/librdkafka/src/rdkafka_mock_handlers.c +345 -49
  102. package/deps/librdkafka/src/rdkafka_mock_int.h +180 -61
  103. package/deps/librdkafka/src/rdkafka_msg.c +35 -19
  104. package/deps/librdkafka/src/rdkafka_msg.h +3 -3
  105. package/deps/librdkafka/src/rdkafka_msgset_writer.c +14 -10
  106. package/deps/librdkafka/src/rdkafka_offset.c +33 -5
  107. package/deps/librdkafka/src/rdkafka_op.c +1 -1
  108. package/deps/librdkafka/src/rdkafka_op.h +45 -21
  109. package/deps/librdkafka/src/rdkafka_partition.c +118 -23
  110. package/deps/librdkafka/src/rdkafka_partition.h +16 -7
  111. package/deps/librdkafka/src/rdkafka_proto.h +4 -1
  112. package/deps/librdkafka/src/rdkafka_protocol.h +1 -0
  113. package/deps/librdkafka/src/rdkafka_queue.c +125 -48
  114. package/deps/librdkafka/src/rdkafka_queue.h +19 -0
  115. package/deps/librdkafka/src/rdkafka_range_assignor.c +1 -1
  116. package/deps/librdkafka/src/rdkafka_request.c +336 -64
  117. package/deps/librdkafka/src/rdkafka_request.h +24 -1
  118. package/deps/librdkafka/src/rdkafka_sasl.c +5 -3
  119. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.c +14 -10
  120. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.c +1166 -89
  121. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.h +13 -3
  122. package/deps/librdkafka/src/rdkafka_sasl_plain.c +3 -3
  123. package/deps/librdkafka/src/rdkafka_sasl_scram.c +4 -3
  124. package/deps/librdkafka/src/rdkafka_ssl.c +306 -81
  125. package/deps/librdkafka/src/rdkafka_ssl.h +22 -0
  126. package/deps/librdkafka/src/rdkafka_sticky_assignor.c +4 -0
  127. package/deps/librdkafka/src/rdkafka_telemetry.c +80 -23
  128. package/deps/librdkafka/src/rdkafka_telemetry_encode.c +5 -1
  129. package/deps/librdkafka/src/rdkafka_telemetry_encode.h +20 -20
  130. package/deps/librdkafka/src/rdkafka_topic.c +220 -137
  131. package/deps/librdkafka/src/rdkafka_topic.h +14 -8
  132. package/deps/librdkafka/src/rdkafka_transport.c +59 -47
  133. package/deps/librdkafka/src/rdkafka_transport.h +5 -0
  134. package/deps/librdkafka/src/rdkafka_txnmgr.c +6 -1
  135. package/deps/librdkafka/src/rdmap.c +6 -1
  136. package/deps/librdkafka/src/rdrand.c +11 -1
  137. package/deps/librdkafka/src/rdtime.h +48 -17
  138. package/deps/librdkafka/src/rdunittest.c +42 -25
  139. package/deps/librdkafka/src/rdunittest.h +2 -0
  140. package/deps/librdkafka/src/rdwin32.h +1 -1
  141. package/deps/librdkafka/src/regexp.c +47 -42
  142. package/deps/librdkafka/src/tinycthread_extra.c +45 -21
  143. package/deps/librdkafka/src/tinycthread_extra.h +7 -3
  144. package/deps/librdkafka/src-cpp/rdkafkacpp.h +28 -2
  145. package/deps/librdkafka/tests/0001-multiobj.c +4 -0
  146. package/deps/librdkafka/tests/0004-conf.c +103 -36
  147. package/deps/librdkafka/tests/0009-mock_cluster.c +1 -0
  148. package/deps/librdkafka/tests/0011-produce_batch.c +2 -1
  149. package/deps/librdkafka/tests/0016-client_swname.c +18 -3
  150. package/deps/librdkafka/tests/0017-compression.c +6 -8
  151. package/deps/librdkafka/tests/0018-cgrp_term.c +8 -3
  152. package/deps/librdkafka/tests/0021-rkt_destroy.c +1 -0
  153. package/deps/librdkafka/tests/0022-consume_batch.c +4 -1
  154. package/deps/librdkafka/tests/0026-consume_pause.c +12 -14
  155. package/deps/librdkafka/tests/0028-long_topicnames.c +1 -1
  156. package/deps/librdkafka/tests/0029-assign_offset.c +6 -8
  157. package/deps/librdkafka/tests/0030-offset_commit.c +2 -2
  158. package/deps/librdkafka/tests/0033-regex_subscribe.c +33 -17
  159. package/deps/librdkafka/tests/0034-offset_reset.c +25 -4
  160. package/deps/librdkafka/tests/0036-partial_fetch.c +1 -0
  161. package/deps/librdkafka/tests/0038-performance.c +1 -0
  162. package/deps/librdkafka/tests/0040-io_event.c +11 -5
  163. package/deps/librdkafka/tests/0041-fetch_max_bytes.c +1 -0
  164. package/deps/librdkafka/tests/0044-partition_cnt.c +3 -2
  165. package/deps/librdkafka/tests/0045-subscribe_update.c +284 -20
  166. package/deps/librdkafka/tests/0047-partial_buf_tmout.c +1 -0
  167. package/deps/librdkafka/tests/0048-partitioner.c +1 -1
  168. package/deps/librdkafka/tests/0050-subscribe_adds.c +1 -0
  169. package/deps/librdkafka/tests/0051-assign_adds.c +1 -0
  170. package/deps/librdkafka/tests/0052-msg_timestamps.c +22 -4
  171. package/deps/librdkafka/tests/0053-stats_cb.cpp +12 -20
  172. package/deps/librdkafka/tests/0055-producer_latency.c +176 -3
  173. package/deps/librdkafka/tests/0056-balanced_group_mt.c +6 -2
  174. package/deps/librdkafka/tests/0058-log.cpp +3 -3
  175. package/deps/librdkafka/tests/0059-bsearch.cpp +8 -4
  176. package/deps/librdkafka/tests/0061-consumer_lag.cpp +25 -5
  177. package/deps/librdkafka/tests/0067-empty_topic.cpp +3 -0
  178. package/deps/librdkafka/tests/0068-produce_timeout.c +21 -23
  179. package/deps/librdkafka/tests/0069-consumer_add_parts.c +3 -7
  180. package/deps/librdkafka/tests/0075-retry.c +38 -1
  181. package/deps/librdkafka/tests/0076-produce_retry.c +2 -0
  182. package/deps/librdkafka/tests/0077-compaction.c +8 -2
  183. package/deps/librdkafka/tests/0080-admin_ut.c +34 -4
  184. package/deps/librdkafka/tests/0081-admin.c +455 -155
  185. package/deps/librdkafka/tests/0082-fetch_max_bytes.cpp +4 -0
  186. package/deps/librdkafka/tests/0083-cb_event.c +8 -3
  187. package/deps/librdkafka/tests/0084-destroy_flags.c +14 -18
  188. package/deps/librdkafka/tests/0085-headers.cpp +4 -0
  189. package/deps/librdkafka/tests/0086-purge.c +40 -7
  190. package/deps/librdkafka/tests/0088-produce_metadata_timeout.c +1 -1
  191. package/deps/librdkafka/tests/0089-max_poll_interval.c +12 -7
  192. package/deps/librdkafka/tests/0090-idempotence.c +1 -2
  193. package/deps/librdkafka/tests/0091-max_poll_interval_timeout.c +5 -7
  194. package/deps/librdkafka/tests/0092-mixed_msgver.c +6 -0
  195. package/deps/librdkafka/tests/0093-holb.c +8 -5
  196. package/deps/librdkafka/tests/0094-idempotence_msg_timeout.c +1 -0
  197. package/deps/librdkafka/tests/0097-ssl_verify.cpp +262 -70
  198. package/deps/librdkafka/tests/0098-consumer-txn.cpp +16 -16
  199. package/deps/librdkafka/tests/0099-commit_metadata.c +1 -1
  200. package/deps/librdkafka/tests/0101-fetch-from-follower.cpp +1 -1
  201. package/deps/librdkafka/tests/0102-static_group_rebalance.c +317 -16
  202. package/deps/librdkafka/tests/0103-transactions.c +7 -7
  203. package/deps/librdkafka/tests/0104-fetch_from_follower_mock.c +1 -0
  204. package/deps/librdkafka/tests/0105-transactions_mock.c +18 -11
  205. package/deps/librdkafka/tests/0106-cgrp_sess_timeout.c +35 -14
  206. package/deps/librdkafka/tests/0107-topic_recreate.c +2 -2
  207. package/deps/librdkafka/tests/0109-auto_create_topics.cpp +86 -26
  208. package/deps/librdkafka/tests/0110-batch_size.cpp +1 -2
  209. package/deps/librdkafka/tests/0112-assign_unknown_part.c +3 -14
  210. package/deps/librdkafka/tests/0113-cooperative_rebalance.cpp +248 -104
  211. package/deps/librdkafka/tests/0114-sticky_partitioning.cpp +3 -3
  212. package/deps/librdkafka/tests/0115-producer_auth.cpp +4 -1
  213. package/deps/librdkafka/tests/0116-kafkaconsumer_close.cpp +7 -5
  214. package/deps/librdkafka/tests/0117-mock_errors.c +15 -5
  215. package/deps/librdkafka/tests/0118-commit_rebalance.c +41 -8
  216. package/deps/librdkafka/tests/0119-consumer_auth.cpp +20 -1
  217. package/deps/librdkafka/tests/0120-asymmetric_subscription.c +8 -3
  218. package/deps/librdkafka/tests/0125-immediate_flush.c +1 -1
  219. package/deps/librdkafka/tests/0126-oauthbearer_oidc.c +323 -8
  220. package/deps/librdkafka/tests/0129-fetch_aborted_msgs.c +1 -0
  221. package/deps/librdkafka/tests/0132-strategy_ordering.c +12 -4
  222. package/deps/librdkafka/tests/0133-ssl_keys.c +28 -6
  223. package/deps/librdkafka/tests/0137-barrier_batch_consume.c +24 -14
  224. package/deps/librdkafka/tests/0139-offset_validation_mock.c +510 -2
  225. package/deps/librdkafka/tests/0140-commit_metadata.cpp +1 -1
  226. package/deps/librdkafka/tests/0142-reauthentication.c +37 -17
  227. package/deps/librdkafka/tests/0143-exponential_backoff_mock.c +39 -40
  228. package/deps/librdkafka/tests/0146-metadata_mock.c +76 -15
  229. package/deps/librdkafka/tests/0147-consumer_group_consumer_mock.c +952 -0
  230. package/deps/librdkafka/tests/0148-offset_fetch_commit_error_mock.c +563 -0
  231. package/deps/librdkafka/tests/0149-broker-same-host-port.c +140 -0
  232. package/deps/librdkafka/tests/0150-telemetry_mock.c +9 -6
  233. package/deps/librdkafka/tests/0151-purge-brokers.c +566 -0
  234. package/deps/librdkafka/tests/0152-rebootstrap.c +59 -0
  235. package/deps/librdkafka/tests/0153-memberid.c +128 -0
  236. package/deps/librdkafka/tests/CMakeLists.txt +6 -0
  237. package/deps/librdkafka/tests/LibrdkafkaTestApp.py +34 -9
  238. package/deps/librdkafka/tests/autotest.sh +0 -0
  239. package/deps/librdkafka/tests/broker_version_tests.py +0 -0
  240. package/deps/librdkafka/tests/buildbox.sh +0 -0
  241. package/deps/librdkafka/tests/cleanup-checker-tests.sh +0 -0
  242. package/deps/librdkafka/tests/cluster_testing.py +0 -0
  243. package/deps/librdkafka/tests/delete-test-topics.sh +0 -0
  244. package/deps/librdkafka/tests/fixtures/oauthbearer/jwt_assertion_template.json +10 -0
  245. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.intermediate.p12 +0 -0
  246. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.p12 +0 -0
  247. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.intermediate.pem +72 -0
  248. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.pem +42 -101
  249. package/deps/librdkafka/tests/fixtures/ssl/client2.intermediate.key +46 -0
  250. package/deps/librdkafka/tests/fixtures/ssl/client2.key +41 -29
  251. package/deps/librdkafka/tests/fixtures/ssl/create_keys.sh +112 -37
  252. package/deps/librdkafka/tests/gen-ssl-certs.sh +0 -0
  253. package/deps/librdkafka/tests/interactive_broker_version.py +0 -0
  254. package/deps/librdkafka/tests/java/Makefile +2 -1
  255. package/deps/librdkafka/tests/java/run-class.sh +0 -0
  256. package/deps/librdkafka/tests/lz4_manual_test.sh +0 -0
  257. package/deps/librdkafka/tests/multi-broker-version-test.sh +0 -0
  258. package/deps/librdkafka/tests/parse-refcnt.sh +0 -0
  259. package/deps/librdkafka/tests/performance_plot.py +0 -0
  260. package/deps/librdkafka/tests/requirements.txt +1 -1
  261. package/deps/librdkafka/tests/run-all-tests.sh +79 -0
  262. package/deps/librdkafka/tests/run-consumer-tests.sh +0 -0
  263. package/deps/librdkafka/tests/run-producer-tests.sh +0 -0
  264. package/deps/librdkafka/tests/run-test-batches.py +157 -0
  265. package/deps/librdkafka/tests/run-test.sh +0 -0
  266. package/deps/librdkafka/tests/sasl_test.py +0 -0
  267. package/deps/librdkafka/tests/test.c +478 -18
  268. package/deps/librdkafka/tests/test.h +62 -13
  269. package/deps/librdkafka/tests/testcpp.cpp +6 -1
  270. package/deps/librdkafka/tests/testcpp.h +30 -2
  271. package/deps/librdkafka/tests/testshared.h +16 -2
  272. package/deps/librdkafka/tests/tools/stats/graph.py +0 -0
  273. package/deps/librdkafka/tests/tools/stats/to_csv.py +1 -1
  274. package/deps/librdkafka/tests/trivup/trivup-0.14.0.tar.gz +0 -0
  275. package/deps/librdkafka/tests/until-fail.sh +0 -0
  276. package/deps/librdkafka/tests/xxxx-metadata.cpp +1 -1
  277. package/deps/librdkafka/vcpkg.json +1 -1
  278. package/deps/librdkafka/win32/setup-msys2.ps1 +24 -8
  279. package/deps/librdkafka/win32/setup-vcpkg.ps1 +28 -6
  280. package/deps/librdkafka/win32/tests/tests.vcxproj +6 -0
  281. package/deps/librdkafka/win32/wingetopt.h +5 -4
  282. package/errors.d.ts +27 -1
  283. package/lib/error.js +29 -3
  284. package/make_docs.sh +0 -0
  285. package/package.json +11 -11
  286. package/run_docker.sh +0 -0
  287. package/src/callbacks.cc +6 -9
  288. package/src/callbacks.h +1 -5
  289. package/test/kafka-consumer-worker.js +10 -7
  290. package/test/kafka-consumer.spec.js +32 -21
  291. package/ci/update-version.js +0 -123
  292. package/deps/librdkafka/.semaphore/project.yml +0 -43
  293. package/deps/librdkafka/.semaphore/project_public.yml +0 -20
  294. package/deps/librdkafka/win32/install-openssl.ps1 +0 -33
@@ -28,9 +28,19 @@
28
28
 
29
29
  #ifndef _RDKAFKA_SASL_OAUTHBEARER_OIDC_H_
30
30
  #define _RDKAFKA_SASL_OAUTHBEARER_OIDC_H_
31
- void rd_kafka_oidc_token_refresh_cb(rd_kafka_t *rk,
32
- const char *oauthbearer_config,
33
- void *opaque);
31
+ void rd_kafka_oidc_token_jwt_bearer_refresh_cb(rd_kafka_t *rk,
32
+ const char *oauthbearer_config,
33
+ void *opaque);
34
+
35
+ void rd_kafka_oidc_token_client_credentials_refresh_cb(
36
+ rd_kafka_t *rk,
37
+ const char *oauthbearer_config,
38
+ void *opaque);
39
+
40
+ void rd_kafka_oidc_token_metadata_azure_imds_refresh_cb(
41
+ rd_kafka_t *rk,
42
+ const char *oauthbearer_config,
43
+ void *opaque);
34
44
 
35
45
  int unittest_sasl_oauthbearer_oidc(void);
36
46
 
@@ -81,9 +81,9 @@ int rd_kafka_sasl_plain_client_new(rd_kafka_transport_t *rktrans,
81
81
  cidlen = rk->rk_conf.sasl.username
82
82
  ? (int)strlen(rk->rk_conf.sasl.username)
83
83
  : 0;
84
- pwlen = rk->rk_conf.sasl.password
85
- ? (int)strlen(rk->rk_conf.sasl.password)
86
- : 0;
84
+ pwlen = rk->rk_conf.sasl.password
85
+ ? (int)strlen(rk->rk_conf.sasl.password)
86
+ : 0;
87
87
 
88
88
  buf = rd_alloca(zidlen + 1 + cidlen + 1 + pwlen + 1);
89
89
 
@@ -54,9 +54,10 @@
54
54
  * @brief Per-connection state
55
55
  */
56
56
  struct rd_kafka_sasl_scram_state {
57
- enum { RD_KAFKA_SASL_SCRAM_STATE_CLIENT_FIRST_MESSAGE,
58
- RD_KAFKA_SASL_SCRAM_STATE_SERVER_FIRST_MESSAGE,
59
- RD_KAFKA_SASL_SCRAM_STATE_CLIENT_FINAL_MESSAGE,
57
+ enum {
58
+ RD_KAFKA_SASL_SCRAM_STATE_CLIENT_FIRST_MESSAGE,
59
+ RD_KAFKA_SASL_SCRAM_STATE_SERVER_FIRST_MESSAGE,
60
+ RD_KAFKA_SASL_SCRAM_STATE_CLIENT_FINAL_MESSAGE,
60
61
  } state;
61
62
  rd_chariov_t cnonce; /* client c-nonce */
62
63
  rd_chariov_t first_msg_bare; /* client-first-message-bare */
@@ -135,11 +135,14 @@ const char *rd_kafka_ssl_last_error_str(void) {
135
135
  *
136
136
  * If 'rkb' is non-NULL broker-specific logging will be used,
137
137
  * else it will fall back on global 'rk' debugging.
138
+ *
139
+ * `ctx_identifier` is a string used to customize the log message.
138
140
  */
139
- static char *rd_kafka_ssl_error(rd_kafka_t *rk,
140
- rd_kafka_broker_t *rkb,
141
- char *errstr,
142
- size_t errstr_size) {
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) {
143
146
  unsigned long l;
144
147
  const char *file, *data, *func;
145
148
  int line, flags;
@@ -166,9 +169,11 @@ static char *rd_kafka_ssl_error(rd_kafka_t *rk,
166
169
  if (cnt++ > 0) {
167
170
  /* Log last message */
168
171
  if (rkb)
169
- rd_rkb_log(rkb, LOG_ERR, "SSL", "%s", errstr);
172
+ rd_rkb_log(rkb, LOG_ERR, "SSL", "%s: %s",
173
+ ctx_identifier, errstr);
170
174
  else
171
- rd_kafka_log(rk, LOG_ERR, "SSL", "%s", errstr);
175
+ rd_kafka_log(rk, LOG_ERR, "SSL", "%s: %s",
176
+ ctx_identifier, errstr);
172
177
  }
173
178
 
174
179
  ERR_error_string_n(l, buf, sizeof(buf));
@@ -188,12 +193,18 @@ static char *rd_kafka_ssl_error(rd_kafka_t *rk,
188
193
 
189
194
  if (cnt == 0)
190
195
  rd_snprintf(errstr, errstr_size,
191
- "No further error information available");
196
+ "%s: No further error information available",
197
+ ctx_identifier);
192
198
 
193
199
  return errstr;
194
200
  }
195
201
 
196
-
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
+ }
197
208
 
198
209
  /**
199
210
  * Set transport IO event polling based on SSL error.
@@ -225,16 +236,22 @@ rd_kafka_transport_ssl_io_update(rd_kafka_transport_t *rktrans,
225
236
  if (serr2)
226
237
  rd_kafka_ssl_error(NULL, rktrans->rktrans_rkb, errstr,
227
238
  errstr_size);
228
- else if (!rd_socket_errno || rd_socket_errno == ECONNRESET)
229
- rd_snprintf(errstr, errstr_size, "Disconnected");
230
- else
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
231
247
  rd_snprintf(errstr, errstr_size,
232
248
  "SSL transport error: %s",
233
249
  rd_strerror(rd_socket_errno));
234
250
  return -1;
235
251
 
236
252
  case SSL_ERROR_ZERO_RETURN:
237
- rd_snprintf(errstr, errstr_size, "Disconnected");
253
+ rd_snprintf(errstr, errstr_size,
254
+ "Disconnected: SSL connection closed by peer");
238
255
  return -1;
239
256
 
240
257
  default:
@@ -656,7 +673,7 @@ int rd_kafka_transport_ssl_handshake(rd_kafka_transport_t *rktrans) {
656
673
  " (install ca-certificates package)"
657
674
  #endif
658
675
  ;
659
- else if (!strcmp(errstr, "Disconnected")) {
676
+ else if (rd_kafka_transport_error_disconnected(errstr)) {
660
677
  extra = ": connecting to a PLAINTEXT broker listener?";
661
678
  /* Disconnects during handshake are most likely
662
679
  * not due to SSL, but rather at the transport level */
@@ -697,22 +714,92 @@ static EVP_PKEY *rd_kafka_ssl_PKEY_from_string(rd_kafka_t *rk,
697
714
  return pkey;
698
715
  }
699
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
+
700
763
  /**
701
764
  * @brief Parse a PEM-formatted string into an X509 object.
765
+ * Rest of CA chain is pushed to the \p chainp stack.
702
766
  *
703
- * @param str Input PEM string, nul-terminated
767
+ * @param str Input PEM string, nul-terminated.
768
+ * @param chainp Stack to push the certificates to.
704
769
  *
705
770
  * @returns a new X509 on success or NULL on error.
771
+ *
772
+ * @remark When NULL is returned the chainp stack is not modified.
706
773
  */
707
- static X509 *rd_kafka_ssl_X509_from_string(rd_kafka_t *rk, const char *str) {
774
+ static X509 *rd_kafka_ssl_X509_from_string(rd_kafka_t *rk,
775
+ const char *str,
776
+ STACK_OF(X509) * chainp) {
708
777
  BIO *bio = BIO_new_mem_buf((void *)str, -1);
709
778
  X509 *x509;
710
779
 
711
780
  x509 =
712
781
  PEM_read_bio_X509(bio, NULL, rd_kafka_transport_ssl_passwd_cb, rk);
713
782
 
714
- BIO_free(bio);
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
+ }
715
801
 
802
+ BIO_free(bio);
716
803
  return x509;
717
804
  }
718
805
 
@@ -723,6 +810,7 @@ static X509 *rd_kafka_ssl_X509_from_string(rd_kafka_t *rk, const char *str) {
723
810
  * @brief Attempt load CA certificates from a Windows Certificate store.
724
811
  */
725
812
  static int rd_kafka_ssl_win_load_cert_store(rd_kafka_t *rk,
813
+ const char *ctx_identifier,
726
814
  SSL_CTX *ctx,
727
815
  const char *store_name) {
728
816
  HCERTSTORE w_store;
@@ -737,15 +825,16 @@ static int rd_kafka_ssl_win_load_cert_store(rd_kafka_t *rk,
737
825
  /* Convert store_name to wide-char */
738
826
  werr = mbstowcs_s(&wsize, NULL, 0, store_name, strlen(store_name));
739
827
  if (werr || wsize < 2 || wsize > 1000) {
740
- rd_kafka_log(rk, LOG_ERR, "CERTSTORE",
741
- "Invalid Windows certificate store name: %.*s%s",
742
- 30, store_name,
743
- wsize < 2 ? " (empty)" : " (truncated)");
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)");
744
833
  return -1;
745
834
  }
746
835
  wstore_name = rd_alloca(sizeof(*wstore_name) * wsize);
747
836
  werr = mbstowcs_s(NULL, wstore_name, wsize, store_name,
748
- strlen(store_name));
837
+ strlen(store_name));
749
838
  rd_assert(!werr);
750
839
 
751
840
  w_store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
@@ -756,9 +845,9 @@ static int rd_kafka_ssl_win_load_cert_store(rd_kafka_t *rk,
756
845
  if (!w_store) {
757
846
  rd_kafka_log(
758
847
  rk, LOG_ERR, "CERTSTORE",
759
- "Failed to open Windows certificate "
848
+ "%s: Failed to open Windows certificate "
760
849
  "%s store: %s",
761
- store_name,
850
+ ctx_identifier, store_name,
762
851
  rd_strerror_w32(GetLastError(), errstr, sizeof(errstr)));
763
852
  return -1;
764
853
  }
@@ -794,9 +883,9 @@ static int rd_kafka_ssl_win_load_cert_store(rd_kafka_t *rk,
794
883
  CertCloseStore(w_store, 0);
795
884
 
796
885
  rd_kafka_dbg(rk, SECURITY, "CERTSTORE",
797
- "%d certificate(s) successfully added from "
886
+ "%s: %d certificate(s) successfully added from "
798
887
  "Windows Certificate %s store, %d failed",
799
- cnt, store_name, fail_cnt);
888
+ ctx_identifier, cnt, store_name, fail_cnt);
800
889
 
801
890
  if (cnt == 0 && fail_cnt > 0)
802
891
  return -1;
@@ -809,9 +898,10 @@ static int rd_kafka_ssl_win_load_cert_store(rd_kafka_t *rk,
809
898
  *
810
899
  * @returns the number of successfully loaded certificates, or -1 on error.
811
900
  */
812
- static int rd_kafka_ssl_win_load_cert_stores(rd_kafka_t *rk,
813
- SSL_CTX *ctx,
814
- const char *store_names) {
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) {
815
905
  char *s;
816
906
  int cert_cnt = 0, fail_cnt = 0;
817
907
 
@@ -845,7 +935,8 @@ static int rd_kafka_ssl_win_load_cert_stores(rd_kafka_t *rk,
845
935
  s = "";
846
936
  }
847
937
 
848
- r = rd_kafka_ssl_win_load_cert_store(rk, ctx, store_name);
938
+ r = rd_kafka_ssl_win_load_cert_store(rk, ctx_identifier, ctx,
939
+ store_name);
849
940
  if (r != -1)
850
941
  cert_cnt += r;
851
942
  else
@@ -859,7 +950,32 @@ static int rd_kafka_ssl_win_load_cert_stores(rd_kafka_t *rk,
859
950
  }
860
951
  #endif /* MSC_VER */
861
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);
862
975
 
976
+ return SSL_CTX_load_verify_locations(ctx, *is_dir ? NULL : path,
977
+ *is_dir ? path : NULL);
978
+ }
863
979
 
864
980
  /**
865
981
  * @brief Probe for the system's CA certificate location and if found set it
@@ -867,8 +983,9 @@ static int rd_kafka_ssl_win_load_cert_stores(rd_kafka_t *rk,
867
983
  *
868
984
  * @returns 0 if CA location was set, else -1.
869
985
  */
870
- static int rd_kafka_ssl_probe_and_set_default_ca_location(rd_kafka_t *rk,
871
- SSL_CTX *ctx) {
986
+ int rd_kafka_ssl_probe_and_set_default_ca_location(rd_kafka_t *rk,
987
+ const char *ctx_identifier,
988
+ SSL_CTX *ctx) {
872
989
  #if _WIN32
873
990
  /* No standard location on Windows, CA certs are in the ROOT store. */
874
991
  return -1;
@@ -920,34 +1037,21 @@ static int rd_kafka_ssl_probe_and_set_default_ca_location(rd_kafka_t *rk,
920
1037
  int i;
921
1038
 
922
1039
  for (i = 0; (path = paths[i]); i++) {
923
- struct stat st;
924
1040
  rd_bool_t is_dir;
925
- int r;
926
-
927
- if (stat(path, &st) != 0)
1041
+ int r = rd_kafka_ssl_set_ca_path(rk, ctx_identifier, path, ctx,
1042
+ &is_dir);
1043
+ if (r == -1)
928
1044
  continue;
929
1045
 
930
- is_dir = S_ISDIR(st.st_mode);
931
-
932
- if (is_dir && rd_kafka_dir_is_empty(path))
933
- continue;
934
-
935
- rd_kafka_dbg(rk, SECURITY, "CACERTS",
936
- "Setting default CA certificate location "
937
- "to %s, override with ssl.ca.location",
938
- path);
939
-
940
- r = SSL_CTX_load_verify_locations(ctx, is_dir ? NULL : path,
941
- is_dir ? path : NULL);
942
1046
  if (r != 1) {
943
1047
  char errstr[512];
944
1048
  /* Read error and clear the error stack */
945
1049
  rd_kafka_ssl_error(rk, NULL, errstr, sizeof(errstr));
946
1050
  rd_kafka_dbg(rk, SECURITY, "CACERTS",
947
1051
  "Failed to set default CA certificate "
948
- "location to %s %s: %s: skipping",
1052
+ "location to %s %s for %s: %s: skipping",
949
1053
  is_dir ? "directory" : "file", path,
950
- errstr);
1054
+ ctx_identifier, errstr);
951
1055
  continue;
952
1056
  }
953
1057
 
@@ -956,11 +1060,108 @@ static int rd_kafka_ssl_probe_and_set_default_ca_location(rd_kafka_t *rk,
956
1060
 
957
1061
  rd_kafka_dbg(rk, SECURITY, "CACERTS",
958
1062
  "Unable to find any standard CA certificate"
959
- "paths: is the ca-certificates package installed?");
1063
+ "paths for %s: is the ca-certificates package installed?",
1064
+ ctx_identifier);
960
1065
  return -1;
961
1066
  #endif
962
1067
  }
963
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
+ }
964
1165
 
965
1166
  /**
966
1167
  * @brief Registers certificates, keys, etc, on the SSL_CTX
@@ -1080,7 +1281,7 @@ static int rd_kafka_ssl_set_certs(rd_kafka_t *rk,
1080
1281
  /* Attempt to load CA root certificates from the
1081
1282
  * configured Windows certificate stores. */
1082
1283
  r = rd_kafka_ssl_win_load_cert_stores(
1083
- rk, ctx, rk->rk_conf.ssl.ca_cert_stores);
1284
+ rk, "kafka", ctx, rk->rk_conf.ssl.ca_cert_stores);
1084
1285
  if (r == 0) {
1085
1286
  rd_kafka_log(
1086
1287
  rk, LOG_NOTICE, "CERTSTORE",
@@ -1111,8 +1312,8 @@ static int rd_kafka_ssl_set_certs(rd_kafka_t *rk,
1111
1312
  * of standard CA certificate paths and use the
1112
1313
  * first one that is found.
1113
1314
  * Ignore failures. */
1114
- r = rd_kafka_ssl_probe_and_set_default_ca_location(rk,
1115
- ctx);
1315
+ r = rd_kafka_ssl_probe_and_set_default_ca_location(
1316
+ rk, "kafka", ctx);
1116
1317
  }
1117
1318
 
1118
1319
  if (r == -1) {
@@ -1169,6 +1370,20 @@ static int rd_kafka_ssl_set_certs(rd_kafka_t *rk,
1169
1370
  rd_snprintf(errstr, errstr_size, "ssl_cert failed: ");
1170
1371
  return -1;
1171
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
+ }
1172
1387
  }
1173
1388
 
1174
1389
  if (rk->rk_conf.ssl.cert_location) {
@@ -1188,16 +1403,21 @@ static int rd_kafka_ssl_set_certs(rd_kafka_t *rk,
1188
1403
 
1189
1404
  if (rk->rk_conf.ssl.cert_pem) {
1190
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
+ }
1191
1410
 
1192
1411
  rd_kafka_dbg(rk, SECURITY, "SSL",
1193
1412
  "Loading public key from string");
1194
1413
 
1195
- x509 =
1196
- rd_kafka_ssl_X509_from_string(rk, rk->rk_conf.ssl.cert_pem);
1414
+ x509 = rd_kafka_ssl_X509_from_string(
1415
+ rk, rk->rk_conf.ssl.cert_pem, ca);
1197
1416
  if (!x509) {
1198
1417
  rd_snprintf(errstr, errstr_size,
1199
1418
  "ssl.certificate.pem failed: "
1200
1419
  "not in PEM format?: ");
1420
+ sk_X509_pop_free(ca, X509_free);
1201
1421
  return -1;
1202
1422
  }
1203
1423
 
@@ -1207,11 +1427,25 @@ static int rd_kafka_ssl_set_certs(rd_kafka_t *rk,
1207
1427
 
1208
1428
  if (r != 1) {
1209
1429
  rd_snprintf(errstr, errstr_size,
1210
- "ssl.certificate.pem failed: ");
1430
+ "ssl.certificate.pem failed: "
1431
+ "setting main certificate: ");
1432
+ sk_X509_pop_free(ca, X509_free);
1211
1433
  return -1;
1212
1434
  }
1213
- }
1214
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
+ }
1215
1449
 
1216
1450
  /*
1217
1451
  * ssl_key, ssl.key.location and ssl.key.pem
@@ -1284,8 +1518,8 @@ static int rd_kafka_ssl_set_certs(rd_kafka_t *rk,
1284
1518
  * ssl.keystore.location
1285
1519
  */
1286
1520
  if (rk->rk_conf.ssl.keystore_location) {
1287
- EVP_PKEY *pkey;
1288
- X509 *cert;
1521
+ EVP_PKEY *pkey = NULL;
1522
+ X509 *cert = NULL;
1289
1523
  STACK_OF(X509) *ca = NULL;
1290
1524
  BIO *bio;
1291
1525
  PKCS12 *p12;
@@ -1313,8 +1547,6 @@ static int rd_kafka_ssl_set_certs(rd_kafka_t *rk,
1313
1547
  return -1;
1314
1548
  }
1315
1549
 
1316
- pkey = EVP_PKEY_new();
1317
- cert = X509_new();
1318
1550
  if (!PKCS12_parse(p12, rk->rk_conf.ssl.keystore_password, &pkey,
1319
1551
  &cert, &ca)) {
1320
1552
  EVP_PKEY_free(pkey);
@@ -1330,28 +1562,17 @@ static int rd_kafka_ssl_set_certs(rd_kafka_t *rk,
1330
1562
  return -1;
1331
1563
  }
1332
1564
 
1333
- if (ca != NULL)
1334
- sk_X509_pop_free(ca, X509_free);
1335
-
1336
1565
  PKCS12_free(p12);
1337
1566
  BIO_free(bio);
1338
1567
 
1339
- r = SSL_CTX_use_certificate(ctx, cert);
1340
- X509_free(cert);
1341
- if (r != 1) {
1342
- EVP_PKEY_free(pkey);
1343
- rd_snprintf(errstr, errstr_size,
1344
- "Failed to use ssl.keystore.location "
1345
- "certificate: ");
1346
- return -1;
1347
- }
1348
-
1349
- r = SSL_CTX_use_PrivateKey(ctx, pkey);
1350
- EVP_PKEY_free(pkey);
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);
1351
1573
  if (r != 1) {
1352
1574
  rd_snprintf(errstr, errstr_size,
1353
- "Failed to use ssl.keystore.location "
1354
- "private key: ");
1575
+ "Failed to use ssl.keystore.location: ");
1355
1576
  return -1;
1356
1577
  }
1357
1578
 
@@ -1436,6 +1657,10 @@ static int rd_kafka_ssl_set_certs(rd_kafka_t *rk,
1436
1657
  return -1;
1437
1658
  }
1438
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
+
1439
1664
  return 0;
1440
1665
  }
1441
1666
 
@@ -1570,8 +1795,8 @@ static rd_bool_t rd_kafka_ssl_ctx_load_providers(rd_kafka_t *rk,
1570
1795
  OSSL_PROVIDER *prov;
1571
1796
  const char *buildinfo = NULL;
1572
1797
  OSSL_PARAM request[] = {{"buildinfo", OSSL_PARAM_UTF8_PTR,
1573
- (void *)&buildinfo, 0, 0},
1574
- {NULL, 0, NULL, 0, 0}};
1798
+ (void *)&buildinfo, 0, 0},
1799
+ {NULL, 0, NULL, 0, 0}};
1575
1800
 
1576
1801
  prov = OSSL_PROVIDER_load(NULL, provider);
1577
1802
  if (!prov) {
@@ -1821,7 +2046,7 @@ void rd_kafka_ssl_init(void) {
1821
2046
  if (!CRYPTO_get_locking_callback()) {
1822
2047
  rd_kafka_ssl_locks_cnt = CRYPTO_num_locks();
1823
2048
  rd_kafka_ssl_locks = rd_malloc(rd_kafka_ssl_locks_cnt *
1824
- sizeof(*rd_kafka_ssl_locks));
2049
+ sizeof(*rd_kafka_ssl_locks));
1825
2050
  for (i = 0; i < rd_kafka_ssl_locks_cnt; i++)
1826
2051
  mtx_init(&rd_kafka_ssl_locks[i], mtx_plain);
1827
2052