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