libmongocrypt-helper 1.8.0.0.1001 → 1.11.0.0.1001

Sign up to get free protection for your applications and to get access to all the features.
Files changed (385) hide show
  1. checksums.yaml +4 -4
  2. data/ext/libmongocrypt/libmongocrypt/CHANGELOG.md +33 -0
  3. data/ext/libmongocrypt/libmongocrypt/CMakeLists.txt +12 -1
  4. data/ext/libmongocrypt/libmongocrypt/CODEOWNERS +1 -4
  5. data/ext/libmongocrypt/libmongocrypt/Earthfile +151 -3
  6. data/ext/libmongocrypt/libmongocrypt/README.md +36 -40
  7. data/ext/libmongocrypt/libmongocrypt/bindings/cs/CMakeLists.txt +1 -0
  8. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Driver.snk +0 -0
  9. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt/AssemblyInfo.cs +2 -2
  10. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt/Binary.cs +16 -2
  11. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt/CryptClientFactory.cs +8 -4
  12. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt/Library.cs +10 -0
  13. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt/LibraryLoader.cs +81 -44
  14. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt/MongoDB.Libmongocrypt.csproj +2 -1
  15. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt.Test/MongoDB.Libmongocrypt.Test.csproj +2 -0
  16. data/ext/libmongocrypt/libmongocrypt/bindings/cs/MongoDB.Libmongocrypt.Test32/MongoDB.Libmongocrypt.Test32.csproj +2 -0
  17. data/ext/libmongocrypt/libmongocrypt/bindings/cs/README.md +3 -0
  18. data/ext/libmongocrypt/libmongocrypt/bindings/cs/Scripts/build.cake +21 -26
  19. data/ext/libmongocrypt/libmongocrypt/bindings/cs/Scripts/build.config +3 -0
  20. data/ext/libmongocrypt/libmongocrypt/bindings/cs/Scripts/build.sh +0 -0
  21. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/benchmarks/build.gradle.kts +28 -0
  22. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/benchmarks/src/main/java/com/mongodb/crypt/benchmark/BenchmarkRunner.java +217 -0
  23. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/benchmarks/src/main/resources/keyDocument.json +24 -0
  24. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/build.gradle.kts +21 -6
  25. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/gradle/wrapper/gradle-wrapper.jar +0 -0
  26. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/gradle/wrapper/gradle-wrapper.properties +1 -1
  27. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/gradlew +154 -108
  28. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/gradlew.bat +7 -18
  29. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/settings.gradle.kts +1 -0
  30. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/CAPI.java +41 -6
  31. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/CAPIHelper.java +5 -5
  32. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/CipherCallback.java +27 -1
  33. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/MongoCryptImpl.java +34 -19
  34. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/main/java/com/mongodb/crypt/capi/MongoExplicitEncryptOptions.java +6 -4
  35. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/main/resources/META-INF/native-image/jni-config.json +180 -0
  36. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/main/resources/META-INF/native-image/reflect-config.json +134 -0
  37. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/test/java/com/mongodb/crypt/capi/MongoCryptTest.java +44 -2
  38. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/test/resources/fle2-find-range-explicit-v2/int32/encrypted-payload.json +1 -1
  39. data/ext/libmongocrypt/libmongocrypt/bindings/java/mongocrypt/src/test/resources/fle2-find-range-explicit-v2/int32/rangeopts.json +3 -0
  40. data/ext/libmongocrypt/libmongocrypt/bindings/node/README.md +4 -900
  41. data/ext/libmongocrypt/libmongocrypt/bindings/python/CHANGELOG.rst +60 -0
  42. data/ext/libmongocrypt/libmongocrypt/bindings/python/README.rst +41 -20
  43. data/ext/libmongocrypt/libmongocrypt/bindings/python/RELEASE.rst +6 -24
  44. data/ext/libmongocrypt/libmongocrypt/bindings/python/build-manylinux-wheel.sh +4 -13
  45. data/ext/libmongocrypt/libmongocrypt/bindings/python/hatch_build.py +36 -0
  46. data/ext/libmongocrypt/libmongocrypt/bindings/python/libmongocrypt-version.txt +1 -0
  47. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/__init__.py +2 -2
  48. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/asynchronous/auto_encrypter.py +61 -0
  49. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/asynchronous/credentials.py +156 -0
  50. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/asynchronous/explicit_encrypter.py +156 -0
  51. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/asynchronous/state_machine.py +149 -0
  52. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/auto_encrypter.py +2 -46
  53. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/binary.py +14 -17
  54. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/binding.py +107 -61
  55. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/compat.py +6 -4
  56. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/credentials.py +2 -121
  57. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/crypto.py +31 -20
  58. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/errors.py +2 -2
  59. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/explicit_encrypter.py +2 -233
  60. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/mongocrypt.py +168 -238
  61. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/options.py +265 -0
  62. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/state_machine.py +2 -141
  63. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/synchronous/auto_encrypter.py +61 -0
  64. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/synchronous/credentials.py +156 -0
  65. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/synchronous/explicit_encrypter.py +156 -0
  66. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/synchronous/state_machine.py +149 -0
  67. data/ext/libmongocrypt/libmongocrypt/bindings/python/pymongocrypt/version.py +2 -2
  68. data/ext/libmongocrypt/libmongocrypt/bindings/python/pyproject.toml +118 -0
  69. data/ext/libmongocrypt/libmongocrypt/bindings/python/release.sh +97 -61
  70. data/ext/libmongocrypt/libmongocrypt/bindings/python/{test-requirements.txt → requirements-test.txt} +4 -1
  71. data/ext/libmongocrypt/libmongocrypt/bindings/python/requirements.txt +4 -0
  72. data/ext/libmongocrypt/libmongocrypt/bindings/python/sbom.json +76 -0
  73. data/ext/libmongocrypt/libmongocrypt/bindings/python/strip_header.py +6 -7
  74. data/ext/libmongocrypt/libmongocrypt/bindings/python/synchro.py +64 -0
  75. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/__init__.py +1 -0
  76. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/collection-info.json +1 -1
  77. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/command.json +1 -1
  78. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/compact/success/encrypted-payload.json +21 -21
  79. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/encrypted-command-reply.json +1 -1
  80. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/encrypted-field-config-map.json +1 -1
  81. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/fle2-find-range-explicit-v2/int32/encrypted-payload.json +1 -1
  82. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/fle2-find-range-explicit-v2/int32/rangeopts.json +3 -0
  83. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/fle2-find-rangePreview-explicit/int32/rangeopts.json +11 -0
  84. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/fle2-find-rangePreview-explicit/int32/value-to-encrypt.json +20 -0
  85. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/key-document-azure.json +1 -1
  86. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/key-document-gcp.json +1 -1
  87. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/key-document.json +1 -1
  88. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/key-filter.json +1 -1
  89. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/list-collections-filter.json +1 -1
  90. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/mongocryptd-command.json +1 -1
  91. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/mongocryptd-reply.json +1 -1
  92. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/data/schema-map.json +1 -1
  93. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/performance/keyDocument.json +24 -0
  94. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/performance/perf_test.py +165 -0
  95. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/test_binding.py +8 -12
  96. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/test_crypto.py +9 -11
  97. data/ext/libmongocrypt/libmongocrypt/bindings/python/test/test_mongocrypt.py +988 -340
  98. data/ext/libmongocrypt/libmongocrypt/bindings/python/update-sbom.sh +14 -0
  99. data/ext/libmongocrypt/libmongocrypt/cmake/FetchMongoC.cmake +19 -1
  100. data/ext/libmongocrypt/libmongocrypt/cmake/ImportBSON.cmake +23 -0
  101. data/ext/libmongocrypt/libmongocrypt/cmake/IntelDFP.cmake +19 -227
  102. data/ext/libmongocrypt/libmongocrypt/cmake/Patch.cmake +54 -0
  103. data/ext/libmongocrypt/libmongocrypt/doc/img/cli-icon.png +0 -0
  104. data/ext/libmongocrypt/libmongocrypt/doc/img/reference-targets.png +0 -0
  105. data/ext/libmongocrypt/libmongocrypt/doc/releasing.md +153 -0
  106. data/ext/libmongocrypt/libmongocrypt/etc/calc_release_version.py +61 -28
  107. data/ext/libmongocrypt/libmongocrypt/etc/calc_release_version_selftest.sh +73 -0
  108. data/ext/libmongocrypt/libmongocrypt/etc/cyclonedx.sbom.json +108 -0
  109. data/ext/libmongocrypt/libmongocrypt/etc/format.sh +1 -1
  110. data/ext/libmongocrypt/libmongocrypt/etc/libbson-remove-GCC-diagnostic-pragma.patch +27 -0
  111. data/ext/libmongocrypt/libmongocrypt/etc/mongo-inteldfp-alpine-arm-fix.patch +17 -0
  112. data/ext/libmongocrypt/libmongocrypt/etc/packager.py +120 -91
  113. data/ext/libmongocrypt/libmongocrypt/etc/purls.txt +14 -0
  114. data/ext/libmongocrypt/libmongocrypt/etc/repo_config.yaml +56 -0
  115. data/ext/libmongocrypt/libmongocrypt/etc/silk-create-asset-group.sh +70 -0
  116. data/ext/libmongocrypt/libmongocrypt/etc/ssdlc_compliance_report.md +37 -0
  117. data/ext/libmongocrypt/libmongocrypt/etc/third_party_vulnerabilities.md +42 -0
  118. data/ext/libmongocrypt/libmongocrypt/integrating.md +18 -1
  119. data/ext/libmongocrypt/libmongocrypt/kms-message/CMakeLists.txt +11 -3
  120. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_gcp_request.c +1 -1
  121. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_kmip_reader_writer.c +17 -0
  122. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_kmip_reader_writer_private.h +6 -0
  123. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_kmip_request.c +211 -1
  124. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_kmip_response.c +163 -0
  125. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_kmip_tag_type_private.h +2 -1
  126. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_message/kms_kmip_request.h +17 -0
  127. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_message/kms_kmip_response.h +6 -0
  128. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_port.c +3 -2
  129. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_request.c +4 -2
  130. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_request_str.c +2 -2
  131. data/ext/libmongocrypt/libmongocrypt/kms-message/test/test_kmip_reader_writer.c +23 -2
  132. data/ext/libmongocrypt/libmongocrypt/src/crypto/libcrypto.c +13 -10
  133. data/ext/libmongocrypt/libmongocrypt/src/mc-dec128.h +1 -1
  134. data/ext/libmongocrypt/libmongocrypt/src/mc-efc-private.h +16 -2
  135. data/ext/libmongocrypt/libmongocrypt/src/mc-efc.c +94 -6
  136. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-encryption-placeholder-private.h +15 -5
  137. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-encryption-placeholder.c +114 -53
  138. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-equality-payload-private-v2.h +1 -1
  139. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-equality-payload-private.h +1 -1
  140. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-equality-payload-v2.c +2 -2
  141. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-equality-payload.c +2 -2
  142. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-range-payload-private-v2.h +21 -6
  143. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-range-payload-private.h +5 -5
  144. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-range-payload-v2.c +38 -2
  145. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-find-range-payload.c +1 -1
  146. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-insert-update-payload-private-v2.h +20 -7
  147. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-insert-update-payload-private.h +8 -8
  148. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-insert-update-payload-v2.c +89 -1
  149. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-payload-iev-v2.c +3 -3
  150. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-payload-iev.c +1 -23
  151. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-rfds-private.h +4 -3
  152. data/ext/libmongocrypt/libmongocrypt/src/mc-fle2-rfds.c +15 -12
  153. data/ext/libmongocrypt/libmongocrypt/src/mc-optional-private.h +11 -0
  154. data/ext/libmongocrypt/libmongocrypt/src/mc-range-edge-generation-private.h +16 -6
  155. data/ext/libmongocrypt/libmongocrypt/src/mc-range-edge-generation.c +64 -22
  156. data/ext/libmongocrypt/libmongocrypt/src/mc-range-encoding-private.h +23 -4
  157. data/ext/libmongocrypt/libmongocrypt/src/mc-range-encoding.c +359 -65
  158. data/ext/libmongocrypt/libmongocrypt/src/mc-range-mincover-generator.template.h +26 -14
  159. data/ext/libmongocrypt/libmongocrypt/src/mc-range-mincover-private.h +17 -6
  160. data/ext/libmongocrypt/libmongocrypt/src/mc-range-mincover.c +31 -13
  161. data/ext/libmongocrypt/libmongocrypt/src/mc-rangeopts-private.h +16 -3
  162. data/ext/libmongocrypt/libmongocrypt/src/mc-rangeopts.c +259 -63
  163. data/ext/libmongocrypt/libmongocrypt/src/mc-tokens-private.h +40 -24
  164. data/ext/libmongocrypt/libmongocrypt/src/mc-tokens.c +57 -13
  165. data/ext/libmongocrypt/libmongocrypt/src/mlib/int128.h +17 -0
  166. data/ext/libmongocrypt/libmongocrypt/src/mlib/int128.test.cpp +5 -0
  167. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-binary-private.h +0 -5
  168. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-buffer.c +5 -7
  169. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-cache-key.c +1 -0
  170. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-cache-oauth-private.h +16 -18
  171. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-cache-oauth.c +105 -76
  172. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-crypto.c +9 -3
  173. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-ctx-datakey.c +170 -89
  174. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-ctx-decrypt.c +5 -5
  175. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-ctx-encrypt.c +505 -124
  176. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-ctx-private.h +31 -6
  177. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-ctx.c +81 -13
  178. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-dll-private.h +7 -0
  179. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-kek-private.h +5 -1
  180. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-kek.c +161 -103
  181. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-key-broker-private.h +2 -7
  182. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-key-broker.c +191 -69
  183. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-key.c +1 -1
  184. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-kms-ctx-private.h +50 -15
  185. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-kms-ctx.c +365 -69
  186. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-marking-private.h +2 -1
  187. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-marking.c +200 -107
  188. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-opts-private.h +50 -5
  189. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-opts.c +591 -15
  190. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-private.h +6 -13
  191. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-util.c +3 -2
  192. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt.c +47 -234
  193. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt.h +75 -24
  194. data/ext/libmongocrypt/libmongocrypt/src/os_posix/os_dll.c +18 -2
  195. data/ext/libmongocrypt/libmongocrypt/src/os_win/os_dll.c +4 -0
  196. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/bypassQueryAnalysis/payload.json +53 -0
  197. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/jsonSchema/cmd-to-mongocryptd.json +23 -0
  198. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/jsonSchema/cmd.json +20 -0
  199. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/simple/cmd-to-mongocryptd.json +50 -0
  200. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/simple/cmd.json +20 -0
  201. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/simple/collinfo.json +44 -0
  202. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/simple/encrypted-field-map.json +24 -0
  203. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/simple/encrypted-payload-pattern.json +53 -0
  204. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/simple/mongocryptd-reply.json +62 -0
  205. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/unencrypted/cmd-to-mongocryptd.json +30 -0
  206. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/unencrypted/cmd.json +17 -0
  207. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/unencrypted/mongocryptd-reply.json +39 -0
  208. data/ext/libmongocrypt/libmongocrypt/test/data/bulkWrite/unencrypted/payload.json +21 -0
  209. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/missing-key-id/collinfo.json +20 -0
  210. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/no-fields/collinfo.json +9 -0
  211. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/no-fields/encrypted-payload.json +4 -0
  212. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/success/cmd.json +1 -0
  213. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/success/collinfo.json +63 -0
  214. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/success/encrypted-field-config-map.json +61 -0
  215. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/success/encrypted-payload-range-v2.json +37 -0
  216. data/ext/libmongocrypt/libmongocrypt/test/data/cleanup/success/encrypted-payload.json +29 -0
  217. data/ext/libmongocrypt/libmongocrypt/test/data/compact/anchor-pad/cmd.json +1 -0
  218. data/ext/libmongocrypt/libmongocrypt/test/data/compact/anchor-pad/collinfo.json +64 -0
  219. data/ext/libmongocrypt/libmongocrypt/test/data/compact/anchor-pad/encrypted-payload-range-v2.json +105 -0
  220. data/ext/libmongocrypt/libmongocrypt/test/data/compact/anchor-pad/encrypted-payload.json +30 -0
  221. data/ext/libmongocrypt/libmongocrypt/test/data/compact/no-range/cmd.json +1 -0
  222. data/ext/libmongocrypt/libmongocrypt/test/data/compact/no-range/collinfo.json +49 -0
  223. data/ext/libmongocrypt/libmongocrypt/test/data/compact/no-range/encrypted-field-config-map.json +47 -0
  224. data/ext/libmongocrypt/libmongocrypt/test/data/compact/no-range/encrypted-payload.json +23 -0
  225. data/ext/libmongocrypt/libmongocrypt/test/data/compact/success/collinfo.json +15 -0
  226. data/ext/libmongocrypt/libmongocrypt/test/data/compact/success/encrypted-field-config-map.json +10 -0
  227. data/ext/libmongocrypt/libmongocrypt/test/data/compact/success/encrypted-payload-range-v2.json +104 -0
  228. data/ext/libmongocrypt/libmongocrypt/test/data/compact/success/encrypted-payload.json +6 -0
  229. data/ext/libmongocrypt/libmongocrypt/test/data/fle2-explain/with-csfle/collinfo.json +4 -4
  230. data/ext/libmongocrypt/libmongocrypt/test/data/fle2-explain/with-csfle/encrypted-payload.json +3 -3
  231. data/ext/libmongocrypt/libmongocrypt/test/data/kms-azure/decrypt-response.txt +16 -0
  232. data/ext/libmongocrypt/libmongocrypt/test/data/kms-azure/encrypt-response.txt +16 -0
  233. data/ext/libmongocrypt/libmongocrypt/test/data/kms-azure/oauth-response.txt +19 -0
  234. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/find/cmd.json +9 -0
  235. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/find/encrypted-field-map.json +19 -0
  236. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/find/encrypted-payload.json +62 -0
  237. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/find/mongocryptd-reply.json +69 -0
  238. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/insert/cmd.json +11 -0
  239. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/insert/encrypted-field-map.json +19 -0
  240. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/insert/encrypted-payload.json +40 -0
  241. data/ext/libmongocrypt/libmongocrypt/test/data/no-trimFactor/insert/mongocryptd-reply.json +47 -0
  242. data/ext/libmongocrypt/libmongocrypt/test/data/range-edge-generation/edges_decimal128.cstruct +1 -1
  243. data/ext/libmongocrypt/libmongocrypt/test/data/range-edge-generation/edges_double.cstruct +8637 -7958
  244. data/ext/libmongocrypt/libmongocrypt/test/data/range-edge-generation/edges_int32.cstruct +5522 -1382
  245. data/ext/libmongocrypt/libmongocrypt/test/data/range-edge-generation/edges_int64.cstruct +5042 -1262
  246. data/ext/libmongocrypt/libmongocrypt/test/data/range-min-cover/mincover_decimal128.cstruct +1 -1
  247. data/ext/libmongocrypt/libmongocrypt/test/data/range-min-cover/mincover_decimal128_precision.cstruct +1 -1
  248. data/ext/libmongocrypt/libmongocrypt/test/data/range-min-cover/mincover_double.cstruct +1 -1
  249. data/ext/libmongocrypt/libmongocrypt/test/data/range-min-cover/mincover_double_precision.cstruct +2 -2
  250. data/ext/libmongocrypt/libmongocrypt/test/data/range-min-cover/mincover_int32.cstruct +1 -1
  251. data/ext/libmongocrypt/libmongocrypt/test/data/range-min-cover/mincover_int64.cstruct +1 -1
  252. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-find-int32/cmd.json +8 -0
  253. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-find-int32/encrypted-field-map.json +19 -0
  254. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-find-int32/encrypted-payload.json +53 -0
  255. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-find-int32/mongocryptd-reply.json +58 -0
  256. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-insert-int32/cmd.json +11 -0
  257. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-insert-int32/encrypted-field-map.json +19 -0
  258. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-insert-int32/encrypted-payload.json +40 -0
  259. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/auto-insert-int32/mongocryptd-reply.json +45 -0
  260. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/explicit-find-int32/expected.json +26 -0
  261. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/explicit-find-int32/to-encrypt.json +20 -0
  262. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/explicit-find-int32-defaults/expected.json +26 -0
  263. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/explicit-find-int32-defaults/to-encrypt.json +20 -0
  264. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/explicit-insert-double/expected.json +8 -0
  265. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/explicit-insert-int32/expected.json +8 -0
  266. data/ext/libmongocrypt/libmongocrypt/test/data/range-sends-cryptoParams/explicit-insert-int32-defaults/expected.json +8 -0
  267. data/ext/libmongocrypt/libmongocrypt/test/data/tokens/README.md +7 -4
  268. data/ext/libmongocrypt/libmongocrypt/test/data/tokens/mc.json +9 -5
  269. data/ext/libmongocrypt/libmongocrypt/test/data/tokens/server.json +9 -5
  270. data/ext/libmongocrypt/libmongocrypt/test/example-state-machine.c +1 -0
  271. data/ext/libmongocrypt/libmongocrypt/test/test-gcp-auth.c +8 -8
  272. data/ext/libmongocrypt/libmongocrypt/test/test-mc-efc.c +6 -4
  273. data/ext/libmongocrypt/libmongocrypt/test/test-mc-fle2-find-range-payload-v2.c +43 -3
  274. data/ext/libmongocrypt/libmongocrypt/test/test-mc-fle2-payload-iup-v2.c +76 -0
  275. data/ext/libmongocrypt/libmongocrypt/test/test-mc-fle2-rfds.c +5 -5
  276. data/ext/libmongocrypt/libmongocrypt/test/test-mc-range-edge-generation.c +89 -14
  277. data/ext/libmongocrypt/libmongocrypt/test/test-mc-range-encoding.c +342 -76
  278. data/ext/libmongocrypt/libmongocrypt/test/test-mc-range-mincover.c +94 -12
  279. data/ext/libmongocrypt/libmongocrypt/test/test-mc-rangeopts.c +205 -7
  280. data/ext/libmongocrypt/libmongocrypt/test/test-mc-tokens.c +49 -23
  281. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-assert-match-bson.c +16 -19
  282. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-assert-match-bson.h +22 -1
  283. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-cache-oauth.c +94 -11
  284. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-cleanup.c +374 -0
  285. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-compact.c +121 -42
  286. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-crypto-hooks.c +134 -4
  287. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-crypto-std-hooks.c +40 -0
  288. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-crypto-std-hooks.h +16 -0
  289. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-csfle-lib.c +11 -11
  290. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-ctx-decrypt.c +8 -5
  291. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-ctx-encrypt.c +922 -92
  292. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-ctx-rewrap-many-datakey.c +2 -2
  293. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-ctx-setopt.c +114 -12
  294. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-datakey.c +14 -9
  295. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-kms-ctx.c +424 -3
  296. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-log.c +1 -1
  297. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-marking.c +447 -28
  298. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-opts.c +42 -0
  299. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-traverse-util.c +30 -26
  300. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-util.c +7 -0
  301. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-util.h +3 -0
  302. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt.c +66 -14
  303. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt.h +11 -0
  304. data/ext/libmongocrypt/libmongocrypt/test/test-named-kms-providers.c +2381 -0
  305. data/ext/libmongocrypt/libmongocrypt/test/util/HELP.autogen +3 -1
  306. data/ext/libmongocrypt/libmongocrypt/test/util/README.md +1 -0
  307. data/ext/libmongocrypt/libmongocrypt/test/util/csfle.c +4 -0
  308. data/ext/libmongocrypt/libmongocrypt/test/util/make_includes.py +1 -1
  309. data/ext/libmongocrypt/libmongocrypt/test/util/util.c +38 -3
  310. data/lib/libmongocrypt_helper/version.rb +2 -2
  311. metadata +112 -106
  312. checksums.yaml.gz.sig +0 -0
  313. data/ext/libmongocrypt/libmongocrypt/VERSION_CURRENT +0 -1
  314. data/ext/libmongocrypt/libmongocrypt/bindings/cs/cs.sln +0 -79
  315. data/ext/libmongocrypt/libmongocrypt/bindings/node/CHANGELOG.md +0 -105
  316. data/ext/libmongocrypt/libmongocrypt/bindings/node/LICENSE +0 -201
  317. data/ext/libmongocrypt/libmongocrypt/bindings/node/binding.gyp +0 -79
  318. data/ext/libmongocrypt/libmongocrypt/bindings/node/etc/README.hbs +0 -44
  319. data/ext/libmongocrypt/libmongocrypt/bindings/node/etc/build-static.sh +0 -36
  320. data/ext/libmongocrypt/libmongocrypt/bindings/node/index.d.ts +0 -641
  321. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/autoEncrypter.js +0 -420
  322. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/buffer_pool.js +0 -123
  323. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/clientEncryption.js +0 -821
  324. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/common.js +0 -98
  325. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/cryptoCallbacks.js +0 -87
  326. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/errors.js +0 -75
  327. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/index.js +0 -73
  328. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/mongocryptdManager.js +0 -66
  329. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/providers/aws.js +0 -26
  330. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/providers/azure.js +0 -178
  331. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/providers/gcp.js +0 -24
  332. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/providers/index.js +0 -54
  333. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/providers/utils.js +0 -39
  334. data/ext/libmongocrypt/libmongocrypt/bindings/node/lib/stateMachine.js +0 -492
  335. data/ext/libmongocrypt/libmongocrypt/bindings/node/package-lock.json +0 -15302
  336. data/ext/libmongocrypt/libmongocrypt/bindings/node/package.json +0 -100
  337. data/ext/libmongocrypt/libmongocrypt/bindings/node/src/mongocrypt.cc +0 -956
  338. data/ext/libmongocrypt/libmongocrypt/bindings/node/src/mongocrypt.h +0 -114
  339. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/autoEncrypter.test.js +0 -950
  340. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/buffer_pool.test.js +0 -91
  341. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/clientEncryption.test.js +0 -1093
  342. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/common.test.js +0 -94
  343. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/cryptoCallbacks.test.js +0 -240
  344. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/README.md +0 -5
  345. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/cmd.json +0 -6
  346. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/collection-info.json +0 -37
  347. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/encrypted-document-nested.json +0 -8
  348. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/encrypted-document.json +0 -11
  349. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/encryptedFields.json +0 -30
  350. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/key-document.json +0 -32
  351. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/key1-document.json +0 -30
  352. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/data/mongocryptd-reply.json +0 -18
  353. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/index.test.js +0 -45
  354. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/mongocryptdManager.test.js +0 -48
  355. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/providers/credentialsProvider.test.js +0 -551
  356. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/release.test.js +0 -66
  357. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/requirements.helper.js +0 -51
  358. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/stateMachine.test.js +0 -331
  359. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/tools/chai-addons.js +0 -8
  360. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/tools/mongodb_reporter.js +0 -325
  361. data/ext/libmongocrypt/libmongocrypt/bindings/node/test/types/index.test-d.ts +0 -63
  362. data/ext/libmongocrypt/libmongocrypt/bindings/python/setup.py +0 -89
  363. data/ext/libmongocrypt/libmongocrypt/debian/build_snapshot.sh +0 -79
  364. data/ext/libmongocrypt/libmongocrypt/debian/changelog +0 -105
  365. data/ext/libmongocrypt/libmongocrypt/debian/compat +0 -1
  366. data/ext/libmongocrypt/libmongocrypt/debian/control +0 -41
  367. data/ext/libmongocrypt/libmongocrypt/debian/copyright +0 -129
  368. data/ext/libmongocrypt/libmongocrypt/debian/gbp.conf +0 -23
  369. data/ext/libmongocrypt/libmongocrypt/debian/libmongocrypt-dev.dirs +0 -2
  370. data/ext/libmongocrypt/libmongocrypt/debian/libmongocrypt-dev.install +0 -5
  371. data/ext/libmongocrypt/libmongocrypt/debian/libmongocrypt0.dirs +0 -1
  372. data/ext/libmongocrypt/libmongocrypt/debian/libmongocrypt0.install +0 -1
  373. data/ext/libmongocrypt/libmongocrypt/debian/rules +0 -46
  374. data/ext/libmongocrypt/libmongocrypt/debian/source/format +0 -1
  375. data/ext/libmongocrypt/libmongocrypt/debian/source/lintian-overrides +0 -3
  376. data/ext/libmongocrypt/libmongocrypt/debian/source/options +0 -1
  377. data/ext/libmongocrypt/libmongocrypt/debian/watch +0 -3
  378. data/ext/libmongocrypt/libmongocrypt/test/data/compact/success/mongocryptd-reply.json +0 -72
  379. data.tar.gz.sig +0 -1
  380. metadata.gz.sig +0 -0
  381. /data/ext/libmongocrypt/libmongocrypt/{bindings/node/test/data/kms-decrypt-reply.txt → test/data/kms-aws/decrypt-response.txt} +0 -0
  382. /data/ext/libmongocrypt/libmongocrypt/{bindings/node/test/data/kms-encrypt-reply.txt → test/data/kms-aws/encrypt-response.txt} +0 -0
  383. /data/ext/libmongocrypt/libmongocrypt/test/data/{gcp-auth → kms-gcp}/decrypt-response.txt +0 -0
  384. /data/ext/libmongocrypt/libmongocrypt/test/data/{gcp-auth → kms-gcp}/encrypt-response.txt +0 -0
  385. /data/ext/libmongocrypt/libmongocrypt/test/data/{gcp-auth → kms-gcp}/oauth-response.txt +0 -0
@@ -14,6 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
+ #include "mc-efc-private.h"
17
18
  #include "mc-fle2-rfds-private.h"
18
19
  #include "mc-tokens-private.h"
19
20
  #include "mongocrypt-ciphertext-private.h"
@@ -23,6 +24,7 @@
23
24
  #include "mongocrypt-marking-private.h"
24
25
  #include "mongocrypt-traverse-util-private.h"
25
26
  #include "mongocrypt-util-private.h" // mc_iter_document_as_bson
27
+ #include "mongocrypt.h"
26
28
 
27
29
  /* _fle2_append_encryptedFieldConfig copies encryptedFieldConfig and applies
28
30
  * default state collection names for escCollection, eccCollection, and
@@ -30,7 +32,7 @@
30
32
  static bool _fle2_append_encryptedFieldConfig(const mongocrypt_ctx_t *ctx,
31
33
  bson_t *dst,
32
34
  bson_t *encryptedFieldConfig,
33
- const char *coll_name,
35
+ const char *target_coll,
34
36
  mongocrypt_status_t *status) {
35
37
  bson_iter_t iter;
36
38
  bool has_escCollection = false;
@@ -39,7 +41,7 @@ static bool _fle2_append_encryptedFieldConfig(const mongocrypt_ctx_t *ctx,
39
41
 
40
42
  BSON_ASSERT_PARAM(dst);
41
43
  BSON_ASSERT_PARAM(encryptedFieldConfig);
42
- BSON_ASSERT_PARAM(coll_name);
44
+ BSON_ASSERT_PARAM(target_coll);
43
45
 
44
46
  if (!bson_iter_init(&iter, encryptedFieldConfig)) {
45
47
  CLIENT_ERR("unable to iterate encryptedFieldConfig");
@@ -63,7 +65,7 @@ static bool _fle2_append_encryptedFieldConfig(const mongocrypt_ctx_t *ctx,
63
65
  }
64
66
 
65
67
  if (!has_escCollection) {
66
- char *default_escCollection = bson_strdup_printf("enxcol_.%s.esc", coll_name);
68
+ char *default_escCollection = bson_strdup_printf("enxcol_.%s.esc", target_coll);
67
69
  if (!BSON_APPEND_UTF8(dst, "escCollection", default_escCollection)) {
68
70
  CLIENT_ERR("unable to append escCollection");
69
71
  bson_free(default_escCollection);
@@ -72,7 +74,7 @@ static bool _fle2_append_encryptedFieldConfig(const mongocrypt_ctx_t *ctx,
72
74
  bson_free(default_escCollection);
73
75
  }
74
76
  if (!has_eccCollection && !ctx->crypt->opts.use_fle2_v2) {
75
- char *default_eccCollection = bson_strdup_printf("enxcol_.%s.ecc", coll_name);
77
+ char *default_eccCollection = bson_strdup_printf("enxcol_.%s.ecc", target_coll);
76
78
  if (!BSON_APPEND_UTF8(dst, "eccCollection", default_eccCollection)) {
77
79
  CLIENT_ERR("unable to append eccCollection");
78
80
  bson_free(default_eccCollection);
@@ -81,7 +83,7 @@ static bool _fle2_append_encryptedFieldConfig(const mongocrypt_ctx_t *ctx,
81
83
  bson_free(default_eccCollection);
82
84
  }
83
85
  if (!has_ecocCollection) {
84
- char *default_ecocCollection = bson_strdup_printf("enxcol_.%s.ecoc", coll_name);
86
+ char *default_ecocCollection = bson_strdup_printf("enxcol_.%s.ecoc", target_coll);
85
87
  if (!BSON_APPEND_UTF8(dst, "ecocCollection", default_ecocCollection)) {
86
88
  CLIENT_ERR("unable to append ecocCollection");
87
89
  bson_free(default_ecocCollection);
@@ -94,20 +96,20 @@ static bool _fle2_append_encryptedFieldConfig(const mongocrypt_ctx_t *ctx,
94
96
 
95
97
  static bool _fle2_append_encryptionInformation(const mongocrypt_ctx_t *ctx,
96
98
  bson_t *dst,
97
- const char *ns,
99
+ const char *target_ns,
98
100
  bson_t *encryptedFieldConfig,
99
101
  bson_t *deleteTokens,
100
- const char *coll_name,
102
+ const char *target_coll,
101
103
  mongocrypt_status_t *status) {
102
104
  bson_t encryption_information_bson;
103
105
  bson_t schema_bson;
104
106
  bson_t encrypted_field_config_bson;
105
107
 
106
108
  BSON_ASSERT_PARAM(dst);
107
- BSON_ASSERT_PARAM(ns);
109
+ BSON_ASSERT_PARAM(target_ns);
108
110
  BSON_ASSERT_PARAM(encryptedFieldConfig);
109
111
  /* deleteTokens may be NULL */
110
- BSON_ASSERT_PARAM(coll_name);
112
+ BSON_ASSERT_PARAM(target_coll);
111
113
 
112
114
  if (!BSON_APPEND_DOCUMENT_BEGIN(dst, "encryptionInformation", &encryption_information_bson)) {
113
115
  CLIENT_ERR("unable to begin appending 'encryptionInformation'");
@@ -122,7 +124,7 @@ static bool _fle2_append_encryptionInformation(const mongocrypt_ctx_t *ctx,
122
124
  return false;
123
125
  }
124
126
 
125
- if (!BSON_APPEND_DOCUMENT_BEGIN(&schema_bson, ns, &encrypted_field_config_bson)) {
127
+ if (!BSON_APPEND_DOCUMENT_BEGIN(&schema_bson, target_ns, &encrypted_field_config_bson)) {
126
128
  CLIENT_ERR("unable to begin appending 'encryptedFieldConfig' to "
127
129
  "'encryptionInformation'.'schema'");
128
130
  return false;
@@ -131,7 +133,7 @@ static bool _fle2_append_encryptionInformation(const mongocrypt_ctx_t *ctx,
131
133
  if (!_fle2_append_encryptedFieldConfig(ctx,
132
134
  &encrypted_field_config_bson,
133
135
  encryptedFieldConfig,
134
- coll_name,
136
+ target_coll,
135
137
  status)) {
136
138
  return false;
137
139
  }
@@ -153,8 +155,8 @@ static bool _fle2_append_encryptionInformation(const mongocrypt_ctx_t *ctx,
153
155
  "'encryptionInformation'");
154
156
  return false;
155
157
  }
156
- if (!BSON_APPEND_DOCUMENT(&delete_tokens_bson, ns, deleteTokens)) {
157
- CLIENT_ERR("unable to append '%s' to 'deleteTokens'", ns);
158
+ if (!BSON_APPEND_DOCUMENT(&delete_tokens_bson, target_ns, deleteTokens)) {
159
+ CLIENT_ERR("unable to append '%s' to 'deleteTokens'", target_ns);
158
160
  return false;
159
161
  }
160
162
  if (!bson_append_document_end(&encryption_information_bson, &delete_tokens_bson)) {
@@ -178,12 +180,12 @@ typedef enum { MC_TO_CSFLE, MC_TO_MONGOCRYPTD, MC_TO_MONGOD } mc_cmd_target_t;
178
180
  *
179
181
  * @param cmd_name The name of the command.
180
182
  * @param cmd The command being rewritten. It is an input and output.
181
- * @param ns The <db>.<collection> namespace for the command.
183
+ * @param target_ns The <db>.<collection> namespace for the command.
182
184
  * @param encryptedFieldConfig The "encryptedFields" document for the
183
185
  * collection.
184
186
  * @param deleteTokens Delete tokens to append to "encryptionInformation". May
185
187
  * be NULL.
186
- * @param coll_name The collection name.
188
+ * @param target_coll The collection name.
187
189
  * @param cmd_target The intended destination of the command. csfle,
188
190
  * mongocryptd, and mongod have different requirements for the location of
189
191
  * "encryptionInformation".
@@ -194,10 +196,10 @@ typedef enum { MC_TO_CSFLE, MC_TO_MONGOCRYPTD, MC_TO_MONGOD } mc_cmd_target_t;
194
196
  static bool _fle2_insert_encryptionInformation(const mongocrypt_ctx_t *ctx,
195
197
  const char *cmd_name,
196
198
  bson_t *cmd /* in and out */,
197
- const char *ns,
199
+ const char *target_ns,
198
200
  bson_t *encryptedFieldConfig,
199
201
  bson_t *deleteTokens,
200
- const char *coll_name,
202
+ const char *target_coll,
201
203
  mc_cmd_target_t cmd_target,
202
204
  mongocrypt_status_t *status) {
203
205
  bson_t out = BSON_INITIALIZER;
@@ -207,16 +209,96 @@ static bool _fle2_insert_encryptionInformation(const mongocrypt_ctx_t *ctx,
207
209
 
208
210
  BSON_ASSERT_PARAM(cmd_name);
209
211
  BSON_ASSERT_PARAM(cmd);
210
- BSON_ASSERT_PARAM(ns);
212
+ BSON_ASSERT_PARAM(target_ns);
211
213
  BSON_ASSERT_PARAM(encryptedFieldConfig);
212
214
  /* deleteTokens may be NULL */
213
- BSON_ASSERT_PARAM(coll_name);
215
+ BSON_ASSERT_PARAM(target_coll);
216
+
217
+ // For `bulkWrite`, append `encryptionInformation` inside the `nsInfo.0` document.
218
+ if (0 == strcmp(cmd_name, "bulkWrite")) {
219
+ // Get the single `nsInfo` document from the input command.
220
+ bson_t nsInfo; // Non-owning.
221
+ {
222
+ bson_iter_t nsInfo_iter;
223
+ if (!bson_iter_init(&nsInfo_iter, cmd)) {
224
+ CLIENT_ERR("failed to iterate command");
225
+ goto fail;
226
+ }
227
+ if (!bson_iter_find_descendant(&nsInfo_iter, "nsInfo.0", &nsInfo_iter)) {
228
+ CLIENT_ERR("expected one namespace in `bulkWrite`, but found zero.");
229
+ goto fail;
230
+ }
231
+ if (bson_has_field(cmd, "nsInfo.1")) {
232
+ CLIENT_ERR(
233
+ "expected one namespace in `bulkWrite`, but found more than one. Only one namespace is supported.");
234
+ goto fail;
235
+ }
236
+ if (!mc_iter_document_as_bson(&nsInfo_iter, &nsInfo, status)) {
237
+ goto fail;
238
+ }
239
+ // Ensure `nsInfo` does not already have an `encryptionInformation` field.
240
+ if (bson_has_field(&nsInfo, "encryptionInformation")) {
241
+ CLIENT_ERR("unexpected `encryptionInformation` present in input `nsInfo`.");
242
+ goto fail;
243
+ }
244
+ }
245
+
246
+ // Copy input and append `encryptionInformation` to `nsInfo`.
247
+ {
248
+ // Append everything from input except `nsInfo`.
249
+ bson_copy_to_excluding_noinit(cmd, &out, "nsInfo", NULL);
250
+ // Append `nsInfo` array.
251
+ bson_t nsInfo_array;
252
+ if (!BSON_APPEND_ARRAY_BEGIN(&out, "nsInfo", &nsInfo_array)) {
253
+ CLIENT_ERR("unable to begin appending 'nsInfo' array");
254
+ goto fail;
255
+ }
256
+ bson_t nsInfo_array_0;
257
+ if (!BSON_APPEND_DOCUMENT_BEGIN(&nsInfo_array, "0", &nsInfo_array_0)) {
258
+ CLIENT_ERR("unable to append 'nsInfo.0' document");
259
+ goto fail;
260
+ }
261
+ // Copy everything from input `nsInfo`.
262
+ bson_concat(&nsInfo_array_0, &nsInfo);
263
+ // And append `encryptionInformation`.
264
+ if (!_fle2_append_encryptionInformation(ctx,
265
+ &nsInfo_array_0,
266
+ target_ns,
267
+ encryptedFieldConfig,
268
+ deleteTokens,
269
+ target_coll,
270
+ status)) {
271
+ goto fail;
272
+ }
273
+ if (!bson_append_document_end(&nsInfo_array, &nsInfo_array_0)) {
274
+ CLIENT_ERR("unable to end appending 'nsInfo' document in array");
275
+ }
276
+ if (!bson_append_array_end(&out, &nsInfo_array)) {
277
+ CLIENT_ERR("unable to end appending 'nsInfo' array");
278
+ goto fail;
279
+ }
280
+ // Overwrite `cmd`.
281
+ bson_destroy(cmd);
282
+ if (!bson_steal(cmd, &out)) {
283
+ CLIENT_ERR("failed to steal BSON with encryptionInformation");
284
+ goto fail;
285
+ }
286
+ }
287
+
288
+ goto success;
289
+ }
214
290
 
215
291
  if (0 != strcmp(cmd_name, "explain") || cmd_target == MC_TO_MONGOCRYPTD) {
216
- // All commands except "explain" expect "encryptionInformation"
292
+ // All commands except "explain" and "bulkWrite" expect "encryptionInformation"
217
293
  // at top-level. "explain" sent to mongocryptd expects
218
294
  // "encryptionInformation" at top-level.
219
- if (!_fle2_append_encryptionInformation(ctx, cmd, ns, encryptedFieldConfig, deleteTokens, coll_name, status)) {
295
+ if (!_fle2_append_encryptionInformation(ctx,
296
+ cmd,
297
+ target_ns,
298
+ encryptedFieldConfig,
299
+ deleteTokens,
300
+ target_coll,
301
+ status)) {
220
302
  goto fail;
221
303
  }
222
304
  bson_destroy(&out);
@@ -253,7 +335,13 @@ static bool _fle2_insert_encryptionInformation(const mongocrypt_ctx_t *ctx,
253
335
  bson_copy_to(&tmp, &explain);
254
336
  }
255
337
 
256
- if (!_fle2_append_encryptionInformation(ctx, &explain, ns, encryptedFieldConfig, deleteTokens, coll_name, status)) {
338
+ if (!_fle2_append_encryptionInformation(ctx,
339
+ &explain,
340
+ target_ns,
341
+ encryptedFieldConfig,
342
+ deleteTokens,
343
+ target_coll,
344
+ status)) {
257
345
  goto fail;
258
346
  }
259
347
 
@@ -265,7 +353,7 @@ static bool _fle2_insert_encryptionInformation(const mongocrypt_ctx_t *ctx,
265
353
  bson_copy_to_excluding_noinit(cmd, &out, "explain", NULL);
266
354
  bson_destroy(cmd);
267
355
  if (!bson_steal(cmd, &out)) {
268
- CLIENT_ERR("failed to steal BSON without encryptionInformation");
356
+ CLIENT_ERR("failed to steal BSON with encryptionInformation");
269
357
  goto fail;
270
358
  }
271
359
 
@@ -288,7 +376,7 @@ static bool _mongo_op_collinfo(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out)
288
376
  BSON_ASSERT_PARAM(out);
289
377
 
290
378
  ectx = (_mongocrypt_ctx_encrypt_t *)ctx;
291
- cmd = BCON_NEW("name", BCON_UTF8(ectx->coll_name));
379
+ cmd = BCON_NEW("name", BCON_UTF8(ectx->target_coll));
292
380
  CRYPT_TRACEF(&ectx->parent.crypt->log, "constructed: %s\n", tmp_json(cmd));
293
381
  _mongocrypt_buffer_steal_from_bson(&ectx->list_collections_filter, cmd);
294
382
  out->data = ectx->list_collections_filter.data;
@@ -328,10 +416,46 @@ static bool _set_schema_from_collinfo(mongocrypt_ctx_t *ctx, bson_t *collinfo) {
328
416
  if (!_mongocrypt_buffer_to_bson(&ectx->encrypted_field_config, &efc_bson)) {
329
417
  return _mongocrypt_ctx_fail_w_msg(ctx, "unable to create BSON from encrypted_field_config");
330
418
  }
331
- if (!mc_EncryptedFieldConfig_parse(&ectx->efc, &efc_bson, ctx->status)) {
419
+ if (!mc_EncryptedFieldConfig_parse(&ectx->efc, &efc_bson, ctx->status, ctx->crypt->opts.use_range_v2)) {
332
420
  _mongocrypt_ctx_fail(ctx);
333
421
  return false;
334
422
  }
423
+ } else if (0 == strcmp(ectx->cmd_name, "bulkWrite")) {
424
+ ectx->used_empty_encryptedFields = true;
425
+ // `bulkWrite` is a special case. Sending `bulkWrite` with `jsonSchema` to query analysis results in an error:
426
+ // `The bulkWrite command only supports Queryable Encryption`
427
+ //
428
+ // Add an empty encryptedFields (rather than an empty JSON schema) to ensure `bulkWrite` can be sent to query
429
+ // analysis.
430
+ bson_t empty_encryptedFields = BSON_INITIALIZER;
431
+ {
432
+ char *escCollection = bson_strdup_printf("enxcol_.%s.esc", ectx->target_coll);
433
+ char *ecocCollection = bson_strdup_printf("enxcol_.%s.ecoc", ectx->target_coll);
434
+ bson_t empty_array = BSON_INITIALIZER;
435
+ if (!BSON_APPEND_UTF8(&empty_encryptedFields, "escCollection", escCollection)) {
436
+ return _mongocrypt_ctx_fail_w_msg(ctx, "failed to append `escCollection`");
437
+ }
438
+ if (!BSON_APPEND_UTF8(&empty_encryptedFields, "ecocCollection", ecocCollection)) {
439
+ return _mongocrypt_ctx_fail_w_msg(ctx, "failed to append `ecocCollection`");
440
+ }
441
+ if (!BSON_APPEND_ARRAY(&empty_encryptedFields, "fields", &empty_array)) {
442
+ return _mongocrypt_ctx_fail_w_msg(ctx, "failed to append `fields`");
443
+ }
444
+
445
+ bson_destroy(&empty_array);
446
+ bson_free(escCollection);
447
+ bson_free(ecocCollection);
448
+ }
449
+
450
+ if (!mc_EncryptedFieldConfig_parse(&ectx->efc,
451
+ &empty_encryptedFields,
452
+ ctx->status,
453
+ ctx->crypt->opts.use_range_v2)) {
454
+ bson_destroy(&empty_encryptedFields);
455
+ _mongocrypt_ctx_fail(ctx);
456
+ return false;
457
+ }
458
+ _mongocrypt_buffer_steal_from_bson(&ectx->encrypted_field_config, &empty_encryptedFields);
335
459
  }
336
460
 
337
461
  BSON_ASSERT(bson_iter_init(&iter, collinfo));
@@ -458,7 +582,7 @@ static bool _fle2_collect_keys_for_deleteTokens(mongocrypt_ctx_t *ctx) {
458
582
  mc_EncryptedField_t *field;
459
583
 
460
584
  for (field = ectx->efc.fields; field != NULL; field = field->next) {
461
- if (field->has_queries) {
585
+ if (field->supported_queries) {
462
586
  if (!_mongocrypt_key_broker_request_id(&ctx->kb, &field->keyId)) {
463
587
  _mongocrypt_key_broker_status(&ctx->kb, ctx->status);
464
588
  _mongocrypt_ctx_fail(ctx);
@@ -469,9 +593,10 @@ static bool _fle2_collect_keys_for_deleteTokens(mongocrypt_ctx_t *ctx) {
469
593
  return true;
470
594
  }
471
595
 
472
- /* _fle2_collect_keys_for_compact requests keys required to produce
473
- * compactionTokens. compactionTokens is only applicable to FLE 2. */
474
- static bool _fle2_collect_keys_for_compact(mongocrypt_ctx_t *ctx) {
596
+ /* _fle2_collect_keys_for_compaction requests keys required to produce
597
+ * compactionTokens or cleanupTokens.
598
+ * compactionTokens and cleanupTokens are only applicable to FLE 2. */
599
+ static bool _fle2_collect_keys_for_compaction(mongocrypt_ctx_t *ctx) {
475
600
  _mongocrypt_ctx_encrypt_t *ectx = (_mongocrypt_ctx_encrypt_t *)ctx;
476
601
 
477
602
  BSON_ASSERT_PARAM(ctx);
@@ -483,11 +608,12 @@ static bool _fle2_collect_keys_for_compact(mongocrypt_ctx_t *ctx) {
483
608
 
484
609
  const char *cmd_name = ectx->cmd_name;
485
610
 
486
- if (0 != strcmp(cmd_name, "compactStructuredEncryptionData")) {
611
+ if (0 != strcmp(cmd_name, "compactStructuredEncryptionData")
612
+ && 0 != strcmp(cmd_name, "cleanupStructuredEncryptionData")) {
487
613
  return true;
488
614
  }
489
615
 
490
- /* compactStructuredEncryptionData must not be sent to mongocryptd. */
616
+ /* (compact/cleanup)StructuredEncryptionData must not be sent to mongocryptd. */
491
617
  ectx->bypass_query_analysis = true;
492
618
 
493
619
  mc_EncryptedField_t *field;
@@ -516,7 +642,7 @@ static bool _mongo_feed_collinfo(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *in)
516
642
  }
517
643
 
518
644
  /* Cache the received collinfo. */
519
- if (!_mongocrypt_cache_add_copy(&ctx->crypt->cache_collinfo, ectx->ns, &as_bson, ctx->status)) {
645
+ if (!_mongocrypt_cache_add_copy(&ctx->crypt->cache_collinfo, ectx->target_ns, &as_bson, ctx->status)) {
520
646
  return _mongocrypt_ctx_fail(ctx);
521
647
  }
522
648
 
@@ -538,8 +664,12 @@ static bool _mongo_done_collinfo(mongocrypt_ctx_t *ctx) {
538
664
  if (_mongocrypt_buffer_empty(&ectx->schema)) {
539
665
  bson_t empty_collinfo = BSON_INITIALIZER;
540
666
 
541
- /* If no collinfo was fed, cache an empty collinfo. */
542
- if (!_mongocrypt_cache_add_copy(&ctx->crypt->cache_collinfo, ectx->ns, &empty_collinfo, ctx->status)) {
667
+ /* If no collinfo was fed, apply and cache an empty collinfo. */
668
+ if (!_set_schema_from_collinfo(ctx, &empty_collinfo)) {
669
+ bson_destroy(&empty_collinfo);
670
+ return false;
671
+ }
672
+ if (!_mongocrypt_cache_add_copy(&ctx->crypt->cache_collinfo, ectx->target_ns, &empty_collinfo, ctx->status)) {
543
673
  bson_destroy(&empty_collinfo);
544
674
  return _mongocrypt_ctx_fail(ctx);
545
675
  }
@@ -550,7 +680,7 @@ static bool _mongo_done_collinfo(mongocrypt_ctx_t *ctx) {
550
680
  return false;
551
681
  }
552
682
 
553
- if (!_fle2_collect_keys_for_compact(ctx)) {
683
+ if (!_fle2_collect_keys_for_compaction(ctx)) {
554
684
  return false;
555
685
  }
556
686
 
@@ -564,6 +694,19 @@ static bool _mongo_done_collinfo(mongocrypt_ctx_t *ctx) {
564
694
  return _try_run_csfle_marking(ctx);
565
695
  }
566
696
 
697
+ static const char *_mongo_db_collinfo(mongocrypt_ctx_t *ctx) {
698
+ _mongocrypt_ctx_encrypt_t *ectx;
699
+
700
+ BSON_ASSERT_PARAM(ctx);
701
+
702
+ ectx = (_mongocrypt_ctx_encrypt_t *)ctx;
703
+ if (!ectx->target_db) {
704
+ _mongocrypt_ctx_fail_w_msg(ctx, "Expected target database for `listCollections`, but none exists.");
705
+ return NULL;
706
+ }
707
+ return ectx->target_db;
708
+ }
709
+
567
710
  static bool _fle2_mongo_op_markings(mongocrypt_ctx_t *ctx, bson_t *out) {
568
711
  _mongocrypt_ctx_encrypt_t *ectx;
569
712
  bson_t cmd_bson = BSON_INITIALIZER, encrypted_field_config_bson = BSON_INITIALIZER;
@@ -594,10 +737,10 @@ static bool _fle2_mongo_op_markings(mongocrypt_ctx_t *ctx, bson_t *out) {
594
737
  if (!_fle2_insert_encryptionInformation(ctx,
595
738
  cmd_name,
596
739
  out,
597
- ectx->ns,
740
+ ectx->target_ns,
598
741
  &encrypted_field_config_bson,
599
742
  NULL /* deleteTokens */,
600
- ectx->coll_name,
743
+ ectx->target_coll,
601
744
  ctx->crypt->csfle.okay ? MC_TO_CSFLE : MC_TO_MONGOCRYPTD,
602
745
  ctx->status)) {
603
746
  return _mongocrypt_ctx_fail(ctx);
@@ -734,7 +877,7 @@ static bool _collect_key_from_marking(void *ctx, _mongocrypt_buffer_t *in, mongo
734
877
  static bool _mongo_feed_markings(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *in) {
735
878
  /* Find keys. */
736
879
  bson_t as_bson;
737
- bson_iter_t iter;
880
+ bson_iter_t iter = {0};
738
881
  _mongocrypt_ctx_encrypt_t *ectx;
739
882
 
740
883
  BSON_ASSERT_PARAM(ctx);
@@ -823,7 +966,7 @@ static bool _mongo_done_markings(mongocrypt_ctx_t *ctx) {
823
966
  /**
824
967
  * @brief Append $db to a command being passed to csfle.
825
968
  */
826
- static bool _add_dollar_db(const char *cmd_name, bson_t *cmd, const char *db_name, mongocrypt_status_t *status) {
969
+ static bool _add_dollar_db(const char *cmd_name, bson_t *cmd, const char *cmd_db, mongocrypt_status_t *status) {
827
970
  bson_t out = BSON_INITIALIZER;
828
971
  bson_t explain = BSON_INITIALIZER;
829
972
  bson_iter_t iter;
@@ -831,10 +974,10 @@ static bool _add_dollar_db(const char *cmd_name, bson_t *cmd, const char *db_nam
831
974
 
832
975
  BSON_ASSERT_PARAM(cmd_name);
833
976
  BSON_ASSERT_PARAM(cmd);
834
- BSON_ASSERT_PARAM(db_name);
977
+ BSON_ASSERT_PARAM(cmd_db);
835
978
 
836
979
  if (!bson_iter_init_find(&iter, cmd, "$db")) {
837
- if (!BSON_APPEND_UTF8(cmd, "$db", db_name)) {
980
+ if (!BSON_APPEND_UTF8(cmd, "$db", cmd_db)) {
838
981
  CLIENT_ERR("failed to append '$db'");
839
982
  goto fail;
840
983
  }
@@ -868,7 +1011,7 @@ static bool _add_dollar_db(const char *cmd_name, bson_t *cmd, const char *db_nam
868
1011
  bson_copy_to(&tmp, &explain);
869
1012
  }
870
1013
 
871
- if (!BSON_APPEND_UTF8(&explain, "$db", db_name)) {
1014
+ if (!BSON_APPEND_UTF8(&explain, "$db", cmd_db)) {
872
1015
  CLIENT_ERR("failed to append '$db'");
873
1016
  goto fail;
874
1017
  }
@@ -947,7 +1090,7 @@ static bool _try_run_csfle_marking(mongocrypt_ctx_t *ctx) {
947
1090
 
948
1091
  const char *cmd_name = ectx->cmd_name;
949
1092
 
950
- if (!_add_dollar_db(cmd_name, &cmd, ectx->db_name, ctx->status)) {
1093
+ if (!_add_dollar_db(cmd_name, &cmd, ectx->cmd_db, ctx->status)) {
951
1094
  _mongocrypt_ctx_fail(ctx);
952
1095
  goto fail_create_cmd;
953
1096
  }
@@ -975,8 +1118,12 @@ static bool _try_run_csfle_marking(mongocrypt_ctx_t *ctx) {
975
1118
  CHECK_CSFLE_ERROR("query_analyzer_create", fail_qa_create);
976
1119
 
977
1120
  uint32_t marked_bson_len = 0;
978
- uint8_t *marked_bson =
979
- csfle.analyze_query(qa, bson_get_data(&cmd), ectx->ns, (uint32_t)strlen(ectx->ns), &marked_bson_len, status);
1121
+ uint8_t *marked_bson = csfle.analyze_query(qa,
1122
+ bson_get_data(&cmd),
1123
+ ectx->target_ns,
1124
+ (uint32_t)strlen(ectx->target_ns),
1125
+ &marked_bson_len,
1126
+ status);
980
1127
  CHECK_CSFLE_ERROR("analyze_query", fail_analyze_query);
981
1128
 
982
1129
  // Copy out the marked document.
@@ -1107,7 +1254,7 @@ static bson_t *generate_delete_tokens(_mongocrypt_crypto_t *crypto,
1107
1254
  mc_ECOCToken_t *ecoc = NULL;
1108
1255
  bool loop_ok = false;
1109
1256
  /* deleteTokens are only necessary for indexed fields. */
1110
- if (!ef->has_queries) {
1257
+ if (!ef->supported_queries) {
1111
1258
  goto loop_continue;
1112
1259
  }
1113
1260
 
@@ -1223,8 +1370,11 @@ typedef struct {
1223
1370
 
1224
1371
  // must_omit_encryptionInformation returns true if the command
1225
1372
  // must omit the "encryptionInformation" field when sent to mongod / mongos.
1226
- static moe_result
1227
- must_omit_encryptionInformation(const char *command_name, const bson_t *command, mongocrypt_status_t *status) {
1373
+ static moe_result must_omit_encryptionInformation(const char *command_name,
1374
+ const bson_t *command,
1375
+ bool use_range_v2,
1376
+ const mc_EncryptedFieldConfig_t *efc,
1377
+ mongocrypt_status_t *status) {
1228
1378
  // eligible_commands may omit encryptionInformation if the command does not
1229
1379
  // contain payloads requiring encryption.
1230
1380
  const char *eligible_commands[] = {"find", "aggregate", "distinct", "count", "insert"};
@@ -1232,10 +1382,28 @@ must_omit_encryptionInformation(const char *command_name, const bson_t *command,
1232
1382
  bool found = false;
1233
1383
 
1234
1384
  // prohibited_commands prohibit encryptionInformation on mongod / mongos.
1235
- const char *prohibited_commands[] = {"compactStructuredEncryptionData", "create", "collMod", "createIndexes"};
1385
+ const char *prohibited_commands[] = {"cleanupStructuredEncryptionData", "create", "collMod", "createIndexes"};
1236
1386
 
1237
1387
  BSON_ASSERT_PARAM(command_name);
1238
1388
  BSON_ASSERT_PARAM(command);
1389
+ BSON_ASSERT_PARAM(efc);
1390
+
1391
+ if (0 == strcmp("compactStructuredEncryptionData", command_name)) {
1392
+ // `compactStructuredEncryptionData` is a special case:
1393
+ // - Server 7.0 prohibits `encryptionInformation`.
1394
+ // - Server 8.0 requires `encryptionInformation` if "range" fields are referenced. Otherwise ignores.
1395
+ // Only send `encryptionInformation` if "range" fields are present to support both server versions.
1396
+ bool uses_range_fields = false;
1397
+ if (use_range_v2) {
1398
+ for (const mc_EncryptedField_t *ef = efc->fields; ef != NULL; ef = ef->next) {
1399
+ if (ef->supported_queries & SUPPORTS_RANGE_QUERIES) {
1400
+ uses_range_fields = true;
1401
+ break;
1402
+ }
1403
+ }
1404
+ }
1405
+ return (moe_result){.ok = true, .must_omit = !uses_range_fields};
1406
+ }
1239
1407
 
1240
1408
  for (i = 0; i < sizeof(prohibited_commands) / sizeof(prohibited_commands[0]); i++) {
1241
1409
  if (0 == strcmp(prohibited_commands[i], command_name)) {
@@ -1254,7 +1422,7 @@ must_omit_encryptionInformation(const char *command_name, const bson_t *command,
1254
1422
  }
1255
1423
 
1256
1424
  bool has_payload_requiring_encryptionInformation = false;
1257
- bson_iter_t iter;
1425
+ bson_iter_t iter = {0};
1258
1426
  if (!bson_iter_init(&iter, command)) {
1259
1427
  CLIENT_ERR("unable to iterate command");
1260
1428
  return (moe_result){.ok = false};
@@ -1274,35 +1442,46 @@ must_omit_encryptionInformation(const char *command_name, const bson_t *command,
1274
1442
  }
1275
1443
 
1276
1444
  /* _fle2_append_compactionTokens appends compactionTokens if command_name is
1277
- * "compactStructuredEncryptionData" */
1278
- static bool _fle2_append_compactionTokens(_mongocrypt_crypto_t *crypto,
1445
+ * "compactStructuredEncryptionData" or cleanupTokens if command_name is
1446
+ * "cleanupStructuredEncryptionData"
1447
+ */
1448
+ static bool _fle2_append_compactionTokens(mongocrypt_t *crypt,
1279
1449
  _mongocrypt_key_broker_t *kb,
1280
1450
  mc_EncryptedFieldConfig_t *efc,
1281
1451
  const char *command_name,
1282
1452
  bson_t *out,
1283
1453
  mongocrypt_status_t *status) {
1284
- bson_t result_compactionTokens;
1454
+ bson_t result_compactionTokens = BSON_INITIALIZER;
1285
1455
  bool ret = false;
1286
1456
 
1287
- BSON_ASSERT_PARAM(crypto);
1457
+ BSON_ASSERT_PARAM(crypt);
1288
1458
  BSON_ASSERT_PARAM(kb);
1289
1459
  BSON_ASSERT_PARAM(efc);
1290
1460
  BSON_ASSERT_PARAM(command_name);
1291
1461
  BSON_ASSERT_PARAM(out);
1462
+ _mongocrypt_crypto_t *crypto = crypt->crypto;
1292
1463
 
1293
- if (0 != strcmp(command_name, "compactStructuredEncryptionData")) {
1464
+ bool cleanup = (0 == strcmp(command_name, "cleanupStructuredEncryptionData"));
1465
+
1466
+ if (0 != strcmp(command_name, "compactStructuredEncryptionData") && !cleanup) {
1294
1467
  return true;
1295
1468
  }
1296
1469
 
1297
- BSON_APPEND_DOCUMENT_BEGIN(out, "compactionTokens", &result_compactionTokens);
1470
+ if (cleanup) {
1471
+ BSON_APPEND_DOCUMENT_BEGIN(out, "cleanupTokens", &result_compactionTokens);
1472
+ } else {
1473
+ BSON_APPEND_DOCUMENT_BEGIN(out, "compactionTokens", &result_compactionTokens);
1474
+ }
1298
1475
 
1299
1476
  mc_EncryptedField_t *ptr;
1300
1477
  for (ptr = efc->fields; ptr != NULL; ptr = ptr->next) {
1301
- /* Append ECOC token. */
1478
+ /* Append tokens. */
1302
1479
  _mongocrypt_buffer_t key = {0};
1303
1480
  _mongocrypt_buffer_t tokenkey = {0};
1304
1481
  mc_CollectionsLevel1Token_t *cl1t = NULL;
1305
1482
  mc_ECOCToken_t *ecoct = NULL;
1483
+ mc_ESCToken_t *esct = NULL;
1484
+ mc_AnchorPaddingTokenRoot_t *padt = NULL;
1306
1485
  bool ecoc_ok = false;
1307
1486
 
1308
1487
  if (!_mongocrypt_key_broker_decrypted_key_by_id(kb, &ptr->keyId, &key)) {
@@ -1333,10 +1512,35 @@ static bool _fle2_append_compactionTokens(_mongocrypt_crypto_t *crypto,
1333
1512
 
1334
1513
  const _mongocrypt_buffer_t *ecoct_buf = mc_ECOCToken_get(ecoct);
1335
1514
 
1336
- BSON_APPEND_BINARY(&result_compactionTokens, ptr->path, BSON_SUBTYPE_BINARY, ecoct_buf->data, ecoct_buf->len);
1515
+ if (crypt->opts.use_range_v2 && (ptr->supported_queries & SUPPORTS_RANGE_QUERIES)) {
1516
+ // Append the document {ecoc: <ECOCToken>, anchorPaddingToken: <AnchorPaddingTokenRoot>}
1517
+ esct = mc_ESCToken_new(crypto, cl1t, status);
1518
+ if (!esct) {
1519
+ goto ecoc_fail;
1520
+ }
1521
+ padt = mc_AnchorPaddingTokenRoot_new(crypto, esct, status);
1522
+ if (!padt) {
1523
+ goto ecoc_fail;
1524
+ }
1525
+ const _mongocrypt_buffer_t *padt_buf = mc_AnchorPaddingTokenRoot_get(padt);
1526
+ bson_t tokenDoc;
1527
+ BSON_APPEND_DOCUMENT_BEGIN(&result_compactionTokens, ptr->path, &tokenDoc);
1528
+ BSON_APPEND_BINARY(&tokenDoc, "ecoc", BSON_SUBTYPE_BINARY, ecoct_buf->data, ecoct_buf->len);
1529
+ BSON_APPEND_BINARY(&tokenDoc, "anchorPaddingToken", BSON_SUBTYPE_BINARY, padt_buf->data, padt_buf->len);
1530
+ bson_append_document_end(&result_compactionTokens, &tokenDoc);
1531
+ } else {
1532
+ // Append just <ECOCToken>
1533
+ BSON_APPEND_BINARY(&result_compactionTokens,
1534
+ ptr->path,
1535
+ BSON_SUBTYPE_BINARY,
1536
+ ecoct_buf->data,
1537
+ ecoct_buf->len);
1538
+ }
1337
1539
 
1338
1540
  ecoc_ok = true;
1339
1541
  ecoc_fail:
1542
+ mc_AnchorPaddingTokenRoot_destroy(padt);
1543
+ mc_ESCToken_destroy(esct);
1340
1544
  mc_ECOCToken_destroy(ecoct);
1341
1545
  mc_CollectionsLevel1Token_destroy(cl1t);
1342
1546
  _mongocrypt_buffer_cleanup(&key);
@@ -1363,11 +1567,63 @@ _fle2_strip_encryptionInformation(const char *cmd_name, bson_t *cmd /* in and ou
1363
1567
  BSON_ASSERT_PARAM(cmd_name);
1364
1568
  BSON_ASSERT_PARAM(cmd);
1365
1569
 
1366
- if (0 != strcmp(cmd_name, "explain")) {
1570
+ if (0 != strcmp(cmd_name, "explain") && 0 != strcmp(cmd_name, "bulkWrite")) {
1367
1571
  bson_copy_to_excluding_noinit(cmd, &stripped, "encryptionInformation", NULL);
1368
1572
  goto success;
1369
1573
  }
1370
1574
 
1575
+ if (0 == strcmp(cmd_name, "bulkWrite")) {
1576
+ // Get the single `nsInfo` document from the input command.
1577
+ bson_t nsInfo; // Non-owning.
1578
+ {
1579
+ bson_iter_t nsInfo_iter;
1580
+ if (!bson_iter_init(&nsInfo_iter, cmd)) {
1581
+ CLIENT_ERR("failed to iterate command");
1582
+ goto fail;
1583
+ }
1584
+ if (!bson_iter_find_descendant(&nsInfo_iter, "nsInfo.0", &nsInfo_iter)) {
1585
+ CLIENT_ERR("expected one namespace in `bulkWrite`, but found zero.");
1586
+ goto fail;
1587
+ }
1588
+ if (bson_has_field(cmd, "nsInfo.1")) {
1589
+ CLIENT_ERR(
1590
+ "expected one namespace in `bulkWrite`, but found more than one. Only one namespace is supported.");
1591
+ goto fail;
1592
+ }
1593
+ if (!mc_iter_document_as_bson(&nsInfo_iter, &nsInfo, status)) {
1594
+ goto fail;
1595
+ }
1596
+ }
1597
+
1598
+ // Copy input and exclude `encryptionInformation` from `nsInfo`.
1599
+ {
1600
+ // Append everything from input except `nsInfo`.
1601
+ bson_copy_to_excluding_noinit(cmd, &stripped, "nsInfo", NULL);
1602
+ // Append `nsInfo` array.
1603
+ bson_t nsInfo_array;
1604
+ if (!BSON_APPEND_ARRAY_BEGIN(&stripped, "nsInfo", &nsInfo_array)) {
1605
+ CLIENT_ERR("unable to begin appending 'nsInfo' array");
1606
+ goto fail;
1607
+ }
1608
+ bson_t nsInfo_array_0;
1609
+ if (!BSON_APPEND_DOCUMENT_BEGIN(&nsInfo_array, "0", &nsInfo_array_0)) {
1610
+ CLIENT_ERR("unable to append 'nsInfo.0' document");
1611
+ goto fail;
1612
+ }
1613
+ // Copy everything from input `nsInfo` and exclude `encryptionInformation`.
1614
+ bson_copy_to_excluding_noinit(&nsInfo, &nsInfo_array_0, "encryptionInformation", NULL);
1615
+ if (!bson_append_document_end(&nsInfo_array, &nsInfo_array_0)) {
1616
+ CLIENT_ERR("unable to end appending 'nsInfo' document in array");
1617
+ }
1618
+ if (!bson_append_array_end(&stripped, &nsInfo_array)) {
1619
+ CLIENT_ERR("unable to end appending 'nsInfo' array");
1620
+ goto fail;
1621
+ }
1622
+ }
1623
+
1624
+ goto success;
1625
+ }
1626
+
1371
1627
  // The 'explain' command is a special case.
1372
1628
  // 'encryptionInformation' is returned from mongocryptd and csfle nested
1373
1629
  // inside 'explain'. Example:
@@ -1451,7 +1707,7 @@ static bool _fle2_finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
1451
1707
  bson_copy_to(&original_cmd_bson, &converted);
1452
1708
  } else {
1453
1709
  bson_t as_bson;
1454
- bson_iter_t iter;
1710
+ bson_iter_t iter = {0};
1455
1711
 
1456
1712
  if (!_mongocrypt_buffer_to_bson(&ectx->marked_cmd, &as_bson)) {
1457
1713
  return _mongocrypt_ctx_fail_w_msg(ctx, "malformed bson");
@@ -1488,7 +1744,11 @@ static bool _fle2_finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
1488
1744
  }
1489
1745
  }
1490
1746
 
1491
- moe_result result = must_omit_encryptionInformation(command_name, &converted, ctx->status);
1747
+ moe_result result = must_omit_encryptionInformation(command_name,
1748
+ &converted,
1749
+ ctx->crypt->opts.use_range_v2,
1750
+ &ectx->efc,
1751
+ ctx->status);
1492
1752
  if (!result.ok) {
1493
1753
  bson_destroy(&converted);
1494
1754
  bson_destroy(deleteTokens);
@@ -1496,14 +1756,14 @@ static bool _fle2_finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
1496
1756
  }
1497
1757
 
1498
1758
  /* Append a new 'encryptionInformation'. */
1499
- if (!result.must_omit) {
1759
+ if (!result.must_omit && !ectx->used_empty_encryptedFields) {
1500
1760
  if (!_fle2_insert_encryptionInformation(ctx,
1501
1761
  command_name,
1502
1762
  &converted,
1503
- ectx->ns,
1763
+ ectx->target_ns,
1504
1764
  &encrypted_field_config_bson,
1505
1765
  deleteTokens,
1506
- ectx->coll_name,
1766
+ ectx->target_coll,
1507
1767
  MC_TO_MONGOD,
1508
1768
  ctx->status)) {
1509
1769
  bson_destroy(&converted);
@@ -1513,12 +1773,7 @@ static bool _fle2_finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
1513
1773
  }
1514
1774
  bson_destroy(deleteTokens);
1515
1775
 
1516
- if (!_fle2_append_compactionTokens(ctx->crypt->crypto,
1517
- &ctx->kb,
1518
- &ectx->efc,
1519
- command_name,
1520
- &converted,
1521
- ctx->status)) {
1776
+ if (!_fle2_append_compactionTokens(ctx->crypt, &ctx->kb, &ectx->efc, command_name, &converted, ctx->status)) {
1522
1777
  bson_destroy(&converted);
1523
1778
  return _mongocrypt_ctx_fail(ctx);
1524
1779
  }
@@ -1527,7 +1782,7 @@ static bool _fle2_finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
1527
1782
  bson_iter_t iter;
1528
1783
  if (bson_iter_init_find(&iter, &original_cmd_bson, "$db")) {
1529
1784
  if (!bson_iter_init_find(&iter, &converted, "$db")) {
1530
- BSON_APPEND_UTF8(&converted, "$db", ectx->db_name);
1785
+ BSON_APPEND_UTF8(&converted, "$db", ectx->cmd_db);
1531
1786
  }
1532
1787
  }
1533
1788
 
@@ -1545,6 +1800,9 @@ static bool FLE2RangeFindDriverSpec_to_ciphertexts(mongocrypt_ctx_t *ctx, mongoc
1545
1800
  BSON_ASSERT_PARAM(ctx);
1546
1801
  BSON_ASSERT_PARAM(out);
1547
1802
 
1803
+ bson_t with_placholders = BSON_INITIALIZER;
1804
+ bson_t with_ciphertexts = BSON_INITIALIZER;
1805
+
1548
1806
  if (!ctx->opts.rangeopts.set) {
1549
1807
  _mongocrypt_ctx_fail_w_msg(ctx, "Expected RangeOpts to be set for Range Find");
1550
1808
  goto fail;
@@ -1554,8 +1812,6 @@ static bool FLE2RangeFindDriverSpec_to_ciphertexts(mongocrypt_ctx_t *ctx, mongoc
1554
1812
  goto fail;
1555
1813
  }
1556
1814
 
1557
- bson_t with_placholders = BSON_INITIALIZER;
1558
- bson_t with_ciphertexts = BSON_INITIALIZER;
1559
1815
  bson_t in_bson;
1560
1816
  if (!_mongocrypt_buffer_to_bson(&ectx->original_cmd, &in_bson)) {
1561
1817
  _mongocrypt_ctx_fail_w_msg(ctx, "unable to convert input to BSON");
@@ -1663,7 +1919,13 @@ static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *
1663
1919
  marking.type = MONGOCRYPT_MARKING_FLE2_ENCRYPTION;
1664
1920
  if (ctx->opts.query_type.set) {
1665
1921
  switch (ctx->opts.query_type.value) {
1666
- case MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW:
1922
+ case MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED:
1923
+ if (ctx->crypt->opts.use_range_v2) {
1924
+ _mongocrypt_ctx_fail_w_msg(ctx, "Cannot use rangePreview query type with Range V2");
1925
+ goto fail;
1926
+ }
1927
+ // fallthrough
1928
+ case MONGOCRYPT_QUERY_TYPE_RANGE:
1667
1929
  case MONGOCRYPT_QUERY_TYPE_EQUALITY: marking.fle2.type = MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND; break;
1668
1930
  default: _mongocrypt_ctx_fail_w_msg(ctx, "Invalid value for EncryptOpts.queryType"); goto fail;
1669
1931
  }
@@ -1674,7 +1936,13 @@ static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *
1674
1936
  switch (ctx->opts.index_type.value) {
1675
1937
  case MONGOCRYPT_INDEX_TYPE_EQUALITY: marking.fle2.algorithm = MONGOCRYPT_FLE2_ALGORITHM_EQUALITY; break;
1676
1938
  case MONGOCRYPT_INDEX_TYPE_NONE: marking.fle2.algorithm = MONGOCRYPT_FLE2_ALGORITHM_UNINDEXED; break;
1677
- case MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW: marking.fle2.algorithm = MONGOCRYPT_FLE2_ALGORITHM_RANGE; break;
1939
+ case MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED:
1940
+ if (ctx->crypt->opts.use_range_v2) {
1941
+ _mongocrypt_ctx_fail_w_msg(ctx, "Cannot use rangePreview index type with Range V2");
1942
+ goto fail;
1943
+ }
1944
+ // fallthrough
1945
+ case MONGOCRYPT_INDEX_TYPE_RANGE: marking.fle2.algorithm = MONGOCRYPT_FLE2_ALGORITHM_RANGE; break;
1678
1946
  default:
1679
1947
  // This might be unreachable because of other validation. Better safe than
1680
1948
  // sorry.
@@ -1695,7 +1963,11 @@ static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *
1695
1963
 
1696
1964
  // RangeOpts with query_type is handled above.
1697
1965
  BSON_ASSERT(!ctx->opts.query_type.set);
1698
- if (!mc_RangeOpts_to_FLE2RangeInsertSpec(&ctx->opts.rangeopts.value, &old_v, &new_v, ctx->status)) {
1966
+ if (!mc_RangeOpts_to_FLE2RangeInsertSpec(&ctx->opts.rangeopts.value,
1967
+ &old_v,
1968
+ &new_v,
1969
+ ctx->crypt->opts.use_range_v2,
1970
+ ctx->status)) {
1699
1971
  _mongocrypt_ctx_fail(ctx);
1700
1972
  goto fail;
1701
1973
  }
@@ -1730,7 +2002,7 @@ static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *
1730
2002
  }
1731
2003
 
1732
2004
  if (ctx->opts.contention_factor.set) {
1733
- marking.fle2.maxContentionCounter = ctx->opts.contention_factor.value;
2005
+ marking.fle2.maxContentionFactor = ctx->opts.contention_factor.value;
1734
2006
  } else if (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_EQUALITY) {
1735
2007
  _mongocrypt_ctx_fail_w_msg(ctx, "contention factor required for indexed algorithm");
1736
2008
  goto fail;
@@ -1764,7 +2036,7 @@ fail:
1764
2036
 
1765
2037
  static bool _finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
1766
2038
  bson_t as_bson, converted;
1767
- bson_iter_t iter;
2039
+ bson_iter_t iter = {0};
1768
2040
  _mongocrypt_ctx_encrypt_t *ectx;
1769
2041
  bool res;
1770
2042
 
@@ -1811,7 +2083,7 @@ static bool _finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
1811
2083
  bson_iter_t iter;
1812
2084
  if (bson_iter_init_find(&iter, &original_cmd_bson, "$db")) {
1813
2085
  if (!bson_iter_init_find(&iter, &converted, "$db")) {
1814
- BSON_APPEND_UTF8(&converted, "$db", ectx->db_name);
2086
+ BSON_APPEND_UTF8(&converted, "$db", ectx->cmd_db);
1815
2087
  }
1816
2088
  }
1817
2089
  } else {
@@ -1869,9 +2141,10 @@ static void _cleanup(mongocrypt_ctx_t *ctx) {
1869
2141
  }
1870
2142
 
1871
2143
  ectx = (_mongocrypt_ctx_encrypt_t *)ctx;
1872
- bson_free(ectx->ns);
1873
- bson_free(ectx->db_name);
1874
- bson_free(ectx->coll_name);
2144
+ bson_free(ectx->target_ns);
2145
+ bson_free(ectx->cmd_db);
2146
+ bson_free(ectx->target_db);
2147
+ bson_free(ectx->target_coll);
1875
2148
  _mongocrypt_buffer_cleanup(&ectx->list_collections_filter);
1876
2149
  _mongocrypt_buffer_cleanup(&ectx->schema);
1877
2150
  _mongocrypt_buffer_cleanup(&ectx->encrypted_field_config);
@@ -1903,7 +2176,7 @@ static bool _try_schema_from_schema_map(mongocrypt_ctx_t *ctx) {
1903
2176
  return _mongocrypt_ctx_fail_w_msg(ctx, "malformed schema map");
1904
2177
  }
1905
2178
 
1906
- if (bson_iter_init_find(&iter, &schema_map, ectx->ns)) {
2179
+ if (bson_iter_init_find(&iter, &schema_map, ectx->target_ns)) {
1907
2180
  if (!_mongocrypt_buffer_copy_from_document_iter(&ectx->schema, &iter)) {
1908
2181
  return _mongocrypt_ctx_fail_w_msg(ctx, "malformed schema map");
1909
2182
  }
@@ -1939,7 +2212,7 @@ static bool _fle2_try_encrypted_field_config_from_map(mongocrypt_ctx_t *ctx) {
1939
2212
  return _mongocrypt_ctx_fail_w_msg(ctx, "unable to convert encrypted_field_config_map to BSON");
1940
2213
  }
1941
2214
 
1942
- if (bson_iter_init_find(&iter, &encrypted_field_config_map, ectx->ns)) {
2215
+ if (bson_iter_init_find(&iter, &encrypted_field_config_map, ectx->target_ns)) {
1943
2216
  if (!_mongocrypt_buffer_copy_from_document_iter(&ectx->encrypted_field_config, &iter)) {
1944
2217
  return _mongocrypt_ctx_fail_w_msg(ctx,
1945
2218
  "unable to copy encrypted_field_config from "
@@ -1949,7 +2222,7 @@ static bool _fle2_try_encrypted_field_config_from_map(mongocrypt_ctx_t *ctx) {
1949
2222
  if (!_mongocrypt_buffer_to_bson(&ectx->encrypted_field_config, &efc_bson)) {
1950
2223
  return _mongocrypt_ctx_fail_w_msg(ctx, "unable to create BSON from encrypted_field_config");
1951
2224
  }
1952
- if (!mc_EncryptedFieldConfig_parse(&ectx->efc, &efc_bson, ctx->status)) {
2225
+ if (!mc_EncryptedFieldConfig_parse(&ectx->efc, &efc_bson, ctx->status, ctx->crypt->opts.use_range_v2)) {
1953
2226
  _mongocrypt_ctx_fail(ctx);
1954
2227
  return false;
1955
2228
  }
@@ -1970,18 +2243,32 @@ static bool _try_schema_from_cache(mongocrypt_ctx_t *ctx) {
1970
2243
 
1971
2244
  /* Otherwise, we need a remote schema. Check if we have a response to
1972
2245
  * listCollections cached. */
1973
- if (!_mongocrypt_cache_get(&ctx->crypt->cache_collinfo, ectx->ns /* null terminated */, (void **)&collinfo)) {
2246
+ if (!_mongocrypt_cache_get(&ctx->crypt->cache_collinfo,
2247
+ ectx->target_ns /* null terminated */,
2248
+ (void **)&collinfo)) {
1974
2249
  return _mongocrypt_ctx_fail_w_msg(ctx, "failed to retrieve from cache");
1975
2250
  }
1976
2251
 
1977
2252
  if (collinfo) {
1978
2253
  if (!_set_schema_from_collinfo(ctx, collinfo)) {
2254
+ bson_destroy(collinfo);
1979
2255
  return _mongocrypt_ctx_fail(ctx);
1980
2256
  }
1981
2257
  ctx->state = MONGOCRYPT_CTX_NEED_MONGO_MARKINGS;
1982
2258
  } else {
1983
2259
  /* we need to get it. */
1984
2260
  ctx->state = MONGOCRYPT_CTX_NEED_MONGO_COLLINFO;
2261
+ if (ectx->target_db) {
2262
+ if (!ctx->crypt->opts.use_need_mongo_collinfo_with_db_state) {
2263
+ _mongocrypt_ctx_fail_w_msg(
2264
+ ctx,
2265
+ "Fetching remote collection information on separate databases is not supported. Try "
2266
+ "upgrading driver, or specify a local schemaMap or encryptedFieldsMap.");
2267
+ return false;
2268
+ }
2269
+ // Target database may differ from command database. Request collection info from target database.
2270
+ ctx->state = MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB;
2271
+ }
1985
2272
  }
1986
2273
 
1987
2274
  bson_destroy(collinfo);
@@ -2222,7 +2509,9 @@ static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *ms
2222
2509
  return _mongocrypt_ctx_fail_w_msg(ctx, "contention factor is required for indexed algorithm");
2223
2510
  }
2224
2511
 
2225
- if (ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW) {
2512
+ if (ctx->opts.index_type.set
2513
+ && (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_RANGE
2514
+ || ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED)) {
2226
2515
  if (!ctx->opts.contention_factor.set) {
2227
2516
  return _mongocrypt_ctx_fail_w_msg(ctx, "contention factor is required for range indexed algorithm");
2228
2517
  }
@@ -2242,8 +2531,14 @@ static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *ms
2242
2531
  bool matches = false;
2243
2532
 
2244
2533
  switch (ctx->opts.query_type.value) {
2245
- case MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW:
2246
- matches = (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW);
2534
+ case MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED:
2535
+ // Don't allow deprecated query type if we are using new index type.
2536
+ matches = (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED);
2537
+ break;
2538
+ case MONGOCRYPT_QUERY_TYPE_RANGE:
2539
+ // New query type is compatible with both new and old index types.
2540
+ matches = (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED
2541
+ || ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_RANGE);
2247
2542
  break;
2248
2543
  case MONGOCRYPT_QUERY_TYPE_EQUALITY:
2249
2544
  matches = (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_EQUALITY);
@@ -2317,7 +2612,9 @@ bool mongocrypt_ctx_explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_bina
2317
2612
  if (!explicit_encrypt_init(ctx, msg)) {
2318
2613
  return false;
2319
2614
  }
2320
- if (ctx->opts.query_type.set && ctx->opts.query_type.value == MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW) {
2615
+ if (ctx->opts.query_type.set
2616
+ && (ctx->opts.query_type.value == MONGOCRYPT_QUERY_TYPE_RANGE
2617
+ || ctx->opts.query_type.value == MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED)) {
2321
2618
  return _mongocrypt_ctx_fail_w_msg(ctx, "Encrypt may not be used for range queries. Use EncryptExpression.");
2322
2619
  }
2323
2620
  return true;
@@ -2327,22 +2624,77 @@ bool mongocrypt_ctx_explicit_encrypt_expression_init(mongocrypt_ctx_t *ctx, mong
2327
2624
  if (!explicit_encrypt_init(ctx, msg)) {
2328
2625
  return false;
2329
2626
  }
2330
- if (!ctx->opts.query_type.set || ctx->opts.query_type.value != MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW) {
2627
+ if (!ctx->opts.query_type.set
2628
+ || !(ctx->opts.query_type.value == MONGOCRYPT_QUERY_TYPE_RANGE
2629
+ || ctx->opts.query_type.value == MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED)) {
2331
2630
  return _mongocrypt_ctx_fail_w_msg(ctx, "EncryptExpression may only be used for range queries.");
2332
2631
  }
2333
2632
  return true;
2334
2633
  }
2335
2634
 
2635
+ static bool _check_cmd_for_auto_encrypt_bulkWrite(mongocrypt_binary_t *cmd,
2636
+ char **target_db,
2637
+ char **target_coll,
2638
+ mongocrypt_status_t *status) {
2639
+ BSON_ASSERT_PARAM(cmd);
2640
+ BSON_ASSERT_PARAM(target_db);
2641
+ BSON_ASSERT_PARAM(target_coll);
2642
+
2643
+ bson_t as_bson;
2644
+ bson_iter_t cmd_iter = {0};
2645
+
2646
+ if (!_mongocrypt_binary_to_bson(cmd, &as_bson) || !bson_iter_init(&cmd_iter, &as_bson)) {
2647
+ CLIENT_ERR("invalid command BSON");
2648
+ return false;
2649
+ }
2650
+
2651
+ bson_iter_t ns_iter = cmd_iter;
2652
+ if (!bson_iter_find_descendant(&ns_iter, "nsInfo.0.ns", &ns_iter)) {
2653
+ CLIENT_ERR("failed to find namespace in `bulkWrite` command");
2654
+ return false;
2655
+ }
2656
+
2657
+ if (!BSON_ITER_HOLDS_UTF8(&ns_iter)) {
2658
+ CLIENT_ERR("expected namespace to be UTF8, got: %s", mc_bson_type_to_string(bson_iter_type(&ns_iter)));
2659
+ return false;
2660
+ }
2661
+
2662
+ const char *target_ns = bson_iter_utf8(&ns_iter, NULL /* length */);
2663
+ // Parse `target_ns` into "<db>.<coll>"
2664
+ const char *dot = strstr(target_ns, ".");
2665
+ if (!dot) {
2666
+ CLIENT_ERR("expected namespace to contain dot, got: %s", target_ns);
2667
+ return false;
2668
+ }
2669
+ *target_coll = bson_strdup(dot + 1);
2670
+ // Get the database from the `ns` field (which may differ from `cmd_db`).
2671
+ ptrdiff_t db_len = dot - target_ns;
2672
+ if ((uint64_t)db_len > SIZE_MAX) {
2673
+ CLIENT_ERR("unexpected database length exceeds %zu", SIZE_MAX);
2674
+ return false;
2675
+ }
2676
+ *target_db = bson_strndup(target_ns, (size_t)db_len);
2677
+
2678
+ // Ensure only one `nsInfo` element is present.
2679
+ // Query analysis (mongocryptd/crypt_shared) currently only supports one namespace.
2680
+ if (bson_has_field(&as_bson, "nsInfo.1")) {
2681
+ CLIENT_ERR("expected one namespace in `bulkWrite`, but found more than one. Only one namespace is supported.");
2682
+ return false;
2683
+ }
2684
+
2685
+ return true;
2686
+ }
2687
+
2336
2688
  static bool
2337
- _check_cmd_for_auto_encrypt(mongocrypt_binary_t *cmd, bool *bypass, char **collname, mongocrypt_status_t *status) {
2689
+ _check_cmd_for_auto_encrypt(mongocrypt_binary_t *cmd, bool *bypass, char **target_coll, mongocrypt_status_t *status) {
2338
2690
  bson_t as_bson;
2339
- bson_iter_t iter, ns_iter;
2691
+ bson_iter_t iter = {0}, target_coll_iter;
2340
2692
  const char *cmd_name;
2341
2693
  bool eligible = false;
2342
2694
 
2343
2695
  BSON_ASSERT_PARAM(cmd);
2344
2696
  BSON_ASSERT_PARAM(bypass);
2345
- BSON_ASSERT_PARAM(collname);
2697
+ BSON_ASSERT_PARAM(target_coll);
2346
2698
 
2347
2699
  *bypass = false;
2348
2700
 
@@ -2366,22 +2718,22 @@ _check_cmd_for_auto_encrypt(mongocrypt_binary_t *cmd, bool *bypass, char **colln
2366
2718
  CLIENT_ERR("explain value is not a document");
2367
2719
  return false;
2368
2720
  }
2369
- if (!bson_iter_recurse(&iter, &ns_iter)) {
2721
+ if (!bson_iter_recurse(&iter, &target_coll_iter)) {
2370
2722
  CLIENT_ERR("malformed BSON for encrypt command");
2371
2723
  return false;
2372
2724
  }
2373
- if (!bson_iter_next(&ns_iter)) {
2725
+ if (!bson_iter_next(&target_coll_iter)) {
2374
2726
  CLIENT_ERR("invalid empty BSON");
2375
2727
  return false;
2376
2728
  }
2377
2729
  } else {
2378
- memcpy(&ns_iter, &iter, sizeof(iter));
2730
+ memcpy(&target_coll_iter, &iter, sizeof(iter));
2379
2731
  }
2380
2732
 
2381
- if (BSON_ITER_HOLDS_UTF8(&ns_iter)) {
2382
- *collname = bson_strdup(bson_iter_utf8(&ns_iter, NULL));
2733
+ if (BSON_ITER_HOLDS_UTF8(&target_coll_iter)) {
2734
+ *target_coll = bson_strdup(bson_iter_utf8(&target_coll_iter, NULL));
2383
2735
  } else {
2384
- *collname = NULL;
2736
+ *target_coll = NULL;
2385
2737
  }
2386
2738
 
2387
2739
  /* check if command is eligible for auto encryption, bypassed, or ineligible.
@@ -2461,6 +2813,8 @@ _check_cmd_for_auto_encrypt(mongocrypt_binary_t *cmd, bool *bypass, char **colln
2461
2813
  *bypass = true;
2462
2814
  } else if (0 == strcmp(cmd_name, "compactStructuredEncryptionData")) {
2463
2815
  eligible = true;
2816
+ } else if (0 == strcmp(cmd_name, "cleanupStructuredEncryptionData")) {
2817
+ eligible = true;
2464
2818
  } else if (0 == strcmp(cmd_name, "collMod")) {
2465
2819
  eligible = true;
2466
2820
  } else if (0 == strcmp(cmd_name, "hello")) {
@@ -2471,15 +2825,23 @@ _check_cmd_for_auto_encrypt(mongocrypt_binary_t *cmd, bool *bypass, char **colln
2471
2825
  *bypass = true;
2472
2826
  } else if (0 == strcmp(cmd_name, "getLog")) {
2473
2827
  *bypass = true;
2828
+ } else if (0 == strcmp(cmd_name, "createSearchIndexes")) {
2829
+ *bypass = true;
2830
+ } else if (0 == strcmp(cmd_name, "listSearchIndexes")) {
2831
+ *bypass = true;
2832
+ } else if (0 == strcmp(cmd_name, "dropSearchIndex")) {
2833
+ *bypass = true;
2834
+ } else if (0 == strcmp(cmd_name, "updateSearchIndex")) {
2835
+ *bypass = true;
2474
2836
  }
2475
2837
 
2476
2838
  /* database/client commands are ineligible. */
2477
2839
  if (eligible) {
2478
- if (!*collname) {
2840
+ if (!*target_coll) {
2479
2841
  CLIENT_ERR("non-collection command not supported for auto encryption: %s", cmd_name);
2480
2842
  return false;
2481
2843
  }
2482
- if (0 == strlen(*collname)) {
2844
+ if (0 == strlen(*target_coll)) {
2483
2845
  CLIENT_ERR("empty collection name on command: %s", cmd_name);
2484
2846
  return false;
2485
2847
  }
@@ -2507,7 +2869,6 @@ static bool needs_ismaster_check(mongocrypt_ctx_t *ctx) {
2507
2869
  bool mongocrypt_ctx_encrypt_init(mongocrypt_ctx_t *ctx, const char *db, int32_t db_len, mongocrypt_binary_t *cmd) {
2508
2870
  _mongocrypt_ctx_encrypt_t *ectx;
2509
2871
  _mongocrypt_ctx_opts_spec_t opts_spec;
2510
- bool bypass;
2511
2872
 
2512
2873
  if (!ctx) {
2513
2874
  return false;
@@ -2529,15 +2890,13 @@ bool mongocrypt_ctx_encrypt_init(mongocrypt_ctx_t *ctx, const char *db, int32_t
2529
2890
  ctx->vtable.mongo_op_collinfo = _mongo_op_collinfo;
2530
2891
  ctx->vtable.mongo_feed_collinfo = _mongo_feed_collinfo;
2531
2892
  ctx->vtable.mongo_done_collinfo = _mongo_done_collinfo;
2893
+ ctx->vtable.mongo_db_collinfo = _mongo_db_collinfo;
2532
2894
  ctx->vtable.mongo_op_collinfo = _mongo_op_collinfo;
2533
2895
  ctx->vtable.mongo_op_markings = _mongo_op_markings;
2534
2896
  ctx->vtable.mongo_feed_markings = _mongo_feed_markings;
2535
2897
  ctx->vtable.mongo_done_markings = _mongo_done_markings;
2536
2898
  ctx->vtable.finalize = _finalize;
2537
2899
  ctx->vtable.cleanup = _cleanup;
2538
- ctx->vtable.mongo_op_collinfo = _mongo_op_collinfo;
2539
- ctx->vtable.mongo_feed_collinfo = _mongo_feed_collinfo;
2540
- ctx->vtable.mongo_done_collinfo = _mongo_done_collinfo;
2541
2900
  ectx->bypass_query_analysis = ctx->crypt->opts.bypass_query_analysis;
2542
2901
 
2543
2902
  if (!cmd || !cmd->data) {
@@ -2551,27 +2910,38 @@ bool mongocrypt_ctx_encrypt_init(mongocrypt_ctx_t *ctx, const char *db, int32_t
2551
2910
  return _mongocrypt_ctx_fail(ctx);
2552
2911
  }
2553
2912
 
2554
- if (!_check_cmd_for_auto_encrypt(cmd, &bypass, &ectx->coll_name, ctx->status)) {
2555
- return _mongocrypt_ctx_fail(ctx);
2913
+ if (!_mongocrypt_validate_and_copy_string(db, db_len, &ectx->cmd_db) || 0 == strlen(ectx->cmd_db)) {
2914
+ return _mongocrypt_ctx_fail_w_msg(ctx, "invalid db");
2556
2915
  }
2557
2916
 
2558
- if (bypass) {
2559
- ctx->nothing_to_do = true;
2560
- ctx->state = MONGOCRYPT_CTX_READY;
2561
- return true;
2562
- }
2917
+ if (0 == strcmp(ectx->cmd_name, "bulkWrite")) {
2918
+ // Handle `bulkWrite` as a special case.
2919
+ // `bulkWrite` includes the target namespaces in an `nsInfo` field.
2920
+ // Only one target namespace is supported.
2921
+ if (!_check_cmd_for_auto_encrypt_bulkWrite(cmd, &ectx->target_db, &ectx->target_coll, ctx->status)) {
2922
+ return _mongocrypt_ctx_fail(ctx);
2923
+ }
2563
2924
 
2564
- /* if _check_cmd_for_auto_encrypt did not bypass or error, a collection name
2565
- * must have been set. */
2566
- if (!ectx->coll_name) {
2567
- return _mongocrypt_ctx_fail_w_msg(ctx, "unexpected error: did not bypass or error but no collection name");
2568
- }
2925
+ ectx->target_ns = bson_strdup_printf("%s.%s", ectx->target_db, ectx->target_coll);
2926
+ } else {
2927
+ bool bypass;
2928
+ if (!_check_cmd_for_auto_encrypt(cmd, &bypass, &ectx->target_coll, ctx->status)) {
2929
+ return _mongocrypt_ctx_fail(ctx);
2930
+ }
2569
2931
 
2570
- if (!_mongocrypt_validate_and_copy_string(db, db_len, &ectx->db_name) || 0 == strlen(ectx->db_name)) {
2571
- return _mongocrypt_ctx_fail_w_msg(ctx, "invalid db");
2572
- }
2932
+ if (bypass) {
2933
+ ctx->nothing_to_do = true;
2934
+ ctx->state = MONGOCRYPT_CTX_READY;
2935
+ return true;
2936
+ }
2573
2937
 
2574
- ectx->ns = bson_strdup_printf("%s.%s", ectx->db_name, ectx->coll_name);
2938
+ /* if _check_cmd_for_auto_encrypt did not bypass or error, a collection name
2939
+ * must have been set. */
2940
+ if (!ectx->target_coll) {
2941
+ return _mongocrypt_ctx_fail_w_msg(ctx, "unexpected error: did not bypass or error but no collection name");
2942
+ }
2943
+ ectx->target_ns = bson_strdup_printf("%s.%s", ectx->cmd_db, ectx->target_coll);
2944
+ }
2575
2945
 
2576
2946
  if (ctx->opts.kek.provider.aws.region || ctx->opts.kek.provider.aws.cmk) {
2577
2947
  return _mongocrypt_ctx_fail_w_msg(ctx, "aws masterkey options must not be set");
@@ -2593,7 +2963,7 @@ bool mongocrypt_ctx_encrypt_init(mongocrypt_ctx_t *ctx, const char *db, int32_t
2593
2963
  "%s (%s=\"%s\", %s=%d, %s=\"%s\")",
2594
2964
  BSON_FUNC,
2595
2965
  "db",
2596
- ectx->db_name,
2966
+ ectx->cmd_db,
2597
2967
  "db_len",
2598
2968
  db_len,
2599
2969
  "cmd",
@@ -2672,6 +3042,17 @@ static bool mongocrypt_ctx_encrypt_ismaster_done(mongocrypt_ctx_t *ctx) {
2672
3042
  /* Otherwise, we need the the driver to fetch the schema. */
2673
3043
  if (_mongocrypt_buffer_empty(&ectx->schema)) {
2674
3044
  ctx->state = MONGOCRYPT_CTX_NEED_MONGO_COLLINFO;
3045
+ if (ectx->target_db) {
3046
+ if (!ctx->crypt->opts.use_need_mongo_collinfo_with_db_state) {
3047
+ _mongocrypt_ctx_fail_w_msg(
3048
+ ctx,
3049
+ "Fetching remote collection information on separate databases is not supported. Try "
3050
+ "upgrading driver, or specify a local schemaMap or encryptedFieldsMap.");
3051
+ return false;
3052
+ }
3053
+ // Target database may differ from command database. Request collection info from target database.
3054
+ ctx->state = MONGOCRYPT_CTX_NEED_MONGO_COLLINFO_WITH_DB;
3055
+ }
2675
3056
  }
2676
3057
  }
2677
3058
 
@@ -2681,7 +3062,7 @@ static bool mongocrypt_ctx_encrypt_ismaster_done(mongocrypt_ctx_t *ctx) {
2681
3062
  return false;
2682
3063
  }
2683
3064
 
2684
- if (!_fle2_collect_keys_for_compact(ctx)) {
3065
+ if (!_fle2_collect_keys_for_compaction(ctx)) {
2685
3066
  return false;
2686
3067
  }
2687
3068