libmongocrypt-helper 1.19.0.0.1001 → 1.20.3.0.1001

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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/ext/libmongocrypt/libmongocrypt/CHANGELOG.md +37 -0
  3. data/ext/libmongocrypt/libmongocrypt/Earthfile +4 -3
  4. data/ext/libmongocrypt/libmongocrypt/README.md +3 -0
  5. data/ext/libmongocrypt/libmongocrypt/bindings/python/CONTRIBUTING.md +12 -0
  6. data/ext/libmongocrypt/libmongocrypt/bindings/python/scripts/update-version.sh +1 -1
  7. data/ext/libmongocrypt/libmongocrypt/cmake/FetchMongoC.cmake +1 -1
  8. data/ext/libmongocrypt/libmongocrypt/doc/releasing.md +10 -0
  9. data/ext/libmongocrypt/libmongocrypt/etc/cyclonedx.sbom.json +8 -8
  10. data/ext/libmongocrypt/libmongocrypt/etc/purls.txt +1 -1
  11. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_gcp_request.c +42 -0
  12. data/ext/libmongocrypt/libmongocrypt/kms-message/src/kms_kmip_response_parser.c +4 -0
  13. data/ext/libmongocrypt/libmongocrypt/src/mc-efc-private.h +5 -3
  14. data/ext/libmongocrypt/libmongocrypt/src/mc-efc.c +6 -17
  15. data/ext/libmongocrypt/libmongocrypt/src/mc-schema-broker.c +10 -2
  16. data/ext/libmongocrypt/libmongocrypt/src/mc-textopts.c +6 -3
  17. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-ctx-encrypt.c +43 -14
  18. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-ctx-private.h +6 -1
  19. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-ctx.c +20 -7
  20. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-opts.c +4 -0
  21. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt-private.h +5 -0
  22. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt.c +11 -0
  23. data/ext/libmongocrypt/libmongocrypt/src/mongocrypt.h +3 -3
  24. data/ext/libmongocrypt/libmongocrypt/test/data/efc/efc-textSearchFields.json +18 -2
  25. data/ext/libmongocrypt/libmongocrypt/test/test-gcp-auth.c +51 -0
  26. data/ext/libmongocrypt/libmongocrypt/test/test-mc-efc.c +10 -2
  27. data/ext/libmongocrypt/libmongocrypt/test/test-mc-textopts.c +1 -1
  28. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-ctx-encrypt.c +153 -26
  29. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-ctx-setopt.c +14 -9
  30. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt-kms-ctx.c +96 -0
  31. data/ext/libmongocrypt/libmongocrypt/test/test-mongocrypt.c +10 -0
  32. data/lib/libmongocrypt_helper/version.rb +2 -2
  33. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b049e3785ef7124bc0172a97aca5a01ac2c883998bf066bd399b23aaa6f7ab29
4
- data.tar.gz: b993577d300b0aafe7bd074774829edbe4a54425a1bbe631cdfa6424d73abba7
3
+ metadata.gz: b7037c7cdeb5a2f1fe94446f583e7c953539328df98580028a07f46c296689ec
4
+ data.tar.gz: 52a6c553f0e7ee8e0c6aca713184fe9c13f7e5babf97c18e4eff17235b8e7109
5
5
  SHA512:
6
- metadata.gz: 7effe0b13cb6bdea52e7ae92e8ae7fb3ca8230936d95e128d5e11ee35964ec848e46691fd8342e594918915f268ff3b6fa9a924f65d3015c1c25b17e22fc6e6b
7
- data.tar.gz: 4ee52e78b00238026409e733f629ab1067179909d20605c981cd7ce4229ed976ece08fd7f8b4db68645d33cbb571c3a04054e604d9ffbe7e7c5752a8bd98b23b
6
+ metadata.gz: 190dff33114c3f35a8ba07776144bdfde51523e75277176c4c0bf5bdef0be4d500500c3b11eed1520635e43d7b8201faec4faca54da7c99bd119da8d7c3f606e
7
+ data.tar.gz: 20446b82d1838e42ce90980bea22112b4af933cd66daa0984e15b00f1dde2867f408d87f5ed2f86ec146db64b4f0201c0a9be9cdcc30923e48acff5793ab1aa5
@@ -1,5 +1,35 @@
1
1
  # ChangeLog
2
2
 
3
+ ## 1.20.3
4
+
5
+ ### Fixed
6
+ - Validate database and collection name arguments against "." and NUL bytes
7
+ ## 1.20.2
8
+
9
+ ### Changed
10
+ - Add checks when creating GCP requests.
11
+
12
+ ## 1.20.1
13
+
14
+ ## Changed
15
+ - Bump downloaded libbson version from 2.3.0 to 2.3.3 to address configuration error with CMake 4.4.0.
16
+
17
+ ## 1.20.0
18
+
19
+ ### Added
20
+ - Stable support for substring queries.
21
+
22
+ ## 1.19.2
23
+
24
+ ### Added
25
+ - Add static library files to GitHub releases.
26
+
27
+ ## 1.19.1
28
+
29
+ ### Added
30
+ - Restore support for the experimental `prefixPreview` and `suffixPreview` query types.
31
+
32
+
3
33
  ## 1.19.0
4
34
 
5
35
  ### Added
@@ -11,6 +41,13 @@
11
41
  ### Removed
12
42
  - Support for the experimental `prefixPreview` and `suffixPreview` query types.
13
43
 
44
+
45
+ ## 1.18.2
46
+
47
+ ### Fixed
48
+ - Add musl arm64 release to GitHub release. This was an omission in 1.18.0.
49
+ - Reject large KMS replies.
50
+
14
51
  ## 1.18.1
15
52
 
16
53
  ### Fixed
@@ -438,12 +438,12 @@ test-deb-packages-from-ppa:
438
438
  RUN ./test.out
439
439
 
440
440
  # `sign` uses Garasign to sign a file with the libmongocrypt key.
441
- # Requires prior authentication with Artifactory.
441
+ # Requires prior authentication with the DevProd Platforms ECR registry (see doc/releasing.md).
442
442
  # See: https://docs.devprod.prod.corp.mongodb.com/release-tools-container-images/garasign/garasign_signing/.
443
443
  sign:
444
444
  ARG --required file_to_sign
445
445
  ARG --required output_file
446
- FROM artifactory.corp.mongodb.com/release-tools-container-registry-local/garasign-gpg
446
+ FROM 901841024863.dkr.ecr.us-east-1.amazonaws.com/release-infrastructure/garasign-gpg
447
447
  WORKDIR /s
448
448
  COPY ${file_to_sign} /s/file
449
449
  RUN --secret garasign_username --secret garasign_password \
@@ -460,8 +460,9 @@ sign:
460
460
  # An environment with the `silkbomb` command.
461
461
  #
462
462
  # See https://docs.devprod.prod.corp.mongodb.com/mms/python/src/sbom/silkbomb/ for documentation of silkbomb.
463
+ # Requires prior authentication with the DevProd Platforms ECR registry (see doc/releasing.md).
463
464
  silkbomb:
464
- FROM artifactory.corp.mongodb.com/release-tools-container-registry-public-local/silkbomb:2.0
465
+ FROM 901841024863.dkr.ecr.us-east-1.amazonaws.com/release-infrastructure/silkbomb:2.0
465
466
  # Alias the silkbomb executable to a simpler name:
466
467
  RUN ln -s /python/src/sbom/silkbomb/bin /usr/local/bin/silkbomb
467
468
 
@@ -78,6 +78,9 @@ A Windows DLL for x86_64 is available on the Github Releases page. See the [late
78
78
 
79
79
  Use `gpg` to verify the signature. The public key for `libmongocrypt` is available on https://pgp.mongodb.com/.
80
80
 
81
+ ## Python Releases ##
82
+ Python releases and tags are signed using the MongoDB Python driver PGP key. Use `gpg` to verify the signature. The public key is available at https://pgp.mongodb.com/python-driver.pub.
83
+
81
84
 
82
85
  ### Testing ###
83
86
  `test-mongocrypt` mocks all I/O with files stored in the `test/data` and `test/example` directories. Run `test-mongocrypt` from the source directory:
@@ -28,6 +28,18 @@ bash scripts/update-version.sh <new-version>
28
28
  This will set the version in `scripts/libmongocrypt-version.sh` and update `sbom.json` to reflect
29
29
  the new vendored version of `libmongocrypt`.
30
30
 
31
+ This pulls the `silkbomb` image from the DevProd Platforms ECR registry. Authenticate to the ECR
32
+ registry with the container launcher (`docker` or `podman`) before running the script:
33
+
34
+ ```bash
35
+ aws sso login --profile ECRScopedAccess-901841024863
36
+
37
+ # Authenticate "podman" or "docker"
38
+ CONTAINER_LAUNCHER="podman"
39
+
40
+ aws ecr get-login-password --region us-east-1 --profile ECRScopedAccess-901841024863 | $CONTAINER_LAUNCHER login --username AWS --password-stdin 901841024863.dkr.ecr.us-east-1.amazonaws.com
41
+ ```
42
+
31
43
  ## Building wheels
32
44
 
33
45
  To build wheels, run `scripts/release.sh`. It will build the appropriate wheel for the current system
@@ -21,7 +21,7 @@ else
21
21
  fi
22
22
 
23
23
  echo "pkg:github/mongodb/libmongocrypt@$LIBMONGOCRYPT_VERSION" > purls.txt
24
- $DOCKER run --platform="linux/amd64" -it --rm -v $(pwd):$(pwd) artifactory.corp.mongodb.com/release-tools-container-registry-public-local/silkbomb:2.0 update --purls=$(pwd)/purls.txt -o $(pwd)/sbom.json
24
+ $DOCKER run --platform="linux/amd64" -it --rm -v $(pwd):$(pwd) 901841024863.dkr.ecr.us-east-1.amazonaws.com/release-infrastructure/silkbomb:2.0 update --purls=$(pwd)/purls.txt -o $(pwd)/sbom.json
25
25
  rm purls.txt
26
26
 
27
27
  popd
@@ -2,7 +2,7 @@ include (FetchContent)
2
2
 
3
3
  # Set the tag that we will fetch.
4
4
  # When updating the version of libbson, also update the version in etc/purls.txt and .evergreen/prep_c_driver_source.sh
5
- set (MONGOC_FETCH_TAG_FOR_LIBBSON "2.3.0" CACHE STRING "The Git tag of mongo-c-driver that will be fetched to obtain libbson")
5
+ set (MONGOC_FETCH_TAG_FOR_LIBBSON "2.3.3" CACHE STRING "The Git tag of mongo-c-driver that will be fetched to obtain libbson")
6
6
 
7
7
  # Add an option to disable patching if a patch command is unavailable.
8
8
  option (LIBBSON_PATCH_ENABLED "Whether to apply patches to the libbson library" ON)
@@ -93,6 +93,15 @@ Do the following when releasing:
93
93
  ```bash
94
94
  ./.evergreen/earthly.sh +sbom-generate-new-serial-number
95
95
  ```
96
+ This pulls the `silkbomb` image from the DevProd Platforms ECR registry. Authenticate to the ECR registry with the container launcher (`docker` or `podman`):
97
+ ```bash
98
+ aws sso login --profile ECRScopedAccess-901841024863
99
+
100
+ # Authenticate "podman" or "docker"
101
+ CONTAINER_LAUNCHER="podman"
102
+
103
+ aws ecr get-login-password --region us-east-1 --profile ECRScopedAccess-901841024863 | $CONTAINER_LAUNCHER login --username AWS --password-stdin 901841024863.dkr.ecr.us-east-1.amazonaws.com
104
+ ```
96
105
  Commit resulting `etc/cyclonedx.sbom.json` and push to `rx.y`.
97
106
  - Remove yourself from the [releases team](https://github.com/orgs/mongodb/teams/dbx-c-cxx-releases) on GitHub via [MANA](https://mana.corp.mongodb.com/resources/68029673d39aa9f7de6399f9).
98
107
  - If this is a new non-patch release (e.g. `x.y.0`):
@@ -130,6 +139,7 @@ Do the following when releasing:
130
139
  ```bash
131
140
  ./.evergreen/earthly.sh +sbom-generate-new-serial-number
132
141
  ```
142
+ Requires AWS SSO access to the `ECRScopedAccess-901841024863` profile (see note above).
133
143
  Commit resulting `etc/cyclonedx.sbom.json`.
134
144
  - Update the release on the [Jira releases page](https://jira.mongodb.org/projects/MONGOCRYPT/versions).
135
145
  - Record the release on [C/C++ Release Info](https://docs.google.com/spreadsheets/d/1yHfGmDnbA5-Qt8FX4tKWC5xk9AhzYZx1SKF4AD36ecY/edit?usp=sharing). This is done to leave commentary about the process.
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "components": [
3
3
  {
4
- "bom-ref": "pkg:github/mongodb/mongo-c-driver@v2.3.0#src/libbson",
4
+ "bom-ref": "pkg:github/mongodb/mongo-c-driver@2.3.3#src/libbson",
5
5
  "copyright": "Copyright 2009-present MongoDB, Inc.",
6
6
  "externalReferences": [
7
7
  {
8
8
  "type": "distribution",
9
- "url": "https://github.com/mongodb/mongo-c-driver/archive/v2.3.0.tar.gz"
9
+ "url": "https://github.com/mongodb/mongo-c-driver/archive/2.3.3.tar.gz"
10
10
  },
11
11
  {
12
12
  "type": "website",
13
- "url": "https://github.com/mongodb/mongo-c-driver/tree/v2.3.0"
13
+ "url": "https://github.com/mongodb/mongo-c-driver/tree/2.3.3"
14
14
  }
15
15
  ],
16
16
  "group": "mongodb",
@@ -22,9 +22,9 @@
22
22
  }
23
23
  ],
24
24
  "name": "mongo-c-driver",
25
- "purl": "pkg:github/mongodb/mongo-c-driver@v2.3.0#src/libbson",
25
+ "purl": "pkg:github/mongodb/mongo-c-driver@2.3.3#src/libbson",
26
26
  "type": "library",
27
- "version": "v2.3.0"
27
+ "version": "2.3.3"
28
28
  },
29
29
  {
30
30
  "bom-ref": "pkg:generic/IntelRDFPMathLib@20U2?download_url=https://www.netlib.org/misc/intel/IntelRDFPMathLib20U2.tar.gz",
@@ -53,11 +53,11 @@
53
53
  "ref": "pkg:generic/IntelRDFPMathLib@20U2?download_url=https://www.netlib.org/misc/intel/IntelRDFPMathLib20U2.tar.gz"
54
54
  },
55
55
  {
56
- "ref": "pkg:github/mongodb/mongo-c-driver@v2.3.0#src/libbson"
56
+ "ref": "pkg:github/mongodb/mongo-c-driver@2.3.3#src/libbson"
57
57
  }
58
58
  ],
59
59
  "metadata": {
60
- "timestamp": "2026-05-01T14:49:06.464175+00:00",
60
+ "timestamp": "2026-08-07T17:48:10.053548+00:00",
61
61
  "tools": [
62
62
  {
63
63
  "externalReferences": [
@@ -100,7 +100,7 @@
100
100
  }
101
101
  ]
102
102
  },
103
- "serialNumber": "urn:uuid:5c89265b-cc3d-4649-878b-17b482325b56",
103
+ "serialNumber": "urn:uuid:464d2591-6478-4559-a1c4-9a726248fc1e",
104
104
  "version": 1,
105
105
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
106
106
  "bomFormat": "CycloneDX",
@@ -8,7 +8,7 @@
8
8
  # `copyright` property. This information can be manually added.
9
9
 
10
10
  # libbson is obtained via `cmake/FetchMongoC.cmake`.
11
- pkg:github/mongodb/mongo-c-driver@v2.3.0?#src/libbson
11
+ pkg:github/mongodb/mongo-c-driver@2.3.3?#src/libbson
12
12
 
13
13
  # IntelDFP is obtained via `cmake/IntelDFP.cmake`
14
14
  pkg:generic/IntelRDFPMathLib@20U2?download_url=https://www.netlib.org/misc/intel/IntelRDFPMathLib20U2.tar.gz
@@ -20,6 +20,8 @@
20
20
  #include "kms_message_private.h"
21
21
  #include "kms_request_opt_private.h"
22
22
 
23
+ #include <ctype.h>
24
+
23
25
  /* Set a default expiration of 5 minutes for JSON Web Tokens (GCP allows up to
24
26
  * one hour) */
25
27
  #define JWT_EXPIRATION_SECS 5 * 60
@@ -145,6 +147,38 @@ done:
145
147
  return req;
146
148
  }
147
149
 
150
+ /* _check_key_identifier returns true if `value` is safe to use as a URL path segment.
151
+ *
152
+ * Key identifiers may originate from key vault documents or caller-supplied options. They are
153
+ * formatted into the request path, so an unescaped '/', '?', '#', space, or CR/LF would rewrite
154
+ * the request target or inject header lines into the request.
155
+ *
156
+ * Only the RFC 3986 unreserved characters are permitted. This is a superset of what GCP itself
157
+ * accepts, so it does not reject any identifier that would otherwise work:
158
+ * - keyRing and keyName must match `[a-zA-Z0-9_-]{1,63}`. See
159
+ * https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings/create and
160
+ * https://cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings.cryptoKeys/create
161
+ * - projectId is 6-30 characters of lowercase letters, numbers, and hyphens. See
162
+ * https://cloud.google.com/resource-manager/docs/creating-managing-projects
163
+ * - location is a Cloud location name (e.g. "global", "us-east1").
164
+ * - keyVersion is a positive integer.
165
+ *
166
+ * `value` is not included in the error message: it is untrusted, and the error may be logged. */
167
+ static bool
168
+ _check_key_identifier (kms_request_t *req, const char *name, const char *value)
169
+ {
170
+ const char *c;
171
+
172
+ for (c = value; *c != '\0'; c++) {
173
+ if (!isalnum ((unsigned char) *c) && *c != '-' && *c != '.' && *c != '_' &&
174
+ *c != '~') {
175
+ KMS_ERROR (req, "Invalid character in GCP KMS key identifier: %s", name);
176
+ return false;
177
+ }
178
+ }
179
+ return true;
180
+ }
181
+
148
182
  static kms_request_t *
149
183
  _encrypt_decrypt_common (const char *encrypt_decrypt,
150
184
  const char *host,
@@ -192,6 +226,14 @@ _encrypt_decrypt_common (const char *encrypt_decrypt,
192
226
  goto done;
193
227
  }
194
228
 
229
+ if (!_check_key_identifier (req, "projectId", project_id) ||
230
+ !_check_key_identifier (req, "location", location) ||
231
+ !_check_key_identifier (req, "keyRing", key_ring_name) ||
232
+ !_check_key_identifier (req, "keyName", key_name) ||
233
+ (key_version && !_check_key_identifier (req, "keyVersion", key_version))) {
234
+ goto done;
235
+ }
236
+
195
237
  value_base64 = kms_message_raw_to_b64 (value, value_len);
196
238
  if (!value_base64) {
197
239
  KMS_ERROR (req, "Could not bases64-encode plaintext");
@@ -111,6 +111,10 @@ kms_kmip_response_parser_feed (kms_kmip_response_parser_t *parser,
111
111
  uint32_t temp;
112
112
  memcpy (&temp, parser->buf->str + FIRST_LENGTH_OFFSET, sizeof (uint32_t));
113
113
  parser->first_len = KMS_UINT32_FROM_BE (temp);
114
+ if (parser->first_len > KMS_PARSER_MAX_RESPONSE_LEN) {
115
+ KMS_ERROR (parser, "KMS KMIP response too large");
116
+ return false;
117
+ }
114
118
  }
115
119
  return true;
116
120
  }
@@ -28,13 +28,15 @@ typedef enum _supported_query_type_flags {
28
28
  SUPPORTS_RANGE_QUERIES = 1 << 1,
29
29
  // Range preview query supported
30
30
  SUPPORTS_RANGE_PREVIEW_DEPRECATED_QUERIES = 1 << 2,
31
- // Text search preview query supported
32
- SUPPORTS_SUBSTRING_PREVIEW_QUERIES = 1 << 3,
31
+ // Text search query supported
32
+ SUPPORTS_SUBSTRING_QUERIES = 1 << 3,
33
33
  SUPPORTS_SUFFIX_QUERIES = 1 << 4,
34
34
  SUPPORTS_PREFIX_QUERIES = 1 << 5,
35
- // prefixPreview and suffixPreview are dropped. Setting this results in an error.
35
+ // suffixPreview and prefixPreview are deprecated aliases for suffix and prefix, respectively.
36
36
  SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES = 1 << 6,
37
37
  SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES = 1 << 7,
38
+ // substring preview query supported
39
+ SUPPORTS_SUBSTRING_PREVIEW_DEPRECATED_QUERIES = 1 << 8,
38
40
  } supported_query_type_flags;
39
41
 
40
42
  typedef struct _mc_EncryptedField_t {
@@ -33,8 +33,9 @@ static bool _parse_query_type_string(const char *queryType, supported_query_type
33
33
  *out = SUPPORTS_RANGE_QUERIES;
34
34
  } else if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED_STR), qtv)) {
35
35
  *out = SUPPORTS_RANGE_PREVIEW_DEPRECATED_QUERIES;
36
- } else if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_STR), qtv)) {
37
- *out = SUPPORTS_SUBSTRING_PREVIEW_QUERIES;
36
+ } else if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_DEPRECATED_STR), qtv)
37
+ || mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUBSTRING_STR), qtv)) {
38
+ *out = SUPPORTS_SUBSTRING_QUERIES;
38
39
  } else if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUFFIX_STR), qtv)) {
39
40
  *out = SUPPORTS_SUFFIX_QUERIES;
40
41
  } else if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_PREFIX_STR), qtv)) {
@@ -178,20 +179,6 @@ static bool _parse_field(mc_EncryptedFieldConfig_t *efc, bson_t *field, mongocry
178
179
  return false;
179
180
  }
180
181
 
181
- if (query_types & SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES) {
182
- CLIENT_ERR("Cannot use field '%s' with 'prefixPreview' queries. 'prefixPreview' is unsupported. Use 'prefix' "
183
- "instead.",
184
- field_path);
185
- return false;
186
- }
187
-
188
- if (query_types & SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES) {
189
- CLIENT_ERR("Cannot use field '%s' with 'suffixPreview' queries. 'suffixPreview' is unsupported. Use 'suffix' "
190
- "instead.",
191
- field_path);
192
- return false;
193
- }
194
-
195
182
  /* Prepend a new mc_EncryptedField_t */
196
183
  mc_EncryptedField_t *ef = bson_malloc0(sizeof(mc_EncryptedField_t));
197
184
  if (has_keyid) {
@@ -258,7 +245,9 @@ bool mc_EncryptedFieldConfig_parse(mc_EncryptedFieldConfig_t *efc,
258
245
 
259
246
  if (!bson_iter_init_find(&iter, efc_bson, "strEncodeVersion")) {
260
247
  if (all_supported_queries
261
- & (SUPPORTS_SUBSTRING_PREVIEW_QUERIES | SUPPORTS_SUFFIX_QUERIES | SUPPORTS_PREFIX_QUERIES)) {
248
+ & (SUPPORTS_SUBSTRING_QUERIES | SUPPORTS_SUBSTRING_PREVIEW_DEPRECATED_QUERIES | SUPPORTS_SUFFIX_QUERIES
249
+ | SUPPORTS_PREFIX_QUERIES | SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES
250
+ | SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES)) {
262
251
  // Has at least one text search query type, set to latest by default.
263
252
  efc->str_encode_version = LATEST_STR_ENCODE_VERSION;
264
253
  } else {
@@ -323,7 +323,11 @@ bool mc_schema_broker_satisfy_from_collinfo(mc_schema_broker_t *sb,
323
323
  CLIENT_ERR("failed to find 'name' in collinfo in database: %s", sb->db);
324
324
  return false;
325
325
  }
326
- coll = bson_iter_utf8(&name_iter, NULL);
326
+ uint32_t coll_len;
327
+ coll = bson_iter_utf8(&name_iter, &coll_len);
328
+ if (!_mongocrypt_check_no_embedded_nul(coll, coll_len, "collection name in collinfo", status)) {
329
+ return false;
330
+ }
327
331
  }
328
332
 
329
333
  // Cache the received collinfo.
@@ -508,7 +512,11 @@ bool mc_schema_broker_satisfy_from_create_or_collMod(mc_schema_broker_t *sb,
508
512
  CLIENT_ERR("Failed to get collection name from command");
509
513
  return false;
510
514
  }
511
- const char *coll = bson_iter_utf8(&iter, NULL);
515
+ uint32_t coll_len;
516
+ const char *coll = bson_iter_utf8(&iter, &coll_len);
517
+ if (!_mongocrypt_check_no_embedded_nul(coll, coll_len, "collection name", status)) {
518
+ return false;
519
+ }
512
520
 
513
521
  // Check if schema was requested.
514
522
  mc_schema_entry_t *found = NULL;
@@ -368,15 +368,18 @@ bool mc_TextOpts_to_FLE2TextSearchInsertSpec_for_query(const mc_TextOpts_t *txo,
368
368
  CLIENT_ERR("Unexpected query type: %s\n", _mongocrypt_query_type_to_string(query_type));
369
369
  return false;
370
370
  }
371
- case MONGOCRYPT_QUERY_TYPE_PREFIX: {
371
+ case MONGOCRYPT_QUERY_TYPE_PREFIX:
372
+ case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED: {
372
373
  include_prefix = true;
373
374
  break;
374
375
  }
375
- case MONGOCRYPT_QUERY_TYPE_SUFFIX: {
376
+ case MONGOCRYPT_QUERY_TYPE_SUFFIX:
377
+ case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED: {
376
378
  include_suffix = true;
377
379
  break;
378
380
  }
379
- case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW: {
381
+ case MONGOCRYPT_QUERY_TYPE_SUBSTRING:
382
+ case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_DEPRECATED: {
380
383
  include_substring = true;
381
384
  break;
382
385
  }
@@ -890,8 +890,9 @@ static moe_result must_omit_encryptionInformation(const char *command_name,
890
890
  bool has_fields_requiring_ei = false;
891
891
  for (const mc_EncryptedField_t *ef = efc->fields; ef != NULL; ef = ef->next) {
892
892
  if (ef->supported_queries
893
- & (SUPPORTS_RANGE_QUERIES | SUPPORTS_SUBSTRING_PREVIEW_QUERIES | SUPPORTS_SUFFIX_QUERIES
894
- | SUPPORTS_PREFIX_QUERIES)) {
893
+ & (SUPPORTS_RANGE_QUERIES | SUPPORTS_SUBSTRING_QUERIES | SUPPORTS_SUFFIX_QUERIES
894
+ | SUPPORTS_PREFIX_QUERIES | SUPPORTS_SUBSTRING_PREVIEW_DEPRECATED_QUERIES
895
+ | SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES | SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES)) {
895
896
  has_fields_requiring_ei = true;
896
897
  break;
897
898
  }
@@ -1011,8 +1012,9 @@ static bool _fle2_append_compactionTokens(mongocrypt_t *crypt,
1011
1012
  const _mongocrypt_buffer_t *ecoct_buf = mc_ECOCToken_get(ecoct);
1012
1013
 
1013
1014
  if (ptr->supported_queries
1014
- & (SUPPORTS_RANGE_QUERIES | SUPPORTS_SUBSTRING_PREVIEW_QUERIES | SUPPORTS_SUFFIX_QUERIES
1015
- | SUPPORTS_PREFIX_QUERIES)) {
1015
+ & (SUPPORTS_RANGE_QUERIES | SUPPORTS_SUBSTRING_QUERIES | SUPPORTS_SUFFIX_QUERIES | SUPPORTS_PREFIX_QUERIES
1016
+ | SUPPORTS_SUBSTRING_PREVIEW_DEPRECATED_QUERIES | SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES
1017
+ | SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES)) {
1016
1018
  // Append the document {ecoc: <ECOCToken>, anchorPaddingToken: <AnchorPaddingTokenRoot>}
1017
1019
  esct = mc_ESCToken_new(crypto, cl1t, status);
1018
1020
  if (!esct) {
@@ -1522,7 +1524,10 @@ static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *
1522
1524
  // fallthrough
1523
1525
  case MONGOCRYPT_QUERY_TYPE_SUFFIX:
1524
1526
  case MONGOCRYPT_QUERY_TYPE_PREFIX:
1525
- case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW:
1527
+ case MONGOCRYPT_QUERY_TYPE_SUBSTRING:
1528
+ case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED:
1529
+ case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED:
1530
+ case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_DEPRECATED:
1526
1531
  case MONGOCRYPT_QUERY_TYPE_RANGE:
1527
1532
  case MONGOCRYPT_QUERY_TYPE_EQUALITY: marking.u.fle2.type = MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND; break;
1528
1533
  default: _mongocrypt_ctx_fail_w_msg(ctx, "Invalid value for EncryptOpts.queryType"); goto fail;
@@ -2087,19 +2092,19 @@ static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *ms
2087
2092
 
2088
2093
  if (ctx->opts.query_type.set) {
2089
2094
  const mongocrypt_query_type_t qt = ctx->opts.query_type.value;
2090
- if (qt == MONGOCRYPT_QUERY_TYPE_PREFIX) {
2095
+ if (qt == MONGOCRYPT_QUERY_TYPE_PREFIX || qt == MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED) {
2091
2096
  if (!(ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_STRING)) {
2092
2097
  return _mongocrypt_ctx_fail_w_msg(ctx, "prefix query type requires string index type");
2093
2098
  }
2094
2099
  }
2095
- if (qt == MONGOCRYPT_QUERY_TYPE_SUFFIX) {
2100
+ if (qt == MONGOCRYPT_QUERY_TYPE_SUFFIX || qt == MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED) {
2096
2101
  if (!(ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_STRING)) {
2097
2102
  return _mongocrypt_ctx_fail_w_msg(ctx, "suffix query type requires string index type");
2098
2103
  }
2099
2104
  }
2100
- if (qt == MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW) {
2105
+ if (qt == MONGOCRYPT_QUERY_TYPE_SUBSTRING || qt == MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_DEPRECATED) {
2101
2106
  if (!(ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_STRING)) {
2102
- return _mongocrypt_ctx_fail_w_msg(ctx, "substringPreview query type requires string index type");
2107
+ return _mongocrypt_ctx_fail_w_msg(ctx, "substring query type requires string index type");
2103
2108
  }
2104
2109
  }
2105
2110
  }
@@ -2182,7 +2187,10 @@ static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *ms
2182
2187
  // fallthrough
2183
2188
  case MONGOCRYPT_QUERY_TYPE_PREFIX:
2184
2189
  case MONGOCRYPT_QUERY_TYPE_SUFFIX:
2185
- case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW:
2190
+ case MONGOCRYPT_QUERY_TYPE_SUBSTRING:
2191
+ case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED:
2192
+ case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED:
2193
+ case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_DEPRECATED:
2186
2194
  matches = (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_STRING);
2187
2195
  break;
2188
2196
  default:
@@ -2295,7 +2303,11 @@ static bool _check_cmd_for_auto_encrypt_bulkWrite(mongocrypt_binary_t *cmd,
2295
2303
  return false;
2296
2304
  }
2297
2305
 
2298
- const char *target_ns = bson_iter_utf8(&ns_iter, NULL /* length */);
2306
+ uint32_t target_ns_len;
2307
+ const char *target_ns = bson_iter_utf8(&ns_iter, &target_ns_len);
2308
+ if (!_mongocrypt_check_no_embedded_nul(target_ns, target_ns_len, "namespace in `bulkWrite` command", status)) {
2309
+ return false;
2310
+ }
2299
2311
  // Parse `target_ns` into "<db>.<coll>"
2300
2312
  const char *dot = strstr(target_ns, ".");
2301
2313
  if (!dot) {
@@ -2367,7 +2379,12 @@ _check_cmd_for_auto_encrypt(mongocrypt_binary_t *cmd, bool *bypass, char **targe
2367
2379
  }
2368
2380
 
2369
2381
  if (BSON_ITER_HOLDS_UTF8(&target_coll_iter)) {
2370
- *target_coll = bson_strdup(bson_iter_utf8(&target_coll_iter, NULL));
2382
+ uint32_t target_coll_len;
2383
+ const char *target_coll_str = bson_iter_utf8(&target_coll_iter, &target_coll_len);
2384
+ if (!_mongocrypt_check_no_embedded_nul(target_coll_str, target_coll_len, "collection name", status)) {
2385
+ return false;
2386
+ }
2387
+ *target_coll = bson_strdup(target_coll_str);
2371
2388
  } else {
2372
2389
  *target_coll = NULL;
2373
2390
  }
@@ -2564,7 +2581,11 @@ static bool find_collections_in_pipeline(mc_schema_broker_t *sb,
2564
2581
  stage_key);
2565
2582
  return false;
2566
2583
  }
2567
- const char *from = bson_iter_utf8(&lookup_iter, NULL);
2584
+ uint32_t from_len;
2585
+ const char *from = bson_iter_utf8(&lookup_iter, &from_len);
2586
+ if (!_mongocrypt_check_no_embedded_nul(from, from_len, "'from' collection name", status)) {
2587
+ return false;
2588
+ }
2568
2589
  if (!mc_schema_broker_request(sb, db, from, status)) {
2569
2590
  return false;
2570
2591
  }
@@ -2623,7 +2644,11 @@ static bool find_collections_in_pipeline(mc_schema_broker_t *sb,
2623
2644
  stage_key);
2624
2645
  return false;
2625
2646
  }
2626
- const char *coll = bson_iter_utf8(&unionWith_iter, NULL);
2647
+ uint32_t coll_len;
2648
+ const char *coll = bson_iter_utf8(&unionWith_iter, &coll_len);
2649
+ if (!_mongocrypt_check_no_embedded_nul(coll, coll_len, "'coll' collection name", status)) {
2650
+ return false;
2651
+ }
2627
2652
  if (!mc_schema_broker_request(sb, db, coll, status)) {
2628
2653
  return false;
2629
2654
  }
@@ -2714,6 +2739,10 @@ bool mongocrypt_ctx_encrypt_init(mongocrypt_ctx_t *ctx, const char *db, int32_t
2714
2739
  return _mongocrypt_ctx_fail_w_msg(ctx, "invalid db");
2715
2740
  }
2716
2741
 
2742
+ if (strchr(ectx->cmd_db, '.')) {
2743
+ return _mongocrypt_ctx_fail_w_msg(ctx, "invalid db: must not contain a dot");
2744
+ }
2745
+
2717
2746
  if (0 == strcmp(ectx->cmd_name, "bulkWrite")) {
2718
2747
  // Handle `bulkWrite` as a special case.
2719
2748
  // `bulkWrite` includes the target namespaces in an `nsInfo` field.
@@ -46,7 +46,12 @@ typedef enum _mongocrypt_query_type_t {
46
46
  MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED = 3,
47
47
  MONGOCRYPT_QUERY_TYPE_PREFIX = 4,
48
48
  MONGOCRYPT_QUERY_TYPE_SUFFIX = 5,
49
- MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW = 6,
49
+ MONGOCRYPT_QUERY_TYPE_SUBSTRING = 6,
50
+ // prefixPreview and suffixPreview are deprecated aliases for prefix and suffix, respectively. They behave
51
+ // identically; the distinct values exist for consistency (cf. rangePreview) and to ease eventual removal.
52
+ MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED = 7,
53
+ MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED = 8,
54
+ MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_DEPRECATED = 9,
50
55
  } mongocrypt_query_type_t;
51
56
 
52
57
  const char *_mongocrypt_query_type_to_string(mongocrypt_query_type_t val);
@@ -248,6 +248,9 @@ bool mongocrypt_ctx_setopt_algorithm(mongocrypt_ctx_t *ctx, const char *algorith
248
248
  } else if (mstr_eq_ignore_case(algo_str, mstrv_lit(MONGOCRYPT_ALGORITHM_STRING_STR))) {
249
249
  ctx->opts.index_type.value = MONGOCRYPT_INDEX_TYPE_STRING;
250
250
  ctx->opts.index_type.set = true;
251
+ } else if (mstr_eq_ignore_case(algo_str, mstrv_lit(MONGOCRYPT_ALGORITHM_TEXTPREVIEW_DEPRECATED_STR))) {
252
+ _mongocrypt_ctx_fail_w_msg(ctx, "Algorithm 'textPreview' is deprecated, please use 'string'");
253
+ return false;
251
254
  } else {
252
255
  char *error = bson_strdup_printf("unsupported algorithm string \"%.*s\"",
253
256
  algo_str.len <= (size_t)INT_MAX ? (int)algo_str.len : INT_MAX,
@@ -1027,14 +1030,21 @@ bool mongocrypt_ctx_setopt_query_type(mongocrypt_ctx_t *ctx, const char *query_t
1027
1030
  } else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUFFIX_STR))) {
1028
1031
  ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_SUFFIX;
1029
1032
  ctx->opts.query_type.set = true;
1033
+ } else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUBSTRING_STR))) {
1034
+ ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_SUBSTRING;
1035
+ ctx->opts.query_type.set = true;
1030
1036
  } else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR))) {
1031
- _mongocrypt_ctx_fail_w_msg(ctx, "Query type 'prefixPreview' is deprecated, please use 'prefix'");
1032
- return false;
1037
+ // 'prefixPreview' is a deprecated alias for 'prefix'.
1038
+ ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED;
1039
+ ctx->opts.query_type.set = true;
1033
1040
  } else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR))) {
1034
- _mongocrypt_ctx_fail_w_msg(ctx, "Query type 'suffixPreview' is deprecated, please use 'suffix'");
1035
- return false;
1036
- } else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_STR))) {
1037
- ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW;
1041
+ // 'suffixPreview' is a deprecated alias for 'suffix'.
1042
+ ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED;
1043
+ ctx->opts.query_type.set = true;
1044
+ } else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_DEPRECATED_STR))) {
1045
+ // TODO: MONGOCRYPT-938 disallow substringPreview
1046
+ // _mongocrypt_ctx_fail_w_msg(ctx, "Query type 'substringPreview' is deprecated, please use 'substring'");
1047
+ ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_DEPRECATED;
1038
1048
  ctx->opts.query_type.set = true;
1039
1049
  } else {
1040
1050
  /* don't check if qt_str.len fits in int; we want the diagnostic output */
@@ -1066,7 +1076,10 @@ const char *_mongocrypt_query_type_to_string(mongocrypt_query_type_t val) {
1066
1076
  case MONGOCRYPT_QUERY_TYPE_RANGE: return "Range";
1067
1077
  case MONGOCRYPT_QUERY_TYPE_PREFIX: return "Prefix";
1068
1078
  case MONGOCRYPT_QUERY_TYPE_SUFFIX: return "Suffix";
1069
- case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW: return "SubstringPreview";
1079
+ case MONGOCRYPT_QUERY_TYPE_SUBSTRING: return "Substring";
1080
+ case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED: return "PrefixPreview";
1081
+ case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED: return "SuffixPreview";
1082
+ case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_DEPRECATED: return "SubstringPreview";
1070
1083
  default: return "Unknown";
1071
1084
  }
1072
1085
  }
@@ -984,6 +984,10 @@ bool _mongocrypt_parse_kms_providers(mongocrypt_binary_t *kms_providers_definiti
984
984
  } else if (0 == strcmp(field_name, "kmip") && bson_empty(&field_bson)) {
985
985
  kms_providers->need_credentials |= MONGOCRYPT_KMS_PROVIDER_KMIP;
986
986
  } else if (0 == strcmp(field_name, "kmip")) {
987
+ if (0 != (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_KMIP)) {
988
+ CLIENT_ERR("kmip KMS provider already set");
989
+ return false;
990
+ }
987
991
  if (!_mongocrypt_opts_kms_provider_kmip_parse(&kms_providers->kmip_mut, field_name, &field_bson, status)) {
988
992
  return false;
989
993
  }
@@ -161,6 +161,11 @@ typedef enum {
161
161
 
162
162
  bool _mongocrypt_validate_and_copy_string(const char *in, int32_t in_len, char **out) MONGOCRYPT_WARN_UNUSED_RESULT;
163
163
 
164
+ /* _mongocrypt_check_no_embedded_nul returns false and sets @status if @str contains an embedded null byte. See
165
+ * MONGOCRYPT-977. */
166
+ bool _mongocrypt_check_no_embedded_nul(const char *str, uint32_t len, const char *what, mongocrypt_status_t *status)
167
+ MONGOCRYPT_WARN_UNUSED_RESULT;
168
+
164
169
  char *_mongocrypt_new_string_from_bytes(const void *in, int len);
165
170
 
166
171
  /* _mongocrypt_needs_credentials returns true if @crypt was configured to